Compare commits

..

10 Commits

Author SHA1 Message Date
ab1e334695 move files into firmware folder
Some checks failed
ESP-IDF Build / build (esp32, latest) (push) Failing after 19s
ESP-IDF Build / build (esp32, release-v5.4) (push) Failing after 15s
ESP-IDF Build / build (esp32, release-v5.5) (push) Failing after 15s
ESP-IDF Build / build (esp32c3, latest) (push) Failing after 21s
ESP-IDF Build / build (esp32c3, release-v5.4) (push) Failing after 15s
ESP-IDF Build / build (esp32c3, release-v5.5) (push) Failing after 14s
ESP-IDF Build / build (esp32c5, latest) (push) Failing after 14s
ESP-IDF Build / build (esp32c5, release-v5.4) (push) Failing after 15s
ESP-IDF Build / build (esp32c5, release-v5.5) (push) Failing after 15s
ESP-IDF Build / build (esp32c6, latest) (push) Failing after 18s
ESP-IDF Build / build (esp32c6, release-v5.4) (push) Failing after 15s
ESP-IDF Build / build (esp32c6, release-v5.5) (push) Failing after 15s
ESP-IDF Build / build (esp32h2, latest) (push) Failing after 15s
ESP-IDF Build / build (esp32h2, release-v5.4) (push) Failing after 14s
ESP-IDF Build / build (esp32h2, release-v5.5) (push) Failing after 15s
ESP-IDF Build / build (esp32p4, latest) (push) Failing after 15s
ESP-IDF Build / build (esp32p4, release-v5.4) (push) Failing after 18s
ESP-IDF Build / build (esp32p4, release-v5.5) (push) Failing after 15s
ESP-IDF Build / build (esp32s3, latest) (push) Failing after 14s
ESP-IDF Build / build (esp32s3, release-v5.4) (push) Failing after 14s
ESP-IDF Build / build (esp32s3, release-v5.5) (push) Failing after 15s
Signed-off-by: Peter Siegmund <developer@mars3142.org>
2025-08-20 22:32:04 +02:00
57493758b1 updated esp-idf version in github action
Signed-off-by: Peter Siegmund <developer@mars3142.org>
2025-07-26 14:19:21 +02:00
40b61e03ce add licence
Signed-off-by: Peter Siegmund <developer@mars3142.org>
2025-06-29 17:39:53 +02:00
de103142a4 starting with notify
Signed-off-by: Peter Siegmund <developer@mars3142.org>
2025-05-30 22:43:12 +02:00
a7067fb391 read capability.json from storage
Signed-off-by: Peter Siegmund <developer@mars3142.org>
2025-05-30 22:42:58 +02:00
c368899c4d starting with capability service
Signed-off-by: Peter Siegmund <developer@mars3142.org>
2025-05-30 15:35:19 +02:00
dcc679fe27 add github actions permission
Signed-off-by: Peter Siegmund <developer@mars3142.org>
2025-05-29 16:08:48 +02:00
d8d85ac333 add more MCUs
Signed-off-by: Peter Siegmund <developer@mars3142.org>
2025-05-29 15:56:31 +02:00
26e47a8cf9 some modifications
- clang formatter
- new NimBLE settings
- BLE has more advertise data

Signed-off-by: Peter Siegmund <developer@mars3142.org>
2025-05-28 23:25:26 +02:00
7222fb1829 LIGHT ON/OFF testing for WLEDs
Signed-off-by: Peter Siegmund <developer@mars3142.org>
2025-05-25 18:27:48 +02:00
56 changed files with 945 additions and 321 deletions

View File

@@ -7,6 +7,10 @@ on:
schedule: schedule:
- cron: "0 5 * * 3" - cron: "0 5 * * 3"
permissions:
contents: read
pull-requests: write
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
@@ -15,8 +19,9 @@ jobs:
build: build:
strategy: strategy:
matrix: matrix:
idf_ver: [release-v5.4, latest] idf_ver: [release-v5.4, release-v5.5, latest]
idf_target: [esp32, esp32s3, esp32c3] idf_target:
[esp32, esp32c3, esp32c5, esp32c6, esp32h2, esp32p4, esp32s3]
runs-on: ubuntu-latest runs-on: ubuntu-latest

22
LICENSE.md Normal file
View File

@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2025 Peter Siegmund
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,5 +0,0 @@
#pragma once
#include <stdint.h>
void led_matrix_init(void *args);

View File

@@ -1,70 +0,0 @@
#include "led_matrix.h"
#include "freertos/FreeRTOS.h"
#include "led_strip.h"
#include "esp_log.h"
#include "sdkconfig.h"
typedef struct
{
uint8_t red;
uint8_t green;
uint8_t blue;
} led_data_t;
typedef struct
{
led_strip_handle_t led_strip;
led_data_t *data;
uint32_t size;
} led_matrix_t;
led_matrix_t led_matrix;
static void led_strip_init(uint8_t gpio_pin, uint32_t size)
{
led_matrix.size = size;
led_matrix.data = (led_data_t *)malloc(sizeof(led_data_t) * size);
led_strip_config_t strip_config = {
.strip_gpio_num = gpio_pin,
.max_leds = size,
.led_model = LED_MODEL_WS2812,
.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_RGB,
.flags = {
.invert_out = false,
}};
led_strip_rmt_config_t rmt_config = {
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 0,
.mem_block_symbols = 0,
.flags = {
.with_dma = true,
}};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_matrix.led_strip));
}
void led_matrix_init(void *args)
{
ESP_LOGI(pcTaskGetName(NULL), "Calling led_matrix_init()");
led_strip_init(CONFIG_WLED_DIN_PIN, CONFIG_WLED_LED_COUNT);
int value = 0;
for (int i = 0; i < led_matrix.size; i++)
{
led_strip_set_pixel(led_matrix.led_strip, i, value, 0, 0);
}
led_strip_refresh(led_matrix.led_strip);
while (true)
{
vTaskDelay(pdMS_TO_TICKS(100));
}
free(led_matrix.data);
ESP_LOGI(pcTaskGetName(NULL), "Exiting led_matrix_init()");
vTaskDelete(NULL);
}

View File

@@ -1,5 +0,0 @@
idf_component_register(SRCS "led_service.c" "device_service.c" "remote_control.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES
bt
)

View File

@@ -1,15 +0,0 @@
#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;
}

View File

@@ -1,7 +0,0 @@
#pragma once
#include <stdio.h>
#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);

View File

@@ -1,3 +0,0 @@
#pragma once
void ble_init(void *args);

View File

@@ -1,59 +0,0 @@
#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;
}

View File

