回头再解释,先 mark 。
/*----------------------------------------------------------------------------*/
/* +IPD,<id>,<len>:<data> */
/* +IPD,<len>:<data> */
/**
*
* @return -1: parameters error, -2: EOF, -3: timeout, -4:peer closed and no data in buffer
*/
uint32_t recvPkg(esp8285_obj *nic, char *out_buff, uint32_t out_buff_len, uint32_t *data_len, uint32_t timeout, char *coming_mux_id, bool *peer_closed, bool first_time_recv)
{
// printk("%s | head obl %d *dl %d tu %d ftr %d \n", __func__, out_buff_len, *data_len, timeout, first_time_recv);
int err = 0, size = 0;
bool peer_just_closed = false;
// only for single socket but need socket map & buffer TODO:
const mp_stream_p_t *uart_stream = mp_get_stream(nic->uart_obj);
static int8_t mux_id = -1;
static int32_t frame_sum = 0, frame_len = 0, frame_bak = 0;
// parameters check
if (out_buff == NULL) {
return -1;
}
if (first_time_recv) {
frame_sum = frame_len = 0;
}
// required data already in buf, just return data
size = Buffer_Size(&nic->buffer);
if (size >= out_buff_len) {
Buffer_Gets(&nic->buffer, (uint8_t *)out_buff, out_buff_len);
if (data_len) {
*data_len = out_buff_len;
}
size = size > out_buff_len ? out_buff_len : size;
frame_sum -= size;
// printk("Buffer_Size frame_sum %d size %d *data_len %d\n", frame_sum, size, *data_len);
if (frame_sum <= 0) {
Buffer_Clear(&nic->buffer);
if (*peer_closed) { //buffer empty, return EOF
return -2;
}
}
return out_buff_len;
}
enum fsm_state { IDLE, IPD, DATA, EXIT } State = IDLE;
static uint8_t tmp_buf[1560 * 2] = {0}; // tmp_buf as queue 1560
uint32_t tmp_bak = 0, tmp_state = 0, tmp_len = 0, tmp_pos = 0;
mp_uint_t interrupt = 0, uart_recv_len = 0, res = 0;
while (State != EXIT) {
// wait any uart data
uart_recv_len = uart_rx_any(nic->uart_obj);
if (uart_recv_len > 0) {
if (tmp_len >= sizeof(tmp_buf)) { // lock across
// printk("lock across frame_len %d tmp_len %d\n", frame_len, tmp_len);
tmp_len = 0;
}
res = uart_stream->read(nic->uart_obj, tmp_buf + tmp_len, 1, &err);
// printk("%s | tmp_buf %s res %d err %d\n", __func__, tmp_buf, res, err);
if (res == 1 && err == 0) {
interrupt = mp_hal_ticks_ms();
// backup tmp_len to tmp_pos (tmp_pos - 1)
tmp_pos = tmp_len, tmp_len += 1; // buffer push
// printk("[%02X]", tmp_buf[tmp_pos]);
if (State == IDLE) {
if (tmp_buf[tmp_pos] == '+') {
tmp_state = 1, tmp_bak = tmp_pos, State = IPD;
continue;
} else {
// printk("(%02X)", tmp_buf[tmp_pos]);
tmp_len -= 1; // clear don't need data, such as (0D)(0A)
continue;
}
}
if (State == IPD) {
if (tmp_pos - tmp_bak > 12) { // Over the length of the '+IPD,3,1452:' or '+IPD,1452:'
tmp_state = 0, State = IDLE;
continue;
}
if (0 < tmp_state && tmp_state < 5) {
// printk("(%d, %02X) [%d, %02X]\n", tmp_pos, tmp_buf[tmp_pos], tmp_pos - tmp_bak, ("+IPD,")[tmp_pos - tmp_bak]);
if (tmp_buf[tmp_pos] == ("+IPD,")[tmp_pos - tmp_bak]) {
tmp_state += 1; // tmp_state 1 + "IPD," to tmp_state 5
} else {
tmp_state = 0, State = IDLE;
}
continue;
}
if (tmp_state == 5 && tmp_buf[tmp_pos] == ':')
{
tmp_state = 6, State = IDLE;
tmp_buf[tmp_pos + 1] = '\0'; // lock tmp_buf
// printk("%s | is `IPD` tmp_bak %d tmp_len %d command %s\n", __func__, tmp_bak, tmp_len, tmp_buf + tmp_bak);
char *index = strstr((char *)tmp_buf + tmp_bak + 5 /* 5 > '+IPD,' and `+IPD,325:` in tmp_buf */, ",");
int ret = 0, len = 0;
if (index) { // '+IPD,3,1452:'
ret = sscanf((char *)tmp_buf + tmp_bak, "+IPD,%hhd,%d:", &mux_id, &len);
if (ret != 2 || mux_id < 0 || mux_id > 4 || len <= 0) {
; // Misjudge or fail, return, or clean up later
} else {
tmp_len = tmp_bak, tmp_bak = 0; // Clean up the commands in the buffer and roll back the data
frame_len = len, State = DATA;
}
} else { // '+IPD,1452:'
ret = sscanf((char *)tmp_buf + tmp_bak, "+IPD,%d:", &len);
if (ret != 1 || len <= 0) {
; // Misjudge or fail, return, or clean up later
} else {
tmp_len = tmp_bak, tmp_bak = 0; // Clean up the commands in the buffer and roll back the data
frame_len = len, State = DATA;
}
}
continue;
}
}
if (State == DATA) {
// printk("%s | frame_len %d tmp_len %d tmp_buf[tmp_pos] %02X\n", __func__, frame_len, tmp_len, tmp_buf[tmp_pos]);
frame_len -= tmp_len, tmp_len = 0; // get data
if (frame_len < 0) {
if (frame_len == -1 && tmp_buf[tmp_pos] == 'C') { // wait "CLOSED\r\n"
frame_bak = frame_len;
continue;
}
if (tmp_state == 6 && tmp_buf[tmp_pos] == '\r') {
tmp_state = 7;
continue;
}
if (tmp_state == 7 && tmp_buf[tmp_pos] == '\n') {
if (frame_len == -2) { // match +IPD EOF (\r\n)
tmp_state = 0, State = IDLE;
// After receive complete, confirm the data is enough
size = Buffer_Size(&nic->buffer);
// printk("%s | size %d out_buff_len %d\n", __func__, size, out_buff_len);
if (size >= out_buff_len) { // data enough
// printk("%s | recv out_buff_len overflow\n", __func__);
State = EXIT;
}
} else if (frame_len == -8 && frame_len == -1) {
// Get "CLOSED\r\n"
peer_just_closed = *peer_closed = true;
frame_bak = 0, tmp_state = 0, State = EXIT;
} else {
tmp_state = 6;
}
continue;
}
// 存在异常,没有得到 \r\n 的匹配,并排除 CLOSED\r\n 的指令触发的可能性,意味着传输可能越界出错了 \r\n ,则立即回到空闲状态。
if (frame_len <= -1 && frame_bak != -1) {
// printk("%s | tmp_state %d frame_len %d tmp %02X\n", __func__, tmp_state, frame_len, tmp_buf[tmp_pos]);
State = IDLE;
continue;
}
} else {
// for(int i = 0; i < tmp_len; i++) {
// int tmp = tmp_buf[i];
// printk("[%02X]", tmp);
// }
// printk("%s | frame_len %d tmp_len %d\n", __func__, frame_len, tmp_pos + 1);
// printk("%.*s", tmp_len, tmp_buf);
if (!Buffer_Puts(&nic->buffer, tmp_buf, (tmp_pos + 1))) {
printk("%s | network->buffer overflow Buffer Max %d Size %d\n", __func__, ESP8285_BUF_SIZE, Buffer_Size(&nic->buffer));
State = EXIT;
} else {
// reduce data len
// printk("[%02X]", tmp_buf[(tmp_pos + 1)]);
frame_sum += (tmp_pos + 1);
}
// printk("frame_sum %d frame_len %d tmp_len %d\n", frame_sum, frame_len, tmp_pos + 1);
}
continue;
}
} else {
State = EXIT;
}
}
if (mp_hal_ticks_ms() - interrupt > timeout) {
break; // uart no return data to timeout break
}
if (*peer_closed) {
break; // disconnection
}
}
size = Buffer_Size(&nic->buffer);
// peer closed and no data in buffer
if (size == 0 && !peer_just_closed && *peer_closed) {
frame_sum = 0;
return -4;
}
size = size > out_buff_len ? out_buff_len : size;
Buffer_Gets(&nic->buffer, (uint8_t *)out_buff, size);
if (data_len) {
*data_len = size;
}
frame_sum -= size;
if (frame_sum <= 0 || peer_just_closed) {
Buffer_Clear(&nic->buffer);
if (peer_just_closed)
{
frame_sum = 0;
return -2;
}
}
// printk(" %s | tail obl %d *dl %d se %d\n", __func__, out_buff_len, *data_len, size);
return size;
}
肝了三天了,彻底优化了 AT 8285 的通信过程,等测试得差不多了再提交,目前只测到了波特率 576000 下 HTTP 下载 K-Flash.zip (5M)二进制文件,数据完整,接收过程大体是没有太大问题了。
备份旧 CODE 。
uint32_t bak_recvPkg(esp8285_obj *nic, char *out_buff, uint32_t out_buff_len, uint32_t *data_len, uint32_t timeout, char *coming_mux_id, bool *peer_closed, bool first_time_recv)
{
const mp_stream_p_t *uart_stream = mp_get_stream(nic->uart_obj);
static uint8_t temp_buff1[2048] = {0};
static uint8_t temp_buff2[2048] = {0};
uint16_t temp_buff1_len = 0;
uint16_t temp_buff2_len = 0;
uint8_t find_frame_flag_index = 0;
static int8_t mux_id = -1;
static int16_t frame_len = 0;
static int32_t frame_len_sum = 0; //only for single socket TODO:
// bool overflow = false;
int ret = 0;
int size = 0;
int errcode;
mp_uint_t start1 = 0, start2 = 0;
bool no_frame_flag = false;
bool new_frame = false;
mp_uint_t data_len_in_uart_buff = 0;
bool peer_just_closed = false;
// parameters check
if (out_buff == NULL)
{
return -1;
}
// // printk("\r if (out_buff == NULL) { \n");
// init vars
memset(temp_buff1, 0, sizeof(temp_buff1));
memset(temp_buff2, 0, sizeof(temp_buff2));
if (first_time_recv)
{
frame_len = 0;
frame_len_sum = 0;
}
// required data already in buf, just return data
uint32_t buff_size = Buffer_Size(&nic->buffer);
// // printk("\r if(buff_size >= out_buff_len) \n");
// printk("\r buff_size %d out_buff_len %d\n", buff_size, out_buff_len);
if (buff_size >= out_buff_len)
{
Buffer_Gets(&nic->buffer, (uint8_t *)out_buff, out_buff_len);
if (data_len)
*data_len = out_buff_len;
frame_len_sum -= size;
if (frame_len_sum <= 0)
{
frame_len = 0;
frame_len_sum = 0;
Buffer_Clear(&nic->buffer);
if (*peer_closed) //buffer empty, return EOF
{
return -2;
}
}
return out_buff_len;
}
// read from uart buffer, if not frame start flag, put into nic buffer
// and need wait for full frame flag in 200ms(can be fewer), frame format: '+IPD,id,len:data' or '+IPD,len:data'
// wait data from uart buffer if not timeout
start2 = mp_hal_ticks_ms();
data_len_in_uart_buff = uart_rx_any(nic->uart_obj);
// // printk("\r uart_stream->read %p \n", uart_stream->read);
do
{
if (data_len_in_uart_buff > 0)
{
uart_stream->read(nic->uart_obj, temp_buff1 + temp_buff1_len, 1, &errcode);
if (find_frame_flag_index == 0 && temp_buff1[temp_buff1_len] == '+')
{
++find_frame_flag_index;
start1 = mp_hal_ticks_ms();
}
else if (find_frame_flag_index == 1 && temp_buff1[temp_buff1_len] == 'I')
{
++find_frame_flag_index;
}
else if (find_frame_flag_index == 2 && temp_buff1[temp_buff1_len] == 'P')
{
++find_frame_flag_index;
}
else if (find_frame_flag_index == 3 && temp_buff1[temp_buff1_len] == 'D')
{
++find_frame_flag_index;
}
else if (find_frame_flag_index == 4 && temp_buff1[temp_buff1_len] == ',')
{
++find_frame_flag_index;
}
else if (find_frame_flag_index == 5)
{
if (temp_buff1[temp_buff1_len] == ':')
{ // '+IPD,3,1452:' or '+IPD,1452:'
temp_buff1[temp_buff1_len + 1] = '\0';
char *index = strstr((char *)temp_buff1 + 5, ",");
if (index)
{ // '+IPD,3,1452:'
ret = sscanf((char *)temp_buff1, "+IPD,%hhd,%hd:", &mux_id, &frame_len);
if (ret != 2 || mux_id < 0 || mux_id > 4 || frame_len <= 0)
{ // format not satisfy, it's data
no_frame_flag = true;
}
else
{ // find frame start flag, although it may also data
new_frame = true;
}
}
else
{ // '+IPD,1452:'
ret = sscanf((char *)temp_buff1, "+IPD,%hd:", &frame_len);
if (ret != 1 || frame_len <= 0)
{ // format not satisfy, it's data
no_frame_flag = true;
}
else
{ // find frame start flag, although it may also data
new_frame = true;
// // printk("new frame:%d\r\n", frame_len);
}
}
}
}
else
{ // not match frame start flag, put into nic buffer
no_frame_flag = true;
}
// new frame or data
// or wait for frame start flag timeout(300ms, can be fewer), maybe they're data
if (new_frame || no_frame_flag || temp_buff1_len >= 12 ||
(find_frame_flag_index && (mp_hal_ticks_ms() - start1 > 300))) // '+IPD,3,1452:'
{
if (!new_frame)
{
if (frame_len_sum > 0)
{
// // printk("if(frame_len_sum > 0) { temp_buff2_len-%d temp_buff1_len-%d\r\n", temp_buff2_len, temp_buff1_len);
if (!Buffer_Puts(&nic->buffer, temp_buff1, temp_buff1_len + 1))
{
// printk("data_len_in_uart_buff %u temp_buff1_len %u temp_buff1 ", data_len_in_uart_buff, temp_buff1_len);
for (int i = 0; i < temp_buff1_len; i++) {
int tmp = temp_buff1[i];
// printk("(%c %02X)", temp_buff1[i], tmp);
}
// printk("\n");
// printk("data_len_in_uart_buff %u temp_buff1_len %u temp_buff1 ", data_len_in_uart_buff, temp_buff1_len);
for (int i = 0; i < temp_buff1_len; i++) {
int tmp = temp_buff1[i];
// printk("(%c %02X)", temp_buff1[i], tmp);
}
// printk("\n");
// overflow = true;
// break;//TODO:
}
}
else
{
if (temp_buff1[0] == 'C')
{
memset(temp_buff2, 0, sizeof(temp_buff2));
}
// // printk("-%d:%s\r\n", temp_buff2_len, temp_buff2);
// // printk("!(if(frame_len_sum > 0) {) temp_buff2_len-%d temp_buff1_len-%d\r\n", temp_buff2_len, temp_buff1_len);
temp_buff2[temp_buff2_len++] = temp_buff1[0];
// // printk("%c", temp_buff1[0]); //TODO: optimize uart overflow, if uart overflow, uncomment this will print some data
// // printk("-%d:%s\r\n", temp_buff2_len, temp_buff2);
if (strstr((const char *)temp_buff2, "CLOSED\r\n") != NULL)
{
// // printk("pear closed\r\n");
*peer_closed = true;
peer_just_closed = true;
break;
}
}
}
else
{
frame_len_sum += frame_len;
}
find_frame_flag_index = 0;
temp_buff1_len = 0;
new_frame = false;
no_frame_flag = false;
// enough data as required
size = Buffer_Size(&nic->buffer);
if (size >= out_buff_len) // data enough
break;
if (frame_len_sum != 0 && frame_len_sum <= size) // read at least one frame ok
{
break;
}
continue;
}
++temp_buff1_len;
}
if (timeout != 0 && (mp_hal_ticks_ms() - start2 > timeout) && !find_frame_flag_index)
{
// // printk("\n timeout %d start2 %d (mp_hal_ticks_ms() - start2 > timeout) %d find_frame_flag_index %d \n", timeout, start2, (mp_hal_ticks_ms() - start2 > timeout), find_frame_flag_index);
// // printk("\r-3 recvPkg nic %p out_buff %p out_buff_len %p data_len %p timeout %p coming_mux_id %p peer_closed %p first_time_recv %p\n", nic, out_buff, &out_buff_len, data_len, &timeout, coming_mux_id, peer_closed, &first_time_recv);
// printk("data_len_in_uart_buff %u temp_buff1_len %u temp_buff1 ", data_len_in_uart_buff, temp_buff1_len);
for (int i = 0; i < temp_buff1_len; i++) {
int tmp = temp_buff1[i];
// printk("(%c %02X)", temp_buff1[i], tmp);
}
// printk("\n");
return -3;
}
data_len_in_uart_buff = uart_rx_any(nic->uart_obj);
// // printk("\n2-%hd 1-%hd\n", temp_buff2_len, temp_buff1_len);
} while ((timeout || find_frame_flag_index) && (!*peer_closed || data_len_in_uart_buff > 0));
size = Buffer_Size(&nic->buffer);
if (size == 0 && !peer_just_closed && *peer_closed) //peer closed and no data in buffer
{
frame_len = 0;
frame_len_sum = 0;
// // printk("\r-4 recvPkg nic %p out_buff %p out_buff_len %p data_len %p timeout %p coming_mux_id %p peer_closed %p first_time_recv %p\n", nic, out_buff, &out_buff_len, data_len, &timeout, coming_mux_id, peer_closed, &first_time_recv);
return -4;
}
size = size > out_buff_len ? out_buff_len : size;
Buffer_Gets(&nic->buffer, (uint8_t *)out_buff, size);
if (data_len)
*data_len = size;
frame_len_sum -= size;
if (frame_len_sum <= 0 || peer_just_closed)
{
frame_len = 0;
frame_len_sum = 0;
Buffer_Clear(&nic->buffer);
if (peer_just_closed)
{
// // printk("\r-2 recvPkg nic %p out_buff %p out_buff_len %p data_len %p timeout %p coming_mux_id %p peer_closed %p first_time_recv %p\n", nic, out_buff, &out_buff_len, data_len, &timeout, coming_mux_id, peer_closed, &first_time_recv);
return -2;
}
}
// mp_printf(&mp_plat_print, "[MaixPy] %s | size %d out_buff_len %d *data_len %d \n", __func__, size, out_buff_len, *data_len);
return size;
}
旧 code 最大的问题在于处理过程单向思维,新 code 主要是上状态机分离 AT 指令和数据的处理过程。