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;
}
}
}