diff options
-rw-r--r-- | README.rst | 15 | ||||
-rw-r--r-- | host/Makefile | 4 | ||||
-rw-r--r-- | host/font.c | 82 | ||||
-rw-r--r-- | host/font.h | 5 | ||||
-rw-r--r-- | host/main.c | 222 |
5 files changed, 98 insertions, 230 deletions
@@ -29,8 +29,15 @@ There is at least one further server implementation of CRAP in the form of an `H Related Projects ---------------- -There is `a Python script that plays gifs over CRAP`_ and an `HTML5 CRAP emulator`_. - -.. _`a Python script that plays gifs over CRAP`: https://github.com/uwekamper/matelight-gifplayer -.. _`HTML5 CRAP emulator`: https://github.com/sodoku/matelightemu/blob/master/app.js + * `A Python script that plays gifs over CRAP`_ + * `An HTML5 CRAP emulator`_ + * `Webcam streaming on Mate Light`_ + * `A game programming framework for Mate Light`_ + * `Snake for Mate Light`_ + +.. _`A Python script that plays gifs over CRAP`: https://github.com/uwekamper/matelight-gifplayer +.. _`An HTML5 CRAP emulator`: https://github.com/sodoku/matelightemu/blob/master/app.js +.. _`Webcam streaming on Mate Light`: https://github.com/c-base/matetv +.. _`A game programming framework for Mate Light`: https://github.com/c-base/pymlgame +.. _`Snake for Mate Light`: https://github.com/c-base/pymlsnake diff --git a/host/Makefile b/host/Makefile index 90517f9..345058b 100644 --- a/host/Makefile +++ b/host/Makefile @@ -1,6 +1,6 @@ all: main.c font.c font.h color.c color.h gif.h gif.c - gcc -std=gnu11 -Wall -lm -lgif -o matelight -g -O0 main.c font.c color.c gif.c + gcc -shared -std=gnu11 -Wall -lm -o libbdf.so -g -O0 main.c font.c color.c clean: - rm matelight + rm libbdf.so diff --git a/host/font.c b/host/font.c index 8906dfa..494210d 100644 --- a/host/font.c +++ b/host/font.c @@ -23,7 +23,65 @@ void render_glyph(glyph_t *g, color_t *buf, unsigned int bufwidth, unsigned int } } -int read_bdf(FILE *f, glyph_t **glyph_table, unsigned int glyph_table_size){ +glyphtable_t *read_bdf_file(char *filename){ + FILE *fontfile = fopen("unifont.bdf", "r"); + if(!fontfile){ + fprintf(stderr, "Error opening font file: %s\n", strerror(errno)); + goto error; + } + + glyphtable_t *glyph_table = read_bdf(fontfile, glyph_table, BLP_SIZE) + if(!glyph_table){ + fprintf(stderr, "Error reading font file.\n"); + goto error; + } + + fclose(fontfile); + return glyph_table; +error: + fclose(fontfile); + return NULL; +} + +#define START_GLYPHTABLE_SIZE 256 +#define MAX_GLYPHTABLE_INCREMENT 32768 +glyphtable_t *extend_glyphtable(glyphtable_t *glyph_table){ + size_t oldlen = glyph_table->size; + size_t newlen = oldlen + (oldlen<MAX_GLYPHTABLE_INCREMENT ? oldlen : MAX_GLYPHTABLE_INCREMENT); + if(oldlen == 0) + newlen = START_GLYPHTABLE_SIZE; + glyph_t *newdata = realloc(glyph_table->data, newlen*sizeof(glyph_t)); + if(!newdata){ + fprintf(stderr, "Cannot allocate bdf glyph buffer\n"); + goto error; + } + glyph_table->data = newdata; + // Clear newly allocated memory area + memset(glyph_table->data+oldlen, 0, (newlen-oldlen)*sizeof(glyph_t)); + glyph_table->size = newlen; +error: + free_glyphtable(glyph_table); + return NULL; +} + +void free_glyphtable(glyphtable_t *glyph_table){ + if(glyph_table){ + for(unsigned int i=0; i<glyph_table->length; i++){ + free(glyph_table->data[i]); + } + free(glyph_table->data); + } + free(glyph_table); +} + +glyphtable_t *read_bdf(FILE *f){ + glyphtable_t *glyph_table = malloc(sizeof(glyphtable_t)); + if(!glyph_table){ + printf("Cannot allocate glyph table\n"); + goto error; + } + memset(glyph_table, 0, sizeof(*glyph_table)); + char* line = 0; size_t len = 0; @@ -32,9 +90,6 @@ int read_bdf(FILE *f, glyph_t **glyph_table, unsigned int glyph_table_size){ unsigned int encoding = -1; void *glyph_data = 0; - // Clear glyph table before use - memset(glyph_table, 0, sizeof(*glyph_table)); - for(;;){ size_t read = getline(&line, &len, f); if(read == -1){ @@ -64,9 +119,12 @@ int read_bdf(FILE *f, glyph_t **glyph_table, unsigned int glyph_table_size){ fprintf(stderr, "Invalid ENCODING line: %s %s\n", line, args); goto error; } - if(encoding > glyph_table_size){ - fprintf(stderr, "Codepoint out of valid range (0-%d): %d", glyph_table_size, encoding); - goto error; + if(encoding > glyph_table->size){ + glyph_table = extend_glyphtable(glyph_table); + if(!glyph_table){ + fprintf(stderr, "Cannot allocate glyph table.\n"); + goto error; + } } }else if(strcmp("BBX", line) == 0){ @@ -171,7 +229,7 @@ int read_bdf(FILE *f, glyph_t **glyph_table, unsigned int glyph_table_size){ i++; } memcpy(glyph_data, ¤t_glyph, sizeof(glyph_t)); - glyph_table[encoding] = glyph_data; + glyph_table->data[encoding] = glyph_data; // Reset things for next iteration current_glyph.width = -1; @@ -182,12 +240,10 @@ int read_bdf(FILE *f, glyph_t **glyph_table, unsigned int glyph_table_size){ encoding = -1; } } - return 0; + return glyph_table; error: - // Free malloc()ed glyphs free(glyph_data); - for(unsigned int i=0; i<sizeof(glyph_table)/sizeof(glyph_t *); i++) - free(glyph_table[i]); - return 1; + free_glyphtable(glyph_table); + return NULL; } diff --git a/host/font.h b/host/font.h index 72e536b..4a7fe63 100644 --- a/host/font.h +++ b/host/font.h @@ -14,6 +14,11 @@ typedef struct { int8_t y; } glyph_t; +typedef struct { + glyph_t *t; + size_t size; +} glyphtable_t; + // Size of Unicode's basic multilingual plane #define BLP_SIZE 65536 diff --git a/host/main.c b/host/main.c index d8f5062..0d5af6e 100644 --- a/host/main.c +++ b/host/main.c @@ -19,9 +19,14 @@ #include <unistd.h> +void free_framebuffer(framebuffer_t *fb){ + free(fb->data); + free(fb); +} + /* CAUTION: REQUIRES INPUT TO BE \0-TERMINATED - * ...also, it does a hardcodes setlocale of LC_CTYPE to en_US.utf8 for... reasons. */ -framebuffer_t *framebuffer_render_text(char *s, glyph_t **glyph_table, unsigned int glyph_table_size){ + * ...also, it does a hardcoded setlocale of LC_CTYPE to en_US.utf8 for... reasons. */ +framebuffer_t *framebuffer_render_text(char *s, glyphtable_t *glyph_table){ unsigned int len = strlen(s); color_t *gbuf = NULL; @@ -59,12 +64,12 @@ framebuffer_t *framebuffer_render_text(char *s, glyph_t **glyph_table, unsigned break; p += inc; - if(c > glyph_table_size){ - fprintf(stderr, "Error rendering string: Codepoint 0x%lx out of valid range (0-%d).\n", (long int)c, glyph_table_size); + if(c > glyph_table->size){ + fprintf(stderr, "Error rendering string: Codepoint 0x%lx out of valid range (0-%d).\n", (long int)c, glyph_table->size); goto error; } - glyph_t *g = glyph_table[c]; + glyph_t *g = glyph_table->data[c]; if(!g){ fprintf(stderr, "Error rendering string: Codepoint 0x%lx not in font.\n", (long int)c); goto error; @@ -273,7 +278,7 @@ framebuffer_t *framebuffer_render_text(char *s, glyph_t **glyph_table, unsigned color_t fg = inv ? style.fg : style.bg; color_t bg = inv ? style.bg : style.fg; - glyph_t *g = glyph_table[c]; + glyph_t *g = glyph_table->data[c]; render_glyph(g, gbuf, gbufwidth, x, 0, fg, bg); if(style.strikethrough || style.underline){ int sty = gbufheight/2; @@ -351,208 +356,3 @@ void console_render_buffer(framebuffer_t *fb){ } } -int main(int argc, char **argv){ - FILE *f = NULL; - int udpfd = 0; - int udp6fd = 0; - uint8_t *udpbuf = NULL; - uint8_t *fbdata = NULL; - framebuffer_t *fb = NULL; - - if(argc != 2){ - fprintf(stderr, "No or too much input text given\n"); - return 1; - } - - /* Read font file */ - FILE *fontfile = fopen("unifont.bdf", "r"); - if(!fontfile){ - fprintf(stderr, "Error opening font file: %s\n", strerror(errno)); - return 1; - } - glyph_t* glyph_table[BLP_SIZE]; - if(read_bdf(fontfile, glyph_table, BLP_SIZE)){ - fprintf(stderr, "Error reading font file.\n"); - fclose(fontfile); - goto error; - } - fclose(fontfile); - - /* Set up framebuffer */ - fbdata = malloc(DISPLAY_WIDTH*DISPLAY_HEIGHT*sizeof(color_t)); - if(!fbdata){ - fprintf(stderr, "Cannot alloccate framebuffer\n"); - goto error; - } - fb = malloc(sizeof(*fb)); - if(!fb){ - fprintf(stderr, "Cannot alloccate framebuffer\n"); - goto error; - } - fb->w = DISPLAY_WIDTH; - fb->h = DISPLAY_HEIGHT; - fb->data = fbdata; - - /* Set up UDP server */ - udp4fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); - udp6fd = socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); - if(udp4fd < 0 || udp6fd < 0){ - fprintf(stderr, "Cannot open UDP sockets: %s\n", strerror(errno)); - goto error; - } - struct sockaddr_in udp_addr = { - AF_INET, - INADDR_ANY, - htons(UDP_PORT) - }; - bind(udp4fd, &udp_addr, sizeof(udp_addr)); - struct sockaddr_in udp6_addr = { - AF_INET6, - IN6ADDR_ANY_INIT, - htons(UDP_PORT) - }; - bind(udp6fd, &udp_addr, sizeof(udp_addr)); - /* Set up UDP receive buffer */ - struct msghdr msg; - memset(&msg, 0, sizeof(msg)); - udpbuf = malloc(UDP_BUF_SIZE); - if(!buf){ - fprintf(stderr, "Cannot allocate UDP buffer"); - goto error; - } - struct iovec iov[1] = {{udpbuf, sizeof(UDP_BUF_SIZE)}}; - msg.msg_iov = iov; - msg.msg_iovlen = 1; - - /* List of currently active UDP streams */ - LIST_HEAD(udp_client_entry, udp_client) udp_client_head; - struct udp_client { - uint64_t last_timestamp; - uint64_t last_sequence_number; - struct sockaddr remote_addr; - int active:1; - LIST_ENTRY(udp_client) entries; - }; - LIST_INIT(&udp_client_head); - - LIST_HEAD(text_queue_head_t, text_queue_entry) text_queue_head; - struct text_queue_entry { - char *text; - int current_position; - unsigned int loop_count; - LIST_ENTRY(text_queue_entry) entries; - }; - LIST_INIT(&text_queue_head); - - for(;;){ /* Never gonna give you up, never gonna let you down! */ - struct timeb time = {0}; - ftime(&time); - uint64_t now = time.time*1000 + time.millitm; - - int made_active = 0; - /* Choose next active client */ - for(struct udp_client *p = udp_client_head.lh_first; p != NULL; p = p->entries.le_next){ - if(now - p->last_frame_received > FRAME_TIMEOUT){ /* Connection timeout */ - LIST_REMOVE(p, entries); - continue; - } - if(!made_active){ - p->active = 1; - made_active = 1; - }else{ - p->active = 0; - } - } - - if(!made_active){ /* No active streams, render marquee */ - text_queue_entry *entry = text_queue_head.lh_first; - framebuffer_t *text = framebuffer_render_text(entry, glyph_table, BLP_SIZE); - /* COPY TEXT DATA */ - for(size_t line = 0; line < DISPLAY_HEIGHT; line++){ - color_t *datarow = fb->data+(line*DISPLAY_WIDTH); - color_t *textrow = text->data+(line*text->w); - if(entry->current_position > 0) - memset(datarow, 0, sizeof(color_t)*entry->current_position); - if(entry->current_position+text->w < DISPLAY_WIDTH) - memset(datarow+(entry->curent_position+text->w), 0, DISPLAY_WIDTH-(entry->curent_position+text->w)); - memcpy(datarow+(entry->current_position>0 ? entry->current_position : 0), - textrow+(entry->current_position>0 ? 0 : -entry->current_position), - //DISPLAY_WIDTH, text->w-current_position FIXME - } - entry->current_position++; - if(entry->current_position <= -text->w){ - entry->loop_count++; - if(entry->loop_count > TEXT_LOOP_COUNT){ - LIST_REMOVE(entry, entries); - } - } - } - - /* Receive pending IPv4 UDP packets */ - ssize_t received = 0; - while((received = recvmsg(udp4fd, &msg, 0)) > 0){ - if(received < UDP_BUF_SIZE) /* Packet too short */ - continue; - ml_packet_t *pkt = (ml_packet_t*)udpbuf; - if(ntohl(pkt->magic) != 0xDEADBEEF) - continue; - if(ntohs(pkt->width) != DISPLAY_WIDTH || ntohs(pkt->height) != DISPLAY_HEIGHT) - continue; - struct sockaddr_in *src = msg.msg_name; - struct udp_client *entry = NULL; - for(struct udp_client *p = udp_client_head.lh_first; p != NULL; p = p->entries.le_next){ - if(!memcmp(&p->remote_addr, src, sizeof(sockaddr))){ /* found */ - entry = p; - break; - } - } - if(!entry){ - entry = malloc(sizeof(struct udp_client)); - if(!entry){ - fprintf(stderr, "Cannot allocate UDP connection entry\n"); - goto error; - } - memset(entry, 0, sizeof(entry)); - LIST_INSERT_HEAD(&udp_client_head, entry, entries); - memcpy(entry->remote_addr, src, sizeof(sockaddr)); - } - if(entry->last_sequence_number > pkt->seq) /* Delayed packet containing old data */ - continue; - entry->last_timestamp = now; - entry->last_sequence_number = pkt->seq; - if(entry->active){ - /* Copy frame, extending RGB UDP packet data to RGBA framebuffer format */ - color_t *p = fb->data; - rgb_t *q = pkt->data; - while(p < fb->data+fb->w*fb->h){ - p->a = 0; - *(rgb_t *)p++ = *q++; - } - } - } - if(received < 0){ - fprintf(stderr, "Error receiving UDP datagram: %s\n", strerror(errno)); - goto error; - } - - /* Receive pending IPv6 UDP packets */ - /* FIXME */ - - /* Render frame buffer */ - printf("\033[2J"); - console_render_buffer(fb); - printf("\n"); - - usb_send_buffer(fb); - usleep(1000000/FRAMERATE); - } - return 0; -error: - fclose(f); - close(udpfd); - close(udp6fd); - free(udpbuf); - free(fbdata); - free(fb); - return 1; -} |