From 41221c42cd441c5f13811b636a0120feb0a4bdbb Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 4 Oct 2020 14:50:29 +0200 Subject: [PATCH] Update to V4 Update to V4 --- CHANGES.md | 9 + README.md | 88 +- effects/add_random.c | 69 ++ effects/blink.c | 50 + effects/brightness.c | 32 + effects/chaser.c | 81 ++ effects/color_change.c | 50 + effects/fade.c | 52 + effects/fill.c | 45 + effects/fly_in.c | 87 ++ effects/fly_out.c | 82 ++ effects/gradient.c | 66 ++ effects/progress.c | 68 ++ effects/rainbow.c | 34 + effects/random_fade_in_out.c | 147 +++ effects/read_jpg.c | 136 +++ effects/read_png.c | 188 ++++ effects/rotate.c | 57 + main.c | 2030 +++++++++------------------------- makefile | 2 +- 20 files changed, 1868 insertions(+), 1505 deletions(-) create mode 100644 CHANGES.md create mode 100644 effects/add_random.c create mode 100644 effects/blink.c create mode 100644 effects/brightness.c create mode 100644 effects/chaser.c create mode 100644 effects/color_change.c create mode 100644 effects/fade.c create mode 100644 effects/fill.c create mode 100644 effects/fly_in.c create mode 100644 effects/fly_out.c create mode 100644 effects/gradient.c create mode 100644 effects/progress.c create mode 100644 effects/rainbow.c create mode 100644 effects/random_fade_in_out.c create mode 100644 effects/read_jpg.c create mode 100644 effects/read_png.c create mode 100644 effects/rotate.c diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..97cf965 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,9 @@ +# Version 4.0 + +* now possible to run multiple threads in the background executing different commands at the same time. +* threads can be started from all input methods (TCP, CLI, named pipe). +* added thread synchronization and termination commands. +* new progress bar effect (progress command). +* readpng, readjpg support for horizontal flip of odd rows. +* no need to enter a value for optional commands, for example: progress 1,1,0,,,,,1 will use default values for arguments in ,,,,, +* do ... loop supported from direct console input (CLI). \ No newline at end of file diff --git a/README.md b/README.md index b3c55ae..240d2d6 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Newer versions require libjpeg-dev and libpng-dev for reading PNG and JPEG image If you don't want to use JPEG or PNG you can disable this using: * `make NO_JPEG=1 NO_PNG=1` -On newer Raspbian (Jessie) operating system the audio output is activated by default, you need to disable this: +On newer Raspbian (>=Jessie) operating system the audio output is activated by default, you need to disable this: You can do this by blacklisting the sound module: `sudo nano /etc/modprobe.d/snd-blacklist.conf` ``` @@ -181,6 +181,7 @@ delay , #start at pixel offset in JPG file (default is 0) , #operator to use, use NOT to reverse image (default is =) #optional argument the delay between rendering next scan line in the jpg file, if 0 only first line is loaded in to memory and no render performed. default 0 + #optional argument to indicate to horizontally flip rows with odd index ``` * `readpng` command can read the pixels from a PNG file and fill them into the LEDs of a channel @@ -195,6 +196,7 @@ delay , #start at pixel offset in JPG file (default is 0) , #operator to use, use NOT to reverse image (default is =) #optional argument the delay between rendering next scan line in the png file, if 0 only first line is loaded in to memory and no render performed. default 0 + #optional argument to indicate to horizontally flip rows with odd index ``` * `blink` command makes a group of leds blink between 2 given colors @@ -284,6 +286,20 @@ Try this as an example for a 300 LED string: NOTICE: first fill entire strip with a color before calling this function (use fill ,) ``` +* `progress` generates a progress bar effect or sets the leds brightness to a given progress value +``` + progress + , #channel number to use + , #direction of progress bar (default 1) start led = 0%, start + len = 100% + , #delay between increments of progress (default 1s), set 0 to not automatically increment and render progress bar but use the value argument + , #start effect at this led position, default 0 + , #number of leds to change starting at start, default length of strip + , #brightness of led that is on default 255 + , #brightness of led that is off default 0 + #set progress to this value (delay must be 0, manual render needed) + NOTICE: first fill entire strip with a color before calling this function (use fill , or rainbow,...) +``` + * `save_state` saves current color and brightness values of a channel to a CSV file, format is: 8 character hex number for color + , + 2 character hex for brightness + new line: WWBBGGRR,FF the CSV file can be loaded with load_state command. @@ -305,19 +321,59 @@ Try this as an example for a 300 LED string: #load this number of LEDs from the file ``` -* `set_thread_exit_type` only if using TCP mode and threads. This will set if the thread should be aborted when next client connects and immediately start execute next commands or - wait until the thread completes execution of the script and start next script received from client. - The client will receive READY + (newline CR + LF) when the previous script exited and it's ready to take new commands. +* It is possible to start threads, a thread will execute commands between thread_start and thread_stop in the background. + Multiple threads can run at the same time by changing the parameter. + will determine the behavior next time you call thread_start with the value of a thread that is still running + if join_type is 0 the thread will be aborted immediately, value of 1 it will wait until the thread completed all commands and then READY + CRLF is returned. +``` +thread_start , + do + rotate 1,1,2 + render + delay 200 + loop +thread_stop +``` + + +* `set_thread_exit_type` This will set if the thread should be aborted when the kill_thread or ini_thread command is executed for the parameter + READY + newline (CR + LF) will be returned when the thread has exited. ``` set_thread_exit_type - , #The thread number, always 0 + , #The thread number (1-63) #exit type: 0 aborts current running thread and immediate execute next commands - 1 wait until previous transmitted commands complete, then start next script + 1 wait until all commands completed, then exit +``` + +* `wait_thread` wait for a given thread to finish all commands (the exit type is ignored here) +``` + wait_thread + #The thread number (1-63) +``` + +* `kill_thread` terminate the given thread_id +``` + kill_thread + #The thread number (1-63) + #exit type: 0 aborts current running thread + 1 wait until all commands completed +``` + +* `wait_signal` waits for a signal from another thread before executing the next command +``` + wait_signal +``` + + +* `signal_thread` send a signal to the given thread_id to continue executing commands +``` + signal_thread + #The thread number (1-63) ``` # Special keywords -You can add `do ... loop` to repeat commands when using a file or TCP connection. +You can add `do ... loop` to repeat commands. For example the commands between `do` and `loop` will be executed 10 times: ``` @@ -383,28 +439,12 @@ do loop 60 ``` -For `do ... loop` to work from a TCP connection we must start a new thread. -This thread will continue to execute the commands when the client disconnects from the TCP/IP connection. -The thread will automatically stop executing the next time the client reconnects (ideal for webservers). - -For example: -``` -thread_start - do - rotate 1,1,2 - render - delay 200 - loop -thread_stop - -``` - # PHP example First start the server program: * `sudo ./ws2812svr -tcp` -Then run the php code from the webserver: +Then run the php code from the webserver (check out the internet how to setup a webserver PHP+APACHE or PHP+NGINX on your Pi): ```PHP //create a rainbow for 10 leds on channel 1: diff --git a/effects/add_random.c b/effects/add_random.c new file mode 100644 index 0000000..d36bc52 --- /dev/null +++ b/effects/add_random.c @@ -0,0 +1,69 @@ +//generates random colors +//random ,,, +void add_random(thread_context * context, char * args){ + char value[MAX_VAL_LEN]; + int channel=0; + unsigned int start=0, len=0; + char component='L'; //L is brightness level + int use_r=1, use_g=1, use_b=1, use_w=1, use_l=1; + + if (is_valid_channel_number(channel)){ + len = ledstring.channel[channel].count;; + } + + args = read_channel(args, & channel); + if (is_valid_channel_number(channel)){ + len = ledstring.channel[channel].count;; + } + args = read_int(args, & start); + args = read_int(args, & len); + if (args!=NULL && *args!=0){ + args = read_val(args, value, MAX_VAL_LEN); + use_r=0, use_g=0, use_b=0, use_w=0, use_l=0; + unsigned char i; + for (i=0;i=ledstring.channel[channel].count) start=0; + if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; + + if (debug) printf("random %d,%d,%d\n", channel, start, len); + + ws2811_led_t * leds = ledstring.channel[channel].leds; + //unsigned int colors = ledstring[channel].color_size; + unsigned char r=0,g=0,b=0,w=0,l=0; + unsigned int i; + for (i=0; i,,,,,, +void blink (thread_context * context, char * args){ + int channel=0, color1=0, color2=0xFFFFFF,delay=1000, count=10; + unsigned int start=0, len=0; + + if (is_valid_channel_number(channel)){ + len = ledstring.channel[channel].count;; + } + + args = read_channel(args, & channel); + if (is_valid_channel_number(channel)){ + len = ledstring.channel[channel].count;; + } + + if (is_valid_channel_number(channel)) args = read_color_arg(args, & color1, ledstring.channel[channel].color_size); + if (is_valid_channel_number(channel)) args = read_color_arg(args, & color2, ledstring.channel[channel].color_size); + args = read_int(args, & delay); + args = read_int(args, & count); + args = read_int(args, & start); + args = read_int(args, & len); + + + if (is_valid_channel_number(channel)){ + + if (start>=ledstring.channel[channel].count) start=0; + if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; + + if (delay<=0) delay=100; + + if (debug) printf("blink %d, %d, %d, %d, %d, %d, %d\n", channel, color1, color2, delay, count, start, len); + + ws2811_led_t * leds = ledstring.channel[channel].leds; + int i,blinks; + for (blinks=0; blinksend_current_command) break; //signal to exit this command + } + }else{ + fprintf(stderr,ERROR_INVALID_CHANNEL); + } +} diff --git a/effects/brightness.c b/effects/brightness.c new file mode 100644 index 0000000..04fb408 --- /dev/null +++ b/effects/brightness.c @@ -0,0 +1,32 @@ +//dims leds +//brightness ,,, (brightness: 0-255) +void brightness(thread_context * context, char * args){ + int channel=0, brightness=255; + unsigned int start=0, len=0; + if (is_valid_channel_number(channel)){ + len = ledstring.channel[channel].count;; + } + + args = read_channel(args, & channel); + if (is_valid_channel_number(channel)) len = ledstring.channel[channel].count;; + args = read_int(args, & brightness); + args = read_int(args, & start); + args = read_int(args, & len); + + if (is_valid_channel_number(channel)){ + if (brightness<0 || brightness>0xFF) brightness=255; + + if (start>=ledstring.channel[channel].count) start=0; + if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; + + if (debug) printf("Changing brightness %d, %d, %d, %d\n", channel, brightness, start, len); + + ws2811_led_t * leds = ledstring.channel[channel].leds; + unsigned int i; + for (i=start;i,,,,,,,,, +//channel = 1 +//duration = time in seconds, or 0 4ever +//color = color to use +//count = number of leds +//direction = scroll direction +//delay = delay between moving the leds, speed +//start = start index led (default 0) +//len = length of the chaser (default enitre strip) +//brightness = brightness of the chasing leds +//loops = max number of chasing loops, 0 = 4ever, default = 0 +void chaser(thread_context * context, char * args){ + unsigned int channel=0, direction=1, duration=10, delay=10, color=255, brightness=255, loops=0; + int i, n, index, len=0, count=1, start=0; + + args = read_channel(args, & channel); + + if (is_valid_channel_number(channel)){ + len = ledstring.channel[channel].count; + args = read_int(args, & duration); + args = read_color_arg(args, & color, ledstring.channel[channel].color_size); + args = read_int(args, & count); + args = read_int(args, & direction); + args = read_int(args, & delay); + args = read_int(args, & start); + args = read_int(args, & len); + args = read_brightness(args, & brightness); + args = read_int(args, & loops); + } + + if (is_valid_channel_number(channel)){ + if (start>=ledstring.channel[channel].count) start=0; + if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; + if (len==0) len = 1; + if (count>len) count = len; + + if (debug) printf("chaser %d %d %d %d %d %d %d %d %d %d\n", channel, duration, color, count, direction, delay, start, len, brightness, loops); + + ws2811_led_t * org_leds = malloc(len * sizeof(ws2811_led_t)); + ws2811_led_t * leds = ledstring.channel[channel].leds; + memcpy(org_leds, &leds[start], len * sizeof(ws2811_led_t)); //create a backup of original leds + + int loop_count=0; + + unsigned int start_time = time(0); + while (((((time(0) - start_time) < duration) || duration==0) && (loops==0 || loops < loop_count)) && context->end_current_command==0){ + ws2811_led_t tmp_led; + + for (n=0;n0 || (index > 0 && index < len)){ + index = (index + len) % len; + leds[start + index].color = color; + leds[start + index].brightness = brightness; + } + } + + ws2811_render(&ledstring); + usleep(delay * 1000); + + for (n=0;n,,,,, +//start and stop = color values on color wheel (0-255) +void color_change(thread_context * context, char * args) { + int channel=0, count=1,start=0,stop=255,startled=0, len=0, duration=10000, delay=10; + + if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; + args = read_channel(args, & channel); + if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; + args = read_int(args, & start); + args = read_int(args, & stop); + args = read_int(args, & duration); + args = read_int(args, & startled); + args = read_int(args, & len); + + if (is_valid_channel_number(channel)){ + if (start<0 || start > 255) start=0; + if (stop<0 || stop > 255) stop = 255; + if (startled<0) startled=0; + if (startled+len> ledstring.channel[channel].count) len = ledstring.channel[channel].count-startled; + + if (debug) printf("color_change %d,%d,%d,%d,%d,%d\n", channel, start, stop, duration, startled, len); + + int numPixels = len; //ledstring.channel[channel].count;; + int i, j; + ws2811_led_t * leds = ledstring.channel[channel].leds; + + unsigned long long start_time = time_ms(); + unsigned long long curr_time = time_ms() - start_time; + + while (curr_time < duration){ + unsigned int color = deg2color(abs(stop-start) * curr_time / duration + start); + + for(i=0; iend_current_command) break; //signal to exit this command + } + + + + }else{ + fprintf(stderr,ERROR_INVALID_CHANNEL); + } +} \ No newline at end of file diff --git a/effects/fade.c b/effects/fade.c new file mode 100644 index 0000000..847af72 --- /dev/null +++ b/effects/fade.c @@ -0,0 +1,52 @@ +//causes a fade effect in time +//fade ,,,,,, +void fade (thread_context * context, char * args){ + int channel=0, brightness=255,step=1,startbrightness=0, endbrightness=255; + unsigned int start=0, len=0, delay=50; + + if (is_valid_channel_number(channel)){ + len = ledstring.channel[channel].count;; + } + + args = read_channel(args, & channel); + if (is_valid_channel_number(channel)){ + len = ledstring.channel[channel].count;; + } + args = read_int(args, & startbrightness); + args = read_int(args, & endbrightness); + args = read_int(args, & delay); + args = read_int(args, & step); + args = read_int(args, & start); + args = read_int(args, & len); + + + if (is_valid_channel_number(channel)){ + if (startbrightness>0xFF) startbrightness=255; + if (endbrightness>0xFF) endbrightness=255; + + if (start>=ledstring.channel[channel].count) start=0; + if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; + + if (step==0) step = 1; + if (startbrightness>endbrightness){ //swap + if (step > 0) step = -step; + }else{ + if (step < 0) step = -step; + } + + if (debug) printf("fade %d, %d, %d, %d, %d, %d, %d\n", channel, startbrightness, endbrightness, delay, step,start,len); + + ws2811_led_t * leds = ledstring.channel[channel].leds; + int i,brightness; + for (brightness=startbrightness; (startbrightness > endbrightness ? brightness>=endbrightness: brightness<=endbrightness) ;brightness+=step){ + for (i=start;iend_current_command) break; //signal to exit this command + } + }else{ + fprintf(stderr,ERROR_INVALID_CHANNEL); + } +} \ No newline at end of file diff --git a/effects/fill.c b/effects/fill.c new file mode 100644 index 0000000..1dac208 --- /dev/null +++ b/effects/fill.c @@ -0,0 +1,45 @@ +//fills leds with certain color +//fill ,,,, +void fill(thread_context * context, char * args){ + char op=0; + int channel=0,start=0,len=-1; + unsigned int fill_color=0; + + args = read_channel(args, & channel); + if (is_valid_channel_number(channel)) args = read_color_arg(args, & fill_color, ledstring.channel[channel].color_size); + args = read_int(args, & start); + args = read_int(args, & len); + args = read_operation(args, & op); + + + if (is_valid_channel_number(channel)){ + if (start<0 || start>=ledstring.channel[channel].count) start=0; + if (len<=0 || (start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; + + if (debug) printf("fill %d,%d,%d,%d,%d\n", channel, fill_color, start, len,op); + + ws2811_led_t * leds = ledstring.channel[channel].leds; + unsigned int i; + for (i=start;i,,,,,,, +//direction = 0/1 fly in from left or right default 1 +//delay = delay in ms between moving pixel, default 10ms +//brightness = the final brightness of the leds that fly in +//start = where to start effect default 0 +//len = number of leds from start default length of strip +//start_brightness = initial brightness for all leds default is 0 (black) +//color = final color of the leds default is to use the current color +//first have to call "fill ," to initialze a color if you leave color default value +void fly_in(thread_context * context, char * args) { + int channel=0,start=0, len=0, brightness=255, delay=10, direction=1, start_brightness=0, use_color=0; + unsigned int color, tmp_color, repl_color; + + args = read_channel(args, & channel); + if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; + args = read_int(args, & direction); + args = read_int(args, & delay); + args = read_int(args, & brightness); + args = read_int(args, & start); + args = read_int(args, & len); + args = read_int(args, & start_brightness); + use_color = (args!=NULL && (*args)!=0); + + if (is_valid_channel_number(channel)){ + args = read_color_arg(args, & color, ledstring.channel[channel].color_size); + if (start<0) start=0; + if (start+len> ledstring.channel[channel].count) len = ledstring.channel[channel].count-start; + + if (debug) printf("fly_in %d,%d,%d,%d,%d,%d,%d,%d,%d\n", channel, direction, delay, brightness, start, len, start_brightness, color, use_color); + + int numPixels = len; //ledstring.channel[channel].count;; + int i, j; + ws2811_led_t * leds = ledstring.channel[channel].leds; + + for (i=0;iend_current_command) break; //signal to exit this command + } + if (direction){ + leds[start+len-i-1].brightness = brightness; + leds[start+len-i-1].color = repl_color; + }else{ + leds[start+i].brightness = brightness; + leds[start+i].color = repl_color; + } + ws2811_render(&ledstring); + usleep(delay * 1000); + if (context->end_current_command) break; //signal to exit this command + } + + }else{ + fprintf(stderr,ERROR_INVALID_CHANNEL); + } +} \ No newline at end of file diff --git a/effects/fly_out.c b/effects/fly_out.c new file mode 100644 index 0000000..25362ca --- /dev/null +++ b/effects/fly_out.c @@ -0,0 +1,82 @@ +//fly out pixels from left or right filling entire string with black or a color/brightness +//fly_out ,,,,,,, +//direction = 0/1 fly out from left or right default 1 +//delay = delay in ms between moving pixel, default 10ms +//brightness = the final brightness of the leds that fly in +//start = where to start effect default 0 +//len = number of leds from start default length of strip +//end_brightness = brightness for all leds at the end, default is 0 = black +//color = final color of the leds default is to use the current color +//first have to call "fill ," to initialze a color in each led before start fly_out +void fly_out(thread_context * context, char * args) { + int channel=0,start=0, len=0, delay=10, direction=1, brightness=255, use_color=0, end_brightness=0; + unsigned int color, tmp_color, repl_color; + + args = read_channel(args, & channel); + if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; + args = read_int(args, & direction); + args = read_int(args, & delay); + args = read_int(args, & brightness); + args = read_int(args, & start); + args = read_int(args, & len); + args = read_int(args, & end_brightness); + use_color = (args!=NULL && (*args)!=0); + + if (is_valid_channel_number(channel)){ + args = read_color_arg(args, & color, ledstring.channel[channel].color_size); + if (start<0) start=0; + if (start+len> ledstring.channel[channel].count) len = ledstring.channel[channel].count-start; + + if (debug) printf("fly_out %d,%d,%d,%d,%d,%d,%d,%d,%d\n", channel, direction, delay, brightness, start, len, end_brightness, color, use_color); + + int numPixels = len; //ledstring.channel[channel].count;; + int i, j; + ws2811_led_t * leds = ledstring.channel[channel].leds; + + ws2811_render(&ledstring); + for (i=0;iend_current_command) break; //signal to exit this command + } + + if (context->end_current_command) break; //signal to exit this command + ws2811_render(&ledstring); + usleep(delay * 1000); + + } + + }else{ + fprintf(stderr,ERROR_INVALID_CHANNEL); + } +} \ No newline at end of file diff --git a/effects/gradient.c b/effects/gradient.c new file mode 100644 index 0000000..d0b4a20 --- /dev/null +++ b/effects/gradient.c @@ -0,0 +1,66 @@ +//generates a brightness gradient pattern of a color component or brightness level +//gradient ,,,,, +void gradient (thread_context * context, char * args){ + char value[MAX_VAL_LEN]; + int channel=0, startlevel=0,endlevel=255; + unsigned int start=0, len=0; + char component='L'; //L is brightness level + + if (is_valid_channel_number(channel)){ + len = ledstring.channel[channel].count;; + } + + args = read_channel(args, & channel); + if (is_valid_channel_number(channel)){ + len = ledstring.channel[channel].count;; + } + args = read_val(args, value, MAX_VAL_LEN); + component=toupper(value[0]); + args = read_int(args, & startlevel); + args = read_int(args, & endlevel); + args = read_int(args, & start); + args = read_int(args, & len); + + + if (is_valid_channel_number(channel)){ + if (startlevel>0xFF) startlevel=255; + if (endlevel>0xFF) endlevel=255; + + if (start>=ledstring.channel[channel].count) start=0; + if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; + + + float step = 1.0*(endlevel-startlevel) / (float)(len-1); + + if (debug) printf("gradient %d, %c, %d, %d, %d,%d\n", channel, component, startlevel, endlevel, start,len); + + ws2811_led_t * leds = ledstring.channel[channel].leds; + + float flevel = startlevel; + int i; + for (i=0; i100) value=100; + if (direction){ + value = (float)len * value / 100.0f; + for (i=0;i default 1 +// default 1, start 0% --> stop 100% (0 to reverse) +// delay to use between increase, default 1s, use 0 to not automatically fill progress bar +// start at this led default 0 +// use this ammount of leds for progress bar +// the brightness value for leds that are turned on, default 255 +// the brightness value for leds that are turned off, default 0 +// set progress bar to this value in % (0-100), use a delay of 0 +void progress(thread_context * context, char * args) { + int channel=0,start=0, len=0, brightness_on=255, brightness_off=0, delay=1000, direction=1; + float value =0.0; + unsigned int color, tmp_color, repl_color; + + args = read_channel(args, & channel); + if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; + args = read_int(args, & direction); + args = read_int(args, & delay); + args = read_int(args, & start); + args = read_int(args, & len); + args = read_int(args, & brightness_on); + args = read_int(args, & brightness_off); + args = read_float(args, & value); + + if (is_valid_channel_number(channel)){ + if (start<0) start=0; + if (start+len> ledstring.channel[channel].count) len = ledstring.channel[channel].count-start; + + if (debug) printf("progress %d,%d,%d,%d,%d,%d,%d,%d,%d\n", context->id, channel, direction, delay, start, len, brightness_on, brightness_off, value); + + int i; + ws2811_led_t * leds = ledstring.channel[channel].leds; + + if (delay==0){ + if (value<0) value=0; + set_progress(leds, direction, start, len, value, brightness_on, brightness_off); + }else{ + for (i=0;i<=len;i++){ + set_progress(leds, direction, start, len, 100.0f * (float)i/(float)len, brightness_on, brightness_off); + ws2811_render(&ledstring); + usleep(delay * 1000); + if (context->end_current_command) break; //signal to exit this command + } + } + + }else{ + fprintf(stderr,ERROR_INVALID_CHANNEL); + } +} \ No newline at end of file diff --git a/effects/rainbow.c b/effects/rainbow.c new file mode 100644 index 0000000..7f66c3d --- /dev/null +++ b/effects/rainbow.c @@ -0,0 +1,34 @@ +//fills pixels with rainbow effect +//count tells how many rainbows you want +//rainbow ,,,,, +//start and stop = color values on color wheel (0-255) +void rainbow(thread_context * context, char * args) { + int channel=0, count=1,start=0,stop=255,startled=0, len=0; + + if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; + args = read_channel(args, & channel); + if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; + args = read_int(args, & count); + args = read_int(args, & start); + args = read_int(args, & stop); + args = read_int(args, & startled); + args = read_int(args, & len); + + if (is_valid_channel_number(channel)){ + if (start<0 || start > 255) start=0; + if (stop<0 || stop > 255) stop = 255; + if (startled<0) startled=0; + if (startled+len> ledstring.channel[channel].count) len = ledstring.channel[channel].count-startled; + + if (debug) printf("Rainbow %d,%d,%d,%d,%d,%d\n", channel, count,start,stop,startled,len); + + int numPixels = len; //ledstring.channel[channel].count;; + int i, j; + ws2811_led_t * leds = ledstring.channel[channel].leds; + for(i=0; i,,,,,,,,,, +//duration = total max duration of effect +//count = max number of leds that will fade in or out at same time +//delay = delay between changes in brightness +//step = ammount of brightness to increase between delays +//inc_dec = if 1 brightness will start at and decrease to initial brightness of the led, else it will start low and go up +//start = start at led position +//len = stop at led position +//color = use specific color, after blink effect color will return to initial +//brightness = max brightness of blinking led +void random_fade_in_out(thread_context * context, char * args){ + unsigned int channel=0, start=0, len=0, count=0, duration=10, delay=1, step=20, sync_delay=0, inc_dec=1, brightness=255,color=0, change_color=0, i; + fade_in_out_led_status *led_status; + + if (is_valid_channel_number(channel)){ + len = ledstring.channel[channel].count;; + } + + args = read_channel(args, & channel); + if (is_valid_channel_number(channel)){ + len = ledstring.channel[channel].count; + count = len / 3; + args = read_int(args, & duration); + args = read_int(args, & count); + args = read_int(args, & delay); + args = read_int(args, & step); + args = read_int(args, & sync_delay); + args = read_int(args, & inc_dec); + args = read_int(args, & brightness); + args = read_int(args, & start); + args = read_int(args, & len); + change_color = args!=NULL && *args!=0; + args = read_color_arg(args, & color, ledstring.channel[channel].color_size); + args = read_brightness(args, & brightness); + + if (start>=ledstring.channel[channel].count) start=0; + if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; + if (count>len) count = len; + + if (debug) printf("random_fade_in_out %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", channel, count, delay, step, sync_delay, inc_dec, brightness, start, len, color); + + led_status = (fade_in_out_led_status *)malloc(count * sizeof(fade_in_out_led_status)); + ws2811_led_t * leds = ledstring.channel[channel].leds; + + ws2811_render(&ledstring); + + for (i=0; iend_current_command==0){ + for (i=0;i= led_status[i].start_brightness)){ + leds[led_status[i].led_index].brightness = led_status[i].start_brightness; + if (change_color) leds[led_status[i].led_index].color = led_status[i].start_color; + int index=find_random_free_led_index(led_status, count, start, len); + if (index!=-1){ + led_status[i].led_index = index; + led_status[i].brightness = brightness; + led_status[i].start_brightness = leds[led_status[i].led_index].brightness; + led_status[i].start_color = leds[led_status[i].led_index].color; + led_status[i].delay = sync_delay ? (rand() % sync_delay) : 0; + } + } + } + }else{ + led_status[i].delay--; + } + } + ws2811_render(&ledstring); + usleep(delay * 1000); + } + + for (i=0;i,,,,,,, +//offset = where to start in JPEG file +//DELAY = delay ms between 2 reads of LEN pixels, default=0 if 0 only bytes at will be read +void readjpg(thread_context * context, char * args){ + struct jpeg_decompress_struct cinfo; + struct my_error_mgr jerr; + + char value[MAX_VAL_LEN]; + int channel=0; + char filename[MAX_VAL_LEN]; + unsigned int start=0, len=1, offset=0, flip_rows=0, row_index=0; + int op=0,delay=0; + + args = read_channel(args, & channel); + if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; + args = read_str(args, filename, sizeof(filename)); + args = read_int(args, &start); + args = read_int(args, &len); + args = read_int(args, &offset); + args = read_str(args, value, sizeof(value)); + if (strcmp(value, "OR")==0) op=1; + else if (strcmp(value, "AND")==0) op=2; + else if (strcmp(value, "XOR")==0) op=3; + else if (strcmp(value, "NOT")==0) op=4; + args = read_int(args, &delay); + if (len<=0) len =1; + + if (is_valid_channel_number(channel)){ + FILE * infile; /* source file */ + int row_stride; /* physical row width in output buffer */ + + + if (debug) printf("readjpg %d,%s,%d,%d,%d,%d,%d\n", channel, filename, start, len, offset, op, delay); + + if ((infile = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "Error: can't open %s\n", filename); + return; + } + + // We set up the normal JPEG error routines, then override error_exit. + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + // Establish the setjmp return context for my_error_exit to use. + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + jpeg_destroy_decompress(&cinfo); + fclose(infile); + return; + } + + // Now we can initialize the JPEG decompression object. + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, infile); + + jpeg_read_header(&cinfo, TRUE); + jpeg_start_decompress(&cinfo); + + row_stride = cinfo.output_width * cinfo.output_components; + + JSAMPARRAY buffer; // Output row buffer + int i=0,jpg_idx=0,led_idx; //pixel index for current row, jpeg image, led string + buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + ws2811_led_t * leds = ledstring.channel[channel].leds; + + if (start>=ledstring.channel[channel].count) start=0; + if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; + + led_idx=start; //start at this led index + + int eofstring=0; + while (eofstring==0 && cinfo.output_scanline < cinfo.output_height && context->end_current_command==0) { + jpeg_read_scanlines(&cinfo, buffer, 1); + for(i=0;i=offset){ //check jpeg offset + unsigned char r,g,b; + r = buffer[0][i*cinfo.output_components]; + g = buffer[0][i*cinfo.output_components+1]; + b = buffer[0][i*cinfo.output_components+2]; + if (cinfo.output_components==1){ //grayscale image + g = r; + b = r; + } + if (flip_rows){ //this will horizontaly flip the row + if (row_index & 1){ + led_idx = start + cinfo.image_width * row_index + (cinfo.image_width - i); + } + } + if (led_idx= start + len){ + if (delay!=0){//reset led index if we are at end of led string and delay + led_idx=start; + row_index=0; + ws2811_render(&ledstring); + usleep(delay * 1000); + }else{ + eofstring=1; + break; + } + } + } + if (context->end_current_command) break; //signal to exit this command + jpg_idx++; + } + row_index++; + } + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fclose(infile); + } +} \ No newline at end of file diff --git a/effects/read_png.c b/effects/read_png.c new file mode 100644 index 0000000..b24910f --- /dev/null +++ b/effects/read_png.c @@ -0,0 +1,188 @@ +//read PNG image and put pixel data to LEDS +//readpng ,,,,,,,, +//offset = where to start in PNG file +//backcolor = color to use for transparent area, FF0000 = RED +//P = use the PNG backcolor (default) +//W = use the alpha data for the White leds in RGBW LED strips +//DELAY = delay ms between 2 reads of LEN pixels, default=0 if 0 only bytes at will be read +void readpng(thread_context * context,char * args){ + struct jpeg_decompress_struct cinfo; + struct my_error_mgr jerr; + + char value[MAX_VAL_LEN]; + int channel=0; + char filename[MAX_VAL_LEN]; + unsigned int start=0, len=0, offset=0,flip_rows=0; + int op=0; + int backcolor=0; + int backcolortype=0; //0 = use PNG backcolor, 1 = use given backcolor, 2 = no backcolor but use alpha for white leds + int delay=0; + int row_index=0; + + args = read_channel(args, & channel); + if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; + args = read_str(args, filename, sizeof(filename)); + args = read_str(args, value, sizeof(filename)); + if (strlen(value)>=6){ + if (is_valid_channel_number(channel)){ + read_color(value, & backcolor, ledstring.channel[channel].color_size); + backcolortype=1; + } + }else if (strcmp(value, "W")==0){ + backcolortype=2; + } + args = read_int(args, &start); + args = read_int(args, &len); + args = read_int(args, &offset); + args = read_str(args, value, sizeof(value)); + if (strcmp(value, "OR")==0) op=1; + else if (strcmp(value, "AND")==0) op=2; + else if (strcmp(value, "XOR")==0) op=3; + else if (strcmp(value, "NOT")==0) op=4; + args = read_int(args, &delay); + args = read_int(args, &flip_rows); + + if (is_valid_channel_number(channel)){ + FILE * infile; /* source file */ + ulg image_width, image_height, image_rowbytes; + int image_channels,rc; + uch *image_data; + uch bg_red=0, bg_green=0, bg_blue=0; + + if (start<0) start=0; + if (start+len> ledstring.channel[channel].count) len = ledstring.channel[channel].count-start; + + if (debug) printf("readpng %d,%s,%d,%d,%d,%d,%d,%d\n", channel, filename, backcolor, start, len,offset,op, delay); + + if ((infile = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "Error: can't open %s\n", filename); + return; + } + + if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) { + switch (rc) { + case 1: + fprintf(stderr, "[%s] is not a PNG file: incorrect signature.\n", filename); + break; + case 2: + fprintf(stderr, "[%s] has bad IHDR (libpng longjmp).\n", filename); + break; + case 4: + fprintf(stderr, "Read PNG insufficient memory.\n"); + break; + default: + fprintf(stderr, "Unknown readpng_init() error.\n"); + break; + } + fclose(infile); + return; + } + + //get the background color (for transparency support) + if (backcolortype==0){ + if (readpng_get_bgcolor(&bg_red, &bg_green, &bg_blue) > 1){ + readpng_cleanup(TRUE); + fclose(infile); + fprintf(stderr, "libpng error while checking for background color\n"); + return; + } + }else{ + bg_red = get_red(backcolor); + bg_green = get_green(backcolor); + bg_blue = get_blue(backcolor); + } + + //read entire image data + image_data = readpng_get_image(2.2, &image_channels, &image_rowbytes); + + if (image_data) { + int row=0, led_idx=0, png_idx=0, i=0; + uch r, g, b, a; + uch *src; + + ws2811_led_t * leds = ledstring.channel[channel].leds; + + if (start>=ledstring.channel[channel].count) start=0; + if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; + + led_idx=start; //start at this led index + //load all pixels + for (row = 0; row < image_height; row++) { + src = image_data + row * image_rowbytes; + + for (i = image_width; i > 0; --i) { + r = *src++; + g = *src++; + b = *src++; + + if (image_channels != 3){ + a = *src++; + if (backcolortype!=2){ + r = alpha_component(r, bg_red,a); + g = alpha_component(g, bg_green,a); + b = alpha_component(b, bg_blue,a); + } + } + if (png_idx>=offset){ + if (debug) printf("led %d= r %d,g %d,b %d,a %d, PNG channels=%d, PNG idx=%d\n", led_idx, r, g, b, a,image_channels,png_idx); + if (led_idx < start + len){ + int fill_color; + if (backcolortype==2 && ledstring.channel[channel].color_size>3){ + fill_color=color_rgbw(r,g,b,a); + }else{ + fill_color=color(r,g,b); + } + + if (flip_rows){ //this will horizontaly flip the row + if (row_index & 1){ + led_idx = start + image_width * row_index + (image_width - i); + } + } + + switch (op){ + case 0: + leds[led_idx].color=fill_color; + break; + case 1: + leds[i].color|=fill_color; + break; + case 2: + leds[i].color&=fill_color; + break; + case 3: + leds[i].color^=fill_color; + break; + case 4: + leds[i].color=~fill_color; + break; + } + + } + led_idx++; + if ( led_idx>=start + len){ + if (delay!=0){//reset led index if we are at end of led string and delay + led_idx=start; + row_index=0; + ws2811_render(&ledstring); + usleep(delay * 1000); + }else{ + row = image_height; //exit reading + i=0; + break; + } + } + } + png_idx++; + if (context->end_current_command) break; //signal to exit this command + } + if (context->end_current_command) break; + row_index++; + } + readpng_cleanup(TRUE); + }else{ + readpng_cleanup(FALSE); + fprintf(stderr, "Unable to decode PNG image\n"); + } + fclose(infile); + } +} \ No newline at end of file diff --git a/effects/rotate.c b/effects/rotate.c new file mode 100644 index 0000000..d8594df --- /dev/null +++ b/effects/rotate.c @@ -0,0 +1,57 @@ +void rotate_strip(thread_context * context, int channel, int nplaces, int direction, unsigned int new_color, int use_new_color, int new_brightness){ + ws2811_led_t tmp_led; + ws2811_led_t * leds = ledstring.channel[channel].leds; + unsigned int led_count = ledstring.channel[channel].count; + unsigned int n,i; + for(n=0;n0;i--){ + leds[i] = leds[i-1]; + } + if (use_new_color){ + leds[0].color=new_color; + leds[0].brightness=new_brightness; + }else{ + leds[0]=tmp_led; + } + } + } +} + +//shifts all colors 1 position +//rotate ,,,, +//if new color is set then the last led will have this color instead of the color of the first led +void rotate(thread_context * context, char * args){ + int channel=0, nplaces=1, direction=1; + unsigned int new_color=0, new_brightness=255; + int use_new_color=0; + + args = read_channel(args, & channel); + args = read_int(args, & nplaces); + args = read_int(args, & direction); + if (is_valid_channel_number(channel)){ + use_new_color= (args!=NULL && *args!=0); + args = read_color_arg(args, & new_color, ledstring.channel[channel].color_size); + read_brightness(args, & new_brightness); + } + + if (debug) printf("Rotate %d %d %d %d %d\n", channel, nplaces, direction, new_color, new_brightness); + + if (is_valid_channel_number(channel)){ + rotate_strip(context, channel, nplaces, direction, new_color, use_new_color, new_brightness); + }else{ + fprintf(stderr,ERROR_INVALID_CHANNEL); + } +} \ No newline at end of file diff --git a/main.c b/main.c index 5ccc751..43db4f6 100755 --- a/main.c +++ b/main.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "ws2811.h" #define DEFAULT_DEVICE_FILE "/dev/ws281x" @@ -23,7 +24,8 @@ #define MAX_KEY_LEN 255 #define MAX_VAL_LEN 255 -#define MAX_LOOPS 32 +#define MAX_LOOPS 64 +#define MAX_THREADS 64 #define MODE_STDIN 0 #define MODE_NAMED_PIPE 1 @@ -96,21 +98,16 @@ typedef struct { } do_loop; -FILE * input_file; //the named pipe handle -char * command_line; //current command line -char * named_pipe_file; //holds named pipe file name -char * initialize_cmd=NULL; //initialze command -int command_index; //current position -int command_line_size; //max bytes in command line -int exit_program=0; //set to 1 to exit the program -int mode; //mode we operate in (TCP, named pipe, file, stdin) -do_loop loops[MAX_LOOPS]={0}; //positions of 'do' in file loop, max 32 recursive loops -int loop_index=0; //current loop index -int debug=0; //set to 1 to enable debug output +FILE * input_file; //the named pipe handle +char * named_pipe_file; //holds named pipe file name +char * initialize_cmd=NULL; //initialze command +int mode=MODE_STDIN; //mode we operate in (TCP, named pipe, file, stdin) +int debug=0; //set to 1 to enable debug output +volatile int exit_program=0; //set to 1 to exit the program //for TCP mode int sockfd; //socket that listens -int active_socket; //current active connection socket +int active_socket=-1; //current active connection socket socklen_t clilen; struct sockaddr_in serv_addr, cli_addr; int port=0; @@ -118,43 +115,88 @@ int port=0; #define JOIN_THREAD_CANCEL 0 #define JOIN_THREAD_WAIT 1 +typedef struct { + pthread_t thread; //a thread that will repeat code after client closed connection + pthread_mutex_t sync_mutex; + pthread_cond_t sync_cond; //send signal here to continue thread + volatile int waiting_signal; //1 if this thread waits for a signal to continue + volatile int end_current_command; //1 if we need to end current command + char * thread_data; //holds commands to execute in separate thread + int id; //id of thread context + int thread_read_index; //read position + int thread_write_index; //write position + int thread_data_size; //buffer size + int write_to_thread_buffer; //write to thread buffer with this index + int write_to_own_buffer; //1 to write commands to own buffer + volatile int thread_running; //becomes 1 there is a thread running, set to 0 to terminate thread + int thread_join_type; //determines if we need to wait for thread to exit or just kill it on next thread_start command + + int command_index; //current position + char * command_line; //current command line + int command_line_size; //max bytes in command line + + do_loop loops[MAX_LOOPS]; //positions of 'do' in file loop, max 32 nested loops + int loop_index; //current loop index -//for TCP/IP multithreading -volatile int end_current_command=0; //1 if current command must be exited because thread must exit -char * thread_data=NULL; //holds command to execute in separate thread (TCP/IP only) -int thread_read_index=0; //read position -int thread_write_index=0; //write position -int thread_data_size=0; //buffer size -volatile int thread_running=0; //becomes 1 there is a thread running, set to 0 to terminate thread -int write_to_thread_buffer=0; //becomes 1 if we need to write to thread buffer -int start_thread=0; //becomes 1 after the thread_stop command and tells the program to start the thread on disconnect of the TCP/IP connection -int thread_active=0; //1 if a thread is active and we need to join it -int join_thread_type=JOIN_THREAD_CANCEL; //determines how next connection should end previous thread, if JOIN_THREAD_NONE no thread is running + int do_count; //only used for do ... loop in main thread/file + int loop_count; + int execute_main_do_loop; //if 1 the start_loop will execute the do command instead of start writing to internal buffer, only in case of the main thread +} thread_context; -//pthread_mutex_t mutex_fifo_queue; -pthread_t thread; //a thread that will repeat code after client closed connection +thread_context threads[MAX_THREADS+1]; -ws2811_t ledstring; +ws2811_t ledstring; //led string object -void process_character(char c); +void process_character(thread_context * context, char c); //handles exit of program with CTRL+C static void ctrl_c_handler(int signum){ - exit_program=1; + int i; + + signal(signum, SIG_IGN); + + if (threads[0].thread_running){ //interrupt loop in main thread + threads[0].end_current_command=1; + threads[0].thread_running=0; + signal(SIGINT, ctrl_c_handler); + }else{ //exit the program + for (i=0; icommand_line!=NULL) free(context->command_line); + context->command_line = (char *) malloc(size+1); + context->command_line_size = size; + context->command_index = 0; } unsigned char get_red(int color){ @@ -254,7 +296,16 @@ char * read_int(char * args, int * value){ char svalue[MAX_VAL_LEN]; if (args!=NULL && *args!=0){ args = read_val(args, svalue, MAX_VAL_LEN); - *value = atoi(svalue); + if (svalue[0]) *value = atoi(svalue); + } + return args; +} + +char * read_float(char * args, float * value){ + char svalue[MAX_VAL_LEN]; + if (args!=NULL && *args!=0){ + args = read_val(args, svalue, MAX_VAL_LEN); + if (svalue[0]) *value = atof(svalue); } return args; } @@ -268,7 +319,7 @@ char * read_uint(char * args, unsigned int * value){ char svalue[MAX_VAL_LEN]; if (args!=NULL && *args!=0){ args = read_val(args, svalue, MAX_VAL_LEN); - *value = (unsigned int) (strtoul(svalue,NULL, 10) & 0xFFFFFFFF); + if (svalue[0]) *value = (unsigned int) (strtoul(svalue,NULL, 10) & 0xFFFFFFFF); } return args; } @@ -288,7 +339,7 @@ char * read_color(char * args, unsigned int * out_color, unsigned int color_size unsigned char color_string[8]; unsigned int color_string_idx=0; if (args!=NULL && *args!=0){ - *out_color = 0; + //*out_color = 0; while (*args!=0 && color_string_idx, -void init_channels(char * args){ +void init_channels(thread_context * context, char * args){ char value[MAX_VAL_LEN]; int frequency=WS2811_TARGET_FREQ, dma=10; if (ledstring.device!=NULL) ws2811_fini(&ledstring); - if (args!=NULL){ - args = read_val(args, value, MAX_VAL_LEN); - frequency=atoi(value); - if (*args!=0){ - args = read_val(args, value, MAX_VAL_LEN); - dma=atoi(value); - } - } - + args = read_int(args, & frequency); + args = read_int(args, &dma); + ledstring.dmanum=dma; ledstring.freq=frequency; if (debug) printf("Init ws2811 %d,%d\n", frequency, dma); @@ -389,27 +434,46 @@ void init_channels(char * args){ //changes the global channel brightness //global_brightness , -void global_brightness(char * args){ - if (args!=NULL){ - char value[MAX_VAL_LEN]; - args = read_val(args, value, MAX_VAL_LEN); - int channel = atoi(value)-1; - if (*args!=0){ - args = read_val(args, value, MAX_VAL_LEN); - int brightness = atoi(value); - if (is_valid_channel_number(channel)){ - ledstring.channel[channel].brightness=brightness; - if(debug) printf("Global brightness %d, %d\n", channel, brightness); - }else{ - fprintf(stderr,ERROR_INVALID_CHANNEL); - } - } +void global_brightness(thread_context * context, char * args){ + int channel = 1, brightness=255; + args = read_channel(args, &channel); + args = read_int(args, & brightness); + if (is_valid_channel_number(channel)){ + ledstring.channel[channel].brightness=brightness; + if(debug) printf("Global brightness %d, %d\n", channel, brightness); + }else{ + fprintf(stderr,ERROR_INVALID_CHANNEL); } } +//expands thread command buffer (increase size by 2 times) +//thread_context is the context that needs memory expansion +void expand_thread_data_buffer(thread_context * context){ + if (context->thread_data_size==0){ + context->thread_data_size=DEFAULT_BUFFER_SIZE; + context->thread_data = (char *) malloc(context->thread_data_size); + }else{ + context->thread_data_size = context->thread_data_size * 2; + char * tmp_buffer = (char *) malloc(context->thread_data_size); + memcpy((void*) tmp_buffer, (void*)context->thread_data, context->thread_data_size); + free(context->thread_data); + context->thread_data = tmp_buffer; + } +} + +//adds data to the thread buffer +//thread_context is the thread to write to +void write_thread_buffer (thread_context * context, char c){ + if (context->thread_data_size==0) expand_thread_data_buffer(context); + context->thread_data[context->thread_write_index] = c; + context->thread_write_index++; + if (context->thread_write_index==context->thread_data_size) expand_thread_data_buffer(context); + context->thread_data[context->thread_write_index]=0; +} + //sets the ws2811 channels //setup channel, led_count, type, invert, global_brightness, GPIO -void setup_ledstring(char * args){ +void setup_ledstring(thread_context * context, char * args){ int channel=0, led_count=10, type=0, invert=0, brightness=255, GPIO=18; const int led_types[]={WS2811_STRIP_RGB, //0 @@ -464,7 +528,7 @@ void setup_ledstring(char * args){ max_size = size; } } - malloc_command_line(max_size); //allocate memory for full render data + malloc_command_line(context, max_size); //allocate memory for full render data }else{ if (debug) printf("Channel number %d\n", channel); fprintf(stderr,"Invalid channel number, use channels to initialize total channels you want to use.\n"); @@ -491,7 +555,7 @@ void print_settings(){ //optional the colors for leds: //AABBCC are RGB colors for first led //DDEEFF is RGB for second led,... -void render(char * args){ +void render(thread_context * context, char * args){ int channel=0; int r,g,b,w; int size; @@ -514,898 +578,52 @@ void render(char * args){ int led_count = ledstring.channel[channel].count; int led_index = start % led_count; int color_count = ledstring.channel[channel].color_size; - ws2811_led_t * leds = ledstring.channel[channel].leds; - - while (*args!=0){ - unsigned int color=0; - args = read_color(args, & color, color_count); - leds[led_index].color = color; - led_index++; - if (led_index>=led_count) led_index=0; - } - } - } - } - if (is_valid_channel_number(channel)){ - ws2811_render(&ledstring); - }else{ - fprintf(stderr,ERROR_INVALID_CHANNEL); - } -} - -void rotate_strip(int channel, int nplaces, int direction, unsigned int new_color, int use_new_color, int new_brightness){ - ws2811_led_t tmp_led; - ws2811_led_t * leds = ledstring.channel[channel].leds; - unsigned int led_count = ledstring.channel[channel].count; - unsigned int n,i; - for(n=0;n0;i--){ - leds[i] = leds[i-1]; - } - if (use_new_color){ - leds[0].color=new_color; - leds[0].brightness=new_brightness; - }else{ - leds[0]=tmp_led; - } - } - } -} - -//shifts all colors 1 position -//rotate ,,,, -//if new color is set then the last led will have this color instead of the color of the first led -void rotate(char * args){ - int channel=0, nplaces=1, direction=1; - unsigned int new_color=0, new_brightness=255; - int use_new_color=0; - - args = read_channel(args, & channel); - args = read_int(args, & nplaces); - args = read_int(args, & direction); - if (is_valid_channel_number(channel)){ - use_new_color= (args!=NULL && *args!=0); - args = read_color_arg(args, & new_color, ledstring.channel[channel].color_size); - read_brightness(args, & new_brightness); - } - - if (debug) printf("Rotate %d %d %d %d %d\n", channel, nplaces, direction, new_color, new_brightness); - - if (is_valid_channel_number(channel)){ - rotate_strip(channel, nplaces, direction, new_color, use_new_color, new_brightness); - }else{ - fprintf(stderr,ERROR_INVALID_CHANNEL); - } -} - -//fills pixels with rainbow effect -//count tells how many rainbows you want -//rainbow ,,,,, -//start and stop = color values on color wheel (0-255) -void rainbow(char * args) { - int channel=0, count=1,start=0,stop=255,startled=0, len=0; - - if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; - args = read_channel(args, & channel); - if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; - args = read_int(args, & count); - args = read_int(args, & start); - args = read_int(args, & stop); - args = read_int(args, & startled); - args = read_int(args, & len); - - if (is_valid_channel_number(channel)){ - if (start<0 || start > 255) start=0; - if (stop<0 || stop > 255) stop = 255; - if (startled<0) startled=0; - if (startled+len> ledstring.channel[channel].count) len = ledstring.channel[channel].count-startled; - - if (debug) printf("Rainbow %d,%d,%d,%d,%d,%d\n", channel, count,start,stop,startled,len); - - int numPixels = len; //ledstring.channel[channel].count;; - int i, j; - ws2811_led_t * leds = ledstring.channel[channel].leds; - for(i=0; i,,,, -void fill(char * args){ - char op=0; - int channel=0,start=0,len=-1; - unsigned int fill_color=0; - - args = read_channel(args, & channel); - if (is_valid_channel_number(channel)) args = read_color_arg(args, & fill_color, ledstring.channel[channel].color_size); - args = read_int(args, & start); - args = read_int(args, & len); - args = read_operation(args, & op); - - - if (is_valid_channel_number(channel)){ - if (start<0 || start>=ledstring.channel[channel].count) start=0; - if (len<=0 || (start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; - - if (debug) printf("fill %d,%d,%d,%d,%d\n", channel, fill_color, start, len,op); - - ws2811_led_t * leds = ledstring.channel[channel].leds; - unsigned int i; - for (i=start;i,,, (brightness: 0-255) -void brightness(char * args){ - int channel=0, brightness=255; - unsigned int start=0, len=0; - if (is_valid_channel_number(channel)){ - len = ledstring.channel[channel].count;; - } - - args = read_channel(args, & channel); - if (is_valid_channel_number(channel)) len = ledstring.channel[channel].count;; - args = read_int(args, & brightness); - args = read_int(args, & start); - args = read_int(args, & len); - - - if (is_valid_channel_number(channel)){ - if (brightness<0 || brightness>0xFF) brightness=255; - - if (start>=ledstring.channel[channel].count) start=0; - if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; - - if (debug) printf("Changing brightness %d, %d, %d, %d\n", channel, brightness, start, len); - - ws2811_led_t * leds = ledstring.channel[channel].leds; - unsigned int i; - for (i=start;i,,,,,, -void fade (char * args){ - int channel=0, brightness=255,step=1,startbrightness=0, endbrightness=255; - unsigned int start=0, len=0, delay=50; - - if (is_valid_channel_number(channel)){ - len = ledstring.channel[channel].count;; - } - - args = read_channel(args, & channel); - if (is_valid_channel_number(channel)){ - len = ledstring.channel[channel].count;; - } - args = read_int(args, & startbrightness); - args = read_int(args, & endbrightness); - args = read_int(args, & delay); - args = read_int(args, & step); - args = read_int(args, & start); - args = read_int(args, & len); - - - if (is_valid_channel_number(channel)){ - if (startbrightness>0xFF) startbrightness=255; - if (endbrightness>0xFF) endbrightness=255; - - if (start>=ledstring.channel[channel].count) start=0; - if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; - - if (step==0) step = 1; - if (startbrightness>endbrightness){ //swap - if (step > 0) step = -step; - }else{ - if (step < 0) step = -step; - } - - if (debug) printf("fade %d, %d, %d, %d, %d, %d, %d\n", channel, startbrightness, endbrightness, delay, step,start,len); - - ws2811_led_t * leds = ledstring.channel[channel].leds; - int i,brightness; - for (brightness=startbrightness; (startbrightness > endbrightness ? brightness>=endbrightness: brightness<=endbrightness) ;brightness+=step){ - for (i=start;i,,,,,, -void blink (char * args){ - int channel=0, color1=0, color2=0xFFFFFF,delay=1000, count=10; - unsigned int start=0, len=0; - - if (is_valid_channel_number(channel)){ - len = ledstring.channel[channel].count;; - } - - args = read_channel(args, & channel); - if (is_valid_channel_number(channel)){ - len = ledstring.channel[channel].count;; - } - - if (is_valid_channel_number(channel)) args = read_color_arg(args, & color1, ledstring.channel[channel].color_size); - if (is_valid_channel_number(channel)) args = read_color_arg(args, & color2, ledstring.channel[channel].color_size); - args = read_int(args, & delay); - args = read_int(args, & count); - args = read_int(args, & start); - args = read_int(args, & len); - - - if (is_valid_channel_number(channel)){ - - if (start>=ledstring.channel[channel].count) start=0; - if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; - - if (delay<=0) delay=100; - - if (debug) printf("blink %d, %d, %d, %d, %d, %d, %d\n", channel, color1, color2, delay, count, start, len); - - ws2811_led_t * leds = ledstring.channel[channel].leds; - int i,blinks; - for (blinks=0; blinks,,,,, -void gradient (char * args){ - char value[MAX_VAL_LEN]; - int channel=0, startlevel=0,endlevel=255; - unsigned int start=0, len=0; - char component='L'; //L is brightness level - - if (is_valid_channel_number(channel)){ - len = ledstring.channel[channel].count;; - } - - args = read_channel(args, & channel); - if (is_valid_channel_number(channel)){ - len = ledstring.channel[channel].count;; - } - args = read_val(args, value, MAX_VAL_LEN); - component=toupper(value[0]); - args = read_int(args, & startlevel); - args = read_int(args, & endlevel); - args = read_int(args, & start); - args = read_int(args, & len); - - - if (is_valid_channel_number(channel)){ - if (startlevel>0xFF) startlevel=255; - if (endlevel>0xFF) endlevel=255; - - if (start>=ledstring.channel[channel].count) start=0; - if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; - - - float step = 1.0*(endlevel-startlevel) / (float)(len-1); - - if (debug) printf("gradient %d, %c, %d, %d, %d,%d\n", channel, component, startlevel, endlevel, start,len); - - ws2811_led_t * leds = ledstring.channel[channel].leds; - - float flevel = startlevel; - int i; - for (i=0; i,,, -void add_random(char * args){ - char value[MAX_VAL_LEN]; - int channel=0; - unsigned int start=0, len=0; - char component='L'; //L is brightness level - int use_r=1, use_g=1, use_b=1, use_w=1, use_l=1; - - if (is_valid_channel_number(channel)){ - len = ledstring.channel[channel].count;; - } - - args = read_channel(args, & channel); - if (is_valid_channel_number(channel)){ - len = ledstring.channel[channel].count;; - } - args = read_int(args, & start); - args = read_int(args, & len); - if (args!=NULL && *args!=0){ - args = read_val(args, value, MAX_VAL_LEN); - use_r=0, use_g=0, use_b=0, use_w=0, use_l=0; - unsigned char i; - for (i=0;i=ledstring.channel[channel].count) start=0; - if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; - - if (debug) printf("random %d,%d,%d\n", channel, start, len); - - ws2811_led_t * leds = ledstring.channel[channel].leds; - //unsigned int colors = ledstring[channel].color_size; - unsigned char r=0,g=0,b=0,w=0,l=0; - unsigned int i; - for (i=0; i,,,,,,,,,, -//duration = total max duration of effect -//count = max number of leds that will fade in or out at same time -//delay = delay between changes in brightness -//step = ammount of brightness to increase between delays -//inc_dec = if 1 brightness will start at and decrease to initial brightness of the led, else it will start low and go up -//start = start at led position -//len = stop at led position -//color = use specific color, after blink effect color will return to initial -//brightness = max brightness of blinking led -void random_fade_in_out(char * args){ - unsigned int channel=0, start=0, len=0, count=0, duration=10, delay=1, step=20, sync_delay=0, inc_dec=1, brightness=255,color=0, change_color=0, i; - fade_in_out_led_status *led_status; - - if (is_valid_channel_number(channel)){ - len = ledstring.channel[channel].count;; - } - - args = read_channel(args, & channel); - if (is_valid_channel_number(channel)){ - len = ledstring.channel[channel].count; - count = len / 3; - args = read_int(args, & duration); - args = read_int(args, & count); - args = read_int(args, & delay); - args = read_int(args, & step); - args = read_int(args, & sync_delay); - args = read_int(args, & inc_dec); - args = read_int(args, & brightness); - args = read_int(args, & start); - args = read_int(args, & len); - change_color = args!=NULL && *args!=0; - args = read_color_arg(args, & color, ledstring.channel[channel].color_size); - args = read_brightness(args, & brightness); - - if (start>=ledstring.channel[channel].count) start=0; - if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; - if (count>len) count = len; - - if (debug) printf("random_fade_in_out %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", channel, count, delay, step, sync_delay, inc_dec, brightness, start, len, color); - - led_status = (fade_in_out_led_status *)malloc(count * sizeof(fade_in_out_led_status)); - ws2811_led_t * leds = ledstring.channel[channel].leds; - - ws2811_render(&ledstring); - - for (i=0; i= led_status[i].start_brightness)){ - leds[led_status[i].led_index].brightness = led_status[i].start_brightness; - if (change_color) leds[led_status[i].led_index].color = led_status[i].start_color; - int index=find_random_free_led_index(led_status, count, start, len); - if (index!=-1){ - led_status[i].led_index = index; - led_status[i].brightness = brightness; - led_status[i].start_brightness = leds[led_status[i].led_index].brightness; - led_status[i].start_color = leds[led_status[i].led_index].color; - led_status[i].delay = sync_delay ? (rand() % sync_delay) : 0; - } - } - } - }else{ - led_status[i].delay--; - } - } - ws2811_render(&ledstring); - usleep(delay * 1000); - } - - for (i=0;i,,,,,,,,, -//channel = 1 -//duration = time in seconds, or 0 4ever -//color = color to use -//count = number of leds -//direction = scroll direction -//delay = delay between moving the leds, speed -//start = start index led (default 0) -//len = length of the chaser (default enitre strip) -//brightness = brightness of the chasing leds -//loops = max number of chasing loops, 0 = 4ever, default = 0 -void chaser(char * args){ - unsigned int channel=0, direction=1, duration=10, delay=10, color=255, brightness=255, loops=0; - int i, n, index, len=0, count=1, start=0; - - args = read_channel(args, & channel); - - if (is_valid_channel_number(channel)){ - len = ledstring.channel[channel].count; - args = read_int(args, & duration); - args = read_color_arg(args, & color, ledstring.channel[channel].color_size); - args = read_int(args, & count); - args = read_int(args, & direction); - args = read_int(args, & delay); - args = read_int(args, & start); - args = read_int(args, & len); - args = read_brightness(args, & brightness); - args = read_int(args, & loops); - } - - if (is_valid_channel_number(channel)){ - if (start>=ledstring.channel[channel].count) start=0; - if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; - if (len==0) len = 1; - if (count>len) count = len; - - if (debug) printf("chaser %d %d %d %d %d %d %d %d %d %d\n", channel, duration, color, count, direction, delay, start, len, brightness, loops); - - ws2811_led_t * org_leds = malloc(len * sizeof(ws2811_led_t)); - ws2811_led_t * leds = ledstring.channel[channel].leds; - memcpy(org_leds, &leds[start], len * sizeof(ws2811_led_t)); //create a backup of original leds - - int loop_count=0; - - unsigned int start_time = time(0); - while (((((time(0) - start_time) < duration) || duration==0) && (loops==0 || loops < loop_count)) && end_current_command==0){ - ws2811_led_t tmp_led; - - for (n=0;n0 || (index > 0 && index < len)){ - index = (index + len) % len; - leds[start + index].color = color; - leds[start + index].brightness = brightness; - } - } - - ws2811_render(&ledstring); - usleep(delay * 1000); - - for (n=0;n,,,,, -//start and stop = color values on color wheel (0-255) -void color_change(char * args) { - int channel=0, count=1,start=0,stop=255,startled=0, len=0, duration=10000, delay=10; - - if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; - args = read_channel(args, & channel); - if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; - args = read_int(args, & start); - args = read_int(args, & stop); - args = read_int(args, & duration); - args = read_int(args, & startled); - args = read_int(args, & len); - - if (is_valid_channel_number(channel)){ - if (start<0 || start > 255) start=0; - if (stop<0 || stop > 255) stop = 255; - if (startled<0) startled=0; - if (startled+len> ledstring.channel[channel].count) len = ledstring.channel[channel].count-startled; - - if (debug) printf("color_change %d,%d,%d,%d,%d,%d\n", channel, start, stop, duration, startled, len); - - int numPixels = len; //ledstring.channel[channel].count;; - int i, j; - ws2811_led_t * leds = ledstring.channel[channel].leds; - - unsigned long long start_time = time_ms(); - unsigned long long curr_time = time_ms() - start_time; - - while (curr_time < duration){ - unsigned int color = deg2color(abs(stop-start) * curr_time / duration + start); - - for(i=0; i,,,,,,, -//direction = 0/1 fly in from left or right default 1 -//delay = delay in ms between moving pixel, default 10ms -//brightness = the final brightness of the leds that fly in -//start = where to start effect default 0 -//len = number of leds from start default length of strip -//start_brightness = initial brightness for all leds default is 0 (black) -//color = final color of the leds default is to use the current color -//first have to call "fill ," to initialze a color if you leave color default value -void fly_in(char * args) { - int channel=0,start=0, len=0, brightness=255, delay=10, direction=1, start_brightness=0, use_color=0; - unsigned int color, tmp_color, repl_color; - - args = read_channel(args, & channel); - if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; - args = read_int(args, & direction); - args = read_int(args, & delay); - args = read_int(args, & brightness); - args = read_int(args, & start); - args = read_int(args, & len); - args = read_int(args, & start_brightness); - use_color = (args!=NULL && (*args)!=0); - - if (is_valid_channel_number(channel)){ - args = read_color_arg(args, & color, ledstring.channel[channel].color_size); - if (start<0) start=0; - if (start+len> ledstring.channel[channel].count) len = ledstring.channel[channel].count-start; - - if (debug) printf("fly_in %d,%d,%d,%d,%d,%d,%d,%d,%d\n", channel, direction, delay, brightness, start, len, start_brightness, color, use_color); - - int numPixels = len; //ledstring.channel[channel].count;; - int i, j; - ws2811_led_t * leds = ledstring.channel[channel].leds; - - for (i=0;i,,,,,,, -//direction = 0/1 fly out from left or right default 1 -//delay = delay in ms between moving pixel, default 10ms -//brightness = the final brightness of the leds that fly in -//start = where to start effect default 0 -//len = number of leds from start default length of strip -//end_brightness = brightness for all leds at the end, default is 0 = black -//color = final color of the leds default is to use the current color -//first have to call "fill ," to initialze a color in each led before start fly_out -void fly_out(char * args) { - int channel=0,start=0, len=0, delay=10, direction=1, brightness=255, use_color=0, end_brightness=0; - unsigned int color, tmp_color, repl_color; - - args = read_channel(args, & channel); - if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; - args = read_int(args, & direction); - args = read_int(args, & delay); - args = read_int(args, & brightness); - args = read_int(args, & start); - args = read_int(args, & len); - args = read_int(args, & end_brightness); - use_color = (args!=NULL && (*args)!=0); - - if (is_valid_channel_number(channel)){ - args = read_color_arg(args, & color, ledstring.channel[channel].color_size); - if (start<0) start=0; - if (start+len> ledstring.channel[channel].count) len = ledstring.channel[channel].count-start; - - if (debug) printf("fly_out %d,%d,%d,%d,%d,%d,%d,%d,%d\n", channel, direction, delay, brightness, start, len, end_brightness, color, use_color); - - int numPixels = len; //ledstring.channel[channel].count;; - int i, j; - ws2811_led_t * leds = ledstring.channel[channel].leds; - + while (*args!=0){ + unsigned int color=0; + args = read_color(args, & color, color_count); + leds[led_index].color = color; + led_index++; + if (led_index>=led_count) led_index=0; + } + } + } + } + if (is_valid_channel_number(channel)){ ws2811_render(&ledstring); - for (i=0;i,,, -void save_state(char * args){ +void save_state(thread_context * context, char * args){ int channel=0,start=0, len=0, color, brightness,i=0; char filename[MAX_VAL_LEN]; @@ -1440,7 +658,7 @@ void save_state(char * args){ } //load_state ,,, -void load_state(char * args){ +void load_state(thread_context * context, char * args){ FILE * infile; /* source file */ int channel=0,start=0, len=0, color, brightness, i=0; char filename[MAX_VAL_LEN]; @@ -1476,383 +694,65 @@ void load_state(char * args){ } } -void start_loop (char * args){ - if (mode==MODE_FILE){ - if (loop_index>=MAX_LOOPS){ - loop_index=MAX_LOOPS-1; - printf("Warning max nested loops reached!\n"); - return; - } - if (debug) printf ("do %d\n", ftell(input_file)); - loops[loop_index].do_pos = ftell(input_file); - loops[loop_index].n_loops=0; - loop_index++; - }else if (mode==MODE_TCP){ - if (loop_indexid>0 || context->execute_main_do_loop!=0){ + if (context->loop_indexthread_read_index); + context->loops[context->loop_index].do_pos = context->thread_read_index-1; + context->loops[context->loop_index].n_loops=0; + context->loop_index++; }else{ - printf("Warning max nested loops reached!\n"); - } - } + printf("Warning max nested loops reached in thread %d!\n", context->id); + } + }else{ + if (debug) printf ("start do..loop in main thread.\n"); + context->write_to_own_buffer=1; + context->thread_write_index=0; + context->do_count=1; + context->loop_count=0; + write_thread_buffer(context, 'd'); + write_thread_buffer(context, 'o'); + if (args!=NULL && strlen(args)!=0){ + write_thread_buffer(context, ' '); + for (i=0;i max loop counter value, default endless loop +// increase loop counter with this value every interation, default 1 +void end_loop(thread_context * context, char * args){ int max_loops = 0; //number of wanted loops int step = 1; if (args!=NULL){ args = read_int(args, &max_loops); args = read_int(args, &step); } - if (mode==MODE_FILE){ - if (debug) printf ("loop %d, %d, %d\n", ftell(input_file), max_loops, step); - if (loop_index==0){ //no do found! - fseek(input_file, 0, SEEK_SET); - }else{ - loops[loop_index-1].n_loops+=step; - if (max_loops==0 || loops[loop_index-1].n_loops0) loop_index--; //exit loop - } - } - }else if (mode==MODE_TCP){ - if (debug) printf("loop %d\n", thread_read_index); - if (loop_index==0){ - thread_read_index=0; - }else{ - loops[loop_index-1].n_loops+=step; - if (max_loops==0 || loops[loop_index-1].n_loops0) loop_index--; //exit loop - } - } - } -} - - - -//read JPEG image and put pixel data to LEDS -//readjpg ,,,,,, -//offset = where to start in JPEG file -//DELAY = delay ms between 2 reads of LEN pixels, default=0 if 0 only bytes at will be read -#ifdef USE_JPEG -void readjpg(char * args){ - struct jpeg_decompress_struct cinfo; - struct my_error_mgr jerr; - - char value[MAX_VAL_LEN]; - int channel=0; - char filename[MAX_VAL_LEN]; - unsigned int start=0, len=1, offset=0; - int op=0,delay=0; - - args = read_channel(args, & channel); - if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; - args = read_str(args, filename, sizeof(filename)); - args = read_int(args, &start); - args = read_int(args, &len); - args = read_int(args, &offset); - args = read_str(args, value, sizeof(value)); - if (strcmp(value, "OR")==0) op=1; - else if (strcmp(value, "AND")==0) op=2; - else if (strcmp(value, "XOR")==0) op=3; - else if (strcmp(value, "NOT")==0) op=4; - args = read_int(args, &delay); - if (len<=0) len =1; - - if (is_valid_channel_number(channel)){ - FILE * infile; /* source file */ - int row_stride; /* physical row width in output buffer */ - - - if (debug) printf("readjpg %d,%s,%d,%d,%d,%d,%d\n", channel, filename, start, len, offset, op, delay); - - if ((infile = fopen(filename, "rb")) == NULL) { - fprintf(stderr, "Error: can't open %s\n", filename); - return; - } - - // We set up the normal JPEG error routines, then override error_exit. - cinfo.err = jpeg_std_error(&jerr.pub); - jerr.pub.error_exit = my_error_exit; - // Establish the setjmp return context for my_error_exit to use. - if (setjmp(jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. - * We need to clean up the JPEG object, close the input file, and return. - */ - jpeg_destroy_decompress(&cinfo); - fclose(infile); - return; - } - - // Now we can initialize the JPEG decompression object. - jpeg_create_decompress(&cinfo); - jpeg_stdio_src(&cinfo, infile); - - jpeg_read_header(&cinfo, TRUE); - jpeg_start_decompress(&cinfo); - row_stride = cinfo.output_width * cinfo.output_components; - - JSAMPARRAY buffer; // Output row buffer - int i=0,jpg_idx=0,led_idx; //pixel index for current row, jpeg image, led string - buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); - - ws2811_led_t * leds = ledstring.channel[channel].leds; - - if (start>=ledstring.channel[channel].count) start=0; - if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; - - led_idx=start; //start at this led index - - int eofstring=0; - while (eofstring==0 && cinfo.output_scanline < cinfo.output_height && end_current_command==0) { - jpeg_read_scanlines(&cinfo, buffer, 1); - for(i=0;i=offset){ //check jpeg offset - unsigned char r,g,b; - r = buffer[0][i*cinfo.output_components]; - g = buffer[0][i*cinfo.output_components+1]; - b = buffer[0][i*cinfo.output_components+2]; - if (cinfo.output_components==1){ //grayscale image - g = r; - b = r; - } - if (led_idxthread_read_index, context->loop_index, max_loops, step); - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - fclose(infile); + if (context->loop_index>0){ + context->loops[context->loop_index-1].n_loops+=step; + if (max_loops==0 || context->loops[context->loop_index-1].n_loopsthread_read_index = context->loops[context->loop_index-1].do_pos; + }else{ + if (context->loop_index>0) context->loop_index--; //exit loop + } } } -#endif - -//read PNG image and put pixel data to LEDS -//readjpg ,,,,,,, -//offset = where to start in PNG file -//backcolor = color to use for transparent area, FF0000 = RED -//P = use the PNG backcolor (default) -//W = use the alpha data for the White leds in RGBW LED strips -//DELAY = delay ms between 2 reads of LEN pixels, default=0 if 0 only bytes at will be read -#ifdef USE_PNG -void readpng(char * args){ - struct jpeg_decompress_struct cinfo; - struct my_error_mgr jerr; - - char value[MAX_VAL_LEN]; - int channel=0; - char filename[MAX_VAL_LEN]; - unsigned int start=0, len=0, offset=0; - int op=0; - int backcolor=0; - int backcolortype=0; //0 = use PNG backcolor, 1 = use given backcolor, 2 = no backcolor but use alpha for white leds - int delay=0; - - args = read_channel(args, & channel); - if (is_valid_channel_number(channel)) len=ledstring.channel[channel].count; - args = read_str(args, filename, sizeof(filename)); - args = read_str(args, value, sizeof(filename)); - if (strlen(value)>=6){ - if (is_valid_channel_number(channel)){ - read_color(value, & backcolor, ledstring.channel[channel].color_size); - backcolortype=1; - } - }else if (strcmp(value, "W")==0){ - backcolortype=2; - } - args = read_int(args, &start); - args = read_int(args, &len); - args = read_int(args, &offset); - args = read_str(args, value, sizeof(value)); - if (strcmp(value, "OR")==0) op=1; - else if (strcmp(value, "AND")==0) op=2; - else if (strcmp(value, "XOR")==0) op=3; - else if (strcmp(value, "NOT")==0) op=4; - args = read_int(args, &delay); - - if (is_valid_channel_number(channel)){ - FILE * infile; /* source file */ - ulg image_width, image_height, image_rowbytes; - int image_channels,rc; - uch *image_data; - uch bg_red=0, bg_green=0, bg_blue=0; - if (start<0) start=0; - if (start+len> ledstring.channel[channel].count) len = ledstring.channel[channel].count-start; - - if (debug) printf("readpng %d,%s,%d,%d,%d,%d,%d,%d\n", channel, filename, backcolor, start, len,offset,op, delay); - - if ((infile = fopen(filename, "rb")) == NULL) { - fprintf(stderr, "Error: can't open %s\n", filename); - return; - } - - if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) { - switch (rc) { - case 1: - fprintf(stderr, "[%s] is not a PNG file: incorrect signature.\n", filename); - break; - case 2: - fprintf(stderr, "[%s] has bad IHDR (libpng longjmp).\n", filename); - break; - case 4: - fprintf(stderr, "Read PNG insufficient memory.\n"); - break; - default: - fprintf(stderr, "Unknown readpng_init() error.\n"); - break; - } - fclose(infile); - return; - } - - //get the background color (for transparency support) - if (backcolortype==0){ - if (readpng_get_bgcolor(&bg_red, &bg_green, &bg_blue) > 1){ - readpng_cleanup(TRUE); - fclose(infile); - fprintf(stderr, "libpng error while checking for background color\n"); - return; - } - }else{ - bg_red = get_red(backcolor); - bg_green = get_green(backcolor); - bg_blue = get_blue(backcolor); - } - - //read entire image data - image_data = readpng_get_image(2.2, &image_channels, &image_rowbytes); - - if (image_data) { - int row=0, led_idx=0, png_idx=0, i=0; - uch r, g, b, a; - uch *src; - - ws2811_led_t * leds = ledstring.channel[channel].leds; - - if (start>=ledstring.channel[channel].count) start=0; - if ((start+len)>ledstring.channel[channel].count) len=ledstring.channel[channel].count-start; - - led_idx=start; //start at this led index - //load all pixels - for (row = 0; row < image_height; row++) { - src = image_data + row * image_rowbytes; - - for (i = image_width; i > 0; --i) { - r = *src++; - g = *src++; - b = *src++; - - if (image_channels != 3){ - a = *src++; - if (backcolortype!=2){ - r = alpha_component(r, bg_red,a); - g = alpha_component(g, bg_green,a); - b = alpha_component(b, bg_blue,a); - } - } - if (png_idx>=offset){ - if (debug) printf("led %d= r %d,g %d,b %d,a %d, PNG channels=%d, PNG idx=%d\n", led_idx, r, g, b, a,image_channels,png_idx); - if (led_idx < start + len){ - int fill_color; - if (backcolortype==2 && ledstring.channel[channel].color_size>3){ - fill_color=color_rgbw(r,g,b,a); - }else{ - fill_color=color(r,g,b); - } - - switch (op){ - case 0: - leds[led_idx].color=fill_color; - break; - case 1: - leds[i].color|=fill_color; - break; - case 2: - leds[i].color&=fill_color; - break; - case 3: - leds[i].color^=fill_color; - break; - case 4: - leds[i].color=~fill_color; - break; - } - - } - led_idx++; - if ( led_idx==start + len){ - if (delay!=0){//reset led index if we are at end of led string and delay - led_idx=start; - ws2811_render(&ledstring); - usleep(delay * 1000); - }else{ - row = image_height; //exit reading - i=0; - break; - } - } - } - png_idx++; - if (end_current_command) break; //signal to exit this command - } - if (end_current_command) break; - } - readpng_cleanup(TRUE); - }else{ - readpng_cleanup(FALSE); - fprintf(stderr, "Unable to decode PNG image\n"); - } - fclose(infile); - } -} -#endif //sets join type for next socket connect if thread is active // set_thread_exit_type_type , // = 0 // 0 -> Cancel, 1 -> wait -void set_thread_exit_type(char * args){ +void set_thread_exit_type(thread_context * context,char * args){ int thread_index = 0; int join_type = JOIN_THREAD_CANCEL; @@ -1862,7 +762,7 @@ void set_thread_exit_type(char * args){ if (join_type==JOIN_THREAD_CANCEL || join_type==JOIN_THREAD_WAIT){ - join_thread_type=join_type; + context->thread_join_type=join_type; }else{ fprintf(stderr, "Invalid join type %d\n", join_type); } @@ -1870,50 +770,183 @@ void set_thread_exit_type(char * args){ } //initializes the memory for a TCP/IP multithread buffer -void init_thread(char * data){ - if (thread_data==NULL){ - thread_data = (char *) malloc(DEFAULT_BUFFER_SIZE); - thread_data_size = DEFAULT_BUFFER_SIZE; +//thread_start , +void init_thread(thread_context * context, char * args){ + int thread_index = 1; + int join_thread_type = -1; + + args = read_int(args, & thread_index); + args = read_int(args, & join_thread_type); + + if (thread_index > 0 && thread_index <= MAX_THREADS){ + thread_context * t_context = & threads[thread_index]; + + if (join_thread_type!=-1){ + t_context->thread_join_type = join_thread_type; + } + if (t_context->thread_running){ //a thread is already running + switch (t_context->thread_join_type){ + case JOIN_THREAD_WAIT: + //do nothing special but wait for thread to end + break; + default: //default is cancel + t_context->end_current_command=1; //end current command + t_context->thread_running=0; //exit the thread + break; + } + if (debug) printf("Joining thread %d.\n", t_context->id); + if (t_context->waiting_signal) pthread_cond_signal (&t_context->sync_cond); + } + if (t_context->thread!=0){ + int res = pthread_join(t_context->thread,NULL); //wait for thread to finish, clean up and exit + if (res!=0){ + fprintf(stderr,"Error join thread: %d, %d ", t_context->id, res); + perror(NULL); + } + t_context->thread=0; + } + write_to_output("READY\r\n"); //send back command ready to accept incoming commands + t_context->end_current_command=0; + + if (t_context->thread_data==NULL){ + t_context->thread_data = (char *) malloc(DEFAULT_BUFFER_SIZE); + t_context->thread_data_size = DEFAULT_BUFFER_SIZE; + } + if (t_context->command_line==NULL) malloc_command_line(t_context, DEFAULT_COMMAND_LINE_SIZE > threads[0].command_line_size ? DEFAULT_COMMAND_LINE_SIZE : threads[0].command_line_size); + t_context->thread_write_index=0; + context->write_to_thread_buffer=thread_index; //from now we save all commands to the thread buffer + }else{ + fprintf(stderr, "Invalid thread number must be in range: 1-%d.", MAX_THREADS); + } +} + +//this function is called by p_thread when a new thread starts, the parameter is a pointer to the thread_context holding commands to execute +void thread_func (thread_context * context){ + context->thread_read_index=0; + context->command_index=0; + context->command_line[0]=0; + if (debug) printf("Enter thread %d,%d,%d,%d.\n", context->thread_running, context->thread_read_index, context->thread_write_index, context->id); + + while (context->thread_running){ + char c = context->thread_data[context->thread_read_index]; + process_character(context, c); + context->thread_read_index++; + if (context->thread_read_index>=context->thread_write_index) break; //exit loop if we are at the end of the file + //to do: check in TCP mode if client disconnected and terminate endless loops + //if (context->id==0 && mode==MODE_TCP && ) } - end_current_command=0; - loop_index=0; - thread_active=0; - start_thread=0; - thread_read_index=0; - thread_write_index=0; - thread_running=0; - write_to_thread_buffer=1; //from now we save all commands to the thread buffer + context->thread_running=0; + if (debug) printf("Exit thread %d.\n", context->id); + if (context->id!=0) pthread_exit(NULL); //exit the tread } -//expands the TCP/IP multithread buffer (increase size by 2) -void expand_thread_data_buffer(){ - thread_data_size = thread_data_size * 2; - char * tmp_buffer = (char *) malloc(thread_data_size); - memcpy((void*) tmp_buffer, (void*)thread_data, thread_data_size); - free(thread_data); - thread_data = tmp_buffer; +//starts a new thread, given the index where context is located +void start_thread(int thread_context_index){ + if (debug) printf("Creating pthread %d.\n", thread_context_index); + thread_context * context = &threads[thread_context_index]; + + context->thread_running=1; + int s = pthread_create(& context->thread, NULL, (void* (*)(void*)) & thread_func, context); + if (s!=0){ + fprintf(stderr,"Error creating new thread: %d", s); + perror(NULL); + } + } -//adds data to the thread buffer -void write_thread_buffer (char c){ - thread_data[thread_write_index] = c; - thread_write_index++; - if (thread_write_index==thread_data_size) expand_thread_data_buffer(); +//wait for a thread to finish +//wait_thread +void wait_thread(thread_context * context, char * args){ + int thread_index = 1; + + args = read_int(args, & thread_index); + if (thread_index > 0 && thread_index <= MAX_THREADS){ + thread_context * t_context = & threads[thread_index]; + if (t_context->thread_running){ + if (debug) printf("Waiting for thread %d to finish.\n", thread_index); + int res = pthread_join(t_context->thread,NULL); //wait for thread to finish, clean up and exit + if (res!=0){ + fprintf(stderr,"Error join thread: %d, %d ", t_context->id, res); + perror(NULL); + } + t_context->thread=0; + if (debug) printf("Thread %d finished.", thread_index); + } + }else{ + fprintf(stderr, "Invalid thread id %d", thread_index); + } } -//this function can be run in other thread for TCP/IP to enable do ... loops (usefull for websites) -void thread_func (void * param){ - thread_read_index=0; - if (debug) printf("Enter thread %d,%d,%d.\n", thread_running,thread_read_index,thread_write_index); - while (thread_running){ - char c = thread_data[thread_read_index]; - process_character(c); - thread_read_index++; - if (thread_read_index>=thread_write_index) break; //exit loop if we are at the end of the file - } - thread_running=0; - if (debug) printf("Exit thread.\n"); - pthread_exit(NULL); //exit the tread + +//terminate a running thread +//kill_thread , +void kill_thread(thread_context * context, char * args){ + int thread_index = 1; + int join_thread_type = -1; + + args = read_int(args, & thread_index); + args = read_int(args, & join_thread_type); + + if (thread_index > 0 && thread_index <= MAX_THREADS){ + thread_context * t_context = & threads[thread_index]; + + if (join_thread_type!=-1){ + t_context->thread_join_type = join_thread_type; + } + + if (t_context->thread_running){ //a thread is already running + if (debug) printf("Killing thread %d,%d.\n", thread_index, join_thread_type); + switch (t_context->thread_join_type){ + case JOIN_THREAD_WAIT: + //do nothing special but wait for thread to end + break; + default: //default is cancel + t_context->end_current_command=1; //end current command + t_context->thread_running=0; //exit the thread + break; + } + if (debug) printf("Joining thread %d.\n", t_context->id); + if (t_context->waiting_signal) pthread_cond_signal (&t_context->sync_cond); + int res = pthread_join(t_context->thread,NULL); //wait for thread to finish, clean up and exit + if (res!=0){ + fprintf(stderr,"Error join thread: %d, %d ", t_context->id, res); + perror(NULL); + } + t_context->thread=0; + t_context->end_current_command=0; + }else{ + if (debug) printf("Thread %d not running.\n", thread_index); + } + }else{ + fprintf(stderr, "Invalid thread id %d\n", thread_index); + } +} + +void signal_thread(thread_context * context, char * args){ + int thread_index = 1; + + args = read_int(args, & thread_index); + if (thread_index > 0 && thread_index <= MAX_THREADS){ + thread_context * t_context = & threads[thread_index]; + if (debug) printf("Sending signal to thread %d from %d.\n", thread_index, context->id); + pthread_cond_signal (&t_context->sync_cond); + }else{ + fprintf(stderr, "Invalid thread id %d\n", thread_index); + } +} + +void wait_signal(thread_context * context, char * args){ + if (debug) printf("Waiting for signal to continue in thread %d.\n", context->id); + if (context->id==0) { + fprintf(stderr, "wait_signal not possible on main thread %d\n", context->id); + return; //don't do on main thread + } + pthread_mutex_lock (&context->sync_mutex); + context->waiting_signal=1; + pthread_cond_wait (&context->sync_cond, &context->sync_mutex); + context->waiting_signal=0; + pthread_mutex_unlock (&context->sync_mutex); + if (debug) printf("Signal received in thread %d.\n", context->id); } void str_replace(char * dst, char * src, char * find, char * replace){ @@ -1935,25 +968,38 @@ void str_replace(char * dst, char * src, char * find, char * replace){ } //executes 1 command line -void execute_command(char * command_line){ - +void execute_command(thread_context * context, char * command_line){ + int i; if (command_line[0]=='#') return; //=comments - if (write_to_thread_buffer){ + if (context->write_to_thread_buffer > 0){ //inside thread_start -> thread_stop structure, write all commands to a different thread buffer if (strncmp(command_line, "thread_stop", 11)==0){ - if (mode==MODE_TCP){ - write_to_thread_buffer=0; - if (debug) printf("Thread stop.\n"); - if (thread_write_index>0) start_thread=1; //remember to start the thread when client closes the TCP/IP connection - } + if (debug) printf("Starting thread.\n"); + start_thread(context->write_to_thread_buffer); + context->write_to_thread_buffer=0; }else{ if (debug) printf("Write to thread buffer: %s\n", command_line); while (*command_line!=0){ - write_thread_buffer(*command_line); //for TCP/IP we write to the thread buffer + write_thread_buffer(& threads[context->write_to_thread_buffer], *command_line); //for TCP/IP we write to the thread buffer command_line++; } - write_thread_buffer(';'); + write_thread_buffer(& threads[context->write_to_thread_buffer], ';'); } + }else if (context->write_to_own_buffer){ //inside do ... loop in main thread, write all commands to temporary buffer, when reaching the last loop exit from this mode and execute the captured commands + for (i=0;iloop_count++; + }else if (strncmp(command_line, "do", 2)==0){ + context->do_count++; + } + if (context->loop_count==context->do_count){ + context->write_to_own_buffer=0; + context->thread_running=1; + context->execute_main_do_loop=1; //needed for the start_loop function to know if it must execute the command + thread_func(context); //now execute captured commands + context->execute_main_do_loop=0; + } }else{ char * raw_args = strchr(command_line, ' '); char * command = strtok(command_line, " \r\n"); @@ -1969,9 +1015,9 @@ void execute_command(char * command_line){ char find_loop_nr[MAX_LOOPS+2]; char replace_loop_index[MAX_LOOPS+2]; strcpy(arg,raw_args); - for (i=0;iloop_index;i++){ sprintf(find_loop_nr, "{%d}", i); - sprintf(replace_loop_index, "%d", loops[i].n_loops); + sprintf(replace_loop_index, "%d", context->loops[i].n_loops); str_replace(tmp_arg, arg, find_loop_nr, replace_loop_index); //cannot put result in same string we are replacing, store in temp buffer strcpy(arg, tmp_arg); } @@ -1980,56 +1026,58 @@ void execute_command(char * command_line){ } if (strcmp(command, "render")==0){ - render(arg); + render(context, arg); }else if (strcmp(command, "rotate")==0){ - rotate(arg); + rotate(context, arg); }else if (strcmp(command, "delay")==0){ if (arg!=NULL) usleep((atoi(arg)+1)*1000); }else if (strcmp(command, "brightness")==0){ - brightness(arg); + brightness(context, arg); }else if (strcmp(command, "rainbow")==0){ - rainbow(arg); + rainbow(context, arg); }else if (strcmp(command, "fill")==0){ - fill(arg); + fill(context, arg); }else if (strcmp(command, "fade")==0){ - fade(arg); + fade(context, arg); }else if (strcmp(command, "gradient")==0){ - gradient(arg); + gradient(context, arg); }else if (strcmp(command, "random")==0){ - add_random(arg); + add_random(context, arg); }else if (strcmp(command, "do")==0){ - start_loop(arg); + start_loop(context, arg); }else if (strcmp(command, "loop")==0){ - end_loop(arg); - }else if (strcmp(command, "thread_start")==0){ //start a new thread that processes code - if (thread_active==0 && mode==MODE_TCP) init_thread(arg); + end_loop(context, arg); + }else if (strcmp(command, "thread_start")==0){ //start a new thread that processes code, in case thread is already running it will abort or wait depending on the join thread type + init_thread(context, arg); }else if (strcmp(command, "init")==0){ //first init ammount of channels wanted - init_channels(arg); + init_channels(context, arg); }else if (strcmp(command, "setup")==0){ //setup the channels - setup_ledstring(arg); + setup_ledstring(context, arg); }else if (strcmp(command, "settings")==0){ print_settings(); }else if (strcmp(command, "global_brightness")==0){ - global_brightness(arg); + global_brightness(context, arg); }else if (strcmp(command, "blink")==0){ - blink(arg); + blink(context, arg); }else if (strcmp(command, "random_fade_in_out")==0){ - random_fade_in_out(arg); + random_fade_in_out(context, arg); }else if (strcmp(command, "chaser")==0){ - chaser(arg); + chaser(context, arg); }else if (strcmp(command, "color_change")==0){ - color_change(arg); + color_change(context, arg); }else if (strcmp(command, "fly_in")==0){ - fly_in(arg); + fly_in(context, arg); }else if (strcmp(command, "fly_out")==0){ - fly_out(arg); + fly_out(context, arg); + }else if (strcmp(command, "progress")==0){ + progress(context, arg); #ifdef USE_JPEG }else if (strcmp(command, "readjpg")==0){ - readjpg(arg); + readjpg(context, arg); #endif #ifdef USE_PNG }else if (strcmp(command, "readpng")==0){ - readpng(arg); + readpng(context, arg); #endif }else if (strcmp(command, "help")==0){ printf("debug (enables some debug output)\n"); @@ -2061,24 +1109,38 @@ void execute_command(char * command_line){ printf("color_change ,,,,,\n"); printf("fly_in ,,,,,,,\n"); printf("fly_out ,,,,,,,\n"); + printf("progress ,,,,,,,\n"); printf("save_state ,,,\n"); printf("load_state ,,,\n"); #ifdef USE_JPEG - printf("readjpg ,,,,,\n"); + printf("readjpg ,,,,,,\n"); #endif #ifdef USE_PNG - printf("readpng ,,,,,,\n BACKCOLOR=XXXXXX for color, PNG=USE PNG Back color (default), W=Use alpha for white leds in RGBW strips.\n"); + printf("readpng ,,,,,,,\n BACKCOLOR=XXXXXX for color, PNG=USE PNG Back color (default), W=Use alpha for white leds in RGBW strips.\n"); #endif printf("settings\n"); - printf("do ... loop (TCP / File mode only)\n"); - printf("Inside a finite loop {x} will be replaced by the current loop index number. x stands for the loop number in case of multiple nested loops (default use 0)."); + printf("do ... loop\n"); + printf("thread_start , .... thread_stop\n"); + printf("kill_thread ,\n"); + printf("signal_thread \n"); + printf("wait_signal\n"); + printf("wait_thread\n"); + printf("Inside a finite loop {x} will be replaced by the current loop index number. x stands for the loop number in case of multiple nested loops (default use 0).\n"); printf("exit\n"); }else if (strcmp(command, "save_state")==0){ - save_state(arg); + save_state(context, arg); }else if (strcmp(command, "load_state")==0){ - load_state(arg); + load_state(context, arg); }else if (strcmp(command, "set_thread_exit_type")==0){ - set_thread_exit_type(arg); + set_thread_exit_type(context, arg); + }else if (strcmp(command, "wait_thread_exit")==0){ + wait_thread(context, arg); + }else if (strcmp(command, "kill_thread")==0){ + kill_thread(context, arg); + }else if (strcmp(command, "wait_signal")==0){ + wait_signal(context, arg); + }else if (strcmp(command, "signal_thread")==0){ + signal_thread(context, arg); }else if (strcmp(command, "debug")==0){ if (debug) debug=0; else debug=1; @@ -2092,18 +1154,18 @@ void execute_command(char * command_line){ } } -void process_character(char c){ +void process_character(thread_context * context, char c){ if (c=='\n' || c == '\r' || c == ';'){ - if (command_index>0){ - command_line[command_index]=0; //terminate with 0 - execute_command(command_line); - command_index=0; + if (context->command_index>0){ + context->command_line[context->command_index]=0; //terminate with 0 + execute_command(context, context->command_line); + context->command_index=0; } }else{ - if (!(command_index==0 && c==' ')){ - command_line[command_index]=(char)c; - command_index++; - if (command_index==command_line_size) command_index=0; + if (!(context->command_index==0 && c==' ')){ + context->command_line[context->command_index]=(char)c; + context->command_index++; + if (context->command_index==context->command_line_size) context->command_index=0; } } } @@ -2117,56 +1179,18 @@ void tcp_wait_connection (){ socklen_t optlen = sizeof (sock_opt); if (active_socket!=-1) close(active_socket); - - if (start_thread){ - if (debug) printf("Running thread.\n"); - thread_active=1; - thread_running=1; //thread will run untill thread_running becomes 0 (this is after a new client has connected) - int s = pthread_create(& thread, NULL, (void* (*)(void*)) & thread_func, NULL); - if (s!=0){ - fprintf(stderr,"Error creating new thread: %d", s); - perror(NULL); - } - } printf("Waiting for client to connect.\n"); clilen = sizeof(cli_addr); active_socket = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); - if (active_socket!=-1){ + if (active_socket!=-1){ if (setsockopt(active_socket, SOL_SOCKET, SO_KEEPALIVE, &sock_opt, optlen)) printf("Error set SO_KEEPALIVE\n"); - //if there is a thread active we exit it - if (thread_active){ - switch (join_thread_type){ - case JOIN_THREAD_WAIT: - - break; - default: //default is cancel - end_current_command=1; //end current command - thread_running=0; //exit the thread - break; - } - int res = pthread_join(thread,NULL); //wait for thread to finish, clean up and exit - if (res!=0){ - fprintf(stderr,"Error join thread: %d ", res); - perror(NULL); - } - end_current_command=0; - thread_active=0; - } - - write(active_socket, "READY\r\n", 7); - - write_to_thread_buffer=0; - thread_write_index=0; - thread_read_index=0; - start_thread=0; - printf("Client connected.\n"); }else{ perror("Socket accept error"); - } + } } //sets up sockets @@ -2258,7 +1282,7 @@ void load_config_file(char * filename){ //main routine int main(int argc, char *argv[]){ int ret = 0; - int i; + int i,j; int index=0; srand (time(NULL)); @@ -2271,9 +1295,37 @@ int main(int argc, char *argv[]){ ledstring.channel[1].count = 0; } - command_line = NULL; + + for (i=0;i creates a named pipe at location where you can write command to.\n"); printf("-f read commands from \n"); @@ -2356,7 +1408,7 @@ int main(int argc, char *argv[]){ if (initialize_cmd!=NULL){ for(i=0;i0 && threads[i].thread_running){ + threads[i].thread_running=0; + threads[i].end_current_command=1; + if (threads[i].waiting_signal){ + pthread_cond_signal (&threads[i].sync_cond); + } + pthread_join(threads[i].thread,NULL); + } + if (threads[i].thread_data!=NULL) free(threads[i].thread_data); + if (threads[i].command_line!=NULL) free(threads[i].command_line); + threads[i].thread_data=NULL; + threads[i].command_line=NULL; + pthread_mutex_destroy(&threads[i].sync_mutex); + pthread_cond_destroy(&threads[i].sync_cond); + } + + + //if (thread_data!=NULL) free(thread_data); if (ledstring.device!=NULL) ws2811_fini(&ledstring); return ret; diff --git a/makefile b/makefile index 931b464..3d9629d 100755 --- a/makefile +++ b/makefile @@ -37,7 +37,7 @@ endif ws2811.o: ws2811.c ws2811.h rpihw.h pwm.h pcm.h mailbox.h clk.h gpio.h dma.h rpihw.h readpng.h $(CC) -c $< -o $@ -main.o: main.c ws2811.h +main.o: main.c ws2811.h effects/rotate.c effects/rainbow.c effects/fill.c effects/brightness.c effects/fade.c effects/blink.c effects/gradient.c effects/add_random.c effects/random_fade_in_out.c effects/chaser.c effects/color_change.c effects/fly_in.c effects/fly_out.c effects/read_png.c effects/read_jpg.c effects/progress.c $(CC) -c $< -o $@ ifneq (1,$(NO_PNG))