kopia lustrzana https://github.com/OpenRTX/OpenRTX
Implementation of xmodem data reception
rodzic
48824accb9
commit
f513454acf
|
|
@ -37,6 +37,15 @@ extern "C" {
|
|||
*/
|
||||
void xmodem_sendPacket(const void *data, size_t size, uint8_t blockNum);
|
||||
|
||||
/**
|
||||
* Receive an XMODEM packet from the serial port.
|
||||
*
|
||||
* @param data: pointer to a buffer for payload data.
|
||||
* @param expectedBlockNum: expected block number, for sanity check.
|
||||
* @return number of bytes received or zero in case of errors.
|
||||
*/
|
||||
size_t xmodem_receivePacket(void *data, uint8_t expectedBlockNum);
|
||||
|
||||
/**
|
||||
* Send data using the XMODEM protocol, blocking function.
|
||||
* Data transfer begins when the start command from the receiving endpoint is
|
||||
|
|
@ -45,9 +54,20 @@ void xmodem_sendPacket(const void *data, size_t size, uint8_t blockNum);
|
|||
* @param size: data size.
|
||||
* @param callback: pointer to a callback function in charge of providing data
|
||||
* for the new packets being sent.
|
||||
* @return number of bytes sent.
|
||||
*/
|
||||
ssize_t xmodem_sendData(size_t size, int (*callback)(uint8_t *, size_t));
|
||||
|
||||
/**
|
||||
* Receive data using the XMODEM protocol, blocking function.
|
||||
* Transfer starts immediately when this function is called.
|
||||
*
|
||||
* @param size: expected data size, in bytes.
|
||||
* @param callback: callback function invoked when a new data block is recevied.
|
||||
* @return number of bytes received.
|
||||
*/
|
||||
ssize_t xmodem_receiveData(size_t size, void (*callback)(uint8_t *, size_t));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,16 +25,15 @@
|
|||
#include <string.h>
|
||||
#include <crc.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 */
|
||||
|
||||
#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
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
|
@ -86,6 +85,39 @@ void xmodem_sendPacket(const void *data, size_t size, uint8_t blockNum)
|
|||
vcom_writeBlock(buf, 2);
|
||||
}
|
||||
|
||||
size_t xmodem_receivePacket(void* data, uint8_t expectedBlockNum)
|
||||
{
|
||||
// Get first byte
|
||||
uint8_t status = 0;
|
||||
while((status != STX) && (status != SOH))
|
||||
{
|
||||
waitForData(&status, 1);
|
||||
}
|
||||
|
||||
// Get sequence number
|
||||
uint8_t seq[2] = {0};
|
||||
waitForData(seq, 2);
|
||||
|
||||
// Determine payload size and get data
|
||||
size_t blockSize = 128;
|
||||
if(status == STX) blockSize = 1024;
|
||||
waitForData(((uint8_t *) data), blockSize);
|
||||
|
||||
// Get CRC
|
||||
uint8_t crc[2] = {0};
|
||||
waitForData(crc, 2);
|
||||
|
||||
// First sanity check: sequence number
|
||||
if((seq[0] ^ seq[1]) != 0xFF) return 0;
|
||||
if(expectedBlockNum != seq[0]) return 0;
|
||||
|
||||
// Second sanity check: CRC
|
||||
uint16_t dataCrc = crc_ccitt(data, blockSize);
|
||||
if((crc[0] != (dataCrc >> 8)) || (crc[1] != (dataCrc & 0xFF))) return 0;
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
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.
|
||||
|
|
@ -158,3 +190,52 @@ ssize_t xmodem_sendData(size_t size, ssize_t (*callback)(uint8_t *, size_t))
|
|||
|
||||
return sentSize;
|
||||
}
|
||||
|
||||
ssize_t xmodem_receiveData(size_t size, void (*callback)(uint8_t *, size_t))
|
||||
{
|
||||
uint8_t dataBuf[1024];
|
||||
uint8_t command = 0;
|
||||
uint8_t blockNum = 1;
|
||||
size_t rcvdSize = 0;
|
||||
|
||||
// Request data transfer in CRC mode
|
||||
command = CRC;
|
||||
vcom_writeBlock(&command, 1);
|
||||
|
||||
while(rcvdSize < size)
|
||||
{
|
||||
size_t blockSize = xmodem_receivePacket(dataBuf, blockNum);
|
||||
if(blockSize == 0)
|
||||
{
|
||||
// Bad packet, send NACK
|
||||
command = NAK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// New data arrived
|
||||
size_t delta = size - rcvdSize;
|
||||
if(blockSize < delta) delta = blockSize;
|
||||
callback(dataBuf, delta);
|
||||
|
||||
rcvdSize += delta;
|
||||
blockNum++;
|
||||
|
||||
// ACK and go on
|
||||
command = ACK;
|
||||
}
|
||||
|
||||
vcom_writeBlock(&command, 1);
|
||||
}
|
||||
|
||||
// Wait for EOT from the sender, ACK and return
|
||||
uint8_t status = 0;
|
||||
while(status != EOT)
|
||||
{
|
||||
waitForData(&status, 1);
|
||||
}
|
||||
|
||||
command = ACK;
|
||||
vcom_writeBlock(&command, 1);
|
||||
|
||||
return rcvdSize;
|
||||
}
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue