ESPTOOL.EXE en windows XP x32

¿Quien usa ya Windows XP? Es un sistema operativo de 2001, tiene una antigüedad de más de 20 años, y Microsoft dejó de darle soporte hace 10 años, en 2014… Pero para algunos programas o para hardware antiguo sigue siendo necesario.

El caso es que necesito la herramienta esptool de expresiff https://github.com/espressif/esptool/releases que corra en Windows XP de 32 bits. Esta herramienta sirve para programar los chips ESP32 por puerto serie. Suelo proporcionar a mis clientes un script que llama a esptool.exe con los parámetros adecuados para programar los chips con el firmware que proporciono.

En este caso, el cliente tiene en el taller de verificación y control de calidad un antiguo PC con Windows XP x32 que utiliza para probar y programar dispositivos antiguos, es la herramienta que quiere utilizar también con mis programas.

Desgraciadamente esptool.exe sólo existe para Windows 7 y superiores. Expresiff lo proporciona escrito en python https://www.python.org/, aunque existen versiones ejecutables independientes construidas usando el compilador de python a .exe pyinstaller: https://pyinstaller.org/en/stable/.

En principio parece fácil: instalo python y pyinstaller en una máquina de Windows XP, cargo esptool.py y lo compilo. Pero la práctica es algo más dificil por problemas de compatibilidad de las herramientas de compilación con el antiguo Windows XP. Aquí voy a describir cómo instalar las versiones adecuadas de cada herramienta o librería para la compilación bajo Windows XP SP3 de 32 bits:

En primer lugar necesito una versión del intérprete de python que corra en Windows XP… pero que también sea compatible con pyinstaller. Las versiones posibles serían phthon 2.7.9 y la 3.4.4 según comentan en https://stackoverflow.com/questions/47516712/what-versions-of-python-will-work-in-windows-xp. Pero lo mejor sería una versión superior a 3.5 por compatibilidad con pyinstaller, pero no funcionaría en Windows XP, sólo en versiones superiores de Windows. Por suerte python se distribuye en código fuente y es posible modificarlo y recompilarlo para adaptarlo. Eso ya lo ha hecho «Zorba the Geek» y lo ha publicado en este hilo: una versión modificada de python 3.8.13 para Windows XP SP3: https://msfn.org/board/topic/183741-python-3813-for-windows-xp-sp3/page/4/

En la máquina con Windows XP copio «Python 3.8.1350.7z» y lo descomprimo a «c:\python_». A continuación ejecuto el instalador «c:\python_\install c:\». No funciona!. Es necesaria una librería .dll. Es necesario instalar previamente «vc2015_redist.x86.exe», que todavía puede descargarse de la página de microsoft: https://www.microsoft.com/es-es/download/details.aspx?id=53840. Entonces sí funciona la instalación de python, que creará un directorio «c:\python38». Ya puede borrarse el instalador en «c:\Python_».

Ahora hay que configurar el python para compilar esptool, esto se hace desde línea de comandos (abrir un CMD con Win+R y ejecutar CMD).

Instalar PIP (esta línea instalará PIP 22.0.4):
C:\Python38\python -m ensurepip --default-pip

Instalar intelhex (esta línea instalará intelhex 2.30):
C:\Python38\python -m pip install intelhex

Instalar pyserial en la versión compatible con pyinstaller y esptool (3.0.1):
C:\Python38\python -m pip install pyserial==3.0.1

Instalar pyinstaller en la versión compatible con windows XP y esptool 4.10):
C:\Python38\python -m pip install pyinstaller==4.10

Instalar wheel:
C:\Python38\python -m pip install wheel

Actualizar el entorno (actualiza setuptools de 56.0.0 a 69.1.1 y pip de 22.0.4 a 24.0.4):
C:\Python38\python -m pip install --upgrade pip setuptools wheel

A continuación es necesario salir de la consola con EXIT y reiniciar la máquina. Si no no carga algunas variables de entorno que se necesitan para el correcto funcionamiento de python y se producen errores raros de paths no encontrados etc.

Descargar la última versión del código fuente de esptool (esptool-4.7.0.zip) de https://github.com/espressif/esptool/archive/refs/tags/v4.7.0.zip y descomprimirlo en «c:\esptool_». Ahora bastaría con compilarlo con pyinstaller. Para mi sorpresa, una vez compilado correctamente, al ejecutarlo conectado correctamente a un ESP32 falla después de iniciar la comunicación correctamente, al no encontrar unos ficheros .json «esptool/targets/stub_flasher/*.json». Parece que no se han incluido en el proceso de compilación. Después de mucho tiempo buscando el problema sólo encuentro una pista, cómo no en stackoverflow, https://stackoverflow.com/questions/41870727/pyinstaller-adding-data-files

El comando correcto para compilar con TODOS los ficheros necesarios es:
cd c:\esptool_
pyinstaller -F --add-data "c:/esptool_/esptool/targets/stub_flasher/*.json;esptool/targets/stub_flasher/" --onefile esptool.py   

Esto debe dejar el ejecutable «esptool.exe» en «C:\esptool_\dist».

Como internet es efímero, dejo aquí el ejecutable compilado y la versión de python personalizada:

El ejecutable esptool.exe para Windows XP ya compilado:

La versión de «Zorba the Geek» de python3 para Windows XP:

Ingeniería inversa de un convertidor RS232 a ETHERNET parte 3

Ahora que ya tengo terminado el protocolo «discover» puedo hacer que el instalador del driver «NPORT Windows Driver Manager 3.5» reconozca mi ESP32 como un dispositivo MOXA y monte los puertos COM1 y COM2. El siguiente paso es identificar el protocolo de configuración del puerto y el protocolo de transmisión de datos. Aparentemente los puertos TCP/IP 960 y 966 tienen algo que ver:

Para averiguarlos monto el MOXA DE-311como puerto COM1 y analizo con WireShark la comunicación cuando abro el puerto con un programa terminal (Realterm)y envío datos:

Voy cambiando las configuraciones del puerto, baudrate, bits, paridad, control de flujo etc

Los datos de configuración del puerto se envían por el puerto TCP/IP 966. He observado que si hay más puertos activos utiliza los puertos TCP/IP 967, 968 etc hasta 982. El protocolo es algo distinto del protocolo «discover» pero sencillo:

El primer byte es el código de comando, el segundo es la longitud total mensaje y a continuación un grupo de datos variable, con un significado distinto según el comando.

He identificado bastantes comandos de configuración, aunque a otros no he sido capaz de encontrarles la utilidad.

  • 39 00 = Abrir el puerto
  • 2F 04 E8 03 00 00 = repetido x3 = Cerrar el puerto
  • 13 00 = KeepAlive o Heartbeat
  • 2C 13 10 03 01 01 00 00 00 00 4C454E4F564F2D54455354 = Configurar baudrate, bits etc
  • 17 04 40380000 = Baudrate arbitrario
  • 10 02 00 03 = Configurar baudrate, bits, paridad y bits stop
  • 11 04 00 00 00 00 = Establecer de flujo RTS/CTS DTR/DSR XON/FOFF
  • 12 02 00 00 = Establecer estado de RTS y DTR
  • 21 00 = Establecer BREAK
  • 22 00 = Cancelar BREAK
  • 30 01 10 = Sin identificar
  • 18 02 11 13 = Sin identificar

El MOXA contesta a casi todos estos comandos con ACK que es siempre COMANDO+4F4B

Los datos viajan bidireccionalmente entre el puerto COM y el MOXA por el puerto TCP/IP 950 sin modificación.

Con estos datos escribo el programa para ESP32 (DeVkit V2 o similar) «MoxaEmulator.ino» que realiza todas las funciones necesarias. El programa responde al «discover» y comunica por los puertos necesarios para emular un MOXA DE-302 de dos puertos. El programa sólo hace ECO de los datos serie que entran, enviándolos a la salida, pero eso permite ver que funciona. En esta captura se ve la detección del MOXA DE-311 auténtico y el DE-302 emulado:

El programa del ESP32 envía gran cantidad de información de depuración por el puerto serie, mostrando el intercambio de mensajes con el driver.

Y eso es todo… al final me ha llevado dos tardes más de lo que pensaba, pero los programas han quedado más depurados y fáciles de entender. Analizando el código puede seguirse con relativa facilidad el protocolo de MOXA y puede usarse en otros proyectos.

Links de descarga de los tres programas, aunque como cada uno es la evolución del anterior el «MoxaEmulator.ino» es el más completo y contiene el código de los anteriores.

MoxaDiscover1.ino

MoxaDiscover2.ino

MoxaEmulator.ino

Ingeniería inversa de un convertidor RS232 a ETHERNET parte 2

Con el primer programa el software DSU ya identifica el ESP32 como un dispositivo MOXA de la serie DE. Ahora sigo analizando paquetes para depurar las respuestas. Usando el software «Nport Windows Driver Manager» observo otro mensaje de descubrimiento, lo incorporo también al programa.

El siguiente paso es analizar el protocolo para el cambio de IP del dispositivo.

Y observo con Wireshark la comunicación:

Con estas captura puedo identificar comandos distintos: 0x45 que parece sirve para habilitar la configuración y seleccionar IP estática o DHCP, 0x33 para cambiar la IP y la máscara de red, 0x34 para cambiar el gateway y 0x35 que parece sirve para salvar los cambios, ya que no contiene información.

Con esta información actualizo el programa y ahora es posible también cambiar la IP del ESP32 usando la aplicación DSU. Se trata de un programa de pruebas, la configuración recibida no se salva en EEPROM y se pierde al reiniciar, pero sirve como prueba de concepto: MoxaDiscover2.ino

Ingeniería inversa de un convertidor RS232 a ETHERNET

Motivación:
Llevo más de 15 años usando los dispositivos del fabricante MOXA para llevar puertos serie RS232/RS485/RS422 a distancias largas a través de ethernet.
He usado principalmente los DE-311
https://www.moxa.com/en/products/industrial-edge-connectivity/serial-device-servers/general-device-servers/nport-express-series/de-311
y los NPort5210
https://www.moxa.com/en/products/industrial-edge-connectivity/serial-device-servers/general-device-servers/nport-5200-series/nport-5210

