/* 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 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; ret = nh_ctrl_api_general_request(api, &tx_msg); if (ret != NH_RET_SUCCESS) { goto give_sem_exit; } CtrlMsg rx_msg; 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 *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) { 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 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; 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; }