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

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