En este post se cuentan algunos re los esfuerzos y errores encontrados. Si bien poner todos sería extremadamente extenso, solo se contarán ciertos matices.
El código se publicará cuando esté "en limpio", es decir, listo para hacer varias pruebas sobre él. Ya que de otro modo su testeo es inmanejable.
Características destacables
Modo librería
Se han implementado las cabeceras y respuestas de la mayoría de los comandos (todos los de valor fijo), así como funciones de atajo.
De este modo, se puede usar la librería a 3 niveles:
1. A nivel de byte, usando los mensajes definidos.
2. A nivel de mensaje, usando la función
sendCommand.
3. A nivel de función, usando funciones específicas.
Multisoporte
El código descansa sobre Stream. Luego cualquier implementación de puerto serie que herede de ella se puede utilizar de forma nativa.
Además, para exponer dicha implementación, se expone la variable
serialPtr, que gracias al uso de templates no requiere casting para utilizar cualquier extra de dicha implementación.
Ejemplo:
Facilidades
Muchas veces, especialmente al inicio, no interesa conocer qué devuelve el comando. Basta con enviarlo y esperar que funcione. Aunque el uso correcto es comprobarlo.
Por ello se implementan dos utilidades
consumeData() - que "limpia" el buffer de lectura
checkResponse() - que verifica si la respuesta esperada y recibida son iguales
Errores encontrados
Envío incorrecto de los mensajes
Tras leer la documentación de
Serial, especialmente los comandos
write(),
print(), y su clase básica
Stream, he descubierto que el parche propuesto por la profesora es un error grave cuyas consecuencias esperemos que no sean catastróficas (cámara rota). Sin embargo, el código de la documentación oficial tiene el mismo error de criterio, luego algún fallo de concepto se ha perdido por el camino (quien haya actualizado/implementado el código de ejemplo, o quien haya decidido cuál es el comportamiento de print (core <1.0 --> core >1.0)).
Actualización
El código referido es para arduino < 100. El uso de print a partir de entonces (#include <Arduino.h>) debe ser exclusivamente para comunicación en modo ASCII.
Por tanto, cualquier Serial.print anterior a 100 debería ser sustituido por write.
Según la documentación, print
convierte cualquier argumento a string. Luego en vez de enviar bytes
se están enviando chars. Pero además con el problema adicional de que son "iguales" a la vista, luego su valor a nivel de bit es diferente.
Prints data to the serial port as human-readable ASCII text. This command can take many forms. Numbers are printed using an ASCII character for each digit. Floats are similarly printed as ASCII digits, defaulting to two decimal places. Bytes are sent as a single character.
For example:
Serial.print(78, BIN) gives "1001110"
Serial.print(78, DEC) gives "78"
Serial.print(78, HEX) gives "4E"
Serial.println(1.23456, 0) gives "1"
Serial.println(1.23456, 2) gives "1.23"
Veamos la situación:
El código
[...]
El cambio
ss->write(MH);
ss->write(ML);
ss->write((byte)0x00);
ss->write((byte)0x00);
ss->write(KH);
ss->write(KL);
Tras este cambio, el código se parece a [
LinkSptite Forum Thread].
No válido para múltiples capturas
El código base está entrelazado y con números mágicos.
Por ejemplo el uso del tamaño del buffer, no solo como número mágico, sino que además en diferente escritura (decimal y hexadecimal).
Y lo más importante,
falta parte del flujo de uso.
Tras tomar la foto es necesario "cerrar" la petición, cosa que no se realizaba. [
actualización: stop_take_picture solo se emplea para hacer un halt, luego si la imagen se ha leído completamente dicho comando devolverá "error" (acabado en 0x01) ].
Así como reestablecer el "puntero remoto", que marca el desplazamiento del pixel a recuperar.
Uso incorrecto de una API de entrada salida no bloqueante
Serial está definido como un I/O no bloqueante. Por tanto, cuando no hay datos que leer devuelve -1.
Cabe destacar, que muchas implementaciones no bloqueantes no definen el comportamiendo de available(), por ello siempre devolverá 0.
Por tanto, en lugar de ver si hay datos disponibles, se lee directamente el puerto. Y en caso de ser -1 se cancela el resto de la ejecución (continue).
Destacar de no ser por available, este valor se estaba convirtiendo sin comprobar a byte, dando lugar a 0xFF. Situación que se ha visto a lo largo del desarrollo.
[
actualización: el problema de available()==0 era que la cámara estaba bloqueada (soft-brick)]
Otros problemas menores
Valores hexadecimanes clavados a pelo, cuando deberían ser variables. El ejemplo más crítico: el tamaño de la imagen, todavía mantenido en
sendReadDataCmd. (refiérase a KM KL).