From 53dc930115123a69b7a43afc07b80cc85e598ec8 Mon Sep 17 00:00:00 2001 From: mcuw <112967559+mcuw@users.noreply.github.com> Date: Fri, 28 Aug 2026 22:18:27 +0200 Subject: [PATCH] chore: add common ot_coap_client component which contains a function to ensure that CoAP is started --- ot_br/components/ot_br_web_api/CMakeLists.txt | 2 +- .../ot_br_web_api/ot_br_web_api_coap_client.c | 9 ++++-- .../components/ot_coap_client/CMakeLists.txt | 5 +++ .../ot_coap_client/include/ot_coap_client.h | 31 +++++++++++++++++++ .../ot_coap_client/ot_coap_client.c | 24 ++++++++++++++ 5 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 ot_br/components/ot_coap_client/CMakeLists.txt create mode 100644 ot_br/components/ot_coap_client/include/ot_coap_client.h create mode 100644 ot_br/components/ot_coap_client/ot_coap_client.c diff --git a/ot_br/components/ot_br_web_api/CMakeLists.txt b/ot_br/components/ot_br_web_api/CMakeLists.txt index e1e1d24..29bbd47 100644 --- a/ot_br/components/ot_br_web_api/CMakeLists.txt +++ b/ot_br/components/ot_br_web_api/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( SRCS "ot_br_web_api.c" "ot_br_web_api_auth.c" "ot_br_web_api_handlers.c" "ot_br_web_api_ota.c" "ot_br_web_api_static.c" "ot_br_web_api_setup_mode.c" "ot_br_web_api_command.c" "ot_br_web_api_coap_client.c" INCLUDE_DIRS "include" - REQUIRES esp_http_server openthread nvs_flash esp_hw_support esp_app_format mbedtls espressif__cjson app_update esp_https_ota esp_http_client joltwallet__littlefs esp_driver_gpio esp_timer + REQUIRES esp_http_server openthread nvs_flash esp_hw_support esp_app_format mbedtls espressif__cjson app_update esp_https_ota esp_http_client joltwallet__littlefs esp_driver_gpio esp_timer ot_coap_client ) \ No newline at end of file diff --git a/ot_br/components/ot_br_web_api/ot_br_web_api_coap_client.c b/ot_br/components/ot_br_web_api/ot_br_web_api_coap_client.c index 3e6ac47..bef3211 100644 --- a/ot_br/components/ot_br_web_api/ot_br_web_api_coap_client.c +++ b/ot_br/components/ot_br_web_api/ot_br_web_api_coap_client.c @@ -9,6 +9,8 @@ #include "openthread/netdiag.h" #include "freertos/semphr.h" +#include "ot_coap_client.h" + static const char *TAG = "ot_br_coap_client"; static SemaphoreHandle_t s_response_sem = NULL; static otCoapCode s_last_response_code = 0; @@ -43,12 +45,13 @@ void ot_br_coap_client_init(void) s_response_sem = xSemaphoreCreateBinary(); otInstance *instance = esp_openthread_get_instance(); + esp_openthread_lock_acquire(portMAX_DELAY); - otError err = otCoapStart(instance, OT_DEFAULT_COAP_PORT); + esp_err_t err = ot_coap_client_ensure_started(instance); esp_openthread_lock_release(); - if (err != OT_ERROR_NONE && err != OT_ERROR_ALREADY) { - ESP_LOGE("ot_br_coap_client", "otCoapStart fehlgeschlagen: %d", err); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to start CoAP-Client"); } } diff --git a/ot_br/components/ot_coap_client/CMakeLists.txt b/ot_br/components/ot_coap_client/CMakeLists.txt new file mode 100644 index 0000000..f7202e8 --- /dev/null +++ b/ot_br/components/ot_coap_client/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRCS "ot_coap_client.c" + INCLUDE_DIRS "include" + REQUIRES driver openthread +) \ No newline at end of file diff --git a/ot_br/components/ot_coap_client/include/ot_coap_client.h b/ot_br/components/ot_coap_client/include/ot_coap_client.h new file mode 100644 index 0000000..ddb191a --- /dev/null +++ b/ot_br/components/ot_coap_client/include/ot_coap_client.h @@ -0,0 +1,31 @@ +#pragma once + +#include "esp_err.h" +#include "openthread/instance.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Ensure the OpenThread CoAP layer's UDP socket is open. + * + * otCoapSendRequest() requires otCoapStart() to have been called at + * least once -- even for pure client usage that never registers a + * resource -- otherwise it fails with OT_ERROR_INVALID_STATE. This + * wrapper makes that call exactly once per boot and is safe to call + * from every place that is about to send a CoAP request. + * + * Must be called with the OpenThread lock already held by the caller + * (esp_openthread_lock_acquire()), same as any other otXxx() call. + * + * @param instance A valid OpenThread instance (e.g. from + * esp_openthread_get_instance()). + * @return ESP_OK if the CoAP layer is started (either just now or + * already before), ESP_FAIL if otCoapStart() itself failed. + */ +esp_err_t ot_coap_client_ensure_started(otInstance *instance); + +#ifdef __cplusplus +} +#endif diff --git a/ot_br/components/ot_coap_client/ot_coap_client.c b/ot_br/components/ot_coap_client/ot_coap_client.c new file mode 100644 index 0000000..967ea21 --- /dev/null +++ b/ot_br/components/ot_coap_client/ot_coap_client.c @@ -0,0 +1,24 @@ +#include "ot_coap_client.h" + +#include "esp_log.h" +#include "openthread/coap.h" + +static const char *TAG = "ot_coap_client"; +static bool s_coap_started = false; + +esp_err_t ot_coap_client_ensure_started(otInstance *instance) +{ + if (s_coap_started) { + return ESP_OK; + } + + otError error = otCoapStart(instance, OT_DEFAULT_COAP_PORT); + if (error != OT_ERROR_NONE && error != OT_ERROR_ALREADY) { + ESP_LOGE(TAG, "otCoapStart failed: %s", otThreadErrorToString(error)); + return ESP_FAIL; + } + + s_coap_started = true; + ESP_LOGI(TAG, "CoAP client layer started on port %d", OT_DEFAULT_COAP_PORT); + return ESP_OK; +} \ No newline at end of file