@@ -1,140 +0,0 @@
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_nimble_hci.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "host/ble_sm.h"
#include "services/gap/ble_svc_gap.h"
#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";
uint8_t ble_addr_type;
void ble_app_advertise(void);
// 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 = 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}},
},
{0}};
// BLE event handling
static int ble_gap_event(struct ble_gap_event *event, void *arg)
{
switch (event->type)
{
case BLE_GAP_EVENT_CONNECT:
ESP_LOGI(TAG, "BLE GAP EVENT CONNECT %s", event->connect.status == 0 ? "OK!" : "FAILED!");
if (event->connect.status == 0)
{
// Start security pairing without disconnecting
int ret = ble_gap_security_initiate(event->connect.conn_handle);
ESP_LOGI(TAG, "BLE GAP SECURITY INITIATE %s", ret == 0 ? "OK!" : "FAILED!");
}
else
{
// Re-advertise if connection failed
ble_app_advertise();
}
break;
case BLE_GAP_EVENT_DISCONNECT:
ESP_LOGI(TAG, "BLE GAP EVENT DISCONNECTED");
// Re-advertise after disconnection
ble_app_advertise();
break;
case BLE_GAP_EVENT_ADV_COMPLETE:
ESP_LOGI(TAG, "BLE GAP EVENT ADV COMPLETE");
// Re-advertise to continue accepting new clients
ble_app_advertise();
break;
case BLE_GAP_EVENT_ENC_CHANGE:
if (event->enc_change.status == 0)
{
ESP_LOGI(TAG, "Encryption enabled for connection");
}
else
{
ESP_LOGE(TAG, "Failed to enable encryption, status=%d", event->enc_change.status);
}
break;
default:
break;
}
return 0;
}
// Define the BLE connection
void ble_app_advertise(void)
{
// GAP - device name definition
struct ble_hs_adv_fields fields;
const char *device_name;
memset(&fields, 0, sizeof(fields));
device_name = ble_svc_gap_device_name(); // Read the BLE device name
fields.name = (uint8_t *)device_name;
fields.name_len = strlen(device_name);
fields.name_is_complete = 1;
ble_gap_adv_set_fields(&fields);
// GAP - device connectivity definition
struct ble_gap_adv_params adv_params;
memset(&adv_params, 0, sizeof(adv_params));
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; // connectable or non-connectable
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; // discoverable or non-discoverable
ble_gap_adv_start(ble_addr_type, NULL, BLE_HS_FOREVER, &adv_params, ble_gap_event, NULL);
}
// The application
void ble_app_on_sync(void)
{
ble_hs_id_infer_auto(0, &ble_addr_type); // Determines the best address type automatically
ble_app_advertise(); // Define the BLE connection
}
// The infinite task
void host_task(void *param)
{
nimble_port_run(); // This function will return only when nimble_port_stop() is executed
}
void ble_init(void *args)
{
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;
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
}

2
firmware/.clang-format Normal file
View File

@@ -0,0 +1,2 @@
---
BasedOnStyle: Microsoft

17
firmware/.clangd Normal file
View File

@@ -0,0 +1,17 @@
CompileFlags:
Add:
- -Wno-unknown-warning-option
- -Wno-format
Remove:
- -mword-relocations
Diagnostics:
ClangTidy:
FastCheckFilter: None
---
If:
PathMatch: .*\.h
Diagnostics:
UnusedIncludes: None

View File

View File

@@ -0,0 +1,7 @@
#pragma once
#include <stdint.h>
void led_matrix_init(void *args);
uint32_t led_matrix_get_size();
void led_matrix_set_pixel(uint32_t index, uint8_t red, uint8_t green, uint8_t blue);

View File

@@ -0,0 +1,67 @@
#include "led_matrix.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "led_strip.h"
#include "sdkconfig.h"
typedef struct
{
led_strip_handle_t led_strip;
uint32_t size;
} led_matrix_t;
led_matrix_t led_matrix;
static void led_strip_init(uint8_t gpio_pin, uint32_t size)
{
led_matrix.size = size;
led_strip_config_t strip_config = {.strip_gpio_num = gpio_pin,
.max_leds = size,
.led_model = LED_MODEL_WS2812,
.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_RGB,
.flags = {
.invert_out = false,
}};
led_strip_rmt_config_t rmt_config = {.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 0,
.mem_block_symbols = 0,
.flags = {
.with_dma = true,
}};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_matrix.led_strip));
}
uint32_t led_matrix_get_size()
{
return led_matrix.size;
}
void led_matrix_set_pixel(uint32_t index, uint8_t red, uint8_t green, uint8_t blue)
{
led_strip_set_pixel(led_matrix.led_strip, index, red, green, blue);
}
void led_matrix_init(void *args)
{
ESP_LOGI(pcTaskGetName(NULL), "Calling led_matrix_init()");
led_strip_init(CONFIG_WLED_DIN_PIN, CONFIG_WLED_LED_COUNT);
int value = 0;
for (int i = 0; i < led_matrix.size; i++)
{
led_matrix_set_pixel(i, 0, value, 0);
}
while (true)
{
led_strip_refresh(led_matrix.led_strip);
vTaskDelay(pdMS_TO_TICKS(100));
}
ESP_LOGI(pcTaskGetName(NULL), "Exiting led_matrix_init()");
vTaskDelete(NULL);
}

View File

@@ -0,0 +1,12 @@
idf_component_register(SRCS
"capability_service.c"
"device_service.c"
"led_service.c"
"remote_control.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES
bt
esp_app_format
storage
led_matrix
)

View File

@@ -0,0 +1,156 @@
#include "capability_service.h"
#include "esp_log.h"
#include "storage.h"
#include <string.h>
#include <stdlib.h> // 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);
}

View File

@@ -0,0 +1,29 @@
#include "include/device_service.h"
#include "esp_app_desc.h"
#include <stdio.h>
#include <string.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_str[65];
const esp_app_desc_t *app_desc = esp_app_get_description();
if (app_desc->project_name[0] != '\0' && app_desc->version[0] != '\0')
{
snprintf(model_number_str, sizeof(model_number_str), "%s v%s", app_desc->project_name, app_desc->version);
}
else
{
snprintf(model_number_str, sizeof(model_number_str), "undefined");
}
os_mbuf_append(ctxt->om, model_number_str, strlen(model_number_str));
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;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "host/ble_hs.h"
#include <stdio.h>
/// 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);

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <stdio.h>
#include "host/ble_hs.h" #include "host/ble_hs.h"
#include <stdio.h>
int ds_model_number_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); 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); int ds_manufacturer_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);

View File

@@ -0,0 +1,12 @@
#pragma once
#include "host/ble_hs.h"
#include <stdio.h>
/// LED Service Characteristic Callbacks
int ls_write(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int ls_capabilities_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
/// LED Service Characteristic User Description
int ls_char_a000_user_desc(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int ls_char_dead_user_desc(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);

View File

@@ -0,0 +1,3 @@
#pragma once
void ble_init(void);

View File

@@ -0,0 +1,77 @@
#include "include/led_service.h"
#include "led_matrix.h"
static const char *TAG = "led_service";
/// Capabilities of Device
int ls_capabilities_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
char *data = "To be implemented later";
os_mbuf_append(ctxt->om, data, strlen(data));
return 0;
}
// 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");
for (int i = 0; i < led_matrix_get_size(); i++)
{
led_matrix_set_pixel(i, 10, 10, 0);
}
}
else if (payload_len == (sizeof(CMD_LIGHT_OFF) - 1) && strncmp(received_payload, CMD_LIGHT_OFF, payload_len) == 0)
{
ESP_LOGI(TAG, "LIGHT OFF");
for (int i = 0; i < led_matrix_get_size(); i++)
{
led_matrix_set_pixel(i, 0, 0, 0);
}
}
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;
}
int ls_char_a000_user_desc(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
const char *desc = "Capabilities of Device";
os_mbuf_append(ctxt->om, desc, strlen(desc));
return 0;
}
int ls_char_dead_user_desc(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
const char *desc = "Readable Data from Server";
os_mbuf_append(ctxt->om, desc, strlen(desc));
return 0;
}

View File

