Added source

master
unicod 3 years ago
parent 46df35be9e
commit 6073eab934

@ -0,0 +1,108 @@
#include "TimedPin.h"
/***************************************************************************//**
* @brief Constructor
*******************************************************************************/
TimedPin::TimedPin(uint8_t pin_id, bool inverted) {
PinId = pin_id;
PinInvert = inverted;
PinMode = TPM_OFF;
OnTime = 0;
OffTime = 0;
}
void TimedPin::begin() {
pinMode(PinId, OUTPUT);
PinOff();
}
void TimedPin::loop() {
uint32_t t = millis();
int32_t tdif = t - RefTime;
switch (PinMode) {
case TPM_OFF:
break;
case TPM_ON:
break;
case TPM_BLINK: {
if (PinState) { // pin == on
if (tdif >= OnTime) { // on time expired
RefTime = t;
PinOff(); // toggle pin
}
} else { // pin == off
if (tdif >= OffTime) { // off time expired
RefTime = t;
PinOn(); // toggle pin
}
}
} break;
case TPM_TIMED_ON: {
if (tdif >= OnTime) { // on time expired
PinOff();
PinMode = TPM_OFF;
}
} break;
case TPM_TIMED_OFF: {
if (tdif >= OffTime) { // off time expired
PinOn();
PinMode = TPM_ON;
}
} break;
default: {
PinMode = TPM_OFF;
} break;
}
}
void TimedPin::OffTimed(uint32_t t) {
PinOff();
PinMode = TPM_TIMED_OFF;
RefTime = millis();
OffTime = t;
}
void TimedPin::OnTimed(uint32_t t) {
PinOn();
PinMode = 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;
PinOn();
}
RefTime = millis();
OnTime = t_on;
OffTime = t_off;
}
void TimedPin::On() {
PinOn();
PinMode = TPM_ON;
}
void TimedPin::Off() {
PinOff();
PinMode = TPM_OFF;
}
// =============================================================================
// Internal functions
// =============================================================================
void TimedPin::PinOn() {
PinState = true;
digitalWrite(PinId, PinInvert ? LOW : HIGH);
}
void TimedPin::PinOff() {
PinState = false;
digitalWrite(PinId, PinInvert ? HIGH : LOW);
}

@ -0,0 +1,42 @@
#ifndef __TIMED_PIN__H__
#define __TIMED_PIN__H__
#include <Arduino.h>
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
};
class TimedPin {
private:
uint8_t PinId;
TPinModes PinMode;
bool PinState;
bool PinInvert;
uint32_t RefTime;
uint32_t OnTime;
uint32_t OffTime;
uint16_t CycleCnt;
void PinOn();
void PinOff();
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) { Blink(t, t); }
// void BlinkCycles(uint32_t t_on, uint32_t t_off, uint16_t cycles);
void Off();
void OffTimed(uint32_t t);
void On();
void OnTimed(uint32_t t);
};
#endif

@ -0,0 +1,169 @@
#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 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);
/***************************************************************************//**
* @brief MIDI instance (serial port)
*******************************************************************************/
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 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.
}
// -----------------------------------------------------------------------------
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();
// 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.begin(MIDI_CHANNEL_OMNI); // Initiate MIDI communications, listen to all channels
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 = 0xFF;
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 mask = 1;
if (BtnNew) {
for (uint_fast8_t i = 0; i < BTN_MAX; i++) {
if (BtnNew & mask) {
BtnNew &= ~mask; // Bit clr
UI_EventProc(EV_UI_KEY_PRESS + i);
break;
}
mask <<= 1;
}
}else if (BtnRel) { // released button
for (uint_fast8_t i = 0; i < BTN_MAX; 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);
}
}

@ -0,0 +1,45 @@
/***************************************************************************//**
* @file statemachine.cpp
*
* Simple finite state machine
*
*******************************************************************************/
#include <stdint.h>
#include <string.h>
#include "statemachine.h"
void StateMachine(STATE_MACHINE* const me, uint16_t ev) {
me->State(me, ev); // call actual state
if (me->StateNew != NULL) { // new state request
me->StateReturn = me->State; // remeber last state
me->State(me, EV_STATE_EXIT); // closing last state
me->State = me->StateNew; // switching state
me->StateNew = NULL;
me->State(me, EV_STATE_ENTER); // init new state
}
}
void SM_ST_StateDelayed(STATE_MACHINE* const me, uint16_t event) {
switch (event) {
case EV_TIMER_TICK: {
if (me->Timer_StateDelay) {
me->Timer_StateDelay--;
}else {
SM_SET_STATE(me->StateDelayed);
}
}break;
default: break;
}
}
void StateMachineInit(STATE_MACHINE* const me, SM_STATE_FUNC* const init_state) {
me->State = init_state;
me->StateNew = NULL;
me->StateDelayed = init_state;
me->StateReturn = init_state;
me->State(me, EV_STATE_ENTER); // enter into initial state (initial transition)
}

