Cerradura electronica con tarjetas de proximidad Mifare con Arduino UNO

Hace unos meses me pidieron un curso personalizado centrado en el uso de tarjetas de proximidad (contactless cards) con tecnología Mifare desde Arduino. Aunque es una tecnología que ya había usado antes no la conocía lo suficiente como para dar un curso. Entonces pensé que lo mejor sería desarrollar algún proyecto con esta tecnología para empaparme bien de sus peculiaridades. Y lo que empezó como un miniproyecto de autoaprendizaje esta terminando en un monstruo que ya ocupa 30K de los 32K que tiene Arduino UNO!

Esta cerradura es bastante completa, tiene casi todas las funciones que se pueden desear en una cerradura electrónica:
– Cada cerradura puede manejar 100 tarjetas distintas en sus listas, si no se usan listas el número de tarjetas es de 255 para cada cerradura. Se pueden configurar 255 cerraduras distintas.
– Funcionamiento Tarjeta + PIN o solo tarjeta. El PIN puede ser de hasta 8 dígitos.
– Funcionamiento en modo Trust, en el que todas las tarjetas son aceptadas si contienen los datos cifrados correctos, o NO trust en el que las tarjetas deben ser introducidas previamente en una de las listas de cada cerradura.
– Listas: Blanca: tarjeta aceptada, util en el modo NO Trust. Negra: La tarjeta incluida en esta lista es rechazada y activa la alarma. Gris: La tarjeta es aceptada pero activa la alarma silenciosa. Gold: Las tarjetas de esta lista NO necesitan PIN, Es más cómodo operar la cerradura pero menos seguro si un usuario pierde la tarjeta.
– Pin de pánico. Si se introduce el PIN 2 se permite el acceso pero se activa la alarma silenciosa.
– Tarjetas personalizables con un mensaje de 16 caracteres que se muestra al usarlas.
– Dos franjas horarias de permiso en cada tarjeta, la tarjeta se rechaza fuera de esas franjas horarias.
– Tarjetas con fecha de caducidad preprogramable, pasada la fecha son rechazadas por las cerraduras.
-Anti Passback programable. Si se activa esta función es necesario salir antes de volver a entrar. Son necesarias cerraduras distintas para la entrada y la salida.
– Niveles de acceso: cada tarjeta se programa para abrir las cerraduras de igual o menor nivel, y no las de mayor nivel.
– Permisos: cada tarjeta se programa con unos permisos: abrir, administrar, cancelar alarma etc. Es posible crear tarjetas que solo permiten poner en hora la cerradura o cancelar la alarma.
– Cambio de PIN por el usuario. Introduciendo el PIN actual en cualquier cerradura.
– Cambio de PIN administrativo. Si un usuario olvida su PIN es posible cambiarlo sin conocerlo. Se necesita autorizar la operación con una tarjeta que tenga activo el permiso de cambio administrativo de PIN.
– Las tarjetas son compatibles con otros sistemas. Los datos almacenados en la tarjeta ocupan 2 bloques y 7 sectores y es posible configurar 4 zonas distintas. El lector busca datos válidos en cada una de las 4 zonas. Esto permite utilizar los bloques que dejan libres otros sistemas y trabajar conjuntamente. Yo lo he probado con tarjetas de vending de Autobar y funciona perfectamente: la tarjeta sigue siendo válida en las máquinas de vending y además funciona en las cerraduras.
– Datos cifrados. La tecnología mifare cifra los datos en las comunicaciones y tiene unas Keys de 48 bits pero es una tecnología ya rota. Existen distintos tipos de ataques que podrían revelar los datos contenidos en las tarjetas o incluso copiarlas. Esta cerradura cifra los datos con elalgoritmo XXTEA y una key de 128 bits. Aunque un atacante pudiera leerla y copiarla no podría averiguar el PIN ni modificar los datos.
– Registro de acceso en las tarjetas: en cada tarjeta se almacenan los 5 últimos usos, con fecha y hora, número de cerradura y tipo de acceso. Estos datos pueden consultarse desde el menú administrativo.
– Registro de acceso en la cerradura: cada cerradura almacena el último acceso de cada una de las 100 tarjetas distintas.
– Configuración sencilla desde PC mediante un programa terminal serie (o desde el entorno Arduino). Una vez introducidos los datos mínimos: password de comunicaciones y Keys es posible crear y administrar las tarjetas desde la propia derradura sin PC.
– Sin Keys ni password por defecto. Eso suele ser un foco de problemas de seguridad. La cerradura NO funciona si no se programa el password de comunicaciones. Es necesario programar también las Keys y recordarlas si quiere que distintas cerraduras sean compatibles entre si.
– Configuración sencilla mediante tarjeta administrativa ZeroCard que permite el acceso a todos os menús de configuración.
– Pantalla LCD de 2×16 para mostrar estado y configurar la cerradura.
– Realimentación visual con dos LED de estado y sonora con altavoz para un uso más cómodo.
-Salida de relé para alarma silenciosa en caso de que el usuario introduzca el PIN 2 con una tarjeta válida o si la tarjeta esta en la lista negra o gris.
– Interruptor anti tamper para detectar manipulación de la cerradura, con alarma y bloqueo del funcionamiento. Posibilidad de autodestrucción en caso de manipulación (se borran las keys y contraseñas).
– Detección de hardware en runtime, que permite detectar y dar alarma si falla el RTC o el lector MFRC522.
– Alarma retentiva, no se desactiva al quitar alimentación. Es necesario borrarla usando una tarjeta con el permiso de cancelar alarma.
– Posibilidad de desformatear las tarjetas y dejarlas en configuración de fábrica (transport). De esta forma pueden usarse en otros sistemas.

