selftest.ino 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. #include <EEPROM.h>
  2. #include <SPI.h>
  3. #include <GD2.h>
  4. #define GD3 ft8xx_model
  5. #define INIT_DATA GD3_43__init
  6. // #define INIT_DATA GD3_7__init
  7. // #define INIT_DATA GD3_VGA__init
  8. #define UART_SPEED 115200
  9. #include "selftest_assets.h"
  10. #define SCREEN_ADDR 0x30000UL
  11. byte x, y;
  12. static void log(const char*s)
  13. {
  14. while (*s) {
  15. char c = *s++;
  16. #ifndef RASPBERRY_PI
  17. Serial.write(c);
  18. #endif
  19. if (c == '\n') {
  20. x = 0;
  21. y++;
  22. } else {
  23. uint32_t dst = SCREEN_ADDR + (((x + (y * 48)) << 1));
  24. GD.wr16(dst, 0x0f00 | c);
  25. x++;
  26. }
  27. };
  28. }
  29. void setup()
  30. {
  31. Serial.begin(UART_SPEED);
  32. Serial.println("---- GAMEDUINO 2/3 SELFTEST ----");
  33. }
  34. static void ramp(int y, uint32_t color)
  35. {
  36. GD.ScissorSize(400, 8);
  37. GD.ScissorXY(40, y);
  38. GD.cmd_gradient(40, 0, 0x000000, 440, 0, color);
  39. }
  40. void testcard(int pass, const char *message)
  41. {
  42. // GD.ClearColorRGB(0x204060);
  43. GD.get_inputs();
  44. GD.Clear();
  45. GD.cmd_text(GD.w / 2, 12, 28, OPT_CENTER,
  46. GD3 ? "Gameduino3 Self test" :
  47. "Gameduino2 Self test");
  48. GD.cmd_text(GD.w - 2, 12, 27, OPT_CENTERY | OPT_RIGHTX,
  49. GD2_VERSION);
  50. int y;
  51. y = PIXELS(50);
  52. GD.Begin(POINTS);
  53. for (int i = 0; i < 6; i++) {
  54. byte l = 4 << i;
  55. int x = map(1 + i, 0, 7, 0, PIXELS(GD.w));
  56. GD.PointSize(280);
  57. GD.ColorRGB(0xffffff);
  58. GD.Vertex2f(x, y);
  59. GD.PointSize(240);
  60. GD.ColorRGB(l, l, l);
  61. GD.Vertex2f(x, y);
  62. }
  63. y += 30;
  64. ramp(y, 0xff0000); y += 12;
  65. ramp(y, 0x00ff00); y += 12;
  66. ramp(y, 0x0000ff); y += 12;
  67. ramp(y, 0xffffff); y += 12;
  68. GD.RestoreContext();
  69. // GD.Begin(BITMAPS);
  70. // GD.Vertex2ii(0, 272 - (8 * 16), 1, 0);
  71. // GD.Vertex2ii(480 - LENA_WIDTH, 272 - LENA_WIDTH, 0, 0);
  72. if (pass == -1)
  73. GD.ColorRGB(0x808000);
  74. else
  75. GD.ColorRGB(pass ? 0x40ff40 : 0xff4040);
  76. GD.cmd_text(GD.w / 2, 180, 31, OPT_CENTER, message);
  77. GD.ColorRGB(0xffffff);
  78. GD.Begin(LINES);
  79. GD.Vertex2f(PIXELS(GD.inputs.x), PIXELS(0));
  80. GD.Vertex2f(PIXELS(GD.inputs.x), PIXELS(GD.h));
  81. GD.Vertex2f(PIXELS(0), PIXELS(GD.inputs.y));
  82. GD.Vertex2f(PIXELS(GD.w), PIXELS(GD.inputs.y));
  83. GD.swap();
  84. GD.finish();
  85. }
  86. #define SCREENTEST(NAME) \
  87. do { \
  88. Serial.println(#NAME); \
  89. testcard(-1, #NAME); \
  90. r = test_##NAME(); \
  91. const char* msg = r ? (#NAME ": pass") : (#NAME ": FAIL"); \
  92. Serial.println(msg); \
  93. testcard(r, msg); \
  94. while (!r) ; \
  95. } while (0)
  96. int test_ident()
  97. {
  98. byte id = GD.rd(REG_ID);
  99. if (id != 0x7c) {
  100. Serial.println(id, HEX);
  101. return 0;
  102. }
  103. return 1;
  104. }
  105. int test_clock()
  106. {
  107. int SPEEDUP = 8;
  108. GD.rd32(REG_CLOCK); // warm-up
  109. delay(10);
  110. long t1 = GD.rd32(REG_CLOCK);
  111. delay(1000 / SPEEDUP);
  112. long t2 = GD.rd32(REG_CLOCK);
  113. float measured = float(t2 - t1);
  114. // measured should be 48e6, within 2%
  115. float expected = (GD3 ? 60e6 : 48e6) / SPEEDUP;
  116. Serial.println(measured, DEC);
  117. Serial.println(expected, DEC);
  118. float diff = measured - expected;
  119. float percent = fabs(100 * (diff / expected));
  120. return percent < 5.0;
  121. }
  122. int test_tune()
  123. {
  124. GD.tune();
  125. return 1;
  126. }
  127. static byte test_RAM(void)
  128. {
  129. uint32_t a;
  130. for (a = 0; a < 0x40000U; a += 947)
  131. GD.wr(a, a);
  132. for (a = 0; a < 0x40000U; a += 947)
  133. if (GD.rd(a) != (a & 0xff))
  134. return 0;
  135. return 1;
  136. }
  137. static byte test_PWM(void)
  138. {
  139. for (int i = 128; i >= 0; i--) {
  140. GD.wr(REG_PWM_DUTY, i);
  141. delay(2);
  142. }
  143. GD.wr(REG_PWM_DUTY, 128);
  144. return 1;
  145. }
  146. static byte test_storage(void)
  147. {
  148. GD.storage();
  149. return test_ident();
  150. }
  151. static byte test_SDcard(void)
  152. {
  153. for (byte i = 0; i < 2; i++) {
  154. GD.safeload("selftest.gd2");
  155. uint32_t pcrc = GD.cmd_memcrc(0, ASSETS_END);
  156. GD.finish();
  157. uint32_t crc = GD.rd32(pcrc);
  158. if (crc != KITTEN_CRC)
  159. return 0;
  160. }
  161. return 1;
  162. }
  163. static void collect(int &rx, int &ry, int &rz)
  164. {
  165. uint16_t ax = 0, ay = 0, az = 0;
  166. for (byte i = 32; i; i--) {
  167. int x = 0, y = 0, z = 0;
  168. #ifdef A2
  169. x = analogRead(A2);
  170. #endif
  171. #ifdef A1
  172. y = analogRead(A1);
  173. #endif
  174. #ifdef A0
  175. z = analogRead(A0);
  176. #endif
  177. ax += x;
  178. ay += y;
  179. az += z;
  180. }
  181. rx = ax >> 5;
  182. ry = ay >> 5;
  183. rz = az >> 5;
  184. }
  185. static byte test_accel2(void)
  186. {
  187. while (1) {
  188. GD.finish();
  189. if ((millis() % 2000) < 1000)
  190. GD.wr(REG_GPIO, 0x80);
  191. else
  192. GD.wr(REG_GPIO, 0x81);
  193. int x, y, z;
  194. collect(x, y, z);
  195. GD.Clear();
  196. GD.cmd_number(0, 40, 26, 3, x);
  197. GD.cmd_slider(50, 40, 400, 10, 0, x, 512);
  198. GD.cmd_number(0, 70, 26, 3, y);
  199. GD.cmd_slider(50, 70, 400, 10, 0, y, 512);
  200. GD.cmd_number(0, 100, 26, 3, GD.rd(REG_GPIO));
  201. GD.cmd_slider(50, 100, 400, 10, 0, z, 512);
  202. GD.swap();
  203. }
  204. return 1;
  205. }
  206. static byte test_accel(void)
  207. {
  208. int x0, y0, z0;
  209. int x1, y1, z1;
  210. GD.wr(REG_GPIO, 0x80);
  211. collect(x0, y0, z0);
  212. delay(100);
  213. GD.wr(REG_GPIO, 0x81);
  214. delay(100);
  215. collect(x1, y1, z1);
  216. Serial.print(x0); Serial.print(" "); Serial.print(y0); Serial.print(" "); Serial.println(z0);
  217. Serial.print(x1); Serial.print(" "); Serial.print(y1); Serial.print(" "); Serial.println(z1);
  218. // if ((x0 > x1) || (y0 > y1) || (z0 > z1)) return 0;
  219. int d;
  220. d = abs(x0 - x1);
  221. if ((d < 30) || (120 < d))
  222. return 0;
  223. d = abs(y0 - y1);
  224. if ((d < 30) || (120 < d))
  225. return 0;
  226. d = abs(z0 - z1);
  227. if ((d < 50) || (200 < d))
  228. return 0;
  229. z0 %= 37;
  230. while (z0--)
  231. GD.random();
  232. return 1;
  233. }
  234. static void play(uint16_t n)
  235. {
  236. GD.wr16(REG_SOUND, n);
  237. GD.wr(REG_PLAY, 1);
  238. }
  239. static void play_wait(uint16_t n)
  240. {
  241. play(n);
  242. while (GD.rd(REG_PLAY))
  243. ;
  244. }
  245. static byte test_touch(void)
  246. {
  247. if (!GD3) {
  248. GD.self_calibrate();
  249. // write the new calibration back to EEPROM
  250. #if !defined(RASPBERRY_PI) && !defined(__DUE__)
  251. for (int i = 0; i < 24; i++)
  252. EEPROM.write(1 + i, GD.rd(REG_TOUCH_TRANSFORM_A + i));
  253. #endif
  254. }
  255. byte hit = 0;
  256. while (hit != 0x0f) {
  257. GD.finish();
  258. byte tag = GD.rd(REG_TOUCH_TAG);
  259. if ((1 <= tag) && (tag <= 4)) {
  260. play(0x50);
  261. hit |= (1 << (tag - 1));
  262. }
  263. if (tag == 77)
  264. return 0;
  265. GD.ClearTag(77);
  266. GD.Clear();
  267. GD.PointSize(20 * 16);
  268. GD.Begin(POINTS);
  269. for (byte i = 1; i <= 4; i++) {
  270. if (hit & (1 << (i - 1))) {
  271. GD.ColorRGB(0x00ff00);
  272. GD.Tag(0xff);
  273. } else {
  274. GD.ColorRGB(0x808080);
  275. GD.Tag(i);
  276. }
  277. switch (i) {
  278. case 1: GD.Vertex2ii(20, 20, 0, 0); break;
  279. case 2: GD.Vertex2ii(460, 20, 0, 0); break;
  280. case 3: GD.Vertex2ii(20, 250, 0, 0); break;
  281. case 4: GD.Vertex2ii(460, 250, 0, 0); break;
  282. }
  283. }
  284. GD.random(); // scramble PRN state for later
  285. GD.swap();
  286. }
  287. return 1;
  288. }
  289. static const PROGMEM uint32_t digits[11] = {
  290. DIGIT_0,
  291. DIGIT_1,
  292. DIGIT_2,
  293. DIGIT_3,
  294. DIGIT_4,
  295. DIGIT_5,
  296. DIGIT_6,
  297. DIGIT_7,
  298. DIGIT_8,
  299. DIGIT_9,
  300. DIGIT_9 + DIGIT_9_LENGTH
  301. };
  302. static void saydigit(byte n)
  303. {
  304. GD.wr32(REG_PLAYBACK_FREQ, 8000);
  305. GD.wr32(REG_PLAYBACK_FORMAT, ADPCM_SAMPLES);
  306. uint32_t dstart = pgm_read_dword(digits + n);
  307. uint32_t dend = pgm_read_dword(digits + n + 1);
  308. GD.wr32(REG_PLAYBACK_START, dstart);
  309. GD.wr32(REG_PLAYBACK_LENGTH, dend - dstart);
  310. GD.wr(REG_PLAYBACK_PLAY, 1);
  311. }
  312. static void blank(int n)
  313. {
  314. for (int i = 0; i < n; i++) {
  315. GD.get_inputs();
  316. GD.cmd_gradient(0, 0, 0xb0b0a0, 0, 272, 0x404040);
  317. GD.swap();
  318. }
  319. }
  320. static byte getkey()
  321. {
  322. byte prev_tag;
  323. do {
  324. prev_tag = GD.inputs.tag;
  325. GD.get_inputs();
  326. if (GD.inputs.x & 1)
  327. GD.random();
  328. GD.cmd_gradient(0, 0, 0xb0b0a0, 0, 272, 0x404040);
  329. for (int i = 0; i < 9; i++) {
  330. byte digit = i + 1;
  331. int x = 120 + 80 * (i % 3);
  332. int y = 20 + 80 * (i / 3);
  333. GD.Tag(digit);
  334. char msg[2] = { '0' + digit, 0 };
  335. GD.cmd_fgcolor((digit == GD.inputs.tag) ? 0xc08000 : 0x003870);
  336. GD.cmd_button(x, y, 70, 70, 31, 0, msg);
  337. }
  338. GD.swap();
  339. } while (!((GD.inputs.tag == 0) && (1 <= prev_tag) && (prev_tag <= 9)));
  340. return prev_tag;
  341. }
  342. static byte test_audio(void)
  343. {
  344. // Stir up the PRN
  345. for (int i = micros() % 97; i; i--)
  346. GD.random();
  347. blank(20);
  348. for (int i = 0; i < 3; i++) {
  349. byte d = 1 + GD.random(9);
  350. saydigit(d);
  351. blank(12);
  352. if (getkey() != d)
  353. return 0;
  354. }
  355. return 1;
  356. }
  357. static struct {
  358. byte t, note;
  359. } pacman[] = {
  360. { 0, 71 },
  361. { 2, 83 },
  362. { 4, 78 },
  363. { 6, 75 },
  364. { 8, 83 },
  365. { 9, 78 },
  366. { 12, 75 },
  367. { 16, 72 },
  368. { 18, 84 },
  369. { 20, 79 },
  370. { 22, 76 },
  371. { 24, 84 },
  372. { 25, 79 },
  373. { 28, 76 },
  374. { 32, 71 },
  375. { 34, 83 },
  376. { 36, 78 },
  377. { 38, 75 },
  378. { 40, 83 },
  379. { 41, 78 },
  380. { 44, 75 },
  381. { 48, 75 },
  382. { 49, 76 },
  383. { 50, 77 },
  384. { 52, 77 },
  385. { 53, 78 },
  386. { 54, 79 },
  387. { 56, 79 },
  388. { 57, 80 },
  389. { 58, 81 },
  390. { 60, 83 },
  391. { 255, 255 }
  392. };
  393. static const uint8_t GD3_43__init[128] = {
  394. 255, 255, 1, 1, 26, 255, 255, 255, 12, 32, 48, 0, 4, 0, 0, 0, 0, 135,
  395. 147, 3, 26, 255, 255, 255, 80, 33, 48, 0, 24, 0, 0, 0, 46, 46, 46, 46,
  396. 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
  397. 46, 46, 46, 34, 255, 255, 255, 88, 32, 48, 0, 120, 156, 99, 100, 96,
  398. 96, 216, 198, 200, 192, 0, 68, 12, 204, 12, 16, 26, 132, 217, 128, 24,
  399. 0, 17, 207, 0, 197, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255,
  400. 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0,
  401. 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255
  402. };
  403. static const uint8_t GD3_7__init[128] = {
  404. 255, 255, 1, 1, 26, 255, 255, 255, 12, 32, 48, 0, 4, 0, 0, 0, 0, 39,
  405. 134, 3, 26, 255, 255, 255, 80, 33, 48, 0, 24, 0, 0, 0, 46, 46, 46, 46,
  406. 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
  407. 46, 46, 46, 34, 255, 255, 255, 44, 32, 48, 0, 120, 156, 59, 201, 204,
  408. 192, 16, 193, 192, 192, 160, 0, 164, 65, 192, 0, 136, 89, 152, 128,
  409. 124, 32, 253, 128, 17, 34, 6, 149, 98, 0, 113, 183, 49, 66, 104, 100,
  410. 49, 160, 114, 6, 0, 164, 38, 3, 65, 0, 0, 0, 0, 255, 255, 255, 0, 255,
  411. 255, 255, 0, 255, 255, 255, 0, 255, 255, 255
  412. };
  413. static const uint8_t GD3_VGA__init[128] = {
  414. 255, 255, 1, 2, 26, 255, 255, 255, 12, 32, 48, 0, 4, 0, 0, 0, 64, 210,
  415. 223, 3, 26, 255, 255, 255, 148, 32, 48, 0, 4, 0, 0, 0, 16, 0, 0, 0, 7,
  416. 0, 0, 38, 0, 0, 0, 0, 1, 255, 255, 255, 0, 255, 255, 255, 34, 255,
  417. 255, 255, 44, 32, 48, 0, 120, 156, 115, 96, 101, 96, 208, 96, 100, 96,
  418. 96, 96, 97, 0, 131, 14, 32, 86, 99, 102, 96, 80, 6, 113, 152, 33, 98,
  419. 108, 12, 8, 160, 2, 84, 203, 200, 128, 10, 64, 124, 0, 81, 19, 1, 119,
  420. 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255,
  421. 255, 0, 255, 255, 255, 0, 255, 255, 255
  422. };
  423. #define FREQUENCY_OFFSET 16
  424. #define CALIBRATION_OFFSET 32
  425. uint8_t gpio, gpio_dir;
  426. void set_SDA(byte n)
  427. {
  428. GD.wr(REG_GPIO_DIR, gpio_dir | (0x03 - n)); // Drive SCL, SDA low
  429. }
  430. void set_SCL(byte n)
  431. {
  432. GD.wr(REG_GPIO, gpio | (n << 1));
  433. }
  434. int get_SDA(void)
  435. {
  436. return GD.rd(REG_GPIO) & 1;
  437. }
  438. void i2c_start(void)
  439. {
  440. set_SDA(1);
  441. set_SCL(1);
  442. set_SDA(0);
  443. set_SCL(0);
  444. }
  445. void i2c_stop(void)
  446. {
  447. set_SDA(0);
  448. set_SCL(1);
  449. set_SDA(1);
  450. set_SCL(1);
  451. }
  452. int i2c_rx1()
  453. {
  454. set_SDA(1);
  455. set_SCL(1);
  456. byte r = get_SDA();
  457. set_SCL(0);
  458. return r;
  459. }
  460. void i2c_tx1(byte b)
  461. {
  462. set_SDA(b);
  463. set_SCL(1);
  464. set_SCL(0);
  465. }
  466. int i2c_tx(byte x)
  467. {
  468. for (int i = 7; i >= 0; i--)
  469. i2c_tx1(1 & (x >> i));
  470. return i2c_rx1();
  471. }
  472. int i2c_rx(int nak)
  473. {
  474. byte r = 0;
  475. for (byte i = 0; i < 8; i++)
  476. r = (r << 1) | i2c_rx1();
  477. i2c_tx1(nak);
  478. return r;
  479. }
  480. void i2c_begin(void)
  481. {
  482. gpio = GD.rd(REG_GPIO) & ~3;
  483. gpio_dir = GD.rd(REG_GPIO_DIR) & ~3;
  484. // 2-wire software reset
  485. i2c_start();
  486. i2c_rx(1);
  487. i2c_start();
  488. i2c_stop();
  489. }
  490. #define ADDR 0xa0
  491. void ram_write(const uint8_t *v)
  492. {
  493. for (byte i = 0; i < 128; i += 8) {
  494. i2c_start();
  495. i2c_tx(ADDR);
  496. i2c_tx(i);
  497. for (byte j = 0; j < 8; j++)
  498. i2c_tx(*v++);
  499. i2c_stop();
  500. delay(6);
  501. }
  502. }
  503. byte ram_read(byte a)
  504. {
  505. i2c_start();
  506. i2c_tx(ADDR);
  507. i2c_tx(a);
  508. i2c_start();
  509. i2c_tx(ADDR | 1);
  510. byte r = i2c_rx(1);
  511. i2c_stop();
  512. return r;
  513. }
  514. void ramdump(void)
  515. {
  516. for (int i = 0; i < 128; i++) {
  517. byte v = ram_read(i);
  518. Serial.print(i, HEX);
  519. Serial.print(" ");
  520. Serial.println(v, HEX);
  521. }
  522. }
  523. void ram_get(byte *v)
  524. {
  525. i2c_start();
  526. i2c_tx(ADDR);
  527. i2c_tx(0);
  528. i2c_start();
  529. i2c_tx(ADDR | 1);
  530. for (int i = 0; i < 128; i++) {
  531. *v++ = i2c_rx(i == 127);
  532. // Serial.println(v[-1], DEC);
  533. }
  534. i2c_stop();
  535. }
  536. static void load_flash(uint8_t *config)
  537. {
  538. byte b[128];
  539. i2c_begin();
  540. ram_write(config);
  541. ram_get(b);
  542. int diff = memcmp(config, b, 128);
  543. if (diff != 0) {
  544. Serial.println("Flash fault");
  545. GD.Clear();
  546. GD.cmd_text(GD.w / 2, GD.h / 2, 30, OPT_CENTERX, "Flash fault");
  547. GD.swap();
  548. for (;;);
  549. }
  550. Serial.println("Flash verified OK");
  551. GD.begin(0);
  552. }
  553. static void setup_flash()
  554. {
  555. GD.begin(0);
  556. if (GD3) {
  557. uint8_t stage[128];
  558. memcpy(stage, INIT_DATA, 128);
  559. load_flash(stage);
  560. GD.self_calibrate();
  561. GD.finish();
  562. for (int i = 0; i < 24; i++)
  563. stage[CALIBRATION_OFFSET + i] = GD.rd(REG_TOUCH_TRANSFORM_A + i);
  564. load_flash(stage);
  565. }
  566. }
  567. void loop()
  568. {
  569. if (EEPROM.read(0) == 0x7c)
  570. EEPROM.write(0, 0xff);
  571. setup_flash();
  572. GD.begin(0);
  573. x = y = 0;
  574. testcard(1, "Starting tests");
  575. GD.finish();
  576. Serial.println("Starting self-test");
  577. byte r, pass = 1;
  578. {
  579. SCREENTEST(ident);
  580. if (!GD3)
  581. SCREENTEST(tune);
  582. SCREENTEST(clock);
  583. SCREENTEST(RAM);
  584. SCREENTEST(PWM);
  585. SCREENTEST(storage);
  586. SCREENTEST(SDcard);
  587. if (0)
  588. SCREENTEST(accel);
  589. if (1) {
  590. SCREENTEST(touch);
  591. SCREENTEST(audio);
  592. }
  593. {
  594. int i = 0, t = 0;
  595. for (;;) {
  596. testcard(1, "* ALL PASS *");
  597. if (t == 4 * pacman[i].t)
  598. GD.play(HARP, pacman[i++].note - 12);
  599. if (++t == 256) {
  600. t = 0;
  601. i = 0;
  602. }
  603. }
  604. }
  605. }
  606. if (pass) {
  607. char msg[60];
  608. log("All tests passed\n");
  609. long seconds = millis() / 1000;
  610. int minutes = seconds / 60;
  611. sprintf(msg, "%d minutes", minutes);
  612. log(msg);
  613. } else {
  614. for (;;)
  615. ;
  616. }
  617. delay(5000);
  618. }