|
@@ -48,6 +48,23 @@
|
48
|
48
|
#include "animations.h"
|
49
|
49
|
#include "transmit.h"
|
50
|
50
|
|
|
51
|
+// Length of an idle animation frame, 24 -> 1 second
|
|
52
|
+#define IDLELENGTH 48
|
|
53
|
+
|
|
54
|
+void init(void);
|
|
55
|
+uint8_t audioModeSelected(void);
|
|
56
|
+uint8_t selfTest(void);
|
|
57
|
+void serialHandler(char c);
|
|
58
|
+
|
|
59
|
+uint8_t defaultImageCube[64] = { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81,
|
|
60
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
61
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
62
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
63
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
64
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
65
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
66
|
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
67
|
+
|
51
|
68
|
#define NOERROR 0
|
52
|
69
|
// Audio does not answer
|
53
|
70
|
#define AUDIOERROR 1
|
|
@@ -58,161 +75,139 @@
|
58
|
75
|
// x = errorcode, e = error definition, not NOERROR
|
59
|
76
|
#define ISERROR(x, e) ((x) & (e))
|
60
|
77
|
|
61
|
|
-// Length of an idle animation frame, 24 -> 1 second
|
62
|
|
-#define IDLELENGTH 48
|
63
|
|
-
|
64
|
|
-void serialHandler(char c);
|
65
|
|
-uint8_t audioModeSelected(void);
|
66
|
|
-void printErrors(uint8_t e);
|
67
|
|
-uint8_t selfTest(void);
|
68
|
|
-void printTime(void);
|
69
|
|
-
|
70
|
|
-// #include "snake.c"
|
71
|
|
-
|
72
|
78
|
uint8_t shouldRestart = 0;
|
73
|
|
-uint8_t refreshAnimationCount = 1;
|
|
79
|
+uint8_t refreshAnimationCount = 0;
|
74
|
80
|
uint8_t lastButtonState = 0;
|
75
|
|
-uint8_t maxButtonState = 0;
|
76
|
|
-char buffer[11];
|
77
|
|
-
|
78
|
|
-#include "builtInFrames.c"
|
|
81
|
+uint8_t maxButtonState = 1; // No audio, get's checked later
|
|
82
|
+uint8_t disableAudioData = 0;
|
|
83
|
+uint8_t disableMemory = 0;
|
|
84
|
+uint8_t disableAnim = 0;
|
79
|
85
|
|
80
|
|
-uint8_t DebugDone = 0; // Bit 0: 10s int. count, Bit 1: idle switch
|
81
|
|
- // Bit 2: state changed, disable idle
|
|
86
|
+char buffer[11];
|
82
|
87
|
|
83
|
88
|
int main(void) {
|
84
|
|
- uint8_t *audioData = NULL;
|
85
|
|
- uint8_t *imageData = NULL;
|
86
|
|
- uint8_t i, length = 0;
|
87
|
|
- uint16_t count;
|
88
|
|
- uint64_t lastChecked;
|
89
|
|
- uint8_t idleCounter = 0;
|
|
89
|
+ /*
|
|
90
|
+ Quick Summary of the jobs main has to do:
|
|
91
|
+ - Initialize Cube
|
|
92
|
+ - Regularly check the buttonstate
|
|
93
|
+ - Check for incoming serial transmission and run serialHandler
|
|
94
|
+ - Check if animations are stored
|
|
95
|
+ --> If yes, display them
|
|
96
|
+ --> If no, display our idle animations
|
|
97
|
+ */
|
|
98
|
+
|
|
99
|
+ uint8_t i;
|
|
100
|
+ uint8_t imageIndex = 0, imageCount = 0;
|
|
101
|
+ uint8_t idleIndex = 0, idleCount = 0;
|
|
102
|
+ uint8_t lastButtonCheck, fpsWasSent = 0;
|
90
|
103
|
uint32_t temp;
|
|
104
|
+ uint8_t *imageData = NULL, *audioData = NULL;
|
|
105
|
+ uint8_t duration = 0;
|
91
|
106
|
|
92
|
|
- MCUCSR = 0;
|
|
107
|
+ // Initialization:
|
|
108
|
+ MCUCSR = 0; // Reset Watchdog
|
93
|
109
|
wdt_disable();
|
94
|
|
-
|
95
|
|
- DDRA = 0xFF; // Latch Data Bus as Output
|
96
|
|
- DDRD = 0xFC; DDRB = 24; // Mosfets as Output
|
97
|
|
- DDRC = 0xFC; DDRB |= 6; // Latch Enable as Output
|
98
|
|
- DDRB &= ~(1 << PB0); // Pushbutton as Input
|
99
|
|
-
|
100
|
|
- initCube();
|
101
|
|
- serialInit(25, 8, NONE, 1);
|
102
|
|
- i2c_init();
|
103
|
|
- initSystemTimer();
|
104
|
|
- sei(); // Enable Interrupts
|
105
|
|
-
|
106
|
|
- setImage(defaultImageCube); // Display something
|
107
|
|
-
|
|
110
|
+ init(); // Initialize all subsystems, set port directions, enable interrupts
|
108
|
111
|
wdt_enable(WDTO_1S); // Watchdog reset after 1 second
|
109
|
|
-
|
110
|
|
- serialWriteString(getString(2)); // "Initialized: "
|
111
|
|
-
|
112
|
|
- i = selfTest();
|
113
|
|
- if (i) {
|
114
|
|
- serialWriteString(getString(1)); // Selftest error
|
115
|
|
- serialWriteString(itoa(i, buffer, 2));
|
116
|
|
- serialWrite('\n');
|
117
|
|
- printErrors(i);
|
118
|
|
- }
|
119
|
|
-
|
120
|
|
- serialWriteString(getString(0)); // Version
|
121
|
|
-
|
122
|
|
- maxButtonState = numberOfVisualizations() + 1; // All visualizations and anim mode
|
123
|
|
-
|
124
|
|
- audioModeSelected();
|
125
|
|
- lastChecked = getSystemTime();
|
126
|
|
-
|
127
|
|
- i = 0; // Image count
|
128
|
|
- count = getAnimationCount();
|
129
|
|
-
|
130
|
|
- while (1) {
|
131
|
|
- // Reset if requested
|
132
|
|
- if (!shouldRestart) {
|
|
112
|
+ i = selfTest(); // Run selftest, print errors
|
|
113
|
+ // Disable subsystems if they are unavailable
|
|
114
|
+ if (ISERROR(i, AUDIOERROR))
|
|
115
|
+ disableAudioData = 1;
|
|
116
|
+ if (ISERROR(i, MEMORYERROR) || ISERROR(i, MEMORYWRITEERROR))
|
|
117
|
+ disableMemory = 1;
|
|
118
|
+ serialWriteString(getString(0)); // Print Version
|
|
119
|
+
|
|
120
|
+ audioModeSelected(); // Initial button state check
|
|
121
|
+ lastButtonCheck = getSystemTime(); // Time we checked
|
|
122
|
+
|
|
123
|
+ if (disableMemory == 0)
|
|
124
|
+ imageCount = getAnimationCount(); // Retrieve image count from memory
|
|
125
|
+ idleCount = numOfAnimations();
|
|
126
|
+ if (disableAudioData == 0)
|
|
127
|
+ maxButtonState = numberOfVisualizations() + 1; // Number of toggle steps for button
|
|
128
|
+
|
|
129
|
+ while(1) { // Our Mainloop
|
|
130
|
+ if (!shouldRestart) { // A flag to trigger a watchdog reset
|
133
|
131
|
wdt_reset();
|
134
|
132
|
}
|
135
|
133
|
|
136
|
|
- if(lastButtonState >= 1) {
|
137
|
|
- // Get Audio Data and visualize it.
|
138
|
|
- // Visualization id is in (lastButtonState - 1)
|
139
|
|
- if (isFinished()) {
|
140
|
|
- audioData = getAudioData(); // Not malloc'ed => Don't free
|
141
|
|
- if (audioData != NULL) {
|
142
|
|
- runVisualization(audioData, lastButtonState - 1);
|
143
|
|
- }
|
144
|
|
- }
|
145
|
|
- } else {
|
146
|
|
- if (refreshAnimationCount) {
|
147
|
|
- // Get animation count stored in FRAM via TWI, if needed
|
148
|
|
- count = getAnimationCount();
|
149
|
|
- refreshAnimationCount = 0;
|
150
|
|
- i = 0;
|
151
|
|
- }
|
|
134
|
+ if (refreshAnimationCount) {
|
|
135
|
+ refreshAnimationCount = 0;
|
|
136
|
+ if (disableMemory == 0)
|
|
137
|
+ imageCount = getAnimationCount();
|
|
138
|
+ }
|
152
|
139
|
|
153
|
|
- if (count > 0) { // We have frames stored
|
154
|
|
- if (isFinished() > length) {
|
155
|
|
- // Load next image
|
156
|
|
- if (i < (count - 1)) {
|
157
|
|
- i++;
|
158
|
|
- } else {
|
159
|
|
- i = 0;
|
160
|
|
- }
|
|
140
|
+ if (serialHasChar()) { // Run serialHandler
|
|
141
|
+ serialHandler((char)(serialGet()));
|
|
142
|
+ }
|
161
|
143
|
|
162
|
|
- imageData = getFrame(i);
|
163
|
|
- length = imageData[64];
|
164
|
|
- setImage(imageData);
|
165
|
|
- free(imageData);
|
166
|
|
- }
|
167
|
|
- } else { // No frames available
|
168
|
|
- if (!(DebugDone & 4)) { // Idle animation allowed
|
169
|
|
- if (DebugDone & 2) {
|
170
|
|
- if (idleCounter < numOfAnimations()) {
|
171
|
|
- executeAnimation(idleCounter++);
|
|
144
|
+ if ((getSystemTime() - lastButtonCheck) > 150) { // Check button state every 150ms
|
|
145
|
+ audioModeSelected();
|
|
146
|
+ lastButtonCheck = getSystemTime();
|
|
147
|
+ }
|
|
148
|
+
|
|
149
|
+ if (lastButtonState == 0) {
|
|
150
|
+ // Display animations, stored or built-in
|
|
151
|
+ if (disableAnim == 0) {
|
|
152
|
+ if ((imageCount > 0) && (disableMemory == 0)) {
|
|
153
|
+ // Memory frames
|
|
154
|
+ if (isFinished() > duration) {
|
|
155
|
+ // Last frame was displayed long enough
|
|
156
|
+ imageIndex = (imageIndex < (imageCount - 1)) ? (imageIndex + 1) : 0;
|
|
157
|
+ imageData = getFrame(i);
|
|
158
|
+ if (imageData == NULL) {
|
|
159
|
+ duration = 24;
|
|
160
|
+ setImage(defaultImageCube);
|
172
|
161
|
} else {
|
173
|
|
- idleCounter = 0;
|
174
|
|
- DebugDone &= ~(2); // Show frames again
|
175
|
|
- }
|
176
|
|
- } else {
|
177
|
|
- // Show idle frames
|
178
|
|
- if (isFinished() >= IDLELENGTH) {
|
179
|
|
- setImage(idleAnimation[idleCounter]);
|
180
|
|
- if (idleCounter < IDLEANIMATIONCOUNT) {
|
181
|
|
- idleCounter++;
|
182
|
|
- } else {
|
183
|
|
- idleCounter = 0;
|
184
|
|
- DebugDone |= 2; // Show animation
|
185
|
|
- }
|
|
162
|
+ duration = imageData[64];
|
|
163
|
+ setImage(imageData);
|
|
164
|
+ free(imageData);
|
186
|
165
|
}
|
187
|
166
|
}
|
|
167
|
+ } else {
|
|
168
|
+ // Built-In Frames
|
|
169
|
+ if (isFinished()) {
|
|
170
|
+ idleIndex = (idleIndex < (idleCount - 1)) ? (idleIndex + 1) : 0;
|
|
171
|
+ executeAnimation(idleIndex);
|
|
172
|
+ }
|
188
|
173
|
}
|
189
|
174
|
}
|
190
|
|
- }
|
|
175
|
+ } else {
|
|
176
|
+ // An audiomode is selected
|
191
|
177
|
|
192
|
|
- if (serialHasChar()) {
|
193
|
|
- serialHandler((char)(serialGet()));
|
194
|
178
|
}
|
195
|
179
|
|
196
|
180
|
// Print fps after one second
|
197
|
|
- if ((getSystemTime() >= 1000) && ((DebugDone & 1) == 0)) {
|
|
181
|
+ if ((getSystemTime() >= 1000) && (fpsWasSent == 0)) {
|
198
|
182
|
temp = getTriggerCount();
|
199
|
183
|
serialWriteString(ltoa(temp, buffer, 10));
|
200
|
184
|
serialWriteString(getString(27));
|
201
|
185
|
serialWriteString(ltoa((temp / 8), buffer, 10));
|
202
|
186
|
serialWriteString(getString(28));
|
203
|
|
- DebugDone |= 1;
|
|
187
|
+ fpsWasSent = 1;
|
204
|
188
|
}
|
205
|
189
|
|
206
|
|
- if ((getSystemTime() - lastChecked) > 150) { // Check button state every 150ms
|
207
|
|
- audioModeSelected();
|
208
|
|
- lastChecked = getSystemTime();
|
209
|
|
- }
|
210
|
190
|
}
|
211
|
191
|
|
212
|
|
- close();
|
|
192
|
+ close(); // This is of course unneccessary. We never reach this point.
|
213
|
193
|
return 0;
|
214
|
194
|
}
|
215
|
195
|
|
|
196
|
+void init(void) {
|
|
197
|
+ DDRA = 0xFF; // Latch Data Bus as Output
|
|
198
|
+ DDRD = 0xFC; DDRB = 24; // Mosfets as Output
|
|
199
|
+ DDRC = 0xFC; DDRB |= 6; // Latch Enable as Output
|
|
200
|
+ DDRB &= ~(1 << PB0); // Pushbutton as Input
|
|
201
|
+
|
|
202
|
+ initCube();
|
|
203
|
+ serialInit(25, 8, NONE, 1);
|
|
204
|
+ i2c_init();
|
|
205
|
+ initSystemTimer();
|
|
206
|
+ sei(); // Enable Interrupts
|
|
207
|
+
|
|
208
|
+ setImage(defaultImageCube); // Display something
|
|
209
|
+}
|
|
210
|
+
|
216
|
211
|
uint8_t audioModeSelected(void) {
|
217
|
212
|
// Pushbutton: PB0, Low active
|
218
|
213
|
|
|
@@ -250,19 +245,22 @@ uint8_t selfTest(void) {
|
250
|
245
|
result |= MEMORYWRITEERROR;
|
251
|
246
|
}
|
252
|
247
|
|
253
|
|
- return result;
|
254
|
|
-}
|
255
|
|
-
|
256
|
|
-void printErrors(uint8_t e) {
|
257
|
|
- if (ISERROR(e, AUDIOERROR)) {
|
258
|
|
- serialWriteString(getString(3));
|
259
|
|
- }
|
260
|
|
- if (ISERROR(e, MEMORYERROR)) {
|
261
|
|
- serialWriteString(getString(4));
|
262
|
|
- }
|
263
|
|
- if (ISERROR(e, MEMORYWRITEERROR)) {
|
264
|
|
- serialWriteString(getString(5));
|
|
248
|
+ if (result) { // Error in Selftest
|
|
249
|
+ serialWriteString(getString(1));
|
|
250
|
+ serialWriteString(itoa(result, buffer, 2));
|
|
251
|
+ serialWrite('\n');
|
|
252
|
+ if (ISERROR(result, AUDIOERROR)) {
|
|
253
|
+ serialWriteString(getString(3));
|
|
254
|
+ }
|
|
255
|
+ if (ISERROR(result, MEMORYERROR)) {
|
|
256
|
+ serialWriteString(getString(4));
|
|
257
|
+ }
|
|
258
|
+ if (ISERROR(result, MEMORYWRITEERROR)) {
|
|
259
|
+ serialWriteString(getString(5));
|
|
260
|
+ }
|
265
|
261
|
}
|
|
262
|
+
|
|
263
|
+ return result;
|
266
|
264
|
}
|
267
|
265
|
|
268
|
266
|
void randomAnimation(void) {
|
|
@@ -276,6 +274,7 @@ void randomAnimation(void) {
|
276
|
274
|
b[x] = 0;
|
277
|
275
|
}
|
278
|
276
|
while(1) {
|
|
277
|
+ wdt_reset();
|
279
|
278
|
setImage(b);
|
280
|
279
|
while(isFinished() == 0);
|
281
|
280
|
x = rand() / 4096;
|
|
@@ -286,7 +285,7 @@ void randomAnimation(void) {
|
286
|
285
|
if (serialHasChar()) {
|
287
|
286
|
serialWriteString(getString(25));
|
288
|
287
|
free(b);
|
289
|
|
- serialHandler(serialGet());
|
|
288
|
+ serialGet();
|
290
|
289
|
return;
|
291
|
290
|
}
|
292
|
291
|
}
|
|
@@ -316,8 +315,10 @@ void serialHandler(char c) {
|
316
|
315
|
break;
|
317
|
316
|
|
318
|
317
|
case 'd': case 'D':
|
319
|
|
- clearMem();
|
|
318
|
+ // clearMem(); // Much too invasive
|
|
319
|
+ setAnimationCount(0);
|
320
|
320
|
serialWrite(OK);
|
|
321
|
+ refreshAnimationCount = 1;
|
321
|
322
|
break;
|
322
|
323
|
|
323
|
324
|
case 'g': case 'G':
|
|
@@ -379,11 +380,7 @@ void serialHandler(char c) {
|
379
|
380
|
break;
|
380
|
381
|
|
381
|
382
|
case 'e': case 'E':
|
382
|
|
- c = selfTest();
|
383
|
|
- serialWriteString(getString(19));
|
384
|
|
- serialWriteString(itoa(c, buffer, 2));
|
385
|
|
- serialWrite('\n');
|
386
|
|
- printErrors(c);
|
|
383
|
+ selfTest();
|
387
|
384
|
break;
|
388
|
385
|
|
389
|
386
|
case 'n': case 'N':
|
|
@@ -392,32 +389,28 @@ void serialHandler(char c) {
|
392
|
389
|
|
393
|
390
|
case '0':
|
394
|
391
|
fillBuffer(0);
|
395
|
|
- DebugDone |= 4;
|
|
392
|
+ disableAnim = 1;
|
396
|
393
|
break;
|
397
|
394
|
|
398
|
395
|
case '1':
|
399
|
396
|
fillBuffer(0xFF);
|
400
|
|
- DebugDone |= 4;
|
|
397
|
+ disableAnim = 1;
|
401
|
398
|
break;
|
402
|
399
|
|
403
|
400
|
case '3':
|
404
|
401
|
setImage(defaultImageCube);
|
405
|
|
- DebugDone |= 4;
|
|
402
|
+ disableAnim = 1;
|
406
|
403
|
break;
|
407
|
404
|
|
408
|
405
|
case '2':
|
409
|
|
- DebugDone |= 4;
|
410
|
406
|
fillBuffer(0);
|
411
|
|
- for (i = 0; i < 64; i++) {
|
412
|
|
- defaultImageA[i] = 0;
|
413
|
|
- }
|
414
|
407
|
while(1) {
|
415
|
408
|
for (i = 0; i < 8; i++) {
|
416
|
409
|
for (y = 0; y < 8; y++) {
|
417
|
|
- defaultImageA[y + (i * 8)] = 0;
|
|
410
|
+ defaultImageCube[y + (i * 8)] = 0;
|
418
|
411
|
for (z = 0; z < 8; z++) {
|
419
|
|
- defaultImageA[y + (i * 8)] |= (1 << z);
|
420
|
|
- setImage(defaultImageA);
|
|
412
|
+ defaultImageCube[y + (i * 8)] |= (1 << z);
|
|
413
|
+ setImage(defaultImageCube);
|
421
|
414
|
while (isFinished() == 0) {
|
422
|
415
|
wdt_reset();
|
423
|
416
|
if (serialHasChar()) {
|
|
@@ -426,13 +419,13 @@ void serialHandler(char c) {
|
426
|
419
|
}
|
427
|
420
|
}
|
428
|
421
|
}
|
429
|
|
- defaultImageA[y + (i * 8)] = 0;
|
|
422
|
+ // defaultImageCube[y + (i * 8)] = 0;
|
430
|
423
|
}
|
431
|
424
|
}
|
432
|
425
|
}
|
433
|
426
|
break;
|
434
|
427
|
killMeForIt:
|
435
|
|
- serialGet();
|
|
428
|
+ serialGet(); // Killed because we got a serial char. Remove it from buffer.
|
436
|
429
|
serialWriteString(getString(25));
|
437
|
430
|
break;
|
438
|
431
|
|
|
@@ -447,30 +440,3 @@ killMeForIt:
|
447
|
440
|
}
|
448
|
441
|
// c was used as temp var and does not contain the char anymore...!
|
449
|
442
|
}
|
450
|
|
-
|
451
|
|
-void printTime(void) {
|
452
|
|
- serialWriteString(getString(14));
|
453
|
|
- serialWriteString(ltoa(getSystemTime(), buffer, 10));
|
454
|
|
- serialWriteString("ms");
|
455
|
|
- if (getSystemTime() > 60000) {
|
456
|
|
- serialWriteString(" (");
|
457
|
|
- serialWriteString(itoa(getSystemTime() / 60000, buffer, 10));
|
458
|
|
- serialWriteString(" min)");
|
459
|
|
- }
|
460
|
|
- if (getSystemTime() > 1000) {
|
461
|
|
- serialWriteString(" (");
|
462
|
|
- serialWriteString(itoa(getSystemTime() / 1000, buffer, 10));
|
463
|
|
- itoa(getSystemTime() % 1000, buffer, 10);
|
464
|
|
- if (buffer[0] != '\0')
|
465
|
|
- serialWrite('.');
|
466
|
|
- if (buffer[2] == '\0')
|
467
|
|
- serialWrite('0');
|
468
|
|
- if (buffer[1] == '\0')
|
469
|
|
- serialWrite('0');
|
470
|
|
- if (buffer[0] != '\0')
|
471
|
|
- serialWriteString(buffer);
|
472
|
|
- serialWriteString("s)\n");
|
473
|
|
- } else {
|
474
|
|
- serialWrite('\n');
|
475
|
|
- }
|
476
|
|
-}
|