354 lines
11 KiB
C
354 lines
11 KiB
C
#include <string.h>
|
|
|
|
/* Private */
|
|
#include "nh_ctrl_api.h"
|
|
#include "protobuf-c/protobuf-c.h"
|
|
|
|
/* PB config */
|
|
#include "esp_hosted_config.pb-c.h"
|
|
|
|
#define NH_COMMAND_TIMEOUT_MSEC 30000
|
|
#define NH_COMMAND_REQ_MEM_SIZE 256
|
|
|
|
#define NH_CTRL_API_CREATE_ALLOCATOR(allocator_name, allocator_ctx) \
|
|
ProtobufCAllocator allocator_name = { \
|
|
.alloc = nh_ctrl_api_protobuf_allocate, \
|
|
.free = nh_ctrl_api_protobuf_free, \
|
|
.allocator_data = allocator_ctx, \
|
|
}
|
|
|
|
#define NH_CTRL_API_TAKE_SEM(s_api, timeout) s_api->osa->sem_take(s_api->osa->user_data, s_api->p_sem_req, timeout)
|
|
#define NH_CTRL_API_GIVE_SEM(s_api) s_api->osa->sem_give(api->osa->user_data, api->p_sem_req)
|
|
#define NH_CTRL_API_ALLOC(s_api, ptr, p_size) s_api->osa->buf_allocate(s_api->osa->user_data, ptr, p_size)
|
|
#define NH_CTRL_API_FREE(s_api, ptr) s_api->osa->buf_free(s_api->osa->user_data, ptr)
|
|
|
|
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, ProtobufCAllocator *allocator);
|
|
static void *nh_ctrl_api_protobuf_allocate(void *handle, size_t size);
|
|
static void nh_ctrl_api_protobuf_free(void *handle, void *data);
|
|
|
|
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_ctrl_wifi_mode_t mode) {
|
|
nh_ret_t ret = NH_RET_SUCCESS;
|
|
|
|
NH_CTRL_API_CREATE_ALLOCATOR(c_alloc, api);
|
|
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_GetMACAddress;
|
|
tx_msg.payload_case = CTRL_MSG__PAYLOAD_REQ_GET_MAC_ADDRESS;
|
|
|
|
ret = NH_CTRL_API_ALLOC(api, (uint8_t **)&tx_msg.req_get_mac_address, sizeof(CtrlMsgReqGetMacAddress));
|
|
if (ret != NH_RET_SUCCESS) goto give_sem_exit;
|
|
|
|
ctrl_msg__req__get_mac_address__init(tx_msg.req_get_mac_address);
|
|
|
|
tx_msg.req_get_mac_address->mode = (mode == NH_CTRL_WIFI_MODE_AP) ? CTRL__WIFI_MODE__AP : CTRL__WIFI_MODE__STA;
|
|
|
|
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_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';
|
|
|
|
free_msg_exit:
|
|
ctrl_msg__free_unpacked(rx_msg, &c_alloc);
|
|
|
|
free_payload_exit:
|
|
NH_CTRL_API_FREE(api, (uint8_t *)tx_msg.req_get_mac_address);
|
|
|
|
give_sem_exit:
|
|
NH_CTRL_API_GIVE_SEM(api);
|
|
|
|
return ret;
|
|
}
|
|
|
|
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 ret = NH_RET_SUCCESS;
|
|
|
|
NH_CTRL_API_CREATE_ALLOCATOR(c_alloc, api);
|
|
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_GetAPScanList;
|
|
tx_msg.payload_case = CTRL_MSG__PAYLOAD_REQ_SCAN_AP_LIST;
|
|
|
|
ret = NH_CTRL_API_ALLOC(api, (uint8_t **)&tx_msg.req_scan_ap_list, sizeof(CtrlMsgReqScanResult));
|
|
if (ret != NH_RET_SUCCESS) goto give_sem_exit;
|
|
|
|
ctrl_msg__req__scan_result__init(tx_msg.req_scan_ap_list);
|
|
|
|
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_GetAPScanList) goto free_msg_exit;
|
|
|
|
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:
|
|
ctrl_msg__free_unpacked(rx_msg, &c_alloc);
|
|
|
|
free_payload_exit:
|
|
NH_CTRL_API_FREE(api, (uint8_t *)tx_msg.req_get_mac_address);
|
|
|
|
give_sem_exit:
|
|
NH_CTRL_API_GIVE_SEM(api);
|
|
|
|
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, api);
|
|
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;
|
|
|
|
uint8_t *payload;
|
|
uint32_t payload_size;
|
|
nh_serial_ep_type_t ep_type;
|
|
|
|
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;
|
|
}
|
|
|
|
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) {
|
|
NH_CTRL_API_CREATE_ALLOCATOR(c_alloc, api);
|
|
|
|
CtrlMsg *msg = ctrl_msg__unpack(&c_alloc, buf_len, buf);
|
|
if (msg == NULL) {
|
|
return NH_RET_FAIL;
|
|
}
|
|
|
|
*event_id = msg->msg_id;
|
|
|
|
ctrl_msg__free_unpacked(msg, &c_alloc);
|
|
return NH_RET_SUCCESS;
|
|
}
|
|
|
|
static void nh_ctrl_api_dispatch_event(nh_ctrl_api_t *api, CtrlMsgId event_id) {
|
|
switch (event_id) {
|
|
case CTRL_MSG_ID__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;
|
|
|
|
size_t packed_size = ctrl_msg__get_packed_size(tx_msg);
|
|
if (packed_size == 0) {
|
|
return NH_RET_FAIL;
|
|
}
|
|
|
|
uint8_t *req_buf;
|
|
|
|
ret = NH_CTRL_API_ALLOC(api, &req_buf, packed_size);
|
|
if (ret != NH_RET_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
if (ctrl_msg__pack(tx_msg, req_buf) != packed_size) {
|
|
ret = NH_RET_FAIL;
|
|
goto free_tx_exit;
|
|
}
|
|
|
|
ret = nh_shared_if_serial_if_send(api->shared_if, req_buf, packed_size, NH_COMMAND_TIMEOUT_MSEC);
|
|
|
|
free_tx_exit:
|
|
NH_CTRL_API_FREE(api, req_buf);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static nh_ret_t nh_ctrl_api_general_response(nh_ctrl_api_t *api, CtrlMsg **rx_msg, ProtobufCAllocator *allocator) {
|
|
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;
|
|
}
|
|
|
|
*rx_msg = ctrl_msg__unpack(allocator, api->p_buf_rx_len, api->p_buf_rx);
|
|
if (*rx_msg == NULL) {
|
|
ret = NH_RET_FAIL;
|
|
}
|
|
|
|
nh_shared_if_serial_if_free(api->shared_if, api->p_buf_rx);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void *nh_ctrl_api_protobuf_allocate(void *handle, size_t size) {
|
|
nh_ctrl_api_t *api = handle;
|
|
uint8_t *buf = NULL;
|
|
|
|
if (NH_CTRL_API_ALLOC(api, &buf, size) != NH_RET_SUCCESS) {
|
|
return NULL;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
static void nh_ctrl_api_protobuf_free(void *handle, void *data) {
|
|
nh_ctrl_api_t *api = handle;
|
|
|
|
NH_CTRL_API_FREE(api, data);
|
|
} |