diff --git a/firmware/.devcontainer/Dockerfile b/firmware/.devcontainer/Dockerfile new file mode 100644 index 0000000..dafb8ad --- /dev/null +++ b/firmware/.devcontainer/Dockerfile @@ -0,0 +1,13 @@ +ARG DOCKER_TAG=latest +FROM espressif/idf:${DOCKER_TAG} + +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + +RUN apt-get update -y && apt-get install udev -y + +RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc + +ENTRYPOINT [ "/opt/esp/entrypoint.sh" ] + +CMD ["/bin/bash", "-c"] \ No newline at end of file diff --git a/firmware/.devcontainer/devcontainer.json b/firmware/.devcontainer/devcontainer.json new file mode 100644 index 0000000..b801786 --- /dev/null +++ b/firmware/.devcontainer/devcontainer.json @@ -0,0 +1,21 @@ +{ + "name": "ESP-IDF QEMU", + "build": { + "dockerfile": "Dockerfile" + }, + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.defaultProfile.linux": "bash", + "idf.espIdfPath": "/opt/esp/idf", + "idf.toolsPath": "/opt/esp", + "idf.gitPath": "/usr/bin/git" + }, + "extensions": [ + "espressif.esp-idf-extension", + "espressif.esp-idf-web" + ] + } + }, + "runArgs": ["--privileged"] +} \ No newline at end of file diff --git a/firmware/.gitignore b/firmware/.gitignore index 869f975..57b6e01 100644 --- a/firmware/.gitignore +++ b/firmware/.gitignore @@ -1,4 +1,4 @@ -build/** +build*/ managed_components/** sdkconfig sdkconfig.old @@ -6,4 +6,3 @@ sdkconfig.old .espidf.*.json *.svd *.lock -build-release/ diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt index 55d60c8..52bd5b3 100644 --- a/firmware/CMakeLists.txt +++ b/firmware/CMakeLists.txt @@ -3,4 +3,4 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(lighthouses) +project(Lighthouse) diff --git a/firmware/Makefile b/firmware/Makefile index 26d1f9a..c7dee66 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -1,2 +1,13 @@ -release: - idf.py -B build-release -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release" fullclean build +compile: clean + idf.py -B build-release -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release" build size + +deploy: compile + idf.py -B build-release -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.release" flash monitor + +clean: + rm -rf build + rm -rf build-release + rm -rf sdkconfig + rm -rf dependencies.lock + +.PHONY: compile deploy clean diff --git a/firmware/components/persistence/persistence.c b/firmware/components/persistence/persistence.c index d242f25..69ed527 100644 --- a/firmware/components/persistence/persistence.c +++ b/firmware/components/persistence/persistence.c @@ -1,7 +1,6 @@ #include "persistence.h" #include "esp_err.h" #include "esp_log.h" -#include "esp_mac.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "nvs_flash.h" diff --git a/firmware/components/remote_control/CMakeLists.txt b/firmware/components/remote_control/CMakeLists.txt index 698c5a7..69633b1 100644 --- a/firmware/components/remote_control/CMakeLists.txt +++ b/firmware/components/remote_control/CMakeLists.txt @@ -1,11 +1,9 @@ idf_component_register(SRCS - "capability_service.c" "device_service.c" - "led_service.c" + "light_service.c" "remote_control.c" INCLUDE_DIRS "include" PRIV_REQUIRES bt esp_app_format - storage ) diff --git a/firmware/components/remote_control/capability_service.c b/firmware/components/remote_control/capability_service.c deleted file mode 100644 index 9824eb1..0000000 --- a/firmware/components/remote_control/capability_service.c +++ /dev/null @@ -1,156 +0,0 @@ -#include "capability_service.h" -#include "esp_log.h" -#include "storage.h" -#include -#include // For malloc, free -#include "host/ble_hs.h" // For ble_hs_mbuf_from_flat, ble_att_mtu -#include "host/ble_uuid.h" // For BLE_ATT_MTU_DFLT (often included via ble_hs.h) -#include "nimble/nimble_port.h" // For os_mbuf related functions - -static const char *TAG_CS = "capability_service"; - -#define CAPA_READ_CHUNK_SIZE 200 // Maximale Bytes pro Lesevorgang aus dem Storage - -int capa_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - esp_err_t storage_status = storage_init(); - if (storage_status != ESP_OK) - { - ESP_LOGE(TAG_CS, "Failed to initialize storage: %s", esp_err_to_name(storage_status)); - const char *err_msg = "Error: Storage init failed"; - os_mbuf_append(ctxt->om, err_msg, strlen(err_msg)); - // storage_uninit() sollte hier nicht aufgerufen werden, da die Initialisierung fehlschlug. - return 0; - } - - char *content = ""; - os_mbuf_append(ctxt->om, content, strlen(content)); - const char *filename = "/storage/capability.json"; // Die zu lesende Datei - char read_buffer[CAPA_READ_CHUNK_SIZE]; - ssize_t bytes_read; - int os_err; - - ESP_LOGI(TAG_CS, "Reading capabilities from %s", filename); - - // Schleife, um die Datei in Chunks zu lesen und an den mbuf anzuhängen - while ((bytes_read = storage_read(filename, read_buffer, sizeof(read_buffer))) > 0) - { - ESP_LOGD(TAG_CS, "Read %zd bytes from storage", bytes_read); - // Den gelesenen Chunk an den BLE-Antwortpuffer anhängen - os_err = os_mbuf_append(ctxt->om, read_buffer, bytes_read); - if (os_err != 0) - { - ESP_LOGE(TAG_CS, "Failed to append to mbuf (error %d). May be out of space.", os_err); - // Der mbuf könnte voll sein. Stoppe das Anhängen. - // Bereits angehängte Daten werden gesendet. - break; - } - } - - // Fehlerbehandlung oder EOF - if (bytes_read < 0) - { - ESP_LOGE(TAG_CS, "Error reading from storage (file: %s, error_code: %zd)", filename, bytes_read); - // Wenn noch nichts angehängt wurde, sende eine Fehlermeldung. - if (ctxt->om->om_len == 0) - { - const char *err_msg = "Error: Failed to read capability data"; - // Hier könnten spezifischere Fehlermeldungen basierend auf bytes_read eingefügt werden - os_mbuf_append(ctxt->om, err_msg, strlen(err_msg)); - } - } - else - { // bytes_read == 0, bedeutet EOF (Ende der Datei) - ESP_LOGI(TAG_CS, "Successfully read and appended all data from %s to mbuf.", filename); - } - - storage_uninit(); - return 0; -} - -int capa_char_1979_user_desc(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - const char *desc = "Capabilities of the device"; - os_mbuf_append(ctxt->om, desc, strlen(desc)); - return 0; -} - -void capa_notify_data(uint16_t conn_handle, uint16_t char_val_handle) -{ - esp_err_t storage_status = storage_init(); - if (storage_status != ESP_OK) - { - ESP_LOGE(TAG_CS, "Notify: Failed to initialize storage: %s", esp_err_to_name(storage_status)); - return; - } - - const char *filename = "/storage/capability.json"; - - uint16_t mtu = ble_att_mtu(conn_handle); - if (mtu == 0) { // Should not happen for an active connection, fallback - ESP_LOGW(TAG_CS, "Notify: ble_att_mtu returned 0, using default MTU %d.", BLE_ATT_MTU_DFLT); - mtu = BLE_ATT_MTU_DFLT; - } - - // Max payload for notification is MTU - 3 (1 byte opcode for Notification, 2 bytes attribute handle) - size_t notify_chunk_size = (mtu > 3) ? (mtu - 3) : (BLE_ATT_MTU_DFLT - 3); // Ensure mtu > 3 - - // Further cap by CAPA_READ_CHUNK_SIZE if it's smaller and meant as an upper limit for any single read op - if (notify_chunk_size > CAPA_READ_CHUNK_SIZE) { - notify_chunk_size = CAPA_READ_CHUNK_SIZE; - } - - if (notify_chunk_size == 0) { // Safety check - ESP_LOGE(TAG_CS, "Notify: Calculated notify_chunk_size is 0. Aborting."); - storage_uninit(); - return; - } - - char *read_buffer = malloc(notify_chunk_size); - if (!read_buffer) - { - ESP_LOGE(TAG_CS, "Notify: Failed to allocate read_buffer (%zu bytes)", notify_chunk_size); - storage_uninit(); - return; - } - - ESP_LOGI(TAG_CS, "Notify: Reading capabilities from %s to notify conn %u, attr %u (chunk size %zu, MTU %u)", - filename, conn_handle, char_val_handle, notify_chunk_size, mtu); - - FILE *fp = fopen(filename, "r"); - if (!fp) - { - ESP_LOGE(TAG_CS, "Notify: Failed to open %s for reading.", filename); - free(read_buffer); - storage_uninit(); - return; - } - - ssize_t bytes_read; - while ((bytes_read = fread(read_buffer, 1, notify_chunk_size, fp)) > 0) - { - ESP_LOGD(TAG_CS, "Notify: Read %zd bytes from storage for notification", bytes_read); - - struct os_mbuf *om = ble_hs_mbuf_from_flat(read_buffer, bytes_read); - if (!om) { - ESP_LOGE(TAG_CS, "Notify: Failed to allocate mbuf for notification. Stopping."); - break; // Stop sending if mbuf allocation fails - } - - int rc = ble_gatts_notify_custom(conn_handle, char_val_handle, om); - if (rc != 0) { - ESP_LOGE(TAG_CS, "Notify: Error sending notification (rc=%d). Stopping.", rc); - // ble_gatts_notify_custom frees 'om' on success or if it takes ownership even on some errors. - // If it returns an error where 'om' is not freed, we might need os_mbuf_free_chain(om); - // For now, assume NimBLE handles 'om' correctly in error cases like BLE_HS_ENOMEM. - break; // Stop if notification fails - } - ESP_LOGD(TAG_CS, "Notify: Sent %zd bytes successfully.", bytes_read); - } - - if (ferror(fp)) { ESP_LOGE(TAG_CS, "Notify: File read error from %s.", filename); } - fclose(fp); - free(read_buffer); - storage_uninit(); - ESP_LOGI(TAG_CS, "Notify: Finished sending capability data for conn %u.", conn_handle); -} diff --git a/firmware/components/remote_control/device_service.c b/firmware/components/remote_control/device_service.c index 2033d9b..9d60189 100644 --- a/firmware/components/remote_control/device_service.c +++ b/firmware/components/remote_control/device_service.c @@ -3,21 +3,48 @@ #include #include -int device_model_number_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +int device_name_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - char model_number_str[65]; + char firmware_revision_str[33]; const esp_app_desc_t *app_desc = esp_app_get_description(); - if (app_desc->project_name[0] != '\0' && app_desc->version[0] != '\0') + if (app_desc->project_name[0] != '\0') { - snprintf(model_number_str, sizeof(model_number_str), "%s v%s", app_desc->project_name, app_desc->version); + snprintf(firmware_revision_str, sizeof(firmware_revision_str), "%s", app_desc->project_name); } else { - snprintf(model_number_str, sizeof(model_number_str), "undefined"); + snprintf(firmware_revision_str, sizeof(firmware_revision_str), "undefined"); } - os_mbuf_append(ctxt->om, model_number_str, strlen(model_number_str)); + os_mbuf_append(ctxt->om, firmware_revision_str, strlen(firmware_revision_str)); + return 0; +} + +int device_firmware_revision_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + char firmware_revision_str[33]; + const esp_app_desc_t *app_desc = esp_app_get_description(); + + if (app_desc->version[0] != '\0') + { + snprintf(firmware_revision_str, sizeof(firmware_revision_str), "%s", app_desc->version); + } + else + { + snprintf(firmware_revision_str, sizeof(firmware_revision_str), "undefined"); + } + + os_mbuf_append(ctxt->om, firmware_revision_str, strlen(firmware_revision_str)); + return 0; +} + +int device_hardware_revision_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + char *hardware_revision = "rev1"; + os_mbuf_append(ctxt->om, hardware_revision, strlen(hardware_revision)); return 0; } diff --git a/firmware/components/remote_control/include/capability_service.h b/firmware/components/remote_control/include/capability_service.h deleted file mode 100644 index 8841fcc..0000000 --- a/firmware/components/remote_control/include/capability_service.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "host/ble_hs.h" -#include - -/// Service Characteristics Callback -int capa_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); -void capa_notify_data(uint16_t conn_handle, uint16_t char_val_handle); - -/// Service Characteristics User Description -int capa_char_1979_user_desc(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); diff --git a/firmware/components/remote_control/include/device_service.h b/firmware/components/remote_control/include/device_service.h index bcc8229..7c8c994 100644 --- a/firmware/components/remote_control/include/device_service.h +++ b/firmware/components/remote_control/include/device_service.h @@ -3,5 +3,16 @@ #include "host/ble_hs.h" #include -int device_model_number_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); +// 0x2A00 Device Name +int device_name_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); + +// 0x2A26 Firmware Revision String +int device_firmware_revision_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, + void *arg); + +// 0x2A27 Hardware Revision String +int device_hardware_revision_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, + void *arg); + +// 0x2A29 Manufacturer Name String int device_manufacturer_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); diff --git a/firmware/components/remote_control/include/led_service.h b/firmware/components/remote_control/include/light_service.h similarity index 71% rename from firmware/components/remote_control/include/led_service.h rename to firmware/components/remote_control/include/light_service.h index 566c548..f03c3f6 100644 --- a/firmware/components/remote_control/include/led_service.h +++ b/firmware/components/remote_control/include/light_service.h @@ -10,3 +10,5 @@ int led_capabilities_read(uint16_t conn_handle, uint16_t attr_handle, struct ble /// LED Service Characteristic User Description int led_char_a000_user_desc(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); int led_char_dead_user_desc(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); +int led_char_dead_presentation(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); +int led_char_dead_valid_range(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); diff --git a/firmware/components/remote_control/led_service.c b/firmware/components/remote_control/light_service.c similarity index 62% rename from firmware/components/remote_control/led_service.c rename to firmware/components/remote_control/light_service.c index 0c1407d..8efa46e 100644 --- a/firmware/components/remote_control/led_service.c +++ b/firmware/components/remote_control/light_service.c @@ -1,6 +1,6 @@ -#include "include/led_service.h" +#include "include/light_service.h" -static const char *TAG = "led_service"; +static const char *TAG = "light_service"; /// Capabilities of Device int led_capabilities_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) @@ -73,3 +73,39 @@ int led_char_dead_user_desc(uint16_t conn_handle, uint16_t attr_handle, struct b os_mbuf_append(ctxt->om, desc, strlen(desc)); return 0; } + +int led_char_dead_presentation(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + if (ctxt->op != BLE_GATT_ACCESS_OP_READ_DSC) + { + return BLE_ATT_ERR_READ_NOT_PERMITTED; + } + + // GATT Presentation Format (0x2904), 7 Bytes: + // [format, exponent, unit(2), namespace, description(2)] + // format 0x04 = uint8, exponent 0, unit 0x2700 (unitless), namespace 1 (Bluetooth SIG Assigned Numbers), + // description 0 + const uint8_t fmt[7] = { + 0x04, // format = uint8 + 0x00, // exponent + 0x00, 0x27, // unit = org.bluetooth.unit.unitless (0x2700) + 0x01, // namespace = 1 (SIG) + 0x00, 0x00 // description + }; + return os_mbuf_append(ctxt->om, fmt, sizeof(fmt)) == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +int led_char_dead_valid_range(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + if (ctxt->op != BLE_GATT_ACCESS_OP_READ_DSC) + { + return BLE_ATT_ERR_READ_NOT_PERMITTED; + } + + // Valid Range Descriptor (0x2906) Payload: + // - Für numerische Werte: [min .. max] im "nativen" Datentyp der Characteristic. + // Hier: uint8, also 1 Byte min + 1 Byte max. + const uint8_t range[2] = {0x00, 0x01}; // min=0, max=1 + + return os_mbuf_append(ctxt->om, range, sizeof(range)) == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} diff --git a/firmware/components/remote_control/remote_control.c b/firmware/components/remote_control/remote_control.c index ad4dbd4..12306da 100644 --- a/firmware/components/remote_control/remote_control.c +++ b/firmware/components/remote_control/remote_control.c @@ -1,7 +1,6 @@ #include #include -#include "capability_service.h" #include "esp_event.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" @@ -11,7 +10,7 @@ #include "host/ble_sm.h" #include "host/ble_uuid.h" #include "include/device_service.h" -#include "include/led_service.h" +#include "include/light_service.h" #include "nimble/nimble_port.h" #include "nimble/nimble_port_freertos.h" #include "sdkconfig.h" @@ -20,10 +19,11 @@ static const char *TAG = "remote_control"; +// static const ble_uuid128_t capability_service_uuid = +// BLE_UUID128_INIT(0x91, 0xB6, 0xCA, 0x95, 0xB2, 0xC6, 0x7B, 0x90, 0x31, 0x45, 0x77, 0xE6, 0x67, 0x10, 0x68, 0xB9); + static const ble_uuid16_t device_service_uuid = BLE_UUID16_INIT(0x180A); -static const ble_uuid128_t capability_service_uuid = - BLE_UUID128_INIT(0x91, 0xB6, 0xCA, 0x95, 0xB2, 0xC6, 0x7B, 0x90, 0x31, 0x45, 0x77, 0xE6, 0x67, 0x10, 0x68, 0xB9); -static const ble_uuid16_t led_service_uuid = BLE_UUID16_INIT(0x1007); +static const ble_uuid16_t light_service_uuid = BLE_UUID16_INIT(0xA000); uint8_t ble_addr_type; @@ -39,57 +39,63 @@ static struct ble_gatt_dsc_def char_0xA000_descs[] = {{ }, {0}}; -static struct ble_gatt_dsc_def char_0xDEAD_descs[] = {{ - .uuid = BLE_UUID16_DECLARE(0x2901), - .att_flags = BLE_ATT_F_WRITE, - .access_cb = led_char_dead_user_desc, - }, - {0}}; - -static struct ble_gatt_dsc_def char_0x1979_desc[] = {{ - .uuid = BLE_UUID16_DECLARE(0x2901), - .att_flags = BLE_ATT_F_READ, - .access_cb = capa_char_1979_user_desc, - }, - {0}}; +static struct ble_gatt_dsc_def char_0xDEAD_descs[] = { + { + .uuid = BLE_UUID16_DECLARE(0x2901), + .att_flags = BLE_ATT_F_WRITE, + .access_cb = led_char_dead_user_desc, + }, + { + .uuid = BLE_UUID16_DECLARE(0x2904), // Presentation Format (optional, empfehlenswert) + .att_flags = BLE_ATT_F_READ, + .access_cb = led_char_dead_presentation, + }, + { + .uuid = BLE_UUID16_DECLARE(0x2906), // Valid Range + .att_flags = BLE_ATT_F_READ, + .access_cb = led_char_dead_valid_range, + }, + {0}}; // Array of pointers to other service definitions static const struct ble_gatt_svc_def gatt_svcs[] = { { .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &device_service_uuid.u, - .characteristics = (struct ble_gatt_chr_def[]){{.uuid = BLE_UUID16_DECLARE(0x2A24), - .flags = BLE_GATT_CHR_F_READ, - .access_cb = device_model_number_read}, - {.uuid = BLE_UUID16_DECLARE(0x2A29), - .flags = BLE_GATT_CHR_F_READ, - .access_cb = device_manufacturer_read}, - {0}}, - }, - { - .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = &capability_service_uuid.u, .characteristics = (struct ble_gatt_chr_def[]){{ - .uuid = BLE_UUID16_DECLARE(0x1979), - .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, - .access_cb = capa_read, - .val_handle = &g_capa_char_val_handle, - .descriptors = char_0x1979_desc, + .uuid = BLE_UUID16_DECLARE(0x2A29), + .flags = BLE_GATT_CHR_F_READ, + .access_cb = device_manufacturer_read, + }, + { + .uuid = BLE_UUID16_DECLARE(0x2A27), + .flags = BLE_GATT_CHR_F_READ, + .access_cb = device_hardware_revision_read, + }, + { + .uuid = BLE_UUID16_DECLARE(0x2A26), + .flags = BLE_GATT_CHR_F_READ, + .access_cb = device_firmware_revision_read, + }, + { + .uuid = BLE_UUID16_DECLARE(0x2A00), + .flags = BLE_GATT_CHR_F_READ, + .access_cb = device_name_read, }, {0}}, }, { .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = &led_service_uuid.u, + .uuid = &light_service_uuid.u, .characteristics = (struct ble_gatt_chr_def[]){{ .uuid = BLE_UUID16_DECLARE(0xA000), - .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE, .access_cb = led_capabilities_read, .descriptors = char_0xA000_descs, }, { .uuid = BLE_UUID16_DECLARE(0xDEAD), - .flags = BLE_GATT_CHR_F_WRITE, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE, .access_cb = led_write, .descriptors = char_0xDEAD_descs, }, @@ -140,7 +146,7 @@ static int ble_gap_event(struct ble_gap_event *event, void *arg) { ESP_LOGI(TAG, "Client subscribed to capability notifications. Sending data..."); // Call the function to send capability data via notifications - capa_notify_data(event->subscribe.conn_handle, g_capa_char_val_handle); + // capa_notify_data(event->subscribe.conn_handle, g_capa_char_val_handle); } else { @@ -163,10 +169,15 @@ static void ble_app_advertise(void) // GAP - advertising definition struct ble_hs_adv_fields fields; memset(&fields, 0, sizeof(fields)); + uint8_t mfg_data[] = {0xDE, 0xC0, 0x05, 0x10, 0x20, 0x25}; + static const ble_uuid16_t services[] = {device_service_uuid, light_service_uuid}; + fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP; - fields.uuids128 = (ble_uuid128_t[]){capability_service_uuid}; - fields.num_uuids128 = 1; - fields.uuids128_is_complete = 1; + fields.uuids16 = services; + fields.num_uuids16 = sizeof(services) / sizeof(services[0]); + fields.uuids16_is_complete = 1; + fields.mfg_data = mfg_data; + fields.mfg_data_len = sizeof(mfg_data); ret = ble_gap_adv_set_fields(&fields); if (ret != 0) diff --git a/firmware/components/storage/CMakeLists.txt b/firmware/components/storage/CMakeLists.txt deleted file mode 100644 index 5e9118b..0000000 --- a/firmware/components/storage/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -idf_component_register(SRCS - "storage.c" - INCLUDE_DIRS "include" - PRIV_REQUIRES - spiffs -) diff --git a/firmware/components/storage/include/storage.h b/firmware/components/storage/include/storage.h deleted file mode 100644 index 3c1f1d1..0000000 --- a/firmware/components/storage/include/storage.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include "esp_err.h" -#include // For ssize_t - -/** - * @brief Initializes the SPIFFS filesystem. - * This function should be called once before any file operations. - * @return ESP_OK on success, error code otherwise. - */ -esp_err_t storage_init(void); - -/** - * @brief Unregisters the SPIFFS filesystem. - * This function should be called once when file operations are finished. - */ -void storage_uninit(void); - -/** - * @brief Reads a chunk of data from a file on SPIFFS. - * This function maintains internal state (file pointer) to allow reading - * the same file chunk by chunk across multiple calls. - * - * @param filename The path to the file to read (e.g., "/storage/my_file.txt"). - * Must be the same filename for consecutive calls to read the same file. - * @param buffer Buffer to store the read data. Must be large enough for max_bytes. - * @param max_bytes The maximum number of bytes to read in this call. Must be > 0. - * @return The number of bytes read on success (>= 0). - * Returns 0 when the end of the file is reached. - * Returns a negative value on error: - * -1: Invalid input parameters (filename, buffer is NULL, or max_bytes is 0). - * -2: Failed to open the file (first call for this filename). - * -3: Filename mismatch with the currently open file (subsequent call). - * -4: Read error occurred. - */ -ssize_t storage_read(const char *filename, char *buffer, size_t max_bytes); - -/** - * @brief Reads a chunk of data from a file on SPIFFS, starting at a specific offset. - * This function is stateless regarding an internally managed file pointer for sequential reads; - * it opens, seeks, reads, and closes the file on each call. - * - * @param filename The path to the file to read (e.g., "/storage/my_file.txt"). - * @param buffer Buffer to store the read data. Must be large enough for nbytes. - * @param offset The offset in the file to start reading from. - * @param nbytes The maximum number of bytes to read in this call. Must be > 0. - * @return The number of bytes read on success (>= 0). - * Returns 0 when the end of the file is reached from the given offset. - * Returns a negative value on error: - * -1: Invalid input parameters (filename, buffer is NULL, nbytes is 0, or offset is negative). - * -2: Failed to open the file. - * -5: Seek error occurred. - * -4: Read error occurred. - */ -ssize_t storage_read_at(const char *filename, char *buffer, off_t offset, size_t nbytes); diff --git a/firmware/components/storage/storage.c b/firmware/components/storage/storage.c deleted file mode 100644 index b61cb2a..0000000 --- a/firmware/components/storage/storage.c +++ /dev/null @@ -1,139 +0,0 @@ -#include "storage.h" - -#include "esp_log.h" -#include -#include -#include - -#include "esp_spiffs.h" - -static const char *TAG = "storage"; - -static FILE *s_current_file = NULL; -static char s_current_filename[256] = {0}; // Buffer to store the current filename - -esp_err_t storage_init(void) -{ - ESP_LOGI(TAG, "Initializing Storage"); - - esp_vfs_spiffs_conf_t conf = { - .base_path = "/storage", // Path where the filesystem will be mounted - .partition_label = "storage", // Partition label (must match partitions.csv) - .max_files = 5, // Maximum number of files that can be open at the same time - .format_if_mount_failed = true // Format partition if mount fails - }; - - // Initialize and mount SPIFFS - esp_err_t ret = esp_vfs_spiffs_register(&conf); - - if (ret != ESP_OK) - { - if (ret == ESP_FAIL) - { - ESP_LOGE(TAG, "Failed to mount or format filesystem"); - } - else if (ret == ESP_ERR_NOT_FOUND) - { - ESP_LOGE(TAG, "Failed to find SPIFFS partition"); - } - else - { - ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret)); - } - return ret; - } - - ESP_LOGI(TAG, "SPIFFS mounted"); - return ESP_OK; -} - -void storage_uninit(void) -{ - if (s_current_file != NULL) - { - // Log before clearing s_current_filename, using its value. - ESP_LOGW(TAG, "File '%s' was still open during uninit. Closing it.", s_current_filename); - fclose(s_current_file); // Close the file - s_current_file = NULL; - s_current_filename[0] = '\0'; - } - esp_vfs_spiffs_unregister("storage"); - ESP_LOGI(TAG, "SPIFFS unmounted"); -} - -ssize_t storage_read(const char *filename, char *buffer, size_t max_bytes) -{ - // Input validation - if (filename == NULL || filename[0] == '\0' || buffer == NULL || max_bytes == 0) - { - ESP_LOGE(TAG, "Invalid input parameters for storage_read"); - return -1; - } - - // If no file is currently open, open the requested one - if (s_current_file == NULL) - { - s_current_file = fopen(filename, "r"); - if (s_current_file == NULL) - { - ESP_LOGE(TAG, "Failed to open file for reading: %s", filename); - s_current_filename[0] = '\0'; // Clear filename as open failed - return -2; // Failed to open file - } - // Store the filename for subsequent calls - strncpy(s_current_filename, filename, sizeof(s_current_filename) - 1); - s_current_filename[sizeof(s_current_filename) - 1] = '\0'; - ESP_LOGI(TAG, "Opened file: %s", s_current_filename); - } - else - { - // If a file is open, ensure it's the same file requested - if (strcmp(filename, s_current_filename) != 0) - { - ESP_LOGE(TAG, "Filename mismatch. Expected '%s', got '%s'. Close the current file first.", - s_current_filename, filename); - // Note: File remains open. Caller might need a separate close function - // or ensure read loop finishes (returns 0 or error) before changing filename. - return -3; // Filename mismatch - } - } - - // Read a chunk - size_t bytes_read = fread(buffer, 1, max_bytes, s_current_file); - - // Check for read errors - if (ferror(s_current_file)) - { - ESP_LOGE(TAG, "Error reading file: %s", s_current_filename); - fclose(s_current_file); - s_current_file = NULL; - s_current_filename[0] = '\0'; - return -4; // Read error - } - - // If fread returns 0 and it's not an error, it means EOF or an empty file. - // The file should be closed only when no more bytes can be read (i.e., bytes_read == 0). - if (bytes_read == 0) // Indicates EOF or empty file (and no ferror) - { - // Log before clearing s_current_filename. - // feof(s_current_file) should be true if end of file was actually reached. - if (feof(s_current_file)) - { - ESP_LOGI(TAG, "EOF reached for file: %s. Closing file.", s_current_filename); - } - else - { - ESP_LOGI(TAG, "Read 0 bytes from file: %s (possibly empty or already at EOF). Closing file.", - s_current_filename); - } - fclose(s_current_file); - s_current_file = NULL; - s_current_filename[0] = '\0'; - // Return 0 as per contract: "Returns 0 when the end of the file is reached." - } - // If bytes_read > 0, return the number of bytes read. - // The file remains open (even if EOF was hit during this read and bytes_read < max_bytes). - // The next call to storage_read for this file will then result in fread returning 0, - // which will then hit the (bytes_read == 0) condition above and close the file. - return bytes_read; -} diff --git a/firmware/data/capability.json b/firmware/data/capability.json deleted file mode 100644 index a922836..0000000 --- a/firmware/data/capability.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "module": "Lighthouse", - "capabilities": [ - { - "id": 0, - "type": "toggle", - "default": "0", - "label": "L8" - }, - { - "id": 1, - "type": "toggle", - "default": "0", - "label": "L8" - }, - { - "id": 2, - "type": "toggle", - "default": "0", - "label": "L8" - }, - { - "id": 3, - "type": "toggle", - "default": "0", - "label": "L8" - }, - { - "id": 4, - "type": "toggle", - "default": "0", - "label": "L8" - }, - { - "id": 5, - "type": "toggle", - "default": "0", - "label": "L8" - }, - { - "id": 6, - "type": "toggle", - "default": "0", - "label": "L8" - } - ] -} \ No newline at end of file diff --git a/firmware/main/CMakeLists.txt b/firmware/main/CMakeLists.txt index 7dfee80..5fe6709 100644 --- a/firmware/main/CMakeLists.txt +++ b/firmware/main/CMakeLists.txt @@ -2,4 +2,3 @@ idf_component_register(SRCS "main.c" INCLUDE_DIRS "." ) -spiffs_create_partition_image(storage ../data FLASH_IN_PROJECT) diff --git a/firmware/partitions.csv b/firmware/partitions.csv index cb15057..2d9cedc 100644 --- a/firmware/partitions.csv +++ b/firmware/partitions.csv @@ -1,7 +1,6 @@ # Name , Type , SubType , Offset , Size , Flags nvs , data , nvs , 0x9000 , 20k , otadata , data , ota , 0xe000 , 8k , -app0 , app , ota_0 , 0x10000 , 1024k , -app1 , app , ota_1 , , 1024k , -storage , data , spiffs , , 1536k , +app0 , app , ota_0 , 0x10000 , 1792k , +app1 , app , ota_1 , , 1792k , coredump , data , coredump , , 64k , diff --git a/firmware/sdkconfig.defaults b/firmware/sdkconfig.defaults index 43731dd..635e650 100755 --- a/firmware/sdkconfig.defaults +++ b/firmware/sdkconfig.defaults @@ -6,11 +6,6 @@ CONFIG_BT_NIMBLE_ENABLED=y CONFIG_BT_NIMBLE_SECURITY_ENABLE=n CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME="lighthouse" -# Logging -CONFIG_LOG_DEFAULT_LEVEL_INFO=y -CONFIG_LOG_DEFAULT_LEVEL=3 -CONFIG_LOG_MAXIMUM_LEVEL=3 - # Flash Size CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_ESPTOOLPY_FLASHSIZE="4MB" diff --git a/firmware/sdkconfig.release b/firmware/sdkconfig.release index e69de29..a9989cf 100644 --- a/firmware/sdkconfig.release +++ b/firmware/sdkconfig.release @@ -0,0 +1,12 @@ +# Core dump +CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y +CONFIG_ESP_COREDUMP_CAPTURE_DRAM=y + +# Build type +CONFIG_APP_REPRODUCIBLE_BUILD=y + +# LOG +CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y + +# Log Level +CONFIG_LOG_DEFAULT_LEVEL_NONE=Y