Files
Shadowtrance dbf850c434 Fixes and new apps (#30)
- M5 Unit Modules library + M5 Unit Test app
- Minor fixes for TodoList, TwoEleven, Snake, Brainfuck and Breakout
- Fixed SerialConsole to use the uart controller as it was broken in one of the many updates
- Fixed keyboard input in TwoEleven, Breakout, Magic8Ball and Snake
- Bluetooth Media Keys app, supports pressing physical keys to trigger the corresponding buttonmatrix button
- Epub Reader app
2026-06-07 15:56:32 +02:00

94 lines
2.7 KiB
C++

#include <UnitMidi.h>
#include <tactility/drivers/uart_controller.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
static constexpr auto* TAG = "UnitMidi";
static constexpr uint32_t BAUD = 31250;
static constexpr uint32_t SEND_TIMEOUT_MS = 20;
bool UnitMidi::begin(Device* dev) {
if (!dev) return false;
UartConfig cfg = {
BAUD,
UART_CONTROLLER_DATA_8_BITS,
UART_CONTROLLER_PARITY_DISABLE,
UART_CONTROLLER_STOP_BITS_1,
};
if (uart_controller_set_config(dev, &cfg) != ERROR_NONE) {
ESP_LOGW(TAG, "uart_controller_set_config failed");
return false;
}
if (uart_controller_open(dev) != ERROR_NONE) {
ESP_LOGW(TAG, "uart_controller_open failed");
return false;
}
dev_ = dev;
ready_ = true;
// Give SAM2695 time to power up, then reset to known state
vTaskDelay(pdMS_TO_TICKS(100));
reset();
ESP_LOGI(TAG, "UnitMidi ready at %" PRIu32 " bps", BAUD);
return true;
}
void UnitMidi::end() {
if (dev_ && ready_) {
allNotesOff(0xFF);
uart_controller_close(dev_);
}
ready_ = false;
dev_ = nullptr;
}
void UnitMidi::send(const uint8_t* data, size_t len) {
if (!ready_ || !dev_) return;
uart_controller_write_bytes(dev_, data, len, pdMS_TO_TICKS(SEND_TIMEOUT_MS));
}
void UnitMidi::reset() {
uint8_t msg[] = { 0xFF };
send(msg, 1);
}
void UnitMidi::noteOn(uint8_t channel, uint8_t note, uint8_t velocity) {
uint8_t msg[] = { (uint8_t)(0x90 | (channel & 0x0F)), (uint8_t)(note & 0x7F), (uint8_t)(velocity & 0x7F) };
send(msg, 3);
}
void UnitMidi::noteOff(uint8_t channel, uint8_t note) {
uint8_t msg[] = { (uint8_t)(0x80 | (channel & 0x0F)), (uint8_t)(note & 0x7F), 0x00 };
send(msg, 3);
}
void UnitMidi::programChange(uint8_t channel, uint8_t program) {
uint8_t msg[] = { (uint8_t)(0xC0 | (channel & 0x0F)), (uint8_t)(program & 0x7F) };
send(msg, 2);
}
void UnitMidi::controlChange(uint8_t channel, uint8_t controller, uint8_t value) {
uint8_t msg[] = { (uint8_t)(0xB0 | (channel & 0x0F)), (uint8_t)(controller & 0x7F), (uint8_t)(value & 0x7F) };
send(msg, 3);
}
void UnitMidi::pitchBend(uint8_t channel, int16_t value) {
// value range -8192..+8191 → offset by 8192, split into 7-bit LSB/MSB
uint16_t v = (uint16_t)(value + 8192);
uint8_t msg[] = {
(uint8_t)(0xE0 | (channel & 0x0F)),
(uint8_t)(v & 0x7F),
(uint8_t)((v >> 7) & 0x7F),
};
send(msg, 3);
}
void UnitMidi::allNotesOff(uint8_t channel) {
if (channel == 0xFF) {
for (uint8_t ch = 0; ch < 16; ch++)
controlChange(ch, 123, 0);
} else {
controlChange(channel, 123, 0);
}
}