5 #include "sw/device/silicon_creator/lib/xmodem.h"
8 #include "sw/device/silicon_creator/lib/drivers/uart.h"
10 #include "sw/device/silicon_creator/lib/xmodem_testlib.h"
25 kXModemSendRetries = 3,
27 kXModemShortTimeout = 100,
28 kXModemLongTimeout = 1000,
31 #ifndef XMODEM_TESTLIB
32 size_t xmodem_read(
void *iohandle, uint8_t *data,
size_t len,
33 uint32_t timeout_ms) {
35 return uart_read(data, len, timeout_ms);
38 void xmodem_write(
void *iohandle,
const uint8_t *data,
size_t len) {
40 uart_write(data, len);
44 void xmodem_putchar(
void *iohandle, uint8_t ch) {
45 xmodem_write(iohandle, &ch,
sizeof(ch));
51 static uint16_t crc16(uint16_t crc,
const void *buf,
size_t len) {
52 const uint8_t *p = (
const uint8_t *)buf;
53 for (
size_t i = 0; i < len; ++i, ++p) {
55 for (
size_t j = 0; j < 8; ++j) {
56 bool msb = (crc & 0x8000) != 0;
68 static uint16_t crc16_block(
const void *buf,
size_t len,
size_t block_sz) {
69 uint16_t crc = crc16(0, buf, len);
71 for (; len < block_sz; ++len) {
72 crc = crc16(crc, &pad, 1);
77 void xmodem_recv_start(
void *iohandle) {
78 xmodem_putchar(iohandle, kXModemCrc16);
81 void xmodem_ack(
void *iohandle,
bool ack) {
82 xmodem_putchar(iohandle, ack ? kXModemAck : kXModemNak);
85 rom_error_t xmodem_recv_frame(
void *iohandle, uint32_t frame, uint8_t *data,
86 size_t *rxlen, uint8_t *unknown_rx) {
88 size_t n = xmodem_read(iohandle, &ch,
sizeof(ch), kXModemLongTimeout);
90 return kErrorXModemTimeoutStart;
91 }
else if (ch == kXModemStx || ch == kXModemSoh) {
93 size_t len = ch == kXModemStx ? 1024 : 128;
97 n = xmodem_read(iohandle, pkt,
sizeof(pkt), kXModemShortTimeout);
98 if (n !=
sizeof(pkt)) {
99 return kErrorXModemTimeoutPacket;
103 bool cancel = pkt[0] != (uint8_t)frame || pkt[0] != 255 - pkt[1];
108 n = xmodem_read(iohandle, data, len, kXModemShortTimeout * 3);
110 return kErrorXModemTimeoutData;
114 n = xmodem_read(iohandle, pkt,
sizeof(pkt), kXModemShortTimeout);
115 if (n !=
sizeof(pkt)) {
116 return kErrorXModemTimeoutCrc;
119 xmodem_cancel(iohandle);
120 return kErrorXModemCancel;
124 uint16_t crc = (uint16_t)(pkt[0] << 8 | pkt[1]);
125 uint16_t val = crc16(0, data, len);
127 return kErrorXModemCrc;
132 }
else if (ch == kXModemEof) {
133 return kErrorXModemEndOfFile;
136 *unknown_rx = (uint8_t)ch;
137 return kErrorXModemUnknown;
144 static rom_error_t xmodem_send_start(
void *iohandle, uint32_t retries) {
147 for (uint32_t i = 0; i < retries; ++i) {
148 size_t n = xmodem_read(iohandle, &ch,
sizeof(ch), kXModemLongTimeout);
155 return kErrorXModemProtocol;
159 return kErrorXModemCancel;
166 return kErrorXModemTimeoutStart;
169 void xmodem_cancel(
void *iohandle) {
170 xmodem_putchar(iohandle, kXModemCancel);
171 xmodem_putchar(iohandle, kXModemCancel);
174 static rom_error_t xmodem_send_finish(
void *iohandle) {
175 xmodem_putchar(iohandle, kXModemEof);
177 xmodem_read(iohandle, &ch,
sizeof(ch), kXModemLongTimeout);
178 if (ch != kXModemAck) {
185 static rom_error_t xmodem_send_data(
void *iohandle,
const void *data,
186 size_t len, uint32_t max_errors) {
187 const uint8_t *p = (
const uint8_t *)data;
190 uint32_t cancels = 0;
192 uint32_t block_sz = len < 1024 ? 128 : 1024;
193 uint32_t chunk = len < block_sz ? len : block_sz;
196 uint16_t crc = crc16_block(p, chunk, block_sz);
201 xmodem_putchar(iohandle, block_sz == 128 ? kXModemSoh : kXModemStx);
202 xmodem_putchar(iohandle, (uint8_t)block);
203 xmodem_putchar(iohandle, 255 - (uint8_t)block);
205 xmodem_write(iohandle, p, chunk);
207 for (uint32_t i = chunk; i < block_sz; ++i) {
208 xmodem_putchar(iohandle, 0);
211 xmodem_putchar(iohandle, crc >> 8);
212 xmodem_putchar(iohandle, crc & 0xFF);
216 size_t n = xmodem_read(iohandle, &ch,
sizeof(ch), kXModemLongTimeout);
218 return kErrorXModemTimeoutAck;
225 return kErrorXModemCancel;
232 if (errors >= max_errors) {
233 return kErrorXModemTooManyErrors;
243 rom_error_t xmodem_send(
void *iohandle,
const void *data,
size_t len) {
244 HARDENED_RETURN_IF_ERROR(xmodem_send_start(iohandle, 30));
245 HARDENED_RETURN_IF_ERROR(
246 xmodem_send_data(iohandle, data, len, kXModemMaxErrors));
247 HARDENED_RETURN_IF_ERROR(xmodem_send_finish(iohandle));