He conectado PLCs Siemens, Hiachi, Omron mediante estos dispositivos a HMI Proface, Omron, ESA VT100 (https://www.esa-automation.com/en/en-products/hmi/), transmisores de peso AUMAT4100 y DAT500 (https://www.pavonesistemi.com/es/electronica-de-pesaje-transmisores-de-peso-dat500) etc
El proceso es fácil, se conecta un dispositivo MOXA adecuadamente configurado para la red ethernet y con un cable personalizado al PLC y en el otro extremo otro al HMI, sensor etc.
Los datos serie entran por uno junto con las señales de control DTR/DSR y RTS/CTS etc y salen por el otro también con sus señales de control DTR/DSR y RTS/CTS después de viajar enrutadas por la red.

Pero una de las mejores funciones que tienen los dispositivos de MOXA es que permiten la opción «Windows Real COM Driver»!!
Cuando el dispositivo de un extremo es un PC con sistema operativo Windows no es necesario montar un MOXA conectado a un puerto serie del PC. Basta con conectar el PC a la red e instalar un driver que crea un «puerto serie virtual» en el PC conectado con un MOXA remoto.
De esta manera los programas en el PC trabajan con un puerto serie como siempre, mientras los datos se envían por la red al moxa remoto por donde salen al dispositivo.
Estos drivers tienen soporte desde Windows 95 hasta Windos 11.

Los productos de MOXA son excelentes y la calidad es excepcional, incluso indican el MTBF en la hoja de datos (más de 225000 horas!). Nunca me ha fallado uno, por lo que no tengo razones para dejar de usarlos.
Sin embargo, para aplicaciones domésticas y experimentación, siempre he ansiado poder tener un puerto serie virtual en el PC que me conecte por la red con mis micros, por ejemplo con ESP32.
De esta forma podría seguir usando los programas antiguos, que comunican por puerto serie, pero a través de la red.

Entonces… si averiguo el protocolo que usa MOXA en sus dispositivos cuando están en modo «REAL COM» podría escribir un programa para mis micros y usar su driver «Windows Real COM Driver»!

Proceso:
Para llevar a cabo la ingeniería inversa del protocolo necesitaré un sniffer de red, utilizaré WireShark: https://www.wireshark.org/
Como esto va a ser una «chapucilla de fin de semana» utilizaré la última versión bajo Windows 11 (Wireshark 4.2.0) en mi taller y una versión más antigua con soporte (no oficial) para Windows 7 para cuando trabaje en el pueblo con un viejo Packard Bell con Core2Duo T7200 http://ftp.uni-kl.de/pub/wireshark/win64/Wireshark-win64-3.6.18.msi.
Analizaré el protocolo de dos MOXA distintos, un DE-311 y un NPort5210 conectados mediante cable cruzado (aunque no es necesario los moxa tienen conexión de red RJ45 10/100 MDi/MDiX) directamente con el PC.
De esta forma minimizo el tráfico de red y no tengo que usar filtros en WireShark.

En el PC instalaré los dos programas que proporciona MOXA para gestionar estos dispositivos.
El programa que permite descubrir dispositivos en la red y asignarles IP:
DSU 2.7 build 23032110 (moxa-device-search-utility-v2.7.zip /dsu_setup_Ver2.7_Build_23032110.exe)
El instalador del driver COM que desubre dispositivos en la red y permite configurarlos como puerto serie local existe en varias versiones según el sistema operativo:
NPORT Windows Driver Manager 3.5 build 22120118 (moxa-win-driver-manager-v3.5-win-7-to-10-and-win-server-2008-r2-to-2019-whql-certified-driver-v3.5.zip / drvmgr_setup_Ver3.5_Build_22120118_whql.exe): Para Windows 7 a Windows 10 y
NPORT Windows Driver Manager 4.2 build (moxa-win-driver-manager-win-11-and-server-2022-and-later-whql-certified-driver-v4.2.zip / drvmgr_setup_Ver4.2_Build_23120717_whql.exe): Para Windows 11
También existen versiones para Windows 95 a Windows Vista que no necesito usar en este proyecto…

Alimento el DE311 y lo conecto al PC mediante un cable de red.

Arranco el WireShark como administrador para capturar de la tarjeta ethernet donde he conectado los MOXA.

Arranco el DSU como Administrador y pulso search.

Si todo va bien deberé poder ver la IP del MOXA en el DSU.

Cierro el DSU y voy a mirar los paquetes capturados por el WireShark.

Identifico varios paquetes UDP desde la IP del PC a la IP de broadcast 255.255.255.255, repetidos varias veces. Seguro que esta es la forma que tiene DSU de «llamar» a los MOXA:
PC (192.168.0.2) port 63683 envia UDP a broadcast (255.255.255.255) port 29168 con 8 bytes 0100000800000000
PC (192.168.0.2) port 63685 envia UDP a broadcast (255.255.255.255) port 4800 con 8 bytes 0100000800000000
PC (192.168.0.2) port 63687 envia UDP a broadcast (255.255.255.255) port 1029 con 6 bytes 490000060000
PC (IPV6 ) port 63691 envia UDP a multicast (IPV6 FF02::1) port 1029 con 28 bytes 7900001c000000000000000000000000000000000100000000010001

Observo que la IP del MOXA sólo contesta a uno de ellos, el sexto, enviado al port 1029 en IPV4 con la respuesta:
MOXA (192.168.0.31) port 50546 envia UDP a broadcast (255.255.255.255) port 1029 con 24 bytes C900001800007EF94CB81103EB9EC0A8006F0090E8049EEB

Supongo que el resto de paquetes no contestados que envía el PC para «llamar» a los posibles MOXA de la red son debidos a que el software DSU soporta varios modelos de MOXA y estará usando varios protocolos distintos…

A continuación el DSU envía un paquete, no ya de broadcast, sino a la dirección IP del MOXA que ha descubierto:

Posiblemente este paquete sirva para obtener información precisa del dispositivo:

PC (192.168.0.111) port 1028 envia UDP a MOXA (192.168.0.31) port 1029 con 6 bytes 010000060000
MOXA (192.168.0.31) port 1029 envia UDP a PC (192.168.0.111) port 1028 con 86 bytes 810000560000FC70148C1103EB9EC0A8006F000104730000040202014E5034303638332020202020202020202020202020202020202020202020020F0F0F0F0F0F0F0F0F0F0F0F0F0F0FC0A80021FFFFFF00C0A80001
También repito el proceso varias veces y siempre obtengo respuesta por el port 1029, también cambian cambian 4 bytes:
MOXA (192.168.0.31) port 1029 envia UDP a PC (192.168.0.111) port 1028 con 86 bytes 810000560000 E118A3CE 1103EB9EC…

Repito varias capturas cambiando la IP del MOXA y del PC para ver las diferencias en los paquetes. A continuación comparo a información que conozco con los datos obtenidos en las capturas para averiguar el significado de cada paquete:

Ahora compararé los paquetes capturados con la información que conozco para ver en que posición hay informacion reconocible.
MOXA DE-311 HW 2.1C, SW 2.4
production S/N á0BEE1240683
S/N 40683 = 9EEB hex
MAC 0090E8049EEB
IP 192.168.0.31 C0A8001F
mask 255.255.255.0 FFFFFF00
gw 192.168.0.1 C0A80001
PC Win 11 con
MAC F8:E4:3B:AF:97:87
IP 192.168.0.111 C0A8006F
mask 255.255.255.0 FFFFFF00

Estas pruebas veo que el primer paquete (comienza por 0x49) y su respuesta podrían tener esta estructura:

Y el segundo paquete, que comienza por 0x01, podría tener esta otra:

Con esta información recopilada he podido escribir un pequeño programa para ARDUINO ESP32 y probar si es correcto. He confirmado que los campos «Modelo» y «Version SW» son correctos cambiándolos por otros valores y observando en DSU la detección. Por ejemplo, en la siguiente captura hago que el ESP32 se identifique como MOXA DE-302 con un firmware version 4.2.

Esta es la captura de la salida de depuración del programa «MoxaDiscover1.ino«. (he eliminado las líneas repetidas):

Moxa discover responder (c) Heli Tejedor, V0.1, enero 2024
Reporting MOXA DE-302 SW version 4.2
Connecting to: xxxxxxxxxx:yyyyyyyyyy
……
Connected!
Signal %:86
MAC: 24:62:AB:F1:DA:44
IP: 192.168.0.165
NetMask: 255.255.255.0
Gateway: 192.168.0.1
DNS: 100.100.1.1
UDP Listening on PORT: 1029… OK
Running at Mhz: 240, Free RAM: 259432
UDP packet type: broadcast, from: 192.168.0.220:57202, to: 255.255.255.255:1029, length: 6, data: 490000060000
Response -> C900001800001214FAFB0203EB9EC0A800DC2462ABF1DA44
Discover CMD 0x49

UDP packet type: broadcast, from: 192.168.0.220:57202, to: 255.255.255.255:1029, length: 10, data: 4900000A00000203EB9E
Response -> C900001800001214FAFB0203EB9EC0A800DC2462ABF1DA44
Discover long CMD 0x49

UDP packet type: unicast, from: 192.168.0.220:1028, to: 192.168.0.165:1029, length: 6, data: 010000060000
Response -> 8100005600001214FAFB0203EB9EC0A800DC000104730000020402014E5034303638332020202020202020202020202020202020202020202020020F0F0F0F0F0F0F0F0F0F0F0F0F0F0FC0A800A5FFFFFF00C0A80001
Read Config CMD 0x01

La siguiente fase: averiguar el protocolo de configuración para cambiar a IP y los otros parámetros de la red

Diagnóstico de una válvula EGR de PSA / STELLANTIS averiada.

Pues resulta que también me voy a atrever con la mecánica… Y es que me ha tocado la moral que haya fallado con 80.000Km y que cueste 780€ (más mano de obra y otro montón de conceptos) .

Y es que mi DS5 edición aniversario de 180Cv es un coche genial: bonito, cómodo, buenos acabados, potente, con un consumo ajustado, pegatina C (cumple EURO 6)… pero ha pasado 4 veces por el taller para averías antes de los 90000Km y eso es inadmisible en un coche «premium».

Tres problemas con el depósito de urea: primero con 40.000Km, cubierto por la garantía. Segundo con 60.000 que me costó unos 600€ y el tercero con 73.000Km, este último sin cargo. Y ahora la válvula EGR con 80.000, que como el depósito de urea forma parte del sistema anticontaminación. A este coche se le cambia el aceite cada 30.000Km… no he podido hacer un cambio sin antes pasar por taller con una avería!!!

Este vehículo viene equipado con un depósito de urea para la reducción de los óxidos de nitrógeno NOx, que es un conjunto indivisible de depósito, bomba y electrónica de control. Según me comentan en el taller, no existe despiece ni es reparable «para evitar la manipulación del sistema anticontaminación». Cuesta unos 660€ más la mano de obra del cambio.

Vamos con la válvula EGR… su misión es también reducir las emisiones de óxidos de nitrógeno (dañinos para la salud y el medio ambiente), pero de una forma distinta y muy interesante. Lo que hace es mezclar parte de los gases de combustión del escape con el aire de la admisión para introducirlo de nuevo en los cilindros. ¿Absurdo? No tanto. Los óxidos de nitrógeno se producen en el interior de los cilindros debido a las altas presiones y altas temperaturas producto de una combustión muy eficiente (menos consumo y más potencia), combinado con la gran cantidad de oxígeno y de nitrógeno que hay en los gases de admisión. Los antiguos motores con bombas mecánicas, menos eficientes no generan estos gases.

Los motores diésel siempre deben aspirar la máxima cantidad de gases posible para poder comprimirlos y que aumente la temperatura y se produzca la combustión. Por lo tanto limitar la cantidad de aire que aspiran, para reducir la cantidad de oxígeno y nitrógeno y en consecuencia los óxidos nitrosos, no es una opción, el motor no funcionaria. Aquí es donde entra en funcionamiento la válvula EGR (Exhaust Gas Recirculation). Para disminuir la cantidad de oxígeno disponible lo que hace esta válvula es recircular los gases ya quemados, que a penas contienen oxígeno y sí mucho CO2, a la admisión. El volumen de gases admitidos es el óptimo, pero la concentración de oxígeno es la adecuada para la combustión del gasóil, no más. De esto se encarga la ECU (Electronic Control Unit,) del motor). No hay suficiente oxígeno como para producir óxidos de nitrógeno. Esto sólo sirve con el motor a bajo régimen, cuando la demanda de potencia es alta la necesidad de oxígeno también y no se puede sustituir parte del aire por gases quemados.

