aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.rst15
-rw-r--r--host/Makefile4
-rw-r--r--host/font.c82
-rw-r--r--host/font.h5
-rw-r--r--host/main.c222
5 files changed, 98 insertions, 230 deletions
diff --git a/README.rst b/README.rst
index ebd59e6..0644a05 100644
--- a/README.rst
+++ b/README.rst
@@ -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, &current_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;
-}