arduino-audio-tools
AudioActions.h
1 #pragma once
2 #include "AudioTools/CoreAudio/AudioBasic/Collections/Vector.h"
3 #include "AudioTools/CoreAudio/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 = ActiveHigh;
45  bool lastState = true;
46  bool enabled = true;
47 
49  int debounceDelayValue = DEBOUNCE_DELAY;
50  int touchLimit = TOUCH_LIMIT;
51 
52  virtual int id() {
53  return pin;
54  }
55 
56  virtual bool readValue() {
57 #ifdef USE_TOUCH_READ
58  bool result;
59  if (this->activeLogic == ActiveTouch) {
60  int value = touchRead(this->pin);
61  result = value <= touchLimit;
62  if (result) {
63  // retry to confirm reading
64  value = touchRead(this->pin);
65  result = value <= touchLimit;
66  LOGI("touch pin: %d value %d (limit: %d) -> %s", this->pin, value,
67  touchLimit, result ? "true" : "false");
68  }
69  } else {
70  result = digitalRead(this->pin);
71  }
72  return result;
73 #else
74  return digitalRead(this->pin);
75 #endif
76  }
77 
78  virtual void process() {
79  if (this->enabled) {
80  bool value = readValue();
81  if (this->actionOn != nullptr && this->actionOff != nullptr) {
82  // we have on and off action defined
83  if (value != this->lastState) {
84  //LOGI("processActions: case with on and off");
85  // execute action -> reports active instead of pin state
86  if ((value && this->activeLogic == ActiveHigh) ||
87  (!value && this->activeLogic == ActiveLow)) {
88  this->actionOn(true, this->pin, this->ref);
89  } else {
90  this->actionOff(false, this->pin, this->ref);
91  }
92  this->lastState = value;
93  }
94  } else if (this->activeLogic == ActiveChange) {
95  bool active = value;
96  // reports pin state
97  if (value != this->lastState && millis() > this->debounceTimeout) {
98  //LOGI("processActions: ActiveChange");
99  // execute action
100  this->actionOn(active, this->pin, this->ref);
101  this->lastState = value;
102  this->debounceTimeout = millis() + debounceDelayValue;
103  }
104  } else {
105  bool active = (this->activeLogic == ActiveLow) ? !value : value;
106  if (active &&
107  (active != this->lastState || millis() > this->debounceTimeout)) {
108  // LOGI("processActions: %d Active %d - %d", this->pin, value,
109  // execute action
110  this->actionOn(active, this->pin, this->ref);
111  this->lastState = active;
112  this->debounceTimeout = millis() + debounceDelayValue;
113  }
114  }
115  }
116  }
117  };
118 
120  AudioActions(bool useInterrupt = false) {
121  selfAudioActions = this;
122  setUsePinInterrupt(useInterrupt);
123  }
124 
127  clear();
128  }
129 
131  void add(Action &action){
132  insertAction(action);
133  }
134 
136  void add(int pin, void (*actionOn)(bool pinStatus, int pin, void *ref),
137  ActiveLogic activeLogic = ActiveLow, void *ref = nullptr) {
138  add(pin, actionOn, nullptr, activeLogic, ref);
139  }
140 
142  void add(int pin, void (*actionOn)(bool pinStatus, int pin, void *ref),
143  void (*actionOff)(bool pinStatus, int pin, void *ref),
144  ActiveLogic activeLogicPar = ActiveLow, void *ref = nullptr) {
145  LOGI("ActionLogic::add pin: %d / logic: %d", pin, activeLogicPar);
146  if (pin >= 0) {
147  // setup pin mode
148  setupPin(pin, activeLogicPar);
149 
150  // add value
151  Action& action = *new Action();
152  action.pin = pin;
153  action.actionOn = actionOn;
154  action.actionOff = actionOff;
155  action.activeLogic = activeLogicPar;
156  action.ref = ref;
157  action.debounceDelayValue = debounceDelayValue;
158  action.touchLimit = touchLimit;
159 
160  insertAction(action);
161  } else {
162  LOGW("pin %d -> Ignored", pin);
163  }
164  }
165 
167  void setEnabled(int pin, bool enabled) {
168  Action *p_action = findAction(pin);
169  if (p_action) {
170  p_action->enabled = enabled;
171  }
172  }
173 
178  void processActions() {
179  static int pos = 0;
180  if (actions.empty())
181  return;
182  // execute action
183  actions[pos]->process();
184  pos++;
185  if (pos >= actions.size()) {
186  pos = 0;
187  }
188  }
189 
192  for (Action *action : actions) {
193  action->process();
194  }
195  }
196 
198  Action *findAction(int id) {
199  for (Action *action : actions) {
200  if (action->id() == id) {
201  return action;
202  }
203  }
204  return nullptr;
205  }
206 
208  int findActionIdx(int id) {
209  int pos = 0;
210  for (Action *action : actions) {
211  if (action->id() == id) {
212  return pos;
213  }
214  pos++;
215  }
216  return -1;
217  }
218 
220  void setDebounceDelay(int value) { debounceDelayValue = value; }
222  void setTouchLimit(int value) { touchLimit = value; }
224  void setUsePinInterrupt(bool active) { use_pin_interrupt = active; }
226  void setPinMode(bool active) { use_pin_mode = active; }
227 
228  void clear() {
229  for (Action *act : actions){
230  delete(act);
231  }
232  actions.reset();
233  }
234 
235 protected:
236  int debounceDelayValue = DEBOUNCE_DELAY;
237  int touchLimit = TOUCH_LIMIT;
238  bool use_pin_interrupt = false;
239  bool use_pin_mode = true;
240  Vector<Action*> actions{0};
241 
242  void insertAction(Action& action){
243  int idx = findActionIdx(action.id());
244  if (idx >= 0) {
245  // replace old action
246  delete(actions[idx]);
247  actions[idx] = &action;
248  } else {
249  // add new action
250  actions.push_back(&action);
251  }
252  }
253 
254  static void audioActionsISR() { selfAudioActions->processAllActions(); }
255 
256  void setupPin(int pin, ActiveLogic logic) {
257  // in the audio-driver library the pins are already set up
258  if (use_pin_mode) {
259  if (logic == ActiveLow) {
260  pinMode(pin, INPUT_PULLUP);
261  LOGI("pin %d -> INPUT_PULLUP", pin);
262  } else {
263  pinMode(pin, INPUT);
264  LOGI("pin %d -> INPUT", pin);
265  }
266  }
267 
268 #if !defined(IS_MIN_DESKTOP)
269  if (use_pin_interrupt) {
270  attachInterrupt(digitalPinToInterrupt(pin), audioActionsISR, CHANGE);
271  }
272 #endif
273  }
274 };
275 
276 } // namespace audio_tools
int digitalRead(int pin)
e.g. for AudioActions
Definition: NoArduino.h:206
A simple class to assign functions to gpio pins e.g. to implement a simple navigation control or volu...
Definition: AudioActions.h:29
int findActionIdx(int id)
Determines the action for the pin/id.
Definition: AudioActions.h:208
AudioActions(bool useInterrupt=false)
Default constructor.
Definition: AudioActions.h:120
void add(int pin, void(*actionOn)(bool pinStatus, int pin, void *ref), ActiveLogic activeLogic=ActiveLow, void *ref=nullptr)
Adds an action.
Definition: AudioActions.h:136
void setTouchLimit(int value)
Defines the touch limit (Default 20)
Definition: AudioActions.h:222
~AudioActions()
deletes all actions
Definition: AudioActions.h:126
void setDebounceDelay(int value)
Defines the debounce delay.
Definition: AudioActions.h:220
void processActions()
Execute all actions if the corresponding pin is low To minimize the runtime: With each call we proces...
Definition: AudioActions.h:178
void add(Action &action)
Adds an Action.
Definition: AudioActions.h:131
Action * findAction(int id)
Determines the action for the pin/id.
Definition: AudioActions.h:198
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:142
void processAllActions()
Execute all actions.
Definition: AudioActions.h:191
void setUsePinInterrupt(bool active)
Use interrupts instead of processActions() call in loop.
Definition: AudioActions.h:224
void setEnabled(int pin, bool enabled)
enable/disable pin actions
Definition: AudioActions.h:167
void setPinMode(bool active)
setup pin mode when true
Definition: AudioActions.h:226
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:823
uint32_t millis()
Returns the milliseconds since the start.
Definition: Time.h:12
Definition: AudioActions.h:38
int debounceDelayValue
determines the value for the action
Definition: AudioActions.h:49