1#if defined(ARDUINO_RASPBERRY_PI_PICO_W) && ENABLE_BLE
3#define BTSTACK_FILE__ "gatt_midi.cpp"
26constexpr uint16_t midi_char_value_handle =
28constexpr uint16_t midi_cccd_handle =
32btstack_packet_callback_registration_t hci_event_callback_registration;
37void connection_handler(uint8_t *packet, [[maybe_unused]] uint16_t size) {
40 if (hci_subevent_le_connection_complete_get_status(packet) != 0)
42 uint16_t conn_handle =
43 hci_subevent_le_connection_complete_get_connection_handle(packet);
47void connection_update_handler([[maybe_unused]] uint8_t *packet,
48 [[maybe_unused]] uint16_t size) {
50 "Connection update: status="
51 << hci_subevent_le_connection_update_complete_get_status(packet)
52 <<
", connection interval="
53 << hci_subevent_le_connection_update_complete_get_conn_interval(packet)
54 <<
", connection latency="
55 << hci_subevent_le_connection_update_complete_get_conn_latency(packet)
56 <<
", supervision timeout="
57 << hci_subevent_le_connection_update_complete_get_supervision_timeout(packet));
61void connection_param_req_handler([[maybe_unused]] uint8_t *packet,
62 [[maybe_unused]] uint16_t size) {
64 "Connection parameter request: interval min="
65 << hci_subevent_le_remote_connection_parameter_request_get_interval_min(packet)
67 << hci_subevent_le_remote_connection_parameter_request_get_interval_max(packet)
69 << hci_subevent_le_remote_connection_parameter_request_get_latency(packet)
71 << hci_subevent_le_remote_connection_parameter_request_get_timeout(packet));
75void le_packet_handler(uint8_t *packet, uint16_t size) {
76 uint8_t type = hci_event_le_meta_get_subevent_code(packet);
80 case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
81 connection_handler(packet, size);
83 case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE:
84 connection_update_handler(packet, size);
86 case HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST:
87 connection_param_req_handler(packet, size);
93void gattservice_handler(uint8_t *packet, [[maybe_unused]] uint16_t size) {
94 [[maybe_unused]] uint8_t type =
95 hci_event_gattservice_meta_get_subevent_code(packet);
97 << hex << type << dec <<
")");
100void disconnect_handler(uint8_t *packet, [[maybe_unused]] uint16_t size) {
102 uint16_t conn_handle =
103 hci_event_disconnection_complete_get_connection_handle(packet);
107void mtu_exchange_complete_handler(uint8_t *packet,
108 [[maybe_unused]] uint16_t size) {
110 uint16_t conn_handle = att_event_mtu_exchange_complete_get_handle(packet);
111 uint16_t mtu = att_event_mtu_exchange_complete_get_MTU(packet);
116void gatt_event_mtu_handler(uint8_t *packet, [[maybe_unused]] uint16_t size) {
118 uint16_t conn_handle = gatt_event_mtu_get_handle(packet);
119 uint16_t mtu = gatt_event_mtu_get_MTU(packet);
123void btstack_event_state_handler(uint8_t *packet,
124 [[maybe_unused]] uint16_t size) {
125 if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING)
127 bd_addr_t local_addr;
128 gap_local_bd_addr(local_addr);
129 DEBUGREF(
"BTstack up and running on " << bd_addr_to_str(local_addr));
133void packet_handler(uint8_t packet_type, [[maybe_unused]] uint16_t channel,
134 uint8_t *packet, uint16_t size) {
135 if (packet_type != HCI_EVENT_PACKET)
137 auto type = hci_event_packet_get_type(packet);
141 case HCI_EVENT_LE_META: le_packet_handler(packet, size);
break;
142 case HCI_EVENT_GATTSERVICE_META:
143 gattservice_handler(packet, size);
145 case HCI_EVENT_DISCONNECTION_COMPLETE:
146 disconnect_handler(packet, size);
149 case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
150 mtu_exchange_complete_handler(packet, size);
153 case GATT_EVENT_MTU: gatt_event_mtu_handler(packet, size);
break;
154 case BTSTACK_EVENT_STATE:
155 btstack_event_state_handler(packet, size);
163uint16_t att_read_callback([[maybe_unused]] hci_con_handle_t connection_handle,
165 [[maybe_unused]] uint16_t offset,
166 [[maybe_unused]] uint8_t *buffer,
167 [[maybe_unused]] uint16_t buffer_size) {
168 if (att_handle == midi_char_value_handle)
173int midi_cccd_write(hci_con_handle_t conn_handle, uint8_t *buffer,
174 [[maybe_unused]] uint16_t buffer_size) {
176 bool notify = (little_endian_read_16(buffer, 0) &
177 GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION) != 0;
184int midi_value_write(hci_con_handle_t conn_handle, uint8_t *buffer,
185 uint16_t buffer_size) {
188 auto data_gen = [data {data}]()
mutable {
return std::exchange(data, {}); };
196int att_write_callback(hci_con_handle_t conn_handle, uint16_t att_handle,
197 [[maybe_unused]] uint16_t transaction_mode,
198 uint16_t offset, uint8_t *buffer, uint16_t buffer_size) {
199 DEBUGREF(
"ATT write: handle=" << att_handle <<
", offset=" << offset
200 <<
", size=" << buffer_size);
202 if (transaction_mode != ATT_TRANSACTION_MODE_NONE)
203 return ATT_ERROR_REQUEST_NOT_SUPPORTED;
206 return ATT_ERROR_INVALID_OFFSET;
208 if (att_handle == midi_cccd_handle)
209 return midi_cccd_write(conn_handle, buffer, buffer_size);
211 else if (att_handle == midi_char_value_handle)
212 return midi_value_write(conn_handle, buffer, buffer_size);
216void le_midi_setup(
const BLESettings &ble_settings) {
221 att_server_init(
profile_data, att_read_callback, att_write_callback);
225 hci_event_callback_registration.callback = &packet_handler;
226 hci_add_event_handler(&hci_event_callback_registration);
228 att_server_register_packet_handler(packet_handler);
232btstack_context_callback_registration_t create_context_callback(F &f) {
233 btstack_context_callback_registration_t ret {};
234 ret.callback = +[](
void *context) { (*
static_cast<F *
>(context))(); };
242 cs::midi_ble_btstack::instance = &instance;
243 le_midi_setup(settings);
244 hci_power_control(HCI_POWER_ON);
253 [[maybe_unused]]
const auto t0 = micros();
258 volatile std::atomic_bool notify_done {
false};
262 DEBUGREF(
"notify " << micros() - t0);
265 DEBUGREF(
"notify done " << micros() - t0);
266 notify_done.store(
true, std::memory_order_release);
268 auto send_ctx = create_context_callback(send);
273 DEBUGREF(
"req send " << micros() - t0);
274 auto ret = att_server_request_to_send_notification(&send_ctx,
276 assert(ret == ERROR_CODE_SUCCESS);
278 auto run_ctx = create_context_callback(run);
281 DEBUGREF(
"req main thread " << micros() - t0);
282 btstack_run_loop_execute_on_main_thread(&run_ctx);
284 while (!notify_done.load(std::memory_order_acquire)) tight_loop_contents();
285 DEBUGREF(
"all done " << micros() - t0);
Type definitions and callback interfaces for communication between the low-level BLE stacks and highe...
@ ConsumeImmediately
Buffer is valid only during the callback. Do not keep any pointers to it.
Callable that returns the next chunk of data from a BLE packet when called.
Defines the interface for callback functions registered by the low-level BLE code.
virtual void handleData(BLEConnectionHandle conn_handle, BLEDataGenerator &&data, BLEDataLifetime lifetime)=0
Called by the BLE stack when the central writes data to the MIDI GATT characteristic.
virtual void handleConnect(BLEConnectionHandle conn_handle)=0
Called by the BLE stack when a connection is established.
virtual void handleSubscribe(BLEConnectionHandle conn_handle, BLECharacteristicHandle char_handle, bool notify)=0
Called by the BLE stack when the central subscribes to receive notifications for the MIDI GATT charac...
virtual void handleDisconnect(BLEConnectionHandle conn_handle)=0
Called by the BLE stack when a connection is terminated.
virtual void handleMTU(BLEConnectionHandle conn_handle, uint16_t mtu)=0
Called by the BLE stack when the maximum transmission unit for the connection changes.
const uint8_t profile_data[]
#define ATT_CHARACTERISTIC_7772E5DB_3868_4112_A1A9_F2669D106BF3_01_CLIENT_CONFIGURATION_HANDLE
#define ATT_CHARACTERISTIC_7772E5DB_3868_4112_A1A9_F2669D106BF3_01_VALUE_HANDLE
#define DEBUGREF(x)
Print an expression and its location (file and line number) to the debug output if debugging is enabl...
static in_place_t in_place
bool init(MIDIBLEInstance &instance, BLESettings settings)
constexpr const char * gattservice_event_names[114]
void notify(BLEConnectionHandle conn_handle, BLECharacteristicHandle char_handle, BLEDataView data)
void le_midi_setup_adv(const BLESettings &ble_settings)
constexpr const char * hci_event_names[256]
constexpr const char * le_event_names[42]
Represents a handle to a local GATT characteristic.
Represents a handle to the connection to another device.
Non-owning, std::span-style read-only view of BLE data.
Configuration options for the low-level BLE code.