From 7e3131d9d1a6727c3a6d9b14c94682babbeff3b4 Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Sat, 12 Mar 2022 23:32:31 +0100 Subject: [PATCH] Implemented xmodem data sending --- openrtx/include/core/xmodem.h | 18 ++++++ openrtx/src/core/xmodem.c | 100 +++++++++++++++++++++++++++-- tests/platform/xmodem_flash_dump.c | 69 ++++---------------- 3 files changed, 125 insertions(+), 62 deletions(-) diff --git a/openrtx/include/core/xmodem.h b/openrtx/include/core/xmodem.h index ae191d97..d6e250a2 100644 --- a/openrtx/include/core/xmodem.h +++ b/openrtx/include/core/xmodem.h @@ -28,8 +28,26 @@ extern "C" { #endif +/** + * Send an XMODEM packet over the serial port. + * + * @param data: pointer to payload data. + * @param size: data size, must be either 128 or 1024 byte. + * @param blockNum: packet sequence number. + */ void xmodem_sendPacket(const void *data, size_t size, uint8_t blockNum); +/** + * Send data using the XMODEM protocol, blocking function. + * Data transfer begins when the start command from the receiving endpoint is + * detected. + * + * @param size: data size. + * @param callback: pointer to a callback function in charge of providing data + * for the new packets being sent. + */ +ssize_t xmodem_sendData(size_t size, int (*callback)(uint8_t *, size_t)); + #ifdef __cplusplus } #endif diff --git a/openrtx/src/core/xmodem.c b/openrtx/src/core/xmodem.c index 1928a64f..6f53ca00 100644 --- a/openrtx/src/core/xmodem.c +++ b/openrtx/src/core/xmodem.c @@ -18,11 +18,12 @@ * along with this program; if not, see * ***************************************************************************/ -#include +#include +#include +#include #include #include -#include -#include +#include #define SOH (0x01) /* start of 128-byte data packet */ #define STX (0x02) /* start of 1024-byte data packet */ @@ -35,11 +36,29 @@ #define ABT2 (0x61) /* 'a' == 0x61, assume try abort by user typing */ +/** + * @internal + * Collect a given amount of data from serial port. + * + * @param ptr: pointer to destination buffer. + * @param size: number of bytes to be retrieved. + */ +static void waitForData(uint8_t *ptr, size_t size) +{ + size_t curSize = 0; + + while(curSize < size) + { + ssize_t recvd = vcom_readBlock(ptr + curSize, size - curSize); + if(recvd >= 0) curSize += recvd; + } +} + void xmodem_sendPacket(const void *data, size_t size, uint8_t blockNum) { // Bad payload size, null block number or null data pointer: do not send - if(((size != 128) && (size != 1024)) || (blockNum == 0) || (data == NULL)) + if(((size != 128) && (size != 1024)) || (data == NULL)) { return; } @@ -66,3 +85,76 @@ void xmodem_sendPacket(const void *data, size_t size, uint8_t blockNum) buf[1] = crc & 0xFF; vcom_writeBlock(buf, 2); } + +ssize_t xmodem_sendData(size_t size, ssize_t (*callback)(uint8_t *, size_t)) +{ + // Wait for the start command from the receiver, only CRC mode is supported. + uint8_t cmd = 0; + while(cmd != CRC) + { + waitForData(&cmd, 1); + } + + // Send data. + uint8_t dataBuf[1024]; + uint8_t blockNum = 1; + size_t sentSize = 0; + + while(sentSize < size) + { + size_t remaining = size - sentSize; + size_t blockSize = 1024; + if(remaining < blockSize) blockSize = remaining; + + // Request data, stop transfer on failure + if(callback(dataBuf, blockSize) < 0) + { + cmd = CAN; + vcom_writeBlock(&cmd, 1); + return -1; + } + + // Pad data to 128 or 1024 bytes, if necessary + size_t padSize = 0; + if(blockSize < 128) + { + padSize = 128 - blockSize; + } + else if(blockSize < 1024) + { + padSize = 1024 - blockSize; + } + + uint8_t *ptr = dataBuf + padSize + 1; + memset(ptr, 0x1A, padSize); + + // Send packet and wait for ACK, resend on NACK. + bool ok = false; + do + { + blockSize += padSize; + xmodem_sendPacket(dataBuf, blockSize, blockNum); + + cmd = 0; + while((cmd != ACK) && (cmd != NAK)) + { + waitForData(&cmd, 1); + if(cmd == ACK) ok = true; + } + } + while(ok == false); + + sentSize += blockSize - padSize; + blockNum++; + } + + // End of transfer + cmd = EOT; + vcom_writeBlock(&cmd, 1); + while(cmd != ACK) + { + waitForData(&cmd, 1); + } + + return sentSize; +} diff --git a/tests/platform/xmodem_flash_dump.c b/tests/platform/xmodem_flash_dump.c index d72f5d17..1c78662f 100644 --- a/tests/platform/xmodem_flash_dump.c +++ b/tests/platform/xmodem_flash_dump.c @@ -24,20 +24,18 @@ #include #include #include "W25Qx.h" -#include "usb_vcom.h" - -#define SOH (0x01) /* start of 128-byte data packet */ -#define STX (0x02) /* start of 1024-byte data packet */ -#define EOT (0x04) /* End Of Transmission */ -#define ACK (0x06) /* ACKnowledge, receive OK */ -#define NAK (0x15) /* Negative ACKnowledge, receiver ERROR, retry */ -#define CAN (0x18) /* two CAN in succession will abort transfer */ -#define CRC (0x43) /* 'C' == 0x43, request 16-bit CRC, use in place of first NAK for CRC mode */ -#define ABT1 (0x41) /* 'A' == 0x41, assume try abort by user typing */ -#define ABT2 (0x61) /* 'a' == 0x61, assume try abort by user typing */ static const size_t FLASH_SIZE = 16*1024*1024; /* 16MB */ -uint8_t blockData[1024]; +size_t addr = 0; + +int callback(uint8_t *ptr, size_t size) +{ + if((addr + size) > FLASH_SIZE) return -1; + W25Qx_readData(addr, ptr, size); + addr += size; + return 0; +} + int main() { @@ -45,52 +43,7 @@ int main() W25Qx_init(); W25Qx_wakeup(); - uint8_t cmd = 0; - while(cmd != 'C') - { - platform_ledOn(GREEN); - sleepFor(0,50); - platform_ledOff(GREEN); - sleepFor(0,50); - vcom_readBlock(&cmd, 1); - } - - - uint8_t block = 1; - for(size_t addr = 0; addr < FLASH_SIZE; ) - { - W25Qx_readData(addr, blockData, 1024); - - bool ok = false; - do - { - xmodem_sendPacket(blockData, 1024, block); - - cmd = 0; - while((cmd != ACK) && (cmd != NAK)) - { - platform_ledOn(RED); - sleepFor(0,50); - platform_ledOff(RED); - sleepFor(0,50); - vcom_readBlock(&cmd, 1); - - if(cmd == ACK) ok = true; - } - } - while(ok == false); - - block++; - if(block == 255) block = 1; - addr += 1024; - } - - cmd = EOT; - vcom_writeBlock(&cmd, 1); - while(cmd != ACK) - { - vcom_readBlock(&cmd, 1); - } + xmodem_sendData(FLASH_SIZE, callback); while(1) {