#ifdef __USB_COMM__ #include "app_factory_cdc_comm.h" #include "plat_types.h" #include "stdbool.h" #include "stdint.h" #include "stdio.h" #include "string.h" #include "sys_api_cdc_comm.h" #include "tool_msg.h" static enum PARSE_STATE parse_state; static struct message_t recv_msg; static struct message_t send_msg = { { PREFIX_CHAR, }, }; static unsigned char check_sum(unsigned char *buf, unsigned char len) { int i; unsigned char sum = 0; for (i = 0; i < len; i++) { sum += buf[i]; } return sum; } int send_reply(const unsigned char *payload, unsigned int len) { int ret = 0; if (len + 1 > sizeof(send_msg.data)) { TRACE(1, "Packet length too long: %u", len); return -1; } send_msg.hdr.type = recv_msg.hdr.type; send_msg.hdr.seq = recv_msg.hdr.seq; send_msg.hdr.len = len; memcpy(&send_msg.data[0], payload, len); send_msg.data[len] = ~check_sum((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg) - 1); ret = send_data((unsigned char *)&send_msg, MSG_TOTAL_LEN(&send_msg)); return ret; } static void reset_parse_state(unsigned char **buf, size_t *len) { parse_state = PARSE_HEADER; memset(&recv_msg.hdr, 0, sizeof(recv_msg.hdr)); *buf = (unsigned char *)&recv_msg.hdr; *len = sizeof(recv_msg.hdr); } static enum ERR_CODE check_msg_hdr(void) { enum ERR_CODE errcode = ERR_NONE; switch (recv_msg.hdr.type) { case TYPE_SYS: if (recv_msg.hdr.len != 1 && recv_msg.hdr.len != 5) { // TRACE(1,"SYS msg length error: %u", recv_msg.hdr.len); errcode = ERR_LEN; } break; case TYPE_READ: if (recv_msg.hdr.len != 4) { // TRACE(1,"READ msg length error: %u", recv_msg.hdr.len); errcode = ERR_LEN; } break; case TYPE_WRITE: if (recv_msg.hdr.len <= 4 || recv_msg.hdr.len > 20) { // TRACE(1,"WRITE msg length error: %u", recv_msg.hdr.len); errcode = ERR_LEN; } break; default: break; } if (errcode == ERR_NONE && recv_msg.hdr.len + 1 > sizeof(recv_msg.data)) { errcode = ERR_LEN; } return errcode; } static enum ERR_CODE handle_sys_cmd(enum SYS_CMD_TYPE cmd, unsigned char *param, unsigned int len) { unsigned char cret[5]; unsigned int bootmode; cret[0] = ERR_NONE; if (cmd == SYS_CMD_SET_BOOTMODE || cmd == SYS_CMD_CLR_BOOTMODE) { if (len != 4) { TRACE(2, "Invalid SYS CMD len %u for cmd: 0x%x", len, cmd); return ERR_DATA_LEN; } } else { if (len != 0) { TRACE(2, "Invalid SYS CMD len %u for cmd: 0x%x", len, cmd); return ERR_DATA_LEN; } } switch (cmd) { case SYS_CMD_REBOOT: { TRACE(0, "--- Reboot---"); send_reply(cret, 1); system_reboot(); break; } case SYS_CMD_SHUTDOWN: { TRACE(0, "--- Shutdown ---"); send_reply(cret, 1); system_shutdown(); break; } case SYS_CMD_SET_BOOTMODE: { TRACE(0, "--- Set bootmode ---"); memcpy(&bootmode, param, 4); system_set_bootmode(bootmode); send_reply(cret, 1); break; } case SYS_CMD_CLR_BOOTMODE: { TRACE(0, "--- Clear bootmode ---"); memcpy(&bootmode, param, 4); system_clear_bootmode(bootmode); send_reply(cret, 1); break; } case SYS_CMD_GET_BOOTMODE: { TRACE(0, "--- Get bootmode ---"); bootmode = system_get_bootmode(); memcpy(&cret[1], &bootmode, 4); send_reply(cret, 5); break; } default: { TRACE(1, "Invalid command: 0x%x", recv_msg.data[0]); return ERR_SYS_CMD; } } return ERR_NONE; } static enum ERR_CODE handle_data(unsigned char **buf, size_t *len, int *extra) { enum ERR_CODE errcode = ERR_NONE; #if 0 uint32_t rlen = 0; #endif *extra = 0; // Checksum if (check_sum((unsigned char *)&recv_msg, MSG_TOTAL_LEN(&recv_msg)) != 0xFF) { TRACE(0, "Checksum error"); return ERR_CHECKSUM; } switch (recv_msg.hdr.type) { case TYPE_SYS: { TRACE_TIME(0, "------ SYS CMD ------"); errcode = handle_sys_cmd((enum SYS_CMD_TYPE)recv_msg.data[0], &recv_msg.data[1], recv_msg.hdr.len - 1); if (errcode != ERR_NONE) { return errcode; } break; } case TYPE_READ: { TRACE_TIME(0, "------ READ CMD ------"); #if 0 uint32_t addr = (recv_msg.data[0] << 16) | (recv_msg.data[1] << 8) | recv_msg.data[2]; uint8_t data[4] = {0}; rlen = read_reg(addr, data); if(rlen == 0) return ERR_LEN; else { send_reply(data, rlen); } #endif break; } case TYPE_WRITE: { TRACE_TIME(0, "------ WRITE CMD ------"); #if 0 uint32_t addr = (recv_msg.data[0] << 16) | (recv_msg.data[1] << 8) | recv_msg.data[2]; uint32_t wdata = (recv_msg.data[3] << 24) | (recv_msg.data[4] << 16) | (recv_msg.data[5] << 8) | recv_msg.data[6]; uint8_t data[1] = {0}; errcode = write_reg(addr, wdata); if (errcode != ERR_NONE) return errcode; else send_reply(data, 1); #endif break; } default: break; } return ERR_NONE; } static int parse_packet(unsigned char **buf, size_t *len) { enum ERR_CODE errcode; int rlen = *len; unsigned char *data; int i; int extra; unsigned char cret; switch (parse_state) { case PARSE_HEADER: ASSERT(rlen > 0 && rlen <= sizeof(recv_msg.hdr), "Invalid rlen!"); if (recv_msg.hdr.prefix == PREFIX_CHAR) { errcode = check_msg_hdr(); if (errcode != ERR_NONE) { goto _err; } parse_state = PARSE_DATA; *buf = &recv_msg.data[0]; *len = recv_msg.hdr.len + 1; } else { data = (unsigned char *)&recv_msg.hdr.prefix; for (i = 1; i < rlen; i++) { if (data[i] == PREFIX_CHAR) { memmove(&recv_msg.hdr.prefix, &data[i], rlen - i); break; } } *buf = &data[rlen - i]; *len = sizeof(recv_msg.hdr) + i - rlen; } break; case PARSE_DATA: errcode = handle_data(buf, len, &extra); if (errcode != ERR_NONE) { goto _err; } // Receive next message reset_parse_state(buf, len); break; default: TRACE(1, "Invalid parse_state: %d", parse_state); break; } return 0; _err: cancel_input(); cret = (unsigned char)errcode; send_reply(&cret, 1); return 1; } void comm_loop(void) { int ret; unsigned char *buf = NULL; size_t len = 0; size_t buf_len, rlen; _sync: reset_transport(); reset_parse_state(&buf, &len); while (1) { rlen = 0; if (parse_state == PARSE_HEADER) { set_recv_timeout(default_recv_timeout_idle); } else { set_recv_timeout(default_recv_timeout_short); } buf_len = 0; ret = recv_data_ex(buf, buf_len, len, &rlen); if (ret) { TRACE(1, "Receiving data failed: %d", ret); goto _err; } if (len != rlen) { TRACE(2, "Receiving part of the data: expect=%u real=%u", len, rlen); goto _err; } ret = parse_packet(&buf, &len); if (ret) { TRACE(0, "Parsing packet failed"); goto _err; } } _err: ret = handle_error(); if (ret == 0) { TRACE(0, "retry ..."); goto _sync; } return; } #endif