Browse Source

reimple ymodem_recv() in lib/ymodem.c

Signed-off-by: surenyi <surenyi82@163.com>
master
surenyi 5 years ago
parent
commit
d71313fa58
  1. 7
      lib/serial_ymodem.c
  2. 423
      lib/ymodem.c
  3. 2
      lib/ymodem.h
  4. 21
      targets/stm32f429-disc/cmds.c
  5. 2
      targets/stm32f429-disc/main.c

7
lib/serial_ymodem.c

@ -25,11 +25,7 @@ static int do_getc(struct ymodem_xfer *xfer, uint8_t *c, int timeout)
static int do_putc(struct ymodem_xfer *xfer, uint8_t c)
{
struct serial_ymodem *modem = (struct serial_ymodem *)xfer;
int nr;
do {
nr = serial_send_buffered(modem->uart, &c, 1);
} while (nr != 1);
serial_send_blocking(modem->uart, &c, 1);
return 0;
}
@ -69,6 +65,7 @@ int serial_ymodem_recv(struct serial *uart, void *user,
.user = user
};
serial_rx_buffer_clear(uart);
return ymodem_recv(&modem.xfer);
}

423
lib/ymodem.c

@ -40,24 +40,79 @@ static int put_byte (struct ymodem_xfer *uart, uint8_t c)
}
/**
* @brief Receive a packet from sender
* @brief Update CRC16 for input byte
* @param CRC input value
* @param input byte
* @retval None
*/
static uint16_t crc16(uint16_t crcIn, uint8_t byte)
{
uint32_t crc = crcIn;
uint32_t in = byte | 0x100;
do {
crc <<= 1;
in <<= 1;
if(in & 0x100)
++crc;
if(crc & 0x10000)
crc ^= 0x1021;
} while (!(in & 0x10000));
return crc & 0xffffu;
}
/**
* @brief Cal CRC16 for YModem Packet
* @param data
* @param length
* @param timeout
* 0: end of transmission
* -1: abort by sender
* >0: packet length
* @retval 0: normally return
* -1: timeout or packet error
* 1: abort by user
* @retval None
*/
static uint16_t do_crc16(const uint8_t* data, uint32_t size)
{
uint32_t crc = 0;
const uint8_t* dataEnd = data+size;
while(data < dataEnd)
crc = crc16(crc, *data++);
crc = crc16(crc, 0);
crc = crc16(crc, 0);
return crc&0xffffu;
}
struct rxdescr {
struct ymodem_xfer *xfer;
int last_error;
int errors;
int eot;
int abort;
uint8_t seq;
char fname[FILE_NAME_LENGTH + 1];
char fsize[FILE_SIZE_LENGTH + 1];
uint8_t data[PACKET_1K_SIZE + PACKET_OVERHEAD];
};
/*
* recv a ymodem frame over xfer.
*
* return : < 0 on error.
* : = 0 on eot or abort.
* : > 0 packet size.
*/
static int do_recv(struct ymodem_xfer *uart, uint8_t *data, int *length, uint32_t timeout)
static int recv_frame(struct rxdescr *rx, uint32_t timeout)
{
uint16_t i, packet_size;
uint8_t c;
*length = 0;
uint16_t ccs, rcs;
int i = 0, packet_size;
if (get_byte(uart, &c, timeout) != 0) {
if (get_byte(rx->xfer, &c, timeout) != 0) {
return -1;
}
@ -69,140 +124,225 @@ static int do_recv(struct ymodem_xfer *uart, uint8_t *data, int *length, uint32_
packet_size = PACKET_1K_SIZE;
break;
case EOT:
++rx->eot;
return 0;
case CA:
if ((get_byte(uart, &c, timeout) == 0) && (c == CA)) {
*length = -1;
if ((get_byte(rx->xfer, &c, timeout) == 0) && (c == CA)) {
++rx->abort;
return 0;
} else {
return -1;
}
case ABORT1:
case ABORT2:
return 1;
++rx->abort;
return 0;
default:
return -1;
}
*data = c;
for (i = 1; i < (packet_size + PACKET_OVERHEAD); i ++) {
if (get_byte(uart, data + i, timeout) != 0) {
return -1;
rx->data[i++] = c;
for (i = 1; i < (packet_size + PACKET_OVERHEAD); i++) {
if (get_byte(rx->xfer, rx->data + i, timeout) != 0) {
return -2;
}
}
if (data[PACKET_SEQNO_INDEX] != ((data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff)) {
return -1;
if (rx->data[PACKET_SEQNO_INDEX] != ((rx->data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff)) {
return -3;
}
*length = packet_size;
return 0;
/* crc in packet */
rcs = rx->data[packet_size + PACKET_OVERHEAD - 2];
rcs <<= 8;
rcs |= rx->data[packet_size + PACKET_OVERHEAD - 1];
/* computed crc from data */
ccs = do_crc16(&rx->data[PACKET_HEADER], packet_size);
if (ccs != rcs) {
#ifdef YMODEM_DEBUG
printf("crc mismatch: %04x, expected: %04x\n", ccs, rcs);
#endif
return -4;
}
return (packet_size);
}
/*
* @brief Receive a file using the ymodem protocol.
*/
int ymodem_recv(struct ymodem_xfer *uart)
{
char filename[FILE_NAME_LENGTH + 1], file_size[FILE_SIZE_LENGTH + 1];
uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], *file_ptr;
int i, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0;
struct rxdescr *rx;
uint8_t *fp;
int pkt_size, i;
unsigned int fsize, recv_bytes = 0;
if (!uart->on_info || !uart->on_data) {
#ifdef YMODEM_DEBUG
printf("please set `on_info` and `on_data`\n");
#endif
return -1;
}
/* allocate enough memory. */
rx = malloc(sizeof *rx);
if (rx == NULL) {
#ifdef YMODEM_DEBUG
printf("%s: out of memory.\n", __func__);
#endif
return -1;
}
memset(rx, 0, sizeof *rx);
rx->xfer = uart;
session_done = 0;
session_begin = 0;
errors = 0;
while (session_done == 0) {
packets_received = 0;
file_done = 0;
while (file_done == 0) {
switch (do_recv(uart, packet_data, &packet_length, NAK_TIMEOUT)) {
case 0:
errors = 0;
switch (packet_length) {
/* Abort by sender */
case -1:
put_byte(uart, ACK);
return 0;
/* End of transmission */
case 0:
put_byte(uart, ACK);
file_done = 1;
break;
/* Normal packet */
default:
if ((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff)) {
put_byte(uart, NAK);
} else {
if (packets_received == 0) {
/* Filename packet */
if (packet_data[PACKET_HEADER] != 0) {
/* Filename packet has valid data */
for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);) {
filename[i++] = *file_ptr++;
}
filename[i++] = '\0';
for (i = 0, file_ptr++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH);) {
file_size[i++] = *file_ptr++;
}
file_size[i++] = '\0';
size = strtoul(file_size, NULL, 0);
/* Test the size of the image to be sent */
/* Image size is greater than Flash size */
if (uart->on_info && uart->on_info(uart, filename, size)) { /* error */
/* End session */
put_byte(uart, CA);
put_byte(uart, CA);
return -1;
}
put_byte(uart, ACK);
put_byte(uart, CRC16);
} else {/* Filename packet is empty, end session */
put_byte(uart, ACK);
file_done = 1;
session_done = 1;
break;
}
} else { /* Data packet */
/* Write received data in Flash */
if (uart->on_data) {
if (uart->on_data(uart, packet_data + PACKET_HEADER, packet_length)) { /* An error occurred while writing to Flash memory */
/* End session */
put_byte(uart, CA);
put_byte(uart, CA);
return -2;
} else {
put_byte(uart, ACK);
}
} else {
put_byte(uart, CA);
put_byte(uart, CA);
}
}
packets_received++;
session_begin = 1;
}
}
break;
case 1:
put_byte(uart, CA);
put_byte(uart, CA);
return -3;
default:
if (session_begin > 0) {
errors ++;
}
if (errors > MAX_ERRORS) {
put_byte(uart, CA);
put_byte(uart, CA);
return 0;
retry:
/* wait to start */
while ((pkt_size = recv_frame(rx, NAK_TIMEOUT)) <= 0) {
put_byte(uart, WANTCRC);
}
if (rx->data[PACKET_SEQNO_INDEX] != 0) { /* seq mismatch */
put_byte(uart, NAK);
goto retry;
}
fp = &rx->data[PACKET_HEADER];
/* packet 0, filename packet. */
if (*fp == 0) { /* have no filename, it's not a vlid ymodem first packet */
put_byte(uart, CA);
put_byte(uart, CA);
#ifdef YMODEM_DEBUG
printf("no filename retry\n");
#endif
goto retry;
}
/* send req 0 response */
put_byte(uart, ACK);
put_byte(uart, WANTCRC);
/* parse filename */
i = 0;
while ((*fp != 0) && (i < FILE_NAME_LENGTH)) {
rx->fname[i++] = *fp++;
}
rx->fname[i++] = '\0';
/* parse file size */
i = 0;
++fp;
while ((*fp != ' ') && (i < FILE_SIZE_LENGTH)) {
rx->fsize[i++] = *fp++;
}
rx->fsize[i++] = '\0';
fsize = strtoul(rx->fsize, NULL, 0);
/* call file info callback */
rx->last_error = uart->on_info(uart, rx->fname, fsize);
#ifdef YMODEM_DEBUG
printf("%s : (%d) bytes (last_error %d)\n", rx->fname, fsize, rx->last_error);
#endif
/* initialize ymodem state */
rx->eot = 0;
rx->abort = 0;
rx->errors = 0;
rx->seq = 1;
/* start to recv file contents */
fp = &rx->data[PACKET_HEADER];
for (;;) {
pkt_size = recv_frame(rx, NAK_TIMEOUT);
if (rx->abort > 0) {
#ifdef YMODEM_DEBUG
printf("abort\n");
#endif
break;
}
if (rx->last_error) {
put_byte(uart, CA);
put_byte(uart, CA);
#ifdef YMODEM_DEBUG
printf("last_error break\n");
#endif
break;
}
if (pkt_size < 0) {
++rx->errors;
if (rx->errors >= MAX_ERRORS) {
put_byte(uart, CA);
put_byte(uart, CA);
#ifdef YMODEM_DEBUG
printf("errors break\n");
#endif
break;
} else {
put_byte(uart, NAK);
#ifdef YMODEM_DEBUG
printf("send NAK\n");
#endif
continue;
}
}
rx->errors = 0;
if (rx->eot == 2 && rx->data[PACKET_SEQNO_INDEX] == 0) {
#ifdef YMODEM_DEBUG
printf("end of ymodem protocol.\n");
#endif
put_byte(uart, ACK);
break;
}
if (pkt_size > 0) { /* on data */
if (rx->data[PACKET_SEQNO_INDEX] == 0) { /* all zeros */
for (i = 0; i < pkt_size; ++i) {
if (fp[i] != 0) {
break;
}
put_byte(uart, CRC16);
}
if ((i == pkt_size) && rx->eot > 0) { /* end of stream */
put_byte(uart, ACK);
break;
}
}
if (rx->seq != rx->data[PACKET_SEQNO_INDEX]) {
put_byte(uart, NAK);
#ifdef YMODEM_DEBUG
printf("data phase: seq mismatch %d, expected %d\n", rx->data[PACKET_SEQNO_INDEX], rx->seq);
#endif
} else {
put_byte(uart, ACK);
rx->last_error = uart->on_data(uart, fp, pkt_size);
++rx->seq;
recv_bytes += pkt_size;
}
continue;
}
/* eot */
if (pkt_size == 0) {
if (rx->eot == 1) {
put_byte(uart, NAK);
continue;
}
if (rx->eot == 2) {
put_byte(uart, ACK);
put_byte(uart, WANTCRC);
}
}
}
return size;
free(rx);
return (recv_bytes);
}
/**
@ -275,49 +415,6 @@ static void prepare_packet(uint8_t *sourceBuf, uint8_t *data, uint8_t pktNo, uin
}
}
/**
* @brief Update CRC16 for input byte
* @param CRC input value
* @param input byte
* @retval None
*/
static uint16_t crc16(uint16_t crcIn, uint8_t byte)
{
uint32_t crc = crcIn;
uint32_t in = byte | 0x100;
do {
crc <<= 1;
in <<= 1;
if(in & 0x100)
++crc;
if(crc & 0x10000)
crc ^= 0x1021;
} while (!(in & 0x10000));
return crc & 0xffffu;
}
/**
* @brief Cal CRC16 for YModem Packet
* @param data
* @param length
* @retval None
*/
static uint16_t do_crc16(const uint8_t* data, uint32_t size)
{
uint32_t crc = 0;
const uint8_t* dataEnd = data+size;
while(data < dataEnd)
crc = crc16(crc, *data++);
crc = crc16(crc, 0);
crc = crc16(crc, 0);
return crc&0xffffu;
}
/**
* @brief Cal Check sum for YModem Packet
* @param data

2
lib/ymodem.h

@ -25,7 +25,7 @@ extern "C" {
#define ACK (0x06) /* acknowledge */
#define NAK (0x15) /* negative acknowledge */
#define CA (0x18) /* two of these in succession aborts transfer */
#define CRC16 (0x43) /* 'C' == 0x43, request 16-bit CRC */
#define WANTCRC (0x43) /* 'C' == 0x43, request 16-bit CRC */
#define ABORT1 (0x41) /* 'A' == 0x41, abort by user */
#define ABORT2 (0x61) /* 'a' == 0x61, abort by user */

21
targets/stm32f429-disc/cmds.c

@ -3,6 +3,7 @@
#include <string.h>
#include "cmd.h"
#include "efs.h"
#include "serial.h"
#include "ymodem.h"
struct fileinfo {
@ -11,7 +12,7 @@ struct fileinfo {
size_t size;
};
static int ry_on_info(void *xfer, const char *name, unsigned int size)
static int rx_on_info(void *xfer, const char *name, unsigned int size)
{
struct fileinfo *s = xfer;
@ -24,15 +25,17 @@ static int ry_on_info(void *xfer, const char *name, unsigned int size)
return 0;
}
static int ry_on_data(void *xfer, const void *data, unsigned int len)
static int rx_on_data(void *xfer, const void *data, unsigned int _len)
{
struct fileinfo *s = xfer;
int len = _len;
s->recv += len;
if (s->recv > s->size) {
if (s->size > 0 && (s->recv > s->size)) {
len -= (s->recv - s->size);
}
efs_write(s->fh, data, len);
if (len > 0)
efs_write(s->fh, data, len);
return 0;
}
@ -55,11 +58,17 @@ static int do_efs(cmd_tbl_t s, int argc, char *argv[])
printf(" rm\tdelete file\n");
} else if (strcmp(argv[1], "rx") == 0) {
memset(&fi, 0, sizeof fi);
err = stdio_ymodem_recv(&fi, ry_on_info, ry_on_data);
#if 0
serial_setup(&serial2, CONSOLE_BAUDRATE, 8, SERIAL_STOPBITS_1);
serial_ymodem_recv(&serial2, &fi, rx_on_info, rx_on_data);
serial_close(&serial2);
#else
stdio_ymodem_recv(&fi, rx_on_info, rx_on_data);
#endif
if (fi.fh > 0) {
efs_close(fi.fh);
}
printf("\n\t\nreceive %d bytes\n", err);
printf("receive %d bytes\n", fi.size);
} else if (strcmp(argv[1], "rm") == 0 && argc >= 3) {
efs_remove(argv[2]);
} else if (strcmp(argv[1], "format") == 0) {

2
targets/stm32f429-disc/main.c

@ -139,7 +139,7 @@ int main()
iis_start_tx(&i2s0);
// efs_mount();
efs_mount();
bkp_sram_write(MAGIC_POS, MAGIC_APP);
printf("build: %s (%s)\r\n", __DATE__, __TIME__);

Loading…
Cancel
Save