tuve un dolor de cabeza similar, pero con CashFlow de la serie SC que son para billetes.
Para trabajar con CashFlow (protocolo MDB), el desafío es que usa 9 bits (8 de datos + 1 de modo). El ESP32 puede manejarlo, pero la configuración cambia según lo que quieras hacer.
Imaginate que vos sos el monedero, el bus MDB es forosdeelectronica donde todos hablan a la vez en este mismo topico. Para que el monedero sepa cuándo le están hablando a el y no enviándole simples datos, se usa un 9º bit...
Otro dolor de cabeza que subestime en un principio: "El Checksum"... Es una suma de control para asegurar que el mensaje no se corrompió en el camino. Como lo haces? Simplemente sumas todos los bytes que enviaste antes del final tomando como regla:
Ahora, vamos a tu sketch. lo que veo ahora, es un simple el error en la lógica de acceso al array dentro de tu if. Estás comparando el puntero del array (b) en lugar del elemento específico en la posición i.
Los puntos críticos a corregir:
Error de sintaxis en tu linea: if ((b == 0x1E || b == 0x9E)...) debe ser if ((b
== 0x1E || b == 0x9E)...). Sin el índice , el código nunca entrará a la condición y de seguro te van aparecer cosas raras...
Protocolo MDB (Nivel Físico): Los monederos CashFlow usan el protocolo MDB, que trabaja a 9600 baudios pero con 9 bits de datos (el 9º bit es el "Mode Bit"). El hardware del ESP32 soporta 9 bits, pero tu configuración actual está en UART_DATA_8_BITS, o sea, vos mismo te estas generando un cuello de botella con la contradiccion.
Lo otro que note, es que en tu logica del loop es que al usar uart_read_bytes con un timeout, podrías estar cortando tramas a la mitad. Para MDB, lo ideal es usar el modo de 9 bits y detectar el bit de dirección. En este punto coincido con Dark.
Primer paso:
Código:
// Cambia la línea del IF por esta:
if ((b[i] == 0x1E || b[i] == 0x9E) && b[i+1] == 0xFF) {
Te muestro dos ejemplos sencillos para que hagas pruebas de comunicacion... Si solo queres escucharlo, un sketch base podria ser este:
CSS:
#include <Arduino.h>
#include "driver/uart.h"
#define RX_PIN 18
#define TX_PIN 17
#define UART_PORT UART_NUM_1
void setup() {
Serial.begin(115200);
uart_config_t uart_config = {
.baud_rate = 9600,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE, // En sniffer, ignoramos el 9º bit por ahora
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
uart_driver_install(UART_PORT, 2048, 0, 0, NULL, 0);
uart_param_config(UART_PORT, &uart_config);
// Inversión para el optoacoplador 6N137
uart_set_line_inverse(UART_PORT, UART_SIGNAL_RXD_INV);
uart_set_pin(UART_PORT, TX_PIN, RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
Serial.println(">>> MODO SNIFFER MDB ACTIVO");
}
void loop() {
uint8_t data[128];
int length = uart_read_bytes(UART_PORT, data, 128, 20 / portTICK_PERIOD_MS);
if (length > 0) {
Serial.print("Trama detectada: ");
for (int i = 0; i < length; i++) {
// Corregido: Acceso por índice [i]
if (data[i] == 0x1E || data[i] == 0x9E) {
Serial.print("[DIR] ");
}
Serial.printf("%02X ", data[i]);
}
Serial.println();
}
}
Ahora, veo que estas usando el 6N137 y no se si estas teniendo en cuenta que la señal TX se invierte; Fijate en este ejemplo para escuchar y controlar, te añadí una linea justamente para trabajar esto "UART_SIGNAL_TXD_INV"... Mas que nada es para que el monedero entienda lo que el ESP32 envía.
CSS:
#include <Arduino.h>
#include "driver/uart.h"
#define RX_PIN 18
#define TX_PIN 17
#define UART_PORT UART_NUM_1
// Función para enviar comando MDB (Primer byte con bit de modo en 1)
void mdb_send_command(uint8_t addr, uint8_t* data, uint8_t len)
{
// 1. Enviar Dirección con bit de modo en 1 (usando paridad MARK)
uart_set_parity(UART_PORT, UART_PARITY_MARK);
uart_write_bytes(UART_PORT, (const char*)&addr, 1);
uart_wait_tx_done(UART_PORT, 10);
// 2. Enviar Datos con bit de modo en 0 (usando paridad SPACE)
if (len > 0) {
uart_set_parity(UART_PORT, UART_PARITY_SPACE);
uart_write_bytes(UART_PORT, (const char*)data, len);
uart_wait_tx_done(UART_PORT, 10);
}
// Calcular y enviar Checksum aquí si es necesario...
}
void setup()
{
Serial.begin(115200);
uart_config_t uart_config =
{
.baud_rate = 9600,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_MARK, // Iniciamos en modo dirección
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
uart_driver_install(UART_PORT, 1024, 1024, 0, NULL, 0);
uart_param_config(UART_PORT, &uart_config);
uart_set_line_inverse(UART_PORT, UART_SIGNAL_RXD_INV | UART_SIGNAL_TXD_INV); // Invertir ambos para 6N137
uart_set_pin(UART_PORT, TX_PIN, RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}
void loop()
{
// Ejemplo: Enviar comando POLL al monedero (Dirección 0x08 para CashFlow)
if (Serial.available()) {
char c = Serial.read();
if (c == 'p') { // Si presionas 'p' en el monitor serial
Serial.println("Enviando POLL...");
uint8_t poll_cmd = 0x08;
mdb_send_command(poll_cmd, NULL, 0);
}
}
// Lectura de respuesta
uint8_t buffer[64];
int len = uart_read_bytes(UART_PORT, buffer, 64, 10 / portTICK_PERIOD_MS);
if (len > 0)
{
Serial.print("Respuesta Monedero: ");
for(int i=0; i<len; i++) Serial.printf("%02X ", buffer[i]);
Serial.println();
}
}
No obvies el MDB Checksum... Tene en cuenta que cada trama MDB termina con un byte de Checksum (la suma de todos los bytes anteriores truncada a 8 bits) como te explique anteriormente. Sin esto, el monedero va a ignorar tus comandos.