El hardware es bastante sencillo:
– Arduino UNO: https://www.tiendatec.es/arduino/placas/379-placa-uno-r3-atmega328p-cable-usb-compatible-arduino-uno-r3-8403790020005.html
– Reloj RTC por I2C zs-042 (chip DS3231): https://www.tiendatec.es/arduino/modulos/400-modulo-zs-042-reloj-en-tiempo-real-rtc-basado-en-ds3231-at24c32-para-arduino-y-raspberry-pi-8404001180013.html
– Lector RFID MFRC522: https://www.tiendatec.es/arduino/rf-rfid-nfc/394-modulo-rfid-rc522-kit-rfid-nfc-con-tarjeta-y-llavero-para-arduino-y-raspberry-pi-8403941180015.html?search_query=mifare&results=7
– Display LCD de 2 líneas de 16 caracteres por I2C: https://www.tiendatec.es/arduino/pantallas-displays/683-pantalla-lcd-1602a-16×2-bus-i2c-iic-azul-para-arduino-8406831590000.html
– Dos relés de nivel lógico: https://www.tiendatec.es/arduino/reles/521-modulo-ky-019-rele-1-canal-5v-para-arduino-8405211430004.html
– Teclado de matriz de 4×4 (aunque solo uso 3×4): https://www.tiendatec.es/arduino/componentes-de-entrada/384-teclado-membrana-4×4-teclas-con-adhesivo-8403841270014.html
– Algunos componentes sueltos: 2 resistencias de 330 Ohmios, un LED rojo y otro verde, un condensador electrolítico de 10uF y 16V, un altavoz de 8 Ohmios y un microinterruptor o contacto reed. También son necesarias algunas resistencias más para convertir el teclado de matriz a analógico: 2 resistencias de 4K7, dos de 1K5, dos de 15K, y una de 2K2.

El esquema es este:

Y el montaje práctico este:

El programa del Arduino necesita algunas librerías adicionales:
Para gestionar el lector MFRC522: https://github.com/miguelbalboa/rfid
Para gesionar el display LCD por I2C: https://github.com/marcoschwartz/LiquidCrystal_I2C
Para gestionar el reloj RTC DS3231: https://github.com/adafruit/RTClib Esta librería la he modificado para detectar, en cada lectura, si el chip RTC esta presente, de forma parecida a como funciona esta otra: https://github.com/PaulStoffregen/DS1307RTC
Mi librería RTClib: RTClib_heli

Para que el programa funcione correctamente es necesario que la memoria EEPROM del Arduino este vacía (a 0xFF). En esta memoria se graban datos importantes, la contraseña de comunicaciones etc y si tiene valores incorrectos no podremos comunicar con la cerradura, ni podrá leer las tarjetas. Lo mejor es borrar previamente la memoria EEPROM, por ejemplo con este programa: http://heli.xbot.es/?p=415

Aunque no esta totalmente terminado y me faltan por probar de forma exaustiva algunas funciones el programa es completamente funcional. Todos los ficheros del proyecto, con los fuentes para Arduino, librerías y esquemas: Cerrojus 0.7.B

Así se ve el prototipo:, la electrónica con arduino y el teclado cony del display LCD. El lector MFRC522 esta pegado tras el teclado y es capaz de leer las tarjetas a través de él.

Y esta es la vista de los circuitos en la parte trasera:

Para el funcinamiento seguro de la cerraura se usan varias Keys y contraseñas que se almacenan en la EEPROM del arduino. Cuando se carga el programa por primera vez deben configurarse con los valores adecuados. Si queremos que distintas cerraduras sean compatibles entre sí deben configurarse con las mismas keys. Esta configuración inicial se realiza desde el propio entorno arduino de programación, mediante el monitor serie.
En el primer uso el menú de administrador no necesita autorización. La primera tarjeta que se cree será la ZeroCard que es la tarjeta administrativa con todos los permisos activos. Después el acceso a los menús necesitará una autorización usando una tarjeta y el PIN correspondiente, dependiendo de los permisos de la tarjeta estarán activos unos menús u otros.
Usando la ZeroCard es posible gestionar todas las funciones de la cerradura y administrar las demás tarjetas, sin necesidad de PC.

En la siguiente entrada el manual de configuración y el manual de uso!

Arduino UNO con wifi ESP8266 por comandos AT simple

Los módulos ESP8266 vienen programados de fábrica para usarse como módems wifi. Para ello se debe usar una extensión del juego de comandos AT estándar: http://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf

