- Added function to read out the display_buffer via USB-Serial - Added basic structure and files for later complete firmware (still in progress) - Added Doc folder with schematic in it - Added Python script and batch file to read out the display buffer and open the image in gimp
400 lines
14 KiB
C
400 lines
14 KiB
C
/*
|
|
* Core1_Light_Controller.c
|
|
*
|
|
* Created: Sat Jan 21 2023 16:22:51
|
|
* Author Chris
|
|
*/
|
|
// ============================================================================================
|
|
// Includes
|
|
#include "Core1_Light_Controller.h"
|
|
|
|
#include "MIDI_Note_List.h"
|
|
#include "Core1_LED_Control.h"
|
|
#include "Command_Definition.h"
|
|
|
|
|
|
// ============================================================================================
|
|
// Defines
|
|
#define PAUSE_LIGHT_TIMEOUT_TICKS (_EEPROM_Content.Pause_Light_Configuration[ch].Timeout * (1000 / TIMER_INTERVALL_LED_UPDATE_ms))
|
|
|
|
#define NOTE_COLOR_RED _EEPROM_Content.Channel_MIDI_Configuration[ch].Note_Color_Red
|
|
#define NOTE_COLOR_GREEN _EEPROM_Content.Channel_MIDI_Configuration[ch].Note_Color_Green
|
|
#define NOTE_COLOR_BLUE _EEPROM_Content.Channel_MIDI_Configuration[ch].Note_Color_Blue
|
|
|
|
#define NOTE_COLOR_RED_ALT NOTE_COLOR_RED + 1
|
|
#define NOTE_COLOR_GREEN_ALT NOTE_COLOR_GREEN + 1
|
|
#define NOTE_COLOR_BLUE_ALT NOTE_COLOR_BLUE + 1
|
|
|
|
#define NOTE_COLOR_COUNT_RESET_THRESHOLD_TICKS 100 // 100 * 10 ms -> 1s
|
|
|
|
|
|
// ============================================================================================
|
|
// Datatypes
|
|
|
|
|
|
// ============================================================================================
|
|
// Variables
|
|
volatile bool _MIDI_To_Light_Enabled;
|
|
extern volatile EEPROM_Content_t _EEPROM_Content;
|
|
|
|
volatile Info_Last_Received_Note_t _Info_Last_Received_Note[NUM_LED_CHANNELS];
|
|
volatile Info_Last_Received_Note_t _Info_Last_Applied_Note[NUM_LED_CHANNELS];
|
|
volatile Pause_Light_Timer_s _Pause_Light_Timer[NUM_LED_CHANNELS];
|
|
volatile int _NoteOn_Color_Counter[NUM_LED_CHANNELS][NUM_LED_COLORS];
|
|
volatile int _NoteOn_Color_Reset_Counter;
|
|
|
|
static const uint8_t _PWM_Lookup[NUM_LED_COLORS][128] = {
|
|
{ // Red
|
|
0x04, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08,
|
|
0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B,
|
|
0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x10, 0x10, 0x11, 0x11,
|
|
0x12, 0x12, 0x13, 0x14, 0x14, 0x15, 0x15, 0x16, 0x17, 0x18, 0x19, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
|
|
0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x25, 0x26, 0x28, 0x29, 0x2A, 0x2C, 0x2D, 0x2E, 0x30, 0x32,
|
|
0x33, 0x35, 0x37, 0x38, 0x3A, 0x3C, 0x3E, 0x40, 0x42, 0x45, 0x47, 0x49, 0x4B, 0x4E, 0x50, 0x53,
|
|
0x56, 0x58, 0x5B, 0x5E, 0x61, 0x64, 0x68, 0x6B, 0x6E, 0x72, 0x76, 0x79, 0x7E, 0x82, 0x86, 0x8B,
|
|
0x8F, 0x94, 0x99, 0x9E, 0xA6, 0xAC, 0xB2, 0xB9, 0xBF, 0xC6, 0xCD, 0xD5, 0xDD, 0xE5, 0xED, 0xFF
|
|
},
|
|
{ // Green
|
|
0x03, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08,
|
|
0x08, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0D, 0x0E, 0x0E, 0x0F, 0x0F,
|
|
0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 0x15, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
|
|
0x1E, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2A, 0x2C, 0x2D, 0x2F, 0x30, 0x32,
|
|
0x33, 0x35, 0x37, 0x38, 0x3A, 0x3C, 0x3D, 0x3F, 0x41, 0x43, 0x45, 0x47, 0x49, 0x4B, 0x4D, 0x4F,
|
|
0x51, 0x53, 0x55, 0x57, 0x5A, 0x5C, 0x5E, 0x60, 0x63, 0x65, 0x68, 0x6B, 0x6F, 0x72, 0x75, 0x78,
|
|
0x7A, 0x7D, 0x81, 0x84, 0x87, 0x8A, 0x8D, 0x90, 0x94, 0x98, 0x9B, 0x9F, 0xA2, 0xA6, 0xAA, 0xAE,
|
|
0xB3, 0xB6, 0xBA, 0xBF, 0xC3, 0xC8, 0xCC, 0xD1, 0xD6, 0xDB, 0xE0, 0xE5, 0xE9, 0xEE, 0xF1, 0xFF
|
|
},
|
|
{ // Blue
|
|
0x01, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08,
|
|
0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0D, 0x0D,
|
|
0x0E, 0x0E, 0x0F, 0x0F, 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 0x14, 0x15, 0x16, 0x17, 0x18,
|
|
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A,
|
|
0x2B, 0x2D, 0x2E, 0x30, 0x31, 0x33, 0x35, 0x36, 0x38, 0x39, 0x3B, 0x3D, 0x3F, 0x40, 0x42, 0x44,
|
|
0x46, 0x49, 0x4B, 0x4E, 0x50, 0x52, 0x55, 0x57, 0x59, 0x5C, 0x5E, 0x61, 0x63, 0x66, 0x69, 0x6C,
|
|
0x6F, 0x72, 0x75, 0x77, 0x7B, 0x7E, 0x81, 0x85, 0x88, 0x8C, 0x90, 0x93, 0x97, 0x9B, 0x9F, 0xA3,
|
|
0xA8, 0xAC, 0xB0, 0xB5, 0xBA, 0xBE, 0xC4, 0xC9, 0xCE, 0xD4, 0xD9, 0xDF, 0xE4, 0xEA, 0xEF, 0xFF
|
|
}
|
|
};
|
|
|
|
|
|
// ============================================================================================
|
|
// Function Declarations
|
|
bool Core1_Light_Controller_Check_Channel_Match (enum LED_Channel channel, uint8_t midi_channel);
|
|
bool Core1_Light_Controller_Check_Octave_Match (enum LED_Channel channel, uint midi_note);
|
|
void Core1_Light_Controller_Pause_Light_Trigger (uint8_t midi_event, uint8_t midi_channel);
|
|
void Core1_Light_Controller_Reset_NoteOn_Counter();
|
|
|
|
|
|
/*******************************************************************
|
|
Interrupt Service Routines
|
|
*******************************************************************/
|
|
|
|
|
|
/*******************************************************************
|
|
Functions
|
|
*******************************************************************/
|
|
void Core1_Light_Controller_Init(void)
|
|
{
|
|
_MIDI_To_Light_Enabled = true;
|
|
|
|
for(uint ch=0;ch<NUM_LED_CHANNELS;ch++)
|
|
{
|
|
_Info_Last_Received_Note[ch].Event = 0;
|
|
_Info_Last_Received_Note[ch].Note = NO_NOTE;
|
|
_Info_Last_Received_Note[ch].Note_In_Octave = NO_NOTE;
|
|
_Info_Last_Received_Note[ch].Velocity = 0;
|
|
_Info_Last_Received_Note[ch].Timestamp_ms = 0;
|
|
|
|
_Info_Last_Applied_Note[ch].Event = 0;
|
|
_Info_Last_Applied_Note[ch].Note = NO_NOTE;
|
|
_Info_Last_Applied_Note[ch].Note_In_Octave = NO_NOTE;
|
|
_Info_Last_Applied_Note[ch].Velocity = 0;
|
|
_Info_Last_Applied_Note[ch].Timestamp_ms = 0;
|
|
}
|
|
|
|
Core1_Light_Controller_Reset_NoteOn_Counter();
|
|
_NoteOn_Color_Reset_Counter = 0;
|
|
}
|
|
|
|
void Core1_Light_Controller_Tick(void)
|
|
{
|
|
if(_MIDI_To_Light_Enabled != true) {
|
|
return;
|
|
}
|
|
|
|
if(Core1_LED_Control_Get_Timer_Fired() != true) {
|
|
return;
|
|
}
|
|
|
|
for(uint ch=0;ch<NUM_LED_CHANNELS;ch++)
|
|
{
|
|
if(_EEPROM_Content.Pause_Light_Configuration[ch].Enabled == 0) {
|
|
continue;
|
|
}
|
|
|
|
if(_Pause_Light_Timer[ch].Timer == PAUSE_LIGHT_TIMEOUT_TICKS && _Pause_Light_Timer[ch].Is_Active != true)
|
|
{
|
|
_Pause_Light_Timer[ch].Is_Active = true;
|
|
|
|
Core1_LED_Control_Set_Fade_Speed(ch, _EEPROM_Content.Pause_Light_Configuration[ch].Fade_Speed);
|
|
|
|
Core1_LED_Control_Set_DC_Target(ch, R, _EEPROM_Content.Pause_Light_Configuration[ch].Color.R);
|
|
Core1_LED_Control_Set_DC_Target(ch, G, _EEPROM_Content.Pause_Light_Configuration[ch].Color.G);
|
|
Core1_LED_Control_Set_DC_Target(ch, B, _EEPROM_Content.Pause_Light_Configuration[ch].Color.B);
|
|
}
|
|
|
|
if(_Pause_Light_Timer[ch].Timer < PAUSE_LIGHT_TIMEOUT_TICKS) {
|
|
_Pause_Light_Timer[ch].Timer++;
|
|
}
|
|
}
|
|
|
|
if(_NoteOn_Color_Reset_Counter < NOTE_COLOR_COUNT_RESET_THRESHOLD_TICKS) {
|
|
_NoteOn_Color_Reset_Counter++;
|
|
}
|
|
else {
|
|
Core1_Light_Controller_Reset_NoteOn_Counter();
|
|
}
|
|
}
|
|
|
|
void Core1_Light_Controller_MIDI_OnOff_Event_Received(uint8_t midi_command_shifted_right, uint8_t midi_channel)
|
|
{
|
|
if(_MIDI_To_Light_Enabled != true) {
|
|
return;
|
|
}
|
|
|
|
Core1_Light_Controller_Pause_Light_Trigger(midi_command_shifted_right, midi_channel);
|
|
}
|
|
|
|
void Core1_Light_Controller_MIDI_Other_Event_Received(uint8_t midi_data)
|
|
{
|
|
if(_MIDI_To_Light_Enabled != true) {
|
|
return;
|
|
}
|
|
|
|
if(IS_MIDI_COMMAND_WITH_CHANNEL(midi_data)) {
|
|
Core1_Light_Controller_Pause_Light_Trigger(MIDI_EVENT_FROM_COMMAND(midi_data), MIDI_CHANNEL_FROM_COMMAND(midi_data));
|
|
} else {
|
|
Core1_Light_Controller_Pause_Light_Trigger(midi_data, MIDI_CHANNEL_16 + 1);
|
|
}
|
|
}
|
|
|
|
void Core1_Light_Controller_MIDI_Full_Note_Received(uint8_t midi_event, uint8_t midi_channel, uint8_t midi_note, uint8_t value)
|
|
{
|
|
if(_MIDI_To_Light_Enabled != true) {
|
|
return;
|
|
}
|
|
|
|
Core1_Light_Controller_Pause_Light_Trigger(midi_event, midi_channel);
|
|
|
|
for(uint ch=0;ch<NUM_LED_CHANNELS;ch++)
|
|
{
|
|
if(Core1_Light_Controller_Check_Channel_Match(ch, midi_channel) != true) {
|
|
continue;
|
|
}
|
|
|
|
if(Core1_Light_Controller_Check_Octave_Match(ch, midi_note) != true) {
|
|
continue;
|
|
}
|
|
|
|
uint8_t midi_note_in_octave = midi_note % NOTES_PER_OCTAVE;
|
|
|
|
_Info_Last_Received_Note[ch].Event = midi_event;
|
|
_Info_Last_Received_Note[ch].Note = midi_note;
|
|
_Info_Last_Received_Note[ch].Note_In_Octave = midi_note_in_octave;
|
|
_Info_Last_Received_Note[ch].Velocity = value;
|
|
_Info_Last_Received_Note[ch].Timestamp_ms = to_ms_since_boot(get_absolute_time());
|
|
|
|
_NoteOn_Color_Reset_Counter = 0;
|
|
|
|
bool Note_Applied = true;
|
|
|
|
if(midi_event == MIDI_EVENT_NOTE_ON)
|
|
{
|
|
if(midi_note_in_octave == NOTE_COLOR_RED || midi_note_in_octave == NOTE_COLOR_RED_ALT)
|
|
{
|
|
uint8_t DutyCycle = value;
|
|
if(_EEPROM_Content.Device_Configuration.Use_Color_Correction > 0) { DutyCycle = _PWM_Lookup[R][value]; } else { DutyCycle = value << 1; }
|
|
|
|
Core1_LED_Control_Set_DC_Direct(ch, R, DutyCycle);
|
|
_NoteOn_Color_Counter[ch][R]++;
|
|
}
|
|
else if(midi_note_in_octave == NOTE_COLOR_GREEN || midi_note_in_octave == NOTE_COLOR_GREEN_ALT)
|
|
{
|
|
uint8_t DutyCycle = value;
|
|
if(_EEPROM_Content.Device_Configuration.Use_Color_Correction > 0) { DutyCycle = _PWM_Lookup[G][value]; } else { DutyCycle = value << 1; }
|
|
|
|
Core1_LED_Control_Set_DC_Direct(ch, G, DutyCycle);
|
|
_NoteOn_Color_Counter[ch][G]++;
|
|
}
|
|
else if(midi_note_in_octave == NOTE_COLOR_BLUE || midi_note_in_octave == NOTE_COLOR_BLUE_ALT)
|
|
{
|
|
uint8_t DutyCycle = value;
|
|
if(_EEPROM_Content.Device_Configuration.Use_Color_Correction > 0) { DutyCycle = _PWM_Lookup[B][value]; } else { DutyCycle = value << 1; }
|
|
|
|
Core1_LED_Control_Set_DC_Direct(ch, B, DutyCycle);
|
|
_NoteOn_Color_Counter[ch][B]++;
|
|
}
|
|
else
|
|
{
|
|
Note_Applied = false;
|
|
}
|
|
}
|
|
else if((midi_event == MIDI_EVENT_NOTE_OFF && _EEPROM_Content.Channel_MIDI_Configuration[ch].Skip_Note_Off_Event == 0))
|
|
{
|
|
if(midi_note_in_octave == NOTE_COLOR_RED || midi_note_in_octave == NOTE_COLOR_RED_ALT)
|
|
{
|
|
_NoteOn_Color_Counter[ch][R]--;
|
|
if(_NoteOn_Color_Counter[ch][R] == 0) { Core1_LED_Control_Set_DC_Direct(ch, R, 0); }
|
|
}
|
|
else if(midi_note_in_octave == NOTE_COLOR_GREEN || midi_note_in_octave == NOTE_COLOR_GREEN_ALT)
|
|
{
|
|
_NoteOn_Color_Counter[ch][G]--;
|
|
if(_NoteOn_Color_Counter[ch][G] == 0) { Core1_LED_Control_Set_DC_Direct(ch, G, 0); }
|
|
}
|
|
else if(midi_note_in_octave == NOTE_COLOR_BLUE || midi_note_in_octave == NOTE_COLOR_BLUE_ALT)
|
|
{
|
|
_NoteOn_Color_Counter[ch][B]--;
|
|
if(_NoteOn_Color_Counter[ch][B] == 0) { Core1_LED_Control_Set_DC_Direct(ch, B, 0); }
|
|
}
|
|
else
|
|
{
|
|
Note_Applied = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Note_Applied = false;
|
|
}
|
|
|
|
if(Note_Applied == true) {
|
|
_Info_Last_Applied_Note[ch].Event = midi_event;
|
|
_Info_Last_Applied_Note[ch].Note = midi_note;
|
|
_Info_Last_Applied_Note[ch].Note_In_Octave = midi_note_in_octave;
|
|
_Info_Last_Applied_Note[ch].Velocity = value;
|
|
_Info_Last_Applied_Note[ch].Timestamp_ms = to_ms_since_boot(get_absolute_time());
|
|
}
|
|
}
|
|
}
|
|
|
|
void Core1_Light_Controller_Set_MIDI_To_Light_Enabled(bool enabled)
|
|
{
|
|
_MIDI_To_Light_Enabled = enabled;
|
|
|
|
for(uint ch=0;ch<NUM_LED_CHANNELS;ch++) {
|
|
_Pause_Light_Timer[ch].Timer = 0;
|
|
_Pause_Light_Timer[ch].Is_Active = false;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
Internal Functions
|
|
*******************************************************************/
|
|
bool Core1_Light_Controller_Check_Channel_Match(enum LED_Channel channel, uint8_t midi_channel)
|
|
{
|
|
if(channel >= NUM_LED_CHANNELS) {
|
|
return false;
|
|
}
|
|
|
|
return (midi_channel == _EEPROM_Content.Channel_MIDI_Configuration[channel].MIDI_Channel);
|
|
}
|
|
|
|
bool Core1_Light_Controller_Check_Octave_Match(enum LED_Channel channel, uint midi_note)
|
|
{
|
|
if(channel >= NUM_LED_CHANNELS) {
|
|
return false;
|
|
}
|
|
|
|
if(midi_note >= MIDI_NOTE_LIST_LENGTH) {
|
|
return false;
|
|
}
|
|
|
|
return (_MIDI_Note_List[midi_note].Octave == _EEPROM_Content.Channel_MIDI_Configuration[channel].Octave);
|
|
}
|
|
|
|
void Core1_Light_Controller_Pause_Light_Trigger(uint8_t midi_event, uint8_t midi_channel)
|
|
{
|
|
for(uint ch=0;ch<NUM_LED_CHANNELS;ch++)
|
|
{
|
|
bool Match_Success = false;
|
|
|
|
switch(_EEPROM_Content.Pause_Light_Configuration[ch].Reset_Condition)
|
|
{
|
|
case CHANNEL_MATCH:
|
|
if(midi_channel == _EEPROM_Content.Channel_MIDI_Configuration[ch].MIDI_Channel) {
|
|
Match_Success = true;
|
|
}
|
|
break;
|
|
|
|
case EVENT_MATCH:
|
|
if(midi_event == MIDI_EVENT_NOTE_ON || midi_event == MIDI_EVENT_NOTE_OFF) {
|
|
Match_Success = true;
|
|
}
|
|
break;
|
|
|
|
case CHANNEL_AND_EVENT_MATCH:
|
|
if( (midi_channel == _EEPROM_Content.Channel_MIDI_Configuration[ch].MIDI_Channel) &&
|
|
(midi_event == MIDI_EVENT_NOTE_ON || midi_event == MIDI_EVENT_NOTE_OFF))
|
|
{
|
|
Match_Success = true;
|
|
}
|
|
break;
|
|
|
|
case ANY_TRAFFIC:
|
|
default:
|
|
Match_Success = true;
|
|
break;
|
|
}
|
|
|
|
if(Match_Success) {
|
|
if(_Pause_Light_Timer[ch].Is_Active == true)
|
|
{
|
|
_Pause_Light_Timer[ch].Is_Active = false;
|
|
|
|
Core1_LED_Control_Set_DC_Direct(ch, R, 0);
|
|
Core1_LED_Control_Set_DC_Direct(ch, G, 0);
|
|
Core1_LED_Control_Set_DC_Direct(ch, B, 0);
|
|
|
|
Core1_LED_Control_Set_DC_Target(ch, R, 0);
|
|
Core1_LED_Control_Set_DC_Target(ch, G, 0);
|
|
Core1_LED_Control_Set_DC_Target(ch, B, 0);
|
|
}
|
|
|
|
_Pause_Light_Timer[ch].Timer = 0;
|
|
Core1_LED_Control_Set_Fade_Speed(ch, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Core1_Light_Controller_Reset_NoteOn_Counter()
|
|
{
|
|
for(uint ch=0;ch<NUM_LED_CHANNELS;ch++)
|
|
{
|
|
for(uint l=0;l<NUM_LED_COLORS;l++)
|
|
{
|
|
if(_NoteOn_Color_Counter[ch][l] > 0) {
|
|
Core1_LED_Control_Set_DC_Direct(ch, l, 0);
|
|
}
|
|
|
|
_NoteOn_Color_Counter[ch][l] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
Note_t Core1_Light_Controller_Get_Octave_Note_For_Channel(enum LED_Channel channel)
|
|
{
|
|
if(channel >= NUM_LED_CHANNELS) {
|
|
return NO_NOTE;
|
|
}
|
|
|
|
return _Info_Last_Applied_Note[channel].Note_In_Octave;
|
|
}
|
|
|
|
Value_t Core1_Light_Controller_Get_Note_Value_For_Channel(enum LED_Channel channel)
|
|
{
|
|
if(channel >= NUM_LED_CHANNELS) {
|
|
return 0;
|
|
}
|
|
|
|
return _Info_Last_Applied_Note[channel].Velocity;
|
|
} |