turn_machine_app.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. #include "misc.h" //just for ACCEL_STATIC_ASSERT
  2. #include "accel_cores.h"
  3. #include "graphics.h"
  4. #include "fat_io_lib/src/fat_filelib.h"
  5. //info timings
  6. #define TURN_ATTENTION_TIME 3
  7. #define TURN_FIRST_DISPLAY_TIME 15
  8. #define TURN_RECALL_TIME 9
  9. #define TURN_UPDATE_DISPLAY_TIME 5
  10. #define INFO_MAX_TIME 30
  11. //digit coordinates
  12. #define BOX_X 450
  13. #define TURN_X 175
  14. #define DIGITS_SEP 95
  15. #define DIGITS_Y 138
  16. #define MOVIE_FPS 30
  17. static uint64_t highres_ticks(void)
  18. {
  19. timer0_uptime_latch_write(1);
  20. return timer0_uptime_cycles_read(); //makes increasing
  21. }
  22. static uint64_t highres_ticks_freq(void) { return CONFIG_CLOCK_FREQUENCY; }
  23. typedef union
  24. {
  25. uint32_t rgba;
  26. struct { uint32_t r:8; uint32_t g:8; uint32_t b:8; uint32_t a:8; };
  27. } pix_t;
  28. //TODO: use uncached regions of memory whenever possible
  29. void flush_cache_region(void *buf, size_t size)
  30. {
  31. flush_cpu_dcache();
  32. flush_l2_cache();
  33. }
  34. uint8_t *const video_buf = (uint8_t *) VIDEO_FRAMEBUFFER_BASE;
  35. const unsigned stride = VIDEO_FRAMEBUFFER_HRES*(VIDEO_FRAMEBUFFER_DEPTH/8);
  36. void wait_vsync(int count)
  37. {
  38. flush_cache_region(video_buf, VIDEO_FRAMEBUFFER_VRES*stride); //only needed for software renderers
  39. uint32_t video_dma;
  40. while(count--)
  41. {
  42. do video_dma = video_framebuffer_dma_offset_read(); while (video_dma == 0); //avoid using first row
  43. while(video_framebuffer_dma_offset_read() >= video_dma);
  44. }
  45. }
  46. static uint8_t *jpeg_buf[2] = {NULL, NULL};
  47. int show_movie_frame(FL_FILE *a, const char *fname, size_t flen)
  48. {
  49. //printf("show_movie_frame: %s, len %u\n", fname, flen);
  50. static int buf_idx = 0;
  51. static int fcount = 0;
  52. free(jpeg_buf[buf_idx]);
  53. jpeg_buf[buf_idx] = (uint8_t *) malloc((flen + 0xFFFF) & 0xFFFF0000);
  54. int fr = fl_fread(jpeg_buf[buf_idx], flen, 1, a);
  55. if(fr != flen)
  56. {
  57. printf("Error reading data: read returns %d\n\n", fr);
  58. return -1;
  59. }
  60. flush_cache_region(jpeg_buf[buf_idx], flen);
  61. int frame_width=640, frame_height=480;
  62. size_t voff = (VIDEO_FRAMEBUFFER_HRES-frame_width)/2*(VIDEO_FRAMEBUFFER_DEPTH/8)+stride*((VIDEO_FRAMEBUFFER_VRES-frame_height)/2);
  63. accel_jpeg_decode(jpeg_buf[buf_idx], flen, video_buf+voff, stride, NULL, NULL, fcount++==0);
  64. ++buf_idx;
  65. if(buf_idx>=2) buf_idx=0;
  66. return 0;
  67. }
  68. struct
  69. {
  70. void *buffer;
  71. size_t size;
  72. } default_font_atlas[256];
  73. int load_default_font_char(FL_FILE *a, const char *fname, size_t flen)
  74. {
  75. int ch = atoi(fname);
  76. if(ch < 0 || ch >= sizeof(default_font_atlas)/sizeof(default_font_atlas[0]))
  77. {
  78. printf("Ignoring char number %d\n", ch);
  79. return 0;
  80. }
  81. void *buf = malloc(flen);
  82. if(buf && fl_fread(buf, flen, 1, a) != flen)
  83. {
  84. printf("Error reading font atlas\n");
  85. return -1;
  86. }
  87. flush_cache_region(buf, flen);
  88. default_font_atlas[ch].buffer = buf;
  89. default_font_atlas[ch].size = flen;
  90. printf("read atlas char %d '%c', buf %p, len %d\n", ch, ch, buf, flen);
  91. return 0;
  92. }
  93. #include "untar.c"
  94. void plot_digit(int x, int y, uint8_t ch)
  95. {
  96. void *img_buf = default_font_atlas[ch].buffer;
  97. size_t len = default_font_atlas[ch].size;
  98. if(img_buf)
  99. {
  100. size_t voff = x*(VIDEO_FRAMEBUFFER_DEPTH/8)+stride*y;
  101. accel_bmp_decode(img_buf, len, video_buf+voff, stride, NULL, NULL, 1);
  102. }
  103. }
  104. void plot_number(int x, int y, unsigned n, int digits)
  105. {
  106. while(digits--)
  107. {
  108. plot_digit(x, y, '0' + n % 10);
  109. n /= 10;
  110. x -= 120;
  111. }
  112. }
  113. void draw_background(void)
  114. {
  115. static void *bk_buf = NULL;
  116. static size_t flen;
  117. if(bk_buf == NULL)
  118. {
  119. printf("opening background file\n");
  120. FL_FILE *bk = fl_fopen("/background.jpeg", "rb");
  121. if(bk)
  122. {
  123. flen = bk->filelength;
  124. bk_buf = malloc(flen);
  125. if(bk_buf && fl_fread(bk_buf, flen, 1, bk) != flen)
  126. {
  127. free(bk_buf);
  128. bk_buf = NULL;
  129. }
  130. flush_cache_region(bk_buf, flen);
  131. fl_fclose(bk);
  132. printf("file size %d, buf %p\n", flen, bk_buf);
  133. }
  134. else
  135. printf("unable to open background\n");
  136. }
  137. if(bk_buf)
  138. {
  139. wait_vsync(1);
  140. accel_jpeg_decode(bk_buf, flen, video_buf, stride, NULL, NULL, 0);
  141. //printf("drawing image background at %p, len %u\r", bk_buf, flen); //FIXME: why needs this delay
  142. wait_vsync(1);
  143. accel_jpeg_decode_waitdone(NULL, NULL); //wait
  144. }
  145. }
  146. int is_movie(const char *filename)
  147. {
  148. const char suffix[] = {".jpeg.tar"};
  149. size_t len_filename = strlen(filename);
  150. if (len_filename < sizeof(suffix)) //base name of len at least 1
  151. return 0;
  152. return strcmp(filename + len_filename - (sizeof(suffix)-1), suffix) == 0;
  153. }
  154. int show_info(int frame)
  155. {
  156. static FL_FILE *movie = NULL;
  157. static FL_DIR dirstat = { .cluster = FAT32_INVALID_CLUSTER };
  158. if(frame == 0 && movie) //restart
  159. {
  160. fl_fclose(movie);
  161. movie = NULL;
  162. }
  163. if(!movie)
  164. {
  165. printf("\n" "start info" "\n");
  166. if(dirstat.cluster == FAT32_INVALID_CLUSTER)
  167. fl_opendir("/videos/", &dirstat);
  168. while (dirstat.cluster != FAT32_INVALID_CLUSTER)
  169. {
  170. struct fs_dir_ent dirent;
  171. if (fl_readdir(&dirstat, &dirent) != 0)
  172. {
  173. fl_closedir(&dirstat);
  174. dirstat.cluster = FAT32_INVALID_CLUSTER;
  175. break;
  176. }
  177. if(!dirent.is_dir)
  178. {
  179. if(is_movie(dirent.filename))
  180. {
  181. char fullname[FATFS_MAX_LONG_FILENAME] = {"/videos/"};
  182. strncpy(fullname+8, dirent.filename, sizeof(fullname)-1);
  183. printf("Opening movie %s, size %lu\n", fullname, dirent.size);
  184. if(movie)
  185. fl_fclose(movie);
  186. movie = fl_fopen(fullname, "rb");
  187. if(movie)
  188. break;
  189. else
  190. printf("failed to open movie\n");
  191. }
  192. }
  193. }
  194. }
  195. else if(untar(movie, show_movie_frame) <= 0)
  196. {
  197. printf("\nmovie end\n");
  198. fl_fclose(movie);
  199. movie = NULL;
  200. return 0;
  201. }
  202. return 1;
  203. }
  204. void ring_bell(void)
  205. {
  206. printf("\n" "next turn, ring bell!" "\n");
  207. }
  208. void load_font_atlas(void)
  209. {
  210. FL_FILE *digit_atlas = NULL;
  211. {
  212. digit_atlas = fl_fopen("/atlas120x240.bmp.tar", "rb");
  213. if(digit_atlas)
  214. {
  215. while(untar(digit_atlas, load_default_font_char) > 0);
  216. fl_fclose(digit_atlas);
  217. printf("closing digit atlas\n");
  218. }
  219. else
  220. printf("Error opening digit atlas\n");
  221. }
  222. }
  223. void turn_machine(void)
  224. {
  225. static int box=-1, turn=0, inactive=0, active=0; //active and inactive refer to the alternate info
  226. {
  227. int attention = inactive > (TURN_FIRST_DISPLAY_TIME - TURN_ATTENTION_TIME)*MOVIE_FPS; //at start
  228. attention |= inactive < TURN_ATTENTION_TIME*MOVIE_FPS; //before info
  229. if(uart_read_nonblock()) //check if something is received
  230. {
  231. int turn_prev = turn;
  232. char ch = uart_read();
  233. if(ch >= '0' && ch <= '9')
  234. {
  235. if(inactive == 0 || !attention) //ignore box requests too close to last one
  236. {
  237. if(box >= 0 && ++turn >= 100) turn = 0; //increment turn if there was a previous box
  238. ring_bell();
  239. box = ch-'0';
  240. inactive = TURN_FIRST_DISPLAY_TIME*MOVIE_FPS;
  241. }
  242. }
  243. else if(ch == '-')
  244. {
  245. if(turn == 0) turn = 100;
  246. --turn;
  247. inactive = TURN_UPDATE_DISPLAY_TIME*MOVIE_FPS;
  248. }
  249. else if(ch == '+')
  250. {
  251. if(++turn >= 100) turn = 0;
  252. inactive = TURN_UPDATE_DISPLAY_TIME*MOVIE_FPS;
  253. }
  254. else
  255. {
  256. inactive = 0;
  257. box = -1;
  258. }
  259. printf("box %d, turn %2d, inactive %3d, active %3d\n", box, turn, inactive, active);
  260. }
  261. if(inactive == 0)
  262. {
  263. if(active >= INFO_MAX_TIME*MOVIE_FPS || !show_info(active++))
  264. {
  265. if(box >= 0)
  266. inactive = TURN_RECALL_TIME*MOVIE_FPS;
  267. else
  268. active = 0; //show other info
  269. }
  270. }
  271. else
  272. {
  273. if(active > 0)
  274. {
  275. active = 0;
  276. draw_background();
  277. }
  278. plot_number(TURN_X, DIGITS_Y, turn, 2);
  279. if(box >= 0)
  280. {
  281. //box blinking logic
  282. if(!attention || (TURN_FIRST_DISPLAY_TIME*MOVIE_FPS-inactive) & 0x8)
  283. plot_number(BOX_X, DIGITS_Y, box, 1);
  284. else
  285. plot_digit(BOX_X, DIGITS_Y, ' ');
  286. }
  287. --inactive;
  288. }
  289. }
  290. //wait for next frame
  291. static uint64_t t0 = 0;
  292. int64_t dt;
  293. for(;;)
  294. {
  295. dt = highres_ticks() - t0;
  296. if(dt > highres_ticks_freq() / MOVIE_FPS)
  297. break;
  298. wait_vsync(1);
  299. }
  300. t0 += dt;
  301. }