From 93a0eb3af60c20d8a5ad5120d780d6d9175b2c2e Mon Sep 17 00:00:00 2001 From: unicod Date: Tue, 18 Oct 2022 20:38:24 +0200 Subject: [PATCH] Air aux mute switch 1,2 works * update LED+mute status from MIDI * toggle mute status via keyboard --- TimedPin.cpp | 34 ++++++++++-------- TimedPin.h | 36 +++++++++---------- XAirMixerControl.ino | 83 +++++++++++++++++++++----------------------- ui.cpp | 44 +++++++++++++++++++---- ui.h | 43 +++++++++++++++++++++++ 5 files changed, 158 insertions(+), 82 deletions(-) diff --git a/TimedPin.cpp b/TimedPin.cpp index f360ba6..5915d85 100644 --- a/TimedPin.cpp +++ b/TimedPin.cpp @@ -1,12 +1,9 @@ #include "TimedPin.h" -/***************************************************************************//** -* @brief Constructor -*******************************************************************************/ TimedPin::TimedPin(uint8_t pin_id, bool inverted) { PinId = pin_id; PinInvert = inverted; - PinMode = TPM_OFF; + TPinMode = TPM_OFF; OnTime = 0; OffTime = 0; } @@ -19,7 +16,7 @@ void TimedPin::begin() { void TimedPin::loop() { uint32_t t = millis(); int32_t tdif = t - RefTime; - switch (PinMode) { + switch (TPinMode) { case TPM_OFF: break; case TPM_ON: @@ -33,6 +30,12 @@ void TimedPin::loop() { } } else { // pin == off if (tdif >= OffTime) { // off time expired + if (CycleCnt) { // cycle count defined: counting down + if (--CycleCnt == 0) { // last cycle reached: + TPinMode = TPM_OFF; // stop blinking + break; + } + } RefTime = t; PinOn(); // toggle pin } @@ -42,55 +45,56 @@ void TimedPin::loop() { case TPM_TIMED_ON: { if (tdif >= OnTime) { // on time expired PinOff(); - PinMode = TPM_OFF; + TPinMode = TPM_OFF; } } break; case TPM_TIMED_OFF: { if (tdif >= OffTime) { // off time expired PinOn(); - PinMode = TPM_ON; + TPinMode = TPM_ON; } } break; default: { - PinMode = TPM_OFF; + TPinMode = TPM_OFF; } break; } } void TimedPin::OffTimed(uint32_t t) { PinOff(); - PinMode = TPM_TIMED_OFF; + TPinMode = TPM_TIMED_OFF; RefTime = millis(); OffTime = t; } void TimedPin::OnTimed(uint32_t t) { PinOn(); - PinMode = TPM_TIMED_ON; + TPinMode = TPM_TIMED_ON; RefTime = millis(); OffTime = t; } -void TimedPin::Blink(uint32_t t_on, uint32_t t_off) { - if (PinMode != TPM_BLINK) { - PinMode = TPM_BLINK; +void TimedPin::Blink(uint32_t t_on, uint32_t t_off, uint16_t cycles) { + if (TPinMode != TPM_BLINK) { + TPinMode = TPM_BLINK; PinOn(); } RefTime = millis(); OnTime = t_on; OffTime = t_off; + CycleCnt = cycles; } void TimedPin::On() { PinOn(); - PinMode = TPM_ON; + TPinMode = TPM_ON; } void TimedPin::Off() { PinOff(); - PinMode = TPM_OFF; + TPinMode = TPM_OFF; } // ============================================================================= diff --git a/TimedPin.h b/TimedPin.h index 64ab78d..2b88da2 100644 --- a/TimedPin.h +++ b/TimedPin.h @@ -4,39 +4,39 @@ #include enum TPinModes { - TPM_OFF, // On - TPM_ON, // Off - TPM_BLINK, // Blink - TPM_ASYM, // asymmetric blink - TPM_TIMED_ON, // timed on, then off - TPM_TIMED_OFF // timed off, then on + TPM_OFF, // permanent on + TPM_ON, // permanent off + TPM_BLINK, // blink + TPM_TIMED_ON, // timed on, then off permanently + TPM_TIMED_OFF // timed off, then on permanently }; class TimedPin { private: - uint8_t PinId; - TPinModes PinMode; - bool PinState; - bool PinInvert; - uint32_t RefTime; - uint32_t OnTime; - uint32_t OffTime; - uint16_t CycleCnt; + uint8_t PinId; /// pin number (assignment on board) + TPinModes TPinMode; /// current working mode + bool PinState; /// current state of pin + bool PinInvert; /// pin configuration (normal:on=HIGH, inverted:on=LOW) + uint32_t RefTime; /// time of start or state change + uint32_t OnTime; /// on time duration + uint32_t OffTime; /// off time duration + uint16_t CycleCnt; /// count of cycles at blink (0=non stop) - void PinOn(); - void PinOff(); + void PinOn(); /// set pin to "on" (internal function) + void PinOff(); /// set pin to "off" (internal function) public: TimedPin(uint8_t pin, bool inverted = false); void begin(); void loop(); - void Blink(uint32_t t_on, uint32_t t_off); + void Blink(uint32_t t_on, uint32_t t_off, uint16_t cycles = 0); void Blink(uint32_t t) { Blink(t, t); } - // void BlinkCycles(uint32_t t_on, uint32_t t_off, uint16_t cycles); + void BlinkCycles(uint32_t t_on, uint32_t t_off, uint16_t cycles) { Blink(t_on, t_off, cycles); }; void Off(); void OffTimed(uint32_t t); void On(); void OnTimed(uint32_t t); + void Set(bool val) { if (val) On(); else Off(); }; }; #endif diff --git a/XAirMixerControl.ino b/XAirMixerControl.ino index 06c1c62..aa46430 100644 --- a/XAirMixerControl.ino +++ b/XAirMixerControl.ino @@ -37,36 +37,30 @@ Tmr Tmr1s = { .Period = 1000 }; /***************************************************************************//** * @brief Button - port assignment *******************************************************************************/ +const uint8_t pinBtnChOn1 = 2; +const uint8_t pinBtnChOn2 = 3; + const uint8_t pinBtnInc1 = 8; const uint8_t pinBtnDec1 = 9; const uint8_t pinBtnInc2 = 10; const uint8_t pinBtnDec2 = 11; -const uint8_t pinBtnChOn1 = 12; -const uint8_t pinBtnChOn2 = 13; - -/***************************************************************************//** -* @brief Button codes -*******************************************************************************/ -enum _BTN_CODES { - BTN_INC1 = 0, - BTN_DEC1, - BTN_INC2, - BTN_DEC2, - BTN_CH_ON1, - BTN_CH_ON2, - - BTN_MAX -}; /***************************************************************************//** * @brief LED *******************************************************************************/ TimedPin LedBoard(LED_BUILTIN); -TimedPin LedChOn1(2); -TimedPin LedChOn2(3); +TimedPin LedChOn1(A0, true); +TimedPin LedChOn2(A1, true); + +bool MidiCfgTxOnly; /// duplex or only tx configuration (without MIDI rx line) +MixerMuteState AirMutes[2] = { + //MixerMuteState(23, &LedBoard), + MixerMuteState(21, &LedChOn1, BTN_CH_ON1, EV_UI_RX_MUTE_CH1_ON, EV_UI_RX_MUTE_CH1_OFF), + MixerMuteState(22, &LedChOn2, BTN_CH_ON2, EV_UI_RX_MUTE_CH2_ON, EV_UI_RX_MUTE_CH2_OFF) +}; /***************************************************************************//** * @brief MIDI instance (serial port) @@ -74,19 +68,21 @@ TimedPin LedChOn2(3); MIDI_CREATE_DEFAULT_INSTANCE(); // ----------------------------------------------------------------------------- - -// This function will be automatically called when a NoteOn is received. -// It must be a void-returning function with the correct parameters, see documentation here: -// https://github.com/FortySevenEffects/arduino_midi_library/wiki/Using-Callbacks -void handleNoteOn(byte channel, byte pitch, byte velocity) { - // Do whatever you want when a note is pressed. - - // Try to keep your callbacks short (no delays ect) otherwise it would slow down the loop() and have a bad impact on real-time performance. +void MidiCCHandler(byte channel, byte ctrl_no, byte val) { + if (channel == 2) { // Mutes: ch=2 + for (uint_fast8_t i=0; i= 64); + mute.MuteLocal = mute.MuteMixer; + mute.Led->Set(!mute.MuteMixer); + UI_EventProc(mute.MuteMixer ? mute.UiEventOff : mute.UiEventOn); + LedBoard.OnTimed(200); + } + } + } } -void handleNoteOff(byte channel, byte pitch, byte velocity) { - // Do something when the note is released. Note that NoteOn messages with 0 velocity are interpreted as NoteOffs. -} // ----------------------------------------------------------------------------- @@ -102,10 +98,9 @@ void setup() { LedChOn1.begin(); LedChOn2.begin(); - // Connect the handleNoteOn function to the library, so it is called upon reception of a NoteOn. - MIDI.setHandleNoteOn(handleNoteOn); // Put only the name of the function - MIDI.setHandleNoteOff(handleNoteOff); // Do the same for NoteOffs + MIDI.setHandleControlChange(MidiCCHandler); MIDI.begin(MIDI_CHANNEL_OMNI); // Initiate MIDI communications, listen to all channels + MIDI.turnThruOff(); UI_Init(); // Start user interface (main state machine) } @@ -119,29 +114,31 @@ void loop() { uint32_t t = millis(); // execute every 10ms ******************************************************* if (Tmr10ms.Check(t)) { - static uint8_t BtnPrev = 0xFF; + static uint8_t BtnPrev = 0x00; static uint8_t BtnNew = 0; static uint8_t BtnRel = 0; - uint8_t btn = (digitalRead(pinBtnInc1) ? (1 << BTN_INC1 ) : 0) - | (digitalRead(pinBtnDec1) ? (1 << BTN_DEC1 ) : 0) - | (digitalRead(pinBtnInc2) ? (1 << BTN_INC2 ) : 0) - | (digitalRead(pinBtnInc2) ? (1 << BTN_DEC2 ) : 0) - | (digitalRead(pinBtnChOn1) ? (1 << BTN_CH_ON1) : 0) - | (digitalRead(pinBtnChOn1) ? (1 << BTN_CH_ON2) : 0); - BtnNew |= (~btn) & BtnPrev; - BtnRel |= btn & (~BtnPrev); + uint8_t btn = (digitalRead(pinBtnInc1) ? 0: (1 << BTN_INC1 )) + | (digitalRead(pinBtnDec1) ? 0: (1 << BTN_DEC1 )) + | (digitalRead(pinBtnInc2) ? 0: (1 << BTN_INC2 )) + | (digitalRead(pinBtnDec2) ? 0: (1 << BTN_DEC2 )) + | (digitalRead(pinBtnChOn1) ? 0: (1 << BTN_CH_ON1)) + | (digitalRead(pinBtnChOn2) ? 0: (1 << BTN_CH_ON2)); + BtnNew |= btn & (~BtnPrev); + BtnRel |= (~btn) & BtnPrev; + BtnPrev = btn; uint8_t mask = 1; if (BtnNew) { - for (uint_fast8_t i = 0; i < BTN_MAX; i++) { + for (uint_fast8_t i = 0; i < 8; i++) { if (BtnNew & mask) { BtnNew &= ~mask; // Bit clr UI_EventProc(EV_UI_KEY_PRESS + i); + LedBoard.OnTimed(50); break; } mask <<= 1; } }else if (BtnRel) { // released button - for (uint_fast8_t i = 0; i < BTN_MAX; i++) { + for (uint_fast8_t i = 0; i < 8; i++) { if (BtnRel & mask) { BtnRel &= ~mask; // Bit clr UI_EventProc(EV_UI_KEY_REL + i); diff --git a/ui.cpp b/ui.cpp index dc88165..8b42ffa 100644 --- a/ui.cpp +++ b/ui.cpp @@ -20,10 +20,14 @@ // Extern variables ============================================================ extern TimedPin LedBoard; +extern TimedPin LedChOn1; +extern TimedPin LedChOn2; extern MIDI_NAMESPACE::SerialMIDI serialMIDI; extern MIDI_NAMESPACE::MidiInterface> MIDI; +extern MixerMuteState AirMutes[2]; + // Typedefs ==================================================================== struct UI_SM { @@ -110,21 +114,27 @@ void UiSt_MixerStartup(UI_SM* const me, uint16_t event) { switch (event) { case EV_STATE_ENTER: { //u MixerStartup: entry: me->Timer = 0; - LedBoard.Blink(50, 450); + LedBoard.Blink(30, 270, 5); + LedChOn1.Blink(500, 500); + LedChOn2.Blink(500, 500); }break; case EV_STATE_EXIT: { }break; - case EV_UI_TICK_100MS: { + case EV_UI_RX_MUTE_CH1_ON: + case EV_UI_RX_MUTE_CH1_OFF: + case EV_UI_RX_MUTE_CH2_ON: + case EV_UI_RX_MUTE_CH2_OFF: { // mixer alive + SM_SET_STATE(&UiSt_Home); }break; case EV_UI_TICK_1S: { if (++me->Timer == 15) { SM_SET_STATE(&UiSt_Home); //u MixerStartup -left-> Home : timeout } - static uint8_t MuteVal = 0; - MIDI.sendControlChange(21, MuteVal, 2); // Send Mute: CH2, 21-26: Aux1-6 - MuteVal = MuteVal ? 0 : 127; + //static uint8_t MuteVal = 0; + //MIDI.sendControlChange(21, MuteVal, 2); // Send Mute: CH2, 21-26: Aux1-6 + //MuteVal = MuteVal ? 0 : 127; }break; } } @@ -136,13 +146,35 @@ void UiSt_MixerStartup(UI_SM* const me, uint16_t event) { * @brief Standby (home) state *******************************************************************************/ void UiSt_Home(UI_SM* const me, uint16_t event) { + uint8_t btn = 0; + if (event >= EV_UI_KEY_PRESS && event <= EV_UI_KEY_PRESS_MAX) { + btn = event - EV_UI_KEY_PRESS; + event = EV_UI_KEY_PRESS; + }else if (event >= EV_UI_KEY_REL && event <= EV_UI_KEY_REL_MAX) { + btn = event - EV_UI_KEY_REL; + event = EV_UI_KEY_REL; + } switch (event) { case EV_STATE_ENTER: { - LedBoard.Blink(1900, 100); + LedBoard.Blink(30, 270, 5); }break; case EV_STATE_EXIT: { }break; + case EV_UI_KEY_PRESS: { + for (uint_fast8_t i=0; iBlink(t_on, t_off); + MIDI.sendControlChange(mute.MidiCtrlNr, mute.MuteLocal ? 0 : 127, 2); + } + } + }break; + case EV_UI_TICK_10MS: { }break; } diff --git a/ui.h b/ui.h index c0a3d75..333efe8 100644 --- a/ui.h +++ b/ui.h @@ -8,17 +8,60 @@ extern "C" { #include "stdint.h" #include "statemachine.h" +#ifndef ELEMCNT +#define ELEMCNT(x) (sizeof(x) / sizeof((x)[0])) +#endif + + +/***************************************************************************//** +* @brief Button codes +*******************************************************************************/ +enum BTN_CODES { + BTN_INC1 = 0, + BTN_DEC1, + BTN_INC2, + BTN_DEC2, + BTN_CH_ON1, + BTN_CH_ON2, + + BTN_MAX +}; + enum UI_EVENTS { EV_UI_TICK_10MS = EV_USER_FIRST, EV_UI_TICK_100MS, EV_UI_TICK_1S, + EV_UI_RX_MUTE_CH1_ON, + EV_UI_RX_MUTE_CH1_OFF, + EV_UI_RX_MUTE_CH2_ON, + EV_UI_RX_MUTE_CH2_OFF, + EV_UI_KEY_PRESS = 0x0100, EV_UI_KEY_PRESS_MAX = 0x01FF, EV_UI_KEY_REL = 0x0200, EV_UI_KEY_REL_MAX = 0x02FF, + + EV_NO_EVENT = 0xFFFF }; +/***************************************************************************//** +* @brief Unit for mute switch from Air mixer +*******************************************************************************/ +struct MixerMuteState { + bool MuteMixer; /// state received from mixer + bool MuteLocal; /// local state (sent to mixer) + uint8_t MidiCtrlNr; /// assign MIDI CC number to MUTE switch of Air mixer + BTN_CODES UiButton; /// assigned button + uint16_t UiEventOn; /// event to send to UI statemachine + uint16_t UiEventOff; /// event to send to UI statemachine + TimedPin* Led; + + MixerMuteState(uint8_t ctrl_nr, TimedPin* led, BTN_CODES button = BTN_MAX, uint16_t uieventon = EV_NO_EVENT, uint16_t uieventoff = EV_NO_EVENT) : + MuteMixer(false), MuteLocal(false), MidiCtrlNr(ctrl_nr), UiButton(button), UiEventOn(uieventon), UiEventOff(uieventoff), Led(led) { } +}; + + extern void UI_Init(); extern void UI_EventProc(uint16_t event);