diff --git a/components/persistence/CMakeLists.txt b/components/persistence/CMakeLists.txt new file mode 100644 index 0000000..9130681 --- /dev/null +++ b/components/persistence/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register(SRCS "persistence.c" + INCLUDE_DIRS "include" + PRIV_REQUIRES + nvs_flash +) diff --git a/components/persistence/include/persistence.h b/components/persistence/include/persistence.h new file mode 100644 index 0000000..ed5ad6d --- /dev/null +++ b/components/persistence/include/persistence.h @@ -0,0 +1,12 @@ +#pragma once + +typedef enum +{ + VALUE_TYPE_STRING, + VALUE_TYPE_INT32, +} persistence_value_type_t; + +void persistence_init(const char *namespace_name); +void persistence_save(persistence_value_type_t value_type, const char *key, const void *value); +void *persistence_load(persistence_value_type_t value_type, const char *key, void *out); +void persistence_deinit(); diff --git a/components/persistence/persistence.c b/components/persistence/persistence.c new file mode 100644 index 0000000..f7a62f9 --- /dev/null +++ b/components/persistence/persistence.c @@ -0,0 +1,114 @@ +#include "persistence.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_mac.h" +#include "nvs_flash.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +static const char *TAG = "persistence"; + +static nvs_handle_t persistence_handle; +static SemaphoreHandle_t persistence_mutex; + +void persistence_init(const char *namespace_name) +{ + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + ESP_ERROR_CHECK(nvs_open(namespace_name, NVS_READWRITE, &persistence_handle)); + + persistence_mutex = xSemaphoreCreateMutex(); + if (persistence_mutex == NULL) + { + ESP_LOGE(TAG, "Failed to create mutex"); + } +} + +void persistence_save(persistence_value_type_t value_type, const char *key, const void *value) +{ + if (persistence_mutex != NULL) + { + if (xSemaphoreTake(persistence_mutex, portMAX_DELAY) == pdTRUE) + { + esp_err_t err = ESP_ERR_INVALID_ARG; + + switch (value_type) + { + case VALUE_TYPE_STRING: + err = nvs_set_str(persistence_handle, key, (char *)value); + break; + + case VALUE_TYPE_INT32: + err = nvs_set_i32(persistence_handle, key, *(int32_t *)value); + break; + + default: + ESP_LOGE(TAG, "Unsupported value type"); + break; + } + + if (err == ESP_OK) + { + ESP_ERROR_CHECK(nvs_commit(persistence_handle)); + } + else + { + ESP_LOGE(TAG, "Error saving key %s: %s", key, esp_err_to_name(err)); + } + + xSemaphoreGive(persistence_mutex); + } + } +} + +void *persistence_load(persistence_value_type_t value_type, const char *key, void *out) +{ + if (persistence_mutex != NULL) + { + if (xSemaphoreTake(persistence_mutex, portMAX_DELAY) == pdTRUE) + { + esp_err_t err = ESP_ERR_INVALID_ARG; + + switch (value_type) + { + case VALUE_TYPE_STRING: + err = nvs_get_str(persistence_handle, key, (char *)out, NULL); + break; + + case VALUE_TYPE_INT32: + err = nvs_get_i32(persistence_handle, key, (int32_t *)out); + break; + + default: + ESP_LOGE(TAG, "Unsupported value type"); + break; + } + + if (err != ESP_OK) + { + ESP_LOGE(TAG, "Error loading key %s: %s", key, esp_err_to_name(err)); + } + + xSemaphoreGive(persistence_mutex); + } + } + + return out; +} + +void persistence_deinit() +{ + if (persistence_mutex != NULL) + { + vSemaphoreDelete(persistence_mutex); + persistence_mutex = NULL; + } + + nvs_close(persistence_handle); +} diff --git a/components/remote_control/CMakeLists.txt b/components/remote_control/CMakeLists.txt index 63ddfcc..919018a 100644 --- a/components/remote_control/CMakeLists.txt +++ b/components/remote_control/CMakeLists.txt @@ -1,4 +1,4 @@ -idf_component_register(SRCS "remote_control.c" +idf_component_register(SRCS "led_service.c" "device_service.c" "remote_control.c" INCLUDE_DIRS "include" PRIV_REQUIRES bt diff --git a/components/remote_control/device_service.c b/components/remote_control/device_service.c new file mode 100644 index 0000000..654634c --- /dev/null +++ b/components/remote_control/device_service.c @@ -0,0 +1,15 @@ +#include "include/device_service.h" + +int ds_model_number_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + char *model_number = "Miniature Town v1"; + os_mbuf_append(ctxt->om, model_number, strlen(model_number)); + return 0; +} + +int ds_manufacturer_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + char *manufacturer = "mars3142"; + os_mbuf_append(ctxt->om, manufacturer, strlen(manufacturer)); + return 0; +} diff --git a/components/remote_control/include/device_service.h b/components/remote_control/include/device_service.h new file mode 100644 index 0000000..e51c0f6 --- /dev/null +++ b/components/remote_control/include/device_service.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include "host/ble_hs.h" + +int ds_model_number_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); +int ds_manufacturer_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); diff --git a/components/remote_control/include/led_service.h b/components/remote_control/include/led_service.h new file mode 100644 index 0000000..1332ba0 --- /dev/null +++ b/components/remote_control/include/led_service.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include "host/ble_hs.h" + +int ls_write(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); +int ls_read(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); diff --git a/components/remote_control/led_service.c b/components/remote_control/led_service.c new file mode 100644 index 0000000..19d0f46 --- /dev/null +++ b/components/remote_control/led_service.c @@ -0,0 +1,59 @@ +#include "include/led_service.h" + +static const char *TAG = "led_service"; + +// Write data to ESP32 defined as server +int ls_write(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + const char *received_payload = (const char *)ctxt->om->om_data; + uint16_t payload_len = ctxt->om->om_len; + + // Define command strings + const char CMD_LIGHT_ON[] = "LIGHT ON"; + const char CMD_LIGHT_OFF[] = "LIGHT OFF"; + const char CMD_FAN_ON[] = "FAN ON"; + const char CMD_FAN_OFF[] = "FAN OFF"; + + if (payload_len == (sizeof(CMD_LIGHT_ON) - 1) && + strncmp(received_payload, CMD_LIGHT_ON, payload_len) == 0) + { + ESP_LOGI(TAG, "LIGHT ON"); + // TODO: Implement action for LIGHT ON + } + else if (payload_len == (sizeof(CMD_LIGHT_OFF) - 1) && + strncmp(received_payload, CMD_LIGHT_OFF, payload_len) == 0) + { + ESP_LOGI(TAG, "LIGHT OFF"); + // TODO: Implement action for LIGHT OFF + } + else if (payload_len == (sizeof(CMD_FAN_ON) - 1) && + strncmp(received_payload, CMD_FAN_ON, payload_len) == 0) + { + ESP_LOGI(TAG, "FAN ON"); + // TODO: Implement action for FAN ON + } + else if (payload_len == (sizeof(CMD_FAN_OFF) - 1) && + strncmp(received_payload, CMD_FAN_OFF, payload_len) == 0) + { + ESP_LOGI(TAG, "FAN OFF"); + // TODO: Implement action for FAN OFF + } + else + { + char temp_buffer[payload_len + 1]; + memcpy(temp_buffer, received_payload, payload_len); + temp_buffer[payload_len] = '\0'; + + ESP_LOGI(TAG, "Unknown command from client: %s", temp_buffer); + } + + return 0; +} + +// Read data from ESP32 defined as server +int ls_read(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + char *data = "Data from the server"; + os_mbuf_append(ctxt->om, data, strlen(data)); + return 0; +} diff --git a/components/remote_control/remote_control.c b/components/remote_control/remote_control.c index 035a650..159e009 100644 --- a/components/remote_control/remote_control.c +++ b/components/remote_control/remote_control.c @@ -14,93 +14,27 @@ #include "services/gatt/ble_svc_gatt.h" #include "sdkconfig.h" +#include "include/device_service.h" +#include "include/led_service.h" + static const char *TAG = "remote_control"; -static const char *DEVICE_NAME = "Miniature Town"; uint8_t ble_addr_type; void ble_app_advertise(void); -// Write data to ESP32 defined as server -static int device_write(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - const char *received_payload = (const char *)ctxt->om->om_data; - uint16_t payload_len = ctxt->om->om_len; - - // Define command strings - const char CMD_LIGHT_ON[] = "LIGHT ON"; - const char CMD_LIGHT_OFF[] = "LIGHT OFF"; - const char CMD_FAN_ON[] = "FAN ON"; - const char CMD_FAN_OFF[] = "FAN OFF"; - - if (payload_len == (sizeof(CMD_LIGHT_ON) - 1) && - strncmp(received_payload, CMD_LIGHT_ON, payload_len) == 0) - { - ESP_LOGI(TAG, "LIGHT ON"); - // TODO: Implement action for LIGHT ON - } - else if (payload_len == (sizeof(CMD_LIGHT_OFF) - 1) && - strncmp(received_payload, CMD_LIGHT_OFF, payload_len) == 0) - { - ESP_LOGI(TAG, "LIGHT OFF"); - // TODO: Implement action for LIGHT OFF - } - else if (payload_len == (sizeof(CMD_FAN_ON) - 1) && - strncmp(received_payload, CMD_FAN_ON, payload_len) == 0) - { - ESP_LOGI(TAG, "FAN ON"); - // TODO: Implement action for FAN ON - } - else if (payload_len == (sizeof(CMD_FAN_OFF) - 1) && - strncmp(received_payload, CMD_FAN_OFF, payload_len) == 0) - { - ESP_LOGI(TAG, "FAN OFF"); - // TODO: Implement action for FAN OFF - } - else - { - char temp_buffer[payload_len + 1]; - memcpy(temp_buffer, received_payload, payload_len); - temp_buffer[payload_len] = '\0'; - - ESP_LOGI(TAG, "Unknown command from client: %s", temp_buffer); - } - - return 0; -} - -// Read data from ESP32 defined as server -static int device_read(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - char *data = "Data from the server"; - os_mbuf_append(ctxt->om, data, strlen(data)); - return 0; -} - -static int model_number_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - char *model_number = "Miniature Town v1"; - os_mbuf_append(ctxt->om, model_number, strlen(model_number)); - return 0; -} -static int manufacturer_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - char *manufacturer = "mars3142"; - os_mbuf_append(ctxt->om, manufacturer, strlen(manufacturer)); - return 0; -} - // Array of pointers to other service definitions static const struct ble_gatt_svc_def gatt_svcs[] = { { .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = BLE_UUID16_DECLARE(0x180A), - .characteristics = (struct ble_gatt_chr_def[]){ - {.uuid = BLE_UUID16_DECLARE(0x2A24), .flags = BLE_GATT_CHR_F_READ, .access_cb = model_number_read}, - {.uuid = BLE_UUID16_DECLARE(0x2A29), .flags = BLE_GATT_CHR_F_READ, .access_cb = manufacturer_read}, - {0}}, + .characteristics = (struct ble_gatt_chr_def[]){{.uuid = BLE_UUID16_DECLARE(0x2A24), .flags = BLE_GATT_CHR_F_READ, .access_cb = ds_model_number_read}, {.uuid = BLE_UUID16_DECLARE(0x2A29), .flags = BLE_GATT_CHR_F_READ, .access_cb = ds_manufacturer_read}, {0}}, + }, + { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(0x180), + .characteristics = (struct ble_gatt_chr_def[]){{.uuid = BLE_UUID16_DECLARE(0xFEF4), .flags = BLE_GATT_CHR_F_READ, .access_cb = ls_read}, {.uuid = BLE_UUID16_DECLARE(0xDEAD), .flags = BLE_GATT_CHR_F_WRITE, .access_cb = ls_write}, {0}}, }, - {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = BLE_UUID16_DECLARE(0x180), .characteristics = (struct ble_gatt_chr_def[]){{.uuid = BLE_UUID16_DECLARE(0xFEF4), .flags = BLE_GATT_CHR_F_READ, .access_cb = device_read}, {.uuid = BLE_UUID16_DECLARE(0xDEAD), .flags = BLE_GATT_CHR_F_WRITE, .access_cb = device_write}, {0}}}, {0}}; // BLE event handling @@ -188,18 +122,18 @@ void host_task(void *param) void ble_init(void *args) { - nimble_port_init(); // 3 - Initialize the host stack - ble_svc_gap_device_name_set(DEVICE_NAME); // 4 - Initialize NimBLE configuration - server name - ble_svc_gap_init(); // 4 - Initialize NimBLE configuration - gap service - ble_svc_gatt_init(); // 4 - Initialize NimBLE configuration - gatt service - ble_gatts_count_cfg(gatt_svcs); // 4 - Initialize NimBLE configuration - config gatt services - ble_gatts_add_svcs(gatt_svcs); // 4 - Initialize NimBLE configuration - queues gatt services. - ble_hs_cfg.sync_cb = ble_app_on_sync; // 5 - Initialize application + nimble_port_init(); + ble_svc_gap_device_name_set("Miniature Town"); + ble_svc_gap_init(); + ble_svc_gatt_init(); + ble_gatts_count_cfg(gatt_svcs); + ble_gatts_add_svcs(gatt_svcs); + ble_hs_cfg.sync_cb = ble_app_on_sync; // Configure security settings - ble_hs_cfg.sm_bonding = 1; // Enable bonding - ble_hs_cfg.sm_sc = 0; // Enable Secure Connections (LE SC) - ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC; // Encryption key distribution + ble_hs_cfg.sm_bonding = 1; + ble_hs_cfg.sm_sc = 0; + ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC; ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ENC; nimble_port_freertos_init(host_task); // Run the host task diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index dbe91be..0169978 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -3,5 +3,5 @@ idf_component_register(SRCS "main.c" PRIV_REQUIRES led_matrix remote_control - nvs_flash + persistence ) diff --git a/main/main.c b/main/main.c index 3d3c53d..781d936 100644 --- a/main/main.c +++ b/main/main.c @@ -1,20 +1,13 @@ #include "led_matrix.h" +#include "persistence.h" #include "remote_control.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "nvs_flash.h" void app_main(void) { - // Initialize NVS - esp_err_t ret = nvs_flash_init(); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) - { - ESP_ERROR_CHECK(nvs_flash_erase()); - ret = nvs_flash_init(); - } - ESP_ERROR_CHECK(ret); + persistence_init("miniature_town"); xTaskCreatePinnedToCore(led_matrix_init, "led_matrix", configMINIMAL_STACK_SIZE * 2, NULL, 5, NULL, 1); ble_init(NULL);