From 75ba8b6f4a22cff90ebb9b461d3b03bdbd3de8dc Mon Sep 17 00:00:00 2001 From: pszsh Date: Mon, 9 Mar 2026 01:56:29 -0700 Subject: [PATCH] etc --- CMakeLists.txt | 4 +- .../BLEMIDI/BTstack/advertising.cpp | 8 +- MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp | 64 +++--- MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.hpp | 4 + .../BLEMIDI/BTstack/gatt_midi_hog.gatt | 7 +- .../BLEMIDI/BTstack/gatt_midi_hog.h | 201 +++++++++++------- boards/waveshare_rp2350b_plus_w.h | 126 +++++++++++ cs_midi.h | 10 + docs | 2 +- tests/examples/CMakeLists.txt | 8 + .../interfaces/midi_input_callback.cpp | 30 +++ tests/examples/interfaces/midi_output.cpp | 23 ++ .../examples/interfaces/midi_pipes_filter.cpp | 41 ++++ .../interfaces/send_all_midi_messages.cpp | 51 +++++ tests/examples/interfaces/send_midi_notes.cpp | 27 +++ .../examples/output/cc_potentiometer_map.cpp | 30 +++ tests/examples/output/enable_disable.cpp | 32 +++ tests/examples/output/finished_controller.cpp | 32 +++ 18 files changed, 589 insertions(+), 111 deletions(-) create mode 100644 boards/waveshare_rp2350b_plus_w.h create mode 100644 tests/examples/interfaces/midi_input_callback.cpp create mode 100644 tests/examples/interfaces/midi_output.cpp create mode 100644 tests/examples/interfaces/midi_pipes_filter.cpp create mode 100644 tests/examples/interfaces/send_all_midi_messages.cpp create mode 100644 tests/examples/interfaces/send_midi_notes.cpp create mode 100644 tests/examples/output/cc_potentiometer_map.cpp create mode 100644 tests/examples/output/enable_disable.cpp create mode 100644 tests/examples/output/finished_controller.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fa648e7..c7450b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ option(CS_MIDI_BLE "Enable BLE MIDI interface (BTstack)" ON) option(CS_MIDI_USB "Enable USB MIDI interface (TinyUSB)" OFF) option(CS_MIDI_SERIAL "Enable Serial MIDI interface (UART)" OFF) option(CS_MIDI_APPLEMIDI "Enable AppleMIDI interface (RTP-MIDI over WiFi)" OFF) -option(CS_MIDI_HID_MOUSE "Advertise as HID mouse for BLE auto-reconnect" OFF) +option(CS_MIDI_HID_KEYBOARD "HID keyboard + Battery Service for BLE auto-reconnect" OFF) # Core sources — always compiled set(CS_MIDI_CORE_SOURCES @@ -80,7 +80,7 @@ target_compile_definitions(cs_midi PUBLIC $<$:CS_MIDI_USB=1> $<$:CS_MIDI_SERIAL=1> $<$:CS_MIDI_APPLEMIDI=1> - $<$:CS_MIDI_HID_MOUSE=1> + $<$:CS_MIDI_HID_KEYBOARD=1> ) target_link_libraries(cs_midi diff --git a/MIDI_Interfaces/BLEMIDI/BTstack/advertising.cpp b/MIDI_Interfaces/BLEMIDI/BTstack/advertising.cpp index 3c051f1..93e0fcc 100644 --- a/MIDI_Interfaces/BLEMIDI/BTstack/advertising.cpp +++ b/MIDI_Interfaces/BLEMIDI/BTstack/advertising.cpp @@ -8,15 +8,15 @@ namespace cs::midi_ble_btstack { namespace { -#ifdef CS_MIDI_HID_MOUSE +#ifdef CS_MIDI_HID_KEYBOARD uint8_t adv_data[] { // Flags general discoverable 0x02, BLUETOOTH_DATA_TYPE_FLAGS, 0x06, // HID Service UUID (16-bit) 0x03, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, 0x12, 0x18, - // Appearance: Mouse (0x03C2) - 0x03, BLUETOOTH_DATA_TYPE_APPEARANCE, 0xC2, 0x03, + // Appearance: Keyboard (0x03C1) + 0x03, BLUETOOTH_DATA_TYPE_APPEARANCE, 0xC1, 0x03, // MIDI Service UUID (128-bit) 0x11, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS, 0x00, 0xc7, 0xc4, 0x4e, 0xe3, 0x6c, 0x51, 0xa7, 0x33, 0x4b, 0xe8, 0xed, @@ -42,7 +42,7 @@ uint8_t adv_rsp_data[LE_ADVERTISING_DATA_SIZE] { ' ', 'M', 'I', 'D', 'I'}; uint8_t adv_rsp_data_len() { return adv_rsp_data[0] + 1; } -#ifdef CS_MIDI_HID_MOUSE +#ifdef CS_MIDI_HID_KEYBOARD void set_adv_connection_interval(uint16_t, uint16_t) {} #else void set_adv_connection_interval(uint16_t min_itvl, uint16_t max_itvl) { diff --git a/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp b/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp index 8aef9e6..34ca620 100644 --- a/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp +++ b/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp @@ -11,9 +11,10 @@ #include "../BLEAPI.hpp" #include "advertising.hpp" -#ifdef CS_MIDI_HID_MOUSE +#ifdef CS_MIDI_HID_KEYBOARD #include "gatt_midi_hog.h" #include +#include #else #include "gatt_midi.h" #endif @@ -36,34 +37,31 @@ BLESettings settings; btstack_packet_callback_registration_t hci_event_callback_registration; btstack_packet_callback_registration_t sm_event_callback_registration; -#ifdef CS_MIDI_HID_MOUSE -const uint8_t hid_descriptor_mouse[] = { +#ifdef CS_MIDI_HID_KEYBOARD +const uint8_t hid_descriptor_keyboard[] = { 0x05, 0x01, // Usage Page (Generic Desktop) - 0x09, 0x02, // Usage (Mouse) + 0x09, 0x06, // Usage (Keyboard) 0xa1, 0x01, // Collection (Application) 0x85, 0x01, // Report ID 1 - 0x09, 0x01, // Usage (Pointer) - 0xa1, 0x00, // Collection (Physical) - 0x05, 0x09, // Usage Page (Buttons) - 0x19, 0x01, // Usage Minimum (1) - 0x29, 0x03, // Usage Maximum (3) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x95, 0x03, // Report Count (3) - 0x75, 0x01, // Report Size (1) - 0x81, 0x02, // Input (Data,Var,Abs) - 0x95, 0x01, // Report Count (1) - 0x75, 0x05, // Report Size (5) - 0x81, 0x03, // Input (Const,Var,Abs) — padding - 0x05, 0x01, // Usage Page (Generic Desktop) - 0x09, 0x30, // Usage (X) - 0x09, 0x31, // Usage (Y) - 0x15, 0x81, // Logical Minimum (-127) - 0x25, 0x7f, // Logical Maximum (127) - 0x75, 0x08, // Report Size (8) - 0x95, 0x02, // Report Count (2) - 0x81, 0x06, // Input (Data,Var,Rel) - 0xc0, // End Collection + 0x05, 0x07, // Usage Page (Keyboard/Keypad) + 0x19, 0xe0, // Usage Minimum (Left Control) + 0x29, 0xe7, // Usage Maximum (Right GUI) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x81, 0x02, // Input (Data,Var,Abs) — modifiers + 0x95, 0x01, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x01, // Input (Const) — reserved + 0x95, 0x06, // Report Count (6) + 0x75, 0x08, // Report Size (8) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xff, 0x00, // Logical Maximum (255) + 0x05, 0x07, // Usage Page (Keyboard/Keypad) + 0x19, 0x00, // Usage Minimum (0) + 0x29, 0xff, // Usage Maximum (255) + 0x81, 0x00, // Input (Data,Ary,Abs) — 6KRO keycodes 0xc0 // End Collection }; @@ -73,7 +71,6 @@ constexpr uint16_t gap_device_name_handle = void hid_packet_handler(uint8_t packet_type, uint16_t, uint8_t *packet, uint16_t) { if (packet_type != HCI_EVENT_PACKET) return; if (hci_event_packet_get_type(packet) != HCI_EVENT_HIDS_META) return; - // Accept HID events but never send mouse reports } #endif @@ -225,7 +222,7 @@ uint16_t att_read_callback([[maybe_unused]] hci_con_handle_t connection_handle, [[maybe_unused]] uint16_t offset, [[maybe_unused]] uint8_t *buffer, [[maybe_unused]] uint16_t buffer_size) { -#ifdef CS_MIDI_HID_MOUSE +#ifdef CS_MIDI_HID_KEYBOARD if (att_handle == gap_device_name_handle) { const char *name = settings.device_name; auto len = static_cast(std::strlen(name)); @@ -294,9 +291,10 @@ void le_midi_setup(const BLESettings &ble_settings) { SM_AUTHREQ_BONDING); // setup ATT server att_server_init(profile_data, att_read_callback, att_write_callback); -#ifdef CS_MIDI_HID_MOUSE - hids_device_init(0, hid_descriptor_mouse, sizeof(hid_descriptor_mouse)); +#ifdef CS_MIDI_HID_KEYBOARD + hids_device_init(0, hid_descriptor_keyboard, sizeof(hid_descriptor_keyboard)); hids_device_register_packet_handler(hid_packet_handler); + battery_service_server_init(100); #endif // setup advertisements le_midi_setup_adv(ble_settings); @@ -368,4 +366,10 @@ void notify(BLEConnectionHandle conn_handle, DEBUGREF("all done " << micros() - t0); } +#ifdef CS_MIDI_HID_KEYBOARD +void set_battery_level(uint8_t percent) { + battery_service_server_set_battery_value(percent); +} +#endif + } // namespace cs::midi_ble_btstack \ No newline at end of file diff --git a/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.hpp b/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.hpp index b927a2e..7761341 100644 --- a/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.hpp +++ b/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.hpp @@ -8,4 +8,8 @@ bool init(MIDIBLEInstance &instance, BLESettings settings); void notify(BLEConnectionHandle conn_handle, BLECharacteristicHandle char_handle, BLEDataView data); +#ifdef CS_MIDI_HID_KEYBOARD +void set_battery_level(uint8_t percent); +#endif + } // namespace cs::midi_ble_btstack diff --git a/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi_hog.gatt b/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi_hog.gatt index e505a1b..90b8297 100644 --- a/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi_hog.gatt +++ b/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi_hog.gatt @@ -3,8 +3,8 @@ CHARACTERISTIC, GATT_DATABASE_HASH, READ, PRIMARY_SERVICE, GAP_SERVICE CHARACTERISTIC, GAP_DEVICE_NAME, READ | DYNAMIC, -// 0x03C2 = HID Mouse -CHARACTERISTIC, GAP_APPEARANCE, READ, C2 03 +// 0x03C1 = HID Keyboard +CHARACTERISTIC, GAP_APPEARANCE, READ, C1 03 // MIDI Service PRIMARY_SERVICE, 03B80E5A-EDE8-4B33-A751-6CE34EC4C700 @@ -12,3 +12,6 @@ CHARACTERISTIC, 7772E5DB-3868-4112-A1A9-F2669D106BF3, READ | WRITE_WITHOUT_RESPO // HID Service #import + +// Battery Service +#import diff --git a/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi_hog.h b/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi_hog.h index 60de924..c8d7af8 100644 --- a/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi_hog.h +++ b/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi_hog.h @@ -1,12 +1,19 @@ -// Generated from gatt_midi_hog.gatt — MIDI + HoG Mouse combined GATT database -// Regenerate: compile_gatt.py gatt_midi_hog.gatt gatt_midi_hog.h + +// clang-format off +// gatt_midi_hog.h generated from gatt_midi_hog.gatt for BTstack +// it needs to be regenerated when the .gatt file is updated. + +// To generate gatt_midi_hog.h: +// compile_gatt.py gatt_midi_hog.gatt gatt_midi_hog.h // att db format version 1 + // binary attribute representation: // - size in bytes (16), flags(16), handle (16), uuid (16/128), value(...) #include +// Reference: https://en.cppreference.com/w/cpp/feature_test #if __cplusplus >= 200704L constexpr #endif @@ -16,92 +23,136 @@ const uint8_t profile_data[] = 1, // 0x0001 PRIMARY_SERVICE-GATT_SERVICE - 0x0a, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x28, 0x01, 0x18, + 0x0a, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x28, 0x01, 0x18, // 0x0002 CHARACTERISTIC-GATT_DATABASE_HASH - READ - 0x0d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x28, 0x02, 0x03, 0x00, 0x2a, 0x2b, - // 0x0003 VALUE CHARACTERISTIC-GATT_DATABASE_HASH - READ - 0x18, 0x00, 0x02, 0x00, 0x03, 0x00, 0x2a, 0x2b, 0xce, 0x0f, 0xc6, 0xd0, 0xa1, 0x9c, 0xd7, 0xa2, 0x98, 0xad, 0x7d, 0x4c, 0x9c, 0x85, 0xed, 0x81, - + 0x0d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x28, 0x02, 0x03, 0x00, 0x2a, 0x2b, + // 0x0003 VALUE CHARACTERISTIC-GATT_DATABASE_HASH - READ -'' + // READ_ANYBODY + 0x18, 0x00, 0x02, 0x00, 0x03, 0x00, 0x2a, 0x2b, 0xab, 0x5a, 0x3b, 0x8c, 0x3f, 0x95, 0x12, 0x5d, 0x5a, 0xa5, 0x27, 0xb7, 0x75, 0x27, 0xfc, 0x2b, // 0x0004 PRIMARY_SERVICE-GAP_SERVICE - 0x0a, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x28, 0x00, 0x18, + 0x0a, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x28, 0x00, 0x18, // 0x0005 CHARACTERISTIC-GAP_DEVICE_NAME - READ | DYNAMIC - 0x0d, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x28, 0x02, 0x06, 0x00, 0x00, 0x2a, + 0x0d, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x28, 0x02, 0x06, 0x00, 0x00, 0x2a, // 0x0006 VALUE CHARACTERISTIC-GAP_DEVICE_NAME - READ | DYNAMIC - 0x08, 0x00, 0x02, 0x01, 0x06, 0x00, 0x00, 0x2a, - // 0x0007 CHARACTERISTIC-GAP_APPEARANCE - READ - Mouse (0x03C2) - 0x0d, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x28, 0x02, 0x08, 0x00, 0x01, 0x2a, - // 0x0008 VALUE CHARACTERISTIC-GAP_APPEARANCE - READ - 0x0a, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x2a, 0xC2, 0x03, - + // READ_ANYBODY + 0x08, 0x00, 0x02, 0x01, 0x06, 0x00, 0x00, 0x2a, + // 0x03C1 = HID Keyboard + // 0x0007 CHARACTERISTIC-GAP_APPEARANCE - READ + 0x0d, 0x00, 0x02, 0x00, 0x07, 0x00, 0x03, 0x28, 0x02, 0x08, 0x00, 0x01, 0x2a, + // 0x0008 VALUE CHARACTERISTIC-GAP_APPEARANCE - READ -'C1 03' + // READ_ANYBODY + 0x0a, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x2a, 0xC1, 0x03, // MIDI Service // 0x0009 PRIMARY_SERVICE-03B80E5A-EDE8-4B33-A751-6CE34EC4C700 - 0x18, 0x00, 0x02, 0x00, 0x09, 0x00, 0x00, 0x28, 0x00, 0xc7, 0xc4, 0x4e, 0xe3, 0x6c, 0x51, 0xa7, 0x33, 0x4b, 0xe8, 0xed, 0x5a, 0x0e, 0xb8, 0x03, + 0x18, 0x00, 0x02, 0x00, 0x09, 0x00, 0x00, 0x28, 0x00, 0xc7, 0xc4, 0x4e, 0xe3, 0x6c, 0x51, 0xa7, 0x33, 0x4b, 0xe8, 0xed, 0x5a, 0x0e, 0xb8, 0x03, // 0x000a CHARACTERISTIC-7772E5DB-3868-4112-A1A9-F2669D106BF3 - READ | WRITE_WITHOUT_RESPONSE | NOTIFY | DYNAMIC - 0x1b, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x03, 0x28, 0x16, 0x0b, 0x00, 0xf3, 0x6b, 0x10, 0x9d, 0x66, 0xf2, 0xa9, 0xa1, 0x12, 0x41, 0x68, 0x38, 0xdb, 0xe5, 0x72, 0x77, + 0x1b, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x03, 0x28, 0x16, 0x0b, 0x00, 0xf3, 0x6b, 0x10, 0x9d, 0x66, 0xf2, 0xa9, 0xa1, 0x12, 0x41, 0x68, 0x38, 0xdb, 0xe5, 0x72, 0x77, // 0x000b VALUE CHARACTERISTIC-7772E5DB-3868-4112-A1A9-F2669D106BF3 - READ | WRITE_WITHOUT_RESPONSE | NOTIFY | DYNAMIC - 0x16, 0x00, 0x06, 0x03, 0x0b, 0x00, 0xf3, 0x6b, 0x10, 0x9d, 0x66, 0xf2, 0xa9, 0xa1, 0x12, 0x41, 0x68, 0x38, 0xdb, 0xe5, 0x72, 0x77, + // READ_ANYBODY, WRITE_ANYBODY + 0x16, 0x00, 0x06, 0x03, 0x0b, 0x00, 0xf3, 0x6b, 0x10, 0x9d, 0x66, 0xf2, 0xa9, 0xa1, 0x12, 0x41, 0x68, 0x38, 0xdb, 0xe5, 0x72, 0x77, // 0x000c CLIENT_CHARACTERISTIC_CONFIGURATION - 0x0a, 0x00, 0x0e, 0x01, 0x0c, 0x00, 0x02, 0x29, 0x00, 0x00, + // READ_ANYBODY, WRITE_ANYBODY + 0x0a, 0x00, 0x0e, 0x01, 0x0c, 0x00, 0x02, 0x29, 0x00, 0x00, + // HID Service - // HID Service (hids.gatt) + + // #import -- BEGIN + // Specification Type org.bluetooth.service.human_interface_device + // https://www.bluetooth.com/api/gatt/xmlfile?xmlFileName=org.bluetooth.service.human_interface_device.xml + // Human Interface Device 1812 // 0x000d PRIMARY_SERVICE-ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE - 0x0a, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x00, 0x28, 0x12, 0x18, - // 0x000e CHARACTERISTIC-PROTOCOL_MODE - DYNAMIC | READ | WRITE_WITHOUT_RESPONSE - 0x0d, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x03, 0x28, 0x06, 0x0f, 0x00, 0x4e, 0x2a, - // 0x000f VALUE CHARACTERISTIC-PROTOCOL_MODE - 0x08, 0x00, 0x06, 0x01, 0x0f, 0x00, 0x4e, 0x2a, - // 0x0010 CHARACTERISTIC-REPORT (Input, ID=1) - DYNAMIC | READ | WRITE | NOTIFY | ENCRYPTION_KEY_SIZE_16 - 0x0d, 0x00, 0x02, 0x00, 0x10, 0x00, 0x03, 0x28, 0x1a, 0x11, 0x00, 0x4d, 0x2a, - // 0x0011 VALUE CHARACTERISTIC-REPORT - 0x08, 0x00, 0x0b, 0xf5, 0x11, 0x00, 0x4d, 0x2a, + 0x0a, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x00, 0x28, 0x12, 0x18, + // 0x000e CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_PROTOCOL_MODE - DYNAMIC | READ | WRITE_WITHOUT_RESPONSE + 0x0d, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x03, 0x28, 0x06, 0x0f, 0x00, 0x4e, 0x2a, + // 0x000f VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_PROTOCOL_MODE - DYNAMIC | READ | WRITE_WITHOUT_RESPONSE + // READ_ANYBODY, WRITE_ANYBODY + 0x08, 0x00, 0x06, 0x01, 0x0f, 0x00, 0x4e, 0x2a, + // 0x0010 CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_REPORT - DYNAMIC | READ | WRITE | NOTIFY | ENCRYPTION_KEY_SIZE_16 + 0x0d, 0x00, 0x02, 0x00, 0x10, 0x00, 0x03, 0x28, 0x1a, 0x11, 0x00, 0x4d, 0x2a, + // 0x0011 VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_REPORT - DYNAMIC | READ | WRITE | NOTIFY | ENCRYPTION_KEY_SIZE_16 + // READ_ENCRYPTED, WRITE_ENCRYPTED, ENCRYPTION_KEY_SIZE=16 + 0x08, 0x00, 0x0b, 0xf5, 0x11, 0x00, 0x4d, 0x2a, // 0x0012 CLIENT_CHARACTERISTIC_CONFIGURATION - 0x0a, 0x00, 0x0f, 0xf1, 0x12, 0x00, 0x02, 0x29, 0x00, 0x00, - // 0x0013 REPORT_REFERENCE - Report ID=1, Type=Input(1) - 0x0a, 0x00, 0x02, 0x00, 0x13, 0x00, 0x08, 0x29, 0x1, 0x1, - // 0x0014 CHARACTERISTIC-REPORT (Output, ID=2) - DYNAMIC | READ | WRITE | WRITE_WITHOUT_RESPONSE | ENCRYPTION_KEY_SIZE_16 - 0x0d, 0x00, 0x02, 0x00, 0x14, 0x00, 0x03, 0x28, 0x0e, 0x15, 0x00, 0x4d, 0x2a, - // 0x0015 VALUE CHARACTERISTIC-REPORT - 0x08, 0x00, 0x0f, 0xf5, 0x15, 0x00, 0x4d, 0x2a, - // 0x0016 REPORT_REFERENCE - Report ID=2, Type=Output(2) - 0x0a, 0x00, 0x02, 0x00, 0x16, 0x00, 0x08, 0x29, 0x2, 0x2, - // 0x0017 CHARACTERISTIC-REPORT (Feature, ID=3) - DYNAMIC | READ | WRITE | ENCRYPTION_KEY_SIZE_16 - 0x0d, 0x00, 0x02, 0x00, 0x17, 0x00, 0x03, 0x28, 0x0a, 0x18, 0x00, 0x4d, 0x2a, - // 0x0018 VALUE CHARACTERISTIC-REPORT - 0x08, 0x00, 0x0b, 0xf5, 0x18, 0x00, 0x4d, 0x2a, - // 0x0019 REPORT_REFERENCE - Report ID=3, Type=Feature(3) - 0x0a, 0x00, 0x02, 0x00, 0x19, 0x00, 0x08, 0x29, 0x3, 0x3, - // 0x001a CHARACTERISTIC-REPORT_MAP - DYNAMIC | READ - 0x0d, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x03, 0x28, 0x02, 0x1b, 0x00, 0x4b, 0x2a, - // 0x001b VALUE CHARACTERISTIC-REPORT_MAP - 0x08, 0x00, 0x02, 0x01, 0x1b, 0x00, 0x4b, 0x2a, - // 0x001c CHARACTERISTIC-BOOT_KEYBOARD_INPUT_REPORT - DYNAMIC | READ | WRITE | NOTIFY - 0x0d, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x03, 0x28, 0x1a, 0x1d, 0x00, 0x22, 0x2a, - // 0x001d VALUE CHARACTERISTIC-BOOT_KEYBOARD_INPUT_REPORT - 0x08, 0x00, 0x0a, 0x01, 0x1d, 0x00, 0x22, 0x2a, + // READ_ANYBODY, WRITE_ENCRYPTED, ENCRYPTION_KEY_SIZE=16 + 0x0a, 0x00, 0x0f, 0xf1, 0x12, 0x00, 0x02, 0x29, 0x00, 0x00, + // fixed report id = 1, type = Input (1) + // 0x0013 REPORT_REFERENCE-READ-1-1 + 0x0a, 0x00, 0x02, 0x00, 0x13, 0x00, 0x08, 0x29, 0x1, 0x1, + // 0x0014 CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_REPORT - DYNAMIC | READ | WRITE | WRITE_WITHOUT_RESPONSE | ENCRYPTION_KEY_SIZE_16 + 0x0d, 0x00, 0x02, 0x00, 0x14, 0x00, 0x03, 0x28, 0x0e, 0x15, 0x00, 0x4d, 0x2a, + // 0x0015 VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_REPORT - DYNAMIC | READ | WRITE | WRITE_WITHOUT_RESPONSE | ENCRYPTION_KEY_SIZE_16 + // READ_ENCRYPTED, WRITE_ENCRYPTED, ENCRYPTION_KEY_SIZE=16 + 0x08, 0x00, 0x0f, 0xf5, 0x15, 0x00, 0x4d, 0x2a, + // fixed report id = 2, type = Output (2) + // 0x0016 REPORT_REFERENCE-READ-2-2 + 0x0a, 0x00, 0x02, 0x00, 0x16, 0x00, 0x08, 0x29, 0x2, 0x2, + // 0x0017 CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_REPORT - DYNAMIC | READ | WRITE | ENCRYPTION_KEY_SIZE_16 + 0x0d, 0x00, 0x02, 0x00, 0x17, 0x00, 0x03, 0x28, 0x0a, 0x18, 0x00, 0x4d, 0x2a, + // 0x0018 VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_REPORT - DYNAMIC | READ | WRITE | ENCRYPTION_KEY_SIZE_16 + // READ_ENCRYPTED, WRITE_ENCRYPTED, ENCRYPTION_KEY_SIZE=16 + 0x08, 0x00, 0x0b, 0xf5, 0x18, 0x00, 0x4d, 0x2a, + // fixed report id = 3, type = Feature (3) + // 0x0019 REPORT_REFERENCE-READ-3-3 + 0x0a, 0x00, 0x02, 0x00, 0x19, 0x00, 0x08, 0x29, 0x3, 0x3, + // 0x001a CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_REPORT_MAP - DYNAMIC | READ + 0x0d, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x03, 0x28, 0x02, 0x1b, 0x00, 0x4b, 0x2a, + // 0x001b VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_REPORT_MAP - DYNAMIC | READ + // READ_ANYBODY + 0x08, 0x00, 0x02, 0x01, 0x1b, 0x00, 0x4b, 0x2a, + // 0x001c CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT - DYNAMIC | READ | WRITE | NOTIFY + 0x0d, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x03, 0x28, 0x1a, 0x1d, 0x00, 0x22, 0x2a, + // 0x001d VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_INPUT_REPORT - DYNAMIC | READ | WRITE | NOTIFY + // READ_ANYBODY, WRITE_ANYBODY + 0x08, 0x00, 0x0a, 0x01, 0x1d, 0x00, 0x22, 0x2a, // 0x001e CLIENT_CHARACTERISTIC_CONFIGURATION - 0x0a, 0x00, 0x0e, 0x01, 0x1e, 0x00, 0x02, 0x29, 0x00, 0x00, - // 0x001f CHARACTERISTIC-BOOT_KEYBOARD_OUTPUT_REPORT - DYNAMIC | READ | WRITE | WRITE_WITHOUT_RESPONSE - 0x0d, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x03, 0x28, 0x0e, 0x20, 0x00, 0x32, 0x2a, - // 0x0020 VALUE CHARACTERISTIC-BOOT_KEYBOARD_OUTPUT_REPORT - 0x08, 0x00, 0x0e, 0x01, 0x20, 0x00, 0x32, 0x2a, - // 0x0021 CHARACTERISTIC-BOOT_MOUSE_INPUT_REPORT - DYNAMIC | READ | WRITE | NOTIFY - 0x0d, 0x00, 0x02, 0x00, 0x21, 0x00, 0x03, 0x28, 0x1a, 0x22, 0x00, 0x33, 0x2a, - // 0x0022 VALUE CHARACTERISTIC-BOOT_MOUSE_INPUT_REPORT - 0x08, 0x00, 0x0a, 0x01, 0x22, 0x00, 0x33, 0x2a, + // READ_ANYBODY, WRITE_ANYBODY + 0x0a, 0x00, 0x0e, 0x01, 0x1e, 0x00, 0x02, 0x29, 0x00, 0x00, + // 0x001f CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_OUTPUT_REPORT - DYNAMIC | READ | WRITE | WRITE_WITHOUT_RESPONSE + 0x0d, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x03, 0x28, 0x0e, 0x20, 0x00, 0x32, 0x2a, + // 0x0020 VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_BOOT_KEYBOARD_OUTPUT_REPORT - DYNAMIC | READ | WRITE | WRITE_WITHOUT_RESPONSE + // READ_ANYBODY, WRITE_ANYBODY + 0x08, 0x00, 0x0e, 0x01, 0x20, 0x00, 0x32, 0x2a, + // 0x0021 CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT - DYNAMIC | READ | WRITE | NOTIFY + 0x0d, 0x00, 0x02, 0x00, 0x21, 0x00, 0x03, 0x28, 0x1a, 0x22, 0x00, 0x33, 0x2a, + // 0x0022 VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT - DYNAMIC | READ | WRITE | NOTIFY + // READ_ANYBODY, WRITE_ANYBODY + 0x08, 0x00, 0x0a, 0x01, 0x22, 0x00, 0x33, 0x2a, // 0x0023 CLIENT_CHARACTERISTIC_CONFIGURATION - 0x0a, 0x00, 0x0e, 0x01, 0x23, 0x00, 0x02, 0x29, 0x00, 0x00, - // 0x0024 CHARACTERISTIC-HID_INFORMATION - READ - 0x0d, 0x00, 0x02, 0x00, 0x24, 0x00, 0x03, 0x28, 0x02, 0x25, 0x00, 0x4a, 0x2a, - // 0x0025 VALUE CHARACTERISTIC-HID_INFORMATION - bcdHID=0x0101, country=0, flags=0x02 - 0x0c, 0x00, 0x02, 0x00, 0x25, 0x00, 0x4a, 0x2a, 0x01, 0x01, 0x00, 0x02, - // 0x0026 CHARACTERISTIC-HID_CONTROL_POINT - DYNAMIC | WRITE_WITHOUT_RESPONSE - 0x0d, 0x00, 0x02, 0x00, 0x26, 0x00, 0x03, 0x28, 0x04, 0x27, 0x00, 0x4c, 0x2a, - // 0x0027 VALUE CHARACTERISTIC-HID_CONTROL_POINT - 0x08, 0x00, 0x04, 0x01, 0x27, 0x00, 0x4c, 0x2a, + // READ_ANYBODY, WRITE_ANYBODY + 0x0a, 0x00, 0x0e, 0x01, 0x23, 0x00, 0x02, 0x29, 0x00, 0x00, + // bcdHID = 0x101 (v1.0.1), bCountryCode 0, remote wakeable = 0 | normally connectable 2 + // 0x0024 CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_HID_INFORMATION - READ + 0x0d, 0x00, 0x02, 0x00, 0x24, 0x00, 0x03, 0x28, 0x02, 0x25, 0x00, 0x4a, 0x2a, + // 0x0025 VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_HID_INFORMATION - READ -'01 01 00 02' + // READ_ANYBODY + 0x0c, 0x00, 0x02, 0x00, 0x25, 0x00, 0x4a, 0x2a, 0x01, 0x01, 0x00, 0x02, + // 0x0026 CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_HID_CONTROL_POINT - DYNAMIC | WRITE_WITHOUT_RESPONSE + 0x0d, 0x00, 0x02, 0x00, 0x26, 0x00, 0x03, 0x28, 0x04, 0x27, 0x00, 0x4c, 0x2a, + // 0x0027 VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_HID_CONTROL_POINT - DYNAMIC | WRITE_WITHOUT_RESPONSE + // WRITE_ANYBODY + 0x08, 0x00, 0x04, 0x01, 0x27, 0x00, 0x4c, 0x2a, + // #import -- END + // Battery Service + + // #import -- BEGIN + // Specification Type org.bluetooth.service.battery_service + // https://www.bluetooth.com/api/gatt/xmlfile?xmlFileName=org.bluetooth.service.battery_service.xml + // Battery Service 180F + // 0x0028 PRIMARY_SERVICE-ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE + 0x0a, 0x00, 0x02, 0x00, 0x28, 0x00, 0x00, 0x28, 0x0f, 0x18, + // 0x0029 CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL - DYNAMIC | READ | NOTIFY + 0x0d, 0x00, 0x02, 0x00, 0x29, 0x00, 0x03, 0x28, 0x12, 0x2a, 0x00, 0x19, 0x2a, + // 0x002a VALUE CHARACTERISTIC-ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL - DYNAMIC | READ | NOTIFY + // READ_ANYBODY + 0x08, 0x00, 0x02, 0x01, 0x2a, 0x00, 0x19, 0x2a, + // 0x002b CLIENT_CHARACTERISTIC_CONFIGURATION + // READ_ANYBODY, WRITE_ANYBODY + 0x0a, 0x00, 0x0e, 0x01, 0x2b, 0x00, 0x02, 0x29, 0x00, 0x00, + // #import -- END // END - 0x00, 0x00, -}; // total size 252 bytes + 0x00, 0x00, +}; // total size 275 bytes // @@ -123,6 +174,10 @@ const uint8_t profile_data[] = #define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE_END_HANDLE 0x0027 #define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE_01_START_HANDLE 0x000d #define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE_01_END_HANDLE 0x0027 +#define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE_START_HANDLE 0x0028 +#define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE_END_HANDLE 0x002b +#define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE_01_START_HANDLE 0x0028 +#define ATT_SERVICE_ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE_01_END_HANDLE 0x002b // // list mapping between characteristics and handles @@ -145,3 +200,5 @@ const uint8_t profile_data[] = #define ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_BOOT_MOUSE_INPUT_REPORT_01_CLIENT_CONFIGURATION_HANDLE 0x0023 #define ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_HID_INFORMATION_01_VALUE_HANDLE 0x0025 #define ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_HID_CONTROL_POINT_01_VALUE_HANDLE 0x0027 +#define ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL_01_VALUE_HANDLE 0x002a +#define ATT_CHARACTERISTIC_ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL_01_CLIENT_CONFIGURATION_HANDLE 0x002b diff --git a/boards/waveshare_rp2350b_plus_w.h b/boards/waveshare_rp2350b_plus_w.h new file mode 100644 index 0000000..022778b --- /dev/null +++ b/boards/waveshare_rp2350b_plus_w.h @@ -0,0 +1,126 @@ +#ifndef _BOARDS_WAVESHARE_RP2350B_PLUS_W_H +#define _BOARDS_WAVESHARE_RP2350B_PLUS_W_H + +pico_board_cmake_set(PICO_PLATFORM, rp2350) +pico_board_cmake_set(PICO_CYW43_SUPPORTED, 1) + +#define WAVESHARE_RP2350B_PLUS_W + +// --- RP2350 VARIANT --- +#define PICO_RP2350A 0 + +// --- UART --- +#ifndef PICO_DEFAULT_UART +#define PICO_DEFAULT_UART 0 +#endif +#ifndef PICO_DEFAULT_UART_TX_PIN +#define PICO_DEFAULT_UART_TX_PIN 0 +#endif +#ifndef PICO_DEFAULT_UART_RX_PIN +#define PICO_DEFAULT_UART_RX_PIN 1 +#endif + +// --- LED --- +#ifndef PICO_DEFAULT_LED_PIN +#define PICO_DEFAULT_LED_PIN 23 +#endif + +// --- I2C --- +#ifndef PICO_DEFAULT_I2C +#define PICO_DEFAULT_I2C 1 +#endif +#ifndef PICO_DEFAULT_I2C_SDA_PIN +#define PICO_DEFAULT_I2C_SDA_PIN 6 +#endif +#ifndef PICO_DEFAULT_I2C_SCL_PIN +#define PICO_DEFAULT_I2C_SCL_PIN 7 +#endif + +// --- SPI --- +#ifndef PICO_DEFAULT_SPI +#define PICO_DEFAULT_SPI 0 +#endif +#ifndef PICO_DEFAULT_SPI_SCK_PIN +#define PICO_DEFAULT_SPI_SCK_PIN 18 +#endif +#ifndef PICO_DEFAULT_SPI_TX_PIN +#define PICO_DEFAULT_SPI_TX_PIN 19 +#endif +#ifndef PICO_DEFAULT_SPI_RX_PIN +#define PICO_DEFAULT_SPI_RX_PIN 16 +#endif +#ifndef PICO_DEFAULT_SPI_CSN_PIN +#define PICO_DEFAULT_SPI_CSN_PIN 17 +#endif + +// --- FLASH --- +#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1 + +#ifndef PICO_FLASH_SPI_CLKDIV +#define PICO_FLASH_SPI_CLKDIV 2 +#endif + +pico_board_cmake_set_default(PICO_FLASH_SIZE_BYTES, (16 * 1024 * 1024)) +#ifndef PICO_FLASH_SIZE_BYTES +#define PICO_FLASH_SIZE_BYTES (16 * 1024 * 1024) +#endif + +// --- CYW43 (RM2) on B-package extra pins --- +#ifndef CYW43_WL_GPIO_COUNT +#define CYW43_WL_GPIO_COUNT 3 +#endif + +#ifndef CYW43_WL_GPIO_LED_PIN +#define CYW43_WL_GPIO_LED_PIN 0 +#endif + +#ifndef CYW43_WL_GPIO_SMPS_PIN +#define CYW43_WL_GPIO_SMPS_PIN 1 +#endif + +#ifndef CYW43_WL_GPIO_VBUS_PIN +#define CYW43_WL_GPIO_VBUS_PIN 2 +#endif + +#ifndef CYW43_USES_VSYS_PIN +#define CYW43_USES_VSYS_PIN 1 +#endif + +#ifndef PICO_VSYS_PIN +#define PICO_VSYS_PIN 29 +#endif + +#ifndef CYW43_PIN_WL_DYNAMIC +#define CYW43_PIN_WL_DYNAMIC 0 +#endif + +#ifndef CYW43_DEFAULT_PIN_WL_REG_ON +#define CYW43_DEFAULT_PIN_WL_REG_ON 36u +#endif + +#ifndef CYW43_DEFAULT_PIN_WL_DATA_OUT +#define CYW43_DEFAULT_PIN_WL_DATA_OUT 37u +#endif + +#ifndef CYW43_DEFAULT_PIN_WL_DATA_IN +#define CYW43_DEFAULT_PIN_WL_DATA_IN 37u +#endif + +#ifndef CYW43_DEFAULT_PIN_WL_HOST_WAKE +#define CYW43_DEFAULT_PIN_WL_HOST_WAKE 37u +#endif + +#ifndef CYW43_DEFAULT_PIN_WL_CLOCK +#define CYW43_DEFAULT_PIN_WL_CLOCK 39u +#endif + +#ifndef CYW43_DEFAULT_PIN_WL_CS +#define CYW43_DEFAULT_PIN_WL_CS 38u +#endif + +pico_board_cmake_set_default(PICO_RP2350_A2_SUPPORTED, 1) +#ifndef PICO_RP2350_A2_SUPPORTED +#define PICO_RP2350_A2_SUPPORTED 1 +#endif + +#endif diff --git a/cs_midi.h b/cs_midi.h index 91b99bc..6ba97e2 100644 --- a/cs_midi.h +++ b/cs_midi.h @@ -23,6 +23,7 @@ // MIDI interfaces — common #include +#include // MIDI interfaces — transport-specific #ifdef CS_MIDI_BLE @@ -93,4 +94,13 @@ using BluetoothMIDI_Interface = GenericBLEMIDI_Interface; #endif +#if defined(CS_MIDI_HID_KEYBOARD) && defined(CS_MIDI_BLE) +namespace midi_ble_btstack { +void set_battery_level(uint8_t percent); +} +inline void setBLEBatteryLevel(uint8_t percent) { + midi_ble_btstack::set_battery_level(percent); +} +#endif + END_CS_NAMESPACE diff --git a/docs b/docs index 3927d07..be1ee30 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 3927d073e938973be113ee08db4e596c7d853ad3 +Subproject commit be1ee309670a861adca5fb8f46aefe6a723a6bb4 diff --git a/tests/examples/CMakeLists.txt b/tests/examples/CMakeLists.txt index ffa2a62..43307ba 100644 --- a/tests/examples/CMakeLists.txt +++ b/tests/examples/CMakeLists.txt @@ -69,6 +69,9 @@ set(EXAMPLE_SOURCES output/program_changer.cpp output/cc_potentiometers.cpp output/borrowed_cc_rotary_encoder.cpp + output/cc_potentiometer_map.cpp + output/finished_controller.cpp + output/enable_disable.cpp # Input elements input/note_led.cpp @@ -84,6 +87,11 @@ set(EXAMPLE_SOURCES # Interfaces interfaces/ble_midi.cpp interfaces/midi_pipes.cpp + interfaces/midi_output.cpp + interfaces/send_midi_notes.cpp + interfaces/send_all_midi_messages.cpp + interfaces/midi_input_callback.cpp + interfaces/midi_pipes_filter.cpp # Banks banks/bank_cc_values.cpp diff --git a/tests/examples/interfaces/midi_input_callback.cpp b/tests/examples/interfaces/midi_input_callback.cpp new file mode 100644 index 0000000..b7958aa --- /dev/null +++ b/tests/examples/interfaces/midi_input_callback.cpp @@ -0,0 +1,30 @@ +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +struct MyMIDI_Callbacks : MIDI_Callbacks { + void onChannelMessage(MIDI_Interface &, ChannelMessage msg) override { + (void)msg; + } + void onSysExMessage(MIDI_Interface &, SysExMessage msg) override { + (void)msg; + } + void onRealTimeMessage(MIDI_Interface &, RealTimeMessage msg) override { + (void)msg; + } +} callback; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + midi.begin(); + midi.setCallbacks(callback); + while (true) { + midi.update(); + sleep_ms(1); + } +} diff --git a/tests/examples/interfaces/midi_output.cpp b/tests/examples/interfaces/midi_output.cpp new file mode 100644 index 0000000..832c429 --- /dev/null +++ b/tests/examples/interfaces/midi_output.cpp @@ -0,0 +1,23 @@ +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +const MIDIAddress address {MIDI_Notes::C[4], Channel_1}; +const uint8_t velocity = 0x7F; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + midi.begin(); + while (true) { + midi.sendNoteOn(address, velocity); + sleep_ms(500); + midi.sendNoteOff(address, velocity); + sleep_ms(500); + midi.update(); + } +} diff --git a/tests/examples/interfaces/midi_pipes_filter.cpp b/tests/examples/interfaces/midi_pipes_filter.cpp new file mode 100644 index 0000000..d1d6696 --- /dev/null +++ b/tests/examples/interfaces/midi_pipes_filter.cpp @@ -0,0 +1,41 @@ +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +struct NoteFilter : MIDI_Pipe { + void mapForwardMIDI(ChannelMessage msg) override { + switch (msg.getMessageType()) { + case MIDIMessageType::NoteOff: + case MIDIMessageType::NoteOn: + msg.setChannel(Channel_5); + if (msg.data1 >= 12) + msg.data1 -= 12; + sourceMIDItoSink(msg); + break; + default: + break; + } + } + void mapForwardMIDI(SysExMessage) override {} + void mapForwardMIDI(SysCommonMessage) override {} + void mapForwardMIDI(RealTimeMessage msg) override { + sourceMIDItoSink(msg); + } +}; + +NoteFilter filter; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + midi >> filter >> midi; + midi.begin(); + while (true) { + midi.update(); + sleep_ms(1); + } +} diff --git a/tests/examples/interfaces/send_all_midi_messages.cpp b/tests/examples/interfaces/send_all_midi_messages.cpp new file mode 100644 index 0000000..000a6ac --- /dev/null +++ b/tests/examples/interfaces/send_all_midi_messages.cpp @@ -0,0 +1,51 @@ +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + midi.begin(); + + // Channel voice messages + MIDIAddress note = {MIDI_Notes::C[4], Channel_6}; + midi.sendNoteOn(note, 127); + midi.sendNoteOff(note, 127); + midi.sendKeyPressure(note, 64); + + MIDIAddress controller = {MIDI_CC::Channel_Volume, Channel_2}; + midi.sendControlChange(controller, 120); + + MIDIAddress program = {MIDI_PC::Harpsichord, Channel_9}; + midi.sendProgramChange(program); + + midi.sendChannelPressure(Channel_3, 64); + midi.sendPitchBend(Channel_3, 16383); + + // System common messages + midi.sendMTCQuarterFrame(2, 15); + midi.sendSongPositionPointer(10000); + midi.sendSongSelect(70); + midi.sendTuneRequest(); + + // System exclusive + uint8_t sysex[] = {0xF0, 0x00, 0x01, 0x02, 0x03, 0xF7}; + midi.sendSysEx(sysex); + + // Real-time messages + midi.sendTimingClock(); + midi.sendStart(); + midi.sendContinue(); + midi.sendStop(); + midi.sendActiveSensing(); + midi.sendSystemReset(); + + while (true) { + midi.update(); + sleep_ms(1); + } +} diff --git a/tests/examples/interfaces/send_midi_notes.cpp b/tests/examples/interfaces/send_midi_notes.cpp new file mode 100644 index 0000000..4bc903e --- /dev/null +++ b/tests/examples/interfaces/send_midi_notes.cpp @@ -0,0 +1,27 @@ +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +AH::Button pushbutton {5}; + +const MIDIAddress noteAddress {MIDI_Notes::C[4], Channel_1}; +const uint8_t velocity = 0x7F; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + pushbutton.begin(); + midi.begin(); + while (true) { + midi.update(); + pushbutton.update(); + if (pushbutton.getState() == AH::Button::Falling) + midi.sendNoteOn(noteAddress, velocity); + else if (pushbutton.getState() == AH::Button::Rising) + midi.sendNoteOff(noteAddress, velocity); + } +} diff --git a/tests/examples/output/cc_potentiometer_map.cpp b/tests/examples/output/cc_potentiometer_map.cpp new file mode 100644 index 0000000..2ca3a19 --- /dev/null +++ b/tests/examples/output/cc_potentiometer_map.cpp @@ -0,0 +1,30 @@ +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCPotentiometer potentiometer {26, {MIDI_CC::Channel_Volume, Channel_1}}; + +constexpr analog_t maxRawValue = CCPotentiometer::getMaxRawValue(); +constexpr analog_t minimumValue = maxRawValue / 64; +constexpr analog_t maximumValue = maxRawValue - maxRawValue / 64; + +analog_t mappingFunction(analog_t raw) { + if (raw < minimumValue) raw = minimumValue; + if (raw > maximumValue) raw = maximumValue; + return (raw - minimumValue) * maxRawValue / (maximumValue - minimumValue); +} + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + potentiometer.map(mappingFunction); + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/enable_disable.cpp b/tests/examples/output/enable_disable.cpp new file mode 100644 index 0000000..d1250e4 --- /dev/null +++ b/tests/examples/output/enable_disable.cpp @@ -0,0 +1,32 @@ +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteButton button1 {5, {MIDI_Notes::C[4], Channel_1}}; +NoteButton button2 {6, {MIDI_Notes::D[4], Channel_1}}; +AH::Button toggleBtn {7}; + +bool button2Enabled = true; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + toggleBtn.begin(); + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + toggleBtn.update(); + if (toggleBtn.getState() == AH::Button::Falling) { + button2Enabled = !button2Enabled; + if (button2Enabled) + button2.enable(); + else + button2.disable(); + } + sleep_ms(1); + } +} diff --git a/tests/examples/output/finished_controller.cpp b/tests/examples/output/finished_controller.cpp new file mode 100644 index 0000000..7a36371 --- /dev/null +++ b/tests/examples/output/finished_controller.cpp @@ -0,0 +1,32 @@ +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +// 4 banks, 2 tracks per bank +Bank<4> bank(2); + +// Two buttons to cycle banks +IncrementDecrementSelector<4> bankSelector {bank, {2, 3}, Wrap::Wrap}; + +// Bankable CC value readers — bank switches the CC address +Bankable::CCValue<4> volume1 {{bank, BankType::ChangeAddress}, {16, Channel_1}}; +Bankable::CCValue<4> volume2 {{bank, BankType::ChangeAddress}, {17, Channel_1}}; + +// Non-bankable output elements +NoteButton button {5, {MIDI_Notes::C[4], Channel_1}}; +CCPotentiometer pot {26, {MIDI_CC::Channel_Volume, Channel_1}}; +CCRotaryEncoder enc {{0, 1}, {MIDI_CC::Pan, Channel_1}, 1, 4}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +}