diff --git a/main/ble.c b/main/ble.c index 57564ad..f48b41a 100644 --- a/main/ble.c +++ b/main/ble.c @@ -30,13 +30,20 @@ static const ble_uuid128_t midi_chr_uuid = BLE_UUID128_INIT( 0xf3, 0x6b, 0x10, 0x9d, 0x66, 0xf2, 0xa9, 0xa1, 0x12, 0x41, 0x68, 0x38, 0xdb, 0xe5, 0x72, 0x77); +#define MAX_CONNECTIONS 2 + static EventGroupHandle_t ble_events; static QueueHandle_t cmd_queue; -static uint16_t conn_hdl = BLE_HS_CONN_HANDLE_NONE; static uint16_t midi_val_hdl; static uint16_t hid_input_val_hdl; -static bool midi_notify_en; -static bool hid_notify_en; + +static struct { + uint16_t hdl; + bool midi_notify; + bool hid_notify; +} conns[MAX_CONNECTIONS]; + +static int conn_count; /* ---- HID keyboard report map ---- */ @@ -436,14 +443,19 @@ static const struct ble_gatt_svc_def gatt_svcs[] = { /* ---- send empty keyboard report ---- */ -static void send_empty_hid_report(void) +static int conn_find(uint16_t hdl) +{ + for (int i = 0; i < conn_count; i++) + if (conns[i].hdl == hdl) return i; + return -1; +} + +static void send_empty_hid_report(uint16_t hdl) { - if (conn_hdl == BLE_HS_CONN_HANDLE_NONE || !hid_notify_en) - return; static const uint8_t empty[8] = {0}; struct os_mbuf *om = ble_hs_mbuf_from_flat(empty, sizeof(empty)); if (om) - ble_gatts_notify_custom(conn_hdl, hid_input_val_hdl, om); + ble_gatts_notify_custom(hdl, hid_input_val_hdl, om); } /* ---- GAP / advertising ---- */ @@ -456,33 +468,49 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) switch (event->type) { case BLE_GAP_EVENT_CONNECT: if (event->connect.status == 0) { - conn_hdl = event->connect.conn_handle; + uint16_t hdl = event->connect.conn_handle; + if (conn_count < MAX_CONNECTIONS) { + conns[conn_count].hdl = hdl; + conns[conn_count].midi_notify = false; + conns[conn_count].hid_notify = false; + conn_count++; + } xEventGroupSetBits(ble_events, CONNECTED_BIT); ble_att_set_preferred_mtu(128); - ble_gattc_exchange_mtu(conn_hdl, NULL, NULL); - ble_gap_security_initiate(conn_hdl); - printf("BLE: connected\n"); + ble_gattc_exchange_mtu(hdl, NULL, NULL); + ble_gap_security_initiate(hdl); + printf("BLE: connected (%d/%d)\n", conn_count, MAX_CONNECTIONS); + if (conn_count < MAX_CONNECTIONS) + start_adv(); } else { start_adv(); } break; - case BLE_GAP_EVENT_DISCONNECT: - conn_hdl = BLE_HS_CONN_HANDLE_NONE; - midi_notify_en = false; - hid_notify_en = false; - xEventGroupClearBits(ble_events, CONNECTED_BIT); - printf("BLE: disconnected\n"); + case BLE_GAP_EVENT_DISCONNECT: { + uint16_t hdl = event->disconnect.conn.conn_handle; + int idx = conn_find(hdl); + if (idx >= 0) { + conns[idx] = conns[--conn_count]; + } + if (conn_count == 0) + xEventGroupClearBits(ble_events, CONNECTED_BIT); + printf("BLE: disconnected (%d/%d)\n", conn_count, MAX_CONNECTIONS); start_adv(); break; - case BLE_GAP_EVENT_SUBSCRIBE: - if (event->subscribe.attr_handle == midi_val_hdl) - midi_notify_en = event->subscribe.cur_notify; - if (event->subscribe.attr_handle == hid_input_val_hdl) { - hid_notify_en = event->subscribe.cur_notify; - if (hid_notify_en) - send_empty_hid_report(); + } + case BLE_GAP_EVENT_SUBSCRIBE: { + int idx = conn_find(event->subscribe.conn_handle); + if (idx >= 0) { + if (event->subscribe.attr_handle == midi_val_hdl) + conns[idx].midi_notify = event->subscribe.cur_notify; + if (event->subscribe.attr_handle == hid_input_val_hdl) { + conns[idx].hid_notify = event->subscribe.cur_notify; + if (conns[idx].hid_notify) + send_empty_hid_report(event->subscribe.conn_handle); + } } break; + } case BLE_GAP_EVENT_REPEAT_PAIRING: { struct ble_gap_conn_desc desc; ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc); @@ -547,10 +575,9 @@ static void host_task(void *param) static int send_sysex(const uint8_t *sysex, uint16_t len) { - if (conn_hdl == BLE_HS_CONN_HANDLE_NONE || !midi_notify_en) + if (conn_count == 0) return -1; - /* BLE MIDI SysEx: [header, ts, F0, payload..., ts, F7] */ uint16_t pkt_len = len + 3; uint8_t pkt[80]; if (pkt_len > sizeof(pkt)) @@ -562,10 +589,15 @@ static int send_sysex(const uint8_t *sysex, uint16_t len) pkt[len + 1] = 0x80; pkt[len + 2] = 0xF7; - struct os_mbuf *om = ble_hs_mbuf_from_flat(pkt, pkt_len); - if (!om) return -1; - - return ble_gatts_notify_custom(conn_hdl, midi_val_hdl, om); + int sent = 0; + for (int i = 0; i < conn_count; i++) { + if (!conns[i].midi_notify) continue; + struct os_mbuf *om = ble_hs_mbuf_from_flat(pkt, pkt_len); + if (!om) continue; + if (ble_gatts_notify_custom(conns[i].hdl, midi_val_hdl, om) == 0) + sent++; + } + return sent > 0 ? 0 : -1; } /* ---- public API ---- */ @@ -604,7 +636,7 @@ int ble_init(void) int ble_is_connected(void) { - return conn_hdl != BLE_HS_CONN_HANDLE_NONE; + return conn_count > 0; } void ble_wait_for_connection(void) diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 34efbfa..686f1a4 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -1,6 +1,7 @@ +CONFIG_IDF_TARGET="esp32s3" CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y -CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1 +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=2 CONFIG_BT_NIMBLE_ROLE_PERIPHERAL=y CONFIG_BT_NIMBLE_ROLE_CENTRAL=y CONFIG_BT_NIMBLE_ROLE_OBSERVER=n