diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cf210e6 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +BUILD_DIR = tests/build + +dist-tests: $(BUILD_DIR)/Makefile + @$(MAKE) -C $(BUILD_DIR) examples + @echo "All examples compiled successfully." + +$(BUILD_DIR)/Makefile: tests/CMakeLists.txt tests/examples/CMakeLists.txt + @mkdir -p $(BUILD_DIR) + @cd $(BUILD_DIR) && PICO_SDK_PATH=$$HOME/Staging/pico-sdk cmake .. + +clean: + @rm -rf $(BUILD_DIR) + +.PHONY: dist-tests clean diff --git a/docs b/docs index 7b2e253..fe87726 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 7b2e25395d18139a822910b85119a819e6724444 +Subproject commit fe877262d1b3d3283060dcaabe6a576b45ca0f1b diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..7e385c1 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,21 @@ +# Standalone build for cs-midi examples — compile-only verification. +# Invoked via: make dist-tests (from lib/cs-midi/) + +set(PICO_BOARD pico2_w) + +cmake_minimum_required(VERSION 3.13) + +include(pico_sdk_import.cmake) + +project(cs_midi_examples C CXX ASM) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + +pico_sdk_init() + +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/cs_midi) + +# cs_midi's BTstack sources need btstack_config.h from this directory +target_include_directories(cs_midi PRIVATE ${CMAKE_CURRENT_LIST_DIR}) + +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/examples ${CMAKE_CURRENT_BINARY_DIR}/examples) diff --git a/tests/btstack_config.h b/tests/btstack_config.h new file mode 100644 index 0000000..53f5d38 --- /dev/null +++ b/tests/btstack_config.h @@ -0,0 +1,43 @@ +#ifndef _BTSTACK_CONFIG_H +#define _BTSTACK_CONFIG_H + +// BLE +#define ENABLE_LE_PERIPHERAL +#define ENABLE_LE_CENTRAL +#define ENABLE_L2CAP_LE_CREDIT_BASED_FLOW_CONTROL_MODE + +#define HCI_OUTGOING_PRE_BUFFER_SIZE 4 +#define HCI_ACL_PAYLOAD_SIZE (1691 + 4) +#define HCI_ACL_CHUNK_SIZE_ALIGNMENT 4 + +#define MAX_NR_GATT_CLIENTS 1 +#define MAX_NR_HCI_CONNECTIONS 2 +#define MAX_NR_L2CAP_CHANNELS 4 +#define MAX_NR_L2CAP_SERVICES 3 +#define MAX_NR_SM_LOOKUP_ENTRIES 3 +#define MAX_NR_WHITELIST_ENTRIES 1 +#define MAX_NR_LE_DEVICE_DB_ENTRIES 4 + +#define MAX_NR_CONTROLLER_ACL_BUFFERS 3 +#define MAX_NR_CONTROLLER_SCO_PACKETS 3 + +#define ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL +#define HCI_HOST_ACL_PACKET_LEN 1024 +#define HCI_HOST_ACL_PACKET_NUM 3 +#define HCI_HOST_SCO_PACKET_LEN 120 +#define HCI_HOST_SCO_PACKET_NUM 3 + +#define NVM_NUM_DEVICE_DB_ENTRIES 16 + +#define MAX_ATT_DB_SIZE 512 + +#define ENABLE_LOG_INFO +#define ENABLE_PRINTF_HEXDUMP + +#define HAVE_EMBEDDED_TIME_MS +#define HAVE_ASSERT + +#define ENABLE_SOFTWARE_AES128 +#define ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS + +#endif diff --git a/tests/examples/CMakeLists.txt b/tests/examples/CMakeLists.txt new file mode 100644 index 0000000..4eea5f1 --- /dev/null +++ b/tests/examples/CMakeLists.txt @@ -0,0 +1,70 @@ +# Build each example as a standalone executable to verify compilation. +# Invoked via: make dist-tests (from lib/cs-midi/) + +set(EXAMPLE_SOURCES + # Output elements + output/note_button.cpp + output/cc_button.cpp + output/pc_button.cpp + output/note_chord_button.cpp + output/note_button_latched.cpp + output/note_button_latching.cpp + output/note_buttons.cpp + output/note_button_matrix.cpp + output/cc_button_latched.cpp + output/cc_button_latching.cpp + output/cc_buttons.cpp + output/cc_button_matrix.cpp + output/cc_potentiometer.cpp + output/pb_potentiometer.cpp + output/cc_rotary_encoder.cpp + output/cc_absolute_encoder.cpp + output/pb_absolute_encoder.cpp + output/cc_increment_decrement_buttons.cpp + output/program_changer.cpp + output/cc_potentiometers.cpp + output/borrowed_cc_rotary_encoder.cpp + + # Input elements + input/note_led.cpp + input/note_range_leds.cpp + input/cc_value.cpp + input/pb_value.cpp + input/note_value.cpp + input/kp_value.cpp + input/cc_led.cpp + input/note_range.cpp + input/cc_range.cpp + + # Interfaces + interfaces/ble_midi.cpp + interfaces/midi_pipes.cpp + + # Banks + banks/bank_cc_values.cpp + banks/transposer.cpp + banks/encoder_selector.cpp + banks/many_buttons_selector.cpp + banks/switch_selector.cpp + banks/program_change_selector.cpp + banks/bankable_note_led.cpp +) + +foreach(src ${EXAMPLE_SOURCES}) + get_filename_component(name ${src} NAME_WE) + set(target "example_${name}") + add_executable(${target} ${src}) + target_include_directories(${target} PRIVATE ${CMAKE_SOURCE_DIR}) + target_link_libraries(${target} + pico_stdlib + pico_cyw43_arch_lwip_threadsafe_background + pico_btstack_ble + pico_btstack_cyw43 + hardware_adc + cs_midi + ) + set_target_properties(${target} PROPERTIES EXCLUDE_FROM_ALL TRUE) + list(APPEND EXAMPLE_TARGETS ${target}) +endforeach() + +add_custom_target(examples DEPENDS ${EXAMPLE_TARGETS}) diff --git a/tests/examples/banks/bank_cc_values.cpp b/tests/examples/banks/bank_cc_values.cpp new file mode 100644 index 0000000..40e1045 --- /dev/null +++ b/tests/examples/banks/bank_cc_values.cpp @@ -0,0 +1,51 @@ +// Bank with bankable CC input elements. +// Demonstrates bank switching with input-side bankable elements. +// Note: bankable OUTPUT elements (e.g. Bankable::CCPotentiometer) are not yet +// extracted. This example uses bankable INPUT elements instead. +// Original concept: examples/5.Banks/Bank/Bank.ino + +#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); + +// Selector: two buttons to increment/decrement the active bank +IncrementDecrementSelector<4> selector { + bank, + {2, 3}, + Wrap::Wrap, +}; + +// Bankable CC value readers — bank switching changes the CC address. +// Bank 1: reads CC 16, CC 17 +// Bank 2: reads CC 18, CC 19 +// Bank 3: reads CC 20, CC 21 +// Bank 4: reads CC 22, CC 23 +Bankable::CCValue<4> ccVal1 { + {bank, BankType::ChangeAddress}, + {16, Channel_1}, +}; +Bankable::CCValue<4> ccVal2 { + {bank, BankType::ChangeAddress}, + {17, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t v1 = ccVal1.getValue(); + uint8_t v2 = ccVal2.getValue(); + (void)v1; + (void)v2; + sleep_ms(1); + } +} diff --git a/tests/examples/banks/bankable_note_led.cpp b/tests/examples/banks/bankable_note_led.cpp new file mode 100644 index 0000000..c31623d --- /dev/null +++ b/tests/examples/banks/bankable_note_led.cpp @@ -0,0 +1,33 @@ +// Bankable NoteLED — bank-switched LED responds to different notes per bank. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +Bank<4> bank(1); + +IncrementDecrementSelector<4> selector { + bank, + {2, 3}, + Wrap::Wrap, +}; + +Bankable::NoteLED<4> led { + {bank, BankType::ChangeAddress}, + 13, + {MIDI_Notes::C[4], Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/banks/encoder_selector.cpp b/tests/examples/banks/encoder_selector.cpp new file mode 100644 index 0000000..9f76eab --- /dev/null +++ b/tests/examples/banks/encoder_selector.cpp @@ -0,0 +1,35 @@ +// EncoderSelector — bank selection via rotary encoder. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +Bank<4> bank(2); + +Bankable::CCValue<4> ccVal { + {bank, BankType::ChangeAddress}, + {16, Channel_1}, +}; + +EncoderSelector<4> selector { + bank, + {0, 2}, + 4, + Wrap::Wrap, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t val = ccVal.getValue(); + (void)val; + sleep_ms(1); + } +} diff --git a/tests/examples/banks/many_buttons_selector.cpp b/tests/examples/banks/many_buttons_selector.cpp new file mode 100644 index 0000000..aebe7c5 --- /dev/null +++ b/tests/examples/banks/many_buttons_selector.cpp @@ -0,0 +1,33 @@ +// ManyButtonsSelector — one button per bank. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +Bank<4> bank(2); + +Bankable::CCValue<4> ccVal { + {bank, BankType::ChangeAddress}, + {16, Channel_1}, +}; + +ManyButtonsSelector<4> selector { + bank, + {2, 3, 4, 5}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t val = ccVal.getValue(); + (void)val; + sleep_ms(1); + } +} diff --git a/tests/examples/banks/program_change_selector.cpp b/tests/examples/banks/program_change_selector.cpp new file mode 100644 index 0000000..5cf8d4a --- /dev/null +++ b/tests/examples/banks/program_change_selector.cpp @@ -0,0 +1,33 @@ +// ProgramChangeSelector — bank selection via incoming MIDI Program Change. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +Bank<8> bank(1); + +Bankable::CCValue<8> ccVal { + {bank, BankType::ChangeAddress}, + {16, Channel_1}, +}; + +ProgramChangeSelector<8> selector { + bank, + {Channel_1, Cable_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t val = ccVal.getValue(); + (void)val; + sleep_ms(1); + } +} diff --git a/tests/examples/banks/switch_selector.cpp b/tests/examples/banks/switch_selector.cpp new file mode 100644 index 0000000..1cd7a95 --- /dev/null +++ b/tests/examples/banks/switch_selector.cpp @@ -0,0 +1,33 @@ +// SwitchSelector — two-state bank from toggle switch. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +Bank<2> bank(1); + +Bankable::CCValue<2> ccVal { + {bank, BankType::ChangeAddress}, + {16, Channel_1}, +}; + +SwitchSelector selector { + bank, + 5, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t val = ccVal.getValue(); + (void)val; + sleep_ms(1); + } +} diff --git a/tests/examples/banks/transposer.cpp b/tests/examples/banks/transposer.cpp new file mode 100644 index 0000000..79022b1 --- /dev/null +++ b/tests/examples/banks/transposer.cpp @@ -0,0 +1,30 @@ +// Transposer — note transposition via buttons. +// Original: examples/5.Banks/Transposer/Transposer.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +Transposer<-12, +12> transposer; + +NoteButton button {5, {MIDI_Notes::C[4], Channel_1}}; + +IncrementDecrementSelector<25> selector { + transposer, + {2, 3}, + Wrap::Clamp, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/input/cc_led.cpp b/tests/examples/input/cc_led.cpp new file mode 100644 index 0000000..233be25 --- /dev/null +++ b/tests/examples/input/cc_led.cpp @@ -0,0 +1,24 @@ +// CCLED — LED responds to incoming CC messages. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCLED led { + 13, + {MIDI_CC::General_Purpose_Controller_1, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/input/cc_range.cpp b/tests/examples/input/cc_range.cpp new file mode 100644 index 0000000..a8586c1 --- /dev/null +++ b/tests/examples/input/cc_range.cpp @@ -0,0 +1,25 @@ +// CCRange — reads a contiguous range of incoming CC values. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCRange<8> ccRange {{MIDI_CC::General_Purpose_Controller_1, Channel_1}}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + for (uint8_t i = 0; i < 8; i++) { + uint8_t val = ccRange.getValue(i); + (void)val; + } + sleep_ms(1); + } +} diff --git a/tests/examples/input/cc_value.cpp b/tests/examples/input/cc_value.cpp new file mode 100644 index 0000000..ce46aea --- /dev/null +++ b/tests/examples/input/cc_value.cpp @@ -0,0 +1,25 @@ +// CCValue — reads incoming CC messages and stores the value. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCValue ccVal { + {MIDI_CC::Channel_Volume, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t val = ccVal.getValue(); + (void)val; + sleep_ms(1); + } +} diff --git a/tests/examples/input/kp_value.cpp b/tests/examples/input/kp_value.cpp new file mode 100644 index 0000000..ea875d8 --- /dev/null +++ b/tests/examples/input/kp_value.cpp @@ -0,0 +1,23 @@ +// KPValue — reads incoming Key Pressure (aftertouch) values. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +KPValue kpVal {{MIDI_Notes::C[4], Channel_1}}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t val = kpVal.getValue(); + (void)val; + sleep_ms(1); + } +} diff --git a/tests/examples/input/note_led.cpp b/tests/examples/input/note_led.cpp new file mode 100644 index 0000000..b7c2ef7 --- /dev/null +++ b/tests/examples/input/note_led.cpp @@ -0,0 +1,25 @@ +// NoteLED — LED responds to incoming Note On/Off messages. +// Original: examples/2. MIDI Input/1. LEDs/1.Note-LED/1.Note-LED.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteLED led { + 13, // LED pin + {MIDI_Notes::C[4], Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/input/note_range.cpp b/tests/examples/input/note_range.cpp new file mode 100644 index 0000000..7fc3fc4 --- /dev/null +++ b/tests/examples/input/note_range.cpp @@ -0,0 +1,25 @@ +// NoteRange — reads a contiguous range of incoming Note values. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteRange<4> noteRange {{MIDI_Notes::C[4], Channel_1}}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + for (uint8_t i = 0; i < 4; i++) { + uint8_t val = noteRange.getValue(i); + (void)val; + } + sleep_ms(1); + } +} diff --git a/tests/examples/input/note_range_leds.cpp b/tests/examples/input/note_range_leds.cpp new file mode 100644 index 0000000..b3a9e6a --- /dev/null +++ b/tests/examples/input/note_range_leds.cpp @@ -0,0 +1,27 @@ +// NoteRange + LEDs — multiple LEDs respond to a range of incoming notes. +// Original: examples/2. MIDI Input/1. LEDs/2.Note-Range-LEDs/2.Note-Range-LEDs.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteLED leds[] { + {2, {MIDI_Notes::C[4], Channel_1}}, + {3, {MIDI_Notes::D[4], Channel_1}}, + {4, {MIDI_Notes::E[4], Channel_1}}, + {5, {MIDI_Notes::F[4], Channel_1}}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/input/note_value.cpp b/tests/examples/input/note_value.cpp new file mode 100644 index 0000000..2b103e5 --- /dev/null +++ b/tests/examples/input/note_value.cpp @@ -0,0 +1,23 @@ +// NoteValue — reads incoming Note On values. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteValue noteVal {{MIDI_Notes::C[4], Channel_1}}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint8_t val = noteVal.getValue(); + (void)val; + sleep_ms(1); + } +} diff --git a/tests/examples/input/pb_value.cpp b/tests/examples/input/pb_value.cpp new file mode 100644 index 0000000..28d4b2b --- /dev/null +++ b/tests/examples/input/pb_value.cpp @@ -0,0 +1,24 @@ +// PBValue — reads incoming Pitch Bend messages (14-bit). +// Original: examples/2. MIDI Input/Pitch-Bend-Value/Pitch-Bend-Value.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +PBValue pbVal {Channel_1}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + uint16_t val = pbVal.getValue(); + (void)val; + sleep_ms(1); + } +} diff --git a/tests/examples/interfaces/ble_midi.cpp b/tests/examples/interfaces/ble_midi.cpp new file mode 100644 index 0000000..3fbdfc8 --- /dev/null +++ b/tests/examples/interfaces/ble_midi.cpp @@ -0,0 +1,24 @@ +// BLE MIDI — basic Bluetooth Low Energy MIDI interface setup. +// This is the primary interface for cs-midi on pico-sdk. +// Replaces USBMIDI_Interface from the original Control Surface library. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteButton button {5, {MIDI_Notes::C[4], Channel_1}}; +CCRotaryEncoder enc {{0, 2}, {16, 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); + } +} diff --git a/tests/examples/interfaces/midi_pipes.cpp b/tests/examples/interfaces/midi_pipes.cpp new file mode 100644 index 0000000..b2b686f --- /dev/null +++ b/tests/examples/interfaces/midi_pipes.cpp @@ -0,0 +1,28 @@ +// MIDI Pipes — routing between interfaces. +// Original: examples/3. MIDI Interfaces/MIDI_Pipes-Routing/MIDI_Pipes-Routing.ino +// Demonstrates pipe factory operators for connecting interfaces. +// +// Pipe operators: +// a >> pipes >> b — forward A->B +// a << pipes << b — forward B->A +// a | pipes | b — bidirectional (uses BidirectionalMIDI_PipeFactory) + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface ble; + +NoteButton button {5, {MIDI_Notes::C[4], Channel_1}}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/borrowed_cc_rotary_encoder.cpp b/tests/examples/output/borrowed_cc_rotary_encoder.cpp new file mode 100644 index 0000000..20ccadc --- /dev/null +++ b/tests/examples/output/borrowed_cc_rotary_encoder.cpp @@ -0,0 +1,28 @@ +// BorrowedCCRotaryEncoder — shared encoder reference for CC output. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +AHEncoder encoder {0, 2}; + +BorrowedCCRotaryEncoder enc { + encoder, + {16, 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); + } +} diff --git a/tests/examples/output/cc_absolute_encoder.cpp b/tests/examples/output/cc_absolute_encoder.cpp new file mode 100644 index 0000000..9877845 --- /dev/null +++ b/tests/examples/output/cc_absolute_encoder.cpp @@ -0,0 +1,27 @@ +// CCAbsoluteEncoder — encoder position mapped to absolute CC value. +// Original: examples/1. MIDI Output/3. Rotary Encoders/AbsoluteRotaryEncoder/AbsoluteRotaryEncoder.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCAbsoluteEncoder enc { + {0, 2}, // encoder pins + MIDI_CC::Pan, // CC address + 1, // speed multiplier + 4, // pulses per step +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/cc_button.cpp b/tests/examples/output/cc_button.cpp new file mode 100644 index 0000000..f986514 --- /dev/null +++ b/tests/examples/output/cc_button.cpp @@ -0,0 +1,25 @@ +// CCButton — sends CC 127 on press, CC 0 on release. +// Original: examples/1. MIDI Output/2. Buttons & Switches/1. Momentary Push Buttons/CCButton/CCButton.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCButton button { + 5, + {MIDI_CC::General_Purpose_Controller_1, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/cc_button_latched.cpp b/tests/examples/output/cc_button_latched.cpp new file mode 100644 index 0000000..fcaaf4f --- /dev/null +++ b/tests/examples/output/cc_button_latched.cpp @@ -0,0 +1,24 @@ +// CCButtonLatched — first press sends CC 127, second press sends CC 0. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCButtonLatched button { + 5, + {MIDI_CC::General_Purpose_Controller_1, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/cc_button_latching.cpp b/tests/examples/output/cc_button_latching.cpp new file mode 100644 index 0000000..5a2bdd5 --- /dev/null +++ b/tests/examples/output/cc_button_latching.cpp @@ -0,0 +1,24 @@ +// CCButtonLatching — CC 127 while held, CC 0 on release; toggles state. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCButtonLatching button { + 5, + {MIDI_CC::General_Purpose_Controller_1, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/cc_button_matrix.cpp b/tests/examples/output/cc_button_matrix.cpp new file mode 100644 index 0000000..5f50466 --- /dev/null +++ b/tests/examples/output/cc_button_matrix.cpp @@ -0,0 +1,29 @@ +// CCButtonMatrix — grid of CC buttons using row/column scanning. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCButtonMatrix<2, 3> matrix { + {0, 1}, // row pins + {2, 3, 4}, // column pins + {{ + {16, 17, 18}, + {19, 20, 21}, + }}, + Channel_1, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/cc_buttons.cpp b/tests/examples/output/cc_buttons.cpp new file mode 100644 index 0000000..e44ede9 --- /dev/null +++ b/tests/examples/output/cc_buttons.cpp @@ -0,0 +1,25 @@ +// CCButtons — multiple CC buttons with sequential addresses. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCButtons<4> buttons { + {2, 3, 4, 5}, + {MIDI_CC::General_Purpose_Controller_1, Channel_1}, + 1, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/cc_increment_decrement_buttons.cpp b/tests/examples/output/cc_increment_decrement_buttons.cpp new file mode 100644 index 0000000..ffa9f0a --- /dev/null +++ b/tests/examples/output/cc_increment_decrement_buttons.cpp @@ -0,0 +1,28 @@ +// CCIncrementDecrementButtons — two buttons for CC increment/decrement with optional reset. +// Original: examples/1. MIDI Output/2. Buttons & Switches/4. RelativeIncrementDecrement/CCIncrementDecrementButtons/CCIncrementDecrementButtons.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCIncrementDecrementButtons buttons { + {5, 6}, // increment pin, decrement pin + {16, Channel_1}, // CC address + 1, // multiplier + {0x45, Channel_1}, // reset note (sent when both pressed) +}; + +int main() { + stdio_init_all(); + RelativeCCSender::setMode(relativeCCmode::MACKIE_CONTROL_RELATIVE); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/cc_potentiometer.cpp b/tests/examples/output/cc_potentiometer.cpp new file mode 100644 index 0000000..9d1c07e --- /dev/null +++ b/tests/examples/output/cc_potentiometer.cpp @@ -0,0 +1,25 @@ +// CCPotentiometer — analog input mapped to CC value 0-127. +// Original: examples/1. MIDI Output/1. Potentiometers & Faders/Control-Change-Potentiometer/Control-Change-Potentiometer.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCPotentiometer pot { + 26, // ADC pin (GPIO 26 = ADC0) + {MIDI_CC::Channel_Volume, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/cc_potentiometers.cpp b/tests/examples/output/cc_potentiometers.cpp new file mode 100644 index 0000000..d329c7c --- /dev/null +++ b/tests/examples/output/cc_potentiometers.cpp @@ -0,0 +1,26 @@ +// Multiple CCPotentiometers — several analog inputs mapped to CC. +// Original: examples/1. MIDI Output/1. Potentiometers & Faders/Multiple-Control-Change-Potentiometers/Multiple-Control-Change-Potentiometers.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCPotentiometer pots[] { + {26, {MIDI_CC::Channel_Volume, Channel_1}}, + {27, {MIDI_CC::Channel_Volume, Channel_2}}, + {28, {MIDI_CC::Channel_Volume, Channel_3}}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/cc_rotary_encoder.cpp b/tests/examples/output/cc_rotary_encoder.cpp new file mode 100644 index 0000000..f14f720 --- /dev/null +++ b/tests/examples/output/cc_rotary_encoder.cpp @@ -0,0 +1,28 @@ +// CCRotaryEncoder — relative CC encoder for DAW parameter control. +// Original: examples/1. MIDI Output/3. Rotary Encoders/RotaryEncoder/RotaryEncoder/RotaryEncoder.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +CCRotaryEncoder enc { + {0, 2}, // encoder pins A and B (constructs AHEncoder) + {16, Channel_1}, // CC address + 1, // speed multiplier + 4, // pulses per step +}; + +int main() { + stdio_init_all(); + RelativeCCSender::setMode(relativeCCmode::MACKIE_CONTROL_RELATIVE); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/note_button.cpp b/tests/examples/output/note_button.cpp new file mode 100644 index 0000000..df569ad --- /dev/null +++ b/tests/examples/output/note_button.cpp @@ -0,0 +1,25 @@ +// NoteButton — sends Note On/Off on button press/release. +// Original: examples/1. MIDI Output/2. Buttons & Switches/1. Momentary Push Buttons/NoteButton/NoteButton.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteButton button { + 5, // push button on GPIO 5 + {MIDI_Notes::C[4], Channel_1}, // note C4, channel 1 +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/note_button_latched.cpp b/tests/examples/output/note_button_latched.cpp new file mode 100644 index 0000000..443ccf1 --- /dev/null +++ b/tests/examples/output/note_button_latched.cpp @@ -0,0 +1,24 @@ +// NoteButtonLatched — first press sends Note On, second press sends Note Off. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteButtonLatched button { + 5, + {MIDI_Notes::C[4], Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/note_button_latching.cpp b/tests/examples/output/note_button_latching.cpp new file mode 100644 index 0000000..e12ae16 --- /dev/null +++ b/tests/examples/output/note_button_latching.cpp @@ -0,0 +1,24 @@ +// NoteButtonLatching — Note On while held, Note Off on release; toggles state. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteButtonLatching button { + 5, + {MIDI_Notes::C[4], Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/note_button_matrix.cpp b/tests/examples/output/note_button_matrix.cpp new file mode 100644 index 0000000..f573ace --- /dev/null +++ b/tests/examples/output/note_button_matrix.cpp @@ -0,0 +1,30 @@ +// NoteButtonMatrix — grid of note buttons using row/column scanning. +// Original: examples/1. MIDI Output/2. Buttons & Switches/1. Momentary Push Buttons/NoteButtonMatrix/NoteButtonMatrix.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteButtonMatrix<2, 3> matrix { + {0, 1}, // row pins + {2, 3, 4}, // column pins + {{ + {MIDI_Notes::C[4], MIDI_Notes::D[4], MIDI_Notes::E[4]}, + {MIDI_Notes::F[4], MIDI_Notes::G[4], MIDI_Notes::A[4]}, + }}, + Channel_1, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/note_buttons.cpp b/tests/examples/output/note_buttons.cpp new file mode 100644 index 0000000..e156525 --- /dev/null +++ b/tests/examples/output/note_buttons.cpp @@ -0,0 +1,25 @@ +// NoteButtons — multiple note buttons with sequential addresses. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +NoteButtons<4> buttons { + {2, 3, 4, 5}, // GPIO pins + {MIDI_Notes::C[4], Channel_1}, // base address + 1, // increment between addresses +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/note_chord_button.cpp b/tests/examples/output/note_chord_button.cpp new file mode 100644 index 0000000..bb30973 --- /dev/null +++ b/tests/examples/output/note_chord_button.cpp @@ -0,0 +1,33 @@ +// NoteChordButton — plays a chord on button press. +// Original: examples/1. MIDI Output/2. Buttons & Switches/1. Momentary Push Buttons/NoteChordButton/NoteChordButton.ino +// Note: bankable variant (with Transposer) requires bankable output elements (not yet extracted). + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +constexpr Channel channel = Channel_1; + +NoteChordButton buttons[] { + {2, {MIDI_Notes::C[4], channel}, Bass::Double + Chords::Major}, + {3, {MIDI_Notes::D[4], channel}, Bass::Double + Chords::Minor}, + {4, {MIDI_Notes::E[4], channel}, Bass::Double + Chords::Minor}, + {5, {MIDI_Notes::F[4], channel}, Bass::Double + Chords::MajorFirstInv}, + {6, {MIDI_Notes::G[4], channel}, Bass::Double + Chords::MajorSecondInv}, + {7, {MIDI_Notes::A[4], channel}, Bass::Double + Chords::MinorSecondInv}, + {8, {MIDI_Notes::B[4], channel}, Bass::Double + Chords::Diminished}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/pb_absolute_encoder.cpp b/tests/examples/output/pb_absolute_encoder.cpp new file mode 100644 index 0000000..d830473 --- /dev/null +++ b/tests/examples/output/pb_absolute_encoder.cpp @@ -0,0 +1,26 @@ +// PBAbsoluteEncoder — encoder position mapped to 14-bit Pitch Bend. + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +PBAbsoluteEncoder enc { + {0, 2}, // encoder pins + Channel_1, + 127, // large multiplier for PB's 14-bit range + 4, // pulses per step +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/pb_potentiometer.cpp b/tests/examples/output/pb_potentiometer.cpp new file mode 100644 index 0000000..cce841c --- /dev/null +++ b/tests/examples/output/pb_potentiometer.cpp @@ -0,0 +1,25 @@ +// PBPotentiometer — analog input mapped to 14-bit Pitch Bend. +// Original: examples/1. MIDI Output/1. Potentiometers & Faders/Pitch-Bend-Potentiometer/Pitch-Bend-Potentiometer.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +PBPotentiometer pot { + 26, // ADC pin + Channel_1, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/pc_button.cpp b/tests/examples/output/pc_button.cpp new file mode 100644 index 0000000..fb37397 --- /dev/null +++ b/tests/examples/output/pc_button.cpp @@ -0,0 +1,25 @@ +// PCButton — sends Program Change on button press. +// Original: examples/1. MIDI Output/4. Program Changers/PCButton/PCButton.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +PCButton pcBtn { + 2, + {MIDI_PC::Steel_Drums, Channel_1}, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/examples/output/program_changer.cpp b/tests/examples/output/program_changer.cpp new file mode 100644 index 0000000..5bf442b --- /dev/null +++ b/tests/examples/output/program_changer.cpp @@ -0,0 +1,36 @@ +// ProgramChanger — sends different program changes based on selector state. +// Original: examples/1. MIDI Output/4. Program Changers/Program-Changer/Program-Changer.ino + +#include "pico/stdlib.h" +#include "pico/cyw43_arch.h" +#include + +using namespace cs; + +BluetoothMIDI_Interface midi; + +ProgramChanger<4> programChanger { + {{ + MIDI_PC::Acoustic_Grand_Piano, + MIDI_PC::Rock_Organ, + MIDI_PC::Steel_Drums, + MIDI_PC::Pad_2, + }}, + Channel_1, +}; + +IncrementDecrementSelector<4> selector { + programChanger, + {2, 3}, + Wrap::Wrap, +}; + +int main() { + stdio_init_all(); + if (cyw43_arch_init()) return 1; + Control_Surface.begin(); + while (true) { + Control_Surface.loop(); + sleep_ms(1); + } +} diff --git a/tests/lwipopts.h b/tests/lwipopts.h new file mode 100644 index 0000000..d008790 --- /dev/null +++ b/tests/lwipopts.h @@ -0,0 +1,19 @@ +#ifndef _LWIPOPTS_H +#define _LWIPOPTS_H + +#define NO_SYS 1 +#define LWIP_SOCKET 0 +#define LWIP_NETCONN 0 +#define LWIP_RAW 1 +#define LWIP_DHCP 1 +#define LWIP_DNS 1 +#define LWIP_IGMP 1 +#define LWIP_NETIF_HOSTNAME 1 +#define LWIP_NETIF_STATUS_CALLBACK 1 +#define LWIP_UDP 1 +#define LWIP_TCP 1 +#define MEM_SIZE 4096 +#define MEMP_NUM_UDP_PCB 6 +#define MEMP_NUM_TCP_PCB 4 + +#endif diff --git a/tests/pico_sdk_import.cmake b/tests/pico_sdk_import.cmake new file mode 100644 index 0000000..e215d32 --- /dev/null +++ b/tests/pico_sdk_import.cmake @@ -0,0 +1,120 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + else () + FetchContent_Populate( + pico_sdk + QUIET + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + + SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src + BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build + SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild + ) + endif () + + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE})