diff --git a/firmware/components/remote_control/CMakeLists.txt b/firmware/components/remote_control/CMakeLists.txt index 8cfd239..7e28cfb 100644 --- a/firmware/components/remote_control/CMakeLists.txt +++ b/firmware/components/remote_control/CMakeLists.txt @@ -2,6 +2,7 @@ idf_component_register(SRCS "device_service.c" "light_service.c" "remote_control.c" + "uart_service.c" INCLUDE_DIRS "include" PRIV_REQUIRES bt diff --git a/firmware/components/remote_control/include/uart_service.h b/firmware/components/remote_control/include/uart_service.h new file mode 100644 index 0000000..c8ba92f --- /dev/null +++ b/firmware/components/remote_control/include/uart_service.h @@ -0,0 +1,21 @@ +#pragma once + +#include "host/ble_hs.h" +#include "host/ble_sm.h" +#include "host/ble_uuid.h" + +// Unique UUIDs for UART-Service (compatible with Nordic UART Service) +// Service UUID: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E +extern const ble_uuid128_t gatt_svr_svc_uart_uuid; + +// RX Characteristic UUID: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E +extern const ble_uuid128_t gatt_svr_chr_uart_rx_uuid; + +// TX Characteristic UUID: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E +extern const ble_uuid128_t gatt_svr_chr_uart_tx_uuid; + +extern uint16_t conn_handle; +extern uint16_t tx_chr_val_handle; + +int gatt_svr_chr_uart_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); +void send_ble_data(const char *data); diff --git a/firmware/components/remote_control/remote_control.c b/firmware/components/remote_control/remote_control.c index d032d62..e13d059 100644 --- a/firmware/components/remote_control/remote_control.c +++ b/firmware/components/remote_control/remote_control.c @@ -1,3 +1,5 @@ +#include "include/remote_control.h" + #include #include @@ -11,6 +13,7 @@ #include "host/ble_uuid.h" #include "include/device_service.h" #include "include/light_service.h" +#include "include/uart_service.h" #include "nimble/nimble_port.h" #include "nimble/nimble_port_freertos.h" #include "sdkconfig.h" @@ -19,99 +22,127 @@ static const char *TAG = "remote_control"; -static const ble_uuid16_t device_service_uuid = BLE_UUID16_INIT(0x180A); -static const ble_uuid16_t light_service_uuid = BLE_UUID16_INIT(0xA000); -static const ble_uuid16_t settings_service_uuid = BLE_UUID16_INIT(0xA999); +static const ble_uuid16_t gatt_svr_svc_device_uuid = BLE_UUID16_INIT(0x180A); +static const ble_uuid16_t gatt_svr_svc_light_uuid = BLE_UUID16_INIT(0xA000); +static const ble_uuid16_t gatt_svr_svc_settings_uuid = BLE_UUID16_INIT(0xA999); 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); // Descriptors for the characteristics -static struct ble_gatt_dsc_def led_char_desc[] = {{ - .uuid = BLE_UUID16_DECLARE(0x2901), - .att_flags = BLE_ATT_F_READ, - .access_cb = led_char_user_desc_cb, - }, - { - .uuid = BLE_UUID16_DECLARE(0x2904), - .att_flags = BLE_ATT_F_READ, - .access_cb = bool_char_presentation_cb, - }, - { - .uuid = BLE_UUID16_DECLARE(0x2906), - .att_flags = BLE_ATT_F_READ, - .access_cb = bool_char_valid_range_cb, - }, - {0}}; +static struct ble_gatt_dsc_def led_char_desc[] = { + { + .uuid = BLE_UUID16_DECLARE(0x2901), + .att_flags = BLE_ATT_F_READ, + .access_cb = led_char_user_desc_cb, + }, + { + .uuid = BLE_UUID16_DECLARE(0x2904), + .att_flags = BLE_ATT_F_READ, + .access_cb = bool_char_presentation_cb, + }, + { + .uuid = BLE_UUID16_DECLARE(0x2906), + .att_flags = BLE_ATT_F_READ, + .access_cb = bool_char_valid_range_cb, + }, + {0}, +}; -static struct ble_gatt_dsc_def beacon_char_desc[] = {{ - .uuid = BLE_UUID16_DECLARE(0x2901), - .att_flags = BLE_ATT_F_READ, - .access_cb = beacon_char_user_desc_cb, - }, - { - .uuid = BLE_UUID16_DECLARE(0x2904), - .att_flags = BLE_ATT_F_READ, - .access_cb = bool_char_presentation_cb, - }, - { - .uuid = BLE_UUID16_DECLARE(0x2906), - .att_flags = BLE_ATT_F_READ, - .access_cb = bool_char_valid_range_cb, - }, - {0}}; +static struct ble_gatt_dsc_def beacon_char_desc[] = { + { + .uuid = BLE_UUID16_DECLARE(0x2901), + .att_flags = BLE_ATT_F_READ, + .access_cb = beacon_char_user_desc_cb, + }, + { + .uuid = BLE_UUID16_DECLARE(0x2904), + .att_flags = BLE_ATT_F_READ, + .access_cb = bool_char_presentation_cb, + }, + { + .uuid = BLE_UUID16_DECLARE(0x2906), + .att_flags = BLE_ATT_F_READ, + .access_cb = bool_char_valid_range_cb, + }, + {0}, +}; // Array of pointers to 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(0x2A29), - .flags = BLE_GATT_CHR_F_READ, - .access_cb = device_manufacturer_cb, - }, - { - .uuid = BLE_UUID16_DECLARE(0x2A27), - .flags = BLE_GATT_CHR_F_READ, - .access_cb = device_hardware_revision_cb, - }, - { - .uuid = BLE_UUID16_DECLARE(0x2A26), - .flags = BLE_GATT_CHR_F_READ, - .access_cb = device_firmware_revision_cb, - }, - { - .uuid = BLE_UUID16_DECLARE(0x2A00), - .flags = BLE_GATT_CHR_F_READ, - .access_cb = device_name_cb, - }, - {0}}, + .uuid = &gatt_svr_svc_device_uuid.u, + .characteristics = + (struct ble_gatt_chr_def[]){ + { + .uuid = BLE_UUID16_DECLARE(0x2A29), + .flags = BLE_GATT_CHR_F_READ, + .access_cb = device_manufacturer_cb, + }, + { + .uuid = BLE_UUID16_DECLARE(0x2A27), + .flags = BLE_GATT_CHR_F_READ, + .access_cb = device_hardware_revision_cb, + }, + { + .uuid = BLE_UUID16_DECLARE(0x2A26), + .flags = BLE_GATT_CHR_F_READ, + .access_cb = device_firmware_revision_cb, + }, + { + .uuid = BLE_UUID16_DECLARE(0x2A00), + .flags = BLE_GATT_CHR_F_READ, + .access_cb = device_name_cb, + }, + {0}, + }, }, { .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = &light_service_uuid.u, - .characteristics = (struct ble_gatt_chr_def[]){{ - .uuid = BLE_UUID16_DECLARE(0xBEA0), - .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE, - .access_cb = beacon_cb, - .descriptors = beacon_char_desc, - }, - { - .uuid = BLE_UUID16_DECLARE(0xF037), - .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE, - .access_cb = led_cb, - .descriptors = led_char_desc, - }, - {0}}, + .uuid = &gatt_svr_svc_light_uuid.u, + .characteristics = + (struct ble_gatt_chr_def[]){ + { + .uuid = BLE_UUID16_DECLARE(0xBEA0), + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE, + .access_cb = beacon_cb, + .descriptors = beacon_char_desc, + }, + { + .uuid = BLE_UUID16_DECLARE(0xF037), + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE, + .access_cb = led_cb, + .descriptors = led_char_desc, + }, + {0}, + }, }, { .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = &settings_service_uuid.u, + .uuid = &gatt_svr_svc_uart_uuid.u, + .characteristics = + (struct ble_gatt_chr_def[]){ + { + // Characteristic: RX (Receiving of data) + .uuid = &gatt_svr_chr_uart_rx_uuid.u, + .access_cb = gatt_svr_chr_uart_access, + .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP, + }, + { + // Characteristic: TX (Sending of data) + .uuid = &gatt_svr_chr_uart_tx_uuid.u, + .access_cb = gatt_svr_chr_uart_access, + .val_handle = &tx_chr_val_handle, + .flags = BLE_GATT_CHR_F_NOTIFY, + }, + {0}, + }, + }, + { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = &gatt_svr_svc_settings_uuid.u, .characteristics = (struct ble_gatt_chr_def[]){{0}}, }, {0}}; @@ -122,52 +153,22 @@ 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(); - } + ESP_LOGI(TAG, "Connection established; status=%d", event->connect.status); + conn_handle = event->connect.conn_handle; + ESP_LOGI(TAG, "Connection handle: %d", conn_handle); break; case BLE_GAP_EVENT_DISCONNECT: - ESP_LOGI(TAG, "BLE GAP EVENT DISCONNECTED"); - // Re-advertise after disconnection + ESP_LOGI(TAG, "Disconnected; reason=%d", event->disconnect.reason); + conn_handle = 0; 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 + ESP_LOGI(TAG, "Advertising complete"); 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; } @@ -183,7 +184,8 @@ static void ble_app_advertise(void) 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, settings_service_uuid}; + static const ble_uuid16_t services[] = {gatt_svr_svc_device_uuid, gatt_svr_svc_light_uuid, + gatt_svr_svc_settings_uuid}; fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP; fields.uuids16 = services; @@ -254,6 +256,22 @@ static void ble_app_on_sync(void) ble_app_advertise(); } +static void uart_tx_task(void *param) +{ + char buffer[50]; + int count = 0; + while (1) + { + vTaskDelay(pdMS_TO_TICKS(2000)); + if (conn_handle != 0) + { + ESP_LOGI(TAG, "Sending data over BLE UART TX"); + sprintf(buffer, "Hello World #%d", count++); + send_ble_data(buffer); + } + } +} + // The infinite task static void host_task(void *param) { @@ -268,8 +286,10 @@ void remote_control_init(void) ble_gatts_count_cfg(gatt_svcs); ble_gatts_add_svcs(gatt_svcs); - // Callback für Synchronisation + // Callback for synchronization ble_hs_cfg.sync_cb = ble_app_on_sync; - nimble_port_freertos_init(host_task); // Start BLE-Host-Task + nimble_port_freertos_init(host_task); // Start BLE host task + + xTaskCreate(uart_tx_task, "uart_tx", 2048, NULL, 1, NULL); } diff --git a/firmware/components/remote_control/uart_service.c b/firmware/components/remote_control/uart_service.c new file mode 100644 index 0000000..5d4c8d0 --- /dev/null +++ b/firmware/components/remote_control/uart_service.c @@ -0,0 +1,70 @@ +#include "include/uart_service.h" + +static const char *TAG = "uart_service"; + +// Service UUID: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E +const ble_uuid128_t gatt_svr_svc_uart_uuid = + BLE_UUID128_INIT(0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E); + +// RX Characteristic UUID: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E +const ble_uuid128_t gatt_svr_chr_uart_rx_uuid = + BLE_UUID128_INIT(0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E); + +// TX Characteristic UUID: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E +const ble_uuid128_t gatt_svr_chr_uart_tx_uuid = + BLE_UUID128_INIT(0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x03, 0x00, 0x40, 0x6E); + +uint16_t conn_handle; +uint16_t tx_chr_val_handle; + +// Callback function for GATT events (read/write on characteristics) +int gatt_svr_chr_uart_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + switch (ctxt->op) + { + case BLE_GATT_ACCESS_OP_WRITE_CHR: + // Check if the RX characteristic is being written to + // if (ble_uuid_cmp((const ble_uuid_t *)&ctxt->chr->uuid, (const ble_uuid_t *)&gatt_svr_chr_uart_rx_uuid) == 0) + { + // Get data from the buffer + uint16_t data_len = OS_MBUF_PKTLEN(ctxt->om); + char *data = (char *)malloc(data_len + 1); + if (data) + { + int rc = ble_hs_mbuf_to_flat(ctxt->om, data, data_len, NULL); + if (rc == 0) + { + data[data_len] = '\0'; + ESP_LOGI(TAG, "Received data: %s", data); + } + free(data); + } + return 0; + } + break; + default: + break; + } + return BLE_ATT_ERR_UNLIKELY; +} + +// Function to send data via the TX characteristic +void send_ble_data(const char *data) +{ + if (conn_handle != 0) + { // Only send when connected + struct os_mbuf *om = ble_hs_mbuf_from_flat(data, strlen(data)); + if (om) + { + int rc = ble_gatts_notify_custom(conn_handle, tx_chr_val_handle, om); + if (rc == 0) + { + ESP_LOGI(TAG, "Sent data: %s", data); + } + else + { + ESP_LOGE(TAG, "Error sending data: %d", rc); + } + } + } +}