/* * ne_sweeper.c -- provide iot-system device layer of yanxuan sweeper operation interface. * * * ORIGINAL AUTHOR: * * Copyright (c) 2018 Netease Corporation */ #include "c_types.h" #include "user_main.h" #include "ne_sweeper.h" #include "esp_common.h" #include "cfg.h" #include "uart.h" #include "log.h" #include "ne_device.h" #include "esp_MSG_ctrl.h" #include "ota.h" #include "freertos/semphr.h" static void *yanxuan_sweeper_sema; /* * yanxuan sweeper uart init. */ int32 yanxuan_sweeper_init(void *arg) { UART_WaitTxFifoEmpty(UART0); UART_WaitTxFifoEmpty(UART1); UART_IntrConfTypeDef uart_intr; uart_intr.UART_IntrEnMask = UART_RXFIFO_TOUT_INT_ENA | UART_FRM_ERR_INT_ENA | UART_RXFIFO_FULL_INT_ENA; uart_intr.UART_RX_FifoFullIntrThresh = 120; uart_intr.UART_RX_TimeOutIntrThresh = 2; uart_intr.UART_TX_FifoEmptyIntrThresh = 10; UART_IntrConfig(UART0, &uart_intr); UART_ConfigTypeDef uart_config; uart_config.baud_rate = BIT_RATE_115200; uart_config.data_bits = UART_WordLength_8b; uart_config.parity = USART_Parity_None; uart_config.stop_bits = USART_StopBits_1; uart_config.flow_ctrl = USART_HardwareFlowControl_CTS_RTS; uart_config.UART_RxFlowThresh = 120; uart_config.UART_InverseMask = UART_None_Inverse; UART_ParamConfig(UART0, &uart_config); uart_config.flow_ctrl = USART_HardwareFlowControl_None; UART_ParamConfig(UART1, &uart_config); UART_SetPrintPort(UART1); // uart1 for log. ETS_UART_INTR_ENABLE(); yanxuan_sweeper_sema = xSemaphoreCreateMutex(); if (yanxuan_sweeper_sema == NULL) { LOG_EX(LOG_Info, "init fail!\r\n"); return -ERR_FAIL; } return ERR_OK; } int32 yanxuan_sweeper_deinit(void * arg) { return ERR_OK; } int32 yanxuan_sweeper_write(void *arg, uint8 *input, uint32 len) { xSemaphoreTake(yanxuan_sweeper_sema, portMAX_DELAY); uart_tx_buf(0, input, len); xSemaphoreGive(yanxuan_sweeper_sema); return ERR_OK; } /* * yanxuan sweeper read datas. */ int32 yanxuan_sweeper_read(void *arg, uint8 **output, uint32 *len) { static int32 recv_temp_len=0; ne_uart_recv_t * recv = ne_get_uart_recv_info(); if(recv->recv_len > recv_temp_len){ recv_temp_len = recv->recv_len; } else if(recv->recv_len == recv_temp_len && recv_temp_len != 0){ *len = recv_temp_len; *output = recv->uart_buf; recv_temp_len = 0; return ERR_OK; } else{ recv_temp_len = 0; } return -ERR_FAIL; } /* * yanxuan sweeper 8bit check. */ uint8 yanxuan_sweeper_check_8bit (uint8* in_data,uint8 in_len) { uint8 crc = 0; uint8 loop = 0; for (loop = 0;loop < in_len; loop++) { crc += in_data[loop]; } crc = ~crc; crc += 1; return crc; } /* * yanxuan sweeper 16bit check. */ uint16 yanxuan_sweeper_check_16bit(uint8_t *input, uint16 input_len) { uint16 check_sum=0; uint16 loop; for(loop=0;loopframe_header[0]<<0); frame_header |= (header_b->frame_header[1]<<8); /* header check */ if (header->frame_header != 0xAA && frame_header != 0xefcc) continue; /* sweeper protocol check */ if(header->frame_header == 0xAA){ if ((header == NULL) || (len - pos < sizeof(yanxuan_sweeper_protocol_header_t)) || (header->msg_len > len - pos - 1)) continue; /* get checksum */ if (input[header->msg_len + pos] != yanxuan_sweeper_check_8bit(&(header->msg_len), header->msg_len - 1)) { LOG_EX(LOG_Debug," yanxuan_sweeper_check_8bit error!\r\n"); continue; } *out_len = header->msg_len + 1; memcpy(output, input + pos, *out_len); *offset =pos + *out_len; return MSG_DIRECTION_UART_UP; } /* sweeper expand protocol check */ else if(frame_header == 0xefcc){ if((header_b == NULL) || (len - pos < sizeof(yanxuan_sweeper_expand_protocol_header_t))) continue; msg_len = (header_b->msg_len[0]<<0); msg_len |= (header_b->msg_len[1]<<8); if(msg_len > NE_DEVICE_BUF_SIZE || (msg_len > len - pos - 2)){ LOG_EX(LOG_Debug," len overflow!\r\n"); continue; } check_sum_d = input[msg_len + pos]; check_sum_d |= input[msg_len+1 + pos]<<8; /* get checksum */ check_sum_c = yanxuan_sweeper_check_16bit((uint8 *)&header_b->msg_len, msg_len - 2); if(check_sum_d != check_sum_c){ LOG_EX(LOG_Debug,"check_sum_d=0x%x, check_sum_c=0x%x\r\n",check_sum_d, check_sum_c); continue; } *out_len = msg_len + 2; memcpy(output, input + pos, *out_len); *offset =pos + *out_len; return MSG_DIRECTION_BDATA_UP; } } *offset = pos; return -ERR_FAIL; } int yanxuan_sweeper_create_frame(uint8_t cmd, uint8_t *payload, int in_len, uint8 *output, int max_len) { yanxuan_sweeper_protocol_header_t *msg_header; int count = 0; int msg_len; /* params check */ if(payload == NULL || output == NULL || in_len <= 0 || in_len + sizeof(yanxuan_sweeper_protocol_header_t) + 1 > max_len){ return -ERR_FAIL; } msg_header = (yanxuan_sweeper_protocol_header_t *)output; memset(msg_header, 0 , sizeof(yanxuan_sweeper_protocol_header_t)); /* set msg header */ msg_header->frame_header = 0xaa; msg_header->msg_len = in_len + sizeof(yanxuan_sweeper_protocol_header_t) - 1; msg_header->device_type = 0xb8; msg_header->msg_id = cmd; /* get payload */ memcpy(output + sizeof(yanxuan_sweeper_protocol_header_t), payload, in_len); /* calculate sum */ output[msg_header->msg_len] = yanxuan_sweeper_check_8bit(&msg_header->msg_len, msg_header->msg_len - 1); /* message len */ msg_len = msg_header->msg_len + 1; return msg_len; } void yanxuan_sweeper_connect_rsp(uint8 result) { uint8_t r_buf[] = {0xaa,0x0c,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x01,0x01,0xff}; LOG_EX(LOG_Info, "connect respond to mcu!\r\n"); r_buf[10] = result; // 1:success r_buf[r_buf[1]] = yanxuan_sweeper_check_8bit(&r_buf[1], r_buf[1]-1); yanxuan_sweeper_write(NULL, r_buf, sizeof(r_buf)); } static void _yanxuan_sweeper_enter_softap(void) { ne_cfg_set_init_type(NE_DEVICE_APCONFIG); // wifi_station_disconnect(); // vTaskDelay(500 / portTICK_RATE_MS); system_restart(); } static void _yanxuan_sweeper_exit_softap(void) { uint8_t r_buf[] = {0xaa,0x0c,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x01,0x01,0xff}; LOG_EX(LOG_Info, "exit softap!\r\n"); wifi_set_opmode(STATION_MODE); //SoftAPExitCfgMode(0); ne_cfg_set_init_type(NE_DEVICE_NORMAL); /* respond */ r_buf[10] = 1; // 1:success r_buf[r_buf[1]] = yanxuan_sweeper_check_8bit(&r_buf[1], r_buf[1]-1); yanxuan_sweeper_write(NULL, r_buf, sizeof(r_buf)); vTaskDelay(500 / portTICK_RATE_MS); /* restart */ system_restart(); } static void _yanxuan_sweeper_cannel_bind(void) { uint8_t r_buf[] = {0xaa,0x0c,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x84,0x01,0x01,0xff}; wifi_station_disconnect(); ne_clear_ssid_psk(); // respond OK LOG_EX(LOG_Info, "cannel bind!\r\n"); r_buf[10] = 1; // 1:success r_buf[r_buf[1]] = yanxuan_sweeper_check_8bit(&r_buf[1], r_buf[1]-1); yanxuan_sweeper_write(NULL, r_buf, sizeof(r_buf)); } static void _yanxuan_sweeper_clear_ssid(void) { uint8_t r_buf[] = {0xaa,0x0b,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x01,0xff}; wifi_station_disconnect(); ne_clear_ssid_psk(); // respond OK LOG_EX(LOG_Info, "clear ssid!\r\n"); r_buf[10] = 1; // 1:success r_buf[r_buf[1]] = yanxuan_sweeper_check_8bit(&r_buf[1], r_buf[1]-1); yanxuan_sweeper_write(NULL, r_buf, sizeof(r_buf)); } static void _yanxuan_sweeper_ota_process(uint8_t *input, uint8_t len) { uint8_t msg_type; yanxuan_sweeper_protocol_header_t* header = (yanxuan_sweeper_protocol_header_t*)input; if(len > 255){ LOG_EX(LOG_Error, "len error!\r\n"); } input += sizeof(yanxuan_sweeper_protocol_header_t); msg_type = input[0]; switch(msg_type){ case 0x02: { struct OTA_Start_Cmd cmd; cmd.type = OTA_DEVICE_MCU; MSG_ctrl_cmd_put(MSG_CONTROL_CMD_OTA_START, &cmd); } break; case 0x03: { struct OTA_SegDownload_Cmd cmd; cmd.seg_num = input[1]; cmd.seg_size = 256*1000; MSG_ctrl_cmd_put(MSG_CONTROL_CMD_OTA_SEGDOWNLOAD, &cmd); } break; case 0x04: { struct OTA_SegRead_Cmd cmd; cmd.length = (input[1]<<0); cmd.length |= (input[2]<<8); cmd.offset = (input[3]<<0); cmd.offset |= (input[4]<<8); cmd.offset |= (input[5]<<16); cmd.offset |= (input[6]<<24); MSG_ctrl_cmd_put(MSG_CONTROL_CMD_OTA_SEGREAD, &cmd); } break; case 0x05: { struct OTA_Quit_Cmd cmd; MSG_ctrl_cmd_put(MSG_CONTROL_CMD_OTA_QUIT, &cmd); } break; case 0x11: // ProCacheMCUMsg(input, len, MSG_TYPE_BYPASS); break; } } /* * yanxuan sweeper protocol process. */ int32 yanxuan_sweeper_process(void *arg, uint8 msgdir, uint8 *input, uint32 ilen, uint8 *output, uint32 max_len) { uint8 msg_id; yanxuan_sweeper_protocol_header_t* header = (yanxuan_sweeper_protocol_header_t*)input; LOG_EX(LOG_Info, "[msgdir]=%d [msg_id]=0x%x [ilen] = %u\n", msgdir, header->msg_id, ilen); /* protocol process */ if(msgdir == MSG_DIRECTION_BDATA_UP){ ProCacheMCUMsg(input, ilen, MSG_TYPE_BIGDATA); } else if (msgdir == MSG_DIRECTION_CLOUD_DOWN || msgdir == MSG_DIRECTION_OTA_DOWN || msgdir == MSG_DIRECTION_BDATA_DOWN){ if(ilen > max_len) return -ERR_FAIL; memcpy(output, input, ilen); return ilen; } else { switch (header->msg_id) { case 0x04: case 0x05: ProCacheMCUMsg(input, ilen, MSG_TYPE_SHADOW); break; case 0x02: case 0x03: case 0x20: case 0x06: ProCacheMCUMsg(input, ilen, MSG_TYPE_BYPASS); break; case 0x08: _yanxuan_sweeper_ota_process(input, ilen); break; case 0x63: set_platform_product_id(input + 12, 4); _yanxuan_sweeper_enter_softap(); break; case 0x82: _yanxuan_sweeper_exit_softap(); break; case 0x84: _yanxuan_sweeper_cannel_bind(); break; case 0x86: _yanxuan_sweeper_clear_ssid(); break; default: break; } } return ERR_OK; }