From 60a5a9fb07c3a0215cc9dede4a3507be4b48c5ef Mon Sep 17 00:00:00 2001 From: Yilin Sun Date: Tue, 17 Jan 2023 23:03:26 +0800 Subject: [PATCH] Added scan and connect commands. Signed-off-by: Yilin Sun --- README.md | 12 ++---- include/nh_ctrl_api.h | 55 ++++++++++++++++++-------- src/nh_ctrl_api.c | 91 +++++++++++++++++++++++++++++++++++++++++-- src/nh_shared_if.c | 24 ++++++++---- 4 files changed, 145 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 185d830..c7eb9c8 100644 --- a/README.md +++ b/README.md @@ -71,15 +71,9 @@ typedef enum { ## Issues -Who owns the buffers? How many buffers should we allocate? - -* Minimize the memory block operations (malloc and free) -* Control plane and data plane can be async -* Control API can be blocking until responded -* At least 2 full-sized buffers are required (for full duplex operations) -* To re-use the bus while a request is underway, control plane and data plane RX buffers should be copied -* Bus TX operation should be blocking, however the previous RX data (if any) can be received. -* The response for the request being transmitted will never arrive within the same transaction +* Only a subset of commands are implemented. +* Jumbo frames (larger than 1518 bytes) are not supported, since no `realloc` available. +* Just hope ESP won't send some frame larger than that. ## License Not decided yet, please be patient. At least not before the project is usable. \ No newline at end of file diff --git a/include/nh_ctrl_api.h b/include/nh_ctrl_api.h index 78a8da5..2b78c5e 100644 --- a/include/nh_ctrl_api.h +++ b/include/nh_ctrl_api.h @@ -3,6 +3,8 @@ #include "nh_shared_if.h" +#define NH_CTRL_API_MAC_LENGTH 17 + typedef enum { NH_CTRL_WIFI_MODE_NONE, NH_CTRL_WIFI_MODE_STA, @@ -11,26 +13,45 @@ typedef enum { } nh_ctrl_wifi_mode_t; typedef enum { - NH_CTRL_WIFI_ENC_MODE_OPEN, - NH_CTRL_WIFI_ENC_MODE_WEP, - NH_CTRL_WIFI_ENC_MODE_WPA_PSK, - NH_CTRL_WIFI_ENC_MODE_WPA2_PSK, - NH_CTRL_WIFI_ENC_MODE_WPA_WPA2_PSK, - NH_CTRL_WIFI_ENC_MODE_WPA2_ENT, - NH_CTRL_WIFI_ENC_MODE_WPA3_PSK, - NH_CTRL_WIFI_ENC_MODE_WPA2_WPA3_PSK, -} nh_ctrl_api_wifi_encryption_mode_t; + NH_CTRL_API_ENC_MODE_OPEN, + NH_CTRL_API_ENC_MODE_WEP, + NH_CTRL_API_ENC_MODE_WPA_PSK, + NH_CTRL_API_ENC_MODE_WPA2_PSK, + NH_CTRL_API_ENC_MODE_WPA_WPA2_PSK, + NH_CTRL_API_ENC_MODE_WPA2_ENT, + NH_CTRL_API_ENC_MODE_WPA3_PSK, + NH_CTRL_API_ENC_MODE_WPA2_WPA3_PSK, +} nh_ctrl_ap_enc_mode_t; + +typedef enum { + NH_CTRL_CONNECT_SUCCESS = 0x00U, + NH_CTRL_CONNECT_NO_AP_FOUND = 0x02U, + NH_CTRL_CONNECT_INVALID_PASSWORD = 0x03U, + NH_CTRL_CONNECT_FAILURE = 0xFFU, +} nh_ctrl_conn_status_t; typedef struct { - char *ssid; - char *bssid; - int rssi; - int channel; - nh_ctrl_api_wifi_encryption_mode_t encryption_mode; -} nh_ctrl_api_wifi_scan_item_t; + char *ssid; + char *bssid; + int rssi; + uint32_t channel; + nh_ctrl_ap_enc_mode_t encryption_mode; +} nh_ctrl_ap_scan_item_t; -typedef void (*nh_ctrl_api_ap_scan_list_cb_t)(void *handle, nh_ctrl_api_wifi_scan_item_t); +typedef struct { + char *ssid; + char *bssid; + char *password; + bool wpa3_supported; + int32_t listen_interval; +} nh_ctrl_ap_conn_params_t; +typedef struct { + nh_ctrl_conn_status_t status; + char *mac_addr; +} nh_ctrl_ap_conn_result_t; + +typedef void (*nh_ctrl_api_ap_scan_list_cb_t)(void *handle, nh_ctrl_ap_scan_item_t *item); typedef void (*nh_ctrl_api_event_cb_init_t)(void *handle); typedef struct { @@ -53,5 +74,7 @@ typedef struct { 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, nh_ctrl_wifi_mode_t mode); +nh_ret_t nh_ctrl_api_get_ap_scan_list(nh_ctrl_api_t *api, nh_ctrl_api_ap_scan_list_cb_t cb); +nh_ret_t nh_ctrl_api_connect_ap(nh_ctrl_api_t *api, nh_ctrl_ap_conn_params_t *params, nh_ctrl_ap_conn_result_t *result); #endif // NH_CTRL_API_H diff --git a/src/nh_ctrl_api.c b/src/nh_ctrl_api.c index f972ea1..d4745f9 100644 --- a/src/nh_ctrl_api.c +++ b/src/nh_ctrl_api.c @@ -86,6 +86,9 @@ nh_ret_t nh_ctrl_api_get_mac_address(nh_ctrl_api_t *api, uint8_t *mac_addr, nh_c ret = nh_ctrl_api_general_response(api, &rx_msg, &c_alloc); if (ret != NH_RET_SUCCESS || rx_msg->msg_id != CTRL_MSG_ID__Resp_GetMACAddress) goto free_msg_exit; + /* Sanity check */ + if (rx_msg->resp_get_mac_address->mac.len != NH_CTRL_API_MAC_LENGTH) goto free_msg_exit; + memcpy(mac_addr, rx_msg->resp_get_mac_address->mac.data, rx_msg->resp_get_mac_address->mac.len); mac_addr[rx_msg->resp_get_mac_address->mac.len] = '\0'; @@ -127,11 +130,38 @@ nh_ret_t nh_ctrl_api_get_ap_scan_list(nh_ctrl_api_t *api, nh_ctrl_api_ap_scan_li ret = nh_ctrl_api_general_response(api, &rx_msg, &c_alloc); if (ret != NH_RET_SUCCESS || rx_msg->msg_id != CTRL_MSG_ID__Resp_GetAPScanList) goto free_msg_exit; - - for(uint32_t i = 0; i < rx_msg->resp_scan_ap_list->count; i++) { - nh_ctrl_api_wifi_scan_item_t item = { - .ssid = rx_msg->resp_scan_ap_list->entries[i]->ssid.data, + for (uint32_t i = 0; i < rx_msg->resp_scan_ap_list->count; i++) { + nh_ctrl_ap_scan_item_t item = { + .rssi = rx_msg->resp_scan_ap_list->entries[i]->rssi, + .channel = rx_msg->resp_scan_ap_list->entries[i]->chnl, + .encryption_mode = (nh_ctrl_ap_enc_mode_t)rx_msg->resp_scan_ap_list->entries[i]->sec_prot, }; + + uint32_t ssid_len = rx_msg->resp_scan_ap_list->entries[i]->ssid.len; + uint32_t bssid_len = rx_msg->resp_scan_ap_list->entries[i]->bssid.len; + + ret = NH_CTRL_API_ALLOC(api, (uint8_t **)&item.ssid, ssid_len + 1); + if (ret != NH_RET_SUCCESS) goto free_msg_exit; + + ret = NH_CTRL_API_ALLOC(api, (uint8_t **)&item.bssid, bssid_len + 1); + if (ret != NH_RET_SUCCESS) { + NH_CTRL_API_FREE(api, (uint8_t *)item.ssid); + + goto free_msg_exit; + } + + memcpy(item.ssid, rx_msg->resp_scan_ap_list->entries[i]->ssid.data, ssid_len); + memcpy(item.bssid, rx_msg->resp_scan_ap_list->entries[i]->bssid.data, bssid_len); + + item.ssid[ssid_len] = '\0'; + item.bssid[bssid_len] = '\0'; + + if (cb) { + cb(api->user_data, &item); + } + + NH_CTRL_API_FREE(api, (uint8_t *)item.ssid); + NH_CTRL_API_FREE(api, (uint8_t *)item.bssid); } free_msg_exit: @@ -146,6 +176,59 @@ give_sem_exit: return ret; } +nh_ret_t nh_ctrl_api_connect_ap(nh_ctrl_api_t *api, nh_ctrl_ap_conn_params_t *params, + nh_ctrl_ap_conn_result_t *result) { + nh_ret_t ret = NH_RET_SUCCESS; + + NH_CTRL_API_CREATE_ALLOCATOR(c_alloc); + ret = NH_CTRL_API_TAKE_SEM(api, NH_COMMAND_TIMEOUT_MSEC); + if (ret != NH_RET_SUCCESS) return ret; + + CtrlMsg tx_msg; + ctrl_msg__init(&tx_msg); + + tx_msg.msg_id = CTRL_MSG_ID__Req_ConnectAP; + tx_msg.payload_case = CTRL_MSG__PAYLOAD_REQ_CONNECT_AP; + + ret = NH_CTRL_API_ALLOC(api, (uint8_t **)&tx_msg.req_connect_ap, sizeof(CtrlMsgReqConnectAP)); + if (ret != NH_RET_SUCCESS) goto give_sem_exit; + + ctrl_msg__req__connect_ap__init(tx_msg.req_connect_ap); + + tx_msg.req_connect_ap->ssid = params->ssid; + tx_msg.req_connect_ap->bssid = params->bssid; + tx_msg.req_connect_ap->pwd = params->password; + tx_msg.req_connect_ap->is_wpa3_supported = params->wpa3_supported; + tx_msg.req_connect_ap->listen_interval = params->listen_interval; + + ret = nh_ctrl_api_general_request(api, &tx_msg); + if (ret != NH_RET_SUCCESS) goto free_payload_exit; + + CtrlMsg *rx_msg; + + ret = nh_ctrl_api_general_response(api, &rx_msg, &c_alloc); + if (ret != NH_RET_SUCCESS || rx_msg->msg_id != CTRL_MSG_ID__Resp_ConnectAP) goto free_msg_exit; + + uint32_t mac_len = rx_msg->resp_connect_ap->mac.len; + if (mac_len != NH_CTRL_API_MAC_LENGTH) goto free_msg_exit; + + memcpy(result->mac_addr, rx_msg->resp_connect_ap->mac.data, mac_len); + result->mac_addr[mac_len] = '\0'; + + result->status = (nh_ctrl_conn_status_t)rx_msg->resp_connect_ap->resp; + +free_msg_exit: + ctrl_msg__free_unpacked(rx_msg, &c_alloc); + +free_payload_exit: + NH_CTRL_API_FREE(api, (uint8_t *)tx_msg.req_connect_ap); + +give_sem_exit: + NH_CTRL_API_GIVE_SEM(api); + + return ret; +} + void nh_ctrl_api_task(nh_ctrl_api_t *api) { nh_ret_t ret = NH_RET_SUCCESS; diff --git a/src/nh_shared_if.c b/src/nh_shared_if.c index a96d6ca..5401a6d 100644 --- a/src/nh_shared_if.c +++ b/src/nh_shared_if.c @@ -51,6 +51,8 @@ typedef struct __attribute__((packed)) { }; /* Offset: 0x0B */ } nh_xfer_pkt_hdr_t; /* Size: 0x0C (12 bytes) */ +static void nh_shared_if_dispatch_sta(nh_shared_if_t *shared_if, uint8_t *payload, uint16_t len); +static void nh_shared_if_dispatch_ap(nh_shared_if_t *shared_if, uint8_t *payload, uint16_t len); static void nh_shared_if_dispatch_if_serial(nh_shared_if_t *shared_if, uint8_t *payload, uint16_t len); static void nh_shared_if_dispatch_if_priv(nh_shared_if_t *shared_if, nh_xfer_priv_type_t type, uint8_t *payload); @@ -243,22 +245,28 @@ void nh_shared_if_task(nh_shared_if_t *shared_if) { item.buf_len = LE16_TO_H(hdr->len); item.buf = &shared_if->p_buf_frame_rx[LE16_TO_H(hdr->offset)]; /* DO NOT FREE THIS!! */ - if (item.type == NH_SHARED_IF_TYPE_SERIAL) { - if (!item.buf_len) { - return; - } + if (!item.buf_len) { + return; + } + if (item.type == NH_SHARED_IF_TYPE_SERIAL) { nh_shared_if_dispatch_if_serial(shared_if, item.buf, item.buf_len); } else if (item.type == NH_SHARED_IF_TYPE_PRIV) { - if (!item.buf_len) { - return; - } - nh_shared_if_dispatch_if_priv(shared_if, hdr->priv_pkt_type, item.buf); + } else if (item.type == NH_SHARED_IF_TYPE_STA) { + nh_shared_if_dispatch_sta(shared_if, item.buf, item.buf_len); + } else if(item.type == NH_SHARED_IF_TYPE_AP) { + nh_shared_if_dispatch_ap(shared_if, item.buf, item.buf_len); } } } +static void nh_shared_if_dispatch_sta(nh_shared_if_t *shared_if, uint8_t *payload, uint16_t len) { +} + +static void nh_shared_if_dispatch_ap(nh_shared_if_t *shared_if, uint8_t *payload, uint16_t len) { +} + static void nh_shared_if_dispatch_if_priv(nh_shared_if_t *shared_if, nh_xfer_priv_type_t type, uint8_t *payload) { if (type == NH_SHARED_IF_PRIV_TYPE_EVENT) { /* Event is using PRIV interface. */