Add SysEx handling for Launchpad X Programmer mode

- Parse all SysEx CIN types (start, continue, end)
- Reassemble multi-packet SysEx messages
- Handle layout select (Programmer mode = 0x7F)
- Handle Programmer/Live mode switch
This commit is contained in:
2026-06-25 07:20:47 +00:00
parent 8d859ce0af
commit b5bbe24977
3 changed files with 71 additions and 0 deletions
+59
View File
@@ -50,6 +50,14 @@ void AppTask::process_midi_event(const MidiEvent& event) {
// (visible without serial when connected to iPad)
led_driver->flash_activity();
if (event.type == MidiEvent::SYSEX) {
// Cin is encoded in channel for SYSEX packets
uint8_t cin = event.channel;
uint8_t packet[3] = {event.data1, event.data2, 0};
process_sysex_packet(packet, cin);
return;
}
uint8_t led_index = 0xFF;
uint8_t midi_channel = event.channel;
uint8_t midi_note = event.data1;
@@ -137,3 +145,54 @@ void AppTask::process_switch_event(uint8_t switch_id, bool pressed) {
}
}
}
void AppTask::process_sysex_packet(const uint8_t* packet, uint8_t cin) {
// Cin values: 0x4=start/short, 0x5=continue, 0x6=end (2 bytes), 0x7=end (1 byte/3 bytes)
if (cin == 0x4) { // SysEx start
sysex_active = true;
sysex_len = 0;
}
if (!sysex_active || sysex_len >= SYSEX_MAX_LEN) return;
// Add data bytes (skip F0/F7 which are handled by Cin)
sysex_buffer[sysex_len++] = packet[0];
if (cin == 0x4 || cin == 0x5 || cin == 0x6) {
sysex_buffer[sysex_len++] = packet[1];
}
if (cin == 0x6 || cin == 0x7) { // SysEx end
sysex_active = false;
handle_sysex(sysex_buffer, sysex_len);
sysex_len = 0;
}
}
void AppTask::handle_sysex(const uint8_t* data, uint8_t len) {
if (len < 7) return;
// Check Novation SysEx header: F0 00 20 29 02 0C/0D ...
if (data[0] != 0x00 || data[1] != 0x20 || data[2] != 0x29 || data[3] != 0x02) {
return;
}
uint8_t sub_id = data[4];
uint8_t command = data[5];
Serial.printf("[APP] SysEx: sub=%02X cmd=%02X len=%d\n", sub_id, command, len);
// Command 0x00 = Layout select, 0x0E = Programmer/Live mode
if (command == 0x00 && len >= 7) { // Layout select
uint8_t layout = data[6];
Serial.printf("[APP] Layout select: %02X\n", layout);
// 0x7F = Programmer mode
if (layout == 0x7F) {
Serial.println("[APP] Entered Programmer mode");
}
} else if (command == 0x0E && len >= 7) { // Programmer/Live mode
uint8_t mode = data[6];
Serial.printf("[APP] Programmer mode: %02X\n", mode);
}
}