@@ -0,0 +1,250 @@
#include <stdio.h>
#include <string.h>
#include "capability_service.h"
#include "esp_event.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#include "host/ble_hs.h"
#include "host/ble_sm.h"
#include "host/ble_uuid.h"
#include "include/device_service.h"
#include "include/led_service.h"
#include "led_matrix.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "sdkconfig.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
static const char *TAG = "remote_control";
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);
uint8_t ble_addr_type;
// Handle for the capability characteristic value
static uint16_t g_capa_char_val_handle;
static void ble_app_advertise(void);
static struct ble_gatt_dsc_def char_0xA000_descs[] = {{
.uuid = BLE_UUID16_DECLARE(0x2901),
.att_flags = BLE_ATT_F_READ,
.access_cb = ls_char_a000_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 = ls_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}};
// 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 = 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 = &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,
},
{0}},
},
{
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = &led_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,
.access_cb = ls_capabilities_read,
.descriptors = char_0xA000_descs,
},
{
.uuid = BLE_UUID16_DECLARE(0xDEAD),
.flags = BLE_GATT_CHR_F_WRITE,
.access_cb = ls_write,
.descriptors = char_0xDEAD_descs,
},
{0}},
},
{0}};
// BLE event handling
static int ble_gap_event(struct ble_gap_event *event, void *arg)
{
switch (event->type)
{
case BLE_GAP_EVENT_CONNECT:
ESP_LOGI(TAG, "BLE GAP EVENT CONNECT %s", event->connect.status == 0 ? "OK!" : "FAILED!");
if (event->connect.status != 0)
{
// Re-advertise if connection failed
ble_app_advertise();
}
break;
case BLE_GAP_EVENT_DISCONNECT:
ESP_LOGI(TAG, "BLE GAP EVENT DISCONNECTED");
// Re-advertise after disconnection
ble_app_advertise();
break;
case BLE_GAP_EVENT_ADV_COMPLETE:
ESP_LOGI(TAG, "BLE GAP EVENT ADV COMPLETE");
// Re-advertise to continue accepting new clients
ble_app_advertise();
break;
case BLE_GAP_EVENT_SUBSCRIBE:
ESP_LOGI(TAG,
"BLE GAP EVENT SUBSCRIBE conn_handle=%d attr_handle=%d reason=%d "
"prev_notify=%d cur_notify=%d prev_indicate=%d cur_indicate=%d",
event->subscribe.conn_handle, event->subscribe.attr_handle, event->subscribe.reason,
event->subscribe.prev_notify, event->subscribe.cur_notify, event->subscribe.prev_indicate,
event->subscribe.cur_indicate);
// Check if subscription is for the capability characteristic's CCCD.
// The CCCD handle is typically the characteristic value handle + 1.
// g_capa_char_val_handle stores the handle of the characteristic value itself.
if (event->subscribe.attr_handle == g_capa_char_val_handle + 1)
{
if (event->subscribe.cur_notify)
{
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);
}
else
{
ESP_LOGI(TAG, "Client unsubscribed from capability notifications.");
}
}
break;
default:
break;
}
return 0;
}
// Define the BLE connection
static void ble_app_advertise(void)
{
int ret;
// GAP - advertising definition
struct ble_hs_adv_fields fields;
memset(&fields, 0, sizeof(fields));
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;
ret = ble_gap_adv_set_fields(&fields);
if (ret != 0)
{
ESP_LOGE(TAG, "Failed to set advertising data (err: %d)", ret);
return;
}
// GAP - device connectivity definition
struct ble_gap_adv_params adv_params;
memset(&adv_params, 0, sizeof(adv_params));
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; // connectable or non-connectable
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; // discoverable or non-discoverable
ret = ble_gap_adv_start(ble_addr_type, NULL, BLE_HS_FOREVER, &adv_params, ble_gap_event, NULL);
if (ret != 0)
{
ESP_LOGE(TAG, "Advertising failed to start (err %d)", ret);
return;
}
// --- Configure Scan Response Data (SCAN_RSP) ---
struct ble_hs_adv_fields scan_rsp_fields;
memset(&scan_rsp_fields, 0, sizeof(scan_rsp_fields));
// Get the device name
const char *device_name;
device_name = ble_svc_gap_device_name();
scan_rsp_fields.name = (uint8_t *)device_name;
scan_rsp_fields.name_len = strlen(device_name);
scan_rsp_fields.name_is_complete = 1;
// Optionally, add TX power level to scan response
scan_rsp_fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
scan_rsp_fields.tx_pwr_lvl_is_present = 1;
ret = ble_gap_adv_rsp_set_fields(&scan_rsp_fields);
if (ret != 0)
{
ESP_LOGE(TAG, "Error setting scan response data; rc=%d", ret);
return;
}
}
// The application
static void ble_app_on_sync(void)
{
uint8_t ble_addr[6] = {0};
int ret = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, ble_addr, NULL);
if (ret != 0)
{
ESP_LOGE(TAG, "Failed to get BLE MAC address (err: %d)", ret);
return;
}
char formatted_name[32];
snprintf(formatted_name, sizeof(formatted_name), "Miniature Town %02X%02X", ble_addr[4], ble_addr[5]);
ble_svc_gap_device_name_set(formatted_name);
// Start Advertising
ble_hs_id_infer_auto(0, &ble_addr_type); // Determines the best address type automatically
ble_app_advertise();
}
// The infinite task
static void host_task(void *param)
{
nimble_port_run(); // This function will return only when nimble_port_stop() is executed
}
void ble_init(void)
{
nimble_port_init();
ble_svc_gap_init();
ble_svc_gatt_init();
ble_gatts_count_cfg(gatt_svcs);
ble_gatts_add_svcs(gatt_svcs);
// Callback für Synchronisation
ble_hs_cfg.sync_cb = ble_app_on_sync;
nimble_port_freertos_init(host_task); // Start BLE-Host-Task
}

