Implementation of xmodem data reception
This commit is contained in:
parent
48824accb9
commit
f513454acf
|
|
@ -37,6 +37,15 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
void xmodem_sendPacket(const void *data, size_t size, uint8_t blockNum);
|
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.
|
* Send data using the XMODEM protocol, blocking function.
|
||||||
* Data transfer begins when the start command from the receiving endpoint is
|
* 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 size: data size.
|
||||||
* @param callback: pointer to a callback function in charge of providing data
|
* @param callback: pointer to a callback function in charge of providing data
|
||||||
* for the new packets being sent.
|
* for the new packets being sent.
|
||||||
|
* @return number of bytes sent.
|
||||||
*/
|
*/
|
||||||
ssize_t xmodem_sendData(size_t size, int (*callback)(uint8_t *, size_t));
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -25,16 +25,15 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <crc.h>
|
#include <crc.h>
|
||||||
|
|
||||||
#define SOH (0x01) /* start of 128-byte data packet */
|
#define SOH (0x01) // start of 128-byte data packet
|
||||||
#define STX (0x02) /* start of 1024-byte data packet */
|
#define STX (0x02) // start of 1024-byte data packet
|
||||||
#define EOT (0x04) /* End Of Transmission */
|
#define EOT (0x04) // End Of Transmission
|
||||||
#define ACK (0x06) /* ACKnowledge, receive OK */
|
#define ACK (0x06) // ACKnowledge, receive OK
|
||||||
#define NAK (0x15) /* Negative ACKnowledge, receiver ERROR, retry */
|
#define NAK (0x15) // Negative ACKnowledge, receiver ERROR, retry
|
||||||
#define CAN (0x18) /* two CAN in succession will abort transfer */
|
#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 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 ABT1 (0x41) // 'A' == 0x41, assume try abort by user typing
|
||||||
#define ABT2 (0x61) /* 'a' == 0x61, assume try abort by user typing */
|
#define ABT2 (0x61) // 'a' == 0x61, assume try abort by user typing
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
|
|
@ -86,6 +85,39 @@ void xmodem_sendPacket(const void *data, size_t size, uint8_t blockNum)
|
||||||
vcom_writeBlock(buf, 2);
|
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))
|
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.
|
// 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;
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue