Repository navigation
Expand file tree
/
Copy pathsquareWave.cpp
More file actions
242 lines (187 loc) · 7.03 KB
/
Copy pathsquareWave.cpp
File metadata and controls
242 lines (187 loc) · 7.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#include "squareWave.h"
// Constructor with all the goodies.
squareWave::squareWave(float periodMs,float pulseMs, bool blocking) {
init();
setPeriod(periodMs);
setPulse(pulseMs);
mBlocking = blocking;
}
// Default constructor.
squareWave::squareWave(void) { init(); }
// Setup all the defaults for the constructors.
void squareWave::init(void) {
mNextPeriod = 0;
mPeriodChange = false;
mNextPulse = 0;
mPulseChange = false;
mBlocking = false;
mState = sittinIdle;
mSignal = false;
}
// Destructor, but there's really nothing to destruct.
squareWave::~squareWave(void) { }
// People want to know if we're running or not.
bool squareWave::running(void) { return mState != sittinIdle; }
// People want to know if the state is high or low at the moment. Here it is.
bool squareWave::pulseHiLow(void) { return mSignal; }
// Set a new period duration. This takes effect on the next pulse's startup.
void squareWave::setPeriod(float ms) {
if (ms<MIN_PERIOD_MS) { // Sanity we only go -that- small.
ms = MIN_PERIOD_MS; // There's the limit.
} //
if (ms!=mNextPeriod) { // Only bother them if its different.
mNextPeriod = ms; // Save it off.
mPeriodChange = true; // Flag the change.
}
}
// Set a new pulse duration. This also takes effect on the next pulse's startup.
void squareWave::setPulse(float ms) {
if (ms<0) ms = 0; // Sanity, no negatives!
if (ms!=mNextPulse) { // Only bother them if its different.
mNextPulse = ms; // Save it off.
mPulseChange = true; // In any case, flag the change.
}
}
// Set a new pulse duration as a percent of the period. Again, takes effect on
// the next pulse's startup.
void squareWave::setPercent(float perc) {
float ms;
if (perc<0) perc = 0; // Negitive? Set to zero.
if (perc>100) perc = 100; // Bigger than 100%, set to 100.
ms = mNextPeriod * (perc/100.0); // Calculate the new millisecond value.
setPulse(ms); // Set it.
}
// Set blocking for tight timing. At the expense of everyone else. Once the pulse is fired,
// the code will block while it watches for the timer to expire. Default is no blocking.
void squareWave::setBlocking(bool onOff) { mBlocking = onOff; }
/*
* Toggle the wave on or off. Default is off. Pass true to activate.
* WARNING: If the wave is currently low and you call this with false,
* pulseOff() will NOT be invoked. Do not rely on that method being called.
*/
void squareWave::setOnOff(bool onOff) {
/*
* Ensure we are registered in the idle queue before proceeding.
* If turning on: start the wave and begin all timers.
* If turning off: set state to idle and notify the user via ourPulseOff().
*/
hookup();
if (onOff) {
startWave();
} else {
mState = sittinIdle;
ourPulseOff();
}
}
/*
* Manually set the wave high or low, regardless of current state or timer.
* Useful when you want direct control instead of timer-driven operation.
* Note: This bypasses the normal pulse cycle and may disrupt timed operation.
*/
void squareWave::manualSetHiLow(bool hiLow) {
if (hiLow) ourPulseOn();
else ourPulseOff();
}
// We're going to track if the signal is on or off. Only broadcast changes.
void squareWave::ourPulseOn(void) {
if (!mSignal) {
pulseOn();
mSignal = true;
}
}
// This is called when the pulse begins. The user inherits and fills this out for whatever
// action they want.
void squareWave::pulseOn(void) { }
// Just like the one above. We're going to track if the signal is on or off. Only
// broadcast changes.
void squareWave::ourPulseOff(void) {
if (mSignal) {
pulseOff();
mSignal = false;
}
}
/*
* Called when a pulse cycle completes. Override in your subclass to perform
* custom actions. NOTE: This method is never invoked if the pulse duration
* is less than or equal to the period duration.
*/
void squareWave::pulseOff(void) { }
// This sits in a loop watching the timer then calls pulseOff() when the timer dings.
void squareWave::block(void) {
/*
* Wait for the timer to expire while monitoring for completion.
* Set state to low when done. If the pulse timer fired first,
* stop the pulse before returning.
*/
while (!mPulse.ding() && !mPeriod.ding());
mState = ridingLow;
if (mPulse.ding()) {
ourPulseOff();
}
}
/*
* Initialize the wave by checking for pending changes, applying any updates
* to the period or pulse timers, and starting the appropriate timer.
* If blocking mode is enabled, waits for the pulse to complete before returning.
* If no pulse width is defined, transitions to the low state and waits for the period timer.
*/
void squareWave::startWave(void) {
bool newWave;
newWave = mPeriodChange || mState==sittinIdle;
if (mPeriodChange) {
mPeriod.setTime(mNextPeriod,false);
mPeriodChange = false;
}
if (mPulseChange) {
mPulse.setTime(mNextPulse,false);
mPulseChange = false;
}
if (newWave) {
mPeriod.start();
} else {
mPeriod.stepTime();
}
mPulse.start();
if (mNextPulse) {
mState = ridingHi;
ourPulseOn();
if (mBlocking) {
block();
}
} else {
mState = ridingLow;
}
}
// Our idle routine where everything runs in the background.
void squareWave::idle(void) {
switch (mState) { // Have a look at our state.
case sittinIdle : return; // sitting idle? return as fast as possible.
case ridingHi : // Riding high? Pulse is set to high.
if (mPulse.ding()) { // If the pulse timer has expired.
mState = ridingLow; // Swap the state to riding low.
ourPulseOff(); // Announce it.
} //
break; // Jump out.
case ridingLow : // Riding low? Waiting to spin out the clock.
if (mPeriod.ding()) { // If the period timer has expired.
startWave(); // We restart the cycle.
} //
break; // Done, jump out.
}
}
/*
void squareWave::printState(void) {
Serial.print("squareWave, we are : ");
switch(mState) {
case sittinIdle : Serial.println("Sitting idle"); break;
case ridingHi : Serial.println("Riding high!"); break;
case ridingLow : Serial.println("Riding Low."); break;
}
Serial.println("mPeriod timeObj");
mPeriod.printState();
Serial.println();
Serial.println("mPulse timeObj");
mPulse.printState();
Serial.println();
}
*/