Mi coche viene equipado con una válvula EGR (Exhaust Gas Recirculation), modelo 9807593080 que se usa en muchos modelos de DS, citroen, ford y peugeot. Además también es producida por muchos fabricantes distintos (manías de la industria del automóvil: de tener muchos proveedores distintos para cada elemento).

Es un armatoste considerable, pero yo veo al menos 5 elementos completamente independientes y desmontables… ¿Por qué venden todo el conjunto y no los elementos por separado? Además del cuerpo de la válvula, arriba se ve un actuador por depresión, un sensor hall para detectar la posición del actuador, a la derecha un intercambiador de calor aceite / gases y abajo un motor de CC con sensor de posición.

Efectivamente, la válvula tiene elementos extra, además del mecanismo para permitir / impedir la recirculación de gases. El intercambiador de la derecha tiene la misión de enfriar los gases de escape antes de introducirlos en la admisión, algo lógico si pensamos que los gases de admisión interesa que estén lo más fríos posible y los gases de combustión están a más de 600 grados. Esto lo hace intercambiando el calor con el aceite del motor… sí, esta válvula tiene una conexión de entrada y otra de salida del aceite de motor. Como función extra, mediante este intercambiador, es posible calentar el aceite del motor cuando el motor está frío en pocos minutos, a costa del calor residual de los gases de escape. El actuador por depresión comanda una clapeta que abre o cierra el paso de los gases de combustión por el enfriador. Por defecto, un muelle en acatuador mantiene el paso de gases por el intercambiador abierto, se cierra por succión (depresión) de la admisión quizás mediante alguna válvula electroneumática (no he profundizado en este aspecto).

