|
|
@@ -0,0 +1,341 @@
|
|
|
+#include "luat_ymodem.h"
|
|
|
+#include "luat_fs.h"
|
|
|
+#include "luat_malloc.h"
|
|
|
+
|
|
|
+#define LUAT_LOG_TAG "ymodem"
|
|
|
+#include "luat_log.h"
|
|
|
+
|
|
|
+#define XMODEM_FLAG 'C'
|
|
|
+#define XMODEM_SOH 0x01
|
|
|
+#define XMODEM_STX 0x02
|
|
|
+#define XMODEM_EOT 0x04
|
|
|
+#define XMODEM_ACK 0x06
|
|
|
+#define XMODEM_NAK 0x15
|
|
|
+#define XMODEM_CAN 0x18
|
|
|
+#define XMODEM_DATA_POS (3)
|
|
|
+#define XMODEM_SOH_DATA_LEN (128)
|
|
|
+#define XMODEM_STX_DATA_LEN (1024)
|
|
|
+
|
|
|
+typedef struct
|
|
|
+{
|
|
|
+ char *save_path;
|
|
|
+ const char *force_save_path;
|
|
|
+ FILE* fd;
|
|
|
+ uint32_t file_size;
|
|
|
+ uint32_t write_size;
|
|
|
+ uint16_t data_pos;
|
|
|
+ uint16_t data_max;
|
|
|
+ uint8_t state;
|
|
|
+ uint8_t next_sn;
|
|
|
+ uint8_t packet_data[XMODEM_STX_DATA_LEN + 8];
|
|
|
+}ymodem_ctrlstruct;
|
|
|
+
|
|
|
+static uint16_t CRC16_Cal(void *Data, uint16_t Len, uint16_t CRC16Last)
|
|
|
+{
|
|
|
+ uint16_t i;
|
|
|
+ uint16_t CRC16 = CRC16Last;
|
|
|
+ uint8_t *Src = (uint8_t *)Data;
|
|
|
+
|
|
|
+ while (Len--)
|
|
|
+ {
|
|
|
+ for (i = 8; i > 0; i--)
|
|
|
+ {
|
|
|
+ if ((CRC16 & 0x8000) != 0)
|
|
|
+ {
|
|
|
+ CRC16 <<= 1;
|
|
|
+ CRC16 ^= 0x1021;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ CRC16 <<= 1;
|
|
|
+ }
|
|
|
+ if ((*Src&(1 << (i - 1))) != 0)
|
|
|
+ {
|
|
|
+ CRC16 ^= 0x1021;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Src++;
|
|
|
+ }
|
|
|
+ return CRC16;
|
|
|
+}
|
|
|
+
|
|
|
+void *luat_ymodem_create_handler(const char *save_path, const char *force_save_path)
|
|
|
+{
|
|
|
+ ymodem_ctrlstruct *handler = luat_heap_malloc(sizeof(ymodem_ctrlstruct));
|
|
|
+ if (handler)
|
|
|
+ {
|
|
|
+ memset(handler, 0, sizeof(ymodem_ctrlstruct));
|
|
|
+ if (save_path)
|
|
|
+ {
|
|
|
+ handler->save_path = luat_heap_malloc(strlen(save_path) + 1);
|
|
|
+ strcpy(handler->save_path, save_path);
|
|
|
+ }
|
|
|
+ if (force_save_path)
|
|
|
+ {
|
|
|
+ handler->force_save_path = luat_heap_malloc(strlen(force_save_path) + 1);
|
|
|
+ strcpy(handler->force_save_path, force_save_path);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ return handler;
|
|
|
+}
|
|
|
+
|
|
|
+int luat_ymodem_receive(void *handler, uint8_t *data, uint32_t len, uint8_t *ack, uint8_t *flag, uint8_t *file_ok, uint8_t *all_done)
|
|
|
+{
|
|
|
+ ymodem_ctrlstruct *ctrl = handler;
|
|
|
+ uint16_t crc16_org, crc16;
|
|
|
+ uint32_t i, NameEnd, LenEnd;
|
|
|
+ char path[128];
|
|
|
+ *file_ok = 0;
|
|
|
+ *all_done = 0;
|
|
|
+ *flag = 0;
|
|
|
+ if (data)
|
|
|
+ {
|
|
|
+ if (data[0] == XMODEM_CAN)
|
|
|
+ {
|
|
|
+ luat_ymodem_reset(handler);
|
|
|
+ *ack = XMODEM_ACK;
|
|
|
+ *all_done = 1;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (ctrl->state)
|
|
|
+ {
|
|
|
+ case 0:
|
|
|
+ if (!data)
|
|
|
+ {
|
|
|
+ *ack = XMODEM_FLAG;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if ((ctrl->data_pos + len) >= (XMODEM_SOH_DATA_LEN + 5))
|
|
|
+ {
|
|
|
+ memcpy(&ctrl->packet_data[ctrl->data_pos], data, (XMODEM_SOH_DATA_LEN + 5) - ctrl->data_pos);
|
|
|
+ if (ctrl->packet_data[0] != XMODEM_SOH || ctrl->packet_data[1] != 0x00 || ctrl->packet_data[2] != 0xff)
|
|
|
+ {
|
|
|
+ LLOGD("head %x %x %x", ctrl->packet_data[0], ctrl->packet_data[1], ctrl->packet_data[2]);
|
|
|
+ goto DATA_RECIEVE_ERROR;
|
|
|
+ }
|
|
|
+ crc16_org = ctrl->packet_data[XMODEM_SOH_DATA_LEN + 3];
|
|
|
+ crc16_org = (crc16_org << 8) + ctrl->packet_data[XMODEM_SOH_DATA_LEN + 4];
|
|
|
+ crc16 = CRC16_Cal(&ctrl->packet_data[XMODEM_DATA_POS], XMODEM_SOH_DATA_LEN, 0);
|
|
|
+ if (crc16 != crc16_org)
|
|
|
+ {
|
|
|
+ LLOGD("crc16 %x %x ", crc16, crc16_org);
|
|
|
+ goto DATA_RECIEVE_ERROR;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (!ctrl->packet_data[XMODEM_DATA_POS])
|
|
|
+ {
|
|
|
+ luat_ymodem_reset(handler);
|
|
|
+ *ack = XMODEM_ACK;
|
|
|
+ *all_done = 1;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ NameEnd = NULL;
|
|
|
+ for(i = XMODEM_DATA_POS; i++; i < (XMODEM_SOH_DATA_LEN + 5))
|
|
|
+ {
|
|
|
+ if (!ctrl->packet_data[i])
|
|
|
+ {
|
|
|
+ NameEnd = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!NameEnd)
|
|
|
+ {
|
|
|
+ LLOGD("name end");
|
|
|
+ goto DATA_RECIEVE_ERROR;
|
|
|
+ }
|
|
|
+ LenEnd = NULL;
|
|
|
+ for(i = (NameEnd + 1); i++; i < (XMODEM_SOH_DATA_LEN + 5))
|
|
|
+ {
|
|
|
+ if (!ctrl->packet_data[i])
|
|
|
+ {
|
|
|
+ LenEnd = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!LenEnd)
|
|
|
+ {
|
|
|
+ LLOGD("len end");
|
|
|
+ goto DATA_RECIEVE_ERROR;
|
|
|
+ }
|
|
|
+
|
|
|
+ ctrl->file_size = strtol(&ctrl->packet_data[NameEnd + 1], NULL, 10);
|
|
|
+ ctrl->write_size = 0;
|
|
|
+ if (ctrl->force_save_path)
|
|
|
+ {
|
|
|
+ ctrl->fd = luat_fs_fopen(ctrl->force_save_path, "w");
|
|
|
+ LLOGD("%s,%u,%x", ctrl->force_save_path, ctrl->file_size, ctrl->fd);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ sprintf_(path, "%s%s", ctrl->save_path, &ctrl->packet_data[XMODEM_DATA_POS]);
|
|
|
+ ctrl->fd = luat_fs_fopen(path, "w");
|
|
|
+ LLOGD("%s,%u,%x", path, ctrl->file_size, ctrl->fd);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ ctrl->state++;
|
|
|
+ ctrl->next_sn = 0;
|
|
|
+ ctrl->data_max = (XMODEM_STX_DATA_LEN + 5);
|
|
|
+ *flag = XMODEM_FLAG;
|
|
|
+ goto DATA_RECIEVE_OK;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ memcpy(&ctrl->packet_data[ctrl->data_pos], data, len);
|
|
|
+ ctrl->data_pos += len;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ if (!ctrl->data_pos)
|
|
|
+ {
|
|
|
+ switch(data[0])
|
|
|
+ {
|
|
|
+ case XMODEM_STX:
|
|
|
+ ctrl->data_max = (XMODEM_STX_DATA_LEN + 5);
|
|
|
+ break;
|
|
|
+ case XMODEM_SOH:
|
|
|
+ ctrl->data_max = (XMODEM_SOH_DATA_LEN + 5);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ goto DATA_RECIEVE_ERROR;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ memcpy(ctrl->packet_data, data, len);
|
|
|
+ if (len >= ctrl->data_max) goto YMODEM_DATA_CHECK;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if ((ctrl->data_pos + len) >= ctrl->data_max)
|
|
|
+ {
|
|
|
+ memcpy(&ctrl->packet_data[ctrl->data_pos], data, ctrl->data_max - ctrl->data_pos);
|
|
|
+YMODEM_DATA_CHECK:
|
|
|
+ switch(ctrl->packet_data[0])
|
|
|
+ {
|
|
|
+ case XMODEM_SOH:
|
|
|
+ if (ctrl->packet_data[1] != ctrl->next_sn || ctrl->packet_data[2] != (255 - ctrl->next_sn))
|
|
|
+ {
|
|
|
+ LLOGD("head %x %x %x", ctrl->packet_data[0], ctrl->packet_data[1], ctrl->packet_data[2]);
|
|
|
+ goto DATA_RECIEVE_ERROR;
|
|
|
+ }
|
|
|
+
|
|
|
+ crc16_org = ctrl->packet_data[XMODEM_SOH_DATA_LEN + 3];
|
|
|
+ crc16_org = (crc16_org << 8) + ctrl->packet_data[XMODEM_SOH_DATA_LEN + 4];
|
|
|
+ crc16 = CRC16_Cal(&ctrl->packet_data[XMODEM_DATA_POS], XMODEM_SOH_DATA_LEN, 0);
|
|
|
+ if (crc16 != crc16_org)
|
|
|
+ {
|
|
|
+ LLOGD("crc16 %x %x ", crc16, crc16_org);
|
|
|
+ goto DATA_RECIEVE_ERROR;
|
|
|
+ }
|
|
|
+ LenEnd = ((ctrl->file_size - ctrl->write_size) > XMODEM_SOH_DATA_LEN)?XMODEM_SOH_DATA_LEN:(ctrl->file_size - ctrl->write_size);
|
|
|
+ luat_fs_fwrite(ctrl->packet_data, LenEnd, 1, ctrl->fd);
|
|
|
+ ctrl->write_size += LenEnd;
|
|
|
+ goto DATA_RECIEVE_OK;
|
|
|
+ break;
|
|
|
+ case XMODEM_STX:
|
|
|
+ if (ctrl->packet_data[1] != ctrl->next_sn || (ctrl->packet_data[2] != (255 - ctrl->next_sn)))
|
|
|
+ {
|
|
|
+ LLOGD("head %x %x %x", ctrl->packet_data[0], ctrl->packet_data[1], ctrl->packet_data[2]);
|
|
|
+ goto DATA_RECIEVE_ERROR;
|
|
|
+ }
|
|
|
+
|
|
|
+ crc16_org = ctrl->packet_data[XMODEM_STX_DATA_LEN + 3];
|
|
|
+ crc16_org = (crc16_org << 8) + ctrl->packet_data[XMODEM_STX_DATA_LEN + 4];
|
|
|
+ crc16 = CRC16_Cal(&ctrl->packet_data[XMODEM_DATA_POS], XMODEM_STX_DATA_LEN, 0);
|
|
|
+ if (crc16 != crc16_org)
|
|
|
+ {
|
|
|
+ LLOGD("crc16 %x %x ", crc16, crc16_org);
|
|
|
+ goto DATA_RECIEVE_ERROR;
|
|
|
+ }
|
|
|
+ //写入
|
|
|
+ LenEnd = ((ctrl->file_size - ctrl->write_size) > XMODEM_STX_DATA_LEN)?XMODEM_STX_DATA_LEN:(ctrl->file_size - ctrl->write_size);
|
|
|
+ luat_fs_fwrite(ctrl->packet_data, LenEnd, 1, ctrl->fd);
|
|
|
+ ctrl->write_size += LenEnd;
|
|
|
+ goto DATA_RECIEVE_OK;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ if (ctrl->packet_data[1] != ctrl->next_sn || ctrl->packet_data[2] != ~ctrl->next_sn)
|
|
|
+ {
|
|
|
+ LLOGD("head %x %x %x", ctrl->packet_data[0], ctrl->packet_data[1], ctrl->packet_data[2]);
|
|
|
+ goto DATA_RECIEVE_ERROR;
|
|
|
+ }
|
|
|
+ goto DATA_RECIEVE_OK;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ memcpy(&ctrl->packet_data[ctrl->data_pos], data, len);
|
|
|
+ ctrl->data_pos += len;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ ctrl->state++;
|
|
|
+ ctrl->data_pos = 0;
|
|
|
+ *ack = XMODEM_NAK;
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ case 3:
|
|
|
+ if (data[0] == XMODEM_EOT)
|
|
|
+ {
|
|
|
+ ctrl->state = 0;
|
|
|
+ *flag = XMODEM_FLAG;
|
|
|
+ *ack = XMODEM_ACK;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ goto DATA_RECIEVE_ERROR;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ *ack = 0;
|
|
|
+ return 0;
|
|
|
+DATA_RECIEVE_ERROR:
|
|
|
+ ctrl->data_pos = 0;
|
|
|
+ *ack = XMODEM_NAK;
|
|
|
+ *flag = 0;
|
|
|
+ *all_done = 0;
|
|
|
+ return -1;
|
|
|
+DATA_RECIEVE_OK:
|
|
|
+ ctrl->data_pos = 0;
|
|
|
+ ctrl->next_sn++;
|
|
|
+ *ack = XMODEM_ACK;
|
|
|
+ if (ctrl->file_size && (ctrl->write_size >= ctrl->file_size))
|
|
|
+ {
|
|
|
+ luat_fs_fclose(ctrl->fd);
|
|
|
+ ctrl->fd = NULL;
|
|
|
+ ctrl->state = 2;
|
|
|
+ *file_ok = 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void luat_ymodem_reset(void *handler)
|
|
|
+{
|
|
|
+ ymodem_ctrlstruct *ctrl = handler;
|
|
|
+ ctrl->state = 0;
|
|
|
+ ctrl->next_sn = 0;
|
|
|
+ ctrl->file_size = 0;
|
|
|
+ if (ctrl->fd) luat_fs_fclose(ctrl->fd);
|
|
|
+ ctrl->fd = NULL;
|
|
|
+}
|
|
|
+
|
|
|
+void luat_ymodem_release(void *handler)
|
|
|
+{
|
|
|
+ ymodem_ctrlstruct *ctrl = handler;
|
|
|
+ luat_ymodem_reset(handler);
|
|
|
+ luat_heap_free(ctrl->save_path);
|
|
|
+ luat_heap_free(handler);
|
|
|
+}
|