/** @file quec_wifi_msg.c @brief Quectel wifi msg api. */ /*============================================================================ Copyright (c) 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved. Quectel Wireless Solution Proprietary and Confidential. =============================================================================*/ /*=========================================================================== EDIT HISTORY FOR MODULE This section contains comments describing changes made to the module. Notice that changes are listed in reverse chronological order. WHEN WHO WHAT, WHERE, WHY ---------- ------------ ---------------------------------------------------- =============================================================================*/ /*=========================================================================== * include files ===========================================================================*/ #include #include #include #include "quec_cust_feature.h" #include "quec_debug.h" #include "quec_rtos.h" #include "quec_common.h" #include "quec_wifi_app.h" #include "quec_wifi_msg.h" #include "quec_wifi_uart.h" #include "quec_wifi_spi.h" #ifndef MIN_SYS #ifdef QUEC_FGM842D_WIFI_SUPPORT /*======================================================================== * Macro Definition *========================================================================*/ #define QUEC_WIFI_MSG_LOG(msg, ...) custom_log("WIFI_MSG", msg, ##__VA_ARGS__) #define QUEC_FREE_PTR(p) {if(p != NULL) {free(p);p = NULL;}} #define QUEC_WIFI_MSG_TASK_EVENT_CNT 5 #define QUEC_WIFI_MSG_MSG_QUEUE_CNT 200 #ifdef LTEONLY_THIN_SINGLE_SIM_2MFLASH #define QUEC_WIFI_MSG_THREAD_PRIORITY 83 #else #define QUEC_WIFI_MSG_THREAD_PRIORITY 33 #endif /*======================================================================== * Enumeration Definition *========================================================================*/ /*======================================================================== * Type Definition *=========================================================================*/ typedef struct { quec_task_t task; quec_wifi_msg_app_notify_cb msg_notify_cb; char *malloc_data_field; quec_queue_t msg_queue; } quec_wifi_msg_manager_s; /*======================================================================== * Global Variable *========================================================================*/ quec_wifi_msg_manager_s quec_wifi_msg_manager = {0}; quec_mutex_t quec_wifi_msg_mutex = NULL; /*======================================================================== * function Definition *========================================================================*/ extern void wifi_dump_buffer(const char *name, unsigned char *buf, int len); quec_wifi_msg_errcode_e quec_wifi_msg_app_notify_cb_register(quec_wifi_msg_app_notify_cb cb) { // APP engine notification cb for handling app command quec_wifi_msg_manager_s *manager = &quec_wifi_msg_manager; quec_rtos_mutex_lock(quec_wifi_msg_mutex, 0xFFFFFFFF); manager->msg_notify_cb = cb; quec_rtos_mutex_unlock(quec_wifi_msg_mutex); return QUEC_WIFI_MSG_SUCCESS; } int quec_wifi_msg_npto_parse(char *src, int src_len, quec_wifi_msg_protocol_head_info_s *cmdPkt, int *dst_len, int *result) { int i = 0; int cmdlen = 0; char *ptr = src; unsigned char checksum; //wifi_dump_buffer("msg", src, src_len); // Check source input length if (src_len < QUEC_PROTOCOL_HEAD_MAX_SIZE) { QUEC_WIFI_MSG_LOG("less than protocol header size!!\r\n"); *dst_len = 0; // free no magic buff *result = QUEC_WIFI_NPTO_PARSE_RESULT_TOOSMALL; return -1; } // Find header identification "QUEC_WIFI_UART_MAGIC0 QUEC_WIFI_UART_MAGIC1" for (i = 0; i < (src_len - 1); i++) { if (ptr[i] == QUEC_WIFI_UART_MAGIC0 && ptr[i + 1] == QUEC_WIFI_UART_MAGIC1) { break; } } QUEC_WIFI_MSG_LOG("i=%d", i); // Return error when no header if (i >= (src_len - 1)) { QUEC_WIFI_MSG_LOG("no search magic!!"); /* Parse error: No valid magic header,returns i as parsing length. e.g. "0x12 0x34 0x56..."=>*dst_len = i */ *dst_len = i; *result = QUEC_WIFI_NPTO_PARSE_RESULT_NOMAGIC; return -1; } // Check command length cmdlen = src_len - i; if (cmdlen < QUEC_PROTOCOL_HEAD_MAX_SIZE) { QUEC_WIFI_MSG_LOG("to small!! cmdlen = %d", cmdlen); /* Parse error: No valid parsing buffer length,returns i as parsing length. e.g. "uint8_t uint8_t"=>*dst_len = i */ *dst_len = i; *result = QUEC_WIFI_NPTO_PARSE_RESULT_TOOSMALL; return 0; } // Get command header memcpy(cmdPkt, &ptr[i], QUEC_PROTOCOL_HEAD_MAX_SIZE); if (cmdPkt->cmdlen > QUEC_PROTOCOL_MSG_MAX_LEN) { /* Parse error: Command length from header is too large,but is valid.Return i + 2 as parsing length. e.g. "uint8_t uint8_t uint16_t"=>*dst_len = i + 2 */ *dst_len = i + 2; *result = QUEC_WIFI_NPTO_PARSE_RESULT_UNKNOWN; return -1; } // Check if command length is valid if (cmdPkt->cmdlen > cmdlen) { QUEC_WIFI_MSG_LOG("to small!!cmdPkt->cmdlen = %d cmdlen=%d", cmdPkt->cmdlen, cmdlen); /* Parse error: Command length from header is larger than parsing buffer length.Drop command length.Return i as parsing length. e.g. "uint8_t uint8_t"=>*dst_len = i */ *dst_len = i; *result = QUEC_WIFI_NPTO_PARSE_RESULT_TOOSMALL; return 0; } // Get data field if ((cmdPkt->cmdlen - QUEC_PROTOCOL_HEAD_MAX_SIZE) > 0) { cmdPkt->data = malloc(cmdPkt->cmdlen - QUEC_PROTOCOL_HEAD_MAX_SIZE+1);//add \0 to end QUEC_WIFI_MSG_LOG("cmdPkt->data = %p", cmdPkt->data); if (cmdPkt->data == NULL) { QUEC_WIFI_MSG_LOG("malloc failed cmdPkt->cmdlen=%d", cmdPkt->cmdlen); /* Malloc error: No enough memory.Return i + 2 as parsing length. e.g. "uint8_t uint8_t uint16_t"=>*dst_len = i + 2 */ *dst_len = i + 2; *result = QUEC_WIFI_NPTO_PARSE_RESULT_UNKNOWN; return -1; } // Copy data field memset(cmdPkt->data,0,cmdPkt->cmdlen - QUEC_PROTOCOL_HEAD_MAX_SIZE+1); memcpy(cmdPkt->data, &ptr[i + QUEC_PROTOCOL_HEAD_MAX_SIZE], cmdPkt->cmdlen - QUEC_PROTOCOL_HEAD_MAX_SIZE); } if (cmdPkt->checksum != 0) // WIFI UART UL FRAME { // Set checksum 0 for re-calculation ptr[i + 5] = 0; checksum = npto_CRC(&ptr[i], cmdPkt->cmdlen); // Compare checksum from header to calculated checksum if (checksum != cmdPkt->checksum) { QUEC_WIFI_MSG_LOG("crc check error checksum=%x cmdPkt->checksum=%x", checksum, cmdPkt->checksum); /* Checksum error: Checksum mismatched.Return i + 2 as parsing length. e.g. "uint8_t uint8_t uint16_t"=>*dst_len = i + 2 */ if (cmdPkt->data != NULL) { free(cmdPkt->data); cmdPkt->data = NULL; } *dst_len = i + 2; *result = QUEC_WIFI_NPTO_PARSE_RESULT_ERRCRC; return -1; } } /* Parse successfully.Return i + command length as parsing length. e.g. "uint8_t uint8_t ......"=>*dst_len = i + cmdPkt->cmdlen */ *dst_len = i + cmdPkt->cmdlen; *result = QUEC_WIFI_NPTO_PARSE_RESULT_SUCC; return QUEC_WIFI_NPTO_PARSE_RESULT_SUCC; } int quec_wifi_msg_recv(void *ctx) { quec_wifi_msg_info_s *info = (quec_wifi_msg_info_s *)ctx; quec_wifi_msg_manager_s *manager = &quec_wifi_msg_manager; // Data streams from UART/SPI and so on.It needs to be registered as physical device callback. // Once we get data,it will be passed to MSG engine. QuecOSStatus err; quec_wifi_msg_info_s msg_info = {0}; msg_info.data = info->data; msg_info.data_len = info->data_len; QUEC_WIFI_MSG_LOG("msg_info.data=%p", msg_info.data); err = quec_rtos_queue_release(manager->msg_queue, sizeof(quec_wifi_msg_info_s), (uint8 *)&msg_info, QUEC_NO_WAIT); if (err != kNoErr) { free(info->data); info->data = NULL; QUEC_WIFI_MSG_LOG("release msg_queue failed"); } return err; } /*使能staæ—?, 接受到的cmd大致ä¸?: ->41(QUEC_WIFI_APP_RESET_DONE) ->7 (QUEC_WIFI_NPTO_WLAN_DESTROY_CMD) ->6 (QUEC_WIFI_NPTO_WLAN_CREATE_CMD) ->1 (QUEC_WIFI_NPTO_STA_IP_START_CMD) */ quec_wifi_msg_protocol_info_s protocol_info = {0}; static void quec_wifi_msg_thread(void *argv) { QuecOSStatus err; quec_wifi_msg_info_s msg_info = {0}; int max_cache_len = QUEC_MSG_CACHE_MAX_LEN; // max cache 4 data quec_wifi_msg_protocol_head_info_s protocol_head_info = {0}; int dst_buff_len = 0; int result = 0; quec_wifi_msg_manager_s *manager = &quec_wifi_msg_manager; // Create message queue err = quec_rtos_queue_create(&manager->msg_queue, sizeof(quec_wifi_msg_info_s), QUEC_WIFI_MSG_MSG_QUEUE_CNT); if (err) { goto exit; } // Malloc command data streams receive cache protocol_info.data = malloc(max_cache_len); if (protocol_info.data == NULL) { err = -1; goto exit; } // Pointer is used for deinit. manager->malloc_data_field = protocol_info.data; memset(&protocol_head_info, 0, sizeof(quec_wifi_msg_protocol_head_info_s)); while (1) { memset(&msg_info, 0, sizeof(quec_wifi_msg_info_s)); protocol_head_info.data = NULL; dst_buff_len = 0; result = 0; err = quec_rtos_queue_wait(manager->msg_queue, (uint8 *)&msg_info, sizeof(quec_wifi_msg_info_s), QUEC_WAIT_FOREVER); if (err != kNoErr) { QUEC_WIFI_MSG_LOG("wait error err= %d", err); goto exit; } // Protocol processing if (msg_info.data_len + protocol_info.data_len > max_cache_len) { QUEC_WIFI_MSG_LOG("msg data too long!!!!!"); goto exit; } //将数æ�?追加到未处理的数æ�?尾部 memcpy(protocol_info.data + protocol_info.data_len, msg_info.data, msg_info.data_len); //重新计算æœ?处理的数æ�?长度. protocol_info.data_len = protocol_info.data_len + msg_info.data_len; while (protocol_info.data_len > 0) { check_parse: quec_wifi_msg_npto_parse(protocol_info.data, protocol_info.data_len, &protocol_head_info, &dst_buff_len, &result); QUEC_WIFI_MSG_LOG("data_len=%d dst_buff_len=%d result=%d", protocol_info.data_len, dst_buff_len, result); if (dst_buff_len > 0 && protocol_info.data_len >= dst_buff_len) { memmove(protocol_info.data, protocol_info.data + dst_buff_len, protocol_info.data_len - dst_buff_len); protocol_info.data_len -= dst_buff_len; if(QUEC_WIFI_NPTO_PARSE_RESULT_ERRCRC==result && protocol_info.data_len >= QUEC_PROTOCOL_HEAD_MAX_SIZE) { goto check_parse; } } // protocol success if (result == QUEC_WIFI_NPTO_PARSE_RESULT_SUCC) { QUEC_WIFI_MSG_LOG("rx wifi cmd=%d", protocol_head_info.command); switch (protocol_head_info.command) { case QUEC_WIFI_NPTO_802_3_STREAM: { // Pass data streams to NET engine extern int quec_wifi_uart_ul(uint8_t *data,uint16_t len); if(quec_wifi_uart_ul(protocol_head_info.data,(protocol_head_info.cmdlen - QUEC_PROTOCOL_HEAD_MAX_SIZE))) { QUEC_WIFI_MSG_LOG("UART UL ERROR"); } QUEC_FREE_PTR(protocol_head_info.data); break; } case QUEC_WIFI_NPTO_STA_IP_START_CMD: { quec_wifi_sta_ip_start(protocol_head_info.data); QUEC_FREE_PTR(protocol_head_info.data); break; } case QUEC_WIFI_NPTO_STA_IP_DOWN_CMD: { quec_wifi_sta_ip_down(NULL); //protocol_head_info.data is 0, no need to free. break; } case QUEC_WIFI_NPTO_UAP_IP_START_CMD: case QUEC_WIFI_NPTO_UAP_STA_CONNECT_CMD: { if(quec_wifi_wlan_create(protocol_head_info.data) == QUEC_WIFI_SUCCESS) { quec_wifi_uap_ip_start(protocol_head_info.data); } QUEC_FREE_PTR(protocol_head_info.data); break; } case QUEC_WIFI_NPTO_UAP_IP_DOWN_CMD: { quec_wifi_wlan_lan_destroy(protocol_head_info.data); QUEC_FREE_PTR(protocol_head_info.data); break; } case QUEC_WIFI_NPTO_WLAN_CREATE_CMD: { quec_wifi_wlan_create(protocol_head_info.data); QUEC_FREE_PTR(protocol_head_info.data); break; } case QUEC_WIFI_NPTO_WLAN_DESTROY_CMD: { quec_wifi_wlan_destroy(protocol_head_info.data); QUEC_FREE_PTR(protocol_head_info.data); break; } case QUEC_WIFI_NPTO_UAP_STA_DISCONNECT_CMD: { quec_wifi_wlan_destory_lan_by_id(protocol_head_info.data); QUEC_FREE_PTR(protocol_head_info.data); break; } case QUEC_WIFI_APP_STA_STATUS_CMD: { quec_rtos_mutex_lock(quec_wifi_msg_mutex, 0xFFFFFFFF); if (manager->msg_notify_cb != NULL) { quec_wifi_msg_cmd_info_s info = { .msg_id = QUEC_WIFI_APP_STA_LINK_STATUS_CMD, .msg_info = protocol_head_info.data}; manager->msg_notify_cb(&info); } else { QUEC_FREE_PTR(protocol_head_info.data); } quec_rtos_mutex_unlock(quec_wifi_msg_mutex); break; } case QUEC_WIFI_APP_SCAN_START_CMD: case QUEC_WIFI_APP_EVENT_NOTIFY: case QUEC_WIFI_APP_OTA_CMD: case QUEC_WIFI_BOOT_UPGRADE_CMD: case QUEC_WIFI_APP_GET_VERSION: case QUEC_WIFI_APP_RESET_DONE: case QUEC_WIFI_APP_SET_BLACK_MAC: case QUEC_WIFI_APP_WIFI_STATE_REPORT: case QUEC_BLE_APP_INFO_RPT: case QUEC_BLE_APP_GET_BLE_MAC_ADDR_CMD: case QUEC_WIFI_APP_AP_SET_CHANNEL: { quec_rtos_mutex_lock(quec_wifi_msg_mutex, 0xFFFFFFFF); if (manager->msg_notify_cb != NULL) { quec_wifi_msg_cmd_info_s info = { .msg_id = protocol_head_info.command, .msg_info = protocol_head_info.data}; manager->msg_notify_cb(&info); //will free protocol_head_info.data in function quec_wifi_app_thread } else { QUEC_FREE_PTR(protocol_head_info.data); } quec_rtos_mutex_unlock(quec_wifi_msg_mutex); break; } default: { QUEC_FREE_PTR(protocol_head_info.data); QUEC_WIFI_MSG_LOG("command=%d error", protocol_head_info.command); break; } } } else { break; } } QUEC_WIFI_MSG_LOG("msg_info.data=%p", msg_info.data); if (msg_info.data != NULL) { free(msg_info.data); msg_info.data = NULL; } } exit: quec_rtos_mutex_lock(quec_wifi_msg_mutex, 0xFFFFFFFF); QUEC_WIFI_MSG_LOG("quec_wifi_msg_init set 0"); memset(manager, 0, sizeof(quec_wifi_msg_manager_s)); quec_rtos_mutex_unlock(quec_wifi_msg_mutex); quec_rtos_task_delete(NULL); return; } quec_wifi_msg_errcode_e quec_wifi_msg_init(void *argv) { quec_wifi_msg_errcode_e ret = QUEC_WIFI_MSG_SUCCESS; quec_wifi_msg_manager_s *manager = &quec_wifi_msg_manager; QUEC_WIFI_MSG_LOG("quec_wifi_msg_init"); // Create mutex.Never delete. if (NULL == quec_wifi_msg_mutex) { if (0 != quec_rtos_mutex_create(&(quec_wifi_msg_mutex))) { ret = QUEC_WIFI_MSG_MUTEX_CREATE_ERR; return ret; } } if(manager->task==NULL) { memset(manager, 0, sizeof(quec_wifi_msg_manager_s)); QUEC_WIFI_MSG_LOG("quec_wifi_msg_init set 0"); if (0 != quec_rtos_task_create(&manager->task, 2048, QUEC_WIFI_MSG_THREAD_PRIORITY, "wifi_msg", quec_wifi_msg_thread, NULL, QUEC_WIFI_MSG_TASK_EVENT_CNT)) { QUEC_WIFI_MSG_LOG("quec_wifi_msg_init err"); ret = QUEC_WIFI_MSG_TASK_CREATE_ERR; } } return ret; } quec_wifi_msg_errcode_e quec_wifi_msg_deinit(void *argv) { return QUEC_WIFI_MSG_SUCCESS; } #endif /* QUEC_FGM842D_WIFI_SUPPORT */ #endif /* MIN_SYS */