esp_nano_hosted/src/nh_ctrl_api.c

205 lines
5.7 KiB
C

/* 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;
}