From 6380915e6e8d98e2c933ea6eb8df02fb1b123b97 Mon Sep 17 00:00:00 2001 From: Duncan Wilkie Date: Tue, 18 Jul 2023 17:00:44 -0500 Subject: Somewhat finalized base MIDI; got the minimal MIDI-CI done. --- controller/inc/base_midi.h | 6 ++ controller/libs/base_midi.c | 6 +- controller/libs/midi_ci.c | 174 ++++++++++++++++++++++++++++++++++++++++++++ controller/src/main.c | 2 +- specs/periph_driver_lib.pdf | Bin 4830798 -> 0 bytes 5 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 controller/libs/midi_ci.c delete mode 100644 specs/periph_driver_lib.pdf diff --git a/controller/inc/base_midi.h b/controller/inc/base_midi.h index e566a6f..8320803 100644 --- a/controller/inc/base_midi.h +++ b/controller/inc/base_midi.h @@ -16,6 +16,12 @@ // Otherwise sends Note On velocity 0 (so as to exploit running status). #undef EXPORT_CONTROLLERS // If defined, export constants useful for controller messages. +// Device info. Modify to suit your use-case. +#define DEVICE_MANUFACTURER 0x7d +#define DEVICE_FAMILY 0x00'00 +#define DEVICE_MODEL_NUMBER 0x00'00 +#define SOFTWARE_REVISION 0x00'00'00'00 + // Consumers must specify typedef struct { void (*uart_write)(uint8_t); // Blocking, single-byte UART transmit function. diff --git a/controller/libs/base_midi.c b/controller/libs/base_midi.c index e146ec0..6efd2f3 100644 --- a/controller/libs/base_midi.c +++ b/controller/libs/base_midi.c @@ -1,10 +1,10 @@ // This file is written to be read side-along with the MIDI 1.0 spec. // Note the tables at its very end, with /absolutely no direct allusion in the text/. -#include "midi.h" +#include "base_midi.h" #include #include - +// TODO: startup function to initialize ParseMemory buffer. #ifdef RUNNING_STATUS uint8_t last_status = 0x00; #endif @@ -83,9 +83,11 @@ void sysex(uint16_t manufacturer_id, uint8_t* contents, size_t contents_len) { pfns.uart_write(manufacturer_id >> 8); pfns.uart_write(manufacturer_id & 0x00ff); } else { +#ifdef DEBUG if (manufacturer_id > MAX_NON_UNIVERSAL_ID) { while(true); // Used universal sysex ID. } +#endif pfns.uart_write(manufacturer_id); } diff --git a/controller/libs/midi_ci.c b/controller/libs/midi_ci.c new file mode 100644 index 0000000..7013d7a --- /dev/null +++ b/controller/libs/midi_ci.c @@ -0,0 +1,174 @@ +// An implementation of the MIDI Capability Inquiry v1.2 Specification, over a MIDI 1.0 transport, +// with only Property Exchange support. +// Intended to be read alongside the corresponding specs; specifically in the order: +// - MIDI CI Specification, minimum requirements + Property Exchange chapter, +// - Common Rules for MIDI CI Property Exchange. + +#include "base_midi.h" + +uint32_t our_muid = rand(); // TODO: think. + +#define MIDI_CI_SUBID 0x0d +#define PROFILE_CONFIGURATION_MASK 0x20 +#define PROPERTY_EXCHANGE_MASK 0x30 +#define PROCESS_INQUIRY_MASK 0x40 +#define MANAGEMENT_MASK 0x70 +#define MIDI_CI_VERSION 0x02 +#define TO_FUNCTION_BLOCK_ID 0x7f +static void ci(uint8_t source_target, uint8_t message_type, uint32_t destination_miud, + uint8_t *contents, uint8_t contents_len) { + uint8_t *new = malloc(1 + 4 + 4 + contents_len); + new[0] = MIDI_CI_VERSION; + new[1] = our_muid & 0x00'00'00'ff; + new[2] = (our_muid >> 8) & 0x00'00'00'ff; + new[3] = (our_muid >> 16) & 0x00'00'00'ff; + new[4] = (our_muid >> 24) & 0x00'00'00'ff; + new[8] = target_muid & 0x00'00'00'ff; + new[7] = (target_muid >> 8) & 0x00'00'00'ff; + new[6] = (target_muid >> 16) & 0x00'00'00'ff; + new[5] = (target_muid >> 24) & 0x00'00'00'ff; + memcpy(new + 9, contents, contents_len); + + universal_nonrealtime(source_target, (MIDI_CI_SUBID << 8) | message_type, contents, 1 + 4 + 4 + contents_len); + + free(new); + +} + +#define DISCOVERY_SUBID (MANAGEMENT_MASK | 0x00) +#define CI_CATEGORY_SUPPORTED 0b00011100 +#define MAX_SYSEX_SIZE 512 +#define BROADCAST_MUID 0x7f'7f'7f'7f +#define SINGLE_OUTPUT_PATH 0x00 +void discovery() { + uint8_t *new = malloc(3 + 2 + 2 + 4 + 1 + 4 + 1); +#if (DEVICE_MANUFACTURER <= MAX_DATA_BYTE) + new[0] = DEVICE_MANUFACTURER; + new[1] = 0; + new[2] = 0; +#else + new[0] = 0; + new[1] = DEVICE_MANUFACTURER >> 8; + new[2] = DEVICE_MANUFACTURER & 0x00ff; +#endif + new[3] = DEVICE_FAMILY & 0x00ff; + new[4] = DEVICE_FAMILY >> 8; + new[5] = DEVICE_MODEL & 0x00ff; + new[6] = DEVICE_MODEL >> 8; + new[7] = SOFTWARE_REVISION & 0x00'00'00'ff; + new[8] = (SOFTWARE_REVISION >> 8) & 0x00'00'00'ff; + new[9] = (SOFTWARE_REVISION >> 16) & 0x00'00'00'ff; + new[10] = (SOFTWARE_REVISION >> 24) & 0x00'00'00'ff; + new[11] = CI_CATEGORY_SUPPORTED; + new[12] = MAX_SYSEX_SIZE & 0x00'00'00'ff; + new[13] = (MAX_SYSEX_SIZE >> 8) & 0x00'00'00'ff; + new[14] = (MAX_SYSEX_SIZE >> 16) & 0x00'00'00'ff; + new[15] = (MAX_SYSEX_SIZE >> 24) & 0x00'00'00'ff; + new[16] = SINGLE_OUTPUT_PATH; + + ci(TO_FUNCTION_BLOCK_ID, DISCOVERY_SUBID, BROADCAST_MUID, new, 17); + + free(new); +} + +#define REPLY_TO_DISCOVERY_SUBID 0x71 +#define NO_FUNCTION_BLOCK 0x7f +void discovery_reply(uint8_t initiator_muid, uint8_t initiator_output_path_id) { + uint8_t *new = malloc(3 + 2 + 2 + 4 + 1 + 4 + 1 + 1); +#if (DEVICE_MANUFACTURER <= MAX_DATA_BYTE) + new[0] = DEVICE_MANUFACTURER; + new[1] = 0; + new[2] = 0; +#else + new[0] = 0; + new[1] = DEVICE_MANUFACTURER >> 8; + new[2] = DEVICE_MANUFACTURER & 0x00ff; +#endif + new[3] = DEVICE_FAMILY & 0x00ff; + new[4] = DEVICE_FAMILY >> 8; + new[5] = DEVICE_MODEL & 0x00ff; + new[6] = DEVICE_MODEL >> 8; + new[7] = SOFTWARE_REVISION & 0x00'00'00'ff; + new[8] = (SOFTWARE_REVISION >> 8) & 0x00'00'00'ff; + new[9] = (SOFTWARE_REVISION >> 16) & 0x00'00'00'ff; + new[10] = (SOFTWARE_REVISION >> 24) & 0x00'00'00'ff; + new[11] = CI_CATEGORY_SUPPORTED; + new[12] = MAX_SYSEX_SIZE & 0x00'00'00'ff; + new[13] = (MAX_SYSEX_SIZE >> 8) & 0x00'00'00'ff; + new[14] = (MAX_SYSEX_SIZE >> 16) & 0x00'00'00'ff; + new[15] = (MAX_SYSEX_SIZE >> 24) & 0x00'00'00'ff; + new[16] = initiator_output_path_id; + new[17] = NO_FUNCTION_BLOCK; + + ci(TO_FUNCTION_BLOCK_ID, REPLY_TO_DISCOVERY_SUBID, initiator_muid, new, 18); + + free(new); + +} + +// TODO: Decide if Inquiry: Endpoint and Reply to Endpoint are necessary for standard conformace if we're over MIDI 1.0. + +// TODO: should we set a new MUID inside this function? +#define INVALIDATE_MUID_SUBID 0x7e +void invalidate_muid() { + uint8_t *new = malloc(4); + new[0] = our_muid & 0x00'00'00'ff; + new[1] = (our_muid >> 8) & 0x00'00'00'ff; + new[2] = (our_muid >> 16) & 0x00'00'00'ff; + new[3] = (our_muid >> 24) & 0x00'00'00'ff; + + ci(TO_FUNCTION_BLOCK_ID, BROADCAST_MUID, new, 4); + + free(new); + +} + +// TODO: consider structifying? +#define ACK_SUBID 0x7d +void ci_ack(uint8_t acking_device_id, uint8_t acking_muid, uint8_t original_classification, uint8_t status_code, + uint8_t status_data, + uint8_t details1, uint8_t details2, uint8_t details3, uint8_t details4, uint8_t details5, + uint16_t length, uint8_t *text) { + uint8_t *new = malloc(1 + 1 + 1 + 5 + 2 + length); + new[0] = original_classification; + new[1] = status_code; + new[2] = status_data; + new[3] = details1; + new[4] = details2; + new[5] = details3; + new[6] = details4; + new[7] = details5; + new[8] = length & 0x00ff; + new[9] = length >> 8; + memcpy(new + 10, text, length); + + ci(acking_device_id, ACK_SUBID, acking_muid, new, 1 + 1 + 1 + 5 + 2 + length); + + free(new); + +} + + +#define NAK_SUBID 0x7f +void ci_nack(uint8_t naking_device_id, uint8_t naking_muid, uint8_t original_classification, uint8_t status_code, + uint8_t status_data, + uint8_t details1, uint8_t details2, uint8_t details3, uint8_t details4, uint8_t details5, + uint16_t length, uint8_t *text) { + uint8_t *new = malloc(1 + 1 + 1 + 5 + 2 + length); + new[0] = original_classification; + new[1] = status_code; + new[2] = status_data; + new[3] = details1; + new[4] = details2; + new[5] = details3; + new[6] = details4; + new[7] = details5; + new[8] = length & 0x00ff; + new[9] = length >> 8; + memcpy(new + 10, text, length); + + ci(naking_device_id, NAK_SUBID, naking_muid, new, 1 + 1 + 1 + 5 + 2 + length); + + free(new); + +} diff --git a/controller/src/main.c b/controller/src/main.c index fb3f18a..1bfe8b0 100644 --- a/controller/src/main.c +++ b/controller/src/main.c @@ -1,4 +1,4 @@ -#include "midi.h" +#include "base_midi.h" #include "uart.h" int main() { diff --git a/specs/periph_driver_lib.pdf b/specs/periph_driver_lib.pdf deleted file mode 100644 index 711ab77..0000000 Binary files a/specs/periph_driver_lib.pdf and /dev/null differ -- cgit v1.2.3