View File

@@ -0,0 +1,6 @@
idf_component_register(SRCS
"storage.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES
spiffs
)

View File

@@ -0,0 +1,55 @@
#pragma once
#include "esp_err.h"
#include <sys/types.h> // 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);

View File

@@ -0,0 +1,139 @@
#include "storage.h"
#include "esp_log.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#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 SPIFFS");
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;
}

View File

@@ -0,0 +1,47 @@
{
"module": "Miniature Town",
"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"
}
]
}

View File

@@ -0,0 +1,12 @@
idf_component_register(SRCS
main.c
INCLUDE_DIRS "."
PRIV_REQUIRES
driver
esp_timer
led_strip
led_matrix
remote_control
persistence
)
spiffs_create_partition_image(storage ../data FLASH_IN_PROJECT)

View File

@@ -1,14 +1,11 @@
#include "freertos/FreeRTOS.h"
#include "led_matrix.h" #include "led_matrix.h"
#include "persistence.h" #include "persistence.h"
#include "remote_control.h" #include "remote_control.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
void app_main(void) void app_main(void)
{ {
persistence_init("miniature_town"); persistence_init("miniature_town");
ble_init();
xTaskCreatePinnedToCore(led_matrix_init, "led_matrix", configMINIMAL_STACK_SIZE * 2, NULL, 5, NULL, 1); xTaskCreatePinnedToCore(led_matrix_init, "led_matrix", configMINIMAL_STACK_SIZE * 2, NULL, 5, NULL, 1);
ble_init(NULL);
} }

View File

@@ -3,5 +3,5 @@ nvs , data , nvs , 0x9000 , 20k ,
otadata , data , ota , 0xe000 , 8k , otadata , data , ota , 0xe000 , 8k ,
app0 , app , ota_0 , 0x10000 , 1024k , app0 , app , ota_0 , 0x10000 , 1024k ,
app1 , app , ota_1 , , 1024k , app1 , app , ota_1 , , 1024k ,
spiffs , data , spiffs , , 1536k , storage , data , spiffs , , 1536k ,
coredump , data , coredump , , 64k , coredump , data , coredump , , 64k ,
1 # Name Type SubType Offset Size Flags
3 otadata data ota 0xe000 8k
4 app0 app ota_0 0x10000 1024k
5 app1 app ota_1 1024k
6 spiffs storage data spiffs 1536k
7 coredump data coredump 64k

View File

@@ -2,7 +2,8 @@
CONFIG_BT_ENABLED=y CONFIG_BT_ENABLED=y
CONFIG_BT_NIMBLE_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y
# nimble options # NimBLE Options
CONFIG_BT_NIMBLE_SECURITY_ENABLE=n
CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME="miniature" CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME="miniature"
# Logging # Logging

View File

@@ -0,0 +1,2 @@
# default ESP target
CONFIG_IDF_TARGET="esp32c5"

View File

@@ -0,0 +1,2 @@
# default ESP target
CONFIG_IDF_TARGET="esp32c6"

View File

@@ -0,0 +1,2 @@
# default ESP target
CONFIG_IDF_TARGET="esp32h2"

View File

@@ -0,0 +1,2 @@
# default ESP target
CONFIG_IDF_TARGET="esp32p4"

View File

@@ -1,7 +0,0 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS "."
PRIV_REQUIRES
led_matrix
remote_control
persistence
)