Una vez quitado el intercambiador se ve su entrada de gases a a derecha y salida de gases a la izquierda. Abano una apertura ovalada para el paso del aceite. Paso de gases por el intercambiador abierto:

Paso por el intercambiador cerrado:

Esta es la válvula que regula la recirculación de gases, similar en construcción a una válvula de admisión de los cilindros, pero comandada eléctricamente.

Este es el motor que la acciona, mediante un reductor de una etapa, una leva y un empujador. La placa electrónica contiene un sensor HALL que detecta la posición del piñón secundario, indicando la posición de la válvula a la ECU.

Esta era la posición de la leva que comanda la válvula cuando desmonté el conjunto, hacía tope en la posición casi cerrada, pero no llegaba nunca a cerrar por completo. La ECU detectaba este estado e informaba «Válvula EGR en posición distinta a la comandada».

La válvula cierra por acción de un muelle, de forma que al cortar la alimentación del motor se garantiza el cierre… desconozco si el motor tiene control bidireccional. Si sólo acciona en un sentido para abrir y el cierre se produce por la acción del muelle.. entonces es un diseño muy deficiente. La suciedad que impide el cierre esta alojada en la guía del vástago de la válvula (sometido a los gases de combustión calientes y carbonilla) pero no estaba tan agarrotada como para que un motor con algo más de par (quizás un paso más de reducción) no pudiera moverla.

