-
Notifications
You must be signed in to change notification settings - Fork 0
/
Atm_led_matrix.cpp
347 lines (322 loc) · 9.91 KB
/
Atm_led_matrix.cpp
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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
#include "Atm_led_matrix.hpp"
Atm_led_matrix& Atm_led_matrix::begin( IO &io ) {
if ( initialized ) return *this; // idempotent
// clang-format off
const static state_t state_table[] PROGMEM = {
/* ON_ENTER ON_LOOP ON_EXIT EVT_DONE EVT_RUN EVT_UPDATE EVT_MILLI, ELSE */
/* IDLE */ -1, ATM_SLEEP, -1, -1, RUNNING, UPDATING, -1, -1,
/* WAITING */ -1, -1, -1, -1, -1, -1, RUNNING, -1,
/* RUNNING */ ENT_RUNNING, -1, -1, IDLE, -1, UPDATING, -1, WAITING,
/* UPDATING */ ENT_UPDATING, -1, -1, -1, WAITING, -1, -1, IDLE,
};
// clang-format on
Symbolic_Machine::begin( state_table, ELSE );
this->io = &io;
numOfLeds = io.numberOfLeds();
for ( int i = 0; i < numOfLeds; i++ )
profile( i, 0, 127, 50, 0 ); // Select a safe default profile
io.show();
last_milli = millis();
numOfGroups = 0;
initialized = 1;
return *this;
}
Atm_led_matrix& Atm_led_matrix::loadSymbols( const char leds[] ) {
Symbolic_Machine::loadSymbols( leds );
return *this;
}
Atm_led_matrix& Atm_led_matrix::loadGroups( const char groups[] ) {
numOfGroups = countSymbols( 0 ) - io->numberOfLeds();
int16_t data_size = loadIntList( symbols, groups, NULL, numOfGroups, io->numberOfLeds() );
int16_t* pdata = (int16_t *) malloc( data_size * 2 );
if ( pdata == NULL ) Serial.println( "Atm_led_matrix::loadGroups: malloc failed" );
memset( pdata, 0, data_size * 2 );
data_size = loadIntList( symbols, groups, pdata, numOfGroups, io->numberOfLeds() );
group_def = pdata;
return *this;
}
int Atm_led_matrix::event( int id ) {
switch ( id ) {
case EVT_DONE:
return !running && !refresh;
case EVT_RUN:
return running || refresh;
case EVT_UPDATE:
return refresh;
case EVT_MILLI: // Becomes true when milli value changes
uint8_t milli_byte = millis();
if ( last_milli != milli_byte ) {
last_milli = milli_byte;
return 1;
}
return 0;
}
return 0;
}
void Atm_led_matrix::action( int id ) {
switch ( id ) {
case ENT_RUNNING:
running = 0;
for ( int i = 0; i < numOfLeds; i++ ) {
// Set running = 1; while there is work to do
switch ( meta[i].state ) {
case LED_STATE_DELAY:
if ( millis() - meta[i].last_millis >= meta[i].T0 ) {
set( i, meta[i].L1 );
meta[i].state = LED_STATE_RGBW1;
meta[i].last_millis = millis();
refresh = 1;
}
running = 1;
break;
case LED_STATE_RGBW1:
if ( millis() - meta[i].last_millis >= meta[i].T1 ) {
if ( meta[i].L2 ) {
set( i, meta[i].L2 );
meta[i].state = LED_STATE_RGBW2;
refresh = 1;
} else {
set( i, 0 );
meta[i].state = LED_STATE_IDLE;
refresh = 1;
}
} else {
running = 1;
}
break;
}
}
if ( refresh ) {
if ( io->show() ) refresh = 0;
}
return;
case ENT_UPDATING:
if ( io->show() ) refresh = 0;
return;
case ENT_IDLE:
return;
}
}
int16_t* Atm_led_matrix::parseGroups( int16_t* group_def ) {
int16_t* p = group_def;
while ( p[0] != -1 ) *p++ = 0;
numOfGroups = p - group_def;
p++;
while ( p[0] != -1 ) {
int gid = p[0] - numOfLeds; // Leds start at 0 while switches start at 1, does that create a problem here???
group_def[gid] = p - group_def + 1;
p++;
while ( p[0] != -1 ) {
p++;
}
p++;
}
// Make unused entries point to -1 at end of index
p = group_def;
while ( p[0] != -1 ) {
if ( p[0] == 0 ) *p = numOfGroups;
p++;
}
return group_def;
}
Atm_led_matrix& Atm_led_matrix::readProfiles( char label, const int16_t* profile_def ) {
const int16_t* p = profile_def;
while ( p[0] != -1 ) {
int16_t ptype = *p++;
if ( ptype == label ) {
int16_t T0 = *p++;
int16_t L1 = *p++;
int16_t T1 = *p++;
int16_t L2 = *p++;
while ( p[0] != -1 ) {
profile( *p++, T0, L1, T1, L2 );
}
} else {
while ( *p != -1 ) p++;
}
p++;
}
return *this;
}
int16_t Atm_led_matrix::numberOfGroups( void ) {
return numOfGroups;
}
Atm_led_matrix& Atm_led_matrix::set( int16_t ledno, uint32_t c ) {
if ( ledno > -1 ) {
if ( ledno >= numOfLeds ) {
int16_t p = group_def[ledno - numOfLeds];
while ( p != -1 && group_def[p] != -1 )
set( group_def[p++], c );
} else {
io->setPixelColor( ledno, c >> 24, c >> 16 & 0xff, c >> 8 & 0xff, c & 0xff );
}
}
return *this;
}
Atm_led_matrix& Atm_led_matrix::trigger( int event ) {
Symbolic_Machine::trigger( event );
return *this;
}
/* Optionally override the default state() method
Control what the machine returns when another process requests its state
*/
int Atm_led_matrix::state( void ) {
return Symbolic_Machine::state();
}
Atm_led_matrix& Atm_led_matrix::profile( int16_t ledno, uint16_t T0, uint32_t L1, uint16_t T1, uint32_t L2 /* = 0 */ ) {
if ( ledno > -1 ) {
if ( ledno < numOfLeds ) {
meta[ledno].T0 = T0;
meta[ledno].L1 = L1;
meta[ledno].T1 = T1;
meta[ledno].L2 = L2;
} else {
int16_t p = group_def[ledno - numOfLeds];
while ( p != -1 && group_def[p] != -1 )
profile( group_def[p++], T0, L1, T1, L2 );
}
}
return *this;
}
Atm_led_matrix& Atm_led_matrix::profile( const char* led_group_str, uint16_t T0, uint32_t L1, uint16_t T1, uint32_t L2 /* = 0 */ ) {
return profile( findSymbol( led_group_str ), T0, L1, T1, L2 );
}
Atm_led_matrix& Atm_led_matrix::on( int ledno, bool no_update /* = false */ ) {
if ( ledno > -1 ) {
if ( ledno >= numOfLeds ) {
int16_t p = group_def[ledno - numOfLeds];
while ( p != -1 && group_def[p] != -1 )
on( group_def[p++], true );
if ( !no_update ) trigger( EVT_UPDATE );
} else {
if ( meta[ledno].state == LED_STATE_IDLE || meta[ledno].state == LED_STATE_RGBW2 ) {
meta[ledno].last_millis = millis();
if ( meta[ledno].T0 ) {
meta[ledno].state = LED_STATE_DELAY;
set( ledno, 0 );
} else {
if ( meta[ledno].T1 == 0 ) {
set( ledno, meta[ledno].L2 );
meta[ledno].state = LED_STATE_RGBW2;
} else {
set( ledno, meta[ledno].L1 );
meta[ledno].state = LED_STATE_RGBW1;
}
}
refresh = 1;
if ( !no_update ) trigger( EVT_UPDATE );
}
}
}
return *this;
}
Atm_led_matrix& Atm_led_matrix::off( int ledno, bool no_update /* = false */ ) {
if ( ledno > -1 ) {
if ( ledno >= numOfLeds ) {
int16_t p = group_def[ledno - numOfLeds];
while ( p != -1 && group_def[p] != -1 )
off( group_def[p++], true );
if ( !no_update ) trigger( EVT_UPDATE );
} else {
if ( ledno > -1 && meta[ledno].L2 ) { // Ignore off() for leds in pulse mode
meta[ledno].state = LED_STATE_IDLE;
set( ledno, 0 );
refresh = 1;
if ( !no_update ) trigger( EVT_UPDATE );
}
}
}
return *this;
}
Atm_led_matrix& Atm_led_matrix::off() {
for ( int ledno = 0; ledno < numOfLeds; ledno++ )
off( ledno, true );
refresh = 1;
trigger( EVT_UPDATE );
return *this;
}
Atm_led_matrix& Atm_led_matrix::toggle( int ledno, int v /* = -1 */ ) {
if ( ledno > -1 ) {
if ( ledno >= numOfLeds ) {
int16_t p = group_def[ledno - numOfLeds];
while ( p != -1 && group_def[p] != -1 )
toggle( group_def[p++], v );
trigger( EVT_UPDATE );
} else {
if ( v > -1 ) {
if ( v ) on( ledno ); else off( ledno );
return *this;
}
if ( meta[ledno].state ) {
off( ledno );
} else {
on( ledno );
}
}
}
return *this;
}
int Atm_led_matrix::active( int ledno ) {
if ( ledno > -1 ) {
if ( ledno >= numOfLeds ) {
int16_t p = group_def[ledno - numOfLeds];
return active( group_def[p] );
} else {
return ledno > -1 ? meta[ledno].state : 0;
}
}
return 0;
}
int16_t Atm_led_matrix::count( int16_t ledno, int8_t led_active /* = -1 */ ) {
int16_t cnt = 0;
if ( ledno > -1 ) {
if ( ledno < numOfLeds ) { // Physical led
if ( led_active == -1 ) {
cnt++;
} else {
if ( ( meta[ledno].state > 0 ) == led_active ) cnt++;
}
} else { // Virtual led -> expand & recurse
int16_t p = group_def[ledno - numOfLeds];
while ( p != -1 && group_def[p] != -1 )
cnt += this->count( group_def[p++], led_active );
}
}
return cnt;
}
// Returns the n'th led in a led group or -1
// Single led is group of 1, -1 led always returns -1
int16_t Atm_led_matrix::index( int16_t ledno, int16_t n ) {
int16_t cnt = 0;
if ( ledno > -1 ) {
if ( ledno < numOfLeds ) { // Physical led, return ledno
return n == 0 ? ledno : -1;
} else { // Virtual led -> expand & recurse
int16_t p = group_def[ledno - numOfLeds];
while ( p != -1 && group_def[p] != -1 ) {
if ( cnt++ == n ) {
//Serial.println( *p );
return group_def[p];
}
p++;
}
}
}
//Serial.println( -1 );
return -1;
}
Atm_led_matrix& Atm_led_matrix::update() {
trigger( EVT_UPDATE );
return *this;
}
Atm_led_matrix& Atm_led_matrix::trace( Stream & stream ) {
Symbolic_Machine::setTrace( &stream, atm_serial_debug::trace,
"LED_MATRIX\0EVT_DONE\0EVT_RUN\0EVT_UPDATE\0EVT_MILLI\0ELSE\0IDLE\0WAITING\0RUNNING\0UPDATING" );
Serial.printf( "%d Tracing enabled %s@%X\n", millis(), symbols, (long)(this) );
return *this;
}
Atm_led_matrix& Atm_led_matrix::trace( void ) {
Serial.printf( "%d Tracing disabled %s@%X\n", millis(), symbols, (long)(this) );
Machine::setTrace( NULL, NULL, "" );
return *this;
}