Un problema que he encontrado es que los módulos ESP8266 antiguos (firmware 0.9.5) venían configurados por defecto con el puerto serie a 9600 baudios. Esto es muy lento pero muy adecuado para trabajar con los puertos série de software de Arduino UNO (librería softwareserial).
Los nuevos ESP8266 con el firmware (por ejemplo con firmware 1.5.2 ó 2.0.0) vienen configurados con el puerto serie a 115200 bauds. Esto no es problema para un Arduino MEGA que tiene varios puertos serie de hardware. Pero con un Arduino UNO, que solo tiene un puerto serie de hardware y esta conectado al convertidor USB <-> Serie, no podremos usarlos.
Si conectamos el ESP8266 al puerto serie nativo perdemos la comunicación con el PC y la capacidad de depurar el programa por el puerto serie. Además nos interferirá en la carga de sketchs desde el IDE e Arduino.
Si usamos un puerto serie de software (con la librería softwareserial) no podremos comunicar a más de 38400 bauds (teóricamente a 57600 pero yo no lo he conseguido, incluso a 38400 se producen muchos errores).

La solución que propongo es reconfigurar la velocidad por defecto de los ESP8266 a una velocidad mas baja compatible con la librería softwareserial. Una velocidad razonable para esta librería es 19200 baudios.

El procedimiento es el siguiente:
Cargar un sketch vacío en el IDE de arduino y enviarlo al Arduino UNO. A continuación conectar ESP8266 ESP01 para comunicar PC con ESP8266:
ESP8266 PIN 1 (RXD) -> ARDUINO UNO PIN 0 RX
ESP8266 PIN 8 (TXD) -> ARDUINO UNO PIN 1 TX
Según este esquema:

Es necesario que el Arduino UNO tenga un sketch vacío para que no interfiera en las comunicaciones con el ESP8266. Este esquema nos permite usar la placa Arduino UNO como convertidor USB <-> RS232 para comunicar el PC con la placa ESP8266.

A continuación abrir el monitor serie del IDE Arduino ( Herramientas -> Monitor Serie o pulsando Control + Mayúsculas + M) y configurar enviar «Ambos NL & CR» y la velocidad a 115200 baudios.
Enviar AT y enter y el módulo deberá responder OK si todo es correcto. Si la velocidad por defecto del módulo no es 115200 no responerá y posiblemente se vea «basura» en el monitor serie. Entonces habrá que probar distintas velocidades hasta conseguir que el módulo responda OK al comando AT.
Para configurar la velocidad por defecto a 19200 baudios, 8 bits de datos, uno de stop y sin control de flujo hay que enviar el comando:
AT+UART_DEF=19200,8,1,0,0
y el módulo responderá AT.
A continuación no responderá más a AT porque ya habrá conmutado a la nueva velocidad. Para probarlo seleccionar 19200 baudios en el monitor serie y enviar AT. La respuesta deberá ser OK si todo es correcto. Tras este procedimiento la velocidad por defecto queda fijada a 119200 baudios incluso tras un eset del módulo o tras quitarle alimentación.
En este fichero estan los esquemas e instrucciones para este proceso: Esp8266_Config

Ahora ya puede conectarse el ESP8266 en una par de pines generales y configurarlos para puerto serie de software.
Podemos usar los pines 2 y 3 para el puerto serie y conectar también un LED y un pulsador siguiendo este esquema:

A continuación cargamos en el IDE de arduino el sketch «Esp8266_Simple.ino»: Esp8266_Simple
Para monitorizar el trabajo de este sketch se puede usar el monitor serie configurado a 115200 baudios.
La salida será similar a esta:
Enviando: AT+RST
Respuesta: AT+RST
OK
(algo de basura…)
ready
Enviando: AT+CWSAP_CUR=»MyESP8266″,»Test1234″,5,3
Respuesta: AT+CWSAP_CUR=»MyESP8266″,»Test1234″,5,3
OK
Enviando: AT+CWMODE=2
Respuesta: AT+CWMODE=2
OK
Enviando: AT+CIPMUX=1
Respuesta: AT+CIPMUX=1
OK
Enviando: AT+CIPSERVER=1,80
Respuesta: AT+CIPSERVER=1,80
OK
Enviando: AT+CIFSR
Respuesta: AT+CIFSR
+CIFSR:APIP,»192.168.4.1″
+CIFSR:APMAC,»1a:fe:00:00:00:00″
OK
Trabajando
Trabajando
Trabajando
Trabajando

Este programa crea un punto de acceso WIFI (AP) llamado «MyESP8266» con contraseña WPA2 «Test1234» en el canal 5. Nos conectamos a ese punto de acceso, introducimos la contraseña y abrimos en un navegador la dirección 192.168.4.1.
Podremos ver una página web simple con dos botones rotulados ON y OFF. Pulsándolos podremos cambiar el estado del LED conectado el PIN 13 del Arduino. Más abajo podemos ver el estado del PULSADOR conectado en el pin 4.

Lector, copiador y borrador de tarjetas RFID MIFARE

Estoy liado con varios proyectos que involucran lectores de tarjetas RFID tipo MIFARE de NXP https://www.nxp.com/products/identification-and-security/mifare-ics/mifare-classic:MC_41863 con lectores MFRC522 https://www.prometec.net/producto/rfid-kit-arduino y Arduino UNO

MFRC522

Uno de los probemas que he encontrado es que, cuando trabajas con montones de tarjetas y varios proyectos a la vez, es muy facil confundir tarjetas o incluso programar keys incorrectas. En esas condiciones las tarjetas pueden quedar inútiles (es imprescindible conocer las keys internas para usarlas o borrarlas).

