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 13KB

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