diff --git a/libnfc/buses/uart.c b/libnfc/buses/uart.c index aad519f..c5cb3d0 100644 --- a/libnfc/buses/uart.c +++ b/libnfc/buses/uart.c @@ -97,8 +97,6 @@ struct serial_port_unix { int fd; // Serial port file descriptor struct termios termios_backup; // Terminal info before using the port struct termios termios_new; // Terminal info during the transaction - int pins_backup; - int pins_new; }; #define UART_DATA( X ) ((struct serial_port_unix *) X) @@ -144,10 +142,6 @@ uart_open(const char *pcPortName) return INVALID_SERIAL_PORT; } - ioctl(sp->fd, TIOCMGET, &sp->pins_backup); - sp->pins_new = sp->pins_backup; - uart_set_pins(sp, 0); - return sp; } @@ -287,13 +281,11 @@ uart_get_speed(serial_port sp) } void -uart_close_ext(const serial_port sp, const bool restore_status) +uart_close_ext(const serial_port sp, const bool restore_termios) { if (UART_DATA(sp)->fd >= 0) { - if (restore_status) { + if (restore_termios) tcsetattr(UART_DATA(sp)->fd, TCSANOW, &UART_DATA(sp)->termios_backup); - ioctl(UART_DATA(sp)->fd, TIOCMSET, &UART_DATA(sp)->pins_backup); - } close(UART_DATA(sp)->fd); } free(sp); @@ -395,36 +387,6 @@ uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) return NFC_EIO; } -/** - * @brief Asserts/deasserts asynchronous control signals of RS232 ports - * - * @return 0 on success, otherwise a driver error is returned - */ -int -uart_set_pins(serial_port sp, int status) -{ - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "DTR: %d RTS: %d", (status & UART_DTR) ? 1 : 0, (status & UART_RTS) ? 1 : 0); - - int posix = 0; - if (status & UART_DTR) - posix |= TIOCM_DTR; - if (status & UART_RTS) - posix |= TIOCM_RTS; - - /* TODO - Uncomment after fixing Cygwin tcgetattr, which modifies pin status on its own - if (UART_DATA(sp)->pins_new == posix) - return NFC_SUCCESS; - */ - - if (ioctl(UART_DATA(sp)->fd, TIOCMSET, &posix) == -1) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set asynchronous control pins."); - return NFC_EIO; - } - - UART_DATA(sp)->pins_new = posix; - return NFC_SUCCESS; -} - char ** uart_list_ports(void) { diff --git a/libnfc/buses/uart.h b/libnfc/buses/uart.h index f7ae66c..712ef49 100644 --- a/libnfc/buses/uart.h +++ b/libnfc/buses/uart.h @@ -57,10 +57,6 @@ uint32_t uart_get_speed(const serial_port sp); int uart_receive(serial_port sp, uint8_t *pbtRx, const size_t szRx, void *abort_p, int timeout); int uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout); -#define UART_DTR (1 << 0) -#define UART_RTS (1 << 1) -int uart_set_pins(serial_port sp, int status); - char **uart_list_ports(void); void uart_list_free(char **acPorts); diff --git a/libnfc/chips/pn53x.c b/libnfc/chips/pn53x.c index d76006a..f635a86 100644 --- a/libnfc/chips/pn53x.c +++ b/libnfc/chips/pn53x.c @@ -333,6 +333,7 @@ pn53x_transceive(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx }; if (res < 0) { + pnd->last_error = res; log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Chip error: \"%s\" (%02x), returned error: \"%s\" (%d))", pn53x_strerror(pnd), CHIP_DATA(pnd)->last_status_byte, nfc_strerror(pnd), res); } return res; diff --git a/libnfc/chips/rc522-internal.h b/libnfc/chips/rc522-internal.h index 23a91e4..093a5ff 100644 --- a/libnfc/chips/rc522-internal.h +++ b/libnfc/chips/rc522-internal.h @@ -28,6 +28,7 @@ typedef enum { #define REG_CommandReg 0x01 #define REG_CommandReg_RcvOff (1 << 5) #define REG_CommandReg_PowerDown (1 << 4) +#define REG_CommandReg_Command_MASK 0x0F #define REG_ComlEnReg 0x02 @@ -49,6 +50,7 @@ typedef enum { #define REG_FIFODataReg 0x09 #define REG_FIFOLevelReg 0x0A +#define REG_FIFOLevelReg_FlushBuffer (1 << 7) #define REG_WaterLevelReg 0x0B diff --git a/libnfc/chips/rc522.c b/libnfc/chips/rc522.c index 5ba222f..aeb4fb1 100644 --- a/libnfc/chips/rc522.c +++ b/libnfc/chips/rc522.c @@ -35,7 +35,7 @@ const nfc_baud_rate rc522_iso14443a_supported_baud_rates[] = { NBR_847, NBR_424, struct rc522_chip_data { const struct rc522_io * io; - rc522_type version; + uint8_t version; }; #define CHIP_DATA(x) ((struct rc522_chip_data *) (x)->chip_data) @@ -59,7 +59,7 @@ void rc522_data_free(struct nfc_device * pnd) { int rc522_read_bulk(struct nfc_device * pnd, uint8_t reg, uint8_t * val, size_t len) { int ret = CHIP_DATA(pnd)->io->read(pnd, reg, val, len); if (ret) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to read register %02X!", reg); + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to read register %02X (err: %d)", reg, ret); return ret; } @@ -113,7 +113,7 @@ int rc522_write_reg(struct nfc_device * pnd, uint8_t reg, uint8_t val, uint8_t m } int rc522_start_command(struct nfc_device * pnd, rc522_cmd cmd) { - bool needsRX = false; + bool needsRX; // Disabling RX saves energy, so based on the command we'll also update the RxOff flag switch (cmd) { @@ -123,6 +123,7 @@ int rc522_start_command(struct nfc_device * pnd, rc522_cmd cmd) { case CMD_CALCCRC: case CMD_TRANSMIT: case CMD_SOFTRESET: + needsRX = false; break; case CMD_RECEIVE: @@ -136,8 +137,7 @@ int rc522_start_command(struct nfc_device * pnd, rc522_cmd cmd) { default: log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Attempted to execute non-existant command: %02X", cmd); - pnd->last_error = NFC_ESOFT; - return pnd->last_error; + return NFC_ESOFT; } uint8_t regval = cmd; @@ -153,9 +153,6 @@ int rc522_wait_wakeup(struct nfc_device * pnd) { timeout_t to; timeout_init(&to, 50); - // rc522_read_reg updates last_error. Backup it to ignore timeouts - int last_error = pnd->last_error; - while (timeout_check(&to)) { int ret = rc522_read_reg(pnd, REG_CommandReg); if (ret < 0 && ret != NFC_ETIMEOUT) { @@ -164,19 +161,68 @@ int rc522_wait_wakeup(struct nfc_device * pnd) { // If the powerdown bit is zero the RC522 is ready to kick asses! if ((ret & REG_CommandReg_PowerDown) == 0) { - pnd->last_error = last_error; return NFC_SUCCESS; } } - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "rc522_wait_wakeup timeout!"); - pnd->last_error = NFC_ETIMEOUT; - return pnd->last_error; + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_wait_wakeup timeout!"); + return NFC_ETIMEOUT; +} + +int rc522_send_baudrate(struct nfc_device * pnd, uint32_t baudrate) { + uint8_t regval; + + // MFRC522 datasheet 8.1.3.2 + switch (baudrate) { + case 7200: + regval = 0xFA; + break; + case 9600: + regval = 0xEB; + break; + case 14400: + regval = 0xDA; + break; + case 19200: + regval = 0xCB; + break; + case 38400: + regval = 0xAB; + break; + case 57600: + regval = 0x9A; + break; + case 115200: + regval = 0x7A; + break; + case 128000: + regval = 0x74; + break; + case 230400: + regval = 0x5A; + break; + case 460800: + regval = 0x3A; + break; + case 921600: + regval = 0x1C; + break; + case 1288000: + regval = 0x15; + break; + default: + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "rc522_write_baudrate unsupported baud rate: %d bps.", baudrate); + return NFC_EDEVNOTSUPP; + } + + return rc522_write_reg(pnd, REG_SerialSpeedReg, regval, 0xFF); } int rc522_soft_reset(struct nfc_device * pnd) { return + // 1. Send soft reset rc522_start_command(pnd, CMD_SOFTRESET) || + CHIP_DATA(pnd)->io->reset_baud_rate(pnd) || rc522_wait_wakeup(pnd); } @@ -319,11 +365,7 @@ int rc522_set_property_bool(struct nfc_device * pnd, const nfc_property property return NFC_SUCCESS; } - int ret = rc522_set_baud_rate(pnd, NBR_106); - if (ret) { - pnd->last_error = ret; - } - return ret; + return rc522_set_baud_rate(pnd, NBR_106); case NP_ACCEPT_MULTIPLE_FRAMES: case NP_AUTO_ISO14443_4: @@ -333,11 +375,9 @@ int rc522_set_property_bool(struct nfc_device * pnd, const nfc_property property case NP_TIMEOUT_COMMAND: case NP_TIMEOUT_ATR: case NP_TIMEOUT_COM: - pnd->last_error = NFC_EINVARG; return NFC_EINVARG; } - pnd->last_error = NFC_EINVARG; return NFC_EINVARG; } @@ -347,11 +387,13 @@ int rc522_set_property_int(struct nfc_device * pnd, const nfc_property property, } int rc522_abort(struct nfc_device * pnd) { - return rc522_start_command(pnd, CMD_IDLE); + return + rc522_start_command(pnd, CMD_IDLE) || + rc522_write_reg(pnd, REG_FIFOLevelReg, REG_FIFOLevelReg_FlushBuffer, 0xFF); } int rc522_powerdown(struct nfc_device * pnd) { - return rc522_write_reg(pnd, REG_CommandReg, REG_CommandReg_RcvOff | REG_CommandReg_PowerDown | CMD_IDLE, 0xFF); + return rc522_write_reg(pnd, REG_CommandReg, REG_CommandReg_RcvOff | REG_CommandReg_PowerDown | CMD_NOCMDCHANGE, 0xFF); } // NXP MFRC522 datasheet section 16.1.1 @@ -368,22 +410,9 @@ const uint8_t MFRC522_V2_SELFTEST[FIFO_SIZE] = { 0x86, 0x96, 0x83, 0x38, 0xCF, 0x9D, 0x5B, 0x6D, 0xDC, 0x15, 0xBA, 0x3E, 0x7D, 0x95, 0x3B, 0x2F }; -// Extracted from a FM17522 with version 0x88. Fudan Semiconductor datasheet does not include it, though. -const uint8_t FM17522_SELFTEST[FIFO_SIZE] = { - 0x00, 0xD6, 0x78, 0x8C, 0xE2, 0xAA, 0x0C, 0x18, 0x2A, 0xB8, 0x7A, 0x7F, 0xD3, 0x6A, 0xCF, 0x0B, - 0xB1, 0x37, 0x63, 0x4B, 0x69, 0xAE, 0x91, 0xC7, 0xC3, 0x97, 0xAE, 0x77, 0xF4, 0x37, 0xD7, 0x9B, - 0x7C, 0xF5, 0x3C, 0x11, 0x8F, 0x15, 0xC3, 0xD7, 0xC1, 0x5B, 0x00, 0x2A, 0xD0, 0x75, 0xDE, 0x9E, - 0x51, 0x64, 0xAB, 0x3E, 0xE9, 0x15, 0xB5, 0xAB, 0x56, 0x9A, 0x98, 0x82, 0x26, 0xEA, 0x2A, 0x62 -}; - int rc522_self_test(struct nfc_device * pnd) { - int version = rc522_read_reg(pnd, REG_VersionReg); - if (version < 0) { - return version; - } - const uint8_t * correct; - switch (version) { + switch (CHIP_DATA(pnd)->version) { case MFRC522_V1: correct = MFRC522_V1_SELFTEST; break; @@ -392,20 +421,17 @@ int rc522_self_test(struct nfc_device * pnd) { correct = MFRC522_V2_SELFTEST; break; - case FM17522: - correct = FM17522_SELFTEST; - break; - default: - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unknown chip version: 0x%02X", version); - return NFC_ECHIP; + return NFC_EDEVNOTSUPP; } - int ret; + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Executing self test"); + uint8_t zeroes[25]; memset(zeroes, 0x00, sizeof(zeroes)); + // MFRC522 datasheet section 16.1.1 - ret = + int ret = // 1. Perform a soft reset rc522_soft_reset(pnd) || // 2. Clear the internal buffer by writing 25 bytes of 0x00 and execute the Mem command @@ -422,9 +448,9 @@ int rc522_self_test(struct nfc_device * pnd) { } // 6. Wait for the RC522 to calculate the selftest values - // The official datasheet does not mentions how much time does it take, let's use 5ms + // The official datasheet does not mentions how much time does it take, let's use 50ms timeout_t to; - timeout_init(&to, 5); + timeout_init(&to, 50); while (1) { if (!timeout_check(&to)) { @@ -455,7 +481,5 @@ int rc522_self_test(struct nfc_device * pnd) { return NFC_ECHIP; } - CHIP_DATA(pnd)->version = version; return NFC_SUCCESS; } - diff --git a/libnfc/chips/rc522.h b/libnfc/chips/rc522.h index c266f55..d8ee526 100644 --- a/libnfc/chips/rc522.h +++ b/libnfc/chips/rc522.h @@ -25,12 +25,14 @@ struct rc522_io { int (*read)(struct nfc_device * pnd, uint8_t reg, uint8_t * data, size_t size); int (*write)(struct nfc_device * pnd, uint8_t reg, const uint8_t * data, size_t size); + int (*reset_baud_rate)(struct nfc_device * pnd); }; int rc522_data_new(struct nfc_device * pnd, const struct rc522_io * io); void rc522_data_free(struct nfc_device * pnd); int rc522_self_test(struct nfc_device * pnd); int rc522_wait_wakeup(struct nfc_device * pnd); +int rc522_send_baudrate(struct nfc_device * pnd, uint32_t baudrate); int rc522_get_supported_modulation(nfc_device * pnd, const nfc_mode mode, const nfc_modulation_type ** const supported_mt); int rc522_get_supported_baud_rate(nfc_device * pnd, const nfc_mode mode, const nfc_modulation_type nmt, const nfc_baud_rate ** const supported_br); diff --git a/libnfc/drivers/rc522_uart.c b/libnfc/drivers/rc522_uart.c index b3d9975..e9ceed5 100644 --- a/libnfc/drivers/rc522_uart.c +++ b/libnfc/drivers/rc522_uart.c @@ -38,7 +38,8 @@ #include "chips/rc522.h" #include "uart.h" -#define RC522_UART_DEFAULT_SPEED 9600 +#define RC522_UART_BOOT_SPEED 9600 +#define RC522_UART_DEFAULT_SPEED 115200 #define RC522_UART_DRIVER_NAME "rc522_uart" #define RC522_UART_IO_TIMEOUT 50 @@ -49,76 +50,173 @@ const struct rc522_io rc522_uart_io; struct rc522_uart_data { serial_port port; + uint32_t baudrate; }; #define DRIVER_DATA(pnd) ((struct rc522_uart_data*)(pnd->driver_data)) -void rc522_uart_close(nfc_device * pnd) { -// rc522_idle(pnd); +int rc522_uart_wakeup(struct nfc_device * pnd) { + int ret; + /* High Speed Unit (HSU) wake up consist to send 0x55 and wait a "long" delay for RC522 being wakeup. */ + const uint8_t rc522_wakeup_preamble[] = { 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + ret = uart_send(DRIVER_DATA(pnd)->port, rc522_wakeup_preamble, sizeof(rc522_wakeup_preamble), RC522_UART_IO_TIMEOUT); + if (ret < 0) { + return ret; + } + + return rc522_wait_wakeup(pnd); +} + +bool rc522_uart_test_baudrate(struct nfc_device * pnd, uint32_t baudrate) { + int ret; + + if ((ret = uart_set_speed(DRIVER_DATA(pnd)->port, baudrate)) < 0) { + return false; + } + + ret = rc522_wait_wakeup(pnd); + if (ret != NFC_SUCCESS) { + return false; + } + + DRIVER_DATA(pnd)->baudrate = baudrate; + return true; +} + +int rc522_uart_change_baudrate(struct nfc_device * pnd, uint32_t newBaudRate) { + uint32_t oldBaudRate = DRIVER_DATA(pnd)->baudrate; + int ret; + + if (oldBaudRate == newBaudRate) { + return NFC_SUCCESS; + } + + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Switching baud rate from %dbps to %dbps.", oldBaudRate, newBaudRate); + + if ((ret = rc522_send_baudrate(pnd, newBaudRate)) < 0) { + return ret; + } + + if ((ret = uart_set_speed(DRIVER_DATA(pnd)->port, newBaudRate)) < 0) { + return ret; + } + + if ((ret = rc522_wait_wakeup(pnd)) < 0) { + return ret; + } + + DRIVER_DATA(pnd)->baudrate = newBaudRate; + return NFC_SUCCESS; +} + +void rc522_uart_close(nfc_device * pnd) { + rc522_powerdown(pnd); // Release UART port uart_close(DRIVER_DATA(pnd)->port); rc522_data_free(pnd); nfc_device_free(pnd); } +int rc522_uart_create(const nfc_context * context, const nfc_connstring connstring, const char * portPath, uint32_t userBaudRate, struct nfc_device ** pndPtr) { + int ret; + serial_port sp; + + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s.", portPath); + sp = uart_open(portPath); + if (sp == INVALID_SERIAL_PORT) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid serial port: %s", portPath); + return NFC_EIO; + } + if (sp == CLAIMED_SERIAL_PORT) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Serial port already claimed: %s", portPath); + return NFC_EIO; + } + + // We need to flush input to be sure first reply does not comes from older byte transceive + if ((ret = uart_flush_input(sp, true)) < 0) { + return ret; + } + + nfc_device * pnd = nfc_device_new(context, connstring); + if (!pnd) { + perror("nfc_device_new"); + uart_close(sp); + return NFC_ESOFT; + } + pnd->driver = &rc522_uart_driver; + + pnd->driver_data = malloc(sizeof(struct rc522_uart_data)); + + if (!pnd->driver_data) { + perror("malloc"); + uart_close(sp); + nfc_device_free(pnd); + return NFC_ESOFT; + } + DRIVER_DATA(pnd)->port = sp; + + // Alloc and init chip's data + if (rc522_data_new(pnd, &rc522_uart_io)) { + perror("rc522_data_new"); + uart_close(sp); + nfc_device_free(pnd); + return NFC_ESOFT; + } + + // Here we'll have to address several posibilities: + // - The hard reset trick did the work, and the RC522 is up and listening at 9600 + // - The hard reset didn't work, but the RC522 hasn't been used yet and therefore listens at 9600 + // - The hard reset didn't work and the RC522 is not using the default, so we'll use the custom provided baud rate + + // Let's try first with boot baud rate + if ( + !rc522_uart_test_baudrate(pnd, RC522_UART_BOOT_SPEED) && + !rc522_uart_test_baudrate(pnd, userBaudRate) + ) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Could not connect with RC522 at %d or %d bps.", RC522_UART_BOOT_SPEED, userBaudRate); + rc522_uart_close(pnd); + return NFC_EIO; + } + + // Change now the baud rate + if ((ret = rc522_uart_change_baudrate(pnd, userBaudRate)) < 0) { + rc522_uart_close(pnd); + return ret; + } + + // Now the device is awake and listening at a known baudrate, execute a selftest + // Note that some devices (FM17522 for instance) aren't able to run it + ret = rc522_self_test(pnd); + if (ret != NFC_SUCCESS && ret != NFC_EDEVNOTSUPP) { + rc522_uart_close(pnd); + return ret; + } + + *pndPtr = pnd; + return NFC_SUCCESS; +} + size_t rc522_uart_scan(const nfc_context * context, nfc_connstring connstrings[], const size_t connstrings_len) { size_t device_found = 0; - serial_port sp; char ** acPorts = uart_list_ports(); const char * acPort; size_t iDevice = 0; while ((acPort = acPorts[iDevice++])) { - sp = uart_open(acPort); - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find RC522 device on serial port: %s at %d baud.", acPort, RC522_UART_DEFAULT_SPEED); - - if (sp == INVALID_SERIAL_PORT || sp == CLAIMED_SERIAL_PORT) { - continue; - } - - // We need to flush input to be sure first reply does not comes from older byte transceive - uart_flush_input(sp, true); - // Serial port claimed but we need to check if a RC522_UART is opened. - uart_set_speed(sp, RC522_UART_DEFAULT_SPEED); - nfc_connstring connstring; snprintf(connstring, sizeof(nfc_connstring), "%s:%s:%"PRIu32, RC522_UART_DRIVER_NAME, acPort, RC522_UART_DEFAULT_SPEED); - nfc_device * pnd = nfc_device_new(context, connstring); - if (!pnd) { - perror("nfc_device_new"); - uart_close(sp); - nfc_device_free(pnd); + + nfc_device * pnd; + int ret = rc522_uart_create(context, connstring, acPort, RC522_UART_DEFAULT_SPEED, &pnd); + if (ret == NFC_ESOFT) { uart_list_free(acPorts); return 0; } - pnd->driver = &rc522_uart_driver; - - pnd->driver_data = malloc(sizeof(struct rc522_uart_data)); - if (!pnd->driver_data) { - perror("malloc"); - uart_close(sp); - nfc_device_free(pnd); - uart_list_free(acPorts); - return 0; - } - DRIVER_DATA(pnd)->port = sp; - - // Alloc and init chip's data - if (rc522_data_new(pnd, &rc522_uart_io)) { - perror("rc522_data_new"); - uart_close(sp); - nfc_device_free(pnd); - uart_list_free(acPorts); - return 0; - } - - // Check communication using self test - int res = rc522_self_test(pnd); - rc522_uart_close(pnd); - if (res < 0) { + if (ret != NFC_SUCCESS) { continue; } + rc522_uart_close(pnd); memcpy(connstrings[device_found], connstring, sizeof(nfc_connstring)); device_found++; @@ -133,10 +231,11 @@ size_t rc522_uart_scan(const nfc_context * context, nfc_connstring connstrings[] } struct nfc_device * rc522_uart_open(const nfc_context * context, const nfc_connstring connstring) { - char * port_str; - char * baud_str; + char * port_str = NULL; + char * baud_str = NULL; uint32_t baudrate; char * endptr; + struct nfc_device * pnd = NULL; int decodelvl = connstring_decode(connstring, RC522_UART_DRIVER_NAME, NULL, &port_str, &baud_str); switch (decodelvl) { @@ -162,78 +261,11 @@ struct nfc_device * rc522_uart_open(const nfc_context * context, const nfc_conns return NULL; } - serial_port sp; - struct nfc_device * pnd = NULL; - - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d baud.", port_str, baudrate); - sp = uart_open(port_str); - - if (sp == INVALID_SERIAL_PORT) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid serial port: %s", port_str); - free(port_str); - return NULL; - } - - if (sp == CLAIMED_SERIAL_PORT) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Serial port already claimed: %s", port_str); - free(port_str); - return NULL; - } - - // We need to flush input to be sure first reply does not comes from older byte transceive - uart_flush_input(sp, true); - uart_set_speed(sp, baudrate); - - // We have a connection - pnd = nfc_device_new(context, connstring); - if (!pnd) { - perror("nfc_device_new"); - free(port_str); - uart_close(sp); - return NULL; - } - - snprintf(pnd->name, sizeof(pnd->name), "%s:%s", RC522_UART_DRIVER_NAME, port_str); + rc522_uart_create(context, connstring, port_str, baudrate, &pnd); free(port_str); - pnd->driver = &rc522_uart_driver; - pnd->driver_data = malloc(sizeof(struct rc522_uart_data)); - if (!pnd->driver_data) { - perror("malloc"); - uart_close(sp); - nfc_device_free(pnd); - return NULL; - } - DRIVER_DATA(pnd)->port = sp; - - // Alloc and init chip's data - if (!rc522_data_new(pnd, &rc522_uart_io)) { - perror("rc522_data_new"); - uart_close(sp); - nfc_device_free(pnd); - return NULL; - } - - if (rc522_self_test(pnd)) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "rc522_self_test error"); - rc522_uart_close(pnd); - return NULL; - } - return pnd; } -int rc522_uart_wakeup(struct nfc_device * pnd) { - int ret; - - /* High Speed Unit (HSU) wake up consist to send 0x55 and wait a "long" delay for RC522 being wakeup. */ - const uint8_t rc522_wakeup_preamble[] = { 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - if ((ret = uart_send(DRIVER_DATA(pnd)->port, rc522_wakeup_preamble, sizeof(rc522_wakeup_preamble), 0)) < 0) { - return ret; - } - - return rc522_wait_wakeup(pnd); -} - #define READ 1 #define WRITE 0 uint8_t rc522_uart_pack(int reg, int op) { @@ -248,11 +280,11 @@ int rc522_uart_read(struct nfc_device * pnd, uint8_t reg, uint8_t * data, size_t int ret; while (size > 0) { - if ((ret = uart_send(pnd->driver_data, &cmd, 1, RC522_UART_IO_TIMEOUT)) < 0) { + if ((ret = uart_send(DRIVER_DATA(pnd)->port, &cmd, 1, RC522_UART_IO_TIMEOUT)) < 0) { goto error; } - if ((ret = uart_receive(pnd->driver_data, data, 1, NULL, RC522_UART_IO_TIMEOUT)) < 0) { + if ((ret = uart_receive(DRIVER_DATA(pnd)->port, data, 1, NULL, RC522_UART_IO_TIMEOUT)) < 0) { goto error; } @@ -264,35 +296,34 @@ int rc522_uart_read(struct nfc_device * pnd, uint8_t reg, uint8_t * data, size_t error: uart_flush_input(DRIVER_DATA(pnd)->port, true); - return pnd->last_error; + return ret; } int rc522_uart_write(struct nfc_device * pnd, uint8_t reg, const uint8_t * data, size_t size) { uint8_t cmd = rc522_uart_pack(reg, WRITE); + int ret; while (size > 0) { // First: send write request - pnd->last_error = uart_send(pnd->driver_data, &cmd, 1, RC522_UART_IO_TIMEOUT); - if (pnd->last_error < 0) { + if ((ret = uart_send(DRIVER_DATA(pnd)->port, &cmd, 1, RC522_UART_IO_TIMEOUT)) < 0) { goto error; } // Second: wait for a reply uint8_t reply; - pnd->last_error = uart_receive(pnd->driver_data, &reply, 1, NULL, RC522_UART_IO_TIMEOUT); - if (pnd->last_error < 0) { - return pnd->last_error; + if ((ret = uart_receive(DRIVER_DATA(pnd)->port, &reply, 1, NULL, RC522_UART_IO_TIMEOUT)) < 0) { + return ret; } // Third: compare sent and received. They must match. if (cmd != reply) { - pnd->last_error = NFC_EIO; + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "rc522_uart_write ack does not match (sent %02X, received %02X)", cmd, reply); + ret = NFC_ECHIP; goto error; } // Fourth: send register data - pnd->last_error = uart_send(pnd->driver_data, data, 1, RC522_UART_IO_TIMEOUT); - if (pnd->last_error < 0) { + if ((ret = uart_send(DRIVER_DATA(pnd)->port, data, 1, RC522_UART_IO_TIMEOUT)) < 0) { goto error; } @@ -304,12 +335,20 @@ int rc522_uart_write(struct nfc_device * pnd, uint8_t reg, const uint8_t * data, error: uart_flush_input(DRIVER_DATA(pnd)->port, true); - return pnd->last_error; + return ret; +} + +int rc522_uart_reset_baud_rate(struct nfc_device * pnd) { + uint32_t userBaudRate = DRIVER_DATA(pnd)->baudrate; + return + rc522_uart_test_baudrate(pnd, RC522_UART_BOOT_SPEED) || + rc522_uart_change_baudrate(pnd, userBaudRate); } const struct rc522_io rc522_uart_io = { .read = rc522_uart_read, .write = rc522_uart_write, + .reset_baud_rate = rc522_uart_reset_baud_rate, }; const struct nfc_driver rc522_uart_driver = {