1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
30
31
32
33
34
35
36
37
38
39
43
44
48
49
53
54
55
59
60
64
65
66
70
71
72
73
74
80
81
85
93
94
98
99
102
103
104
105
109
110
111
115
116
117
121
122
123
124
129
130
138
139
140
141
146
147
148
178
179
180
185
186
187
188
193
194
195
196
197
198
199
202
208
212
213
214
225
226
227
228
229
230
231
232
233
234
237
238
240
245
246
247
248
249
250
254
257
261
262
263
267
268
269
270
274
275
281
282
283
284
285
286
287
288
289
290
291
292
293
294
298
299
300
304
305
306
307
308
310
316
317
318
319
320
330
331
343
344
345
346
347
348
352
355
356
357
358
362
363
364
365
366
367
368
369
370
371
372
373
378
379
380
381
382
383
384
388
391
392
393
394
398
399
404
405
406
407
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
438
439
442
443
/* ... */
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <esp_err.h>
#include <esp_log.h>
#include <protocomm.h>
#include <protocomm_security0.h>
#include <protocomm_security1.h>
#include <protocomm_security2.h>
#include <esp_local_ctrl.h>
#include "esp_local_ctrl_priv.h"
#include "esp_local_ctrl.pb-c.h"12 includes
#define ESP_LOCAL_CTRL_VERSION "v1.0"
struct inst_ctx {
protocomm_t *pc;
esp_local_ctrl_config_t config;
esp_local_ctrl_prop_t **props;
size_t props_count;
}{ ... };
struct inst_ctx *local_ctrl_inst_ctx;
static const char *TAG = "esp_local_ctrl";
esp_err_t esp_local_ctrl_start(const esp_local_ctrl_config_t *config)
{
esp_err_t ret;
if (!config) {
ESP_LOGE(TAG, "NULL configuration provided");
return ESP_ERR_INVALID_ARG;
}{...}
if (!config->transport) {
ESP_LOGE(TAG, "No transport provided");
return ESP_ERR_INVALID_ARG;
}{...}
if (config->max_properties == 0) {
ESP_LOGE(TAG, "max_properties must be greater than 0");
return ESP_ERR_INVALID_ARG;
}{...}
if (!config->handlers.get_prop_values ||
!config->handlers.set_prop_values) {
ESP_LOGE(TAG, "Handlers cannot be null");
return ESP_ERR_INVALID_ARG;
}{...}
if (local_ctrl_inst_ctx) {
ESP_LOGW(TAG, "Service already active");
return ESP_ERR_INVALID_STATE;
}{...}
local_ctrl_inst_ctx = calloc(1, sizeof(struct inst_ctx));
if (!local_ctrl_inst_ctx) {
ESP_LOGE(TAG, "Failed to allocate memory for instance");
return ESP_ERR_NO_MEM;
}{...}
memcpy(&local_ctrl_inst_ctx->config, config, sizeof(local_ctrl_inst_ctx->config));
local_ctrl_inst_ctx->props = calloc(local_ctrl_inst_ctx->config.max_properties,
sizeof(esp_local_ctrl_prop_t *));
if (!local_ctrl_inst_ctx->props) {
ESP_LOGE(TAG, "Failed to allocate memory for properties");
free(local_ctrl_inst_ctx);
local_ctrl_inst_ctx = NULL;
return ESP_ERR_NO_MEM;
}{...}
/* ... */
if (config->transport->copy_config) {
ret = config->transport->copy_config(&local_ctrl_inst_ctx->config.transport_config,
&config->transport_config);
if (ret != ESP_OK) {
esp_local_ctrl_stop();
return ret;
}{...}
}{...}
/* ... */
if (config->transport->declare_ep) {
/* ... */
uint16_t start_uuid = 0xFF50;
ret = config->transport->declare_ep(&local_ctrl_inst_ctx->config.transport_config,
"esp_local_ctrl/version", start_uuid++);
if (ret != ESP_OK) {
esp_local_ctrl_stop();
return ret;
}{...}
ret = config->transport->declare_ep(&local_ctrl_inst_ctx->config.transport_config,
"esp_local_ctrl/session", start_uuid++);
if (ret != ESP_OK) {
esp_local_ctrl_stop();
return ret;
}{...}
ret = config->transport->declare_ep(&local_ctrl_inst_ctx->config.transport_config,
"esp_local_ctrl/control", start_uuid++);
if (ret != ESP_OK) {
esp_local_ctrl_stop();
return ret;
}{...}
}{...}
local_ctrl_inst_ctx->pc = protocomm_new();
if (!local_ctrl_inst_ctx->pc) {
ESP_LOGE(TAG, "Failed to create new protocomm instance");
esp_local_ctrl_stop();
return ESP_FAIL;
}{...}
if (config->transport->start_service) {
ret = config->transport->start_service(local_ctrl_inst_ctx->pc,
&local_ctrl_inst_ctx->config.transport_config);
if (ret != ESP_OK) {
esp_local_ctrl_stop();
return ret;
}{...}
}{...}
ret = protocomm_set_version(local_ctrl_inst_ctx->pc, "esp_local_ctrl/version",
ESP_LOCAL_CTRL_VERSION);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set version endpoint");
esp_local_ctrl_stop();
return ret;
}{...}
protocomm_security_t *proto_sec_handle = NULL;
switch (local_ctrl_inst_ctx->config.proto_sec.version) {
case PROTOCOM_SEC_CUSTOM:
proto_sec_handle = local_ctrl_inst_ctx->config.proto_sec.custom_handle;
break;...
case PROTOCOM_SEC1:
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1
proto_sec_handle = (protocomm_security_t *) &protocomm_security1;
#else
return ESP_ERR_NOT_SUPPORTED;/* ... */
#endif
break;...
case PROTOCOM_SEC2:
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2
proto_sec_handle = (protocomm_security_t *) &protocomm_security2;
break;/* ... */
#else
return ESP_ERR_NOT_SUPPORTED;/* ... */
#endif...
case PROTOCOM_SEC0:
default:
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0
proto_sec_handle = (protocomm_security_t *) &protocomm_security0;
#else
return ESP_ERR_NOT_SUPPORTED;/* ... */
#endif
break;...
}{...}
ret = protocomm_set_security(local_ctrl_inst_ctx->pc, "esp_local_ctrl/session",
proto_sec_handle, local_ctrl_inst_ctx->config.proto_sec.sec_params);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set session endpoint");
esp_local_ctrl_stop();
return ret;
}{...}
ret = protocomm_add_endpoint(local_ctrl_inst_ctx->pc, "esp_local_ctrl/control",
esp_local_ctrl_data_handler, NULL);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set control endpoint");
esp_local_ctrl_stop();
return ret;
}{...}
return ESP_OK;
}{ ... }
esp_err_t esp_local_ctrl_stop(void)
{
if (local_ctrl_inst_ctx) {
if (local_ctrl_inst_ctx->config.transport->free_config) {
local_ctrl_inst_ctx->config.transport->free_config(&local_ctrl_inst_ctx->config.transport_config);
}{...}
if (local_ctrl_inst_ctx->pc) {
if (local_ctrl_inst_ctx->config.transport->stop_service) {
local_ctrl_inst_ctx->config.transport->stop_service(local_ctrl_inst_ctx->pc);
}{...}
protocomm_delete(local_ctrl_inst_ctx->pc);
}{...}
if (local_ctrl_inst_ctx->config.handlers.usr_ctx_free_fn) {
local_ctrl_inst_ctx->config.handlers.usr_ctx_free_fn(
local_ctrl_inst_ctx->config.handlers.usr_ctx);
}{...}
for (uint32_t i = 0; i < local_ctrl_inst_ctx->config.max_properties; i++) {
if (local_ctrl_inst_ctx->props[i] == NULL) {
continue;
}{...}
free(local_ctrl_inst_ctx->props[i]->name);
if (local_ctrl_inst_ctx->props[i]->ctx_free_fn) {
local_ctrl_inst_ctx->props[i]->ctx_free_fn(local_ctrl_inst_ctx->props[i]->ctx);
}{...}
free(local_ctrl_inst_ctx->props[i]);
}{...}
free(local_ctrl_inst_ctx->props);
free(local_ctrl_inst_ctx);
local_ctrl_inst_ctx = NULL;
}{...}
return ESP_OK;
}{ ... }
static int esp_local_ctrl_get_property_index(const char *name)
{
if (!local_ctrl_inst_ctx || !name) {
return -1;
}{...}
/* ... */
for (uint32_t i = 0; i < local_ctrl_inst_ctx->props_count; i++) {
if (strcmp(local_ctrl_inst_ctx->props[i]->name, name) == 0) {
return i;
}{...}
}{...}
return -1;
}{ ... }
esp_err_t esp_local_ctrl_add_property(const esp_local_ctrl_prop_t *prop)
{
if (!local_ctrl_inst_ctx) {
ESP_LOGE(TAG, "Service not running");
return ESP_ERR_INVALID_STATE;
}{...}
if (!prop || !prop->name) {
return ESP_ERR_INVALID_ARG;
}{...}
if (esp_local_ctrl_get_property_index(prop->name) >= 0) {
ESP_LOGE(TAG, "Property with name %s exists", prop->name);
return ESP_ERR_INVALID_STATE;
}{...}
if (local_ctrl_inst_ctx->config.max_properties
== local_ctrl_inst_ctx->props_count) {
ESP_LOGE(TAG, "Max properties limit reached. Cannot add property %s", prop->name);
return ESP_ERR_NO_MEM;
}{...}
uint32_t i = local_ctrl_inst_ctx->props_count;
local_ctrl_inst_ctx->props[i] = calloc(1, sizeof(esp_local_ctrl_prop_t));
if (!local_ctrl_inst_ctx->props[i]) {
ESP_LOGE(TAG, "Failed to allocate memory for new property %s", prop->name);
return ESP_ERR_NO_MEM;
}{...}
local_ctrl_inst_ctx->props[i]->name = strdup(prop->name);
if (!local_ctrl_inst_ctx->props[i]->name) {
ESP_LOGE(TAG, "Failed to allocate memory for property data %s", prop->name);
free(local_ctrl_inst_ctx->props[i]);
local_ctrl_inst_ctx->props[i] = NULL;
return ESP_ERR_NO_MEM;
}{...}
local_ctrl_inst_ctx->props[i]->type = prop->type;
local_ctrl_inst_ctx->props[i]->size = prop->size;
local_ctrl_inst_ctx->props[i]->flags = prop->flags;
local_ctrl_inst_ctx->props[i]->ctx = prop->ctx;
local_ctrl_inst_ctx->props[i]->ctx_free_fn = prop->ctx_free_fn;
local_ctrl_inst_ctx->props_count++;
return ESP_OK;
}{ ... }
esp_err_t esp_local_ctrl_remove_property(const char *name)
{
int idx = esp_local_ctrl_get_property_index(name);
if (idx < 0) {
ESP_LOGE(TAG, "Property %s not found", name);
return ESP_ERR_NOT_FOUND;
}{...}
if (local_ctrl_inst_ctx->props[idx]->ctx_free_fn) {
local_ctrl_inst_ctx->props[idx]->ctx_free_fn(
local_ctrl_inst_ctx->props[idx]->ctx);
}{...}
free(local_ctrl_inst_ctx->props[idx]->name);
free(local_ctrl_inst_ctx->props[idx]);
local_ctrl_inst_ctx->props[idx++] = NULL;
/* ... */
for (uint32_t i = idx; i < local_ctrl_inst_ctx->props_count; i++) {
if (local_ctrl_inst_ctx->props[i] == NULL) {
break;
}{...}
local_ctrl_inst_ctx->props[i-1] = local_ctrl_inst_ctx->props[i];
}{...}
local_ctrl_inst_ctx->props_count--;
return ESP_OK;
}{ ... }
const esp_local_ctrl_prop_t *esp_local_ctrl_get_property(const char *name)
{
int idx = esp_local_ctrl_get_property_index(name);
if (idx < 0) {
ESP_LOGE(TAG, "Property %s not found", name);
return NULL;
}{...}
return local_ctrl_inst_ctx->props[idx];
}{ ... }
esp_err_t esp_local_ctrl_get_prop_count(size_t *count)
{
if (!local_ctrl_inst_ctx) {
ESP_LOGE(TAG, "Service not running");
return ESP_ERR_INVALID_STATE;
}{...}
if (!count) {
return ESP_ERR_INVALID_ARG;
}{...}
*count = local_ctrl_inst_ctx->props_count;
return ESP_OK;
}{ ... }
esp_err_t esp_local_ctrl_get_prop_values(size_t total_indices, uint32_t *indices,
esp_local_ctrl_prop_t *props,
esp_local_ctrl_prop_val_t *values)
{
if (!local_ctrl_inst_ctx) {
ESP_LOGE(TAG, "Service not running");
return ESP_ERR_INVALID_STATE;
}{...}
if (!indices || !props || !values) {
return ESP_ERR_INVALID_ARG;
}{...}
for (size_t i = 0; i < total_indices; i++) {
if (indices[i] >= local_ctrl_inst_ctx->props_count) {
ESP_LOGE(TAG, "Invalid property index %" PRId32, indices[i]);
return ESP_ERR_INVALID_ARG;
}{...}
props[i].name = local_ctrl_inst_ctx->props[indices[i]]->name;
props[i].type = local_ctrl_inst_ctx->props[indices[i]]->type;
props[i].flags = local_ctrl_inst_ctx->props[indices[i]]->flags;
props[i].size = local_ctrl_inst_ctx->props[indices[i]]->size;
props[i].ctx = local_ctrl_inst_ctx->props[indices[i]]->ctx;
}{...}
esp_local_ctrl_handlers_t *h = &local_ctrl_inst_ctx->config.handlers;
esp_err_t ret = h->get_prop_values(total_indices, props, values, h->usr_ctx);
for (size_t i = 0; i < total_indices; i++) {
if (local_ctrl_inst_ctx->props[indices[i]]->size != 0) {
values[i].size = local_ctrl_inst_ctx->props[indices[i]]->size;
}{...}
}{...}
return ret;
}{ ... }
esp_err_t esp_local_ctrl_set_prop_values(size_t total_indices, uint32_t *indices,
const esp_local_ctrl_prop_val_t *values)
{
if (!local_ctrl_inst_ctx) {
ESP_LOGE(TAG, "Service not running");
return ESP_ERR_INVALID_STATE;
}{...}
if (!indices || !values) {
return ESP_ERR_INVALID_ARG;
}{...}
esp_local_ctrl_prop_t *props = calloc(total_indices,
sizeof(esp_local_ctrl_prop_t));
if (!props) {
ESP_LOGE(TAG, "Unable to allocate memory for properties array");
return ESP_ERR_NO_MEM;
}{...}
for (size_t i = 0; i < total_indices; i++) {
if (indices[i] >= local_ctrl_inst_ctx->props_count) {
ESP_LOGE(TAG, "Invalid property index %" PRId32, indices[i]);
free(props);
return ESP_ERR_INVALID_ARG;
}{...}
if ((local_ctrl_inst_ctx->props[indices[i]]->size != values[i].size) &&
(local_ctrl_inst_ctx->props[indices[i]]->size != 0)) {
ESP_LOGE(TAG, "Invalid property size %d. Expected %d",
values[i].size, local_ctrl_inst_ctx->props[indices[i]]->size);
free(props);
return ESP_ERR_INVALID_ARG;
}{...}
props[i].name = local_ctrl_inst_ctx->props[indices[i]]->name;
props[i].type = local_ctrl_inst_ctx->props[indices[i]]->type;
props[i].flags = local_ctrl_inst_ctx->props[indices[i]]->flags;
props[i].size = local_ctrl_inst_ctx->props[indices[i]]->size;
props[i].ctx = local_ctrl_inst_ctx->props[indices[i]]->ctx;
}{...}
esp_local_ctrl_handlers_t *h = &local_ctrl_inst_ctx->config.handlers;
esp_err_t ret = h->set_prop_values(total_indices, props, values, h->usr_ctx);
free(props);
return ret;
}{ ... }
esp_err_t esp_local_ctrl_set_handler(const char *ep_name,
protocomm_req_handler_t handler,
void *priv_data)
{
esp_err_t ret = ESP_ERR_INVALID_STATE;
if (local_ctrl_inst_ctx) {
ret = protocomm_add_endpoint(local_ctrl_inst_ctx->pc, ep_name,
handler, priv_data);
}{...}
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to register endpoint handler");
}{...}
return ret;
}{ ... }