Este programa para Arduino UNO (posiblemente funcione en otros) nos permite averiguar las keys programadas en las tarjetas para luego borrarlas o copiarlas sin preocuparnos de buscar las keys exactas que fueron programadas dentro.
Para ello es necesario compilar el programa con la lista de las keys comunmente usadas en nuestros proyectos. El programa intenta autentificarse en cada sector con cada una de las keys programadas y crea una lista de keys y secores. Esto nos permite luego borrar la tarjeta y dejarla en condiciones de fábrica o copiarla a otra vacía.
Es necesaria la librería de arduino MRFC522 que puede instalarse desde el gestor de librerías del arduino IDE o de aqui: https://github.com/miguelbalboa/rfid

El conexionado necesario es muy sencillo:

Fos ficheros del proyecto: HeliMifareClonner.zip

Para usar el programa se abre con el IDE de arduino y se carga en el arduino. Luego se abre el «monitor serie» y se configura a 115200 baudios y «sin ajuste de linea». Aparecerá un menú con 5 opciones, que es autoexplicativo:
1: PROBAR las Keys conocidas. Intenta averiguar que key, de la lista incluida en el programa, corresponde con cada sector de la tarjeta.
2: LEER Tarjeta: Lee la tarjeta usando la lista de keys averiguada anteriormente.
3: VER DATOS de tarjeta: Muestra el bloque de datos (1024 bytes) que ha podido leer con la opción 2
4: ESCRIBIR nueva tarjeta: Escribe una tarjeta vacía, que este con las keys de fábrica a FFFFFFFFFFFF, con los datos leidos anteriormente y luego instala las keys averiguadas en cada sector. Esto crea una tarjeta clon de la leíada anteriormente. El bloque 0, que contiene el UID y otros datos del fabricante, no se copia. Aunque algunas tarjetas de fabricantes alternativos (No NXP) permiten escribir en el bloque 0 usando una secuencia de comandos especial, este programa no lo hace (la línea de código necearia esta comentada en el programa) porque no he podido probar que funcione correctamente.
5: COMPROBAR Tarjeta con datos Compara los datos leidos previamente con los datos de otra tarjeta. Si las keys no son las mismas en las dos tarjetas los bloques trailer no podrán coincidir y habrá otros sectores que no podrán leerse y quedarán sin comparar «SIN DATOS».
6: BORRAR tarjeta: Borra una tarjeta usando las keys averiguadas para dejarla tal y como vienen de fábrica, con las keys a FFFFFFFFFFFF («transport keys»).

Como optimizar el consumo de memoria en programas de Arduino

El compilador que usa el entorno Arduino es muy óptimo y es dificil escribir el programa de forma que genere menos código: el compilador optimiza automáticamente independientemente de como lo esribamos.
Pero hay algunos detalles que permiten ahorrar bytes de RAM o de FLASH, cambiando un poco el enfoque de los programas!

Uno es usar el macro F() para las variables de cadena que pasamos a algunas funciones, principalmente Serial.print().
Usando como ejemplo el programa http://heli.xbot.es/?p=501 podemos cambiar la línea 61 de:
        Serial.println («Testing AnalogKeyPad»);
a
        Serial.println (F(«Testing AnalogKeyPad»));

Compilando con el IDE de Arduino 1.8.5 para Arduino UNO (Atmega328p),
la primera forma genera un programa de 1958 bytes que usa 269 bytes de RAM y
la segunda forma genera un programa de 1998 bytes que usa 249 bytes de RAM.
Hemos ahorrado 20 bytes de ram (de los 2048 disponibles) pero el programa ha crecido en 40 bytes!
Que no cunda el pánico, ahora optimizamos mas todavía:
cambiamos la línea 70 de:
        Serial.print («Pulsado «); Serial.println (b);
a
        Serial.print (F(«Pulsado «)); Serial.println (b);
Ahora el programa ocupa 2004 bytes y usamos 239 de RAM, el programa solo ha crecido en 6 bytes y hemos ahorrado 10 bytes de RAM.

El programa sobre el que estamos trabajando es muy sencillo y no tiene mas cadenas constantes, no podemos seguir mejorándolo, pero cualquier cadena que convirtamos en constante en el futuro ahorraría aproximadamente su longitud en RAM incrementando solo 6 bytes de código en FLASH.

¿Y por que es así?
Porque el micro ATMEGA328P, y toda la familia aTMEGA, son micros con Arquitectura Harvard y eso significa que los DATOS y las instrucciones de PROGRAMA se almacenan en espacios separados y se acceden usando instrucciones de programa distintas.
Eso representa un problema para el compilador porque tiene que generar un código distinto para manejar datos variables (en RAM) y datos constantes (en memoria de programa FLASH).
El compilador que usa el entorno de Arduino es el AVR-GCC y soluciona este problema copiando en RAM las constantes y usando siempre funciones que trabajan sobre RAM.
Esto tiene el inconveniente de que cada constante que declaramos en nuestro programa ocupa una cantidad igual de memoria de programa y de RAM.
Y esto no tiene facil solución porque, para manejar datos que solo esten en memoria de programa, hacen falta funciones distintas que sepan manejar los datos residentes en ese espacio de memoria.
En arduino existe el macro F() que permite instruir al compilador para que almacene una cadena constante solo en FLASH.
Además la función Serial.print() esta sobrecargada de forma que se compila de forma distinta para cadenas variables que para cadenas constantes.
La primera vez que usamos la función Serial.print(F()) el compilador añade el código de la librería necesario para manejar cadenas constantes y por eso el programa crece un poco. Los siguientes usos de la función solo incrementen un poco el código debido a la diferente gestión de los datos.
Lo importante es que cada uso de F() ahorra una cantidad de RAM igual a la longitud de la cadena usada! Y en RAM es donde mas justo esta el Atmega328p.

