esp_local_ctrl_handler.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. // Copyright 2019 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <esp_err.h>
  17. #include <esp_log.h>
  18. #include "esp_local_ctrl.h"
  19. #include "esp_local_ctrl_priv.h"
  20. #include "esp_local_ctrl.pb-c.h"
  21. #define SAFE_ALLOCATION(type, var) \
  22. type *var = (type *) malloc(sizeof(type)); \
  23. if (!var) { \
  24. ESP_LOGE(TAG, "Error allocating memory"); \
  25. return ESP_ERR_NO_MEM; \
  26. }
  27. static const char* TAG = "esp_local_ctrl_handler";
  28. typedef struct esp_local_ctrl_cmd {
  29. int cmd_num;
  30. esp_err_t (*command_handler)(LocalCtrlMessage *req,
  31. LocalCtrlMessage *resp, void **ctx);
  32. } esp_local_ctrl_cmd_t;
  33. static esp_err_t cmd_get_prop_count_handler(LocalCtrlMessage *req,
  34. LocalCtrlMessage *resp, void **ctx);
  35. static esp_err_t cmd_get_prop_vals_handler(LocalCtrlMessage *req,
  36. LocalCtrlMessage *resp, void **ctx);
  37. static esp_err_t cmd_set_prop_vals_handler(LocalCtrlMessage *req,
  38. LocalCtrlMessage *resp, void **ctx);
  39. static esp_local_ctrl_cmd_t cmd_table[] = {
  40. {
  41. .cmd_num = LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyCount,
  42. .command_handler = cmd_get_prop_count_handler
  43. },
  44. {
  45. .cmd_num = LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyValues,
  46. .command_handler = cmd_get_prop_vals_handler
  47. },
  48. {
  49. .cmd_num = LOCAL_CTRL_MSG_TYPE__TypeCmdSetPropertyValues,
  50. .command_handler = cmd_set_prop_vals_handler
  51. }
  52. };
  53. static uint16_t err_to_status(esp_err_t err)
  54. {
  55. uint16_t status;
  56. switch (err) {
  57. case ESP_OK:
  58. status = STATUS__Success;
  59. break;
  60. case ESP_ERR_INVALID_ARG:
  61. status = STATUS__InvalidArgument;
  62. break;
  63. case ESP_ERR_INVALID_STATE:
  64. status = STATUS__InvalidProto;
  65. break;
  66. default:
  67. status = STATUS__InternalError;
  68. }
  69. return status;
  70. }
  71. static esp_err_t cmd_get_prop_count_handler(LocalCtrlMessage *req,
  72. LocalCtrlMessage *resp, void **ctx)
  73. {
  74. SAFE_ALLOCATION(RespGetPropertyCount, resp_payload);
  75. resp_get_property_count__init(resp_payload);
  76. size_t prop_count = 0;
  77. resp_payload->status = err_to_status(esp_local_ctrl_get_prop_count(&prop_count));
  78. resp_payload->count = prop_count;
  79. resp->payload_case = LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_GET_PROP_COUNT;
  80. resp->resp_get_prop_count = resp_payload;
  81. ESP_LOGD(TAG, "Got properties count %d", prop_count);
  82. return ESP_OK;
  83. }
  84. typedef void (*prop_val_free_fn_t)(void *val);
  85. static esp_err_t cmd_get_prop_vals_handler(LocalCtrlMessage *req,
  86. LocalCtrlMessage *resp, void **ctx)
  87. {
  88. SAFE_ALLOCATION(RespGetPropertyValues, resp_payload);
  89. resp_get_property_values__init(resp_payload);
  90. esp_local_ctrl_prop_val_t *vals = calloc(req->cmd_get_prop_vals->n_indices,
  91. sizeof(esp_local_ctrl_prop_val_t));
  92. esp_local_ctrl_prop_t *descs = calloc(req->cmd_get_prop_vals->n_indices,
  93. sizeof(esp_local_ctrl_prop_t));
  94. prop_val_free_fn_t *free_fns = calloc(req->cmd_get_prop_vals->n_indices,
  95. sizeof(prop_val_free_fn_t));
  96. resp_payload->props = calloc(req->cmd_get_prop_vals->n_indices,
  97. sizeof(PropertyInfo *));
  98. if (!vals || !descs || !free_fns || !resp_payload->props) {
  99. ESP_LOGE(TAG, "Failed to allocate memory for getting values");
  100. free(vals);
  101. free(descs);
  102. free(free_fns);
  103. free(resp_payload->props);
  104. free(resp_payload);
  105. return ESP_ERR_NO_MEM;
  106. }
  107. esp_err_t ret = esp_local_ctrl_get_prop_values(req->cmd_get_prop_vals->n_indices,
  108. req->cmd_get_prop_vals->indices,
  109. descs, vals);
  110. resp_payload->status = err_to_status(ret);
  111. if (ret == ESP_OK) {
  112. resp_payload->n_props = 0;
  113. for (size_t i = 0; i < req->cmd_get_prop_vals->n_indices; i++) {
  114. resp_payload->props[i] = malloc(sizeof(PropertyInfo));
  115. if (!resp_payload->props[i]) {
  116. resp_payload->status = STATUS__InternalError;
  117. break;
  118. }
  119. resp_payload->n_props++;
  120. property_info__init(resp_payload->props[i]);
  121. resp_payload->props[i]->name = descs[i].name;
  122. resp_payload->props[i]->type = descs[i].type;
  123. resp_payload->props[i]->flags = descs[i].flags;
  124. resp_payload->props[i]->value.data = vals[i].data;
  125. resp_payload->props[i]->value.len = vals[i].size;
  126. free_fns[i] = vals[i].free_fn;
  127. }
  128. }
  129. resp->payload_case = LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_GET_PROP_VALS;
  130. resp->resp_get_prop_vals = resp_payload;
  131. (*ctx) = (void *)free_fns;
  132. free(vals);
  133. free(descs);
  134. /* Unless it's a fatal error, always return ESP_OK, otherwise
  135. * the underlying connection will be closed by protocomm */
  136. return ESP_OK;
  137. }
  138. static esp_err_t cmd_set_prop_vals_handler(LocalCtrlMessage *req,
  139. LocalCtrlMessage *resp, void **ctx)
  140. {
  141. SAFE_ALLOCATION(RespSetPropertyValues, resp_payload);
  142. resp_set_property_values__init(resp_payload);
  143. uint32_t *idxs = calloc(req->cmd_set_prop_vals->n_props, sizeof(uint32_t));
  144. esp_local_ctrl_prop_val_t *vals = calloc(req->cmd_set_prop_vals->n_props,
  145. sizeof(esp_local_ctrl_prop_val_t));
  146. if (!idxs || !vals) {
  147. ESP_LOGE(TAG, "Failed to allocate memory for setting values");
  148. free(idxs);
  149. free(vals);
  150. free(resp_payload);
  151. return ESP_ERR_NO_MEM;
  152. }
  153. for (size_t i = 0; i < req->cmd_set_prop_vals->n_props; i++) {
  154. idxs[i] = req->cmd_set_prop_vals->props[i]->index;
  155. vals[i].data = req->cmd_set_prop_vals->props[i]->value.data;
  156. vals[i].size = req->cmd_set_prop_vals->props[i]->value.len;
  157. }
  158. esp_err_t ret = esp_local_ctrl_set_prop_values(req->cmd_set_prop_vals->n_props,
  159. idxs, vals);
  160. resp_payload->status = err_to_status(ret);
  161. resp->payload_case = LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_SET_PROP_VALS;
  162. resp->resp_set_prop_vals = resp_payload;
  163. free(idxs);
  164. free(vals);
  165. /* Unless it's a fatal error, always return ESP_OK, otherwise
  166. * the underlying connection will be closed by protocomm */
  167. return ESP_OK;
  168. }
  169. static int lookup_cmd_handler(int cmd_id)
  170. {
  171. for (size_t i = 0; i < sizeof(cmd_table)/sizeof(esp_local_ctrl_cmd_t); i++) {
  172. if (cmd_table[i].cmd_num == cmd_id) {
  173. return i;
  174. }
  175. }
  176. return -1;
  177. }
  178. static void esp_local_ctrl_command_cleanup(LocalCtrlMessage *resp, void **ctx)
  179. {
  180. if (!resp) {
  181. return;
  182. }
  183. switch (resp->msg) {
  184. case LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyCount:
  185. free(resp->resp_get_prop_count);
  186. break;
  187. case LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyValues: {
  188. if (resp->resp_get_prop_vals) {
  189. prop_val_free_fn_t *free_fns = (prop_val_free_fn_t *)(*ctx);
  190. for (size_t i = 0; i < resp->resp_get_prop_vals->n_props; i++) {
  191. if (free_fns && free_fns[i]) {
  192. free_fns[i](resp->resp_get_prop_vals->props[i]->value.data);
  193. }
  194. free(resp->resp_get_prop_vals->props[i]);
  195. }
  196. free(free_fns);
  197. free(resp->resp_get_prop_vals->props);
  198. free(resp->resp_get_prop_vals);
  199. }
  200. }
  201. break;
  202. case LOCAL_CTRL_MSG_TYPE__TypeRespSetPropertyValues:
  203. free(resp->resp_set_prop_vals);
  204. break;
  205. default:
  206. ESP_LOGE(TAG, "Unsupported response type in cleanup_handler");
  207. }
  208. return;
  209. }
  210. static esp_err_t esp_local_ctrl_command_dispatcher(LocalCtrlMessage *req,
  211. LocalCtrlMessage *resp,
  212. void **ctx)
  213. {
  214. int cmd_index = lookup_cmd_handler(req->msg);
  215. if (cmd_index < 0) {
  216. ESP_LOGE(TAG, "Invalid command handler lookup");
  217. return ESP_ERR_INVALID_ARG;
  218. }
  219. esp_err_t ret = cmd_table[cmd_index].command_handler(req, resp, ctx);
  220. if (ret != ESP_OK) {
  221. ESP_LOGE(TAG, "Error executing command handler");
  222. return ret;
  223. }
  224. return ESP_OK;
  225. }
  226. esp_err_t esp_local_ctrl_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,
  227. uint8_t **outbuf, ssize_t *outlen, void *priv_data)
  228. {
  229. void *temp_ctx = NULL;
  230. LocalCtrlMessage *req = local_ctrl_message__unpack(NULL, inlen, inbuf);
  231. if (!req) {
  232. ESP_LOGE(TAG, "Unable to unpack payload data");
  233. return ESP_ERR_INVALID_ARG;
  234. }
  235. LocalCtrlMessage resp;
  236. local_ctrl_message__init(&resp);
  237. resp.msg = req->msg + 1; /* Response is request + 1 */
  238. esp_err_t ret = esp_local_ctrl_command_dispatcher(req, &resp, &temp_ctx);
  239. if (ret != ESP_OK) {
  240. ESP_LOGE(TAG, "command dispatcher failed");
  241. esp_local_ctrl_command_cleanup(&resp, &temp_ctx);
  242. local_ctrl_message__free_unpacked(req, NULL);
  243. return ESP_FAIL;
  244. }
  245. local_ctrl_message__free_unpacked(req, NULL);
  246. *outlen = local_ctrl_message__get_packed_size(&resp);
  247. if (*outlen <= 0) {
  248. ESP_LOGE(TAG, "Invalid encoding for response");
  249. esp_local_ctrl_command_cleanup(&resp, &temp_ctx);
  250. return ESP_FAIL;
  251. }
  252. *outbuf = (uint8_t *) malloc(*outlen);
  253. if (!*outbuf) {
  254. ESP_LOGE(TAG, "System out of memory");
  255. esp_local_ctrl_command_cleanup(&resp, &temp_ctx);
  256. return ESP_ERR_NO_MEM;
  257. }
  258. local_ctrl_message__pack(&resp, *outbuf);
  259. esp_local_ctrl_command_cleanup(&resp, &temp_ctx);
  260. ESP_LOG_BUFFER_HEX_LEVEL(TAG, *outbuf, *outlen, ESP_LOG_DEBUG);
  261. return ESP_OK;
  262. }