Skip to content

Commit

Permalink
Update to V4
Browse files Browse the repository at this point in the history
Update to V4
  • Loading branch information
Tom committed Oct 4, 2020
1 parent 2e33fad commit 41221c4
Show file tree
Hide file tree
Showing 20 changed files with 1,868 additions and 1,505 deletions.
9 changes: 9 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -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).
88 changes: 64 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
```
Expand Down Expand Up @@ -181,6 +181,7 @@ delay
<offset>, #start at pixel offset in JPG file (default is 0)
<OR AND XOR NOT =>, #operator to use, use NOT to reverse image (default is =)
<delay> #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
<flip_rows> #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
Expand All @@ -195,6 +196,7 @@ delay
<offset>, #start at pixel offset in JPG file (default is 0)
<OR AND XOR =>, #operator to use, use NOT to reverse image (default is =)
<delay> #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
<flip_rows> #optional argument to indicate to horizontally flip rows with odd index
```

* `blink` command makes a group of leds blink between 2 given colors
Expand Down Expand Up @@ -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 <channel>,<color>)
```

* `progress` generates a progress bar effect or sets the leds brightness to a given progress value
```
progress
<channel>, #channel number to use
<direction>, #direction of progress bar (default 1) start led = 0%, start + len = 100%
<delay>, #delay between increments of progress (default 1s), set 0 to not automatically increment and render progress bar but use the value argument
<start>, #start effect at this led position, default 0
<len>, #number of leds to change starting at start, default length of strip
<brightness_on>, #brightness of led that is on default 255
<brightness_off>, #brightness of led that is off default 0
<value> #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 <channel>,<color> 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.
Expand All @@ -305,19 +321,59 @@ Try this as an example for a 300 LED string:
<len> #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 <index> parameter.
<join_type> will determine the behavior next time you call thread_start with the <index> 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 <index>,<join_type>
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 <thread_id> parameter
READY + newline (CR + LF) will be returned when the thread has exited.
```
set_thread_exit_type
<thread_id>, #The thread number, always 0
<thread_id>, #The thread number (1-63)
<type> #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
<thread_id> #The thread number (1-63)
```

* `kill_thread` terminate the given thread_id
```
kill_thread
<thread_id> #The thread number (1-63)
<type> #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
<thread_id> #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:
```
Expand Down Expand Up @@ -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
<client must close connection now>
```

# 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:
Expand Down
69 changes: 69 additions & 0 deletions effects/add_random.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//generates random colors
//random <channel>,<start>,<len>,<RGBWL>
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<strlen(value);i++){
switch(toupper(value[i])){
case 'R':
use_r=1;
break;
case 'G':
use_g=1;
break;
case 'B':
use_b=1;
break;
case 'W':
use_w=1;
break;
case 'L':
use_l=1;
break;
}
}
}

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 (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<len;i++){
if (use_r) r = rand() % 256;
if (use_g) g = rand() % 256;
if (use_b) b = rand() % 256;
if (use_w) w = rand() % 256;
if (use_l) l = rand() % 256;

if (use_r || use_g || use_b || use_w) leds[start+i].color = color_rgbw(r,g,b,w);
if (use_l) leds[start+i].brightness = l;
}
}else{
fprintf(stderr,ERROR_INVALID_CHANNEL);
}
}
50 changes: 50 additions & 0 deletions effects/blink.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//makes some leds blink between 2 given colors for x times with a given delay
//blink <channel>,<color1>,<color2>,<delay>,<blink_count>,<startled>,<len>
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; blinks<count;blinks++){
for (i=start;i<start+len;i++){
if ((blinks%2)==0) {
leds[i].color=color1;
}else{
leds[i].color=color2;
}
}
ws2811_render(&ledstring);
usleep(delay * 1000);
if (context->end_current_command) break; //signal to exit this command
}
}else{
fprintf(stderr,ERROR_INVALID_CHANNEL);
}
}
32 changes: 32 additions & 0 deletions effects/brightness.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//dims leds
//brightness <channel>,<brightness>,<start>,<len> (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<start+len;i++){
leds[i].brightness=brightness;
}
}else{
fprintf(stderr,ERROR_INVALID_CHANNEL);
}
}
81 changes: 81 additions & 0 deletions effects/chaser.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//chaser makes leds run accross the led strip
//chaser <channel>,<duration>,<color>,<count>,<direction>,<delay>,<start>,<len>,<brightness>,<loops>
//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;n<count;n++){
index = direction==1 ? i - n: len - i + n;
if (loop_count>0 || (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<count;n++){
index = direction==1 ? i - n : len - i + n;
index = (index + len) % len;
leds[start + index].color = org_leds[index].color;
leds[start + index].brightness = org_leds[index].brightness;
}

i++;
i = i % len;
if (i==0){
loop_count++;
}
}

memcpy(org_leds, & leds[start], len * sizeof(ws2811_led_t));
free(org_leds);
}else{
fprintf(stderr, ERROR_INVALID_CHANNEL);
}
}
Loading

0 comments on commit 41221c4

Please sign in to comment.