From ed60865743a5d65240c9da353edb4dc20cf7009f Mon Sep 17 00:00:00 2001 From: Duncan Wilkie Date: Tue, 18 Jul 2023 11:55:03 -0500 Subject: Rename, add startup file. --- controller/Makefile | 4 +- controller/inc/base_midi.h | 206 +++++++++++ controller/inc/midi.h | 207 ----------- controller/inc/startup.h | 173 +++++++++ controller/libs/base_midi.c | 835 ++++++++++++++++++++++++++++++++++++++++++++ controller/libs/midi.c | 826 ------------------------------------------- controller/libs/startup.c | 225 ++++++++++++ controller/src/main.c | 1 + 8 files changed, 1442 insertions(+), 1035 deletions(-) create mode 100644 controller/inc/base_midi.h delete mode 100644 controller/inc/midi.h create mode 100644 controller/inc/startup.h create mode 100644 controller/libs/base_midi.c delete mode 100644 controller/libs/midi.c create mode 100644 controller/libs/startup.c (limited to 'controller') diff --git a/controller/Makefile b/controller/Makefile index 00ed2da..9be9eb3 100644 --- a/controller/Makefile +++ b/controller/Makefile @@ -17,11 +17,11 @@ SRCS = $(wildcard src/*.c) \ OBJ = obj/ OBJS = $(addprefix $(OBJ),$(notdir $(SRCS:.c=.o))) LD_SCRIPT = ld/$(MCU).ld -IPATH = /home/dnw/Code/TivaC/libs +IPATH = /home/dnw/Code/TivaC/libs/driverlib # Flags. CFLAGS = -mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections \ - -fdata-sections -MD -std=c99 -Wall -pedantic -DPART_${MCU} -c -Os -Dgcc -ggdb + -fdata-sections -MD -std=c2x -Wall -Wextra -Werror -DPART_${MCU} -c -Os -Dgcc -ggdb CFLAGS += ${patsubst %,-I%,${subst :, ,${IPATH}}} -iquote inc # Compiler/standard resource locations. diff --git a/controller/inc/base_midi.h b/controller/inc/base_midi.h new file mode 100644 index 0000000..e566a6f --- /dev/null +++ b/controller/inc/base_midi.h @@ -0,0 +1,206 @@ +#ifndef MIDI_H +#define MIDI_H + +#include +#include +#include + +// Configuration. +#define DEBUG 0 // If defined, enable input safety checking (e.g. too large data bytes, bad ID numbers, etc). + // These checks have some performance downside. +#define RUNNING_STATUS 0 // If defined, the MIDI instrument stores a transmit status and uses running statuses whenever possible. +#define KEY_ON_VELOCITY 0 // If defined, the MIDI instrument sends velocities with Note On messages. +#undef RELEASE_VELOCITY // If defined, the MIDI instrument sends Note Off messages with velocities. + // Otherwise, sends Note On velocity 0 or Note Off velocity 0 according to ACTUAL_OFF_MESSAGE. +#undef ACTUAL_OFF_MESSAGE // If defined, the MIDI instrument sends true Note Off messages. + // Otherwise sends Note On velocity 0 (so as to exploit running status). +#undef EXPORT_CONTROLLERS // If defined, export constants useful for controller messages. + +// Consumers must specify +typedef struct { + void (*uart_write)(uint8_t); // Blocking, single-byte UART transmit function. + // Channel voice handlers. + void (*note_on_handler)(uint8_t, uint8_t, uint8_t); + void (*note_off_handler)(uint8_t, uint8_t, uint8_t); + void (*poly_key_handler)(uint8_t, uint8_t, uint8_t); + void (*control_change_handler)(uint8_t, uint8_t, uint8_t); + void (*program_change_handler)(uint8_t, uint8_t); + void (*aftertouch_handler)(uint8_t, uint8_t); + void (*pitch_bend_change_handler)(uint8_t, uint8_t); + // Channel mode handlers. + void (*all_sound_off_handler)(uint8_t); + void (*reset_all_controllers_handler)(uint8_t); + void (*local_control_handler)(uint8_t, uint8_t); + void (*all_notes_off_handler)(uint8_t); + void (*omni_on_handler)(uint8_t); + void (*omni_off_handler)(uint8_t); + void (*mono_on_handler)(uint8_t, uint8_t); + void (*poly_on_handler)(uint8_t); + // System common handlers. + void (*mtc_quarter_frame_handler)(uint8_t, uint8_t); + void (*song_position_pointer_handler)(uint8_t, uint8_t); + void (*song_select_handler)(uint8_t); + void (*tune_request_handler)(); + // System real time handlers. + void (*timing_clock_handler)(); + void (*start_handler)(); + void (*continue_handler)(); + void (*stop_handler)(); + void (*active_sensing_handler)(); + void (*system_reset_handler)(); + // System Exclusive handlers. + bool (*sysex_collector)(uint8_t); // Feeds most recent byte system exclusive byte (status and eox excluded, ID included) + // to client, returning false whenever the client determines sysex can be safely discarded. + // Client is expected to maintain parsing state externally, + // including resetting correctly after aborted parses. + // Client also should not abort the parse before the first post-manufacturer-ID byte. + void (*end_of_sysex_handler)(); // Sent only when client + // Universal System Exclusive handlers. + void (*bulk_tuning_dump_request_handler)(uint8_t, uint8_t); + void (*bulk_tuning_dump_handler)(uint8_t, uint8_t, char*, uint8_t*); + void (*single_note_tuning_change_handler)(uint8_t, uint8_t, uint8_t, uint8_t*); + // TODO: more. + bool (*unimplemented_universal_sysex_collector)(uint8_t); // Same as above. Parsing ends with end_of_sysex_handler. +} ConsumerBehavior; + +extern ConsumerBehavior pfns; // Initialize this globally in your main. + +// System exclusive sends. +void sysex(uint16_t manufacturer_id, uint8_t* contents, size_t contents_len); +void universal_nonrealtime(uint8_t device_id, uint16_t sub_id, uint8_t* contents, size_t contents_len); +void universal_realtime(uint8_t device_id, uint16_t sub_id, uint8_t* contents, size_t contents_len); + +// Channel voice sends. +#ifdef KEY_ON_VELOCITY +void note_on(uint8_t channel, uint8_t note, uint8_t velocity); +#else +void note_on(uint8_t channel, uint8_t note); +#endif +#ifdef RELEASE_VELOCITY +void note_off(uint8_t channel, uint8_t note, uint8_t velocity); +#else +void note_off(uint8_t channel, uint8_t note); +#endif +void control_change(uint8_t channel, uint8_t controller_number, uint8_t control_value); +void program_change(uint8_t channel, uint8_t program_number); +void aftertouch(uint8_t channel, uint8_t pressure_value); +void pitch_bend_change(uint8_t channel, uint16_t pressure_value); + +// Channel mode sends. +void all_sound_off(uint8_t channel); +void reset_all_controllers(uint8_t channel); +void local_control_on(uint8_t channel); +void local_control_off(uint8_t channel); +void all_notes_off(uint8_t channel); +void omni_on(uint8_t channel); +void omni_off(uint8_t channel); +void mono_on(uint8_t channel, uint8_t channel_count); +void poly_on(uint8_t channel); + + +// System Common sends. +// MTC Quarter Frame unimplemented. +void song_position_pointer(uint16_t position); +void song_select(uint8_t song); +void tune_request(); + +// System Real Time sends. +void timing_clock(); +void srt_start(); +void srt_continue(); +void srt_stop(); +void active_sensing(); +void MIDI_reset(); + +// Universal SysEx. +// Only implement MTS; consumers can do their own parsing via unimplemented_universal_sysex_collector. + +// MIDI Tuning Standard sends. +void bulk_tuning_dump_request(uint8_t device_id, uint8_t program); +void bulk_tuning_dump(uint8_t device_id, uint8_t program, char* name, uint8_t* tuning_data); +void single_note_tuning_change(uint8_t device_id, uint8_t program, uint8_t *note_tuning_data, uint8_t keys_changed); + + +// Feed bytes to this in the UART interrupt handler. +void parse_midi_stream(uint8_t byte); + + +// Public constants; magic numbers useful for consumers. +#define ALL_CALL_DEVICE_ID 0x7f +#define DEVICE_KEY_COUNT 128 +#define TUNING_LENGTH (3 * DEVICE_KEY_COUNT) +#define TUNING_NAME_LENGTH 16 +#define NOTE_TUNING_BYTES_PER_KEY 4 + + +#ifdef EXPORT_CONTROLLERS +// Controller constants. +typedef enum Controller { + BANK_SELECT = 0, + MODULATION_WHEEL = 1, + BREATH_CONTROLLER = 2, + // Undefined + FOOT_CONTROLLER = 4, + PORTAMENTO_TIME = 5, + DATA_ENTRY_MSB = 6, + CHANNEL_VOLUME = 7, + BALANCE = 8, + // Undefined + PAN = 10, + EXPRESSION = 11, + EFFECT1 = 12, + EFFECT2 = 13, + // Undefined + GP1 = 16, + GP2 = 17, + GP3 = 18, + GP4 = 19, + DAMPER_PEDAL = 64, + PORTAMENTO_TOGGLE = 65, + SOSTENUTO = 66, + SOFT_PEDAL = 67, + LEGATO_FOOTSWITCH = 68, + HOLD2 = 69, + SC1_SOUND_VARIATION = 70, + SC2_TIMBRE = 71, + SC3_RELEASE_TIME = 72, + SC4_ATTACK_TIME = 73, + SC5_BRIGHTNESS = 74, + SC6 = 75, + SC7 = 76, + SC8 = 77, + SC9 = 78, + SC10 = 79, + GP5 = 80, + GP6 = 81, + GP7 = 82, + GP8 = 83, + PORTAMENTO_CONTROL = 84, + // Undefined + EFFECTS_DEPTH1 = 91, + EFFECTS_DEPTH2 = 92, + EFFECTS_DEPTH3 = 93, + EFFECTS_DEPTH4 = 94, + EFFECTS_DEPTH5 = 95, + DATA_INCREMENT = 96, + DATA_DECREMENT = 97, + NONREGISTERED_LSB = 98, + NONREGISTERED_MSB = 99, + REGISTERED_LSB = 100, + REGISTERED_MSB = 101, + // undefined 102-119 + // reserved for channel mode 120-127 +}; + +typedef enum RegisteredParams { + PITCH_BEND_SENSITIVITY = 0, + FINE_TUNING = 1, + COARSE_TUNING = 2, + TUNING_PROGRAM_SELECT = 3, + TUNING_BANK_SELECT = 4 +}; + +#endif + + +#endif diff --git a/controller/inc/midi.h b/controller/inc/midi.h deleted file mode 100644 index 819db03..0000000 --- a/controller/inc/midi.h +++ /dev/null @@ -1,207 +0,0 @@ -#ifndef MIDI_H -#define MIDI_H - -#include -#include -#include - -// Configuration. - -#define DEBUG 0 // If defined, enable input safety checking (e.g. too large data bytes, bad ID numbers, etc). - // These checks have some performance downside. -#define RUNNING_STATUS 0 // If defined, the MIDI instrument stores a transmit status and uses running statuses whenever possible. -#define KEY_ON_VELOCITY 0 // If defined, the MIDI instrument sends velocities with Note On messages. -#undef RELEASE_VELOCITY // If defined, the MIDI instrument sends Note Off messages with velocities. - // Otherwise, sends Note On velocity 0 or Note Off velocity 0 according to ACTUAL_OFF_MESSAGE. -#undef ACTUAL_OFF_MESSAGE // If defined, the MIDI instrument sends true Note Off messages. - // Otherwise sends Note On velocity 0 (so as to exploit running status). -#undef EXPORT_CONTROLLERS // If defined, export constants useful for controller messages. - -// Consumers must specify -typedef struct { - void (*uart_write)(uint8_t); // Blocking, single-byte UART transmit function. - // Channel voice handlers. - void (*note_on_handler)(uint8_t, uint8_t, uint8_t); - void (*note_off_handler)(uint8_t, uint8_t, uint8_t); - void (*poly_key_handler)(uint8_t, uint8_t, uint8_t); - void (*control_change_handler)(uint8_t, uint8_t, uint8_t); - void (*program_change_handler)(uint8_t, uint8_t); - void (*aftertouch_handler)(uint8_t, uint8_t); - void (*pitch_bend_change_handler)(uint8_t, uint8_t); - // Channel mode handlers. - void (*all_sound_off_handler)(uint8_t); - void (*reset_all_controllers_handler)(uint8_t); - void (*local_control_handler)(uint8_t, uint8_t); - void (*all_notes_off_handler)(uint8_t); - void (*omni_on_handler)(uint8_t); - void (*omni_off_handler)(uint8_t); - void (*mono_on_handler)(uint8_t, uint8_t); - void (*poly_on_handler)(uint8_t); - // System common handlers. - void (*mtc_quarter_frame_handler)(uint8_t, uint8_t); - void (*song_position_pointer_handler)(uint8_t, uint8_t); - void (*song_select_handler)(uint8_t); - void (*tune_request_handler)(); - // System real time handlers. - void (*timing_clock_handler)(); - void (*start_handler)(); - void (*continue_handler)(); - void (*stop_handler)(); - void (*active_sensing_handler)(); - void (*system_reset_handler)(); - // System Exclusive handlers. - bool (*sysex_collector)(uint8_t); // Feeds most recent byte system exclusive byte (status and eox excluded, ID included) - // to client, returning false whenever the client determines sysex can be safely discarded. - // Client is expected to maintain parsing state externally, - // including resetting correctly after aborted parses. - // Client also should not abort the parse before the first post-manufacturer-ID byte. - void (*end_of_sysex_handler)(); // Sent only when client - // Universal System Exclusive handlers. - void (*bulk_tuning_dump_request_handler)(uint8_t, uint8_t); - void (*bulk_tuning_dump_handler)(uint8_t, uint8_t, char*, uint8_t*); - void (*single_note_tuning_change_handler)(uint8_t, uint8_t, uint8_t, uint8_t*); - // TODO: more. - bool (*unimplemented_universal_sysex_collector)(uint8_t); // Same as above. Parsing ends with end_of_sysex_handler. -} ConsumerBehavior; - -extern ConsumerBehavior pfns; // Initialize this globally in your main. - -// System exclusive sends. -void sysex(uint16_t manufacturer_id, bool long_id, uint8_t* contents, size_t contents_len); -void universal_nonrealtime(uint8_t device_id, uint16_t sub_id, uint8_t* contents, size_t contents_len); -void universal_realtime(uint8_t device_id, uint16_t sub_id, uint8_t* contents, size_t contents_len); - -// Channel voice sends. -#ifdef KEY_ON_VELOCITY -void note_on(uint8_t channel, uint8_t note, uint8_t velocity); -#else -void note_on(uint8_t channel, uint8_t note); -#endif -#ifdef RELEASE_VELOCITY -void note_off(uint8_t channel, uint8_t note, uint8_t velocity); -#else -void note_off(uint8_t channel, uint8_t note); -#endif -void control_change(uint8_t channel, uint8_t controller_number, uint8_t control_value); -void program_change(uint8_t channel, uint8_t program_number); -void aftertouch(uint8_t channel, uint8_t pressure_value); -void pitch_bend_change(uint8_t channel, uint16_t pressure_value); - -// Channel mode sends. -void all_sound_off(uint8_t channel); -void reset_all_controllers(uint8_t channel); -void local_control_on(uint8_t channel); -void local_control_off(uint8_t channel); -void all_notes_off(uint8_t channel); -void omni_on(uint8_t channel); -void omni_off(uint8_t channel); -void mono_on(uint8_t channel, uint8_t channel_count); -void poly_on(uint8_t channel); - - -// System Common sends. -// MTC Quarter Frame unimplemented. -void song_position_pointer(uint16_t position); -void song_select(uint8_t song); -void tune_request(); - -// System Real Time sends. -void timing_clock(); -void srt_start(); -void srt_continue(); -void srt_stop(); -void active_sensing(); -void MIDI_reset(); - -// Universal SysEx. -// Only implement MTS; consumers can do their own parsing via unimplemented_universal_sysex_collector. - -// MIDI Tuning Standard sends. -void bulk_tuning_dump_request(uint8_t device_id, uint8_t program); -void bulk_tuning_dump(uint8_t device_id, uint8_t program, char* name, uint8_t* tuning_data); -void single_note_tuning_change(uint8_t device_id, uint8_t program, uint8_t *note_tuning_data, uint8_t keys_changed); - - -// Feed bytes to this in the UART interrupt handler. -void parse_midi_stream(uint8_t byte); - - -// Public constants; magic numbers useful for consumers. -#define ALL_CALL_DEVICE_ID 0x7f -#define DEVICE_KEY_COUNT 128 -#define TUNING_LENGTH (3 * DEVICE_KEY_COUNT) -#define TUNING_NAME_LENGTH 16 -#define NOTE_TUNING_BYTES_PER_KEY 4 - - -#ifdef EXPORT_CONTROLLERS -// Controller constants. -typedef enum Controller { - BANK_SELECT = 0, - MODULATION_WHEEL = 1, - BREATH_CONTROLLER = 2, - // Undefined - FOOT_CONTROLLER = 4, - PORTAMENTO_TIME = 5, - DATA_ENTRY_MSB = 6, - CHANNEL_VOLUME = 7, - BALANCE = 8, - // Undefined - PAN = 10, - EXPRESSION = 11, - EFFECT1 = 12, - EFFECT2 = 13, - // Undefined - GP1 = 16, - GP2 = 17, - GP3 = 18, - GP4 = 19, - DAMPER_PEDAL = 64, - PORTAMENTO_TOGGLE = 65, - SOSTENUTO = 66, - SOFT_PEDAL = 67, - LEGATO_FOOTSWITCH = 68, - HOLD2 = 69, - SC1_SOUND_VARIATION = 70, - SC2_TIMBRE = 71, - SC3_RELEASE_TIME = 72, - SC4_ATTACK_TIME = 73, - SC5_BRIGHTNESS = 74, - SC6 = 75, - SC7 = 76, - SC8 = 77, - SC9 = 78, - SC10 = 79, - GP5 = 80, - GP6 = 81, - GP7 = 82, - GP8 = 83, - PORTAMENTO_CONTROL = 84, - // Undefined - EFFECTS_DEPTH1 = 91, - EFFECTS_DEPTH2 = 92, - EFFECTS_DEPTH3 = 93, - EFFECTS_DEPTH4 = 94, - EFFECTS_DEPTH5 = 95, - DATA_INCREMENT = 96, - DATA_DECREMENT = 97, - NONREGISTERED_LSB = 98, - NONREGISTERED_MSB = 99, - REGISTERED_LSB = 100, - REGISTERED_MSB = 101, - // undefined 102-119 - // reserved for channel mode 120-127 -}; - -typedef enum RegisteredParams { - PITCH_BEND_SENSITIVITY = 0, - FINE_TUNING = 1, - COARSE_TUNING = 2, - TUNING_PROGRAM_SELECT = 3, - TUNING_BANK_SELECT = 4 -}; - -#endif - - -#endif diff --git a/controller/inc/startup.h b/controller/inc/startup.h new file mode 100644 index 0000000..5e47193 --- /dev/null +++ b/controller/inc/startup.h @@ -0,0 +1,173 @@ +#ifndef STARTUP_H +#define STARTUP_H +/* +* Copyright (c) 2018, Shawn D'silva +* All rights reserved. +* +* This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . +* +* File: startup.c +* Author: Shawn D'silva . +* Version: 1.0.0. +* Description: startup header for the TM4C Launchpad board,defines the vector table + handlers and ISRS,also declares external variables +*/ + +// +-----------------------------------------------------------------------------------+ +// + Type Definitions and Macros + +// +-----------------------------------------------------------------------------------+ + +/* + * Defines a macro DEFAULT that aliases the function prototype + * to Default_Handler if the function is not defined +*/ +#define DEFAULT __attribute__((weak, alias("Default_Handler"))) + +/* Defines a type for the ISR's in the vector table */ +typedef void (*element_t)(void); + +/* Defines a type for the vector table */ +typedef union { + element_t isr; //all ISRs use this type + void *stack_top; //pointer to top of the stack +} vector_table_t; + + +// +-----------------------------------------------------------------------------------+ +// + Prototypes of Basic Exception Handlers + +// +-----------------------------------------------------------------------------------+ + +//Default Handler,does nothing +void Default_Handler(void); + +//System Exception Handlers + +void Reset_Handler(void); +DEFAULT void NMI_Handler(void); +DEFAULT void SVC_Handler(void); +DEFAULT void DebugMonitor_Handler(void); +DEFAULT void PendSV_Handler(void); +DEFAULT void SysTick_Handler(void); + +//Fault Handlers + +DEFAULT void HardFault_Handler(void); +DEFAULT void MemManageFault_Handler(void); +DEFAULT void BusFault_Handler(void); +DEFAULT void UsageFault_Handler(void); + +// +-----------------------------------------------------------------------------------+ +// + Prototypes of Interrupt Service Routines + +// +-----------------------------------------------------------------------------------+ +DEFAULT void GPIOPortA_ISR(void); +DEFAULT void GPIOPortB_ISR(void); +DEFAULT void GPIOPortC_ISR(void); +DEFAULT void GPIOPortD_ISR(void); +DEFAULT void GPIOPortE_ISR(void); +DEFAULT void UART0_ISR(void); +DEFAULT void UART1_ISR(void); +DEFAULT void SPI0_ISR(void); +DEFAULT void I2C0_ISR(void); +DEFAULT void PWM0Fault_ISR(void); +DEFAULT void PWM0Generator0_ISR(void); +DEFAULT void PWM0Generator1_ISR(void); +DEFAULT void PWM0Generator2_ISR(void); +DEFAULT void QEI0_ISR(void); +DEFAULT void ADC0Sequence0_ISR(void); +DEFAULT void ADC0Sequence1_ISR(void); +DEFAULT void ADC0Sequence2_ISR(void); +DEFAULT void ADC0Sequence3_ISR(void); +DEFAULT void WatchDogTimer_ISR(void); +DEFAULT void Timer0A_ISR(void); +DEFAULT void Timer0B_ISR(void); +DEFAULT void Timer1A_ISR(void); +DEFAULT void Timer1B_ISR(void); +DEFAULT void Timer2A_ISR(void); +DEFAULT void Timer2B_ISR(void); +DEFAULT void AnalogComparator0_ISR(void); +DEFAULT void AnalogComparator1_ISR(void); +DEFAULT void SystemCtrl_ISR(void); +DEFAULT void FlashCtrl_ISR(void); +DEFAULT void GPIOPortF_ISR(void); +DEFAULT void UART2_ISR(void); +DEFAULT void SPI1_ISR(void); +DEFAULT void Timer3A_ISR(void); +DEFAULT void Timer3B_ISR(void); +DEFAULT void I2C1_ISR(void); +DEFAULT void QEI1_ISR(void); +DEFAULT void CAN0_ISR(void); +DEFAULT void CAN1_ISR(void); +DEFAULT void Hibernation_ISR(void); +DEFAULT void USB0_ISR(void); +DEFAULT void PWM0Generator3_ISR(void); +DEFAULT void UDMASoftware_ISR(void); +DEFAULT void UDMAError_ISR(void); +DEFAULT void ADC1Sequence0_ISR(void); +DEFAULT void ADC1Sequence1_ISR(void); +DEFAULT void ADC1Sequence2_ISR(void); +DEFAULT void ADC1Sequence3_ISR(void); +DEFAULT void SPI2_ISR(void); +DEFAULT void SPI3_ISR(void); +DEFAULT void UART3_ISR(void); +DEFAULT void UART4_ISR(void); +DEFAULT void UART5_ISR(void); +DEFAULT void UART6_ISR(void); +DEFAULT void UART7_ISR(void); +DEFAULT void I2C2_ISR(void); +DEFAULT void I2C3_ISR(void); +DEFAULT void Timer4A_ISR(void); +DEFAULT void Timer4B_ISR(void); +DEFAULT void Timer5A_ISR(void); +DEFAULT void Timer5B_ISR(void); +DEFAULT void WideTimer0A_ISR(void); +DEFAULT void WideTimer0B_ISR(void); +DEFAULT void WideTimer1A_ISR(void); +DEFAULT void WideTimer1B_ISR(void); +DEFAULT void WideTimer2A_ISR(void); +DEFAULT void WideTimer2B_ISR(void); +DEFAULT void WideTimer3A_ISR(void); +DEFAULT void WideTimer3B_ISR(void); +DEFAULT void WideTimer4A_ISR(void); +DEFAULT void WideTimer4B_ISR(void); +DEFAULT void WideTimer5A_ISR(void); +DEFAULT void WideTimer5B_ISR(void); +DEFAULT void SystemException_ISR(void); +DEFAULT void PWM1Generator0_ISR(void); +DEFAULT void PWM1Generator1_ISR(void); +DEFAULT void PWM1Generator2_ISR(void); +DEFAULT void PWM1Generator3_ISR(void); +DEFAULT void PWM1Fault_ISR(void); + +// +-----------------------------------------------------------------------------------+ +// + External Variables declaration + +// +-----------------------------------------------------------------------------------+ + +//main() of your program +extern int main(void); + +//stack pointer +extern int _stack_ptr; +//.text/code,stored in Flash +extern int _etext; +//.data,copied into RAM on boot +extern int _data; +extern int _edata; +//.bss,unitialized variables +extern int _bss; +extern int _ebss; + +/***************************************** END OF FILE *******************************************/ + + +#endif diff --git a/controller/libs/base_midi.c b/controller/libs/base_midi.c new file mode 100644 index 0000000..e146ec0 --- /dev/null +++ b/controller/libs/base_midi.c @@ -0,0 +1,835 @@ + // 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 +#include + +#ifdef RUNNING_STATUS +uint8_t last_status = 0x00; +#endif + +// Helper functions +#define MAX_DATA_BYTE 0b01111111 +static inline void MIDI_bare_send(uint8_t status) { +#ifdef DEBUG + if (status <= MAX_DATA_BYTE) { + while(true); // Illegal status. + } +#endif + + pfns.uart_write(status); + +} + +static inline void MIDI_single_send(uint8_t status, uint8_t byte) { +#ifdef DEBUG + if (status <= MAX_DATA_BYTE || byte > MAX_DATA_BYTE) { + while(true); // Illegal status or data byte. + } +#endif + +#ifdef RUNNING_STATUS + if (status != last_status) { + pfns.uart_write(status); + last_status = status; + } +#else + pfns.uart_write(status); +#endif + pfns.uart_write(byte); +} + +static inline void MIDI_send(uint8_t status, uint8_t byte1, uint8_t byte2) { +#ifdef DEBUG + if (status <= MAX_DATA_BYTE || byte1 > MAX_DATA_BYTE || byte2 > MAX_DATA_BYTE) { + while(true); // Illegal status or data byte. + } +#endif + +#ifdef RUNNING_STATUS + if (status != last_status) { + pfns.uart_write(status); + last_status = status; + } +#else + pfns.uart_write(status); +#endif + pfns.uart_write(byte1); + pfns.uart_write(byte2); +} + + +#define MAX_NON_UNIVERSAL_ID (MAX_DATA_BYTE - 2) +#define SYSEX_STATUS 0xf0 +#define EOX_STATUS 0xf7 +void sysex(uint16_t manufacturer_id, uint8_t* contents, size_t contents_len) { +#ifdef DEBUG + if (manufacturer_id == 0 || (manufacturer_id >> 8) > MAX_DATA_BYTE || (manufacturer_id & 0x00ff) > MAX_DATA_BYTE) { + while(true); // Invalid ID. + } + + // Pretty inefficient to iterate contents twice, but prevents writing partial SysEx messages to the bus. + for (size_t i = 0; i < contents_len; i++) { + if (contents[i] > MAX_DATA_BYTE) { + while(true); + } + } +#endif + + if ((manufacturer_id >> 8) != 0) { + pfns.uart_write(SYSEX_STATUS); + pfns.uart_write(0x00); + pfns.uart_write(manufacturer_id >> 8); + pfns.uart_write(manufacturer_id & 0x00ff); + } else { + if (manufacturer_id > MAX_NON_UNIVERSAL_ID) { + while(true); // Used universal sysex ID. + } + + pfns.uart_write(manufacturer_id); + } + + for (size_t i = 0; i < contents_len; i++) { + pfns.uart_write(contents[i]); + } + + pfns.uart_write(EOX_STATUS); +} + +#define UNIVERSAL_NONREALTIME_SUBID 0x7e +#define UNIVERSAL_REALTIME_SUBID 0x7f +void universal_nonrealtime(uint8_t device_id, uint16_t sub_id, uint8_t *contents, size_t contents_len) { +#ifdef DEBUG + if ((sub_id >> 8) > MAX_DATA_BYTE || (sub_id & 0x00ff) > MAX_DATA_BYTE) { + while(true); + } + + for (size_t i = 0; i < contents_len; i++) { + if (contents[i] > MAX_DATA_BYTE) { + while(true); + } + } +#endif + + pfns.uart_write(SYSEX_STATUS); + pfns.uart_write(UNIVERSAL_NONREALTIME_SUBID); + pfns.uart_write(device_id); + pfns.uart_write(sub_id >> 8); + pfns.uart_write(sub_id & 0x00ff); + + for (size_t i = 0; i < contents_len; i++) { + pfns.uart_write(contents[i]); + } + + pfns.uart_write(EOX_STATUS); +} + +void universal_realtime(uint8_t device_id, uint16_t sub_id, uint8_t *contents, size_t contents_len) { +#ifdef DEBUG + if ((sub_id >> 8) > MAX_DATA_BYTE || (sub_id & 0x00ff) > MAX_DATA_BYTE) { + while(true); + } + + for (size_t i = 0; i < contents_len; i++) { + if (contents[i] > MAX_DATA_BYTE) { + while(true); + } + } +#endif + + pfns.uart_write(SYSEX_STATUS); + pfns.uart_write(UNIVERSAL_REALTIME_SUBID); + pfns.uart_write(device_id); + pfns.uart_write(sub_id >> 8); + pfns.uart_write(sub_id & 0x00ff); + + for (size_t i = 0; i < contents_len; i++) { + pfns.uart_write(contents[i]); + } + + pfns.uart_write(EOX_STATUS); +} +// Channel voice messages. + +#define MAX_CHANNEL 0x0f +#define NOTE_OFF_MASK 0x80 +#define NOTE_ON_MASK 0x90 +#define POLY_KEY_PRESSURE_MASK 0xa0 +#define CONTROL_CHANGE_MASK 0xb0 +#define PROGRAM_CHANGE_MASK 0xc0 +#define AFTERTOUCH_MASK 0xd0 +#define PITCH_BEND_MASK 0xe0 + +#define MIDDLE_VELOCITY 0x40 + +#ifdef KEY_ON_VELOCITY +void note_on(uint8_t channel, uint8_t note, uint8_t velocity) { +#ifdef DEBUG + if (channel > MAX_CHANNEL || note > MAX_DATA_BYTE || velocity > MAX_DATA_BYTE) { + while(true); + } +#endif + + MIDI_send(NOTE_ON_MASK | channel, note, velocity); + +} + +#else + +void note_on(uint8_t channel, uint8_t note) { +#ifdef DEBUG + if (channel > MAX_CHANNEL || note > MAX_DATA_BYTE) { + while(true); + } +#endif + + MIDI_send(NOTE_ON_MASK | channel, note, MIDDLE_VELOCITY); + +} + + +#endif + +#ifdef RELEASE_VELOCITY + +void note_off(uint8_t channel, uint8_t note, uint8_t velocity) { +#ifdef DEBUG + if (channel > MAX_CHANNEL || note > MAX_DATA_BYTE || velocity > MAX_DATA_BYTE) { + while(true); + } +#endif + + MIDI_send(NOTE_OFF_MASK | channel, note, velocity); + +} + +#else + +void note_off(uint8_t channel, uint8_t note) { +#ifdef DEBUG + if (channel > MAX_CHANNEL || note > MAX_DATA_BYTE) { + while(true); + } +#endif + +#ifdef ACTUAL_OFF_MESSAGE + MIDI_send(NOTE_OFF_MASK | channel, note, MIDDLE_VELOCITY); +#else + MIDI_send(NOTE_ON_MASK | channel, note, 0); +#endif + +} + +#endif + +#define MAX_CONTROLLER 119 +void control_change(uint8_t channel, uint8_t controller_number, uint8_t control_value) { +#ifdef DEBUG + if (channel > MAX_CHANNEL || controller_number > MAX_CONTROLLER || control_value > MAX_DATA_BYTE) { + while(true); + } +#endif + + MIDI_send(CONTROL_CHANGE_MASK | channel, controller_number, control_value); + +} + +void program_change(uint8_t channel, uint8_t program_number) { +#ifdef DEBUG + if (channel > MAX_CHANNEL || program_number > MAX_DATA_BYTE) { + while(true); + } +#endif + + MIDI_single_send(PROGRAM_CHANGE_MASK | channel, program_number); + +} + +void aftertouch(uint8_t channel, uint8_t pressure_value) { +#ifdef DEBUG + if (channel > MAX_CHANNEL || pressure_value > MAX_DATA_BYTE) { + while(true); + } +#endif + + MIDI_single_send(AFTERTOUCH_MASK | channel, pressure_value); + +} + +void pitch_bend_change(uint8_t channel, uint16_t pressure_value) { +#ifdef DEBUG + if (channel > MAX_CHANNEL || pressure_value > ((MAX_DATA_BYTE << 8) | MAX_DATA_BYTE)) { + while(true); + } +#endif + + MIDI_single_send(PITCH_BEND_MASK | channel, pressure_value); + +} + + + +// Channel mode messages. + +#define SOUND_OFF_MODE (MAX_CONTROLLER + 1) +#define RESET_ALL_MODE (MAX_CONTROLLER + 2) +#define LOCAL_CONTROL_MODE (MAX_CONTROLLER + 3) +#define NOTES_OFF_MODE (MAX_CONTROLLER + 4) +#define OMNI_OFF_MODE (MAX_CONTROLLER + 5) +#define OMNI_ON_MODE (MAX_CONTROLLER + 6) +#define MONO_ON_MODE (MAX_CONTROLLER + 7) +#define POLY_ON_MODE (MAX_CONTROLLER + 8) + +void all_sound_off(uint8_t channel) { +#ifdef DEBUG + if (channel > MAX_CHANNEL) { + while(true); + } +#endif + + MIDI_send(CONTROL_CHANGE_MASK | channel, SOUND_OFF_MODE, 0); + +} + +void reset_all_controllers(uint8_t channel) { +#ifdef DEBUG + if (channel > MAX_CHANNEL) { + while(true); + } +#endif + + MIDI_send(CONTROL_CHANGE_MASK | channel, RESET_ALL_MODE, 0); + +} + +void local_control_on(uint8_t channel) { +#ifdef DEBUG + if (channel > MAX_CHANNEL) { + while(true); + } +#endif + + MIDI_send(CONTROL_CHANGE_MASK | channel, LOCAL_CONTROL_MODE, MAX_DATA_BYTE); + +} + +void local_control_off(uint8_t channel) { +#ifdef DEBUG + if (channel > MAX_CHANNEL) { + while(true); + } +#endif + + MIDI_send(CONTROL_CHANGE_MASK | channel, LOCAL_CONTROL_MODE, 0); + +} + +void all_notes_off(uint8_t channel) { +#ifdef DEBUG + if (channel > MAX_CHANNEL) { + while(true); + } +#endif + + MIDI_send(CONTROL_CHANGE_MASK | channel, NOTES_OFF_MODE, 0); + +} + +void omni_on(uint8_t channel) { +#ifdef DEBUG + if (channel > MAX_CHANNEL) { + while(true); + } +#endif + + MIDI_send(CONTROL_CHANGE_MASK | channel, OMNI_ON_MODE, 0); + +} + +void omni_off(uint8_t channel) { +#ifdef DEBUG + if (channel > MAX_CHANNEL) { + while(true); + } +#endif + + MIDI_send(CONTROL_CHANGE_MASK | channel, OMNI_OFF_MODE, 0); + +} + +#define RECEIVER_CHANNEL_COUNT 0 +void mono_on(uint8_t channel, uint8_t channel_count) { +#ifdef DEBUG + if (channel > MAX_CHANNEL || channel_count > MAX_DATA_BYTE) { + while(true); + } +#endif + + MIDI_send(CONTROL_CHANGE_MASK | channel, MONO_ON_MODE, channel_count); + +} + +void poly_on(uint8_t channel) { +#ifdef DEBUG + if (channel > MAX_CHANNEL) { + while(true); + } +#endif + + MIDI_send(CONTROL_CHANGE_MASK | channel, POLY_ON_MODE, 0); + +} + + +// System common messages. +// Not implemented: +// - MTC Quarter Frame +// EOX is automatically sent in the functions that send exclusives. + +#define MTC_QUARTER_FRAME_STATUS 0xf1 +#define SONG_POSITION_POINTER_STATUS 0xf2 +// Undefined. +#define SONG_SELECT_STATUS 0xf3 +#define TUNE_REQUEST_STATUS 0xf6 + +void song_position_pointer(uint16_t position) { +#ifdef DEBUG + if ((position & 0x0ff) > MAX_DATA_BYTE || (position >> 8) > MAX_DATA_BYTE) { + while(true); + } +#endif + + MIDI_send(SONG_POSITION_POINTER_STATUS, position & 0x00ff, position >> 8); + +} + +void song_select(uint8_t song) { +#ifdef DEBUG + if (song > MAX_DATA_BYTE) { + while(true); + } +#endif + + MIDI_single_send(SONG_SELECT_STATUS, song); + +} + +void tune_request() { + MIDI_bare_send(TUNE_REQUEST_STATUS); +} + + + +// System real time messages. +// Not implemented: +// - Timing Clock, +// - Start, +// - Continue, +// - Stop, +// - Active Sensing. + +#define TIMING_CLOCK_STATUS 0xf8 +// Undefined. +#define START_STATUS 0xfa +#define CONTINUE_STATUS 0xfb +#define STOP_STATUS 0xfc +// Undefined. +#define ACTIVE_SENSING_STATUS 0xfe +#define SYSTEM_RESET_STATUS 0xff +void timing_clock() { + MIDI_bare_send(TIMING_CLOCK_STATUS); +} + +void srt_start() { + MIDI_bare_send(START_STATUS); +} + +void srt_continue() { + MIDI_bare_send(CONTINUE_STATUS); +} + +void srt_stop() { + MIDI_bare_send(STOP_STATUS); +} + +void active_sensing() { + MIDI_bare_send(ACTIVE_SENSING_STATUS); +} + +void MIDI_reset() { + MIDI_bare_send(SYSTEM_RESET_STATUS); +} + + +// Universal system exclusive messages. + + +// Only implement MIDI Tuning Standard universals and general information. + + +#define TUNING_STANDARD_SUBID 0x08 +#define BULK_DUMP_REQUEST_SUBID 0x00 +void bulk_tuning_dump_request(uint8_t device_id, uint8_t program) { +#ifdef DEBUG + if (program > MAX_DATA_BYTE || device_id > MAX_DATA_BYTE) { + while(true); + } +#endif + + uint8_t contents[] = {program}; + + universal_nonrealtime(device_id, (TUNING_STANDARD_SUBID << 8) | BULK_DUMP_REQUEST_SUBID, contents, 1); + +} + + +#define BULK_DUMP_REPLY_SUBID 0x01 +void bulk_tuning_dump(uint8_t device_id, uint8_t program, char* name, uint8_t* tuning_data) { +#ifdef DEBUG + if (device_id > MAX_DATA_BYTE || program > MAX_DATA_BYTE) { + while(true); + } +#endif + + uint8_t *contents = malloc(1 + TUNING_NAME_LENGTH + TUNING_LENGTH + 1); + contents[0] = program; + memcpy(contents + 1, name, TUNING_NAME_LENGTH); + memcpy(contents + 1 + TUNING_NAME_LENGTH, tuning_data, TUNING_LENGTH); + + // I hate this freaking "standard"...what TF do I checksum??? + uint8_t checksum = UNIVERSAL_NONREALTIME_SUBID ^ device_id ^ TUNING_STANDARD_SUBID ^ BULK_DUMP_REPLY_SUBID ^ program; + for (int i = 0; i < TUNING_LENGTH; i++) { + checksum ^= tuning_data[i]; + } + + contents[1 + TUNING_NAME_LENGTH + DEVICE_KEY_COUNT] = checksum; + + universal_nonrealtime(device_id, (TUNING_STANDARD_SUBID << 8) | BULK_DUMP_REPLY_SUBID, contents, + 1 + TUNING_NAME_LENGTH + TUNING_LENGTH + 1); + + free(contents); + +} + +#define NOTE_CHANGE_SUBID 0x02 +void single_note_tuning_change(uint8_t device_id, uint8_t program, uint8_t *note_tuning_data, uint8_t keys_changed) { +#ifdef DEBUG + if (device_id > MAX_DATA_BYTE || program > MAX_DATA_BYTE || keys_changed > DEVICE_KEY_COUNT) { + while(true); + } +#endif + + uint8_t *contents = malloc(2 + NOTE_TUNING_BYTES_PER_KEY * keys_changed); + contents[0] = program; + contents[1] = keys_changed; + memcpy(contents + 2, note_tuning_data, NOTE_TUNING_BYTES_PER_KEY * keys_changed); + + universal_realtime(device_id, (TUNING_STANDARD_SUBID << 8) | NOTE_CHANGE_SUBID, contents, + 2 + NOTE_TUNING_BYTES_PER_KEY * keys_changed); + + free(contents); + +} + +// TODO: tuning banks. + + +// Parsing. +// Stream parsing. +typedef struct { + uint8_t status; + bool first_byte; + uint8_t byte0; + bool send_eox; + uint8_t *stack; + size_t top; + size_t size; +} ParserMemory; + +#define WAITING_FOR_STATUS 0x00 +ParserMemory memory = {.status = WAITING_FOR_STATUS, + .first_byte = false, + .byte0 = 0x00, + .send_eox = false, + .stack = NULL, // TODO: initialize from main. + .top = 0, + .size = 128}; + +static inline void push_fn(uint8_t val) { + if (memory.top == memory.size - 1) { + memory.stack = realloc(memory.stack, memory.size + 128); + } + + memory.stack[memory.top + 1] = val; + ++memory.top; +} + +#define push() do { \ + push_fn(byte); \ + } while(0) + +static inline uint8_t pop() { + if (memory.size - memory.top > 128) { + memory.stack = realloc(memory.stack, memory.size - 128); + } + + --memory.top; + return memory.stack[memory.top + 1]; +} + +static inline void reset() { + memory.stack = realloc(memory.stack, 128); + memory.size = 128; + memory.top = 0; + memory.status = WAITING_FOR_STATUS; +} + +#define second_byte() do { \ + memory.first_byte = false; \ + memory.byte0 = byte; \ + } while(0) + + +#define channel (memory.status & 0x0f) + + +// Memory should be large enough to handle the largest message that's expected to be processed automatically here. +void parse_midi_stream(uint8_t byte) { + switch (byte) { + // Status byte. + case NOTE_OFF_MASK ... (PITCH_BEND_MASK + MAX_CHANNEL): + memory.status = byte; + break; + + case MTC_QUARTER_FRAME_STATUS ... SONG_SELECT_STATUS: + memory.status = byte; + break; + case TUNE_REQUEST_STATUS: + pfns.tune_request_handler(); + memory.status = WAITING_FOR_STATUS; + break; + + case TIMING_CLOCK_STATUS: + pfns.timing_clock_handler(); + break; + case START_STATUS: + pfns.start_handler(); + break; + case CONTINUE_STATUS: + pfns.continue_handler(); + break; + case STOP_STATUS: + pfns.stop_handler(); + break; + case ACTIVE_SENSING_STATUS: + pfns.active_sensing_handler(); + break; + case SYSTEM_RESET_STATUS: + pfns.system_reset_handler(); + break; + case SYSEX_STATUS: + memory.status = byte; + break; + case EOX_STATUS: + if (memory.send_eox) { + pfns.end_of_sysex_handler(); + memory.send_eox = false; + } + reset(); + break; + + // Data byte. + case 0x00 ... MAX_DATA_BYTE: + switch (memory.status) { + case WAITING_FOR_STATUS: + break; + + case NOTE_OFF_MASK ... (NOTE_OFF_MASK + MAX_CHANNEL): + if (memory.first_byte) + second_byte(); + else { + pfns.note_off_handler(channel, memory.byte0, byte); + memory.first_byte = true; + } + break; + case NOTE_ON_MASK ... (NOTE_ON_MASK + MAX_CHANNEL): + if (memory.first_byte) + second_byte(); + else { + pfns.note_on_handler(channel, memory.byte0, byte); + memory.first_byte = true; + } + break; + case POLY_KEY_PRESSURE_MASK ... (POLY_KEY_PRESSURE_MASK + MAX_CHANNEL): + if (memory.first_byte) + second_byte(); + else { + pfns.poly_key_handler(channel, memory.byte0, byte); + memory.first_byte = true; + } + break; + case CONTROL_CHANGE_MASK ... (CONTROL_CHANGE_MASK + MAX_CHANNEL): + if (memory.first_byte) + second_byte(); + else { + switch (memory.byte0) { + case 0x00 ... MAX_CONTROLLER: + pfns.control_change_handler(channel, memory.byte0, byte); + break; + case SOUND_OFF_MODE: + pfns.all_sound_off_handler(channel); + break; + case RESET_ALL_MODE: + pfns.reset_all_controllers_handler(channel); + break; + case LOCAL_CONTROL_MODE: + pfns.local_control_handler(channel, byte); + break; + case NOTES_OFF_MODE: + pfns.all_notes_off_handler(channel); + break; + case OMNI_OFF_MODE: + pfns.omni_off_handler(channel); + break; + case OMNI_ON_MODE: + pfns.omni_on_handler(channel); + break; + case MONO_ON_MODE: + pfns.mono_on_handler(channel, byte); + break; + case POLY_ON_MODE: + pfns.poly_on_handler(channel); + break; + default: + while(true); // Should be unreachable. + } + memory.first_byte = true; + } + break; + case PROGRAM_CHANGE_MASK ... (PROGRAM_CHANGE_MASK + MAX_CHANNEL): + pfns.program_change_handler(channel, byte); + break; + case AFTERTOUCH_MASK ... (AFTERTOUCH_MASK + MAX_CHANNEL): + pfns.aftertouch_handler(channel, byte); + break; + case PITCH_BEND_MASK ... (PITCH_BEND_MASK + MAX_CHANNEL): + pfns.pitch_bend_change_handler(channel, byte); + break; + + + case MTC_QUARTER_FRAME_STATUS: + if (memory.first_byte) + second_byte(); + else { + pfns.mtc_quarter_frame_handler(memory.byte0, byte); + memory.first_byte = true; + } + break; + case SONG_POSITION_POINTER_STATUS: + if (memory.first_byte) + second_byte(); + else { + pfns.song_position_pointer_handler(memory.byte0, byte); + memory.first_byte = true; + } + break; + case SONG_SELECT_STATUS: + pfns.song_select_handler(byte); + break; + + case SYSEX_STATUS: + if (memory.first_byte) { + reset(); // In case last sysex got interrupted by a status. + if (byte <= MAX_NON_UNIVERSAL_ID) + pfns.sysex_collector(byte); + second_byte(); + } else + switch (memory.byte0) { + case UNIVERSAL_NONREALTIME_SUBID: + push(); + if (memory.top > 2) { + uint8_t device_id = memory.stack[0]; + uint8_t subid1 = memory.stack[1]; + uint8_t subid2 = memory.stack[2]; + switch (subid1) { + case TUNING_STANDARD_SUBID: + switch (subid2) { + case BULK_DUMP_REQUEST_SUBID: + pfns.bulk_tuning_dump_request_handler(device_id, byte); + reset(); + break; + case BULK_DUMP_REPLY_SUBID: + if (memory.top == 4 + TUNING_NAME_LENGTH + TUNING_LENGTH - 1) { + uint8_t tuning_program = memory.stack[3]; + uint8_t checksum = UNIVERSAL_NONREALTIME_SUBID ^ device_id ^ TUNING_STANDARD_SUBID \ + ^ BULK_DUMP_REPLY_SUBID ^ tuning_program; + for (int i = 0; i < TUNING_LENGTH; i++) { + checksum ^= memory.stack[4 + TUNING_NAME_LENGTH - 1 + i]; + } + + if (memory.stack[memory.top] == checksum) { + pfns.bulk_tuning_dump_handler(memory.stack[0], memory.stack[3], (char *)(memory.stack + 4), + memory.stack + 4 + TUNING_NAME_LENGTH); + } + + reset(); + } + default: + while(true); // Unrecognized tuning standard subid2. + } + break; + default: + if (!pfns.unimplemented_universal_sysex_collector(byte)) { + reset(); + } else { + push(); + } + break; + } + } + break; + + case UNIVERSAL_REALTIME_SUBID: + push(); + if (memory.top > 2) { + uint8_t device_id = memory.stack[0]; + uint8_t subid1 = memory.stack[1]; + uint8_t subid2 = memory.stack[2]; + switch (subid1) { + case TUNING_STANDARD_SUBID: + switch (subid2) { + case NOTE_CHANGE_SUBID: + uint8_t program_number = memory.stack[3]; + uint8_t change_count = memory.stack[4]; + if (memory.top >= 4 && memory.top == 4 + (size_t)change_count + 1 - 1) { + pfns.single_note_tuning_change_handler(device_id, program_number, change_count, memory.stack + 5); + reset(); + } + break; + default: + while(true); // Unrecognized tuning standard message. + } + break; + default: + break; + } + } + break; + default: + if (!pfns.sysex_collector(byte)) { + reset(); + } else { + push(); + } + break; + } + default: + while(true); // Unhandled status got set, somehow. + } + break; + + default: + while(true); // Unrecognized status byte. + } +} diff --git a/controller/libs/midi.c b/controller/libs/midi.c deleted file mode 100644 index b718818..0000000 --- a/controller/libs/midi.c +++ /dev/null @@ -1,826 +0,0 @@ - // 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" - -#ifdef RUNNING_STATUS -uint8_t last_status = 0x00; -#endif - -// Helper functions -#define MAX_DATA_BYTE 0b01111111 -static inline void MIDI_bare_send(uint8_t status) { -#ifdef DEBUG - if (status <= MAX_DATA_BYTE) { - while(true); // Illegal status. - } -#endif - - pfns->uart_write(status); - -} - -static inline void MIDI_single_send(uint8_t status, uint8_t byte) { -#ifdef DEBUG - if (status <= MAX_DATA_BYTE || byte > MAX_DATA_BYTE) { - while(true); // Illegal status or data byte. - } -#endif - -#ifdef RUNNING_STATUS - if (status != last_status) { - pfns->uart_write(status); - last_status = status; - } -#else - pfns->uart_write(status); -#endif - pfns->uart_write(byte); -} - -static inline void MIDI_send(uint8_t status, uint8_t byte1, uint8_t byte2) { -#ifdef DEBUG - if (status <= MAX_DATA_BYTE || byte1 > MAX_DATA_BYTE || byte2 > MAX_DATA_BYTE) { - while(true); // Illegal status or data byte. - } -#endif - -#ifdef RUNNING_STATUS - if (status != last_status) { - pfns->uart_write(status); - last_status = status; - } -#else - pfns->uart_write(status); -#endif - pfns->uart_write(byte1); - pfns->uart_write(byte2); -} - - -#define MAX_NON_UNIVERSAL_ID (MAX_DATA_BYTE - 2) -#define SYSEX_STATUS 0xf0 -#define EOX_STATUS 0xf7 -void sysex(uint16_t manufacturer_id, uint8_t* contents, size_t contents_len) { -#ifdef DEBUG - if (manufacturer_id == 0 || (manufacturer_id >> 8) > MAX_DATA_BYTE || (manufacturer_id & 0x00ff) > MAX_DATA_BYTE) { - while(true); // Invalid ID. - } - - // Pretty inefficient to iterate contents twice, but prevents writing partial SysEx messages to the bus. - for (int i = 0; i < contents_len, i++) { - if (contents[i] > MAX_DATA_BYTE) { - while(true); - } - } -#endif - - if ((manufacturer_id >> 8) != 0) { - pfns->uart_write(SYSEX_STATUS); - pfns->uart_write(0x00); - pfns->uart_write(manufacturer_id >> 8); - pfns->uart_write(manufacturer_id & 0x00ff); - } else { - if (manufacturer_id > MAX_NON_UNIVERSAL_ID) { - while(true); // Used universal sysex ID. - } - - pfns->uart_write(manufacturer_id); - } - - for (int i = 0; i < message.contents_len; i++) { - pfns->uart_write(message.contents[i]); - } - - pfns->uart_write(EOX_STATUS); -} - -#define NON_REAL_TIME_ID 0x7e -#define REAL_TIME_ID 0x7f -void universal_nonrealtime(uint8_t device_id, uint16_t sub_id, uint8_t *contents, size_t contents_len) { -#ifdef DEBUG - if ((sub_id >> 8) > MAX_DATA_BYTE || (sub_id & 0x00ff) > MAX_DATA_BYTE) { - while(true); - } - - for (int i = 0; i < contents_len; i++) { - if (contents[i] > MAX_DATA_BYTE) { - while(true); - } - } -#endif - - pfns->uart_write(SYSEX_STATUS); - pfns->uart_write(REAL_TIME_ID); - pfns->uart_write(sub_id >> 8); - pfns->uart_write(sub_id & 0x00ff); - - for (int i = 0; i < message.contents_len; i++) { - pfns->uart_write(message.contents[i]); - } - - pfns->uart_write(EOX_STATUS); -} - -void universal_realtime(uint8_t device_id, uint16_t sub_id, uint8_t *contents, size_t contents_len) { -#ifdef DEBUG - if ((sub_id >> 8) > MAX_DATA_BYTE || (sub_id & 0x00ff) > MAX_DATA_BYTE) { - while(true); - } - - for (int i = 0; i < contents_len; i++) { - if (contents[i] > MAX_DATA_BYTE) { - while(true); - } - } -#endif - - pfns->uart_write(SYSEX_STATUS); - pfns->uart_write(NON_REAL_TIME_ID); - pfns->uart_write(sub_id >> 8); - pfns->uart_write(sub_id & 0x00ff); - - for (int i = 0; i < message.contents_len; i++) { - pfns->uart_write(message.contents[i]); - } - - pfns->uart_write(EOX_STATUS); -} -// Channel voice messages. - -#define MAX_CHANNEL 0x0f -#define NOTE_OFF_MASK 0x80 -#define NOTE_ON_MASK 0x90 -#define POLY_KEY_PRESSURE_MASK 0xa0 -#define CONTROL_CHANGE_MASK 0xb0 -#define PROGRAM_CHANGE_MASK 0xc0 -#define AFTERTOUCH_MASK 0xd0 -#define PITCH_BEND_MASK 0xe0 - -#define MIDDLE_VELOCITY 0x40 - -#ifdef KEY_ON_VELOCITY -void note_on(uint8_t channel, uint8_t note, uint8_t velocity) { -#ifdef DEBUG - if (channel > MAX_CHANNEL || note > MAX_DATA_BYTE || velocity > MAX_DATA_BYTE) { - while(true); - } -#endif - - MIDI_send(NOTE_ON_MASK | channel, note, velocity); - -} - -#else - -void note_on(uint8_t channel, uint8_t note) { -#ifdef DEBUG - if (channel > MAX_CHANNEL || note > MAX_DATA_BYTE) { - while(true); - } -#endif - - MIDI_send(NOTE_ON_MASK | channel, note, MIDDLE_VELOCITY); - -} - - -#endif - -#ifdef RELEASE_VELOCITY - -void note_off(uint8_t channel, uint8_t note, uint8_t velocity) { -#ifdef DEBUG - if (channel > MAX_CHANNEL || note > MAX_DATA_BYTE || velocity > MAX_DATA_BYTE) { - while(true); - } -#endif - - MIDI_send(NOTE_OFF_MASK | channel, note, velocity); - -} - -#else - -void note_off(uint8_t channel, uint8_t note) { -#ifdef DEBUG - if (channel > MAX_CHANNEL || note > MAX_DATA_BYTE) { - while(true); - } -#endif - -#ifdef ACTUAL_OFF_MESSAGE - MIDI_send(NOTE_OFF_MASK | channel, note, MIDDLE_VELOCITY); -#else - MIDI_send(NOTE_ON_MASK | channel, note, 0); -#endif - -} - -#endif - -#define MAX_CONTROLLER 119 -void control_change(uint8_t channel, uint8_t controller_number, uint8_t control_value) { -#ifdef DEBUG - if (channel > MAX_CHANNEL || controller_number > MAX_CONTROLLER_NUMBER || control_value > MAX_DATA_BYTE) { - while(true); - } -#endif - - MIDI_send(CONTROL_CHANGE_MASK | channel, controller_number, control_value); - -} - -void program_change(uint8_t channel, uint8_t program_number) { -#ifdef DEBUG - if (channel > MAX_CHANNEL || program_number > MAX_DATA_BYTE) { - while(true); - } -#endif - - MIDI_single_send(PROGRAM_CHANGE_MASK | channel, program_number); - -} - -void aftertouch(uint8_t channel, uint8_t pressure_value) { -#ifdef DEBUG - if (channel > MAX_CHANNEL || pressure_value > MAX_DATA_BYTE) { - while(true); - } -#endif - - MIDI_single_send(AFTERTOUCH_MASK | channel, pressure_value); - -} - -void pitch_bend_change(uint8_t channel, uint16_t pressure_value) { -#ifdef DEBUG - if (channel > MAX_CHANNEL || pressure_value > (MAX_DATA_BYTE << 8) | MAX_DATA_BYTE) { - while(true); - } -#endif - - MIDI_single_send(PITCH_BEND_CHANGE_MASK | channel, pressure_value); - -} - - - -// Channel mode messages. - -#define SOUND_OFF_MODE (MAX_CONTROLLER + 1) -#define RESET_ALL_MODE (MAX_CONTROLLER + 2) -#define LOCAL_CONTROL_MODE (MAX_CONTROLLER + 3) -#define NOTES_OFF_MODE (MAX_CONTROLLER + 4) -#define OMNI_OFF_MODE (MAX_CONTROLLER + 5) -#define OMNI_ON_MODE (MAX_CONTROLLER + 6) -#define MONO_ON_MODE (MAX_CONTROLLER + 7) -#define POLY_ON_MODE (MAX_CONTROLLER + 8) - -void all_sound_off(uint8_t channel) { -#ifdef DEBUG - if (channel > MAX_CHANNEL) { - while(true); - } -#endif - - MIDI_send(CONTROL_CHANGE_MASK | channel, SOUND_OFF_MODE, 0); - -} - -void reset_all_controllers(uint8_t channel) { -#ifdef DEBUG - if (channel > MAX_CHANNEL) { - while(true); - } -#endif - - MIDI_send(CONTROL_CHANGE_MASK | channel, RESET_ALL_MODE, 0); - -} - -void local_control_on(uint8_t channel) { -#ifdef DEBUG - if (channel > MAX_CHANNEL) { - while(true); - } -#endif - - MIDI_send(CONTROL_CHANGE_MASK | channel, LOCAL_CONTROL_MODE, MAX_DATA_BYTE); - -} - -void local_control_off(uint8_t channel) { -#ifdef DEBUG - if (channel > MAX_CHANNEL) { - while(true); - } -#endif - - MIDI_send(CONTROL_CHANGE_MASK | channel, LOCAL_CONTROL_MODE, 0); - -} - -void all_notes_off(uint8_t channel) { -#ifdef DEBUG - if (channel > MAX_CHANNEL) { - while(true); - } -#endif - - MIDI_send(CONTROL_CHANGE_MASK | channel, NOTES_OFF_MODE, 0) - -} - -void omni_on(uint8_t channel) { -#ifdef DEBUG - if (channel > MAX_CHANNEL) { - while(true); - } -#endif - - MIDI_send(CONTROL_CHANGE_MASK | channel, OMNI_ON_MODE, 0); - -} - -void omni_off(uint8_t channel) { -#ifdef DEBUG - if (channel > MAX_CHANNEL) { - while(true); - } -#endif - - MIDI_send(CONTROL_CHANGE_MASK | channel, OMNI_OFF_MODE, 0); - -} - -#define RECEIVER_CHANNEL_COUNT 0 -void mono_on(uint8_t channel, uint8_t channel_count) { -#ifdef DEBUG - if (channel > MAX_CHANNEL || channel_count > MAX_DATA_BYTE) { - while(true); - } -#endif - - MIDI_send(CONTROL_CHANGE_MASK | channel, MONO_ON_MODE, channel_count); - -} - -void poly_on(uint8_t channel) { -#ifdef DEBUG - if (channel > MAX_CHANNEL) { - while(true); - } -#endif - - MIDI_send(CONTROL_CHANGE_MASK | channel, POLY_ON_MODE, 0); - -} - - -// System common messages. -// Not implemented: -// - MTC Quarter Frame -// EOX is automatically sent in the functions that send exclusives. - -#define MTC_QUARTER_FRAME_STATUS 0xf1 -#define SONG_POSITION_POINTER_STATUS 0xf2 -// Undefined. -#define SONG_SELECT_STATUS 0xf3 -#define TUNE_REQUEST_STATUS 0xf6 - -void song_position_pointer(uint16_t position) { -#ifdef DEBUG - if (position & 0x0ff > MAX_DATA_BYTE || position >> 8 > MAX_DATA_BYTE) { - while(true); - } -#endif - - MIDI_send(SONG_POSITION_POINTER_STATUS, position & 0x00ff, position >> 8); - -} - -void song_select(uint8_t song) { -#ifdef DEBUG - if (song > MAX_DATA_BYTE) { - while(true); - } -#endif - - MIDI_single_send(SONG_SELECT_STATUS, song); - -} - -void tune_request() { - MIDI_bare_send(TUNE_REQUEST_STATUS); -} - - - -// System real time messages. -// Not implemented: -// - Timing Clock, -// - Start, -// - Continue, -// - Stop, -// - Active Sensing. - -#define TIMING_CLOCK_STATUS 0xf8 -// Undefined. -#define START_STATUS 0xfa -#define CONTINUE_STATUS 0xfb -#define STOP_STATUS 0xfc -// Undefined. -#define ACTIVE_SENSING_STATUS 0xfe -#define SYSTEM_RESET_STATUS 0xff -void timing_clock() { - MIDI_bare_send(TIMING_CLOCK_STATUS); -} - -void srt_start() { - MIDI_bare_send(START_STATUS); -} - -void srt_continue() { - MIDI_bare_send(CONTINUE_STATUS); -} - -void srt_stop() { - MIDI_bare_send(STOP_STATUS); -} - -void active_sensing() { - MIDI_bare_send(ACTIVE_SENSING_STATUS); -} - -void MIDI_reset() { - MIDI_bare_send(SYSTEM_RESET_STATUS); -} - - -// Universal system exclusive messages. - - -// Only implement MIDI Tuning Standard universals and general information. - - -#define TUNING_STANDARD_SUBID 0x08 -#define BULK_DUMP_REQUEST_SUBID 0x00 -void bulk_tuning_dump_request(uint8_t device_id, uint8_t program) { -#ifdef DEBUG - if (program > MAX_DATA_BYTE || device_id > MAX_DATA_BYTE) { - while(true); - } -#endif - - uint8_t contents[] = {program}; - - universal_nonrealtime(device_id, TUNING_STANDARD_SUBID, BULK_DUMP_REQUEST_SUBID, contents, 1); - -} - - -#define BULK_DUMP_REPLY_SUBID 0x01 -void bulk_tuning_dump(uint8_t device_id, uint8_t program, char* name, uint8_t* tuning_data) { -#ifdef DEBUG - if (device_id > MAX_DATA_BYTE || program > MAX_DATA_BYTE) { - while(true); - } -#endif - - uint8_t *contents = malloc(1 + TUNING_NAME_LENGTH + TUNING_LENGTH + 1); - contents[0] = program; - memcpy(contents + 1, name, TUNING_NAME_LENGTH); - memcpy(contents + 1 + TUNING_NAME_LENGTH, tuning_data, TUNING_LENGTH); - - // I hate this freaking "standard"...what TF do I checksum??? - uint8_t checksum = NON_REAL_TIME_ID ^ device_id ^ TUNING_STANDARD_SUBID ^ BULK_DUMP_REPLY_SUBID ^ program; - for (int i = 0; i < TUNING_LENGTH; i++) { - checksum ^= tuning_data[i]; - } - - contents[1 + TUNING_NAME_LENGTH + DEVICE_KEY_COUNT] = checksum; - - universal_nonrealtime(device_id, TUNING_STANDARD_SUBID, BULK_DUMP_REPLY_SUBID, contents, - 1 + TUNING_NAME_LENGTH + TUNING_LENGTH + 1); - - free(contents); - -} - -#define NOTE_CHANGE_SUBID 0x02 -void single_note_tuning_change(uint8_t device_id, uint8_t program, uint8_t *note_tuning_data, uint8_t keys_changed) { -#ifdef DEBUG - if (device_id > MAX_DATA_BYTE || program > MAX_DATA_BYTE || keys_changed > DEVICE_KEY_COUNT) { - while(true); - } -#endif - - uint8_t *contents = malloc(2 + NOTE_TUNING_BYTES_PER_KEY * keys_changed); - contents[0] = program; - contents[1] = keys_changed; - memcpy(contents + 2, note_tuning_data, NOTE_TUNING_BYTES_PER_KEY * keys_changed); - - universal_realtime(device_id, TUNING_STANDARD_SUBID, NOTE_CHANGE_SUBID, contents, - 2 + NOTE_TUNING_BYTES_PER_KEY * keys_changed); - - free(contents); - -} - -// TODO: tuning banks. - - -// Parsing. -// Stream parsing. -typedef struct { - uint8_t status; - bool first_byte; - uint8_t byte0; - bool send_eox; - uint8_t *stack; - uint8_t top; - size_t size; -} ParserMemory; - -#define WAITING_FOR_STATUS 0x00 -ParserMemory memory = {.status = WAITING_FOR_STATUS, - .first_byte = false, - .byte0 = 0x00, - .send_eox = false, - .stack = malloc(128), - .top = 0, - .size = 128}; - -static inline void push(uint8_t val) { - if (memory->top == memory->size - 1) { - memory->stack = realloc(memory->stack, memory->size + 128); - } - - memory->stack[memory->top + 1] = val; - ++memory->top; -} - -static inline uint8_t pop() { - if (memory->size - memory->top > 128) { - memory->stack = realloc(memory->stack, memory->size - 128); - } - - --memory->top; - return memory->stack[memory->top + 1]; -} - -static inline void reset() { - memory->stack = realloc(memory->stack, 128); - memory->size = 128; - memory->top = 0; - memory->status = WAITING_FOR_STATUS; -} - -static inline void second_byte() { - memory->first_data_byte = false; - memory->byte0 = byte; -} - -#define channel (memory->status & 0x0f) - - -// Memory should be large enough to handle the largest message that's expected to be processed automatically here. -void parse_midi_stream(uint8_t byte) { - switch (byte) { - // Status byte. - case NOTE_OFF_MASK ... (PITCH_BEND_MASK + MAX_CHANNEL): - memory->status = byte; - break; - - case MTC_QUARTER_FRAME_STATUS ... SONG_SELECT_STATUS: - memory->status = byte; - break; - case TUNE_REQUEST_STATUS: - pfns->tune_request_handler(); - memory->status = WAITING_FOR_STATUS; - break; - - case TIMING_CLOCK_STATUS: - pfns->timing_clock_handler(); - break; - case START_STATUS: - pfns->start_handler(); - break; - case CONTINUE_STATUS: - pfns->continue_handler(); - break; - case STOP_STATUS: - pfns->stop_handler(); - break; - case ACTIVE_SENSING_STATUS: - pfns->active_sensing_handler(); - break; - case SYSTEM_RESET_STATUS: - pfns->system_reset_handler(); - break; - case SYSEX_STATUS: - memory->status = byte; - break; - case EOX_STATUS: - if (memory->send_eox) { - pfns->end_of_sysex_handler(); - memory->send_eox = false; - } - reset(); - break; - - // Data byte. - case 0x00 ... MAX_DATA_BYTE: - switch (memory->status) { - case WAITING_FOR_STATUS: - break; - - case NOTE_OFF_MASK ... (NOTE_OFF_MASK + MAX_CHANNEL): - if (memory->first_data_byte) - second_byte(); - else { - pfns->note_off_handler(channel, memory->byte0, byte); - memory->first_data_byte = true; - } - break; - case NOTE_ON_MASK ... (NOTE_ON_MASK + MAX_CHANNEL): - if (memory->first_data_byte) - second_byte(); - else { - pfns->note_on_handler(channel, memory->byte0, byte); - memory->first_data_byte = true; - } - break; - case POLY_KEY_PRESSURE_MASK ... (POLY_KEY_PRESSURE_MASK + MAX_CHANNEL): - if (memory->first_data_byte) - second_byte(); - else { - pfns->poly_key_handler(channel, memory->byte0, byte); - memory->first_data_byte = true; - } - break; - case CONTROL_CHANGE_MASK ... (CONTROL_CHANGE_MASK + MAX_CHANNEL): - if (memory->first_data_byte): - second_byte(); - else { - switch (memory->byte0) { - case 0x00 ... MAX_CONTROLLER: - pfns->control_change_handler(channel); - break; - case SOUND_OFF_MODE: - pfns->all_sound_off_handler(channel); - break; - case RESET_ALL_MODE: - pfns->reset_all_controllers_handler(channel); - break; - case LOCAL_CONTROL_MODE: - pfns->local_control_handler(channel); - break; - case NOTES_OFF_MODE: - pfns->all_notes_off_handler(channel); - break; - case OMNI_OFF_MODE: - pfns->omni_off_handler(channel); - break; - case OMNI_ON_MODE: - pfns->omni_on_handler(channel); - break; - case MONO_ON_MODE: - pfns->mono_on_handler(channel, byte); - break; - case POLY_ON_MODE: - pfns->poly_on_handler(channel); - break; - default: - while(true); // Should be unreachable. - } - memory->first_data_byte = true; - } - break; - case PROGRAM_CHANGE_MASK ... (PROGRAM_CHANGE_MASK + MAX_CHANNEL): - pfns->program_change_handler(channel, byte); - break; - case AFTERTOUCH_MASK ... (AFTERTOUCH_MASK + MAX_CHANNEL): - pfns->aftertouch_handler(channel, byte); - break; - case PITCH_BEND_MASK ... (PITCH_BEND_MASK + MAX_CHANNEL): - pfns->pitch_bend_change_handler(channel, byte); - break; - - - case MTC_QUARTER_FRAME_STATUS: - if (memory->first_data_byte) - second_byte(); - else { - pfns->mtc_quarter_frame_handler(memory->byte0, byte); - memory->first_data_byte = true; - } - break; - case SONG_POSITION_POINTER_STATUS: - if (memory->first_data_byte) - second_byte(); - else { - pfns->song_position_pointer_handler(memory->byte0, byte); - memory->first_data_byte = true; - } - break; - case SONG_SELECT_STATUS: - song_select_handler(byte); - break; - - case SYSEX_STATUS: - if (memory->first_data_byte) { - reset(); // In case last sysex got interrupted by a status. - if (byte <= MAX_NON_UNIVERSAL_ID) - pfns->sysex_collector(byte); - second_byte(); - } else - switch (memory->byte0) { - case UNIVERSAL_NONREALTIME_SUBID: - push(); - if (memory->top > 2) { - uint8_t device_id = memory->stack[0]; - uint8_t subid1 = memory->stack[1]; - uint8_t subid2 = memory->stack[2]; - switch (subid1) { - case TUNING_STANDARD_SUBID: - switch (subid2) { - case BULK_DUMP_REQUEST_SUBID: - pfns->bulk_tuning_dump_request_handler(device_id, byte); - reset(); - break; - case BULK_DUMP_REPLY_SUBID: - if (memory->top == 4 + TUNING_NAME_LENGTH + TUNING_LENGTH - 1) { - uint8_t tuning_program = memory->stack[3]; - uint8_t checksum = NON_REAL_TIME_ID ^ device_id ^ TUNING_STANDARD_SUBID \ - ^ BULK_DUMP_REPLY_SUBID ^ tuning_program; - for (int i = 0; i < TUNING_LENGTH; i++) { - checksum ^= memory->stack[4 + TUNING_NAME_LENGTH - 1 + i]; - } - - if (memory->stack[memory->top] == checksum) { - pfns->bulk_tuning_dump_handler(memory->stack[0], memory->stack[3], memory->stack + 4, - memory->stack + 4 + TUNING_NAME_LENGTH); - } - - reset(); - } - default: - while(true); // Unrecognized tuning standard subid2. - } - break; - default: - if (!pfns->unimplemented_universal_sysex_collector(byte)) { - reset(); - } else { - push(); - } - break; - } - } - break; - - case UNIVERSAL_REALTIME_SUBID: - push(); - if (memory->top > 2) { - uint8_t device_id = memory->stack[0]; - uint8_t subid1 = memory->stack[1]; - uint8_t subid2 = memory->stack[2]; - switch (subid1) { - case TUNING_STANDARD_SUBID: - switch (subid2) { - case NOTE_CHANGE_SUBID: - uint8_t program_number = memory->stack[3]; - uint8_t change_count = memory->stack[4]; - if (memory->top >= 4 && memory->top == 4 + change_count + 1 - 1) { - pfns->single_note_tuning_change_handler(device_id, program_number, change_count, memory->stack + 5); - reset(); - } - break; - default: - while(true); // Unrecognized tuning standard message. - } - break; - default: - break; - } - } - break; - default: - if (!pfns->sysex_collector(byte)) { - reset(); - } else { - push(); - } - break; - } - default: - while(true); // Unhandled status got set, somehow. - } - break; - - default: - while(true); // Unrecognized status byte. - } -} diff --git a/controller/libs/startup.c b/controller/libs/startup.c new file mode 100644 index 0000000..7c7b77a --- /dev/null +++ b/controller/libs/startup.c @@ -0,0 +1,225 @@ +/* +* Copyright (c) 2018, Shawn D'silva +* All rights reserved. +* +* This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . +* +* File: startup.c +* Author: Shawn D'silva . +* Version: 1.0.0. +* Description: startup file for the TM4C Launchpad board,defines the vector table, + and most importantly the Reset_Handler enabling the TM4C to execute the main program when the + button is pressed on board +*/ +#include "startup.h" + +// +-----------------------------------------------------------------------------------+ +// + Vector Table + +// +-----------------------------------------------------------------------------------+ + +__attribute__((section(".vector_table"))) //marks this vector table as a part of the section "".vector_table" +//in the linker script +const vector_table_t vectors[] = { + {.stack_top = &_stack_ptr}, // 0 Pointer to top of Stack + {.isr = Reset_Handler}, // 1 Reset handler is called when the button is pressed + {.isr = NMI_Handler}, // 2 Non-Maskable Interrupt handler + {.isr = HardFault_Handler}, // 3 Hard Fault Handler + {.isr = MemManageFault_Handler}, // 4 Memory management fault Handler + {.isr = BusFault_Handler}, // 5 Bus Fault Handler + {.isr = UsageFault_Handler}, // 6 Usage Fault Handler + {.isr = 0}, // 7 Reserved + {.isr = 0}, // 8 Reserved + {.isr = 0}, // 9 Reserved + {.isr = 0}, // 10 Reserved + {.isr = SVC_Handler}, // 11 SuperVisor Call Handler + {.isr = DebugMonitor_Handler}, // 12 Debug Monitor Handler + {.isr = 0}, // 13 Reserved + {.isr = PendSV_Handler}, // 14 Pendeable interrupt driven request + {.isr = SysTick_Handler}, // 15 SysTick Timer handler + {.isr = GPIOPortA_ISR}, // 16 GPIO Port A Interrupt Service Routine + {.isr = GPIOPortB_ISR}, // 17 GPIO Port B Interrupt Service Routine + {.isr = GPIOPortC_ISR}, // 18 GPIO Port C Interrupt Service Routine + {.isr = GPIOPortD_ISR}, // 19 GPIO Port D Interrupt Service Routine + {.isr = GPIOPortE_ISR}, // 20 GPIO Port C Interrupt Service Routine + {.isr = UART0_ISR}, // 21 UART 0 + {.isr = UART1_ISR}, // 22 UART 1 + {.isr = SPI0_ISR}, // 23 SPI 0 + {.isr = I2C0_ISR}, + {.isr = PWM0Fault_ISR}, + {.isr = PWM0Generator0_ISR}, + {.isr = PWM0Generator1_ISR}, + {.isr = PWM0Generator2_ISR}, + {.isr = QEI0_ISR}, + {.isr = ADC0Sequence0_ISR}, + {.isr = ADC0Sequence1_ISR}, + {.isr = ADC0Sequence2_ISR}, + {.isr = ADC0Sequence3_ISR}, + {.isr = WatchDogTimer_ISR}, + {.isr = Timer0A_ISR}, + {.isr = Timer0B_ISR}, + {.isr = Timer1A_ISR}, + {.isr = Timer1B_ISR}, + {.isr = Timer2A_ISR}, + {.isr = Timer2B_ISR}, + {.isr = AnalogComparator0_ISR}, + {.isr = AnalogComparator1_ISR}, + {.isr = 0}, + {.isr = SystemCtrl_ISR}, + {.isr = FlashCtrl_ISR}, + {.isr = GPIOPortF_ISR}, + {.isr = 0}, + {.isr = 0}, + {.isr = UART2_ISR}, + {.isr = SPI1_ISR}, + {.isr = Timer3A_ISR}, + {.isr = Timer3B_ISR}, + {.isr = I2C1_ISR}, + {.isr = QEI1_ISR}, + {.isr = CAN0_ISR}, + {.isr = CAN1_ISR}, + {.isr = 0}, + {.isr = 0}, + {.isr = Hibernation_ISR}, + {.isr = USB0_ISR}, + {.isr = PWM0Generator3_ISR}, + {.isr = UDMASoftware_ISR}, + {.isr = UDMAError_ISR}, + {.isr = ADC1Sequence0_ISR}, + {.isr = ADC1Sequence1_ISR}, + {.isr = ADC1Sequence2_ISR}, + {.isr = ADC1Sequence3_ISR}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = SPI2_ISR}, + {.isr = SPI3_ISR}, + {.isr = UART3_ISR}, + {.isr = UART4_ISR}, + {.isr = UART5_ISR}, + {.isr = UART6_ISR}, + {.isr = UART7_ISR}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = I2C2_ISR}, + {.isr = I2C3_ISR}, + {.isr = Timer4A_ISR}, + {.isr = Timer4B_ISR}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, // 95 Reserved + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = Timer5A_ISR}, + {.isr = Timer5B_ISR}, + {.isr = WideTimer0A_ISR}, + {.isr = WideTimer0B_ISR}, + {.isr = WideTimer1A_ISR}, + {.isr = WideTimer1B_ISR}, + {.isr = WideTimer2A_ISR}, + {.isr = WideTimer2B_ISR}, + {.isr = WideTimer3A_ISR}, + {.isr = WideTimer3B_ISR}, + {.isr = WideTimer4A_ISR}, + {.isr = WideTimer4B_ISR}, + {.isr = WideTimer5A_ISR}, + {.isr = WideTimer5B_ISR}, + {.isr = SystemException_ISR}, + {.isr = 0}, //123 Reserved + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = 0}, + {.isr = PWM1Generator0_ISR}, + {.isr = PWM1Generator1_ISR}, + {.isr = PWM1Generator2_ISR}, + {.isr = PWM1Generator3_ISR}, + {.isr = PWM1Fault_ISR}, +}; + +// +-----------------------------------------------------------------------------------+ +// + Implementations of Interrupt Service Routines + +// +-----------------------------------------------------------------------------------+ +void Reset_Handler(void) +{ + + int *src, *dest; + + /* copying of the .data values into RAM */ + + src = &_etext; + for (dest = &_data; dest < &_edata;) + { + *dest++ = *src++; + } + + /* initializing .bss values to zero*/ + + for (dest = &_bss; dest < &_ebss;) + { + *dest++ = 0; + } + + /* your program's main() called */ + main(); +} + +void Default_Handler(void) +{ + while (1) + { + //does literally nothing except infinitely loop + } +} + +/*****************************************END OF FILE*********************************************/ diff --git a/controller/src/main.c b/controller/src/main.c index 1650499..fb3f18a 100644 --- a/controller/src/main.c +++ b/controller/src/main.c @@ -1,4 +1,5 @@ #include "midi.h" +#include "uart.h" int main() { -- cgit v1.2.3