Podemos usar esta técnica para otras constantes, pero si la función que las ha de usar no esta adecuadamente sobrecargada (es decir, no tienen definida función para trabajar con datos en espacio de programa) no será posible. Tenemos que escribir nuestro propio código para acceder a esos datos en memoria de programa… pero es sencillo.

Este es un array normal, cada dato (int) ocupa dos bytes de FLASH y dos de RAM.
        const int KeyVals[nKeys+1] = { 693, 665, 624, 573, 544, 491, 463, 432, 393, 353, 308, 249, 188, 157, 117, 79, 0};

La forma de decir al compilador que queremos que almacene un array en memoria de programa es esta:
        const int KeyVals[nKeys+1 ] PROGMEM = { 693, 665, 624, 573, 544, 491, 463, 432, 393, 353, 308, 249, 188, 157, 117, 79, 0};

Pero al usar la segunda forma ya no podemos hacer:
if (Val >= KeyVals[i]) break;

porque el manejo de variables array solo puede trabajar con datos en RAM. ATENCION el compilador no informará de un error!!! pero el programa no funcionará. Los datos estarán almacenados en un espacio de memoria pero el programa intentará usar punteros a ese espacio de memoria en otro espacio de memoria distinto, con lo que apuntará a datos distintos y no funcionará!! Debe usarse la función adecuada para leer los datos almacenados en la memoria de programa, usando los punteros a memoria de programa ha generado el uso de PROGMEM: pgm_read_word(), porque los datos son de tipo int (ocupan 16 bits):
        if (Val >= pgm_read_word(KeyVals+i)) break;

Para el otro array, que es tipo char (8 bits), se debe usar la función
        pgm_read_byte(Keys+i);

NO se puede usar el índice [i] en un array PROGMEM ya que su gestión esta definida para trabajar con variables RAM. Debe usarse +i que sirve para punteros a RAM o a FLASH.

Después de aplicar estas dos optimizaciones al programa (dos líneas con F() y dos arrays cambiados a PROGMEM) el programa que antes ocupaga 1958 bytes de FLASH y usaba 269 de RAM ahora ocupa 1992 bytes de FLASH pero solo usa 189 bytes de RAM.
Ha crecido en 34 bytes de 32768 disponibles (~ 0.1%) pero ha bajado el uso de ram en 80 bytes de 2048, casi un 4% de mejora.

https://www.arduino.cc/en/Reference/PROGMEM

El programa optimizado: AnalogKeyPad1

Teclado de matriz 4×4 analógico para arduino

