From e0133b486b2db8f671f7c8b09e5fcaa44239b50c Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Mon, 6 Oct 2025 19:30:58 +0100 Subject: [PATCH 01/15] feat: adds note-c platform mutexes --- Kconfig | 8 ++ README.md | 27 ++++ examples/basic_usage_i2c/dependencies.lock | 2 +- include/notecard.h | 27 ++++ src/notecard.c | 3 + src/notecard_platform.c | 160 +++++++++++++++++++++ src/notecard_platform.h | 7 + 7 files changed, 233 insertions(+), 1 deletion(-) diff --git a/Kconfig b/Kconfig index 41f6100..9e6d23d 100644 --- a/Kconfig +++ b/Kconfig @@ -71,6 +71,14 @@ menu "Notecard Configuration" help Enable internal pull-up resistors for I2C lines. Disable this if you have external pull-up resistors. + + config NOTECARD_I2C_MUTEX + bool "Enable I2C mutex" + default y + help + Enable I2C mutex callback to prevent concurrent access to the I2C bus. + Disable if you intend to define your own I2C bus mutex. + endmenu menu "Default UART Configuration" diff --git a/README.md b/README.md index 0caa154..4b16f7b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # ESP-IDF Notecard Component An ESP-IDF component for integrating Espressif devices with the Blues [Notecard](https://blues.com/products/notecard/). +This component provides a thread-safe interface to the Notecard using the [note-c](https://github.com/blues/note-c) library. ## Installation @@ -44,6 +45,32 @@ idf.py menuconfig Component config ---> Notecard Configuration ``` +## Thread Safety + +The component automatically provides thread-safe access to the Notecard in multi-threaded FreeRTOS applications. +The underlying [note-c](https://github.com/blues/note-c) library protects the Notecard from concurrent access using internal mutexes, so no additional locking is required for normal use. + +### I2C Bus Sharing + +If you have other I2C peripherals on the same bus as the Notecard, use the I2C mutex API to coordinate access: + +```c +#include "notecard.h" + +// Access your I2C peripherals +notecard_lock_i2c(); +i2c_master_transmit(my_peripheral_handle, data, len, timeout); +notecard_unlock_i2c(); +``` + +This ensures the `note-c` won't attempt I2C communication while you're accessing your other peripherals. + +In order to enable/disable the provided I2C bus mutex, for example to use your own mutex, use `menuconfig`: + +``` +Component config ---> Notecard Configuration ---> Default I2C Configuration ---> [ ] Enable I2C mutex +``` + ## Examples For examples, see the [examples](examples) directory. diff --git a/examples/basic_usage_i2c/dependencies.lock b/examples/basic_usage_i2c/dependencies.lock index d2df1b0..a28416f 100644 --- a/examples/basic_usage_i2c/dependencies.lock +++ b/examples/basic_usage_i2c/dependencies.lock @@ -5,6 +5,6 @@ dependencies: version: 5.5.1 direct_dependencies: - idf -manifest_hash: 08ac1ee392ce13ac722569147b417c0484712da30ecb148c8d70f9d19fd69d84 +manifest_hash: 76ace180aa99c6f25d2173274f65375f15b1c8465779efd9e729e9b2f8d8c311 target: esp32 version: 2.0.0 diff --git a/include/notecard.h b/include/notecard.h index b76c1b8..4a874b2 100644 --- a/include/notecard.h +++ b/include/notecard.h @@ -159,6 +159,33 @@ bool notecard_is_initialized(void); */ void notecard_set_logging(bool enable); +/** + * @brief Lock the I2C bus mutex + * + * Use this when accessing other I2C peripherals on the same bus to prevent + * conflicts with Notecard I2C operations. Always pair with notecard_unlock_i2c(). + * + * @note Only available if CONFIG_NOTECARD_I2C_MUTEX is enabled in Kconfig + * + * Example: + * @code + * notecard_lock_i2c(); + * // Access your I2C sensor here + * i2c_master_transmit(my_sensor_handle, data, len, timeout); + * notecard_unlock_i2c(); + * @endcode + */ +void notecard_lock_i2c(void); + +/** + * @brief Unlock the I2C bus mutex + * + * Must be called after notecard_lock_i2c() to release the I2C bus. + * + * @note Only available if CONFIG_NOTECARD_I2C_MUTEX is enabled in Kconfig + */ +void notecard_unlock_i2c(void); + #ifdef __cplusplus } #endif diff --git a/src/notecard.c b/src/notecard.c index 81fad2a..391eeff 100644 --- a/src/notecard.c +++ b/src/notecard.c @@ -71,6 +71,9 @@ esp_err_t notecard_init(const notecard_config_t *config) notecard_platform_delay, notecard_platform_millis); + // Register mutex hooks for thread safety + notecard_platform_register_mutex_hooks(); + // Set up logging output if (g_logging_enabled) { NoteSetFnDebugOutput(notecard_logging_output); diff --git a/src/notecard_platform.c b/src/notecard_platform.c index 79ab73a..10e8b49 100644 --- a/src/notecard_platform.c +++ b/src/notecard_platform.c @@ -3,6 +3,7 @@ #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "freertos/semphr.h" #include "driver/i2c_master.h" #include "driver/uart.h" #include @@ -22,6 +23,46 @@ static bool g_i2c_initialized = false; static bool g_uart_initialized = false; static i2c_master_bus_handle_t g_i2c_bus_handle = NULL; +// FreeRTOS mutex handles for thread-safe access +#ifdef CONFIG_NOTECARD_I2C_MUTEX +static SemaphoreHandle_t g_i2c_mutex = NULL; +#endif +static SemaphoreHandle_t g_notecard_mutex = NULL; + +//============================================================================= +// Mutex Platform Implementation +//============================================================================= + +#ifdef CONFIG_NOTECARD_I2C_MUTEX +static void notecard_platform_lock_i2c(void) +{ + if (g_i2c_mutex != NULL) { + xSemaphoreTake(g_i2c_mutex, portMAX_DELAY); + } +} + +static void notecard_platform_unlock_i2c(void) +{ + if (g_i2c_mutex != NULL) { + xSemaphoreGive(g_i2c_mutex); + } +} +#endif + +static void notecard_platform_lock_note(void) +{ + if (g_notecard_mutex != NULL) { + xSemaphoreTake(g_notecard_mutex, portMAX_DELAY); + } +} + +static void notecard_platform_unlock_note(void) +{ + if (g_notecard_mutex != NULL) { + xSemaphoreGive(g_notecard_mutex); + } +} + //============================================================================= // I2C Platform Implementation //============================================================================= @@ -37,6 +78,31 @@ esp_err_t notecard_platform_i2c_init(const notecard_i2c_config_t *config) return ESP_ERR_INVALID_ARG; } + // Create mutexes +#ifdef CONFIG_NOTECARD_I2C_MUTEX + if (g_i2c_mutex == NULL) { + g_i2c_mutex = xSemaphoreCreateMutex(); + if (g_i2c_mutex == NULL) { + ESP_LOGE(TAG, "Failed to create I2C mutex"); + return ESP_ERR_NO_MEM; + } + } +#endif + + if (g_notecard_mutex == NULL) { + g_notecard_mutex = xSemaphoreCreateMutex(); + if (g_notecard_mutex == NULL) { + ESP_LOGE(TAG, "Failed to create Notecard mutex"); +#ifdef CONFIG_NOTECARD_I2C_MUTEX + if (g_i2c_mutex != NULL) { + vSemaphoreDelete(g_i2c_mutex); + g_i2c_mutex = NULL; + } +#endif + return ESP_ERR_NO_MEM; + } + } + // Store configuration memcpy(&g_i2c_config, config, sizeof(notecard_i2c_config_t)); @@ -55,6 +121,16 @@ esp_err_t notecard_platform_i2c_init(const notecard_i2c_config_t *config) esp_err_t ret = i2c_new_master_bus(&bus_config, &g_i2c_bus_handle); if (ret != ESP_OK) { ESP_LOGE(TAG, "I2C master bus creation failed: %s", esp_err_to_name(ret)); +#ifdef CONFIG_NOTECARD_I2C_MUTEX + if (g_i2c_mutex != NULL) { + vSemaphoreDelete(g_i2c_mutex); + g_i2c_mutex = NULL; + } +#endif + if (g_notecard_mutex != NULL) { + vSemaphoreDelete(g_notecard_mutex); + g_notecard_mutex = NULL; + } return ret; } @@ -79,6 +155,20 @@ esp_err_t notecard_platform_i2c_deinit(void) g_i2c_bus_handle = NULL; g_i2c_initialized = false; + + // Clean up mutexes +#ifdef CONFIG_NOTECARD_I2C_MUTEX + if (g_i2c_mutex != NULL) { + vSemaphoreDelete(g_i2c_mutex); + g_i2c_mutex = NULL; + } +#endif + + if (g_notecard_mutex != NULL) { + vSemaphoreDelete(g_notecard_mutex); + g_notecard_mutex = NULL; + } + ESP_LOGI(TAG, "I2C deinitialized"); return ESP_OK; } @@ -228,6 +318,15 @@ esp_err_t notecard_platform_uart_init(const notecard_uart_config_t *config) return ESP_ERR_INVALID_ARG; } + // Create Notecard mutex + if (g_notecard_mutex == NULL) { + g_notecard_mutex = xSemaphoreCreateMutex(); + if (g_notecard_mutex == NULL) { + ESP_LOGE(TAG, "Failed to create Notecard mutex"); + return ESP_ERR_NO_MEM; + } + } + memcpy(&g_uart_config, config, sizeof(notecard_uart_config_t)); uart_config_t uart_conf = { @@ -257,6 +356,10 @@ esp_err_t notecard_platform_uart_init(const notecard_uart_config_t *config) config->tx_buffer_size, 0, NULL, 0); if (ret != ESP_OK) { ESP_LOGE(TAG, "UART driver install failed: %s", esp_err_to_name(ret)); + if (g_notecard_mutex != NULL) { + vSemaphoreDelete(g_notecard_mutex); + g_notecard_mutex = NULL; + } return ret; } @@ -280,6 +383,21 @@ esp_err_t notecard_platform_uart_deinit(void) } g_uart_initialized = false; + + // Clean up mutexes (only if I2C is not also using them) + if (!g_i2c_initialized) { +#ifdef CONFIG_NOTECARD_I2C_MUTEX + if (g_i2c_mutex != NULL) { + vSemaphoreDelete(g_i2c_mutex); + g_i2c_mutex = NULL; + } +#endif + if (g_notecard_mutex != NULL) { + vSemaphoreDelete(g_notecard_mutex); + g_notecard_mutex = NULL; + } + } + ESP_LOGI(TAG, "UART deinitialized"); return ESP_OK; } @@ -385,3 +503,45 @@ void notecard_platform_free(void *ptr) { free(ptr); } + +//============================================================================= +// Mutex Hook Registration +//============================================================================= + +void notecard_platform_register_mutex_hooks(void) +{ + // Register mutex hooks with note-c based on Kconfig settings +#ifdef CONFIG_NOTECARD_I2C_MUTEX + // Both I2C and Notecard mutexes enabled + NoteSetFnMutex(notecard_platform_lock_i2c, + notecard_platform_unlock_i2c, + notecard_platform_lock_note, + notecard_platform_unlock_note); +#else + // Only Notecard mutex enabled (I2C mutex is optional) + NoteSetFnNoteMutex(notecard_platform_lock_note, + notecard_platform_unlock_note); +#endif +} + +//============================================================================= +// Public I2C Mutex API for Application Use +//============================================================================= + +void notecard_lock_i2c(void) +{ +#ifdef CONFIG_NOTECARD_I2C_MUTEX + notecard_platform_lock_i2c(); +#else + ESP_LOGW(TAG, "I2C mutex not enabled in Kconfig"); +#endif +} + +void notecard_unlock_i2c(void) +{ +#ifdef CONFIG_NOTECARD_I2C_MUTEX + notecard_platform_unlock_i2c(); +#else + ESP_LOGW(TAG, "I2C mutex not enabled in Kconfig"); +#endif +} diff --git a/src/notecard_platform.h b/src/notecard_platform.h index 63b1f35..3b5afb1 100644 --- a/src/notecard_platform.h +++ b/src/notecard_platform.h @@ -40,6 +40,13 @@ void notecard_platform_delay(uint32_t ms); void *notecard_platform_malloc(size_t size); void notecard_platform_free(void *ptr); +// Mutex registration function +void notecard_platform_register_mutex_hooks(void); + +// Public I2C mutex functions +void notecard_lock_i2c(void); +void notecard_unlock_i2c(void); + #ifdef __cplusplus } #endif From dab0541833bfb8a38db8e503f19792331522d67f Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Mon, 6 Oct 2025 19:32:42 +0100 Subject: [PATCH 02/15] fix: handle UART cleanup --- src/notecard_platform.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/notecard_platform.c b/src/notecard_platform.c index 10e8b49..0aa00ee 100644 --- a/src/notecard_platform.c +++ b/src/notecard_platform.c @@ -384,18 +384,10 @@ esp_err_t notecard_platform_uart_deinit(void) g_uart_initialized = false; - // Clean up mutexes (only if I2C is not also using them) - if (!g_i2c_initialized) { -#ifdef CONFIG_NOTECARD_I2C_MUTEX - if (g_i2c_mutex != NULL) { - vSemaphoreDelete(g_i2c_mutex); - g_i2c_mutex = NULL; - } -#endif - if (g_notecard_mutex != NULL) { - vSemaphoreDelete(g_notecard_mutex); - g_notecard_mutex = NULL; - } + // Clean up mutexes + if (!g_i2c_initialized && g_notecard_mutex != NULL) { + vSemaphoreDelete(g_notecard_mutex); + g_notecard_mutex = NULL; } ESP_LOGI(TAG, "UART deinitialized"); From fd2dac50c6012370f9bb7f9d942d65039ce69a1d Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Mon, 6 Oct 2025 19:34:18 +0100 Subject: [PATCH 03/15] doc: note I2C mutex is enabled by default --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4b16f7b..3c0e3e9 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,8 @@ In order to enable/disable the provided I2C bus mutex, for example to use your o Component config ---> Notecard Configuration ---> Default I2C Configuration ---> [ ] Enable I2C mutex ``` +> Note: The I2C mutex is enabled by default. + ## Examples For examples, see the [examples](examples) directory. From a0535c48def63af1c566de2ef6ae2ac2a50df185 Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Mon, 6 Oct 2025 22:08:01 +0100 Subject: [PATCH 04/15] fix: address PR feedback --- include/notecard.h | 2 ++ src/notecard_platform.c | 34 +++++++++++++--------------------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/include/notecard.h b/include/notecard.h index 4a874b2..dddb145 100644 --- a/include/notecard.h +++ b/include/notecard.h @@ -159,6 +159,7 @@ bool notecard_is_initialized(void); */ void notecard_set_logging(bool enable); +#ifdef CONFIG_NOTECARD_I2C_MUTEX /** * @brief Lock the I2C bus mutex * @@ -185,6 +186,7 @@ void notecard_lock_i2c(void); * @note Only available if CONFIG_NOTECARD_I2C_MUTEX is enabled in Kconfig */ void notecard_unlock_i2c(void); +#endif #ifdef __cplusplus } diff --git a/src/notecard_platform.c b/src/notecard_platform.c index 0aa00ee..db1407c 100644 --- a/src/notecard_platform.c +++ b/src/notecard_platform.c @@ -37,7 +37,7 @@ static SemaphoreHandle_t g_notecard_mutex = NULL; static void notecard_platform_lock_i2c(void) { if (g_i2c_mutex != NULL) { - xSemaphoreTake(g_i2c_mutex, portMAX_DELAY); + for (;xSemaphoreTake(g_i2c_mutex, portMAX_DELAY) != pdTRUE;); } } @@ -52,7 +52,7 @@ static void notecard_platform_unlock_i2c(void) static void notecard_platform_lock_note(void) { if (g_notecard_mutex != NULL) { - xSemaphoreTake(g_notecard_mutex, portMAX_DELAY); + for (;xSemaphoreTake(g_notecard_mutex, portMAX_DELAY) != pdTRUE;); } } @@ -384,8 +384,8 @@ esp_err_t notecard_platform_uart_deinit(void) g_uart_initialized = false; - // Clean up mutexes - if (!g_i2c_initialized && g_notecard_mutex != NULL) { + // Clean up Notecard mutex + if (g_notecard_mutex != NULL) { vSemaphoreDelete(g_notecard_mutex); g_notecard_mutex = NULL; } @@ -503,37 +503,29 @@ void notecard_platform_free(void *ptr) void notecard_platform_register_mutex_hooks(void) { // Register mutex hooks with note-c based on Kconfig settings -#ifdef CONFIG_NOTECARD_I2C_MUTEX - // Both I2C and Notecard mutexes enabled - NoteSetFnMutex(notecard_platform_lock_i2c, - notecard_platform_unlock_i2c, - notecard_platform_lock_note, - notecard_platform_unlock_note); -#else - // Only Notecard mutex enabled (I2C mutex is optional) + // Enable Notecard mutexes (I2C mutex is optional) NoteSetFnNoteMutex(notecard_platform_lock_note, notecard_platform_unlock_note); + +#ifdef CONFIG_NOTECARD_I2C_MUTEX + // Enable I2C mutexes + NoteSetFnI2CMutex(notecard_platform_lock_i2c, + notecard_platform_unlock_i2c); #endif } //============================================================================= -// Public I2C Mutex API for Application Use +// Public I2C Mutex API //============================================================================= +#ifdef CONFIG_NOTECARD_I2C_MUTEX void notecard_lock_i2c(void) { -#ifdef CONFIG_NOTECARD_I2C_MUTEX notecard_platform_lock_i2c(); -#else - ESP_LOGW(TAG, "I2C mutex not enabled in Kconfig"); -#endif } void notecard_unlock_i2c(void) { -#ifdef CONFIG_NOTECARD_I2C_MUTEX notecard_platform_unlock_i2c(); -#else - ESP_LOGW(TAG, "I2C mutex not enabled in Kconfig"); -#endif } +#endif From 94a69bad57154a06625d175e45ad4a73643b4857 Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Mon, 6 Oct 2025 22:14:40 +0100 Subject: [PATCH 05/15] fix: added public interface behind flag --- src/notecard_platform.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/notecard_platform.h b/src/notecard_platform.h index 3b5afb1..df87cbc 100644 --- a/src/notecard_platform.h +++ b/src/notecard_platform.h @@ -43,9 +43,11 @@ void notecard_platform_free(void *ptr); // Mutex registration function void notecard_platform_register_mutex_hooks(void); +#ifdef CONFIG_NOTECARD_I2C_MUTEX // Public I2C mutex functions void notecard_lock_i2c(void); void notecard_unlock_i2c(void); +#endif #ifdef __cplusplus } From b2847f46fb873c6be9e1f8744a4821a6800d03cf Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Wed, 8 Oct 2025 15:38:22 +0100 Subject: [PATCH 06/15] Update README.md Co-authored-by: Zachary J. Fields --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c0e3e9..c6dc636 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,9 @@ The underlying [note-c](https://github.com/blues/note-c) library protects the No ### I2C Bus Sharing -If you have other I2C peripherals on the same bus as the Notecard, use the I2C mutex API to coordinate access: +If you have other I2C peripherals on the same bus as the Notecard, register your I2C mutex with `note-c` using `NoteSetFnI2CMutex()` to minimize the time spent under lock. + + For your convenience, we have provided a default implementation of I2C mutex APIs to coordinate access (example shown below): ```c #include "notecard.h" From 314b5c93fd2f001fd768f5a2056db04a533a1207 Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Wed, 8 Oct 2025 15:38:32 +0100 Subject: [PATCH 07/15] Update README.md Co-authored-by: Zachary J. Fields --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c6dc636..dcbd367 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ notecard_unlock_i2c(); This ensures the `note-c` won't attempt I2C communication while you're accessing your other peripherals. -In order to enable/disable the provided I2C bus mutex, for example to use your own mutex, use `menuconfig`: +In order to enable/disable the provided I2C bus mutex (e.g. when using your own mutex), use `menuconfig`: ``` Component config ---> Notecard Configuration ---> Default I2C Configuration ---> [ ] Enable I2C mutex From 4a9b51608ca7fc44c62d1ab30c0ba62669d0dcfe Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Wed, 8 Oct 2025 15:44:53 +0100 Subject: [PATCH 08/15] Update src/notecard_platform.c Co-authored-by: Zachary J. Fields --- src/notecard_platform.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/notecard_platform.c b/src/notecard_platform.c index db1407c..93dc54c 100644 --- a/src/notecard_platform.c +++ b/src/notecard_platform.c @@ -122,10 +122,8 @@ esp_err_t notecard_platform_i2c_init(const notecard_i2c_config_t *config) if (ret != ESP_OK) { ESP_LOGE(TAG, "I2C master bus creation failed: %s", esp_err_to_name(ret)); #ifdef CONFIG_NOTECARD_I2C_MUTEX - if (g_i2c_mutex != NULL) { - vSemaphoreDelete(g_i2c_mutex); - g_i2c_mutex = NULL; - } + vSemaphoreDelete(g_i2c_mutex); + g_i2c_mutex = NULL; #endif if (g_notecard_mutex != NULL) { vSemaphoreDelete(g_notecard_mutex); From dca72e6cbaed198f8f199de399cc051217e6f550 Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Wed, 8 Oct 2025 15:45:04 +0100 Subject: [PATCH 09/15] Update src/notecard_platform.c Co-authored-by: Zachary J. Fields --- src/notecard_platform.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/notecard_platform.c b/src/notecard_platform.c index 93dc54c..152a7f8 100644 --- a/src/notecard_platform.c +++ b/src/notecard_platform.c @@ -125,10 +125,8 @@ esp_err_t notecard_platform_i2c_init(const notecard_i2c_config_t *config) vSemaphoreDelete(g_i2c_mutex); g_i2c_mutex = NULL; #endif - if (g_notecard_mutex != NULL) { - vSemaphoreDelete(g_notecard_mutex); - g_notecard_mutex = NULL; - } + vSemaphoreDelete(g_notecard_mutex); + g_notecard_mutex = NULL; return ret; } From aa5650c8ed5f6ceb02ed8ee885d9f0fe2b04e4b0 Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Wed, 8 Oct 2025 15:45:14 +0100 Subject: [PATCH 10/15] Update src/notecard_platform.c Co-authored-by: Zachary J. Fields --- src/notecard_platform.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/notecard_platform.c b/src/notecard_platform.c index 152a7f8..6e0bf54 100644 --- a/src/notecard_platform.c +++ b/src/notecard_platform.c @@ -352,10 +352,8 @@ esp_err_t notecard_platform_uart_init(const notecard_uart_config_t *config) config->tx_buffer_size, 0, NULL, 0); if (ret != ESP_OK) { ESP_LOGE(TAG, "UART driver install failed: %s", esp_err_to_name(ret)); - if (g_notecard_mutex != NULL) { - vSemaphoreDelete(g_notecard_mutex); - g_notecard_mutex = NULL; - } + vSemaphoreDelete(g_notecard_mutex); + g_notecard_mutex = NULL; return ret; } From 7e9e37417b57f0558c301dac1bbd5414483f581f Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Wed, 8 Oct 2025 15:50:43 +0100 Subject: [PATCH 11/15] fix: PR feedback --- README.md | 4 ++-- include/notecard.h | 12 ++++++------ src/notecard_platform.c | 4 ++-- src/notecard_platform.h | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index dcbd367..faf962e 100644 --- a/README.md +++ b/README.md @@ -60,9 +60,9 @@ If you have other I2C peripherals on the same bus as the Notecard, register your #include "notecard.h" // Access your I2C peripherals -notecard_lock_i2c(); +notecard_i2c_lock(); i2c_master_transmit(my_peripheral_handle, data, len, timeout); -notecard_unlock_i2c(); +notecard_i2c_unlock(); ``` This ensures the `note-c` won't attempt I2C communication while you're accessing your other peripherals. diff --git a/include/notecard.h b/include/notecard.h index dddb145..83d20ba 100644 --- a/include/notecard.h +++ b/include/notecard.h @@ -164,28 +164,28 @@ void notecard_set_logging(bool enable); * @brief Lock the I2C bus mutex * * Use this when accessing other I2C peripherals on the same bus to prevent - * conflicts with Notecard I2C operations. Always pair with notecard_unlock_i2c(). + * conflicts with Notecard I2C operations. Always pair with notecard_i2c_unlock(). * * @note Only available if CONFIG_NOTECARD_I2C_MUTEX is enabled in Kconfig * * Example: * @code - * notecard_lock_i2c(); + * notecard_i2c_lock(); * // Access your I2C sensor here * i2c_master_transmit(my_sensor_handle, data, len, timeout); - * notecard_unlock_i2c(); + * notecard_i2c_unlock(); * @endcode */ -void notecard_lock_i2c(void); +void notecard_i2c_lock(void); /** * @brief Unlock the I2C bus mutex * - * Must be called after notecard_lock_i2c() to release the I2C bus. + * Must be called after notecard_i2c_lock() to release the I2C bus. * * @note Only available if CONFIG_NOTECARD_I2C_MUTEX is enabled in Kconfig */ -void notecard_unlock_i2c(void); +void notecard_i2c_unlock(void); #endif #ifdef __cplusplus diff --git a/src/notecard_platform.c b/src/notecard_platform.c index 6e0bf54..b0b3c64 100644 --- a/src/notecard_platform.c +++ b/src/notecard_platform.c @@ -513,12 +513,12 @@ void notecard_platform_register_mutex_hooks(void) //============================================================================= #ifdef CONFIG_NOTECARD_I2C_MUTEX -void notecard_lock_i2c(void) +void notecard_i2c_lock(void) { notecard_platform_lock_i2c(); } -void notecard_unlock_i2c(void) +void notecard_i2c_unlock(void) { notecard_platform_unlock_i2c(); } diff --git a/src/notecard_platform.h b/src/notecard_platform.h index df87cbc..355fb83 100644 --- a/src/notecard_platform.h +++ b/src/notecard_platform.h @@ -45,8 +45,8 @@ void notecard_platform_register_mutex_hooks(void); #ifdef CONFIG_NOTECARD_I2C_MUTEX // Public I2C mutex functions -void notecard_lock_i2c(void); -void notecard_unlock_i2c(void); +void notecard_i2c_lock(void); +void notecard_i2c_unlock(void); #endif #ifdef __cplusplus From 75c30e6d32924d298cef95dc80e411e0b328dd08 Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Wed, 8 Oct 2025 16:13:46 +0100 Subject: [PATCH 12/15] Update src/notecard_platform.c Co-authored-by: Zachary J. Fields --- src/notecard_platform.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/notecard_platform.c b/src/notecard_platform.c index b0b3c64..1364f88 100644 --- a/src/notecard_platform.c +++ b/src/notecard_platform.c @@ -79,30 +79,26 @@ esp_err_t notecard_platform_i2c_init(const notecard_i2c_config_t *config) } // Create mutexes + if (g_notecard_mutex == NULL) { + g_notecard_mutex = xSemaphoreCreateMutex(); + if (g_notecard_mutex == NULL) { + ESP_LOGE(TAG, "Failed to create Notecard mutex"); + return ESP_ERR_NO_MEM; + } + } + #ifdef CONFIG_NOTECARD_I2C_MUTEX if (g_i2c_mutex == NULL) { g_i2c_mutex = xSemaphoreCreateMutex(); if (g_i2c_mutex == NULL) { ESP_LOGE(TAG, "Failed to create I2C mutex"); + vSemaphoreDelete(g_notecard_mutex); + g_notecard_mutex = NULL; return ESP_ERR_NO_MEM; } } #endif - if (g_notecard_mutex == NULL) { - g_notecard_mutex = xSemaphoreCreateMutex(); - if (g_notecard_mutex == NULL) { - ESP_LOGE(TAG, "Failed to create Notecard mutex"); -#ifdef CONFIG_NOTECARD_I2C_MUTEX - if (g_i2c_mutex != NULL) { - vSemaphoreDelete(g_i2c_mutex); - g_i2c_mutex = NULL; - } -#endif - return ESP_ERR_NO_MEM; - } - } - // Store configuration memcpy(&g_i2c_config, config, sizeof(notecard_i2c_config_t)); From b4cdafea61dd3bc94894f608061180e5a66d56be Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Wed, 8 Oct 2025 16:16:31 +0100 Subject: [PATCH 13/15] fix: packaging issue --- .github/workflows/validate-component.yml | 4 ++-- examples/basic_usage_i2c/dependencies.lock | 2 +- idf_component.yml | 18 +++++++++++++----- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.github/workflows/validate-component.yml b/.github/workflows/validate-component.yml index c705637..77ca7b7 100644 --- a/.github/workflows/validate-component.yml +++ b/.github/workflows/validate-component.yml @@ -16,10 +16,10 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: '3.x' + python-version: '3.11' - name: Install IDF Component Manager - run: pip install idf-component-manager + run: pip install 'idf-component-manager==1.5.2' - name: Validate and Pack Component run: compote component pack --name Notecard diff --git a/examples/basic_usage_i2c/dependencies.lock b/examples/basic_usage_i2c/dependencies.lock index a28416f..5e9340d 100644 --- a/examples/basic_usage_i2c/dependencies.lock +++ b/examples/basic_usage_i2c/dependencies.lock @@ -5,6 +5,6 @@ dependencies: version: 5.5.1 direct_dependencies: - idf -manifest_hash: 76ace180aa99c6f25d2173274f65375f15b1c8465779efd9e729e9b2f8d8c311 +manifest_hash: cbc3626899740395aaaf5addbe70903d6950040e23cbea45719d4e50ea14d749 target: esp32 version: 2.0.0 diff --git a/idf_component.yml b/idf_component.yml index d57973e..32e0834 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -29,8 +29,16 @@ maintainers: - "Support " files: - use_gitignore: true - -examples: - - path: examples/basic_usage_i2c - - path: examples/basic_usage_uart + exclude: + - "build/**/*" + - "dist/**/*" + - ".vscode/**/*" + - ".idea/**/*" + - "*.swp" + - "*.swo" + - ".DS_Store" + - "Thumbs.db" + - "sdkconfig" + - "sdkconfig.old" + - "CMakeCache.txt" + - "CMakeFiles/**/*" From 6517519a7c0dd644e9893f3824359f6fb027caa4 Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Wed, 8 Oct 2025 16:49:01 +0100 Subject: [PATCH 14/15] Update README.md Co-authored-by: Zachary J. Fields --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index faf962e..394baeb 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ The underlying [note-c](https://github.com/blues/note-c) library protects the No If you have other I2C peripherals on the same bus as the Notecard, register your I2C mutex with `note-c` using `NoteSetFnI2CMutex()` to minimize the time spent under lock. - For your convenience, we have provided a default implementation of I2C mutex APIs to coordinate access (example shown below): +For your convenience, we have provided a default implementation of I2C mutex APIs to coordinate access (example shown below): ```c #include "notecard.h" From 6e674a2e3ec643234d8d7b0e4dcfd0349aa742cf Mon Sep 17 00:00:00 2001 From: Alex Bucknall Date: Wed, 8 Oct 2025 16:53:39 +0100 Subject: [PATCH 15/15] chore: rename --- examples/basic_usage_uart/dependencies.lock | 2 +- src/notecard_platform.c | 22 ++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/basic_usage_uart/dependencies.lock b/examples/basic_usage_uart/dependencies.lock index d2df1b0..5e9340d 100644 --- a/examples/basic_usage_uart/dependencies.lock +++ b/examples/basic_usage_uart/dependencies.lock @@ -5,6 +5,6 @@ dependencies: version: 5.5.1 direct_dependencies: - idf -manifest_hash: 08ac1ee392ce13ac722569147b417c0484712da30ecb148c8d70f9d19fd69d84 +manifest_hash: cbc3626899740395aaaf5addbe70903d6950040e23cbea45719d4e50ea14d749 target: esp32 version: 2.0.0 diff --git a/src/notecard_platform.c b/src/notecard_platform.c index 1364f88..d10723a 100644 --- a/src/notecard_platform.c +++ b/src/notecard_platform.c @@ -34,14 +34,14 @@ static SemaphoreHandle_t g_notecard_mutex = NULL; //============================================================================= #ifdef CONFIG_NOTECARD_I2C_MUTEX -static void notecard_platform_lock_i2c(void) +static void notecard_platform_i2c_lock(void) { if (g_i2c_mutex != NULL) { for (;xSemaphoreTake(g_i2c_mutex, portMAX_DELAY) != pdTRUE;); } } -static void notecard_platform_unlock_i2c(void) +static void notecard_platform_i2c_unlock(void) { if (g_i2c_mutex != NULL) { xSemaphoreGive(g_i2c_mutex); @@ -49,14 +49,14 @@ static void notecard_platform_unlock_i2c(void) } #endif -static void notecard_platform_lock_note(void) +static void notecard_platform_note_lock(void) { if (g_notecard_mutex != NULL) { for (;xSemaphoreTake(g_notecard_mutex, portMAX_DELAY) != pdTRUE;); } } -static void notecard_platform_unlock_note(void) +static void notecard_platform_note_unlock(void) { if (g_notecard_mutex != NULL) { xSemaphoreGive(g_notecard_mutex); @@ -86,7 +86,7 @@ esp_err_t notecard_platform_i2c_init(const notecard_i2c_config_t *config) return ESP_ERR_NO_MEM; } } - + #ifdef CONFIG_NOTECARD_I2C_MUTEX if (g_i2c_mutex == NULL) { g_i2c_mutex = xSemaphoreCreateMutex(); @@ -494,13 +494,13 @@ void notecard_platform_register_mutex_hooks(void) { // Register mutex hooks with note-c based on Kconfig settings // Enable Notecard mutexes (I2C mutex is optional) - NoteSetFnNoteMutex(notecard_platform_lock_note, - notecard_platform_unlock_note); + NoteSetFnNoteMutex(notecard_platform_note_lock, + notecard_platform_note_unlock); #ifdef CONFIG_NOTECARD_I2C_MUTEX // Enable I2C mutexes - NoteSetFnI2CMutex(notecard_platform_lock_i2c, - notecard_platform_unlock_i2c); + NoteSetFnI2CMutex(notecard_platform_i2c_lock, + notecard_platform_i2c_unlock); #endif } @@ -511,11 +511,11 @@ void notecard_platform_register_mutex_hooks(void) #ifdef CONFIG_NOTECARD_I2C_MUTEX void notecard_i2c_lock(void) { - notecard_platform_lock_i2c(); + notecard_platform_i2c_lock(); } void notecard_i2c_unlock(void) { - notecard_platform_unlock_i2c(); + notecard_platform_i2c_unlock(); } #endif