pinebuds/apps/factory/app_factory_cdc_comm.c

314 lines
7.1 KiB
C

#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