Aunque ya hay teclados de matriz analógicos comerciales y librerías para arduino (este, por ejemplo: https://www.sparkfun.com/products/12080) es interesante convertir los teclados de matriz que ya tenemos por casa a analógico.
Las placas Arduino tienen entradas analógicas de 10 bit y solemos tener alguna sin usar…
Siguiendo esta idea: http://www.technoblogy.com/show?NGM puede hacerse con 7 restencias normales del 5% de tolerancia con este esquema:

Código:

/*
* AnalogKeyPad: Teclado de matriz para lectura analógica
* segun esquema:  http://www.technoblogy.com/show?NGM
*
* (c) Heli Tejedor, http://heli.xbot.es, Octubre 2017
*
* Este Software se distribuye bajo licencia
*
* Creative Commons 3.0 Reconocimiento, No Comercial, Compartir Igual (CC BY-NC-SA 3.0)
* http://creativecommons.org/licenses/by-nc-sa/3.0/deed.es_ES
* http://creativecommons.org/licenses/by-nc-sa/3.0/
*
*/

// Configuracion del teclado
#define nKeys 16

#define NO_KEY 0
#define KEYPAD_PIN A0

// Tecla de la matriz 4x4: NINGUNA S1 S5 S9 S13 S2 S3 S4 S6 S7 S8 S10 S11 S14 S12 S15 S16
const int KeyVals[nKeys+1] = { 693, 665, 624, 573, 544, 491, 463, 432, 393, 353, 308, 249, 188, 157, 117, 79, 0};
const char Keys[nKeys+1] = {NO_KEY, '7', '4', '1', 'A', '8', '9', 'F', '5', '6', 'E', '2', '3', '0', 'T', 'C', 'P'};

// ===============================================================================
// Retorna caracter de la matriz
// ===============================================================================
char GetKey (int Val)
{
char i=0;
for (; i < nKeys; i++) if (Val >= KeyVals[i]) break;
return Keys[i];
}

// ===============================================================================
// Lee el teclado, retorna caracter de la matriz o NO_KEY
// ===============================================================================
char ReadKeyPad()
{
static char OldKey = NO_KEY;
char KeyPressed;
char FirstKey = GetKey (analogRead(KEYPAD_PIN));

// Necesita 10 lecturas validas seguidas durante 10ms
for (char i=0; i<10; i++)
{
KeyPressed = GetKey (analogRead(KEYPAD_PIN));
if (KeyPressed != FirstKey) return NO_KEY;
delay (1);
}
if (KeyPressed == OldKey) return NO_KEY;
OldKey = KeyPressed;
return KeyPressed;
}

// ===============================================================================
void setup(void)
{
Serial.begin (115200);
Serial.println ("Testing AnalogKeyPad");
}

// ===============================================================================
void loop(void)
{
char b = ReadKeyPad();
if (b != NO_KEY)
{
Serial.print ("Pulsado "); Serial.println (b);
}
delay(100);
}

Todos los ficheros del proyecto estan aqui:
http://heli.xbot.es/wp-content/uploads/2017/11/AnalogKeyPad.zip
junto con una tabla de excell para calcular los valores analógicos en función de las resistencias elegidas.

Actualización 2/11/2017: Una mejora que puede hacerse es montar la resisitencia de pullup de 15K Ohmios directamente en la entrada analógica, junto al arduino. De esta forma se evita que un mal conexionado del teclado provoque pulsaciones fantasma de las teclas. Además se elimina un cable del conexionado del teclado: ahora es solo de dos hilos!

Usando viejos displays LED 7 segmentos con SDA2131 desde arduino

Tengo una caja llena de viejos display de 7 segmentos LED, muchos de máquinas pimball, otros de básculas industriales…
Todos tienen más de 25 años y usan para controlar los displays chips Siemens SDA2131. Hoja de datos del SDA2131.

Cada uno de estos chips SDA2131 puede manejar 16 segmentos LED directamente, sin resistencias limitadoras, y la información se carga usando un bus serie síncrono. No es muy dificil escribir un programa que pueda manejarlos.
Usando partes de otro programa para LED de 7 segmentos (YL-3) http://heli.xbot.es/?p=151 que ya había escrito antes he escrito un pequeño programa para Arduino uno que controla estos displays: SDA2131 con Arduino

Usando un display de matriz LED indocumentado CDM102

Haciendo limpieza he desmontado y tirado una docena de viejos switches ethernet 10baseT de Nortel Networks «Baystack 102». Specs Baystack 102

A parte de mucho hierro tienen unas fuentes de alimentación fabricadas por Delta SMP43ep-5 muy interesantes.
https://www.usbid.com/assets/datasheets/C5/smp43ep.pdf
Proporcionan 5V hasta 11A, 12V 3A y -12V 0,5A aunque la potencia total es de 43W.

También son muy interesantes los displays de matriz de 12 * 5 LED bicolores. La pega es que no hay mucha información acerca de su funcionamiento. Llevan impreso el código «CDM102», pero parecen ser diseñados a medida y no existe información pública sobre ellos.

En google he encontrado algo de información, que coincide con mis primeros análisis: http://home.earthlink.net/~drbarrall/CDM102.html

El interface es série síncrono al estilo del SPI. El uso de cada uno de los 6 pines es el siguiente:

1: LOAD Load data (Active low)
2: V+ 5V
3: SDCLK Data Clock (Active high)
4: Ground
5: SDDATA Data
6: Reset (Active low)

Despues de probar los comandos publicados por DrBarral he llegado a la conclusión de que este display es un diseño a medida para Nortel, fabricado por Siemens – Infineon – OSRAM y derivado de los displays estándar SCDQ554x http://www.osram-os.com/Graphics/XPic1/00052446_0.pdf o SCD551x http://www.osram-os.com/Graphics/XPic4/00045726_0.pdf.
CDM102 podría ser Custom Display Module 102.
La principal diferencia es que se trata de una matriz doble de 6 x 5 mientras que los displays citados son de matriz de 5 x 5.

El juego de comandos es bastante sencillo, basado en una única palabra de 8 bits:
00 – 7F: 5 bits de datos para las columnas, bit 0 es el LED de mas arriba. Se incrementa el puntero automaticamente.
Hay 6 columnas
80 – 9F: Nop
A0 – A5: Selecciona bloque de columnas. Hay 2 bloques de 6 columnas. Bloque par color ROJO, impar color VERDE.
El bit 4 no importa. El primer bloque es el de la izquierda.
A6 – AF: Select none
B0 – B5: Selecciona bloque de columnas. Hay 2 bloques de 6 columnas. Bloque par color ROJO, impar color VERDE.
El bit 4 no importa. El primer bloque es el de la izquierda.
B6 – BF: Seleccionar NADA
C0 – DF: Test: rellena filas con rojo+verde: bit 0 = primera columna, bit 1 = segunda etc
E0 – EF: Ajustar brillo en 8 steps, el bit 3 no importa
F0 – FF: Ajustar brillo en 8 steps, el bit 3 no importa

He escrito un software de prueba que permite escribir caracteres en un número arbitrario de displays puestos lado con lado, bien de forma vertical como horizontal. Tembién contiene un ejemplo para usarlo como barra gráfica de 12 barras berticales x 5 LED o 5 barras horizontales de 12 LED.
He aprovechado los bitmap que ya tenía escritos hace años para los SCDQ554x, sirven igual pero solo son de 5 x 5 pixel, dejo sin uso una línea de LED en este display de 6 x 5.
Prueba para CDM102 con Arduino/Teensy

El montaje de pruebas ha quedado así:

Las funciones que he incluido dentro del programa de pruebas son las mismas que ya usé en el display YL-3: http://heli.xbot.es/wp-admin/post.php?post=151
Aunque he añadido un par de comandos para cambiar la orientación del texto y el color «ºh , ºv, «ºr y ºg.

Mini algoritmo de cifrado XXTEA para arduino

Estoy metido en tres fregados simultáneos de IOT (ahora se llama así, antes solo eran redes de sensores distribuidos) y estaba buscando un algoritmo de encriptación aceptable para dispositivos embebidos (no hay que perder de vista la seguridad de la IOT, que luego vienen los disgustos..)
De momento estoy usando Arduino Uno (Atmega328) y había reciclado un DES que usé en otro proyecto (librería de arduino http://spaniakos.github.io/ArduinoDES) pero como voy justo de memoria y tiempo de ciclo pensé en mejorarlo.

Valoré un AES del que también tengo librería para arduino https://github.com/DavyLandman/AESLib pero ocupaba demasiado espacio en flash.

Entonces me encuentro la sorpresa, viendo avr-crypto-lib un listado de algoritmos para micros AVR de atmel, veo que existe uno llamado XTEA muy sencillo de implementar y pensado para dispositivos embebidos. Desgraciadamente la implementación de avr-crypto-lib es muy básica y no es la versión mejorada XXTEA
Buscando por la red he encontrado algunas librerías de XXTEA para Arduino, pero son un calco de la publicación original y no aportan mejoras.

Después de un cortapega de la wikipedia y de machacar el teclado un rato he dejado el algorítmo bastante óptimo para Arduino.

En los test que he realizado, un arduino Uno a 16Mhz tarda en cifrar y descifra un bloque de 64 bytes:
Con DES en modo CBC tarda 284568us y ocupa 2572 bytes de flash
Con XTEA en modo CBC tarda 11008us y ocupa 916 bytes de flash
Con XXTEA tarda 4168us y ocupa 1086 bytes de flash
O sea que es rapidísimo y pequeñito…

La KEY es de 128 bits (mejor que el DES que solo es de 56) aceptable para mi aplicación. Se conocen ataques pero se basan en usar mas de 2^59 «textos planos escogidos», también aceptable!!

El código es extremadamente sencillo, la única desventaja es que sobreescribe los datos planos con los datos encriptados, aunque he preparado una versión con un simple memcpy que soluciona este problema con unas decenas de microsegundos de trabajo extra.

El código fuente con DES, XTEA y XXTEA y algunas pruebas: XxteaTest

Mini programa para iniciar la EEprom del ATmega328 del Arduino UNO

Llevo bastante tiempo liado desarrollando aplicaciones para Arduino…
En algunos proyectos me encuentro que es dificil inicalizar la EEprom del Arduino (ATmega328). El IDE arduino (la version actual es 1.8.2) no genera los ficheros .eep que necesita avrdude para grabar el atmega, entonces declarar variables con EEMEM e inicializarlas en el IDE no sirve para nada.

Para solucionar este problema he escrito un pequeño programa que se carga en el arduino UNO (valdría para otros modelos con algunas modificaciones) y mediante comandos por el puerto serie permite leer o escribir la EEprom y dejarla ya inicializada. Luego se carga el programa que se necesite y se encuentra las EEprom inicada con los valores adecuados.

El proceso es el siguiente:
Se carga este programa en el Arduino UNO (renombrarlo a .ino):

SetEEprom.ino

A continuación se abre el monitor serie y se configura a 115200 baudios y enviar CR LF.
En el monitor serie se pueden escribir los comandos adecuados para ir iniciando la EEprom a los valores deseados. Lo mejor es prepararlo en un archivo de texto y hacer corta-pega sobre el monitor serie.
Estos son los comandos disponibles en el programa:

SetEEprom.txt

Por ejemplo se puede borrar toda ea EEprom (ponerla a 0xFF) con:
Write Init EEprom

Y luego iniciar una cadena de 10 caracteres en la dirección 0 con el valor «hola mundo»
Write String 0 10 Hola Mundo

y un bloque de 10 datos en la dirección 20:
Write EEprom 20 10 0F0302B1421CA7485823

Una vez iniciada la EEprom se carga el programa que necesitamos en el Arduino UNO y cuando arranque se encontrará la EEprom ya iniciada con los valores que introdujimos.

Solucion al crash en mame4all 0.37b5 para raspberry pi con 6 joysticks

Intentando configurar MAME en mi consola con RPI2 y retropie ( esta: http://heli.xbot.es/?p=365 ) con los joysticks /dev/input/js4 y /dev/input/js5 que son tipo PSX, veo que hay algún error en la distribución actual de mame 0.37b5.
Mame4all «casca» con «fallo de segmentación» (técnicamente es un «crash» con «segmentation fault») cuando activo alguno de los botones de los joysticks, incluso aunque no estén configurados en el mame. Basta con tenerlos conectados y usarlos.

Gracias a que el software es de fuente abierta he podido analizar el código (es c y c++) y usando mis superpoderes de programador he conseguido encontrar el error y crear un parche que soluciona el problema.

En primer lugar es necesario descargar los sources actuales de mame4all para RPI.

Esta versión que distribuyen con retropie: https://github.com/RetroPie/mame4all-pi
Esta versión es un poco mas moderna, aunque solo tiene cambios precisamente en la gestión de joysticks de PSX, pero no solucionan mi problema:
https://sourceforge.net/p/mame4allpi/code/ci/master/tree/src/

Desde la RPI con conexión a internet hacer, como usuario pi desde su directorio personal:
git clone git://git.code.sf.net/p/mame4allpi/code mame4allpi-code

Esto creará un directorio «~/mame4allpi-code» con los fuentes actuales V0.37b5 a fecha de hoy (Octubre de 2016).
En «~/mame4allpi-code/src/rpi» se encuentran los dos ficheros que hay que modificar.
El problema se presenta porque se crea un array de 4 elementos para almacenar los datos de 4 joysticks. Un comentario en el código indica que solo se trabajará con 4 joysticks. Pero en una función posterior existe un bucle que rellena los arrays de datos de los joysticks. El buche tiene tantas interaciones como joysticks tenga el sistema (detectado mediante una llamada a la API). Entonces si esa llamada devuelve mas de 4 la función acaba escribiendo datos fuera del los arrays declarados.

En el fichero «minimal.cpp», en la línea 140 se encuentra la función «int init_SDL(void)»
Voy a comentar los cambios necesarios y los problemas que problema el código original de «minimal.cpp»:
//SDL_Joystick* myjoy[4]; // Original: solo soporta 4 joysticks
SDL_Joystick* myjoy[6]; // Nuevo: Ahora tiene cabida para 6 joysticks

int init_SDL(void)
{
myjoy[0]=0;
myjoy[1]=0;
myjoy[2]=0;
myjoy[3]=0;
myjoy[4]=0; // Nuevo: Inicializar los nuevos elementos
myjoy[5]=0; // Nuevo: Inicializar los nuevos elementos

if (SDL_Init(SDL_INIT_JOYSTICK) < 0) {
fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
return(0);
}
sdlscreen = SDL_SetVideoMode(0,0, 16, SDL_SWSURFACE);

//We handle up to four joysticks
if(SDL_NumJoysticks)
{
int i;
SDL_JoystickEventState(SDL_ENABLE);

for(i=0;i<SDL_NumJoysticks;i++) { // Aqui estaba el problema, SDL_NumJoysticks() puede devolver mas de 4
myjoy[i]=SDL_JoystickOpen(i); // Pero solo habia mjoy[] para 4, si SDL_NumJoysticks() devuelve > 4 se escribe fuera del array!

Esto NO SOLUCIONA TODO EL PROBLEMA porque si el sistema tiene configurados mas de 6 joysticks estamos igual. Solo hemos actualizado el mame para que soporte 6 joysticks, pero cascará igual si hay mas.
La solución definitiva sería modifica la función «int init_SDL(void)» en minimal.cpp de forma que solo procese 6 joysticks independientemente del número de ellos que devuelva la llamada al sistema, así:
//We handle up to SIX joysticks
int NumJoysticks = SDL_NumJoysticks();

if (NumJoysticks > 6) NumJoysticks=6; // Ignoramos los demas joysticks
if(NumJoysticks)
{
int i;
SDL_JoystickEventState(SDL_ENABLE);
{
for(i=0;i<NumJoysticks;i++) { // Aqui estaba el problema,
myjoy[i]=SDL_JoystickOpen(i); // Ya no puede escribir escribe fuera del array!

A consecuencia de estos cambios también hay que modificar «input.cpp» para que pueda gestionar los nuevos joysticks:
En la línea 8:
unsigned long ExKey1=0;
unsigned long ExKey2=0;
unsigned long ExKey3=0;
unsigned long ExKey4=0;
unsigned long ExKey5=0; // Nuevo
unsigned long ExKey6=0; // Nuevo
unsigned long ExKeyKB=0;
// int num_joysticks=6; // Original: solo 4 joysticks
int num_joysticks=6; // Nuevo: ahora 6

En la función «void joyprocess(Uint8 button, SDL_bool pressed, Uint8 njoy)»
Uint32 val=0;
unsigned long *mykey=0;

if(njoy == 0) mykey = &ExKey1;
if(njoy == 1) mykey = &ExKey2;
if(njoy == 2) mykey = &ExKey3;
if(njoy == 3) mykey = &ExKey4;
if(njoy == 4) mykey = &ExKey5; // Nuevo
if(njoy == 5) mykey = &ExKey6; // Nuevo

y En la función «void gp2x_joystick_clear(void)»:

ExKey1=0;
ExKey2=0;
ExKey3=0;
ExKey4=0;
ExKey5=0; // Nuevo
ExKey6=0; // Nuevo

Lo mas rápido es descargar estos parches que ya he preparado con los cambios:
http://heli.xbot.es/wp-content/uploads/2016/10/minimal.patch_.txt
http://heli.xbot.es/wp-content/uploads/2016/10/input.patch_.txt
cd mame4allpi-code/src/rpi
wget http://heli.xbot.es/wp-content/uploads/2016/10/minimal.patch_.txt
mv minimal.patch_.txt minimal.patch
patch minimal.cpp minimal.patch
wget http://heli.xbot.es/wp-content/uploads/2016/10/input.patch_.txt
mv input.patch_.txt input.patch
patch input.cpp input.patch

Compilar y copiar el ejecutable al directorio que usa retropie:

cd ..
cd ..
make
sudo mv /opt/retropie/emulators/mame4all/mame /opt/retropie/emulators/mame4all/mame.old
sudo cp mame /opt/retropie/emulators/mame4all