重构+优化 micropython 下 k210 (esp8285) 的 AT network 通信过程,附代码。

回头再解释,先 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 指令和数据的处理过程。

猜你喜欢

转载自www.cnblogs.com/juwan/p/12791366.html
今日推荐