Después de forzarla un poco con la mano cierra al completo:

Esta es la guía del vástago de la válvula y el propio vástago. No parece un mal diseño, la guía es solidaria al cuerpo de aluminio y todo esta refrigerado mediante al aceite del motor. En mi opinión tiene muy poca suciedad para que haya fallado.

Así ha quedado después de limpiarlo todo, no había mucha suciedad, pero ahora ya se mueve sin ninguna resistencia y el muelle la cierra por completo.

Así se ve ahora la válvula y la lumbrera por donde entran los gases calientes:

En general ha quedado bastante limpia…

Este es el intercambiador de calor entre los gases de combustión y el aceite. El aceite circula por el cuerpo de la válvula y la refrigera, y también por la carcasa de plástico donde está este elemento bañado en flujo de aceite del motor. Los gases de combustión entran por los dos tubos horizontales superiores y sale por los dos inferiores, El texturizado de los tubos es para aumentar la superficie de contacto con el aceite:

Por esta parte entran y salen los gases de combustión. La clapeta de la foto anterior hace de bypass: en una posición lleva la circulación de los gases por el intercambiador de calor y en otra los dirige directamente a la válvula EGR:.

Mi diagnóstico: el accionamiento de la válvula es demasiado flojo, con muy poca suciedad se ha bloqueado y sólo con la mano he podido desbloquearlo. ¿Podría un motor con más par solucionar este fallo? ¿O la suciedad se acumularía más y más con los sucesivos accionamientos y solo se retrasaría el fallo unas semanas?

Un autómata programable (PLC) casero, otra vez.

Viene de aqui: https://heli.xbot.es/?p=33

Han pasado otros diez años (alguno más), y nos hemos metido en 2020. El PLC casero no esta muerto, una tarjeta con un micro H8-500 y la versión 3.8 en su EPROM 27C256 continúa trabajando. Todavía controla, con sus 32 entradas y sus 32 salidas digitales, sus dos puertos serie y sus 32K de RAM con RTC y batería de backup, un filtro prensa destinado a desecar lodos.

Aprovechando el parón por el coronavirus me he puesto a revisar el software de programación ECP. La intención era portarlo a Windows. ECP solo corre en MSDOS debido a que hace acceso directo al hardware. Esto era una necesidad en su momento, ni la BIOS ni MSDOS proporcionaban una API adecuada para manejar el hardware. Por ejemplo, la velocidad más alta que podía programarse en los puertos serie era 19200 bauds, aunque los chip UART 8250 podían trabajar hasta 115200 bauds. Solo escribiendo directamente en los registros adecuados de la UART podían conseguirse todas las velocidades diponibles.

Con la llegada de sistemas operativos más avanzados (XP y posteriores) ya no es posible interactuar directamente con el hardware de la máquina. De eso se encarga el propio sistema operativo mediante los drivers, pero proporciona una API para que los programas de usuario puedan acceder al hardware.

El plan era el siguiente: cambios mínimos en el programa ECP para eliminar todas los accesos al hardware y hacerlo a través de la API de Windows. El programa ECP estaba escrito en ANSI C (Borland Turbo C 2.0, todavía se puede mediante DOSBOX bajo Windows XP). Para la nueva versión usaría GCC 9.30 bajo Msys2 y MinGW en Windows 7 x64 ( y en otros momentos máquinas bajo Windows 10 x64). No uso interfaz gráfico, mantengo el interfaz en texto pero usando la librería ncurses.

El resultado es una vesión (alfa todavía) que corre en desde Windows Vista hasta Windows 10 (incluidos Windows 7 y 8.x) de 32 o 64 bits, y también en Windows XP de 32 bits: https://heli.xbot.es/wp-content/uploads/2020/05/EcDuino4.51.zip.

Del mismo modo he tomado los fuentes en C del firmware del PLC V3.8 y lo he portado a Arduino (uso en entorno arduino 1.8.12, aunque compilará con otros anteriores). Junto con algunas librerías he conseguido que entre en la limitada RAM (2K) del Arduino UNO (Atmega328). Teniendo en cuenta que las versiones antiguas trabajaban en micros con 32K de ram es todo un lograo. Para conseguirlo he tenido que rehacer el mapa de memoria del PLC, menos E/S, menos reles internos etc. El resultado es un PLC con las siguientes características:

