You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
5.6 KiB
C++

#include <MIDI.h>
#include "TimedPin.h"
#include "ui.h"
/***************************************************************************//**
* @brief Timer class for generate cyclic signals
*******************************************************************************/
struct Tmr {
int32_t Period; // cycle length (it must be initialized!)
uint32_t TrefMillis;
//---------------------------------------------------------------------------
bool Check(uint32_t t) { // check with external timebase
int32_t tdif = t - TrefMillis;
if (tdif >= Period) { // period expired
TrefMillis += Period;
return true;
}
return false;
};
bool Check() { // check with millisec timebase
uint32_t t = millis();
int32_t tdif = t - TrefMillis;
if (tdif >= Period) { // period expired
TrefMillis += Period;
return true;
}
return false;
};
};
Tmr Tmr10ms = { .Period = 10 };
Tmr Tmr100ms = { .Period = 100 };
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;
/***************************************************************************//**
* @brief LED
*******************************************************************************/
TimedPin LedBoard(LED_BUILTIN);
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)
*******************************************************************************/
MIDI_CREATE_DEFAULT_INSTANCE();
// -----------------------------------------------------------------------------
void MidiCCHandler(byte channel, byte ctrl_no, byte val) {
if (channel == 2) { // Mutes: ch=2
for (uint_fast8_t i=0; i<ELEMCNT(AirMutes); i++) {
MixerMuteState& mute = AirMutes[i];
if (ctrl_no == mute.MidiCtrlNr) {
mute.MuteMixer = (val >= 64);
mute.MuteLocal = mute.MuteMixer;
mute.Led->Set(!mute.MuteMixer);
UI_EventProc(mute.MuteMixer ? mute.UiEventOff : mute.UiEventOn);
LedBoard.OnTimed(200);
}
}
}
}
// -----------------------------------------------------------------------------
void setup() {
pinMode(pinBtnInc1, INPUT_PULLUP);
pinMode(pinBtnDec1, INPUT_PULLUP);
pinMode(pinBtnInc2, INPUT_PULLUP);
pinMode(pinBtnDec2, INPUT_PULLUP);
pinMode(pinBtnChOn1, INPUT_PULLUP);
pinMode(pinBtnChOn2, INPUT_PULLUP);
LedBoard.begin();
LedChOn1.begin();
LedChOn2.begin();
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)
}
/***************************************************************************//**
* @brief Main loop
*******************************************************************************/
void loop() {
MIDI.read(); // Call MIDI.read the fastest you can for real-time performance.
uint32_t t = millis();
// execute every 10ms *******************************************************
if (Tmr10ms.Check(t)) {
static uint8_t BtnPrev = 0x00;
static uint8_t BtnNew = 0;
static uint8_t BtnRel = 0;
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 < 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 < 8; i++) {
if (BtnRel & mask) {
BtnRel &= ~mask; // Bit clr
UI_EventProc(EV_UI_KEY_REL + i);
break;
}
mask <<= 1;
}
}
UI_EventProc(EV_TIMER_TICK);
UI_EventProc(EV_UI_TICK_10MS);
UI_CheckEvent();
LedBoard.loop();
LedChOn1.loop();
LedChOn2.loop();
}
// execute every 100ms ******************************************************
if (Tmr100ms.Check(t)) {
UI_EventProc(EV_UI_TICK_100MS);
}
// execute every 1s *********************************************************
if (Tmr1s.Check(t)) {
UI_EventProc(EV_UI_TICK_1S);
}
}