#include "luat_base.h" #include "stdlib.h" #include "luat_ymodem.h" #ifdef __LUATOS__ #include "luat_fs.h" #include "luat_timer.h" #endif #include "luat_mem.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 { #ifdef __LUATOS__ char *save_path; const char *force_save_path; FILE* fd; #else luat_ymodem_callback cb; #endif 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; } #ifdef __LUATOS__ void *luat_ymodem_create_handler(const char *save_path, const char *force_save_path) #else void *luat_ymodem_create_handler(luat_ymodem_callback cb) #endif { ymodem_ctrlstruct *handler = luat_heap_malloc(sizeof(ymodem_ctrlstruct)); if (handler) { memset(handler, 0, sizeof(ymodem_ctrlstruct)); #ifdef __LUATOS__ if (save_path) { if (save_path[strlen(save_path)-1] == '/'){ handler->save_path = luat_heap_malloc(strlen(save_path) + 1); strcpy(handler->save_path, save_path); handler->save_path[strlen(save_path)] = 0; }else{ handler->save_path = luat_heap_malloc(strlen(save_path) + 2); strcpy(handler->save_path, save_path); handler->save_path[strlen(save_path)] = '/'; handler->save_path[strlen(save_path)+1] = 0; } } if (force_save_path) { handler->force_save_path = luat_heap_malloc(strlen(force_save_path) + 1); strcpy((char*)handler->force_save_path, force_save_path); } #else handler->cb = cb; #endif } 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; *ack = 0; *flag = 0; switch (ctrl->state) { case 0: if (!data || !len) { *ack = XMODEM_FLAG; return 0; } else { if (ctrl->data_pos > 0) { } else { switch(data[0]) { case XMODEM_STX: ctrl->data_max = XMODEM_STX_DATA_LEN; break; case XMODEM_SOH: ctrl->data_max = XMODEM_SOH_DATA_LEN; break; case XMODEM_CAN: luat_ymodem_reset(handler); *ack = XMODEM_ACK; *all_done = 1; return 0; default: goto DATA_RECIEVE_ERROR; break; } } if ((ctrl->data_pos + len) >= (ctrl->data_max + 5)) { //memcpy(&ctrl->packet_data[ctrl->data_pos], data, (XMODEM_SOH_DATA_LEN + 5) - ctrl->data_pos); memcpy(&ctrl->packet_data[ctrl->data_pos], data, (ctrl->data_max + 5) - ctrl->data_pos); //if (ctrl->packet_data[0] != XMODEM_SOH || ctrl->packet_data[1] != 0x00 || ctrl->packet_data[2] != 0xff) if (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); crc16_org = ctrl->packet_data[ctrl->data_max + 3]; crc16_org = (crc16_org << 8) + ctrl->packet_data[ctrl->data_max + 4]; crc16 = CRC16_Cal(&ctrl->packet_data[XMODEM_DATA_POS], ctrl->data_max, 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); *flag = 0; *ack = XMODEM_ACK; *all_done = 1; return 0; } NameEnd = 0; //for(i = XMODEM_DATA_POS; i < (XMODEM_SOH_DATA_LEN + 5); i++) for(i = XMODEM_DATA_POS; i < (ctrl->data_max + 5); i++) { if (!ctrl->packet_data[i]) { NameEnd = i; break; } } if (!NameEnd) { LLOGD("name end"); goto DATA_RECIEVE_ERROR; } LenEnd = 0; //for(i = (NameEnd + 1); i < (XMODEM_SOH_DATA_LEN + 5); i++) for(i = (NameEnd + 1); i < (ctrl->data_max + 5); i++) { if (!ctrl->packet_data[i]) { LenEnd = i; break; } } if (!LenEnd) { LLOGD("len end"); goto DATA_RECIEVE_ERROR; } ctrl->file_size = strtol((const char*)&ctrl->packet_data[NameEnd + 1], NULL, 10); ctrl->write_size = 0; #ifdef __LUATOS__ 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); } #else ctrl->cb(&ctrl->packet_data[XMODEM_DATA_POS], 0); ctrl->cb(NULL, ctrl->file_size); #endif 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 (!data || !len) { return 0; } 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; case XMODEM_CAN: luat_ymodem_reset(handler); *ack = XMODEM_ACK; *all_done = 1; return 0; default: LLOGD("%x", data[0]); goto DATA_RECIEVE_ERROR; break; } if (len > (XMODEM_STX_DATA_LEN + 8)) //防止溢出死机 { len = XMODEM_STX_DATA_LEN + 8; } memcpy(ctrl->packet_data, data, len); ctrl->data_pos += 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,%d", ctrl->packet_data[0], ctrl->packet_data[1], ctrl->packet_data[2],ctrl->next_sn); 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); #ifdef __LUATOS__ luat_fs_fwrite(ctrl->packet_data+3, LenEnd, 1, ctrl->fd); #else ctrl->cb(ctrl->packet_data+3, LenEnd); #endif 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); #ifdef __LUATOS__ luat_fs_fwrite(ctrl->packet_data+3, LenEnd, 1, ctrl->fd); #else ctrl->cb(ctrl->packet_data+3, LenEnd); #endif 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: if (!data || !len) { return 0; } switch(data[0]) { case XMODEM_EOT: ctrl->state++; ctrl->data_pos = 0; *flag = 0; *ack = XMODEM_NAK; #ifdef __LUATOS__ if (ctrl->fd) luat_fs_fclose(ctrl->fd); ctrl->fd = NULL; #else ctrl->cb(NULL, 0); #endif break; case XMODEM_CAN: luat_ymodem_reset(handler); *ack = XMODEM_ACK; *all_done = 1; return 0; default: goto DATA_RECIEVE_ERROR; } 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)) { #ifdef __LUATOS__ luat_fs_fclose(ctrl->fd); ctrl->fd = NULL; #else #endif 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; #ifdef __LUATOS__ if (ctrl->fd) luat_fs_fclose(ctrl->fd); ctrl->fd = NULL; #else ctrl->cb(NULL, 0); #endif } void luat_ymodem_release(void *handler) { ymodem_ctrlstruct *ctrl = handler; luat_ymodem_reset(handler); #ifdef __LUATOS__ luat_heap_free(ctrl->save_path); #endif luat_heap_free(handler); }