123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- #include "misc.h" //just for ACCEL_STATIC_ASSERT
- #include "accel_cores.h"
- #include "graphics.h"
- #include "fat_io_lib/src/fat_filelib.h"
- //info timings
- #define TURN_ATTENTION_TIME 3
- #define TURN_FIRST_DISPLAY_TIME 15
- #define TURN_RECALL_TIME 9
- #define TURN_UPDATE_DISPLAY_TIME 5
- #define INFO_MAX_TIME 30
- //digit coordinates
- #define BOX_X 450
- #define TURN_X 175
- #define DIGITS_SEP 95
- #define DIGITS_Y 138
- #define MOVIE_FPS 30
- static uint64_t highres_ticks(void)
- {
- timer0_uptime_latch_write(1);
- return timer0_uptime_cycles_read(); //makes increasing
- }
- static uint64_t highres_ticks_freq(void) { return CONFIG_CLOCK_FREQUENCY; }
- typedef union
- {
- uint32_t rgba;
- struct { uint32_t r:8; uint32_t g:8; uint32_t b:8; uint32_t a:8; };
- } pix_t;
- //TODO: use uncached regions of memory whenever possible
- void flush_cache_region(void *buf, size_t size)
- {
- flush_cpu_dcache();
- flush_l2_cache();
- }
- uint8_t *const video_buf = (uint8_t *) VIDEO_FRAMEBUFFER_BASE;
- const unsigned stride = VIDEO_FRAMEBUFFER_HRES*(VIDEO_FRAMEBUFFER_DEPTH/8);
- void wait_vsync(int count)
- {
- flush_cache_region(video_buf, VIDEO_FRAMEBUFFER_VRES*stride); //only needed for software renderers
- uint32_t video_dma;
- while(count--)
- {
- do video_dma = video_framebuffer_dma_offset_read(); while (video_dma == 0); //avoid using first row
- while(video_framebuffer_dma_offset_read() >= video_dma);
- }
- }
- static uint8_t *jpeg_buf[2] = {NULL, NULL};
- int show_movie_frame(FL_FILE *a, const char *fname, size_t flen)
- {
- //printf("show_movie_frame: %s, len %u\n", fname, flen);
-
- static int buf_idx = 0;
- static int fcount = 0;
-
- free(jpeg_buf[buf_idx]);
- jpeg_buf[buf_idx] = (uint8_t *) malloc((flen + 0xFFFF) & 0xFFFF0000);
- int fr = fl_fread(jpeg_buf[buf_idx], flen, 1, a);
- if(fr != flen)
- {
- printf("Error reading data: read returns %d\n\n", fr);
- return -1;
- }
- flush_cache_region(jpeg_buf[buf_idx], flen);
- int frame_width=640, frame_height=480;
- size_t voff = (VIDEO_FRAMEBUFFER_HRES-frame_width)/2*(VIDEO_FRAMEBUFFER_DEPTH/8)+stride*((VIDEO_FRAMEBUFFER_VRES-frame_height)/2);
- accel_jpeg_decode(jpeg_buf[buf_idx], flen, video_buf+voff, stride, NULL, NULL, fcount++==0);
- ++buf_idx;
- if(buf_idx>=2) buf_idx=0;
-
- return 0;
- }
- struct
- {
- void *buffer;
- size_t size;
- } default_font_atlas[256];
- int load_default_font_char(FL_FILE *a, const char *fname, size_t flen)
- {
- int ch = atoi(fname);
- if(ch < 0 || ch >= sizeof(default_font_atlas)/sizeof(default_font_atlas[0]))
- {
- printf("Ignoring char number %d\n", ch);
- return 0;
- }
- void *buf = malloc(flen);
- if(buf && fl_fread(buf, flen, 1, a) != flen)
- {
- printf("Error reading font atlas\n");
- return -1;
- }
- flush_cache_region(buf, flen);
- default_font_atlas[ch].buffer = buf;
- default_font_atlas[ch].size = flen;
- printf("read atlas char %d '%c', buf %p, len %d\n", ch, ch, buf, flen);
- return 0;
- }
- #include "untar.c"
- void plot_digit(int x, int y, uint8_t ch)
- {
- void *img_buf = default_font_atlas[ch].buffer;
- size_t len = default_font_atlas[ch].size;
- if(img_buf)
- {
- size_t voff = x*(VIDEO_FRAMEBUFFER_DEPTH/8)+stride*y;
- accel_bmp_decode(img_buf, len, video_buf+voff, stride, NULL, NULL, 1);
- }
- }
- void plot_number(int x, int y, unsigned n, int digits)
- {
- while(digits--)
- {
- plot_digit(x, y, '0' + n % 10);
- n /= 10;
- x -= 120;
- }
- }
- void draw_background(void)
- {
- static void *bk_buf = NULL;
- static size_t flen;
- if(bk_buf == NULL)
- {
- printf("opening background file\n");
- FL_FILE *bk = fl_fopen("/background.jpeg", "rb");
- if(bk)
- {
- flen = bk->filelength;
- bk_buf = malloc(flen);
- if(bk_buf && fl_fread(bk_buf, flen, 1, bk) != flen)
- {
- free(bk_buf);
- bk_buf = NULL;
- }
- flush_cache_region(bk_buf, flen);
- fl_fclose(bk);
- printf("file size %d, buf %p\n", flen, bk_buf);
- }
- else
- printf("unable to open background\n");
- }
- if(bk_buf)
- {
- wait_vsync(1);
- accel_jpeg_decode(bk_buf, flen, video_buf, stride, NULL, NULL, 0);
- //printf("drawing image background at %p, len %u\r", bk_buf, flen); //FIXME: why needs this delay
- wait_vsync(1);
- accel_jpeg_decode_waitdone(NULL, NULL); //wait
- }
- }
- int is_movie(const char *filename)
- {
- const char suffix[] = {".jpeg.tar"};
- size_t len_filename = strlen(filename);
- if (len_filename < sizeof(suffix)) //base name of len at least 1
- return 0;
- return strcmp(filename + len_filename - (sizeof(suffix)-1), suffix) == 0;
- }
- int show_info(int frame)
- {
- static FL_FILE *movie = NULL;
- static FL_DIR dirstat = { .cluster = FAT32_INVALID_CLUSTER };
- if(frame == 0 && movie) //restart
- {
- fl_fclose(movie);
- movie = NULL;
- }
-
- if(!movie)
- {
- printf("\n" "start info" "\n");
- if(dirstat.cluster == FAT32_INVALID_CLUSTER)
- fl_opendir("/videos/", &dirstat);
- while (dirstat.cluster != FAT32_INVALID_CLUSTER)
- {
- struct fs_dir_ent dirent;
- if (fl_readdir(&dirstat, &dirent) != 0)
- {
- fl_closedir(&dirstat);
- dirstat.cluster = FAT32_INVALID_CLUSTER;
- break;
- }
- if(!dirent.is_dir)
- {
- if(is_movie(dirent.filename))
- {
- char fullname[FATFS_MAX_LONG_FILENAME] = {"/videos/"};
- strncpy(fullname+8, dirent.filename, sizeof(fullname)-1);
- printf("Opening movie %s, size %lu\n", fullname, dirent.size);
- if(movie)
- fl_fclose(movie);
- movie = fl_fopen(fullname, "rb");
- if(movie)
- break;
- else
- printf("failed to open movie\n");
- }
- }
- }
- }
- else if(untar(movie, show_movie_frame) <= 0)
- {
- printf("\nmovie end\n");
- fl_fclose(movie);
- movie = NULL;
- return 0;
- }
- return 1;
- }
- void ring_bell(void)
- {
- printf("\n" "next turn, ring bell!" "\n");
- }
- void load_font_atlas(void)
- {
- FL_FILE *digit_atlas = NULL;
- {
- digit_atlas = fl_fopen("/atlas120x240.bmp.tar", "rb");
- if(digit_atlas)
- {
- while(untar(digit_atlas, load_default_font_char) > 0);
- fl_fclose(digit_atlas);
- printf("closing digit atlas\n");
- }
- else
- printf("Error opening digit atlas\n");
- }
- }
- void turn_machine(void)
- {
- static int box=-1, turn=0, inactive=0, active=0; //active and inactive refer to the alternate info
- {
- int attention = inactive > (TURN_FIRST_DISPLAY_TIME - TURN_ATTENTION_TIME)*MOVIE_FPS; //at start
- attention |= inactive < TURN_ATTENTION_TIME*MOVIE_FPS; //before info
- if(uart_read_nonblock()) //check if something is received
- {
- int turn_prev = turn;
- char ch = uart_read();
- if(ch >= '0' && ch <= '9')
- {
- if(inactive == 0 || !attention) //ignore box requests too close to last one
- {
- if(box >= 0 && ++turn >= 100) turn = 0; //increment turn if there was a previous box
- ring_bell();
- box = ch-'0';
- inactive = TURN_FIRST_DISPLAY_TIME*MOVIE_FPS;
- }
- }
- else if(ch == '-')
- {
- if(turn == 0) turn = 100;
- --turn;
- inactive = TURN_UPDATE_DISPLAY_TIME*MOVIE_FPS;
- }
- else if(ch == '+')
- {
- if(++turn >= 100) turn = 0;
- inactive = TURN_UPDATE_DISPLAY_TIME*MOVIE_FPS;
- }
- else
- {
- inactive = 0;
- box = -1;
- }
- printf("box %d, turn %2d, inactive %3d, active %3d\n", box, turn, inactive, active);
- }
-
- if(inactive == 0)
- {
- if(active >= INFO_MAX_TIME*MOVIE_FPS || !show_info(active++))
- {
- if(box >= 0)
- inactive = TURN_RECALL_TIME*MOVIE_FPS;
- else
- active = 0; //show other info
- }
- }
- else
- {
- if(active > 0)
- {
- active = 0;
- draw_background();
- }
- plot_number(TURN_X, DIGITS_Y, turn, 2);
- if(box >= 0)
- {
- //box blinking logic
- if(!attention || (TURN_FIRST_DISPLAY_TIME*MOVIE_FPS-inactive) & 0x8)
- plot_number(BOX_X, DIGITS_Y, box, 1);
- else
- plot_digit(BOX_X, DIGITS_Y, ' ');
- }
- --inactive;
- }
-
- }
-
- //wait for next frame
- static uint64_t t0 = 0;
- int64_t dt;
- for(;;)
- {
- dt = highres_ticks() - t0;
- if(dt > highres_ticks_freq() / MOVIE_FPS)
- break;
- wait_vsync(1);
- }
- t0 += dt;
- }
|