diff --git a/Makefile b/Makefile index eb8ad586da99dd7927d883877244dfec4345ffab..d76fbd0a8dfef612756c64a02e38547c9f3bc9b7 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,6 @@ ARCHIVE=osdd-$(VERSION).tar.gz CFLAGS=-g3 -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -Wundef -Wredundant-decls -std=gnu99 -Wformat-truncation=0 -#-fsanitize=address - all: osdd osdc osd-batt osd-alsa osdd: osdd.o util.o osdd-set.o @@ -13,7 +11,10 @@ osd-batt: osd-batt.o util.o client.o osd-alsa: osd-alsa.o util.o client.o # OSDD MODULES -osdd: display.o osdd-file.o +osdd: display.o +osdd: osdd-file.o osdd-to-string.o +osdd: osdd-mqtt.o osdd-to-string.o -lpaho-mqtt3a -lpaho-mqtt3c + osdd: LDLIBS+=$(shell pkg-config --libs xft) -lXext -lX11 #LDLIBS += -fsanitize=address @@ -24,7 +25,7 @@ osd-batt: LDLIBS+=-lX11 osd-alsa.o: CFLAGS+=$(shell pkg-config --cflags alsa) osd-alsa: LDLIBS+=$(shell pkg-config --libs alsa) -lX11 -display.o osdd-file.o: CFLAGS+=$(shell pkg-config --cflags xft) +display.o osdd-to-string.o: CFLAGS+=$(shell pkg-config --cflags xft) clean: rm -f *~ *.o TAGS core osdd osdc osd-batt osd-alsa diff --git a/osdd-file.c b/osdd-file.c index a6ca2b1d6d41d8afd8d15889b458f2fd186b8cbb..b3bcef1c37c0339468b7dc2c67f98750512124b0 100644 --- a/osdd-file.c +++ b/osdd-file.c @@ -6,99 +6,14 @@ #include "osdd-file.h" #include "util.h" -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <getopt.h> -#include <stdlib.h> - -#include <X11/Xlib.h> -#include <X11/Xlib.h> -#include <X11/Xatom.h> -#include <X11/extensions/shape.h> -#include <X11/extensions/render.h> -#include <X11/Xft/Xft.h> +#include "osdd-to-string.h" #include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> #include <string.h> -#include <time.h> -#include <X11/Xlib.h> -#include <X11/Xatom.h> -#include <X11/extensions/shape.h> -#include <X11/extensions/render.h> -#include <X11/Xft/Xft.h> #include <getopt.h> +#include <stdlib.h> -static void replace_no_text(char * in) -{ - for(;*in;in++) - { - if(' '== *in) continue; - if('a'<= *in&& *in<='z') continue; - if('A'<= *in&& *in<='Z') continue; - if('0'<= *in&& *in<='9') continue; - //if(128 <= (unsigned char)*in) continue; - *in='?'; - } -} - -static -char * expand_backslash(char * in) -{ - char * out = xmalloc(strlen(in)+1); - int i=0; - for(;*in;i++,in++) - { - if(in[0]=='\\') - { - switch(in[1]) - { - case 'n': - out[i]='\n'; - break; - case 't': - out[i]='\t'; - break; - case '0': - out[i]='\0'; - break; - default: - out[i]='?'; - break; - } - if(in[1]) in++; - } - else - out[i]=*in; - } - out[i]=0; - return out; -} - -static void -colorToRGB(char * name, int *r, int *g, int *b) -{ - - Display *d = XOpenDisplay(NULL); - int s = XDefaultScreen(d); - Visual *v = XDefaultVisual(d,s); - Colormap cmap = DefaultColormap(d,s); - - XftColor color; - if (XftColorAllocName(d, v, cmap, name, &color)) - { - typeof(color.color) c = color.color; - *r = c.red; - *g = c.green; - *b = c.blue; - } - else *r=*g=*b=-1; - XftColorFree(d, v, cmap, &color); - XCloseDisplay(d); -} // ************************* STATE STRUCT ********** @@ -106,101 +21,15 @@ struct file_state { char * file_name; char * open_mode; - bool clear; - char * line_separator; - char * msq_separator; - char * time_separator; - - //tmp usage: - XftColor fg_color; - enum { - FILE_COLOR_NO, - FILE_COLOR_RGB_DEC, - FILE_COLOR_RGB_HEX, - FILE_COLOR_RGB_HASHTAG_HEX, - FILE_COLOR_TERM_RGB, - FILE_COLOR_ORIGINAL, - } color_mode; - enum { - FILE_TIME_NO, - FILE_TIME_UNIX, - FILE_TIME_ISO, - } time_mode; - bool replace_no_text; + struct osd_to_string_state to_string; }; // ************************* MAIN FUNCTIONS ******* static -void file_show(struct file_state *state, struct osd_line * lines, int num_lines) +void file_write_to_file(struct file_state *state, VECTOR(char) out) { - VECTOR(char) out = NULL; - switch(state->time_mode) - { - case FILE_TIME_NO: - break; - case FILE_TIME_UNIX: - vprint(&out,"%lld%s",(long long)time(0),state->time_separator); - break; - case FILE_TIME_ISO: - { - time_t t = time(NULL); - struct tm tm = *localtime(&t); - vprint(&out,"%04d-%02d-%02d %02d:%02d:%02d%s", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,state->time_separator); - } - break; - } - for(int i=0;i<num_lines;i++) - { - struct osd_line * line = lines+i; - //if(!(line->log & 1)) continue; - if(line->type!=OSD_TYPE_TEXT) continue; - int r,g,b; - VECTOR(char) text=0; - VRESERVE(text,strlen(line->u.text)+1); - char color[30]; - color[0]=0; - char * end_color = ""; - - vprint(&text,"%s",line->u.text); - if(state->replace_no_text) replace_no_text(text); - switch(state->color_mode) - { - case FILE_COLOR_RGB_DEC: - case FILE_COLOR_RGB_HEX: - case FILE_COLOR_RGB_HASHTAG_HEX: - case FILE_COLOR_TERM_RGB: - colorToRGB(line->fg_color,&r,&g,&b); - break; - default: - break; - } - switch(state->color_mode) - { - case FILE_COLOR_RGB_DEC: - sprintf(color,"%d %d %d ",r/256,g/256,b/256); - break; - case FILE_COLOR_RGB_HEX: - sprintf(color,"%02x%02x%02x ",r/256,g/256,b/256); - break; - case FILE_COLOR_RGB_HASHTAG_HEX: - sprintf(color,"#%02x%02x%02x ",r/256,g/256,b/256); - break; - case FILE_COLOR_TERM_RGB: - sprintf(color,"\e[38;2;%d;%d;%dm",r/256,g/256,b/256); - end_color = "\e[0m"; - break; - case FILE_COLOR_ORIGINAL: - sprintf(color,"%s ",line->fg_color); - break; - case FILE_COLOR_NO: - break; - } - vprint(&out,"%s%s%s%s", color, text, end_color,state->line_separator); - VFREE(text); - - } - vprint(&out,"%s",state->msq_separator); + if(!out) return; FILE * f = fopen(state->file_name,state->open_mode); if(f) { @@ -210,11 +39,16 @@ void file_show(struct file_state *state, struct osd_line * lines, int num_lines) VFREE(out); } +static +void file_show(struct file_state *state, struct osd_line * lines, int num_lines) +{ + file_write_to_file(state,osd_to_string(&state->to_string, lines, num_lines)); +} + static void file_clear(struct file_state *state) { - if(state->clear) - file_show(state,0,0); + file_write_to_file(state,osd_to_string_end_msg(&state->to_string)); } // ************************* NEW ****************** @@ -225,12 +59,7 @@ void file_new_help(FILE * f) fprintf(f,"\ Module FILE help:\n\ -a, --append \t\tAppend to file (do not overwrite)\n\ --c, --color=<{}>\tSet how to print color of messages {no, rgbDEC, rgbHEX, rgbHEXHASHTAG, term, original}\n\ --l, --line-separator=<s>Separato of each line.\n\ --m, --msq-separator=<s>\tSeparato of each message.\n\ --r, --replace\t\tReplace not alphabet and number in output to '?'\n\ --t, --time=<{}>\t\tSet how to print actual time {no, unix, iso}\n\ --T, --time-separator=<s>Separator of time and message text\n\ +" OSDD_TO_STRING_HELP "\ \n\ "); } @@ -241,15 +70,10 @@ struct osd_abstract file_new(int argc, char ** argv, Display * nope) (void)nope; argc++;argv--; struct osd_abstract r; - static const char short_opts[] = "+ac:l:m:rt:T:"; + static const char short_opts[] = "+a" OSDD_TO_STRING_SHORTOP; static const struct option long_opts[] = { { "append", no_argument, NULL, 'a' }, - { "color", required_argument, NULL, 'c' }, - { "line-separator", required_argument, NULL, 'l' }, - { "msq-separator", required_argument, NULL, 'm' }, - { "replace", no_argument, NULL, 'r' }, - { "time", required_argument, NULL, 't' }, - { "time-separator", required_argument, NULL, 'T' }, + OSDD_TO_STRING_LONGOP { NULL, 0, NULL, 0 }, }; memset(&r,0,sizeof(r)); @@ -257,58 +81,18 @@ struct osd_abstract file_new(int argc, char ** argv, Display * nope) memset(state,0,sizeof(state)[0]); state->open_mode = "w"; - state->line_separator = expand_backslash("\\n"); - state->time_separator = expand_backslash("\\n"); - state->msq_separator = expand_backslash(""); - state->clear=0; + osd_to_string_state_init(&state->to_string); int opt; optind = 0; while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) >= 0) { + if(!osd_to_string_parse_arg(&state->to_string,opt)) switch (opt) { case 'a': state->open_mode = "a"; break; - case 'c': - if(!strcmp(optarg,"no")) state->color_mode = FILE_COLOR_NO; else - if(!strcmp(optarg,"rgbDEC")) state->color_mode = FILE_COLOR_RGB_DEC; else - if(!strcmp(optarg,"rgbHEX")) state->color_mode = FILE_COLOR_RGB_HEX; else - if(!strcmp(optarg,"rgbHEXHASHTAG")) state->color_mode = FILE_COLOR_RGB_HASHTAG_HEX; else - if(!strcmp(optarg,"term")) state->color_mode = FILE_COLOR_TERM_RGB; else - if(!strcmp(optarg,"original")) state->color_mode = FILE_COLOR_ORIGINAL; else - { - fprintf(stderr,"Color mode %s not exist\n\n",optarg); - file_new_help(stderr); - exit(0); - } - break; - case 'l': - free(state->line_separator); - state->line_separator = expand_backslash(optarg); - break; - case 'm': - free(state->msq_separator); - state->msq_separator = expand_backslash(optarg); - break; - case 'r': - state->replace_no_text = 1; - break; - case 't': - if(!strcmp(optarg,"no")) state->time_mode = FILE_TIME_NO; else - if(!strcmp(optarg,"unix")) state->time_mode = FILE_TIME_UNIX; else - if(!strcmp(optarg,"iso")) state->time_mode = FILE_TIME_ISO; else - { - fprintf(stderr,"Time mode %s not exist\n\n",optarg); - file_new_help(stderr); - exit(0); - } - break; - case 'T': - free(state->time_separator); - state->time_separator = expand_backslash(optarg); - break; default: fprintf(stderr,"Option %c not exist\n\n",opt); file_new_help(stderr); diff --git a/osdd-mqtt.c b/osdd-mqtt.c new file mode 100644 index 0000000000000000000000000000000000000000..86a40162d14fc0494f4e331c74fbe7d3296a4541 --- /dev/null +++ b/osdd-mqtt.c @@ -0,0 +1,258 @@ +/* + * On-screen Display + * + * (c) 2021 Jiri Kalvoda <jirikalvoda@kam.mff.cuni.cz> + */ + +#include "osdd-mqtt.h" +#include "util.h" +#include "osdd-to-string.h" + +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> + +#include <MQTTClient.h> + + +// ************************* STATE STRUCT ********** + +struct mqtt_state +{ + char * mqtt_addres; + char * mqtt_user; + char * mqtt_passwd; + char * mqtt_topic; + struct osd_to_string_state to_string; + int pipe_fd; + bool mqtt_retained; + int mqtt_qos; +}; + +struct mqtt_fork_state +{ + int fd; + bool connected; + MQTTClient client; + struct mqtt_state * state; +}; + +// ************************* FORK ***************** + +static +void mqtt_fork_connect(struct mqtt_fork_state * fork_state) +{ + //fprintf(stderr,"MQTT CONNECT\n"); + int rc; + for(int i=0;i<2;i++) + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" + MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; + conn_opts.httpProxy = 0; +#pragma GCC diagnostic pop + + static char mqtt_con_name[300] = ""; + if(!mqtt_con_name[0]) sprintf(mqtt_con_name,"led-include-%d-%d",(1),(2)); + MQTTClient_create(&fork_state->client, fork_state->state->mqtt_addres, mqtt_con_name, + MQTTCLIENT_PERSISTENCE_NONE, NULL); + + conn_opts.keepAliveInterval = 600; + conn_opts.cleansession = 0; + conn_opts.username = fork_state->state->mqtt_user; + conn_opts.password = fork_state->state->mqtt_passwd; + + if ((rc = MQTTClient_connect(fork_state->client , &conn_opts)) == MQTTCLIENT_SUCCESS) + { + //fprintf(stderr,"MQTT CONNECT OK\n"); + fork_state->connected = 1; + return; + } + MQTTClient_destroy(&fork_state->client); + fprintf(stderr,"MQTT CONNECT FAILD\n"); + } + fork_state->connected = 0; + //printf("Failed to connect MQTT, return code %d\n", rc); + //throw std::runtime_error("MQTT Connect error"); +} + +int TIMEOUT = 10000; +static +void mqtt_fork_sent(struct mqtt_fork_state * fork_state, char * data) +{ + int rc; + for(int i=0;;i++) + { + if(!fork_state->connected) mqtt_fork_connect(fork_state); + if(fork_state->connected) + for(int i=0;i<2;i++) + { + MQTTClient_message pubmsg = MQTTClient_message_initializer; + MQTTClient_deliveryToken token; + pubmsg.payload = (void *)data; + pubmsg.payloadlen = strlen(data); + pubmsg.qos = fork_state->state->mqtt_qos; + pubmsg.retained = fork_state->state->mqtt_retained; + //fprintf(stderr,"RETAINED %d QOS %d\n", pubmsg.retained, pubmsg.qos); + MQTTClient_publishMessage(fork_state->client, fork_state->state->mqtt_topic, &pubmsg, &token); + rc = MQTTClient_waitForCompletion(fork_state->client, token, TIMEOUT); + if(rc == MQTTCLIENT_SUCCESS) return; + } + if(i==1) + return; + MQTTClient_destroy(&fork_state->client); + mqtt_fork_connect(fork_state); + } +} + +static +void NONRET mqtt_fork_main(struct mqtt_state * state, int fd) +{ + struct mqtt_fork_state fork_state; + fork_state.fd = fd; + fork_state.connected = 0; + fork_state.state = state; + + while(1) + { + int size; + read(fd,&size,sizeof(int)); + char * in = xmalloc(size); + read(fd,in,size); + //fprintf(stderr,"MQTT |%s|\n",in); + mqtt_fork_sent(&fork_state,in); + } +} + +// ************************* MAIN FUNCTIONS ******* + +static +void mqtt_write_to_mqtt(struct mqtt_state *state, VECTOR(char) out) +{ + if(!out) return; + int size = VSIZE(out); + char * buf = xmalloc(size+sizeof(int)); + memcpy(buf + sizeof(int), out, size); + *(int *) buf = size; + write(state->pipe_fd,buf,size+sizeof(int)); + free(buf); + VFREE(out); +} + +static +void mqtt_show(struct mqtt_state *state, struct osd_line * lines, int num_lines) +{ + mqtt_write_to_mqtt(state,osd_to_string(&state->to_string, lines, num_lines)); +} + +static +void mqtt_clear(struct mqtt_state *state) +{ + mqtt_write_to_mqtt(state,osd_to_string_end_msg(&state->to_string)); +} + +// ************************* NEW ****************** + +static +void mqtt_new_help(FILE * f) +{ + fprintf(f,"\ +Module MQTT help:\n\ +-R, --retained \t\tSending messages will be retained\n\ +-q, --qos=<{}> \t\tSet QOS of sending messages. {0,1,2}\n\ +" OSDD_TO_STRING_HELP "\ +\n\ +"); +} + +static +struct osd_abstract mqtt_new(int argc, char ** argv, Display * nope) +{ + (void)nope; + argc++;argv--; + struct osd_abstract r; + static const char short_opts[] = "+Rq:" OSDD_TO_STRING_SHORTOP; + static const struct option long_opts[] = { + { "retained", no_argument, NULL, 'R' }, + { "qos", required_argument, NULL, 'q' }, + OSDD_TO_STRING_LONGOP + { NULL, 0, NULL, 0 }, + }; + memset(&r,0,sizeof(r)); + struct mqtt_state *state = xmalloc(sizeof(*state)); + memset(state,0,sizeof(state)[0]); + state->mqtt_qos = 1; + state->mqtt_retained = 0; + + osd_to_string_state_init(&state->to_string); + + int opt; + optind = 0; + while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) >= 0) + { + if(!osd_to_string_parse_arg(&state->to_string,opt)) + switch (opt) + { + case 'R': + state->mqtt_retained = 1; + break; + case 'q': + state->mqtt_qos = atoi(optarg); + break; + default: + fprintf(stderr,"Option %c not exist\n\n",opt); + mqtt_new_help(stderr); + exit(0); + } + } + int ind = optind; + if(ind + 4 > argc) + { + fprintf(stderr,"Missing positional argument\n\n"); + mqtt_new_help(stderr); + exit(0); + } + state->mqtt_addres = argv[ind++]; + state->mqtt_user = argv[ind++]; + state->mqtt_passwd = argv[ind++]; + state->mqtt_topic = argv[ind++]; + if(ind != argc) + { + fprintf(stderr,"Too many arguments\n\n"); + mqtt_new_help(stderr); + exit(0); + + } + + r.context = state; + void (*show)(struct mqtt_state*, struct osd_line*, int) = mqtt_show; + r.show = (void (*)(void*, struct osd_line*, int)) show; + void (*clear)(struct mqtt_state*) = mqtt_clear; + r.clear = (void (*)(void*)) clear; + int fd[2]; + pipe(fd); + if(fork() == 0) + { + close (fd[1]); + //write (fd[WRITE], phrase, strlen ( phrase) +1); + mqtt_fork_main(state , fd[0]); + } + close(fd[0]); + fcntl(fd[1], F_SETFL, O_NONBLOCK); + state->pipe_fd = fd[1]; + return r; +} + +// ************************* CREATOR **************************** +struct osd_creator_abstract mqtt_creator_new(void) +{ + struct osd_creator_abstract r; + memset(&r, 0, sizeof(r)); + r.name = "MQTT"; + r.help = mqtt_new_help; + r.new.add_one_osd = mqtt_new; + return r; +} diff --git a/osdd-mqtt.h b/osdd-mqtt.h new file mode 100644 index 0000000000000000000000000000000000000000..bb9bded944896483b2fefa636a910770ff8ce7bd --- /dev/null +++ b/osdd-mqtt.h @@ -0,0 +1,9 @@ +/* + * On-screen Display + * + * (c) 2020--2021 Jiri Kalvoda <jirikalvoda@kam.mff.cuni.cz> + */ + +#include "osdd-set.h" + +struct osd_creator_abstract mqtt_creator_new(void); diff --git a/osdd-run b/osdd-run index 5a90f472b2cf920de6ef242b5fcfafc47b540885..37c054c290d724c8e87c26baf8619c0ac1645a67 100755 --- a/osdd-run +++ b/osdd-run @@ -6,5 +6,16 @@ pkill -f not2osd not2osd & tmp=$(mktemp) echo "Xft.render: False" > $tmp -XENVIRONMENT=$tmp ./osdd -D DISPLAY_BY_OUTPUTS default nolog [ -n a%d ] FILE default log loglog [ -a -l' ' -m'\n' -T' ' -tiso -cterm ~/.osdd_log ] FILE default log loglast [ -l'\n' -tunix -T'\n' -crgbHEX -r ~/.osdd_last ] | bash - +XENVIRONMENT=$tmp \ + ./osdd -D \ + DISPLAY_BY_OUTPUTS default nolog [ -n a%d ] \ + FILE default log loglog [ -a -l' ' -m'\n' -T' ' -tiso -cterm ~/.osdd_log ] \ + FILE default log loglast [ -l'\n' -tunix -T'\n' -crgbHEX -r ~/.osdd_last ] \ + MQTT default mqtt led [ -e'\0' -E -crgbDEC -tunix -R -q0 \ + $(cat ~/.secret/mqtt/rpi0-all.addres) \ + $(cat ~/.secret/mqtt/rpi0-led-include.user) \ + $(cat ~/.secret/mqtt/rpi0-led-include.passwd) \ + osd/arch ] \ + | bash +rm $tmp +pkill -f not2osd diff --git a/osdd-to-string.c b/osdd-to-string.c new file mode 100644 index 0000000000000000000000000000000000000000..c4f6876f135a832fb747eccb43ae0203e27f6c39 --- /dev/null +++ b/osdd-to-string.c @@ -0,0 +1,238 @@ +/* + * On-screen Display + * + * (c) 2020--2021 Jiri Kalvoda <jirikalvoda@kam.mff.cuni.cz> + */ + +#include "osdd-to-string.h" +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <getopt.h> +#include <time.h> + +#include <X11/Xlib.h> +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/extensions/shape.h> +#include <X11/extensions/render.h> +#include <X11/Xft/Xft.h> + +static +char * expand_backslash(char * in) +{ + char * out = xmalloc(strlen(in)+1); + int i=0; + for(;*in;i++,in++) + { + if(in[0]=='\\') + { + switch(in[1]) + { + case 'n': + out[i]='\n'; + break; + case 't': + out[i]='\t'; + break; + case '0': + out[i]='\0'; + break; + default: + out[i]='?'; + break; + } + if(in[1]) in++; + } + else + out[i]=*in; + } + out[i]=0; + return out; +} + +static void replace_no_text(char * in) +{ + for(;*in;in++) + { + if(' '== *in) continue; + if('a'<= *in&& *in<='z') continue; + if('A'<= *in&& *in<='Z') continue; + if('0'<= *in&& *in<='9') continue; + //if(128 <= (unsigned char)*in) continue; + *in='?'; + } +} + + +static void +colorToRGB(char * name, int *r, int *g, int *b) +{ + + Display *d = XOpenDisplay(NULL); + int s = XDefaultScreen(d); + Visual *v = XDefaultVisual(d,s); + Colormap cmap = DefaultColormap(d,s); + + XftColor color; + if (XftColorAllocName(d, v, cmap, name, &color)) + { + typeof(color.color) c = color.color; + *r = c.red; + *g = c.green; + *b = c.blue; + } + else *r=*g=*b=-1; + XftColorFree(d, v, cmap, &color); + XCloseDisplay(d); +} + + +bool osd_to_string_parse_arg(struct osd_to_string_state *state, char arg) +{ + switch(arg) + { + case 'c': + if(!strcmp(optarg,"no")) state->color_mode = FILE_COLOR_NO; else + if(!strcmp(optarg,"rgbDEC")) state->color_mode = FILE_COLOR_RGB_DEC; else + if(!strcmp(optarg,"rgbHEX")) state->color_mode = FILE_COLOR_RGB_HEX; else + if(!strcmp(optarg,"rgbHEXHASHTAG")) state->color_mode = FILE_COLOR_RGB_HASHTAG_HEX; else + if(!strcmp(optarg,"term")) state->color_mode = FILE_COLOR_TERM_RGB; else + if(!strcmp(optarg,"original")) state->color_mode = FILE_COLOR_ORIGINAL; else + { + fprintf(stderr,"Color mode %s not exist\n\n",optarg); + exit(0); + } + break; + case 'l': + free(state->line_separator); + state->line_separator = expand_backslash(optarg); + break; + case 'm': + free(state->msq_separator); + state->msq_separator = expand_backslash(optarg); + break; + case 'r': + state->replace_no_text = 1; + break; + case 't': + if(!strcmp(optarg,"no")) state->time_mode = FILE_TIME_NO; else + if(!strcmp(optarg,"unix")) state->time_mode = FILE_TIME_UNIX; else + if(!strcmp(optarg,"iso")) state->time_mode = FILE_TIME_ISO; else + { + fprintf(stderr,"Time mode %s not exist\n\n",optarg); + exit(0); + } + break; + case 'T': + free(state->time_separator); + state->time_separator = expand_backslash(optarg); + break; + case 'e': + if(state->end_of_mes_by) free(state->end_of_mes_by); + state->end_of_mes_by = expand_backslash(optarg); + break; + case 'E': + state->end_of_mes_time = 1; + break; + default: + return 0; + } + return 1; +} + +static +void osd_to_string_time(struct osd_to_string_state *state, VECTOR(char) * out) +{ + switch(state->time_mode) + { + case FILE_TIME_NO: + break; + case FILE_TIME_UNIX: + vprint(out,"%lld%s",(long long)time(0),state->time_separator); + break; + case FILE_TIME_ISO: + { + time_t t = time(NULL); + struct tm tm = *localtime(&t); + vprint(out,"%04d-%02d-%02d %02d:%02d:%02d%s", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,state->time_separator); + } + break; + } +} + +VECTOR(char) osd_to_string(struct osd_to_string_state *state, struct osd_line * lines, int num_lines) +{ + VECTOR(char) out = NULL; + osd_to_string_time(state, &out); + for(int i=0;i<num_lines;i++) + { + struct osd_line * line = lines+i; + //if(!(line->log & 1)) continue; + if(line->type!=OSD_TYPE_TEXT) continue; + int r,g,b; + VECTOR(char) text=0; + VRESERVE(text,strlen(line->u.text)+1); + char color[30]; + color[0]=0; + char * end_color = ""; + + vprint(&text,"%s",line->u.text); + if(state->replace_no_text) replace_no_text(text); + switch(state->color_mode) + { + case FILE_COLOR_RGB_DEC: + case FILE_COLOR_RGB_HEX: + case FILE_COLOR_RGB_HASHTAG_HEX: + case FILE_COLOR_TERM_RGB: + colorToRGB(line->fg_color,&r,&g,&b); + break; + default: + break; + } + switch(state->color_mode) + { + case FILE_COLOR_RGB_DEC: + sprintf(color,"%d %d %d ",r/256,g/256,b/256); + break; + case FILE_COLOR_RGB_HEX: + sprintf(color,"%02x%02x%02x ",r/256,g/256,b/256); + break; + case FILE_COLOR_RGB_HASHTAG_HEX: + sprintf(color,"#%02x%02x%02x ",r/256,g/256,b/256); + break; + case FILE_COLOR_TERM_RGB: + sprintf(color,"\e[38;2;%d;%d;%dm",r/256,g/256,b/256); + end_color = "\e[0m"; + break; + case FILE_COLOR_ORIGINAL: + sprintf(color,"%s ",line->fg_color); + break; + case FILE_COLOR_NO: + break; + } + vprint(&out,"%s%s%s%s", color, text, end_color,state->line_separator); + VFREE(text); + + } + vprint(&out,"%s",state->msq_separator); + return out; +} + +VECTOR(char) osd_to_string_end_msg(struct osd_to_string_state *state) +{ + if(!state->end_of_mes_by) return 0; + VECTOR(char) out=0; + if(state->end_of_mes_time) + osd_to_string_time(state, &out); + vprint(&out,"%s",state->end_of_mes_by); + return out; +} + +void osd_to_string_state_init(struct osd_to_string_state * state) +{ + state->line_separator = expand_backslash("\\n"); + state->time_separator = expand_backslash("\\n"); + state->msq_separator = expand_backslash(""); + state->end_of_mes_by = 0; +} diff --git a/osdd-to-string.h b/osdd-to-string.h new file mode 100644 index 0000000000000000000000000000000000000000..459712d7b55814e4b33b5933564d324259eeb36a --- /dev/null +++ b/osdd-to-string.h @@ -0,0 +1,58 @@ +/* + * On-screen Display + * + * (c) 2020--2021 Jiri Kalvoda <jirikalvoda@kam.mff.cuni.cz> + */ + +#include "osdd-set.h" +#include "util.h" + +#define OSDD_TO_STRING_LONGOP \ + { "color", required_argument, NULL, 'c' },\ + { "line-separator", required_argument, NULL, 'l' },\ + { "msq-separator", required_argument, NULL, 'm' },\ + { "replace", no_argument, NULL, 'r' },\ + { "time", required_argument, NULL, 't' },\ + { "time-separator", required_argument, NULL, 'T' },\ + { "end", required_argument, NULL, 'e' },\ + +#define OSDD_TO_STRING_SHORTOP \ + "c:l:m:rt:T:e:E" + +#define OSDD_TO_STRING_HELP "\ +-c, --color=<{}>\tSet how to print color of messages {no, rgbDEC, rgbHEX, rgbHEXHASHTAG, term, original}\n\ +-l, --line-separator=<s>Separato of each line.\n\ +-m, --msq-separator=<s>\tSeparato of each message.\n\ +-r, --replace\t\tReplace not alphabet and number in output to '?'\n\ +-t, --time=<{}>\t\tSet how to print actual time {no, unix, iso}\n\ +-T, --time-separator=<s>Separator of time and message text\n\ +-E, --end-time\t\tWrite actual time to end messages (format from -t -T)\n\ +" + +struct osd_to_string_state +{ + char * line_separator; + char * msq_separator; + char * time_separator; + enum { + FILE_COLOR_NO, + FILE_COLOR_RGB_DEC, + FILE_COLOR_RGB_HEX, + FILE_COLOR_RGB_HASHTAG_HEX, + FILE_COLOR_TERM_RGB, + FILE_COLOR_ORIGINAL, + } color_mode; + enum { + FILE_TIME_NO, + FILE_TIME_UNIX, + FILE_TIME_ISO, + } time_mode; + bool replace_no_text; + char * end_of_mes_by; + bool end_of_mes_time; +}; + +VECTOR(char) osd_to_string(struct osd_to_string_state *state, struct osd_line * lines, int num_lines); +VECTOR(char) osd_to_string_end_msg(struct osd_to_string_state *state); +bool osd_to_string_parse_arg(struct osd_to_string_state *state, char arg); +void osd_to_string_state_init(struct osd_to_string_state * state); diff --git a/osdd.c b/osdd.c index 705c330b8085d8e763ac2f12737bb4d8360401de..dd25e5dc8126de873d5685c64396fcf048fdaf39 100644 --- a/osdd.c +++ b/osdd.c @@ -18,8 +18,10 @@ #define DEBUG #include "util.h" #include "osdd-set.h" + #include "display.h" #include "osdd-file.h" +#include "osdd-mqtt.h" static struct osd_set osd; @@ -431,6 +433,7 @@ main(int argc, char **argv) VPB(creator,display_creator_new()); VPB(creator,display_by_outputs_creator_new()); VPB(creator,file_creator_new()); + VPB(creator,mqtt_creator_new()); setlocale(LC_CTYPE, "");