Simple single-color 8x8x8 LED Cube with AVRs
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

main.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /*
  2. * main.c
  3. *
  4. * Copyright 2011 Thomas Buck <xythobuz@me.com>
  5. * Copyright 2011 Max Nuding <max.nuding@gmail.com>
  6. * Copyright 2011 Felix Bäder <baeder.felix@gmail.com>
  7. *
  8. * This file is part of LED-Cube.
  9. *
  10. * LED-Cube is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * LED-Cube is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with LED-Cube. If not, see <http://www.gnu.org/licenses/>.
  22. */
  23. #ifndef F_CPU
  24. #define F_CPU 16000000L
  25. #endif
  26. #define OK 0x42
  27. #define ERROR 0x23
  28. #include <avr/io.h>
  29. #include <util/delay.h>
  30. #include <avr/interrupt.h>
  31. #include <avr/pgmspace.h>
  32. #include <stdint.h>
  33. #include <stdlib.h>
  34. #include <avr/wdt.h>
  35. #include "serial.h"
  36. #include "cube.h"
  37. #include "time.h"
  38. #include "audio.h"
  39. #include "mem.h"
  40. #include "memLayer.h"
  41. #include "twi.h"
  42. #include "strings.h"
  43. #include "visualizer.h"
  44. #include "animations.h"
  45. #include "transmit.h"
  46. // Length of an idle animation frame, 24 -> 1 second
  47. #define IDLELENGTH 48
  48. void init(void);
  49. uint8_t audioModeSelected(void);
  50. uint8_t selfTest(void);
  51. void serialHandler(char c);
  52. uint8_t defaultImageCube[64] = { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81,
  53. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  54. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  55. 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81,
  56. 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81,
  57. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  58. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  59. 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 };
  60. #define NOERROR 0
  61. // Audio does not answer
  62. #define AUDIOERROR 1
  63. // Memory does not answer
  64. #define MEMORYERROR 2
  65. // Memory not writeable
  66. #define MEMORYWRITEERROR 4
  67. // x = errorcode, e = error definition, not NOERROR
  68. #define ISERROR(x, e) ((x) & (e))
  69. uint8_t shouldRestart = 0;
  70. uint8_t refreshAnimationCount = 0;
  71. uint8_t lastButtonState = 0;
  72. uint8_t maxButtonState = 1; // No audio, get's checked later
  73. uint8_t disableAudioData = 0;
  74. uint8_t disableMemory = 0;
  75. uint8_t disableAnim = 0;
  76. char buffer[11];
  77. /* Not so powerful Debouncing Example
  78. * No Interrupt needed
  79. * Author: Peter Dannegger
  80. */
  81. #define debounce(port, pin) ({ \
  82. static uint8_t flag = 0; /* new variable on every macro usage */ \
  83. uint8_t i = 0; \
  84. if (flag) { /* check for key release: */ \
  85. for(;;) { /* loop ... */ \
  86. if(!(port & 1 << pin)) { /* ... until key pressed or ... */ \
  87. i = 0; \
  88. break; \
  89. } \
  90. _delay_us(98); /* * 256 = 25ms */ \
  91. if(--i == 0) { /* ... until key >25ms released */ \
  92. flag = 0; /* clear press flag */ \
  93. i = 0; /* 0 = key release debounced */ \
  94. break; \
  95. } \
  96. } \
  97. } else { /* else check for key press: */ \
  98. for(;;) { /* loop ... */ \
  99. if ((port & 1<<pin)) { /* ... until key released or ... */ \
  100. i = 0; \
  101. break; \
  102. } \
  103. _delay_us( 98 ); /* * 256 = 25ms */ \
  104. if (--i == 0) { /* ... until key >25ms pressed */ \
  105. flag = 1; /* set press flag */ \
  106. i = 1; /* 1 = key press debounced */ \
  107. break; \
  108. } \
  109. } \
  110. } \
  111. i; /* return value of Macro */ \
  112. })
  113. int main(void) {
  114. /*
  115. Quick Summary of the jobs main has to do:
  116. - Initialize Cube
  117. - Regularly check the buttonstate
  118. - Check for incoming serial transmission and run serialHandler
  119. - Check if animations are stored
  120. --> If yes, display them
  121. --> If no, display our idle animations
  122. */
  123. uint8_t i;
  124. uint8_t imageIndex = 0, imageCount = 0;
  125. uint8_t idleIndex = 0, idleCount = 0;
  126. uint8_t lastButtonCheck;
  127. // uint8_t fpsWasSent = 0;
  128. // uint32_t temp;
  129. uint8_t *imageData = NULL, *audioData = NULL;
  130. uint8_t duration = 0;
  131. // Initialization:
  132. MCUCSR = 0; // Reset Watchdog
  133. wdt_disable();
  134. init(); // Initialize all subsystems, set port directions, enable interrupts
  135. wdt_enable(WDTO_1S); // Watchdog reset after 1 second
  136. i = selfTest(); // Run selftest, print errors
  137. // Disable subsystems if they are unavailable
  138. if (ISERROR(i, AUDIOERROR))
  139. disableAudioData = 1;
  140. if (ISERROR(i, MEMORYERROR) || ISERROR(i, MEMORYWRITEERROR))
  141. disableMemory = 1;
  142. serialWriteString(getString(0)); // Print Version
  143. audioModeSelected(); // Initial button state check
  144. lastButtonCheck = getSystemTime(); // Time we checked
  145. if (disableMemory == 0)
  146. imageCount = getAnimationCount(); // Retrieve image count from memory
  147. idleCount = numOfAnimations();
  148. if (disableAudioData == 0)
  149. maxButtonState = numberOfVisualizations() + 1; // Number of toggle steps for button
  150. while(1) { // Our Mainloop
  151. if (!shouldRestart) { // A flag to trigger a watchdog reset
  152. wdt_reset();
  153. }
  154. if (refreshAnimationCount) {
  155. refreshAnimationCount = 0;
  156. if (disableMemory == 0)
  157. imageCount = getAnimationCount();
  158. }
  159. if (serialHasChar()) { // Run serialHandler
  160. serialHandler((char)(serialGet()));
  161. }
  162. //if ((getSystemTime() - lastButtonCheck) >= 150) { // Check button state every 150ms
  163. audioModeSelected();
  164. // lastButtonCheck = getSystemTime();
  165. //}
  166. if (lastButtonState == 0) {
  167. // Display animations, stored or built-in
  168. if (disableAnim == 0) {
  169. if ((imageCount > 0) && (disableMemory == 0)) {
  170. // Memory frames
  171. if (isFinished() > duration) {
  172. // Last frame was displayed long enough
  173. imageIndex = (imageIndex < (imageCount - 1)) ? (imageIndex + 1) : 0;
  174. imageData = getFrame(imageIndex);
  175. if (imageData == NULL) {
  176. duration = 24;
  177. setImage(defaultImageCube);
  178. } else {
  179. duration = imageData[64];
  180. setImage(imageData);
  181. free(imageData);
  182. }
  183. }
  184. } else {
  185. // Built-In Anims
  186. if (isFinished() > duration) {
  187. idleIndex = (idleIndex < (idleCount - 1)) ? (idleIndex + 1) : 0;
  188. duration = executeAnimation(idleIndex);
  189. }
  190. }
  191. }
  192. } else {
  193. // An audiomode is selected
  194. if (disableAudioData == 0) {
  195. if (isFinished()) {
  196. audioData = getAudioData();
  197. if (audioData != NULL) {
  198. runVisualization(audioData, (lastButtonState - 1));
  199. } else {
  200. lastButtonState = 0;
  201. duration = 24;
  202. setImage(defaultImageCube); // Quasi Error Screen
  203. }
  204. }
  205. } else {
  206. lastButtonState = 0;
  207. }
  208. }
  209. // Print fps after one second
  210. /* if ((getSystemTime() >= 1000) && (fpsWasSent == 0)) {
  211. temp = getTriggerCount();
  212. serialWriteString(ltoa(temp, buffer, 10));
  213. serialWriteString(getString(27));
  214. serialWriteString(ltoa((temp / 8), buffer, 10));
  215. serialWriteString(getString(28));
  216. fpsWasSent = 1;
  217. } */
  218. }
  219. close(); // This is of course unneccessary. We never reach this point.
  220. return 0;
  221. }
  222. void init(void) {
  223. DDRA = 0xFF; // Latch Data Bus as Output
  224. DDRD = 0xFC; DDRB = 24; // Mosfets as Output
  225. DDRC = 0xFC; DDRB |= 6; // Latch Enable as Output
  226. DDRB &= ~(1 << PB0); // Pushbutton as Input
  227. initCube();
  228. serialInit(25, 8, NONE, 1);
  229. i2c_init();
  230. initSystemTimer();
  231. sei(); // Enable Interrupts
  232. setImage(defaultImageCube); // Display something
  233. }
  234. uint8_t audioModeSelected(void) {
  235. // Pushbutton: PB0, Low active
  236. if (debounce(PINB, PB0)) {
  237. // Button pushed
  238. if (lastButtonState < (maxButtonState - 1)) {
  239. lastButtonState++;
  240. } else {
  241. lastButtonState = 0;
  242. }
  243. }
  244. return lastButtonState;
  245. }
  246. uint8_t selfTest(void) {
  247. uint8_t result = NOERROR;
  248. uint8_t *data = getAudioData();
  249. if (data == NULL) {
  250. result |= AUDIOERROR;
  251. } else {
  252. }
  253. data = memGetBytes(0, 1);
  254. if (data == NULL) {
  255. result |= MEMORYERROR;
  256. } else {
  257. free(data);
  258. }
  259. setGeneralPurposeByte(0, 0x23);
  260. if (getGeneralPurposeByte(0) != 0x23) {
  261. result |= MEMORYWRITEERROR;
  262. }
  263. if (result) { // Error in Selftest
  264. serialWriteString(getString(1));
  265. serialWriteString(itoa(result, buffer, 2));
  266. serialWrite('\n');
  267. if (ISERROR(result, AUDIOERROR)) {
  268. serialWriteString(getString(3));
  269. }
  270. if (ISERROR(result, MEMORYERROR)) {
  271. serialWriteString(getString(4));
  272. }
  273. if (ISERROR(result, MEMORYWRITEERROR)) {
  274. serialWriteString(getString(5));
  275. }
  276. }
  277. return result;
  278. }
  279. void randomAnimation(void) {
  280. uint8_t *b = (uint8_t *)malloc(64);
  281. uint8_t x, y, z;
  282. if (b == NULL) {
  283. serialWriteString(getString(24));
  284. return;
  285. }
  286. for (x = 0; x < 64; x++) {
  287. b[x] = 0;
  288. }
  289. while(1) {
  290. wdt_reset();
  291. setImage(b);
  292. while(isFinished() == 0);
  293. x = rand() / 4096;
  294. y = rand() / 4096;
  295. z = rand() / 4096;
  296. b[x + (8 * y)] ^= (1 << z);
  297. if (serialHasChar()) {
  298. serialWriteString(getString(25));
  299. free(b);
  300. serialGet();
  301. return;
  302. }
  303. }
  304. free(b);
  305. }
  306. void serialHandler(char c) {
  307. // Used letters:
  308. // a, b, c, d, e, f, g, h, i, n, q, r, s, t, u, v, x, y, 0, 1, 2, 3, #
  309. uint8_t i, y, z;
  310. uint8_t *tmp;
  311. switch(c) {
  312. case OK:
  313. serialWrite(OK);
  314. break;
  315. case 'h': case 'H': case '?':
  316. serialWriteString(getString(6));
  317. serialWriteString(getString(7));
  318. serialWriteString(getString(8));
  319. serialWriteString(getString(9));
  320. serialWriteString(getString(10));
  321. serialWriteString(getString(26));
  322. serialWriteString(getString(34));
  323. serialWriteString(getString(11));
  324. serialWriteString(getString(12));
  325. serialWriteString(getString(13));
  326. break;
  327. case 'd': case 'D':
  328. setAnimationCount(0);
  329. serialWrite(OK);
  330. refreshAnimationCount = 1;
  331. break;
  332. case 'f': case 'F':
  333. serialWriteString(getString(32));
  334. clearMem();
  335. serialWriteString(getString(33));
  336. refreshAnimationCount = 1;
  337. break;
  338. case 'g': case 'G':
  339. transmitAnimations();
  340. break;
  341. case 's': case 'S':
  342. recieveAnimations();
  343. refreshAnimationCount = 1;
  344. break;
  345. case 'v': case 'V':
  346. serialWriteString(getString(0));
  347. break;
  348. case 'm': case 'M':
  349. if (lastButtonState < (maxButtonState - 1)) {
  350. lastButtonState++;
  351. } else {
  352. lastButtonState = 0;
  353. }
  354. if (lastButtonState) {
  355. serialWriteString(getString(41));
  356. } else {
  357. serialWriteString(getString(40));
  358. }
  359. break;
  360. case 'q': case 'Q':
  361. shouldRestart = 1;
  362. serialWriteString(getString(30));
  363. break;
  364. case 'r': case 'R':
  365. randomAnimation();
  366. break;
  367. case 't': case 'T':
  368. printTime();
  369. break;
  370. case 'a': case 'A':
  371. sendAudioData();
  372. break;
  373. case 'c': case 'C':
  374. serialWriteString(itoa(getAnimationCount(), buffer, 10));
  375. serialWriteString(" (");
  376. serialWriteString(itoa(refreshAnimationCount, buffer, 10));
  377. serialWriteString(")");
  378. serialWriteString(getString(15));
  379. break;
  380. case 'u': case 'U':
  381. serialWriteString(getString(31));
  382. while(!serialHasChar()) {
  383. wdt_reset();
  384. }
  385. i = serialGet() - '0';
  386. serialWrite(i + '0');
  387. serialWrite('\n');
  388. tmp = getFrame(i);
  389. dumpFrame(tmp);
  390. free(tmp);
  391. break;
  392. case 'x': case 'X':
  393. // Get byte, store as animation count
  394. serialWriteString(getString(16));
  395. while (!serialHasChar());
  396. c = serialGet();
  397. setAnimationCount(c);
  398. serialWriteString(itoa(c, buffer, 10));
  399. serialWriteString(getString(17));
  400. break;
  401. case 'y': case 'Y':
  402. setAnimationCount(0x2201);
  403. serialWriteString(getString(18));
  404. break;
  405. case 'e': case 'E':
  406. selfTest();
  407. break;
  408. case 'n': case 'N':
  409. // snake();
  410. break;
  411. case '0':
  412. fillBuffer(0);
  413. disableAnim = 1;
  414. break;
  415. case '1':
  416. fillBuffer(0xFF);
  417. disableAnim = 1;
  418. break;
  419. case '3':
  420. setImage(defaultImageCube);
  421. disableAnim = 1;
  422. break;
  423. case '2':
  424. fillBuffer(0);
  425. while(1) {
  426. for (i = 0; i < 8; i++) {
  427. for (y = 0; y < 8; y++) {
  428. defaultImageCube[y + (i * 8)] = 0;
  429. for (z = 0; z < 8; z++) {
  430. defaultImageCube[y + (i * 8)] |= (1 << z);
  431. setImage(defaultImageCube);
  432. while (isFinished() == 0) {
  433. wdt_reset();
  434. if (serialHasChar()) {
  435. goto killMeForIt; // Yes I know...
  436. // But I need to break out of 2 while Loops...
  437. }
  438. }
  439. }
  440. // defaultImageCube[y + (i * 8)] = 0;
  441. }
  442. }
  443. }
  444. break;
  445. killMeForIt:
  446. serialGet(); // Killed because we got a serial char. Remove it from buffer.
  447. serialWriteString(getString(25));
  448. break;
  449. case 'I': case 'i':
  450. serialWriteString(ltoa(getTriggerCount(), buffer, 10));
  451. serialWrite('\n');
  452. break;
  453. default:
  454. serialWrite(ERROR);
  455. break;
  456. }
  457. // c was used as temp var and does not contain the char anymore...!
  458. }