muwerk mupplet Core Library
muwerk applets; mupplets: functional units that support specific hardware or reusable applications
Loading...
Searching...
No Matches
mup_frequency_counter.h
1// mup_frequency_counter.h
2#pragma once
3
4#include "scheduler.h"
5
6namespace ustd {
7
8#if defined(__ESP32__) || defined(__ESP__)
9#define G_INT_ATTR IRAM_ATTR
10#else
11#define G_INT_ATTR
12#endif
13
14#define USTD_MAX_FQ_PIRQS (10)
15
16volatile unsigned long pFqIrqCounter[USTD_MAX_FQ_PIRQS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
17volatile unsigned long pFqLastIrqTimer[USTD_MAX_FQ_PIRQS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
18volatile unsigned long pFqBeginIrqTimer[USTD_MAX_FQ_PIRQS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
19
20void G_INT_ATTR ustd_fq_pirq_master(uint8_t irqno) {
21 unsigned long curr = micros();
22 if (pFqBeginIrqTimer[irqno] == 0)
23 pFqBeginIrqTimer[irqno] = curr;
24 else
25 ++pFqIrqCounter[irqno];
26 pFqLastIrqTimer[irqno] = curr;
27}
28
29void G_INT_ATTR ustd_fq_pirq0() {
30 ustd_fq_pirq_master(0);
31}
32void G_INT_ATTR ustd_fq_pirq1() {
33 ustd_fq_pirq_master(1);
34}
35void G_INT_ATTR ustd_fq_pirq2() {
36 ustd_fq_pirq_master(2);
37}
38void G_INT_ATTR ustd_fq_pirq3() {
39 ustd_fq_pirq_master(3);
40}
41void G_INT_ATTR ustd_fq_pirq4() {
42 ustd_fq_pirq_master(4);
43}
44void G_INT_ATTR ustd_fq_pirq5() {
45 ustd_fq_pirq_master(5);
46}
47void G_INT_ATTR ustd_fq_pirq6() {
48 ustd_fq_pirq_master(6);
49}
50void G_INT_ATTR ustd_fq_pirq7() {
51 ustd_fq_pirq_master(7);
52}
53void G_INT_ATTR ustd_fq_pirq8() {
54 ustd_fq_pirq_master(8);
55}
56void G_INT_ATTR ustd_fq_pirq9() {
57 ustd_fq_pirq_master(9);
58}
59
60void (*ustd_fq_pirq_table[USTD_MAX_FQ_PIRQS])() = {ustd_fq_pirq0, ustd_fq_pirq1, ustd_fq_pirq2, ustd_fq_pirq3,
61 ustd_fq_pirq4, ustd_fq_pirq5, ustd_fq_pirq6, ustd_fq_pirq7,
62 ustd_fq_pirq8, ustd_fq_pirq9};
63
64unsigned long getFqResetpIrqCount(uint8_t irqno) {
65 unsigned long count = (unsigned long)-1;
66 noInterrupts();
67 if (irqno < USTD_MAX_FQ_PIRQS) {
68 count = pFqIrqCounter[irqno];
69 pFqIrqCounter[irqno] = 0;
70 }
71 interrupts();
72 return count;
73}
74
75double fQfrequencyMultiplicator = 1000000.0;
76double getFqResetpIrqFrequency(uint8_t irqno, unsigned long minDtUs = 50) {
77 double frequency = 0.0;
78 noInterrupts();
79 if (irqno < USTD_MAX_FQ_PIRQS) {
80 unsigned long count = pFqIrqCounter[irqno];
81 unsigned long dt = timeDiff(pFqBeginIrqTimer[irqno], pFqLastIrqTimer[irqno]);
82 if (dt > minDtUs) { // Ignore small Irq flukes
83 frequency = (count * fQfrequencyMultiplicator) / dt; // = count/2.0*fQfrequenceMultiplicator uS / dt;
84 // no. of waves (count/2) / dt.
85 }
86 pFqBeginIrqTimer[irqno] = 0;
87 pFqIrqCounter[irqno] = 0;
88 pFqLastIrqTimer[irqno] = 0;
89 }
90 interrupts();
91 return frequency;
92}
93
94// clang-format off
132 public:
136 IM_CHANGE
137 };
138
148 };
149 String FREQUENCY_COUNTER_VERSION = "0.1.0";
150 private:
151 Scheduler *pSched;
152 int tID;
153
154 String name;
155 uint8_t pin_input;
156 uint8_t irqno_input;
157 int8_t interruptIndex_input;
158 MeasureMode measureMode;
159 InterruptMode irqMode;
160 uint8_t ipin = 255;
161
162 bool detectZeroChange = false;
163 bool irqsAttached = false;
164 double inputFrequencyVal = 0.0;
165
166 public:
167 ustd::sensorprocessor frequency = ustd::sensorprocessor(4, 600, 0.01);
168 double frequencyRenormalisation = 1.0;
169
170 FrequencyCounter(String name, uint8_t pin_input, int8_t interruptIndex_input,
171 MeasureMode measureMode = HIGHFREQUENCY_MEDIUM,
173 : name(name), pin_input(pin_input), interruptIndex_input(interruptIndex_input),
174 measureMode(measureMode), irqMode(irqMode) {
183 setMeasureMode(measureMode, true);
184 }
185
187 if (irqsAttached) {
188 detachInterrupt(irqno_input);
189 }
190 }
191
192 void setMeasureMode(MeasureMode mode, bool silent = false) {
198 switch (mode) {
200 detectZeroChange = false;
201 measureMode = LOWFREQUENCY_FAST;
202 frequency.update(4,15,0.01); // requires muwerk 0.6.3 or higher!
203 break;
205 detectZeroChange = false;
206 measureMode = LOWFREQUENCY_MEDIUM;
207 frequency.update(12,120,0.01);
208 break;
210 detectZeroChange = false;
211 measureMode = LOWFREQUENCY_LONGTERM;
212 frequency.update(60,600,0.001);
213 break;
215 detectZeroChange = true;
216 measureMode = HIGHFREQUENCY_FAST;
217 frequency.update(1,15,0.1);
218 break;
220 detectZeroChange = true;
221 measureMode = HIGHFREQUENCY_MEDIUM;
222 frequency.update(10,120,0.01);
223 break;
224 default:
226 detectZeroChange = true;
227 measureMode = HIGHFREQUENCY_LONGTERM;
228 frequency.update(60,600,0.001);
229 break;
230 }
231 if (!silent)
232 publishMeasureMode();
233 }
234
235 bool begin(Scheduler *_pSched, uint32_t scheduleUs=2000000L) {
242 pSched = _pSched;
243
244 pinMode(pin_input, INPUT_PULLUP);
245
246 if (interruptIndex_input >= 0 && interruptIndex_input < USTD_MAX_FQ_PIRQS) {
247 irqno_input = digitalPinToInterrupt(pin_input);
248 switch (irqMode) {
249 case IM_FALLING:
250 attachInterrupt(irqno_input, ustd_fq_pirq_table[interruptIndex_input], FALLING);
251 fQfrequencyMultiplicator = 1000000L;
252 break;
253 case IM_RISING:
254 attachInterrupt(irqno_input, ustd_fq_pirq_table[interruptIndex_input], RISING);
255 fQfrequencyMultiplicator = 1000000L;
256 break;
257 case IM_CHANGE:
258 attachInterrupt(irqno_input, ustd_fq_pirq_table[interruptIndex_input], CHANGE);
259 fQfrequencyMultiplicator = 500000L;
260 break;
261 }
262 irqsAttached = true;
263 } else {
264 return false;
265 }
266
267 auto ft = [=]() { this->loop(); };
268 tID = pSched->add(ft, name, scheduleUs); // uS schedule
269
270 auto fnall = [=](String topic, String msg, String originator) {
271 this->subsMsg(topic, msg, originator);
272 };
273 pSched->subscribe(tID, name + "/#", fnall);
274 return true;
275 }
276
277 private:
278 void publishMeasureMode() {
279 switch (measureMode) {
281 pSched->publish(name + "/sensor/mode", "LOWFREQUENCY_FAST");
282 break;
284 pSched->publish(name + "/sensor/mode", "LOWFREQUENCY_MEDIUM");
285 break;
287 pSched->publish(name + "/sensor/mode", "LOWFREQUENCY_LONGTERM");
288 break;
290 pSched->publish(name + "/sensor/mode", "HIGHFREQUENCY_FAST");
291 break;
293 pSched->publish(name + "/sensor/mode", "HIGHFREQUENCY_MEDIUM");
294 break;
296 pSched->publish(name + "/sensor/mode", "HIGHFREQUENCY_LONGTERM");
297 break;
298 }
299 }
300
301 void publish_frequency() {
302 char buf[32];
303 sprintf(buf, "%10.3f", inputFrequencyVal);
304 char *p1 = buf;
305 while (*p1 == ' ')
306 ++p1;
307 pSched->publish(name + "/sensor/frequency", p1);
308 }
309
310 void publish() {
311 publish_frequency();
312 }
313
314 void loop() {
315 double freq = getFqResetpIrqFrequency(interruptIndex_input, 0) * frequencyRenormalisation;
316 if (detectZeroChange) {
317 if ((frequency.lastVal == 0.0 && freq > 0.0) ||
318 (frequency.lastVal > 0.0 && freq == 0.0))
319 frequency.reset();
320 }
321 if (freq >= 0.0 && freq < 1000000.0) {
322 if (frequency.filter(&freq)) {
323 inputFrequencyVal = freq;
324 publish_frequency();
325 }
326 }
327 }
328
329 void subsMsg(String topic, String msg, String originator) {
330 if (topic == name + "/sensor/state/get") {
331 publish();
332 } else if (topic == name + "/sensor/frequency/get") {
333 publish_frequency();
334 } else if (topic == name + "/sensor/mode/set") {
335 if (msg == "LOWFREQUENCY_FAST" || msg == "0") {
337 }
338 if (msg == "LOWFREQUENCY_MEDIUM" || msg == "1") {
340 }
341 if (msg == "LOWFREQUENCY_LONGTERM" || msg == "2") {
343 }
344 if (msg == "HIGHFREQUENCY_FAST" || msg == "3") {
346 }
347 if (msg == "HIGHFREQUENCY_MEDIUM" || msg == "4") {
349 }
350 if (msg == "HIGHFREQUENCY_LONGTERM" || msg == "5") {
352 }
353 } else if (topic == name + "/sensor/mode/get") {
354 publishMeasureMode();
355 }
356 };
357}; // FrequencyCounter
358
359} // namespace ustd
Definition: mup_frequency_counter.h:131
InterruptMode
Definition: mup_frequency_counter.h:134
@ IM_CHANGE
Definition: mup_frequency_counter.h:136
@ IM_FALLING
Definition: mup_frequency_counter.h:135
@ IM_RISING
Definition: mup_frequency_counter.h:134
void setMeasureMode(MeasureMode mode, bool silent=false)
Definition: mup_frequency_counter.h:192
FrequencyCounter(String name, uint8_t pin_input, int8_t interruptIndex_input, MeasureMode measureMode=HIGHFREQUENCY_MEDIUM, InterruptMode irqMode=InterruptMode::IM_FALLING)
Definition: mup_frequency_counter.h:170
bool begin(Scheduler *_pSched, uint32_t scheduleUs=2000000L)
Definition: mup_frequency_counter.h:235
MeasureMode
Definition: mup_frequency_counter.h:140
@ HIGHFREQUENCY_LONGTERM
Definition: mup_frequency_counter.h:146
@ LOWFREQUENCY_FAST
Definition: mup_frequency_counter.h:141
@ HIGHFREQUENCY_MEDIUM
Definition: mup_frequency_counter.h:145
@ LOWFREQUENCY_MEDIUM
Definition: mup_frequency_counter.h:142
@ LOWFREQUENCY_LONGTERM
Definition: mup_frequency_counter.h:143
@ HIGHFREQUENCY_FAST
Definition: mup_frequency_counter.h:144
The muwerk namespace.
Definition: home_assistant.h:10