mydodo协议


wifi_串口协议v1.0.0

目录


帧结构

没帧数据由帧头+长度+载荷+校验和组成。

帧头1 帧头2 设备号 数据长度 数据 校验和
0x4D 0x59 xxx nByte xxxx BBC(异或校验)

例子:A5 5A 01 00 00,MCU上电初始化命令。

操作码 长度 载荷
1Byte 1Byte nBytes(0~130)

当一包数据最大只能20Bytes时,一帧数据可能会有拆包传输的情况,收到首包数据,需要根据长度字段判断该数据包是否接受完成,若长度字段大于18,则载荷部分拆包传输;若长度为0,则载荷部分为空。

命令

enum {
    eCmd_M2W_Init      = 0x00,    // MCU上电初始化
    eCmd_W2M_Init      = 0x01,    // WIFI上电初始化
    eCmd_W2M_WIFI_Conn = 0x02,    // wifi联网
    eCmd_M2W_Reset     = 0x03,    // 复位
    eCmd_M2W_Factory   = 0x04,    // 出厂模式

    eCmd_W2M_Update_Time    = 0x10,    // 更新时间
    eCmd_W2M_Update_Lunar   = 0x11,    // 更新农历
    eCmd_W2M_Update_Weather = 0x12,    // 更新天气
    eCmd_W2M_Sync_Time      = 0x13,    // 同步时间
    eCmd_W2M_Sync_Lunar     = 0x14,    // 同步农历
    eCmd_M2W_Sync_Weather   = 0x15,    // 同步天气

    eCmd_W2M_CFG_ALarm  = 0x20,    // 配置闹钟
    eCmd_W2M_Crtl_ALarm = 0x21,    // 控制闹钟
    eCmd_W2M_Play_Music = 0x22,    // 播放铃声

    eCmd_W2M_CFG_Sleep      = 0x30,    // 配置睡眠
    eCmd_W2M_Preview_SLight = 0x31,    // 预览睡眠亮度

    eCmd_W2M_CFG_HourMode       = 0x40,    // 配置时钟模式
    eCmd_M2W_CFG_HourMode       = 0x40,    // 配置时钟模式
    eCmd_W2M_CFG_TempMode       = 0x41,    // 配置温度模式
    eCmd_M2W_CFG_TempMode       = 0x41,    // 配置温度模式
    eCmd_W2M_CFG_DateMode       = 0x42,    // 配置日月模式
    eCmd_W2M_CFG_Scroll_Weather = 0x43,    // 配置天气切换
    eCmd_M2W_CFG_Scroll_Weather = 0x43,    // 配置天气切换
    eCmd_W2M_CFG_Content        = 0x44,    // 配置显示内容
    eCmd_W2M_CFG_Screen_SW      = 0x45,    // 配置屏幕关闭切换
    eCmd_W2M_CFG_Light          = 0x46,    // 配置屏幕亮度
    eCmd_M2W_CFG_Light          = 0x46,    // 配置屏幕亮度

    eCmd_W2M_Test_Init   = 0xF0,    // 产测开始
    eCmd_W2M_Test_RISS   = 0xF1,    // 产测信号强度
    eCmd_W2M_Test_Finish = 0xF2,    // 产测完成
    eCmd_W2M_Test_Failed = 0xF3,    // 产测失败
};

命令中,W2M类型命令属于是WIFI发往MCU指令;M2W类型命令属于MCU发往WIFI指令。

协议

代码样例

enum {
    eUart_Head0 = 0x00,
    eUart_Head1,
    eUart_Len,
    eUart_Body,
    eUart_CheckSum,
};

static uint8_t uart_protocol_state = eUart_Head0;
static uint8_t recv_timeout_cnt    = 0;

os_timer_t recv_timeout_timer;

/**
 * @brief  校验和
 * @note
 * @param  *source:
 * @param  len:
 * @retval
 */
uint8_t BCC_Check(uint8_t *dat, uint8_t dsize)
{
	uint8_t i=0;
        uint8_t check_sum = dat[0];

	for(i=1; i<dsize; i++)
		check_sum ^= dat[i];
	return check_sum;
}

/**
 * @brief  串口数据发送
 * @note
 * @param  *payload:
 * @param  payload_len:
 * @retval None
 */
void user_uart1_protocol_send(uint8_t *payload, uint8_t payload_len) {
    uint8_t buff[128] = {0};
    uint8_t checksum  = 0;
    uint8_t buff_len  = 0;

    buff[0] = UART_PROTOCOL_HEAD0;
    buff[1] = UART_PROTOCOL_HEAD1;
    buff[2] = payload_len;
    memcpy(&buff[3], payload, payload_len);
    checksum              = user_protocol_checksum(payload, payload_len);
    buff[3 + payload_len] = checksum;
    buff_len              = 4 + payload_len;

    uart_write(UART1, buff, buff_len);
}

