starting with notify
Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
@@ -2,6 +2,10 @@
|
|||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include <string.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";
|
static const char *TAG_CS = "capability_service";
|
||||||
|
|
||||||
@@ -70,3 +74,83 @@ int capa_char_1979_user_desc(uint16_t con_handle, uint16_t attr_handle, struct b
|
|||||||
os_mbuf_append(ctxt->om, desc, strlen(desc));
|
os_mbuf_append(ctxt->om, desc, strlen(desc));
|
||||||
return 0;
|
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);
|
||||||
|
}
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
/// Service Characteristics Callback
|
/// Service Characteristics Callback
|
||||||
int capa_read(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
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
|
/// 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);
|
int capa_char_1979_user_desc(uint16_t con_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||||
|
@@ -28,6 +28,9 @@ static const ble_uuid16_t led_service_uuid = BLE_UUID16_INIT(0x1007);
|
|||||||
|
|
||||||
uint8_t ble_addr_type;
|
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 void ble_app_advertise(void);
|
||||||
|
|
||||||
static struct ble_gatt_dsc_def char_0xA000_descs[] = {{
|
static struct ble_gatt_dsc_def char_0xA000_descs[] = {{
|
||||||
@@ -69,6 +72,7 @@ static const struct ble_gatt_svc_def gatt_svcs[] = {
|
|||||||
.uuid = BLE_UUID16_DECLARE(0x1979),
|
.uuid = BLE_UUID16_DECLARE(0x1979),
|
||||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
|
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
|
||||||
.access_cb = capa_read,
|
.access_cb = capa_read,
|
||||||
|
.val_handle = &g_capa_char_val_handle,
|
||||||
.descriptors = char_0x1979_desc,
|
.descriptors = char_0x1979_desc,
|
||||||
},
|
},
|
||||||
{0}},
|
{0}},
|
||||||
@@ -118,6 +122,32 @@ static int ble_gap_event(struct ble_gap_event *event, void *arg)
|
|||||||
ble_app_advertise();
|
ble_app_advertise();
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user