256 pasos de programa, 32 temporicadores/contadores, 32 entradas y 32 salidas. Dos entradas analógicas 0 a 5V de 10 bit y una salida analógica de 10 bit de 0 a 5V. 64 + 64 relés internos y reloj (si se usa el módulo RTC DS3231).

Como extra he mantenido el HMI (human-machine interface), con teclado de 6 teclas por I2C mediante PCF8754 y pantalla LCD d e16 caracteres por 2 líneas por I2C. Esto nos permite interactuar con el PLC.

Este es el montaje de prueba:

Este es el software para el Arduino UNO. Yo he usado el entorno 1.8.12, pero funcionará con otros más antiguos. Son necesarias 3 librerías que se encuentran en el directorio «libraries» dentro del ZIP: https://heli.xbot.es/wp-content/uploads/2020/04/EcDuinoUno0.2

El reloj no es imprescindible para el funcionamiento del programa, eliminarse de forma opcional. También es posible eliminar el conjunto del display y teclado dejando sin conectar los dos hilos del I2C amarillo y gris que val a los pines A4 y A5 del arduino. En caso de eliminar todo es recomendable conectar en esos pines un par de resistencias de 10K a positivo, o mejor eliminar la línea 65 de header.h «#define _DISPLAY_» para que no se compile la parte del display.

Algunos programas para el PLC para hacer pruebas: https://heli.xbot.es/wp-content/uploads/2020/04/ProgramasTest.zip

Migrando de Arduino UNO a ESP8266: excepciones

Estoy portando un programa que tengo funcinando en varios Arduino UNO a un ESP8266 y me encuentro que no funciona, provoca una excepción 28 y un volcado de pila en cuanto introduzco datos…

Excepciones del ESP8266: https://arduino-esp8266.readthedocs.io/en/latest/exception_causes.html

Después de mucho revisar compruebo que el programa para Arduino no lo tengo demasiado bien escrito, pero no causa problemas. Eso es debido a que no tiene MMU (unidad de manejo de memoria). El ATMEGA328P es un micro muy sencillo y tiene toda la memoria expuesta. Si tengo un «puntero loco» siempre puedo leer el o escribir en la dirección de memoria a donde apunta.

Sin embargo, el ESP8266, tiene un micro Tensilica Xtensa, bastante más complejo, con MMU https://en.wikipedia.org/wiki/Memory_management_unit y excepciones. Si un puntero apunta a la zona de memoria incorrecta es muy facil que se genere una excepción al intentar leer o escribir datos.

El código mal programado es este:

char *SavePtr;

char * MySerialbuffer;

char *Token = strtok_r(MySerialBuffer, " ", &SavePtr);
if (strcmp(Token, "Read") == 0) // Primera palabra clave
{
Token = strtok_r(NULL, " ", &SavePtr);
while (*SavePtr == ' ') SavePtr++; // Elimina espacios extra
  if (strcmp(Token, "Data") == 0) // Segunda palabra clave
  {
  int Src = atoi(strtok_r(NULL, Space, &SavePtr)); // Primer parametro
  int Len = atoi(strtok_r(NULL, Space, &SavePtr)); // Segundo paametro
// etc...
}
}

En MySerialBuffer estan los comandos que recibo por el puero serie. El trozo de código anterior detecta si he escrito «Read Data 12 23» donde 12 y 23 serían dos parámetros numéricos… Pero ese código es un despropósito.

La función «Token = strtok_r(caden ade entrada, delimitadores, saveptr)» https://linux.die.net/man/3/strtok_r devolverá un puntero nulo (NULL) cuando no encuentre una cadena que terminada por los delimitadores. En un micro sin MMU eso no tiene trascendencia, excepto porque cuando leamos datos de *Token estaremos leyendo de la zona de memoria 0 que puede contener cualquier cosa. En mi caso como son comparaciones con palabras clave es casi imposible que en esa zona de memoria haya algo parecido a lo que busco, la comparación falla y ya esta.

Pero en el ESP8266, con el micro Xtensa y su MMU, leer datos de un puntero nulo genera una excepción y el programa termina en una detención halt.

La forma correcta de programar es ir comprobando que el puntero devuelto por strtok_r no es nulo:

char *Token = strtok_r(MySerialBuffer, " ", &SavePtr);  
if (Token==NULL) return 0; // No continuar
if (strcmp(Token, "Read") == 0) // Primera palabra clave
{
Token = strtok_r(NULL, " ", &SavePtr);
if (Token==NULL) return 0; // No continuar
// Elimina espacios extra, con seguridad
if (SavePtr!=NULL) while (*SavePtr == ' ') SavePtr++;
  if (strcmp(Token, "Data") == 0) // Segunda palabra clave
  {
Token = strtok_r(NULL, Space, &SavePtr);
  if (Token != NULL) Src = atoi(Token);
  else return 0; // Falta un parametro
  Token = strtok_r(NULL, Space, &SavePtr);
  if (Token != NULL) Len = atoi(Token);
  else return 0; // Falta un el otro parametro
// etc...
}
}

Es lo que pasa cuando uno se acostumbra demasiado a programar micros ulrasencillos, luego hay que volver a la realidad de las MMU, la alineaciones a página etc

