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