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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  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. // Length of an idle animation frame, 24 -> 1 second
  45. #define IDLELENGTH 48
  46. void init(void);
  47. uint8_t selfTest(void);
  48. void serialHandler(char c);
  49. uint8_t defaultImageCube[64] = { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81,
  50. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  51. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  52. 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81,
  53. 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81,
  54. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  55. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  56. 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 };
  57. #define NOERROR 0
  58. // Audio does not answer
  59. #define AUDIOERROR 1
  60. // Memory does not answer
  61. #define MEMORYERROR 2
  62. // Memory not writeable
  63. #define MEMORYWRITEERROR 4
  64. // x = errorcode, e = error definition, not NOERROR
  65. #define ISERROR(x, e) ((x) & (e))
  66. uint8_t shouldRestart = 0;
  67. uint8_t refreshAnimationCount = 0;
  68. uint8_t lastButtonState = 0;
  69. uint8_t maxButtonState = 1; // No audio, get's checked later
  70. uint8_t disableAudioData = 0;
  71. uint8_t disableMemory = 0;
  72. uint8_t disableAnim = 0;
  73. char buffer[11];
  74. /* Not so powerful Debouncing Example
  75. * No Interrupt needed
  76. * Author: Peter Dannegger
  77. */
  78. #define debounce(port, pin) ({ \
  79. static uint8_t flag = 0; /* new variable on every macro usage */ \
  80. uint8_t i = 0; \
  81. if (flag) { /* check for key release: */ \
  82. for(;;) { /* loop ... */ \
  83. if(!(port & 1 << pin)) { /* ... until key pressed or ... */ \
  84. i = 0; \
  85. break; \
  86. } \
  87. _delay_us(98); /* * 256 = 25ms */ \
  88. if(--i == 0) { /* ... until key >25ms released */ \
  89. flag = 0; /* clear press flag */ \
  90. i = 0; /* 0 = key release debounced */ \
  91. break; \
  92. } \
  93. } \
  94. } else { /* else check for key press: */ \
  95. for(;;) { /* loop ... */ \
  96. if ((port & 1<<pin)) { /* ... until key released or ... */ \
  97. i = 0; \
  98. break; \
  99. } \
  100. _delay_us( 98 ); /* * 256 = 25ms */ \
  101. if (--i == 0) { /* ... until key >25ms pressed */ \
  102. flag = 1; /* set press flag */ \
  103. i = 1; /* 1 = key press debounced */ \
  104. break; \
  105. } \
  106. } \
  107. } \
  108. i; /* return value of Macro */ \
  109. })
  110. int main(void) {
  111. /*
  112. Quick Summary of the jobs main has to do:
  113. - Initialize Cube
  114. - Regularly check the buttonstate
  115. - Check for incoming serial transmission and run serialHandler
  116. - Check if animations are stored
  117. --> If yes, display them
  118. --> If no, display our idle animations
  119. */
  120. uint8_t i;
  121. uint8_t imageIndex = 0, imageCount = 0;
  122. uint8_t idleIndex = 0, idleCount = 0;
  123. uint8_t *imageData = NULL, *audioData = NULL;
  124. uint8_t duration = 0;
  125. // Initialization:
  126. MCUCSR = 0; // Reset Watchdog
  127. wdt_disable();
  128. init(); // Initialize all subsystems, set port directions, enable interrupts
  129. wdt_enable(WDTO_1S); // Watchdog reset after 1 second
  130. i = selfTest(); // Run selftest, print errors
  131. // Disable subsystems if they are unavailable
  132. if (ISERROR(i, AUDIOERROR))
  133. disableAudioData = 1;
  134. if (ISERROR(i, MEMORYERROR) || ISERROR(i, MEMORYWRITEERROR))
  135. disableMemory = 1;
  136. serialWriteString(getString(0)); // Print Version
  137. if (disableMemory == 0)
  138. imageCount = getAnimationCount(); // Retrieve image count from memory
  139. idleCount = numOfAnimations();
  140. if (disableAudioData == 0)
  141. maxButtonState = numberOfVisualizations() + 1; // Number of toggle steps for button
  142. lastButtonState = 1;
  143. while(1) { // Our Mainloop
  144. if (!shouldRestart) { // A flag to trigger a watchdog reset
  145. wdt_reset();
  146. }
  147. if (refreshAnimationCount) {
  148. refreshAnimationCount = 0;
  149. if (disableMemory == 0)
  150. imageCount = getAnimationCount();
  151. }
  152. if (serialHasChar()) { // Run serialHandler
  153. serialHandler((char)(serialGet()));
  154. }
  155. if (debounce(PINB, PB0)) {
  156. if (lastButtonState > 0) {
  157. lastButtonState--;
  158. } else {
  159. lastButtonState = maxButtonState - 1;
  160. }
  161. }
  162. if (lastButtonState == 0) {
  163. // Display animations, stored or built-in
  164. if (disableAnim == 0) {
  165. if ((imageCount > 0) && (disableMemory == 0)) {
  166. // Memory frames
  167. if (isFinished() > duration) {
  168. // Last frame was displayed long enough
  169. imageIndex = (imageIndex < (imageCount - 1)) ? (imageIndex + 1) : 0;
  170. imageData = getFrame(imageIndex);
  171. if (imageData == NULL) {
  172. duration = 24;
  173. setImage(defaultImageCube);
  174. } else {
  175. duration = imageData[64];
  176. setImage(imageData);
  177. free(imageData);
  178. }
  179. }
  180. } else {
  181. // Built-In Anims
  182. if (isFinished() > duration) {
  183. idleIndex = (idleIndex < (idleCount - 1)) ? (idleIndex + 1) : 0;
  184. duration = executeAnimation(idleIndex);
  185. }
  186. }
  187. }
  188. } else {
  189. // An audiomode is selected
  190. if (disableAudioData == 0) {
  191. if (isFinished()) {
  192. audioData = getAudioData();
  193. if (audioData != NULL) {
  194. runVisualization(audioData, (lastButtonState - 1));
  195. } else {
  196. lastButtonState = 0;
  197. duration = 24;
  198. setImage(defaultImageCube); // Quasi Error Screen
  199. }
  200. }
  201. } else {
  202. lastButtonState = 0;
  203. }
  204. }
  205. // Print fps after one second
  206. /* if ((getSystemTime() >= 1000) && (fpsWasSent == 0)) {
  207. temp = getTriggerCount();
  208. serialWriteString(ltoa(temp, buffer, 10));
  209. serialWriteString(getString(27));
  210. serialWriteString(ltoa((temp / 8), buffer, 10));
  211. serialWriteString(getString(28));
  212. fpsWasSent = 1;
  213. } */
  214. }
  215. close(); // This is of course unneccessary. We never reach this point.
  216. return 0;
  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, p, q, r, s, t, u, v, 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': case '?':
  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':
  331. serialWriteString(getString(0));
  332. break;
  333. case 'm': case 'M':
  334. if (lastButtonState > 0) {
  335. lastButtonState--;
  336. } else {
  337. lastButtonState = maxButtonState - 1;
  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 'x': case 'X':
  386. // Get byte, store as animation count
  387. serialWriteString(getString(16)); // "New animation count: "
  388. setAnimationCount(readNumber(10));
  389. refreshAnimationCount = 1;
  390. break;
  391. case 'p': case 'P':
  392. simpleAnimationInput();
  393. break;
  394. case 'y': case 'Y':
  395. serialWriteString(getString(18)); // "Frame to change: "
  396. i = readNumber(10);
  397. tmp = readAFrame();
  398. setFrame(i, tmp);
  399. free(tmp);
  400. break;
  401. case 'e': case 'E':
  402. selfTest();
  403. break;
  404. case 'n': case 'N':
  405. // snake();
  406. break;
  407. case '0':
  408. fillBuffer(0);
  409. disableAnim = 1;
  410. break;
  411. case '1':
  412. fillBuffer(0xFF);
  413. disableAnim = 1;
  414. break;
  415. case '3':
  416. setImage(defaultImageCube);
  417. disableAnim = 1;
  418. break;
  419. case '2':
  420. fillBuffer(0);
  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 'I': case 'i':
  446. serialWriteString(ltoa(getTriggerCount(), buffer, 10));
  447. serialWrite('\n');
  448. break;
  449. default:
  450. serialWrite(ERROR);
  451. break;
  452. }
  453. // c was used as temp var and does not contain the char anymore...!
  454. }