Doble puerto serie simultáneo SoftwareSerial para arduino

Como las placas Arduino UNO, micro nano etc (todas las basadas en el ATMEGA328P) solo disponen de un puerto serie es necesario usar la librería «SoftwareSerial.h» del entorno Arduino para manejar más de un puertos serie.

Esa librería es multi instancia, pueden declararse varios objetos tipo «SoftwareSerial» pero solo se puede escuchar la recepción de UNO en cada momento (seleccioándolo mediante el procedimiento listen().

En el proyecto que estoy trabajando ahora necesito escuchar simultáneamente dos puertos, y la opción de conmutar mediante listen() no sirve porque pierde caracteres.

Para solucionarlo he creado esta bominación, una librería que he llamado «SoftwareSerial2RX.h» que permite tener DOS puertos serie de solo recepción (no necesito transmitir y he eliminado esa parte para no consumir pines) por cada instancia.

Es necesario que los dos pines de recepción se encuentren en el mismo puerto del micro, pero pueden crearse varias instancias con parejas de pines en puertos distintos y escuchar 2, 4 ó 6 puertos en un solo arduino. Este horror no permite la recepción concurrente: si esta recibiendo datos de un puerto y llegan por el otro se interrumpen las dos recepciones. No esta muy currado, pero para leer tarjetas RFID es suficiente porque el usuario pasa de nuevo la tarjeta por el lector si observa que no se ha leido correctamente. Como uso un puerto para el tarjetero de entrada y otro para el de salida no se usarán nunca los dos puertos a la vez.

Esta es la librería, con un ejemplo de utilización: SoftwareSerial2RX

Este es un ejemplo de utilización, los procedimientos estan duplicados, uno para cada puerto: available() y available1(), read() y read1() etc…

#include <SoftwareSerial2RX.h>
// Double software serial: RX0 = digital pin 2, RX1 = digital pin 3
SoftwareSerial2RX TwoPortSerial(2, 3); 

void setup() { 
// Open serial communications and wait for port to open: 
  Serial.begin(9600); 
  
  while (!Serial) {; // wait for serial port to connect. Needed for native USB port only 
  }
  Serial.println (F("SoftwareSerial2RX: Two simultaneous receive only serial ports"));
  // Start only RX serial ports 
  TwoPortSerial.begin(9600); 
} 

void loop() { 
// while there is data coming in, read it 
// and send to the hardware serial port: 
  if (TwoPortSerial.c() > 0) { 
    Serial.print (F("FromPort0: ")); 
    while (TwoPortSerial.available() > 0) { 
        char inByte = TwoPortSerial.read(); 
        Serial.write(inByte); 
      }
      Serial.println(); 
    } 

  if (TwoPortSerial.available1() > 0) { 
    Serial.print (F("FromPort1: ")); 
    while (TwoPortSerial.available1() > 0) { 
        char inByte = TwoPortSerial.read1(); 
        Serial.write(inByte); 
      } 
      Serial.println(); 
   } 
   delay (50); // Slow down! 
}

Mejorando un lector RFID de 125Khz RDM6300

He comprado un par de lectores RFID de 125Khz modelo RDM6300 V3.1 para un proyecto de control de accesos. https://www.amazon.es/dp/B00K8R7FR6
Son muy fáciles de usar y se encuentra bastante documentación en internet:

Pero la sensibilidad de lectura es bastante baja, aunque promete leer las tarjetas desde 15mm, solo llega a 10mm. En cualquier caso 15mm es una distancia de lectura bastante baja, obliga a pegar la tarjeta contra la carcasa del lector y no permite leerlas si estan guardadas en una cartera abultada o en una mochila.

He pensado que sería posible aumentar la distancia con alguna modificación, en primer lugar he obtenido el esquema aproximado de la placa:

No he medido muchos componentes, pero no es relevante para entender el funcionamiento. La primera modificación que se me ha ocurrido es alimentar la bobina desde 5V en lugar de hacerlo desde 3,3V. Esto puede hacerse desoldando una pata de la boina de choque SMD que alimenta el emisor del transistor PNP y soldando un hilo a +5V. Aumenta un poco la sensibilidad pero no es relevante.

La solución óptima es usar una antena mejor. La antena que se suministra con el módulo es de pequeño tamaño, de hilo de 0,24mm de diámetro. Despues de probar con distintas antenas he encontrado una excelente: esta construida con hilo de 0,3mm de diámeto y consta de 60 espiras sobre un soporte de 60mm de diámetro.

El resultado es espectacular, con la antena original la señal en la antena es de 20V pp:

Con la antena de 60mm de diámetro de 60 espiras la tensión sube hasta 60V pp, quizás hasta demasiado para los transistores S8050 y S8550 (VCE de 25), pero funciona!! La distancia de detección es ahora de 60mm. Ahora puede leer tarjetas guardadas en una cartera dentro de una mochila!!

Para probar el módulo he usado un arduino UNO con el PIN 2 conectado a la salida TX del módulo. El módulo se alimenta entre GND y +5V del arduino. El programa de test es este: Rdm6300Test

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: https://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!