From 624150181c4d8a86c8f098b5f5c02c3ab9b756e2 Mon Sep 17 00:00:00 2001 From: Yilin Sun Date: Sun, 8 Jan 2023 22:22:13 +0800 Subject: [PATCH] Added CTRL interface parser and event dispatch, fixed proto for nanopb. Signed-off-by: Yilin Sun --- CMakeLists.txt | 3 +- include/nh_ctrl_api.h | 12 ++ .../{nh_event_helpers.h => nh_helper_event.h} | 0 include/nh_helper_serial.h | 21 ++ include/nh_shared_if.h | 12 +- proto/esp_hosted_config.pb.c | 2 +- proto/esp_hosted_config.pb.h | 99 ++++----- proto/esp_hosted_config.proto | 4 + src/nh_ctrl_api.c | 194 +++++++++++++++++- src/{nh_event_helpers.c => nh_helper_event.c} | 2 +- src/nh_helper_serial.c | 96 +++++++++ src/nh_shared_if.c | 83 +++++--- 12 files changed, 440 insertions(+), 88 deletions(-) rename include/{nh_event_helpers.h => nh_helper_event.h} (100%) create mode 100644 include/nh_helper_serial.h rename src/{nh_event_helpers.c => nh_helper_event.c} (97%) create mode 100644 src/nh_helper_serial.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 556a60b..249a308 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,8 @@ project(esp_nano_hosted) set(NH_SOURCES "proto/esp_hosted_config.pb.c" "src/nh_ctrl_api.c" - "src/nh_event_helpers.c" + "src/nh_helper_event.c" + "src/nh_helper_serial.c" "src/nh_shared_if.c" ) diff --git a/include/nh_ctrl_api.h b/include/nh_ctrl_api.h index 5361e66..6ed1c76 100644 --- a/include/nh_ctrl_api.h +++ b/include/nh_ctrl_api.h @@ -3,15 +3,27 @@ #include "nh_shared_if.h" +typedef void (*nh_ctrl_api_event_cb_init_t)(void *handle); + +typedef struct { + nh_ctrl_api_event_cb_init_t init; +} nh_ctrl_api_cb_t; + typedef struct { nh_shared_if_t *shared_if; nh_osa_t *osa; + nh_ctrl_api_cb_t cb; void *user_data; /* Private states */ + nh_osa_semaphore_t p_sem_req; + nh_osa_semaphore_t p_sem_resp; + uint8_t *p_buf_rx; + uint32_t p_buf_rx_len; } nh_ctrl_api_t; nh_ret_t nh_ctrl_api_init(nh_ctrl_api_t *api); void nh_ctrl_api_task(nh_ctrl_api_t *api); +nh_ret_t nh_ctrl_api_get_mac_address(nh_ctrl_api_t *api, uint8_t *mac_addr); #endif // NH_CTRL_API_H diff --git a/include/nh_event_helpers.h b/include/nh_helper_event.h similarity index 100% rename from include/nh_event_helpers.h rename to include/nh_helper_event.h diff --git a/include/nh_helper_serial.h b/include/nh_helper_serial.h new file mode 100644 index 0000000..54277ac --- /dev/null +++ b/include/nh_helper_serial.h @@ -0,0 +1,21 @@ +#ifndef NH_HELPER_SERIAL_H +#define NH_HELPER_SERIAL_H + +#include "nh_common.h" + +typedef enum { + NH_SERIAL_TAG_EP_NAME = 1U, + NH_SERIAL_TAG_DATA = 2U, +} nh_serial_tag_t; + +typedef enum { + NH_SERIAL_EP_RESP, + NH_SERIAL_EP_EVENT, +} nh_serial_ep_type_t; + +nh_ret_t nh_serial_get_type(nh_serial_ep_type_t *type, uint8_t *buf); +nh_ret_t nh_serial_get_payload(uint8_t *buf, uint8_t **payload, uint16_t *length); +nh_ret_t nh_serial_header_length(nh_serial_ep_type_t type, uint16_t *header_length); +nh_ret_t nh_serial_write_header(nh_serial_ep_type_t type, uint8_t *buf, uint16_t data_len, uint8_t **data_start); + +#endif // NH_HELPER_SERIAL_H diff --git a/include/nh_shared_if.h b/include/nh_shared_if.h index a2bc313..781db2f 100644 --- a/include/nh_shared_if.h +++ b/include/nh_shared_if.h @@ -2,7 +2,8 @@ #define NH_SHARED_IF_H #include "nh_common.h" -#include "nh_event_helpers.h" +#include "nh_helper_event.h" +#include "nh_helper_serial.h" /* OPS */ typedef nh_ret_t (*nh_shared_if_ops_spi_xfer_t)(void *handle, uint8_t *tx_data, uint8_t *rx_data, uint32_t len); @@ -34,7 +35,7 @@ typedef struct { nh_osa_queue_t p_queue_tx; nh_osa_queue_t p_queue_rx_data; - nh_osa_queue_t p_queue_rx_ctrl; + nh_osa_queue_t p_queue_rx_serial; uint8_t *p_buf_frame_tx; /* SPI TX frame */ uint8_t *p_buf_frame_rx; /* SPI RX frame */ @@ -45,8 +46,9 @@ void nh_shared_if_task(nh_shared_if_t *shared_if); void nh_shared_if_inject_data_ready(nh_shared_if_t *shared_if); /* Internal APIs */ -nh_ret_t nh_shared_if_ctrl_send(nh_shared_if_t *shared_if, uint8_t *tx_payload, uint32_t len, uint32_t timeout_ms); -nh_ret_t nh_shared_if_ctrl_recv(nh_shared_if_t *shared_if, uint8_t **rx_payload, uint32_t *len, uint32_t timeout_ms); -nh_ret_t nh_shared_if_ctrl_free(nh_shared_if_t *shared_if, uint8_t *rx_payload); +nh_ret_t nh_shared_if_serial_if_send(nh_shared_if_t *shared_if, uint8_t *tx_payload, uint32_t len, uint32_t timeout_ms); +nh_ret_t nh_shared_if_serial_if_recv(nh_shared_if_t *shared_if, nh_serial_ep_type_t *ep_type, uint8_t **rx_payload, + uint32_t *len, uint32_t timeout_ms); +nh_ret_t nh_shared_if_serial_if_free(nh_shared_if_t *shared_if, uint8_t *rx_payload); #endif // NH_SHARED_IF_H diff --git a/proto/esp_hosted_config.pb.c b/proto/esp_hosted_config.pb.c index 415da0e..7d83b8e 100644 --- a/proto/esp_hosted_config.pb.c +++ b/proto/esp_hosted_config.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.8-dev */ +/* Generated by nanopb-0.4.7 */ #include "esp_hosted_config.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/proto/esp_hosted_config.pb.h b/proto/esp_hosted_config.pb.h index 5290a33..37087dc 100644 --- a/proto/esp_hosted_config.pb.h +++ b/proto/esp_hosted_config.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.8-dev */ +/* Generated by nanopb-0.4.7 */ #ifndef PB_ESP_HOSTED_CONFIG_PB_H_INCLUDED #define PB_ESP_HOSTED_CONFIG_PB_H_INCLUDED @@ -365,6 +365,7 @@ typedef struct _CtrlMsg { CtrlMsgType msg_type; /* msg id */ CtrlMsgId msg_id; + pb_callback_t cb_payload; pb_size_t which_payload; union { /* * Requests * */ @@ -558,7 +559,7 @@ extern "C" { #define CtrlMsg_Event_Heartbeat_init_default {0} #define CtrlMsg_Event_StationDisconnectFromAP_init_default {0} #define CtrlMsg_Event_StationDisconnectFromESPSoftAP_init_default {0, {{NULL}, NULL}} -#define CtrlMsg_init_default {_CtrlMsgType_MIN, _CtrlMsgId_MIN, 0, {CtrlMsg_Req_GetMacAddress_init_default}} +#define CtrlMsg_init_default {_CtrlMsgType_MIN, _CtrlMsgId_MIN, {{NULL}, NULL}, 0, {CtrlMsg_Req_GetMacAddress_init_default}} #define ScanResult_init_zero {{{NULL}, NULL}, 0, 0, {{NULL}, NULL}, _Ctrl_WifiSecProt_MIN} #define ConnectedSTAList_init_zero {{{NULL}, NULL}, 0} #define CtrlMsg_Req_GetMacAddress_init_zero {0} @@ -602,7 +603,7 @@ extern "C" { #define CtrlMsg_Event_Heartbeat_init_zero {0} #define CtrlMsg_Event_StationDisconnectFromAP_init_zero {0} #define CtrlMsg_Event_StationDisconnectFromESPSoftAP_init_zero {0, {{NULL}, NULL}} -#define CtrlMsg_init_zero {_CtrlMsgType_MIN, _CtrlMsgId_MIN, 0, {CtrlMsg_Req_GetMacAddress_init_zero}} +#define CtrlMsg_init_zero {_CtrlMsgType_MIN, _CtrlMsgId_MIN, {{NULL}, NULL}, 0, {CtrlMsg_Req_GetMacAddress_init_zero}} /* Field tags (for use in manual encoding/decoding) */ #define ScanResult_ssid_tag 1 @@ -1002,52 +1003,52 @@ X(a, CALLBACK, SINGULAR, BYTES, mac, 2) #define CtrlMsg_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UENUM, msg_type, 1) \ X(a, STATIC, SINGULAR, UENUM, msg_id, 2) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_get_mac_address,payload.req_get_mac_address), 101) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_set_mac_address,payload.req_set_mac_address), 102) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_get_wifi_mode,payload.req_get_wifi_mode), 103) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_set_wifi_mode,payload.req_set_wifi_mode), 104) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_scan_ap_list,payload.req_scan_ap_list), 105) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_get_ap_config,payload.req_get_ap_config), 106) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_connect_ap,payload.req_connect_ap), 107) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_disconnect_ap,payload.req_disconnect_ap), 108) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_get_softap_config,payload.req_get_softap_config), 109) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_set_softap_vendor_specific_ie,payload.req_set_softap_vendor_specific_ie), 110) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_start_softap,payload.req_start_softap), 111) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_softap_connected_stas_list,payload.req_softap_connected_stas_list), 112) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_stop_softap,payload.req_stop_softap), 113) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_set_power_save_mode,payload.req_set_power_save_mode), 114) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_get_power_save_mode,payload.req_get_power_save_mode), 115) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_ota_begin,payload.req_ota_begin), 116) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_ota_write,payload.req_ota_write), 117) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_ota_end,payload.req_ota_end), 118) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_set_wifi_max_tx_power,payload.req_set_wifi_max_tx_power), 119) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_get_wifi_curr_tx_power,payload.req_get_wifi_curr_tx_power), 120) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,req_config_heartbeat,payload.req_config_heartbeat), 121) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_get_mac_address,payload.resp_get_mac_address), 201) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_set_mac_address,payload.resp_set_mac_address), 202) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_get_wifi_mode,payload.resp_get_wifi_mode), 203) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_set_wifi_mode,payload.resp_set_wifi_mode), 204) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_scan_ap_list,payload.resp_scan_ap_list), 205) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_get_ap_config,payload.resp_get_ap_config), 206) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_connect_ap,payload.resp_connect_ap), 207) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_disconnect_ap,payload.resp_disconnect_ap), 208) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_get_softap_config,payload.resp_get_softap_config), 209) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_set_softap_vendor_specific_ie,payload.resp_set_softap_vendor_specific_ie), 210) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_start_softap,payload.resp_start_softap), 211) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_softap_connected_stas_list,payload.resp_softap_connected_stas_list), 212) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_stop_softap,payload.resp_stop_softap), 213) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_set_power_save_mode,payload.resp_set_power_save_mode), 214) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_get_power_save_mode,payload.resp_get_power_save_mode), 215) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_ota_begin,payload.resp_ota_begin), 216) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_ota_write,payload.resp_ota_write), 217) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_ota_end,payload.resp_ota_end), 218) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_set_wifi_max_tx_power,payload.resp_set_wifi_max_tx_power), 219) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_get_wifi_curr_tx_power,payload.resp_get_wifi_curr_tx_power), 220) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,resp_config_heartbeat,payload.resp_config_heartbeat), 221) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,event_esp_init,payload.event_esp_init), 301) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,event_heartbeat,payload.event_heartbeat), 302) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,event_station_disconnect_from_AP,payload.event_station_disconnect_from_AP), 303) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,event_station_disconnect_from_ESP_SoftAP,payload.event_station_disconnect_from_ESP_SoftAP), 304) +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_get_mac_address,payload.req_get_mac_address), 101) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_set_mac_address,payload.req_set_mac_address), 102) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_get_wifi_mode,payload.req_get_wifi_mode), 103) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_set_wifi_mode,payload.req_set_wifi_mode), 104) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_scan_ap_list,payload.req_scan_ap_list), 105) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_get_ap_config,payload.req_get_ap_config), 106) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_connect_ap,payload.req_connect_ap), 107) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_disconnect_ap,payload.req_disconnect_ap), 108) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_get_softap_config,payload.req_get_softap_config), 109) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_set_softap_vendor_specific_ie,payload.req_set_softap_vendor_specific_ie), 110) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_start_softap,payload.req_start_softap), 111) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_softap_connected_stas_list,payload.req_softap_connected_stas_list), 112) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_stop_softap,payload.req_stop_softap), 113) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_set_power_save_mode,payload.req_set_power_save_mode), 114) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_get_power_save_mode,payload.req_get_power_save_mode), 115) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_ota_begin,payload.req_ota_begin), 116) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_ota_write,payload.req_ota_write), 117) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_ota_end,payload.req_ota_end), 118) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_set_wifi_max_tx_power,payload.req_set_wifi_max_tx_power), 119) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_get_wifi_curr_tx_power,payload.req_get_wifi_curr_tx_power), 120) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,req_config_heartbeat,payload.req_config_heartbeat), 121) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_get_mac_address,payload.resp_get_mac_address), 201) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_set_mac_address,payload.resp_set_mac_address), 202) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_get_wifi_mode,payload.resp_get_wifi_mode), 203) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_set_wifi_mode,payload.resp_set_wifi_mode), 204) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_scan_ap_list,payload.resp_scan_ap_list), 205) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_get_ap_config,payload.resp_get_ap_config), 206) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_connect_ap,payload.resp_connect_ap), 207) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_disconnect_ap,payload.resp_disconnect_ap), 208) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_get_softap_config,payload.resp_get_softap_config), 209) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_set_softap_vendor_specific_ie,payload.resp_set_softap_vendor_specific_ie), 210) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_start_softap,payload.resp_start_softap), 211) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_softap_connected_stas_list,payload.resp_softap_connected_stas_list), 212) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_stop_softap,payload.resp_stop_softap), 213) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_set_power_save_mode,payload.resp_set_power_save_mode), 214) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_get_power_save_mode,payload.resp_get_power_save_mode), 215) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_ota_begin,payload.resp_ota_begin), 216) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_ota_write,payload.resp_ota_write), 217) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_ota_end,payload.resp_ota_end), 218) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_set_wifi_max_tx_power,payload.resp_set_wifi_max_tx_power), 219) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_get_wifi_curr_tx_power,payload.resp_get_wifi_curr_tx_power), 220) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,resp_config_heartbeat,payload.resp_config_heartbeat), 221) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,event_esp_init,payload.event_esp_init), 301) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,event_heartbeat,payload.event_heartbeat), 302) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,event_station_disconnect_from_AP,payload.event_station_disconnect_from_AP), 303) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,event_station_disconnect_from_ESP_SoftAP,payload.event_station_disconnect_from_ESP_SoftAP), 304) #define CtrlMsg_CALLBACK NULL #define CtrlMsg_DEFAULT NULL #define CtrlMsg_payload_req_get_mac_address_MSGTYPE CtrlMsg_Req_GetMacAddress diff --git a/proto/esp_hosted_config.proto b/proto/esp_hosted_config.proto index 158d244..8888a7b 100644 --- a/proto/esp_hosted_config.proto +++ b/proto/esp_hosted_config.proto @@ -1,5 +1,7 @@ syntax = "proto3"; +import 'nanopb.proto'; + /* Enums similar to ESP IDF */ enum Ctrl_VendorIEType { Beacon = 0; @@ -360,6 +362,8 @@ message CtrlMsg_Event_StationDisconnectFromESPSoftAP { } message CtrlMsg { + option (nanopb_msgopt).submsg_callback = true; + /* msg_type could be req, resp or Event */ CtrlMsgType msg_type = 1; diff --git a/src/nh_ctrl_api.c b/src/nh_ctrl_api.c index fc38929..49414e9 100644 --- a/src/nh_ctrl_api.c +++ b/src/nh_ctrl_api.c @@ -8,26 +8,206 @@ /* PB config */ #include "esp_hosted_config.pb.h" -#define NH_RECEIVE_TIMEOUT_MSEC 5000 #define NH_COMMAND_TIMEOUT_MSEC 30000 +#define NH_COMMAND_REQ_MEM_SIZE 256 + +static nh_ret_t nh_ctrl_api_parse_event(nh_ctrl_api_t *api, CtrlMsgId *event_id, uint8_t *buf, uint32_t buf_len); +static void nh_ctrl_api_dispatch_event(nh_ctrl_api_t *api, CtrlMsgId event_id); +static nh_ret_t nh_ctrl_api_general_request(nh_ctrl_api_t *api, CtrlMsg *tx_msg); +static nh_ret_t nh_ctrl_api_general_response(nh_ctrl_api_t *api, CtrlMsg *rx_msg); +static nh_ret_t nh_ctrl_api_general_response_free(nh_ctrl_api_t *api); +static bool nh_ctrl_api_payload_decode_cb(pb_istream_t *stream, const pb_field_t *field, void **arg); nh_ret_t nh_ctrl_api_init(nh_ctrl_api_t *api) { nh_ret_t ret = NH_RET_SUCCESS; + ret = api->osa->sem_create(api->osa->user_data, &api->p_sem_req); + if (ret != NH_RET_SUCCESS) { + return ret; + } + + ret = api->osa->sem_create(api->osa->user_data, &api->p_sem_resp); + if (ret != NH_RET_SUCCESS) { + goto free_sem_req; + } + + ret = api->osa->sem_give(api->osa->user_data, api->p_sem_req); + if (ret != NH_RET_SUCCESS) { + goto free_sem_resp; + } + + return ret; + +free_sem_resp: + api->osa->sem_destroy(api->osa->user_data, api->p_sem_resp); + +free_sem_req: + api->osa->sem_destroy(api->osa->user_data, api->p_sem_req); + + return ret; +} + +nh_ret_t nh_ctrl_api_get_mac_address(nh_ctrl_api_t *api, uint8_t *mac_addr) { + nh_ret_t ret = NH_RET_SUCCESS; + + ret = api->osa->sem_take(api->osa->user_data, api->p_sem_req, NH_COMMAND_TIMEOUT_MSEC); + if (ret != NH_RET_SUCCESS) { + return ret; + } + + CtrlMsg tx_msg = CtrlMsg_init_zero; + + tx_msg.msg_type = CtrlMsgType_Req; + tx_msg.msg_id = CtrlMsgId_Req_GetMACAddress; + tx_msg.which_payload = CtrlMsg_req_get_mac_address_tag; + tx_msg.payload.req_get_mac_address.mode = Ctrl_WifiMode_STA; + + ret = nh_ctrl_api_general_request(api, &tx_msg); + if (ret != NH_RET_SUCCESS) { + goto give_sem_exit; + } + + CtrlMsg rx_msg = CtrlMsg_init_zero; + + rx_msg.cb_payload.arg = mac_addr; + + ret = nh_ctrl_api_general_response(api, &rx_msg); + if (ret != NH_RET_SUCCESS) { + goto give_sem_exit; + } + + nh_ctrl_api_general_response_free(api); + +give_sem_exit: + api->osa->sem_give(api->osa->user_data, api->p_sem_req); + return ret; } void nh_ctrl_api_task(nh_ctrl_api_t *api) { nh_ret_t ret = NH_RET_SUCCESS; - uint8_t *rx_payload; - uint32_t rx_payload_size; + uint8_t *payload; + uint32_t payload_size; + nh_serial_ep_type_t ep_type; - ret = nh_shared_if_ctrl_recv(api->shared_if, &rx_payload, &rx_payload_size, NH_RECEIVE_TIMEOUT_MSEC); + ret = nh_shared_if_serial_if_recv(api->shared_if, &ep_type, &payload, &payload_size, NH_COMMAND_TIMEOUT_MSEC); if (ret != NH_RET_SUCCESS) { return; } - /* TODO: process SERIAL data */ - nh_shared_if_ctrl_free(api->shared_if, rx_payload); -} \ No newline at end of file + if (ep_type == NH_SERIAL_EP_RESP) { + api->p_buf_rx = payload; + api->p_buf_rx_len = payload_size; + + ret = api->osa->sem_give(api->osa->user_data, api->p_sem_resp); + if (ret != NH_RET_SUCCESS) { + nh_shared_if_serial_if_free(api->shared_if, payload); + return; + } + } else if (ep_type == NH_SERIAL_EP_EVENT) { + CtrlMsgId event_id; + ret = nh_ctrl_api_parse_event(api, &event_id, payload, payload_size); + if (ret == NH_RET_SUCCESS) { + nh_ctrl_api_dispatch_event(api, event_id); + } + + nh_shared_if_serial_if_free(api->shared_if, payload); + } +} + +static nh_ret_t nh_ctrl_api_parse_event(nh_ctrl_api_t *api, CtrlMsgId *event_id, uint8_t *buf, uint32_t buf_len) { + pb_istream_t stream = pb_istream_from_buffer(buf, buf_len); + + CtrlMsg event_msg = CtrlMsg_init_zero; + + if (!pb_decode(&stream, CtrlMsg_fields, &event_msg)) { + return NH_RET_FAIL; + } + + *event_id = event_msg.msg_id; + + return NH_RET_SUCCESS; +} + +static void nh_ctrl_api_dispatch_event(nh_ctrl_api_t *api, CtrlMsgId event_id) { + switch (event_id) { + case CtrlMsgId_Event_ESPInit: { + if (api->cb.init) { + api->cb.init(api->user_data); + } + + break; + } + + default: + break; + } +} + +static nh_ret_t nh_ctrl_api_general_request(nh_ctrl_api_t *api, CtrlMsg *tx_msg) { + nh_ret_t ret = NH_RET_SUCCESS; + + uint8_t *req_buf; + ret = api->osa->buf_allocate(api->osa->user_data, &req_buf, NH_COMMAND_REQ_MEM_SIZE); + if (ret != NH_RET_SUCCESS) { + return ret; + } + + pb_ostream_t tx_stream = pb_ostream_from_buffer(req_buf, NH_COMMAND_REQ_MEM_SIZE); + if (!pb_encode(&tx_stream, CtrlMsg_fields, tx_msg)) { + /* False on error: */ + ret = NH_RET_FAIL; + goto free_tx_exit; + } + + ret = nh_shared_if_serial_if_send(api->shared_if, req_buf, tx_stream.bytes_written, NH_COMMAND_TIMEOUT_MSEC); + +free_tx_exit: + api->osa->buf_free(api->osa->user_data, req_buf); + + return ret; +} + +static nh_ret_t nh_ctrl_api_general_response(nh_ctrl_api_t *api, CtrlMsg *rx_msg) { + nh_ret_t ret = NH_RET_SUCCESS; + + ret = api->osa->sem_take(api->osa->user_data, api->p_sem_resp, NH_COMMAND_TIMEOUT_MSEC); + if (ret != NH_RET_SUCCESS) { + return ret; + } + + pb_istream_t rx_stream = pb_istream_from_buffer(api->p_buf_rx, api->p_buf_rx_len); + + rx_msg->cb_payload.funcs.decode = nh_ctrl_api_payload_decode_cb; + + if (!pb_decode(&rx_stream, CtrlMsg_fields, rx_msg)) { + nh_shared_if_serial_if_free(api->shared_if, api->p_buf_rx); + return NH_RET_FAIL; + } + + return ret; +} + +static nh_ret_t nh_ctrl_api_general_response_free(nh_ctrl_api_t *api) { + return nh_shared_if_serial_if_free(api->shared_if, api->p_buf_rx); +} + +static bool nh_ctrl_api_bytes_decode_cb(pb_istream_t *stream, const pb_field_t *field, void **arg) { + if (stream->bytes_left) { + return pb_read(stream, *arg, stream->bytes_left); + } + + return true; +} + +static bool nh_ctrl_api_payload_decode_cb(pb_istream_t *stream, const pb_field_t *field, void **arg) { + if (field->tag == CtrlMsg_resp_get_mac_address_tag) { + CtrlMsg_Resp_GetMacAddress *sub_msg = field->pData; + + sub_msg->mac.funcs.decode = nh_ctrl_api_bytes_decode_cb; + sub_msg->mac.arg = *arg; + } + + return true; +} diff --git a/src/nh_event_helpers.c b/src/nh_helper_event.c similarity index 97% rename from src/nh_event_helpers.c rename to src/nh_helper_event.c index 02b631d..ed89832 100644 --- a/src/nh_event_helpers.c +++ b/src/nh_helper_event.c @@ -1,4 +1,4 @@ -#include "nh_event_helpers.h" +#include "nh_helper_event.h" /** * Espressif wraps Tag-Length-Value(TLV) data in the packet for events diff --git a/src/nh_helper_serial.c b/src/nh_helper_serial.c new file mode 100644 index 0000000..7b799c9 --- /dev/null +++ b/src/nh_helper_serial.c @@ -0,0 +1,96 @@ +#include "nh_helper_serial.h" + +#include + +#define SERIAL_EP_NAME(x) (nh_serial_ep_names[x]) +#define SERIAL_EP_SIZE(x) (strlen(nh_serial_ep_names[x])) + +static const char *nh_serial_ep_names[] = { + [NH_SERIAL_EP_RESP] = "ctrlResp", + [NH_SERIAL_EP_EVENT] = "ctrlEvnt", +}; + +/* In the SERIAL I/F, a different TLV is used: + * | 1 | 2 | N | + * | Tag | Length | Value | + * Each TLV contains 2 fields, "EP name" and "Data" + */ + +nh_ret_t nh_serial_get_type(nh_serial_ep_type_t *type, uint8_t *buf) { + uint8_t tag = buf[0]; + uint8_t length = (buf[2] << 8U) | buf[1]; + char *value = (char *)&buf[3]; + + if (tag != NH_SERIAL_TAG_EP_NAME) { + return NH_RET_FAIL; + } + + if (length == 0) { + return NH_RET_FAIL; + } + + if (strncmp(value, SERIAL_EP_NAME(NH_SERIAL_EP_RESP), SERIAL_EP_SIZE(NH_SERIAL_EP_RESP)) == 0) { + *type = NH_SERIAL_EP_RESP; + + return NH_RET_SUCCESS; + } + + if (strncmp(value, SERIAL_EP_NAME(NH_SERIAL_EP_EVENT), SERIAL_EP_SIZE(NH_SERIAL_EP_EVENT)) == 0) { + *type = NH_SERIAL_EP_EVENT; + + return NH_RET_SUCCESS; + } + + return NH_RET_FAIL; +} + +nh_ret_t nh_serial_get_payload(uint8_t *buf, uint8_t **payload, uint16_t *length) { + uint8_t name_tag = buf[0]; + uint8_t name_len = (buf[2] << 8U) | buf[1]; + + uint16_t data_tag_offset = 3 + name_len; + + uint8_t data_tag = buf[data_tag_offset]; + uint16_t data_len = (buf[data_tag_offset + 2] << 8U) | buf[data_tag_offset + 1]; + uint8_t *data_value = &buf[data_tag_offset + 3]; + + if (name_tag != NH_SERIAL_TAG_EP_NAME) { + return NH_RET_FAIL; + } + + if (data_tag != NH_SERIAL_TAG_DATA) { + return NH_RET_FAIL; + } + + *payload = data_value; + *length = data_len; + + return NH_RET_SUCCESS; +} + +nh_ret_t nh_serial_header_length(nh_serial_ep_type_t type, uint16_t *header_length) { + *header_length = (6 + SERIAL_EP_SIZE(type)); + return NH_RET_SUCCESS; +} + +nh_ret_t nh_serial_write_header(nh_serial_ep_type_t type, uint8_t *buf, uint16_t data_len, uint8_t **data_start) { + uint16_t name_len = SERIAL_EP_SIZE(type); + uint8_t *name_buf = &buf[3]; + + buf[0] = NH_SERIAL_TAG_EP_NAME; + buf[1] = name_len & 0xFFU; + buf[2] = (name_len >> 8U) & 0xFFU; + + memcpy(name_buf, SERIAL_EP_NAME(type), name_len); + + uint8_t data_tag_offset = 3 + name_len; + uint8_t *data_buf = &buf[data_tag_offset + 3]; + + buf[data_tag_offset] = NH_SERIAL_TAG_DATA; + buf[data_tag_offset + 1] = data_len & 0xFFU; + buf[data_tag_offset + 2] = (data_len >> 8U) & 0xFFU; + + *data_start = data_buf; + + return NH_RET_SUCCESS; +} \ No newline at end of file diff --git a/src/nh_shared_if.c b/src/nh_shared_if.c index f0b556a..c3546d9 100644 --- a/src/nh_shared_if.c +++ b/src/nh_shared_if.c @@ -2,9 +2,10 @@ #include "string.h" -#define NH_XFER_REQ_TIMEOUT 5000 -#define NH_XFER_MAX_SIZE 1600 -#define NH_XFER_QUEUE_SIZE 1 +#define NH_XFER_REQ_TIMEOUT 5000 +#define NH_XFER_BLOCKING_TIMEOUT 500 +#define NH_XFER_MAX_SIZE 1600 +#define NH_XFER_QUEUE_SIZE 1 #ifdef __GNUC__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ @@ -29,9 +30,9 @@ typedef enum { } nh_xfer_priv_type_t; typedef struct { - nh_xfer_type_t type; - uint8_t *buf; - uint32_t buf_len; + uint32_t type; + uint8_t *buf; + uint32_t buf_len; } nh_xfer_queue_item_t; typedef struct __attribute__((packed)) { @@ -76,7 +77,7 @@ nh_ret_t nh_shared_if_init(nh_shared_if_t *shared_if) { goto err_free_queue_tx; } - ret = shared_if->osa->queue_create(shared_if->osa->user_data, &shared_if->p_queue_rx_ctrl, + ret = shared_if->osa->queue_create(shared_if->osa->user_data, &shared_if->p_queue_rx_serial, sizeof(nh_xfer_queue_item_t), NH_XFER_QUEUE_SIZE); if (ret != NH_RET_SUCCESS) { goto err_free_queue_rx_data; @@ -98,7 +99,7 @@ err_free_tx_buf: shared_if->osa->buf_free(shared_if->osa->user_data, shared_if->p_buf_frame_tx); err_free_queue_rx_ctrl: - shared_if->osa->queue_destroy(shared_if->osa->user_data, shared_if->p_queue_rx_ctrl); + shared_if->osa->queue_destroy(shared_if->osa->user_data, shared_if->p_queue_rx_serial); err_free_queue_rx_data: shared_if->osa->queue_destroy(shared_if->osa->user_data, shared_if->p_queue_rx_data); @@ -116,19 +117,28 @@ void nh_shared_if_inject_data_ready(nh_shared_if_t *shared_if) { shared_if->osa->sem_give(shared_if->osa->user_data, shared_if->p_semaphore_xfer_req); } -nh_ret_t nh_shared_if_ctrl_send(nh_shared_if_t *shared_if, uint8_t *tx_payload, uint32_t len, uint32_t timeout_ms) { +nh_ret_t nh_shared_if_serial_if_send(nh_shared_if_t *shared_if, uint8_t *tx_payload, uint32_t len, + uint32_t timeout_ms) { nh_ret_t ret = NH_RET_SUCCESS; + uint16_t header_len; + nh_serial_header_length(NH_SERIAL_EP_RESP, &header_len); + nh_xfer_queue_item_t item = { .type = NH_SHARED_IF_TYPE_SERIAL, - .buf_len = len, + .buf_len = len + header_len, }; - ret = shared_if->osa->buf_allocate(shared_if->osa->user_data, &item.buf, len); + ret = shared_if->osa->buf_allocate(shared_if->osa->user_data, &item.buf, item.buf_len); if (ret != NH_RET_SUCCESS) { return ret; } + uint8_t *data_start; + nh_serial_write_header(NH_SERIAL_EP_RESP, item.buf, len, &data_start); + + memcpy(data_start, tx_payload, len); + ret = shared_if->osa->queue_enqueue(shared_if->osa->user_data, shared_if->p_queue_tx, &item, timeout_ms); if (ret != NH_RET_SUCCESS) { shared_if->osa->buf_free(shared_if->osa->user_data, item.buf); @@ -136,26 +146,29 @@ nh_ret_t nh_shared_if_ctrl_send(nh_shared_if_t *shared_if, uint8_t *tx_payload, return ret; } + ret = shared_if->osa->sem_give(shared_if->osa->user_data, shared_if->p_semaphore_xfer_req); return ret; } -nh_ret_t nh_shared_if_ctrl_recv(nh_shared_if_t *shared_if, uint8_t **rx_payload, uint32_t *len, uint32_t timeout_ms) { +nh_ret_t nh_shared_if_serial_if_recv(nh_shared_if_t *shared_if, nh_serial_ep_type_t *ep_type, uint8_t **rx_payload, + uint32_t *len, uint32_t timeout_ms) { nh_ret_t ret = NH_RET_SUCCESS; nh_xfer_queue_item_t item; - ret = shared_if->osa->queue_dequeue(shared_if->osa->user_data, shared_if->p_queue_rx_ctrl, &item, timeout_ms); + ret = shared_if->osa->queue_dequeue(shared_if->osa->user_data, shared_if->p_queue_rx_serial, &item, timeout_ms); if (ret != NH_RET_SUCCESS) { return ret; } *rx_payload = item.buf; *len = item.buf_len; + *ep_type = item.type; return ret; } -nh_ret_t nh_shared_if_ctrl_free(nh_shared_if_t *shared_if, uint8_t *rx_payload) { +nh_ret_t nh_shared_if_serial_if_free(nh_shared_if_t *shared_if, uint8_t *rx_payload) { return shared_if->osa->buf_free(shared_if->osa->user_data, rx_payload); } @@ -191,14 +204,15 @@ void nh_shared_if_task(nh_shared_if_t *shared_if) { /* Write header and payload since we have data to send */ nh_xfer_pkt_hdr_t *hdr = (nh_xfer_pkt_hdr_t *)shared_if->p_buf_frame_tx; - hdr->if_type = item.type; - hdr->offset = H_TO_LE16(sizeof(nh_xfer_pkt_hdr_t)); /* Payload follows header... */ - hdr->len = H_TO_LE16(item.buf_len); - hdr->checksum = H_TO_LE16(nh_shared_if_checksum_calculate(hdr)); + hdr->if_type = item.type; + hdr->offset = H_TO_LE16(sizeof(nh_xfer_pkt_hdr_t)); /* Payload follows header... */ + hdr->len = H_TO_LE16(item.buf_len); /* Copy payload */ memcpy(&shared_if->p_buf_frame_tx[sizeof(nh_xfer_pkt_hdr_t)], item.buf, item.buf_len); + hdr->checksum = H_TO_LE16(nh_shared_if_checksum_calculate(hdr)); + /* Queue consumer owns the buffer. */ shared_if->osa->buf_free(shared_if->osa->user_data, item.buf); } @@ -261,10 +275,30 @@ static void nh_shared_if_dispatch_if_priv(nh_shared_if_t *shared_if, nh_xfer_pri static void nh_shared_if_dispatch_if_serial(nh_shared_if_t *shared_if, uint8_t *payload, uint16_t len) { nh_ret_t ret = NH_RET_SUCCESS; + /* Payload in SERIAL interface has two types, coded in TLV, event and response. + * Both payloads are wrapped in protobuf, so we don't need to distinguish them. + * Pass them to upper layer (CTRL). + */ + + uint8_t *ctrl_data; + uint16_t ctrl_data_len; + nh_serial_ep_type_t ep_type; + + ret = nh_serial_get_type(&ep_type, payload); + if (ret != NH_RET_SUCCESS) { + return; + } + + /* Try to find data and length from TLV */ + ret = nh_serial_get_payload(payload, &ctrl_data, &ctrl_data_len); + if (ret != NH_RET_SUCCESS) { + return; + } + nh_xfer_queue_item_t item; - item.type = NH_SHARED_IF_TYPE_SERIAL; - item.buf_len = len; + item.type = ep_type; + item.buf_len = ctrl_data_len; /* Allocate payload */ ret = shared_if->osa->buf_allocate(shared_if->osa->user_data, &item.buf, item.buf_len); @@ -272,10 +306,11 @@ static void nh_shared_if_dispatch_if_serial(nh_shared_if_t *shared_if, uint8_t * return; } - memcpy(item.buf, payload, item.buf_len); + memcpy(item.buf, ctrl_data, item.buf_len); /* Enqueue response */ - ret = shared_if->osa->queue_enqueue(shared_if->osa->user_data, shared_if->p_queue_rx_ctrl, &item, 0); + ret = shared_if->osa->queue_enqueue(shared_if->osa->user_data, shared_if->p_queue_rx_serial, &item, + NH_XFER_BLOCKING_TIMEOUT); if (ret != NH_RET_SUCCESS) { /* Queue is full, maybe the ctrl interface is not active, drop the packet */ shared_if->osa->buf_free(shared_if->osa->user_data, item.buf); @@ -285,9 +320,9 @@ static void nh_shared_if_dispatch_if_serial(nh_shared_if_t *shared_if, uint8_t * static uint16_t nh_shared_if_checksum_calculate(nh_xfer_pkt_hdr_t *hdr) { uint16_t checksum = 0U; - uint16_t checksum_length = sizeof(nh_xfer_pkt_hdr_t) + LE16_TO_H(hdr->len); + uint16_t checksum_end = sizeof(nh_xfer_pkt_hdr_t) + LE16_TO_H(hdr->len); - for (size_t i = 0; i < checksum_length; i++) { + for (uint16_t i = 0; i < checksum_end; i++) { checksum += ((uint8_t *)hdr)[i]; }