arduino-audio-tools
AudioActions.h
1 #pragma once
2 #include "AudioBasic/Collections/Vector.h"
3 #include "AudioTools/AudioLogger.h"
4 
5 #ifndef TOUCH_LIMIT
6 #define TOUCH_LIMIT 20
7 #endif
8 
9 #ifndef DEBOUNCE_DELAY
10 #define DEBOUNCE_DELAY 500
11 #endif
12 
13 #if defined(IS_MIN_DESKTOP)
14 extern "C" void pinMode(int, int);
15 extern "C" int digitalRead(int);
16 #endif
17 
18 namespace audio_tools {
19 
20 // global reference to access from static callback methods
21 class AudioActions;
22 static AudioActions *selfAudioActions = nullptr;
23 
29 class AudioActions {
30 public:
31  enum ActiveLogic : uint8_t {
32  ActiveLow,
33  ActiveHigh,
34  ActiveChange,
35  ActiveTouch
36  };
37 
38  struct Action {
39  int16_t pin = -1;
40  void (*actionOn)(bool pinStatus, int pin, void *ref) = nullptr;
41  void (*actionOff)(bool pinStatus, int pin, void *ref) = nullptr;
42  void *ref = nullptr;
43  unsigned long debounceTimeout = 0;
44  ActiveLogic activeLogic;
45  bool lastState = true;
46  bool enabled = true;
47 
49  int debounceDelayValue = DEBOUNCE_DELAY;
50  int touchLimit = TOUCH_LIMIT;
51 
52  bool readValue() {
53 #ifdef USE_TOUCH_READ
54  bool result;
55  if (this->activeLogic == ActiveTouch) {
56  int value = touchRead(this->pin);
57  result = value <= touchLimit;
58  if (result) {
59  // retry to confirm reading
60  value = touchRead(this->pin);
61  result = value <= touchLimit;
62  LOGI("touch pin: %d value %d (limit: %d) -> %s", this->pin, value,
63  touchLimit, result ? "true" : "false");
64  }
65  } else {
66  result = digitalRead(this->pin);
67  }
68  return result;
69 #else
70  return digitalRead(this->pin);
71 #endif
72  }
73 
74  void process() {
75  if (this->enabled) {
76  bool value = readValue();
77  if (this->actionOn != nullptr && this->actionOff != nullptr) {
78  // we have on and off action defined
79  if (value != this->lastState) {
80  //LOGI("processActions: case with on and off");
81  // execute action -> reports active instead of pin state
82  if ((value && this->activeLogic == ActiveHigh) ||
83  (!value && this->activeLogic == ActiveLow)) {
84  this->actionOn(true, this->pin, this->ref);
85  } else {
86  this->actionOff(false, this->pin, this->ref);
87  }
88  this->lastState = value;
89  }
90  } else if (this->activeLogic == ActiveChange) {
91  bool active = value;
92  // reports pin state
93  if (value != this->lastState && millis() > this->debounceTimeout) {
94  //LOGI("processActions: ActiveChange");
95  // execute action
96  this->actionOn(active, this->pin, this->ref);
97  this->lastState = value;
98  this->debounceTimeout = millis() + debounceDelayValue;
99  }
100  } else {
101  bool active = (this->activeLogic == ActiveLow) ? !value : value;
102  if (active &&
103  (active != this->lastState || millis() > this->debounceTimeout)) {
104  // LOGI("processActions: %d Active %d - %d", this->pin, value,
105  // execute action
106  this->actionOn(active, this->pin, this->ref);
107  this->lastState = active;
108  this->debounceTimeout = millis() + debounceDelayValue;
109  }
110  }
111  }
112  }
113  };
114 
116  AudioActions(bool useInterrupt = false) {
117  selfAudioActions = this;
118  setUsePinInterrupt(useInterrupt);
119  }
120 
122  void add(int pin, void (*actionOn)(bool pinStatus, int pin, void *ref),
123  ActiveLogic activeLogic = ActiveLow, void *ref = nullptr) {
124  add(pin, actionOn, nullptr, activeLogic, ref);
125  }
126 
128  void add(int pin, void (*actionOn)(bool pinStatus, int pin, void *ref),
129  void (*actionOff)(bool pinStatus, int pin, void *ref),
130  ActiveLogic activeLogicPar = ActiveLow, void *ref = nullptr) {
131  LOGI("ActionLogic::add pin: %d / logic: %d", pin, activeLogicPar);
132  if (pin >= 0) {
133  // setup pin mode
134  setupPin(pin, activeLogicPar);
135 
136  Action *p_action = findAction(pin);
137  if (p_action) {
138  // replace value
139  p_action->actionOn = actionOn;
140  p_action->actionOff = actionOff;
141  p_action->activeLogic = activeLogicPar;
142  p_action->ref = ref;
143  } else {
144  // add value
145  Action action;
146  action.pin = pin;
147  action.actionOn = actionOn;
148  action.actionOff = actionOff;
149  action.activeLogic = activeLogicPar;
150  action.ref = ref;
151 
152  action.debounceDelayValue = debounceDelayValue;
153  action.touchLimit = touchLimit;
154 
155  actions.push_back(action);
156  }
157  } else {
158  LOGW("pin %d -> Ignored", pin);
159  }
160  }
161 
163  void setEnabled(int pin, bool enabled) {
164  Action *p_action = findAction(pin);
165  if (p_action) {
166  p_action->enabled = enabled;
167  }
168  }
169 
174  void processActions() {
175  static int pos = 0;
176  if (actions.empty())
177  return;
178  // execute action
179  actions[pos].process();
180  pos++;
181  if (pos >= actions.size()) {
182  pos = 0;
183  }
184  }
185 
188  for (Action &action : actions) {
189  action.process();
190  }
191  }
192 
194  Action *findAction(int pin) {
195  for (Action &action : actions) {
196  if (action.pin == pin) {
197  return &action;
198  }
199  }
200  return nullptr;
201  }
202 
204  void setDebounceDelay(int value) { debounceDelayValue = value; }
206  void setTouchLimit(int value) { touchLimit = value; }
208  void setUsePinInterrupt(bool active) { use_pin_interrupt = active; }
210  void setPinMode(bool active) { use_pin_mode = active; }
211 
212 protected:
213  int debounceDelayValue = DEBOUNCE_DELAY;
214  int touchLimit = TOUCH_LIMIT;
215  bool use_pin_interrupt = false;
216  bool use_pin_mode = true;
217 
218  Vector<Action> actions{0};
219 
220  static void audioActionsISR() { selfAudioActions->processAllActions(); }
221 
222  void setupPin(int pin, ActiveLogic logic) {
223  // in the audio-driver library the pins are already set up
224  if (use_pin_mode) {
225  if (logic == ActiveLow) {
226  pinMode(pin, INPUT_PULLUP);
227  LOGI("pin %d -> INPUT_PULLUP", pin);
228  } else {
229  pinMode(pin, INPUT);
230  LOGI("pin %d -> INPUT", pin);
231  }
232  }
233 
234 #if !defined(IS_MIN_DESKTOP)
235  if (use_pin_interrupt) {
236  attachInterrupt(digitalPinToInterrupt(pin), audioActionsISR, CHANGE);
237  }
238 #endif
239  }
240 };
241 
242 } // namespace audio_tools
int digitalRead(int pin)
e.g. for AudioActions
Definition: NoArduino.h:205
A simple class to assign functions to gpio pins e.g. to implement a simple navigation control or volu...
Definition: AudioActions.h:29
AudioActions(bool useInterrupt=false)
Default constructor.
Definition: AudioActions.h:116
void add(int pin, void(*actionOn)(bool pinStatus, int pin, void *ref), ActiveLogic activeLogic=ActiveLow, void *ref=nullptr)
Adds an action.
Definition: AudioActions.h:122
void setTouchLimit(int value)
Defines the touch limit (Default 20)
Definition: AudioActions.h:206
void setDebounceDelay(int value)
Defines the debounce delay.
Definition: AudioActions.h:204
void processActions()
Execute all actions if the corresponding pin is low To minimize the runtime: With each call we proces...
Definition: AudioActions.h:174
void add(int pin, void(*actionOn)(bool pinStatus, int pin, void *ref), void(*actionOff)(bool pinStatus, int pin, void *ref), ActiveLogic activeLogicPar=ActiveLow, void *ref=nullptr)
Adds an action.
Definition: AudioActions.h:128
void processAllActions()
Execute all actions.
Definition: AudioActions.h:187
void setUsePinInterrupt(bool active)
Use interrupts instead of processActions() call in loop.
Definition: AudioActions.h:208
void setEnabled(int pin, bool enabled)
enable/disable pin actions
Definition: AudioActions.h:163
Action * findAction(int pin)
Determines the action for the pin.
Definition: AudioActions.h:194
void setPinMode(bool active)
setup pin mode when true
Definition: AudioActions.h:210
Vector implementation which provides the most important methods as defined by std::vector....
Definition: Vector.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AnalogAudio.h:10
uint32_t millis()
Returns the milliseconds since the start.
Definition: Millis.h:18
Definition: AudioActions.h:38
int debounceDelayValue
determines the value for the action
Definition: AudioActions.h:49