@ -0,0 +1,55 @@
#ifndef __STATEMACHINE_H__
#define __STATEMACHINE_H__
#ifdef __cplusplus
extern "C" {
#endif
#if 0
} // workaround for CB folding bug
#endif
#include <stdint.h>
enum SM_EVENTS {
EV_STATE_ENTER,
EV_STATE_EXIT,
EV_TIMER_TICK,
EV_USER_FIRST
};
#define SM_SET_STATE(st) do { \
((STATE_MACHINE*)me)->StateNew = (SM_STATE_FUNC*)(st); \
} while (0)
#define SM_SET_STATE_DELAYED(st, delay) do { \
((STATE_MACHINE*)me)->StateDelayed = (SM_STATE_FUNC*)(st); \
((STATE_MACHINE*)me)->Timer_StateDelay = delay; \
((STATE_MACHINE*)me)->StateNew = &SM_ST_StateDelayed; \
} while (0)
struct _STATE_MACHINE;
typedef struct _STATE_MACHINE STATE_MACHINE;
typedef void SM_STATE_FUNC(STATE_MACHINE* me, uint16_t event);
struct _STATE_MACHINE {
SM_STATE_FUNC* State; // actual state
SM_STATE_FUNC* StateNew; // new state
SM_STATE_FUNC* StateDelayed; // auto state switch after delay
SM_STATE_FUNC* StateReturn; // return state for nested states
uint16_t Timer_StateDelay;
};
extern void StateMachineInit(STATE_MACHINE* const me, SM_STATE_FUNC* const init_state);
extern void StateMachine(STATE_MACHINE* const me, uint16_t ev);
extern void SM_ST_StateDelayed(STATE_MACHINE* const me, uint16_t event);
#if 0
{ // workaround for CB folding bug
#endif
#ifdef __cplusplus
}
#endif
#endif // __STATEMACHINE_H__

157
ui.cpp

@ -0,0 +1,157 @@
/***************************************************************************//**
* @file ui.cpp
*******************************************************************************/
#include <Arduino.h>
#include <stdio.h>
#include <string.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
//#include "gitinfo.h"
#include "MIDI.h"
#include "TimedPin.h"
#include "ui.h"
#define ELEMCNT(x) (sizeof(x) / sizeof((x)[0]))
// Extern variables ============================================================
extern TimedPin LedBoard;
extern MIDI_NAMESPACE::SerialMIDI<HardwareSerial> serialMIDI;
extern MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<HardwareSerial>> MIDI;
// Typedefs ====================================================================
struct UI_SM {
STATE_MACHINE sm;
uint32_t Events;
uint16_t Timer;
uint16_t KeyTimer;
};
typedef void UI_STATE_FUNC(UI_SM* me, uint16_t event);
// Local variables =============================================================
static UI_SM UiSm;
#define DEFINE_MY_OBJECT() UI_SM* const me = &UiSm;
const uint16_t ToutProg = 30; // [s]
// Local function declarations =================================================
static void UiSt_MixerStartup(UI_SM* me, uint16_t event);
static void UiSt_Home(UI_SM* me, uint16_t event);
// Function definitions ========================================================
//u @startuml
//u skinparam defaultTextAlignment left
//u state UserInterface {
/***************************************************************************//**
* @brief Initialize state machine for user interface
*******************************************************************************/
void UI_Init() {
DEFINE_MY_OBJECT();
me->Events = 0;
StateMachineInit(&me->sm, (SM_STATE_FUNC*)&UiSt_MixerStartup); //u [*] -> MixerStartup
}
/***************************************************************************//**
* @brief Execute event handler
*******************************************************************************/
void UI_EventProc(uint16_t event) {
DEFINE_MY_OBJECT();
StateMachine((STATE_MACHINE*)me, event);
}
/***************************************************************************//**
* @brief Check and execute asynchron event (from event buffer)
*******************************************************************************/
void UI_CheckEvent() {
DEFINE_MY_OBJECT();
if (me->Events) {
uint32_t mask = 1;
uint8_t ev;
for (ev = 0; ev < 32; ev++) {
if (me->Events & mask) {
me->Events &= ~mask;
StateMachine((STATE_MACHINE*)me, ev);
break;
}
mask <<= 1; // shift left
}
}
}
/***************************************************************************//**
* @brief Send (asynchron) event to state machine to process it later
*******************************************************************************/
static inline void EventSend(UI_SM* const me, uint16_t event) {
me->Events |= (1 << event);
}
// State definitions ===========================================================
//u state MixerStartup {
/***************************************************************************//**
* @brief MixerStartup
*******************************************************************************/
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);
}break;
case EV_STATE_EXIT: {
}break;
case EV_UI_TICK_100MS: {
}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;
}break;
}
}
//u }
//u state Home {
/***************************************************************************//**
* @brief Standby (home) state
*******************************************************************************/
void UiSt_Home(UI_SM* const me, uint16_t event) {
switch (event) {
case EV_STATE_ENTER: {
LedBoard.Blink(1900, 100);
}break;
case EV_STATE_EXIT: {
}break;
case EV_UI_TICK_10MS: {
}break;
}
}
//u }
//u }
//u @enduml

33
ui.h

@ -0,0 +1,33 @@
#ifndef __UI_H__
#define __UI_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"
#include "statemachine.h"
enum UI_EVENTS {
EV_UI_TICK_10MS = EV_USER_FIRST,
EV_UI_TICK_100MS,
EV_UI_TICK_1S,
EV_UI_KEY_PRESS = 0x0100,
EV_UI_KEY_PRESS_MAX = 0x01FF,
EV_UI_KEY_REL = 0x0200,
EV_UI_KEY_REL_MAX = 0x02FF,
};
extern void UI_Init();
extern void UI_EventProc(uint16_t event);
extern void UI_EventSend(uint16_t event);
extern void UI_CheckEvent();
#ifdef __cplusplus
}
#endif
#endif
Loading…
Cancel
Save