/**
 * @brief  串口接收协议处理
 * @note
 * @retval None
 */
void user_uart1_recv_protocol_process(void) {
    static uint8_t byte_buf      = 0;
    static uint8_t payload_index = 0;

    while (fifo_get_cnt(&fifo_uart_recv) > 0) {
        fifo_getone(&fifo_uart_recv, &byte_buf);
        // LOG_INFO("byte_buf:%02X \r\n", byte_buf);

        switch (uart_protocol_state) {
        case eUart_Head0: {
            if (UART_PROTOCOL_HEAD0 == byte_buf) {
                uart_protocol_state++;
                os_timer_start(&recv_timeout_timer, 10, 1);
                recv_timeout_cnt = 0;
            }
            break;
        }
        case eUart_Head1: {
            if (UART_PROTOCOL_HEAD1 == byte_buf) {
                uart_protocol_state++;
                recv_timeout_cnt = 0;
            } else {
                if (UART_PROTOCOL_HEAD0 == byte_buf) {
                    recv_timeout_cnt = 0;
                } else {
                    uart_protocol_state--;
                    os_timer_stop(&recv_timeout_timer);
                }
            }

            break;
        }
        case eUart_Len: {
            payload_len = byte_buf;
            if (payload_len <= sizeof(payload_buff)) {
                payload_index = 0;
                uart_protocol_state++;
                recv_timeout_cnt = 0;
            } else {
                uart_protocol_state = eUart_Head0;
                os_timer_stop(&recv_timeout_timer);
            }
            break;
        }
        case eUart_Body: {
            payload_buff[payload_index] = byte_buf;
            payload_index++;
            if (payload_index == payload_len) {
                uart_protocol_state++;
            }
            recv_timeout_cnt = 0;
            break;
        }
        case eUart_CheckSum: {
            uint8_t check_sum     = byte_buf;
            uint8_t clc_check_sum = 0;

            os_timer_stop(&recv_timeout_timer);

            clc_check_sum = user_protocol_checksum(payload_buff, payload_len);
            if (clc_check_sum == check_sum) {
                // TODO: 解析协议
                user_protocol_recv_process(payload_buff, payload_len);
            }
            uart_protocol_state = eUart_Head0;
            break;
        }
        }
    }
}

/**
 * @brief  接收超时处理
 * @note
 * @param  *arg:
 * @retval None
 */
static void timer_recv_timeout_func(void *arg) {
    recv_timeout_cnt++;
    if (recv_timeout_cnt == 3) {
        uart_protocol_state = eUart_Head0;
        os_timer_stop(&recv_timeout_timer);
        LOG_ERR("uart recv timeout\r\n");
    }
}


/**
 * @brief  接收协议处理
 * @note
 * @param  *data:
 * @param  len:
 * @retval None
 */
void user_protocol_recv_process(uint8_t *data, uint8_t len) {
    if ((data == NULL) || (len == 0)) {
        return;
    }

    uint8_t *ptr  = data;
    uint8_t  len_ = len - 1;

    switch (*ptr++) {
    case eCmd_W2M_Init: {
        LOG_INFO("eCmd_W2M_Init\r\n");
        break;
    }
    case eCmd_W2M_WIFI_Conn: {
         // TODO: wifi连接处理
        break;
    }
    case eCmd_W2M_Update_Time: {
        // TODO: 更新时间
        break;
    }
    case eCmd_W2M_Update_Lunar: {
        // TODO: 更新农历时间
        break;
    }
    case eCmd_W2M_Update_Weather: {
        // TODO: 更新天气
        break;
    }
    case eCmd_W2M_CFG_ALarm: {
        // TODO: 配置闹钟
        break;
    }
    case eCmd_W2M_Crtl_ALarm: {
        // TODO: 控制闹钟
        break;
    }
    case eCmd_W2M_Play_Music: {
        // TODO: 播放铃声
        break;
    }
    case eCmd_W2M_CFG_Sleep: {
        // TODO: 配置睡眠
        break;
    }
    case eCmd_W2M_Preview_SLight: {
        // TODO: 预览睡眠亮度
        break;
    }
    case eCmd_W2M_CFG_HourMode: {
        // TODO: 配置小时制
    }
    case eCmd_W2M_CFG_Scroll_Weather: {
        // TODO: 配置天气滚动
        break;
    }
    case eCmd_W2M_CFG_Light: {
        // TODO: 配置亮度
        break;
    }
    }
}

上一篇:day34 网络编程


下一篇:Python 复习笔记 socket