├── .gitattributes ├── .github └── FUNDING.yml ├── .gitignore ├── 2D ├── camera.c ├── camera.h ├── change_layer.c ├── change_layer.h ├── circle.c ├── circle.h ├── cls.c ├── cls.h ├── image.c ├── image.h ├── init_layer.c ├── init_layer.h ├── line.c ├── line.h ├── message_board.c ├── message_board.h ├── print_text.c ├── print_text.h ├── rectangle.c ├── rectangle.h ├── screenshot.c ├── screenshot.h ├── set_pixel.c ├── set_pixel.h ├── text_input.c └── text_input.h ├── BCM2835-ARM-Peripherals.pdf ├── CHANGES.md ├── COMMANDS.md ├── README.md ├── audio ├── light_organ.c ├── light_organ.h ├── pulses.c ├── pulses.h ├── record.c ├── record.h ├── test.wav ├── vu_meter.c ├── vu_meter.h ├── wave.c └── wave.h ├── clk.h ├── dma.c ├── dma.h ├── effects ├── add_random.c ├── add_random.h ├── ambilight.c ├── ambilight.h ├── blink.c ├── blink.h ├── brightness.c ├── brightness.h ├── chaser.c ├── chaser.h ├── color_change.c ├── color_change.h ├── fade.c ├── fade.h ├── fill.c ├── fill.h ├── fly_in.c ├── fly_in.h ├── fly_out.c ├── fly_out.h ├── gradient.c ├── gradient.h ├── progress.c ├── progress.h ├── rainbow.c ├── rainbow.h ├── random_fade_in_out.c ├── random_fade_in_out.h ├── read_jpg.c ├── read_jpg.h ├── read_png.c ├── read_png.h ├── rotate.c └── rotate.h ├── enhanced_led_board-7.ttf ├── examples ├── ambilight.htm ├── ambilight.png ├── camera.htm ├── circle.htm ├── fill.htm ├── gpio.htm ├── hdmi_capture.jpg ├── image.htm ├── index.htm ├── light_organ.htm ├── line.htm ├── master_slave.htm ├── master_slave.png ├── master_slave_fade.htm ├── message_board.htm ├── multi_layer.htm ├── multichannel.htm ├── panel_type_0.png ├── panel_type_1.png ├── panel_type_2.png ├── panel_type_3.png ├── print_text.htm ├── pulses.htm ├── rainbow_easy.htm ├── record_audio.htm ├── rectangle.htm ├── red-green.png ├── rgb.jpg ├── rgb.png ├── rotating_colors.htm ├── run_script.htm ├── screenshot.htm ├── setup_2D.htm ├── stream_audio_multiple_threads.htm ├── style.css ├── sync_threads.htm ├── test.gif ├── test.png ├── text_input.htm ├── threads.htm └── vu_meter.htm ├── fifo.c ├── fifo.h ├── gifdec.c ├── gifdec.h ├── gpio.h ├── jpghelper.c ├── jpghelper.h ├── mailbox.c ├── mailbox.h ├── main.c ├── makefile ├── master_slave.c ├── master_slave.h ├── pcm.c ├── pcm.h ├── php ├── colormap.gif └── index.php ├── pico w ├── code.py ├── lib │ ├── adafruit_pixelbuf.mpy │ └── neopixel.mpy ├── settings.toml └── vs.code-workspace ├── pipe.c ├── pipe.h ├── pwm.c ├── pwm.h ├── readpng.c ├── readpng.h ├── rpihw.c ├── rpihw.h ├── sk9822.c ├── sk9822.h ├── sockets.c ├── sockets.h ├── spi.cpp ├── spi.h ├── test_ss.c ├── ws2811.c ├── ws2811.h ├── ws2812svr.c ├── ws2812svr.conf ├── ws2812svr.h └── ws2812svr.service /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: #Tom54321 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: https://paypal.me/Tom54321 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | 45 | #executable / objects: 46 | *.o 47 | *.elf 48 | ws2812svr 49 | 50 | tests/ 51 | 52 | .vscode 53 | .github -------------------------------------------------------------------------------- /2D/camera.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _2D_CAMERA_H 3 | #define _2D_CAMERA_H 4 | #include "../ws2812svr.h" 5 | 6 | void camera(thread_context* context, char* args); 7 | 8 | #endif -------------------------------------------------------------------------------- /2D/change_layer.c: -------------------------------------------------------------------------------- 1 | #include "change_layer.h" 2 | 3 | //change_layer, changes the current cairo render object to a different layer 4 | //change_layer , 5 | void change_layer(thread_context* context, char* args) { 6 | int channel = 0, layer_nr=0; 7 | 8 | args = read_channel(args, &channel); 9 | 10 | if (is_valid_2D_channel_number(channel)) { 11 | args = read_int(args, &layer_nr); 12 | if (debug) printf("change_layer %d, %d.\n", channel, layer_nr); 13 | 14 | channel_info * led_channel = get_channel(channel); 15 | if (layer_nr != 0) { 16 | layer_nr--; 17 | if (layer_nr >=0 && layer_nr < CAIRO_MAX_LAYERS && led_channel->layers[layer_nr].cr != NULL) { 18 | led_channel->cr = led_channel->layers[layer_nr].cr; 19 | } else { 20 | fprintf(stderr, "Invalid layer nr %d.\n", layer_nr + 1); 21 | return; 22 | } 23 | } else { 24 | led_channel->cr = led_channel->main_cr; 25 | } 26 | 27 | } else { 28 | fprintf(stderr, ERROR_INVALID_2D_CHANNEL); 29 | } 30 | } -------------------------------------------------------------------------------- /2D/change_layer.h: -------------------------------------------------------------------------------- 1 | #ifndef _2D_CHANGE_LAYER_H 2 | #define _2D_CHANGE_LAYER_H 3 | #include "../ws2812svr.h" 4 | 5 | void change_layer(thread_context* context, char* args); 6 | 7 | #endif -------------------------------------------------------------------------------- /2D/circle.c: -------------------------------------------------------------------------------- 1 | #define _USE_MATH_DEFINES 2 | #include 3 | #include "../ws2812svr.h" 4 | 5 | //http://zetcode.com/gfx/cairo/basicdrawing/ 6 | //draw_circle 7 | //draw_circle ,,,,,,,,, 8 | void draw_circle(thread_context* context, char* args) { 9 | int channel = 0, fill_color = COLOR_TRANSPARENT, border_color = COLOR_TRANSPARENT; 10 | double start_angle = 0.0, stop_angle = 360.0 , x = 0, y = 0, radius = 0, border_width = 0; 11 | bool fill_color_empty = true; 12 | int negative = 0; 13 | 14 | args = read_channel(args, &channel); 15 | 16 | if (is_valid_2D_channel_number(channel)) { 17 | 18 | args = read_double(args, &x); 19 | args = read_double(args, &y); 20 | args = read_double(args, &radius); 21 | args = read_color_arg_empty(args, &fill_color, 4, &fill_color_empty); 22 | args = read_double(args, &border_width); 23 | args = read_color_arg(args, &border_color, 4); 24 | args = read_double(args, &start_angle); 25 | args = read_double(args, &stop_angle); 26 | args = read_int(args, &negative); 27 | 28 | //cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); 29 | if (debug) printf("draw_circle %d,%f,%f,%f,%d,%f,%d,%f,%f,%d\n", channel, x, y, radius, fill_color, border_width, border_color,start_angle,stop_angle,negative); 30 | 31 | channel_info * led_channel = get_channel(channel); 32 | cairo_t* cr = led_channel->cr; 33 | 34 | 35 | /*cairo_set_line_width(cr, 1); 36 | set_cairo_color_rgba(cr, 255); 37 | cairo_translate(cr, 4, 4); 38 | cairo_arc(cr, 0, 0, 3, 0, 2.0 * M_PI); 39 | cairo_close_path(cr); 40 | cairo_stroke_preserve(cr); 41 | set_cairo_color_rgba(cr, 0xFF00); 42 | cairo_fill(cr);*/ 43 | 44 | cairo_save(cr); 45 | 46 | 47 | if (border_width > 0.0) { 48 | cairo_set_line_width(cr, border_width); 49 | set_cairo_color_rgba(cr, border_color); 50 | } 51 | 52 | cairo_translate(cr, x, y); 53 | 54 | if (negative==0) { 55 | cairo_arc(cr, 0, 0, radius, start_angle / 360.0 * 2.0 * M_PI, stop_angle / 360.0 * 2.0 * M_PI); 56 | } else { 57 | cairo_arc_negative(cr, 0, 0, radius, start_angle / 360.0 * 2.0 * M_PI, stop_angle / 360.0 * 2.0 * M_PI); 58 | } 59 | 60 | if (border_width > 0) { 61 | if (!fill_color_empty) { 62 | cairo_close_path(cr); 63 | cairo_stroke_preserve(cr); 64 | } else { 65 | cairo_stroke(cr); 66 | } 67 | } 68 | 69 | if (!fill_color_empty) { 70 | set_cairo_color_rgba(cr, fill_color); 71 | cairo_fill(cr); 72 | } 73 | 74 | cairo_restore(cr); 75 | 76 | } else { 77 | fprintf(stderr, ERROR_INVALID_2D_CHANNEL); 78 | } 79 | } -------------------------------------------------------------------------------- /2D/circle.h: -------------------------------------------------------------------------------- 1 | #ifndef _2D_CIRCLE_H 2 | #define _2D_CIRCLE_H 3 | #include "../ws2812svr.h" 4 | 5 | void draw_circle(thread_context* context, char* args); 6 | 7 | #endif -------------------------------------------------------------------------------- /2D/cls.c: -------------------------------------------------------------------------------- 1 | #include "cls.h" 2 | //fills 2D channel with color 3 | //cls , 4 | void cls(thread_context* context, char* args) { 5 | int channel = 0, color = COLOR_TRANSPARENT; 6 | 7 | args = read_channel(args, &channel); 8 | 9 | if (is_valid_2D_channel_number(channel)) { 10 | 11 | channel_info * led_channel = get_channel(channel); 12 | cairo_t* cr = led_channel->cr; 13 | 14 | if (cr == led_channel->main_cr) color = 0; 15 | 16 | args = read_color_arg(args, &color, 4); 17 | 18 | cairo_save(cr); 19 | cairo_identity_matrix(cr); 20 | set_cairo_color_rgba(cr, color); 21 | cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); 22 | cairo_paint(cr); 23 | 24 | cairo_restore(cr); 25 | 26 | /*cairo_surface_flush(led_channel->surface); 27 | if (color == 0) { 28 | unsigned char* pixels = cairo_image_surface_get_data(led_channel->surface); //get pointer to pixel data 29 | memset(pixels, convert_cairo_color(color), led_channel->surface_stride * sizeof(unsigned char) * led_channel->height); 30 | }else { 31 | unsigned int * pixels = (unsigned int *) cairo_image_surface_get_data(led_channel->surface); //get pointer to pixel data 32 | unsigned int* pixels_end = pixels + led_channel->width * led_channel->height; 33 | color = convert_cairo_color(color); 34 | while (pixels != pixels_end) { 35 | *pixels = color; 36 | pixels++; 37 | } 38 | } 39 | 40 | cairo_surface_mark_dirty(led_channel->surface);*/ 41 | } else { 42 | fprintf(stderr, ERROR_INVALID_2D_CHANNEL); 43 | } 44 | } -------------------------------------------------------------------------------- /2D/cls.h: -------------------------------------------------------------------------------- 1 | #ifndef _2D_CLS_H 2 | #define _2D_CLS_H 3 | #include "../ws2812svr.h" 4 | 5 | void cls(thread_context* context, char* args); 6 | 7 | #endif -------------------------------------------------------------------------------- /2D/image.h: -------------------------------------------------------------------------------- 1 | #ifndef _2D_IMAGE_H 2 | #define _2D_IMAGE_H 3 | #include "../ws2812svr.h" 4 | 5 | void draw_image(thread_context* context, char* args); 6 | 7 | #endif -------------------------------------------------------------------------------- /2D/init_layer.c: -------------------------------------------------------------------------------- 1 | 2 | #include "init_layer.h" 3 | //init_layer, inits an extra layer or changes painting options, layers are painted from top to bottom 4 | //init_layer ,,,,,,, 5 | //filter_types: 6 | /*CAIRO_FILTER_BEST = 2 7 | CAIRO_FILTER_BILINEAR = 4 8 | CAIRO_FILTER_FAST = 0 9 | CAIRO_FILTER_GOOD = 1 10 | CAIRO_FILTER_NEAREST = 3*/ 11 | /* 12 | * 13 | BEST 14 | DEFAULT = 0 15 | FAST 16 | GOOD 17 | GRAY = 2 18 | NONE = 1 19 | SUBPIXEL = 3 20 | * */ 21 | 22 | /* 23 | * 24 | CAIRO_OPERATOR_CLEAR = 0 25 | CAIRO_OPERATOR_SOURCE = 1 26 | CAIRO_OPERATOR_OVER = 2 27 | CAIRO_OPERATOR_IN = 3 28 | CAIRO_OPERATOR_OUT = 4 29 | CAIRO_OPERATOR_ATOP = 5 30 | CAIRO_OPERATOR_DEST = 6 31 | CAIRO_OPERATOR_DEST_OVER = 7 32 | CAIRO_OPERATOR_DEST_IN = 8 33 | CAIRO_OPERATOR_DEST_OUT = 9 34 | CAIRO_OPERATOR_DEST_ATOP = 10 35 | CAIRO_OPERATOR_XOR = 11 36 | CAIRO_OPERATOR_ADD = 12 37 | CAIRO_OPERATOR_SATURATE = 13 38 | CAIRO_OPERATOR_MULTIPLY = 14 39 | CAIRO_OPERATOR_SCREEN = 15 40 | CAIRO_OPERATOR_OVERLAY = 16 41 | CAIRO_OPERATOR_DARKEN = 17 42 | CAIRO_OPERATOR_LIGHTEN = 18 43 | CAIRO_OPERATOR_COLOR_DODGE = 19 44 | CAIRO_OPERATOR_COLOR_BURN = 20 45 | CAIRO_OPERATOR_HARD_LIGHT = 21 46 | CAIRO_OPERATOR_SOFT_LIGHT = 22 47 | CAIRO_OPERATOR_DIFFERENCE = 23 48 | CAIRO_OPERATOR_EXCLUSION = 24 49 | CAIRO_OPERATOR_HSL_HUE = 25 50 | CAIRO_OPERATOR_HSL_SATURATION = 26 51 | CAIRO_OPERATOR_HSL_COLOR = 27 52 | CAIRO_OPERATOR_HSL_LUMINOSITY = 28 53 | */ 54 | 55 | void init_layer(thread_context* context, char* args) { 56 | int channel = 0, layer_nr = 0, x=0, y=0, type=0, operation= CAIRO_OPERATOR_SOURCE, antialias=CAIRO_ANTIALIAS_DEFAULT, filter_type=CAIRO_FILTER_FAST; 57 | 58 | args = read_channel(args, &channel); 59 | 60 | if (is_valid_2D_channel_number(channel)) { 61 | 62 | args = read_int(args, &layer_nr); 63 | args = read_int(args, &operation); 64 | args = read_int(args, &type); 65 | args = read_int(args, &antialias); 66 | args = read_int(args, &filter_type); 67 | args = read_int(args, &x); 68 | args = read_int(args, &y); 69 | 70 | if (debug) printf("init_layer %d,%d,%d,%d,%d,%d.\n", channel, layer_nr, operation, type, x, y); 71 | 72 | //cairo_pattern_set_filter(cairo_get_source(led_channel->cr), CAIRO_FILTER_NEAREST); 73 | //cairo_set_antialias(led_channel->cr, CAIRO_ANTIALIAS_NONE); 74 | channel_info * led_channel = get_channel(channel); 75 | 76 | if (layer_nr == 0) { 77 | cairo_set_operator(led_channel->cr, operation); 78 | cairo_pattern_set_filter(cairo_get_source(led_channel->cr), filter_type); 79 | cairo_set_antialias(led_channel->cr, antialias); 80 | } else { 81 | layer_nr--; 82 | if (layer_nr >= 0 && layer_nr < CAIRO_MAX_LAYERS) { 83 | if (led_channel->layers[layer_nr].cr == NULL) { 84 | led_channel->layers[layer_nr].surface = cairo_surface_create_similar(led_channel->surface, CAIRO_CONTENT_COLOR_ALPHA, led_channel->width, led_channel->height); 85 | led_channel->layers[layer_nr].cr = cairo_create(led_channel->layers[layer_nr].surface); 86 | } 87 | led_channel->layers[layer_nr].type = type; 88 | led_channel->layers[layer_nr].op = operation; 89 | led_channel->layers[layer_nr].x = x; 90 | led_channel->layers[layer_nr].y = y; 91 | 92 | cairo_pattern_set_filter(cairo_get_source(led_channel->layers[layer_nr].cr), filter_type); 93 | cairo_set_antialias(led_channel->layers[layer_nr].cr, antialias); 94 | } else { 95 | fprintf(stderr, "Invalid layer nr %d.\n", layer_nr + 1); 96 | return; 97 | } 98 | } 99 | } else { 100 | fprintf(stderr, ERROR_INVALID_2D_CHANNEL); 101 | } 102 | } -------------------------------------------------------------------------------- /2D/init_layer.h: -------------------------------------------------------------------------------- 1 | #ifndef _2D_INIT_LAYER_H 2 | #define _2D_INIT_LAYER_H 3 | #include "../ws2812svr.h" 4 | 5 | void init_layer(thread_context* context, char* args); 6 | 7 | #endif -------------------------------------------------------------------------------- /2D/line.c: -------------------------------------------------------------------------------- 1 | #include "line.h" 2 | #include 3 | //draw_line 4 | //draw_line ,,,,,, 5 | void draw_line(thread_context* context, char* args) { 6 | int channel = 0, color = COLOR_TRANSPARENT, height = 0; 7 | double x1 = 0, y1 = 0, x2 = 0, y2 = 0, width = 0; 8 | bool color_empty = true; 9 | 10 | args = read_channel(args, &channel); 11 | 12 | if (is_valid_2D_channel_number(channel)) { 13 | 14 | args = read_double(args, &x1); 15 | args = read_double(args, &y1); 16 | args = read_double(args, &x2); 17 | args = read_double(args, &y2); 18 | args = read_double(args, &width); 19 | args = read_color_arg_empty(args, &color, 4, &color_empty); 20 | 21 | //cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); 22 | 23 | if (debug) printf("draw_line %d,%f,%f,%f,%f,%f,%d\n", channel, x1, y1, x2, y2, width, color); 24 | 25 | channel_info * led_channel = get_channel(channel); 26 | cairo_t* cr = led_channel->cr; 27 | 28 | if (!color_empty) { 29 | set_cairo_color_rgba(cr, color); 30 | } 31 | 32 | cairo_new_path(cr); 33 | cairo_set_line_width(cr, width); 34 | 35 | cairo_move_to(cr, x1, y1); 36 | cairo_line_to(cr, x2, y2); 37 | cairo_stroke(cr); 38 | } else { 39 | fprintf(stderr, ERROR_INVALID_2D_CHANNEL); 40 | } 41 | } 42 | 43 | //draw a sharp 1 pixel line without anti aliasing 44 | //draw_sharp_line ,,,,,, 45 | //width argument must always be 1, not implemented 46 | void draw_sharp_line(thread_context* context, char* args) { 47 | int x, y, dx, dy, dx1, dy1, px, py, xe, ye, i; 48 | int x1, y1, x2, y2, channel, line_width=1; 49 | unsigned int color = 255; 50 | 51 | args = read_channel(args, &channel); 52 | 53 | if (is_valid_2D_channel_number(channel)) { 54 | 55 | args = read_int(args, &x1); 56 | args = read_int(args, &y1); 57 | args = read_int(args, &x2); 58 | args = read_int(args, &y2); 59 | args = read_int(args, &line_width); 60 | args = read_color_arg(args, &color, 3); 61 | 62 | } else { 63 | fprintf(stderr, ERROR_INVALID_2D_CHANNEL); 64 | return; 65 | } 66 | 67 | if (debug) printf("draw_sharp_line %d,%d,%d,%d,%d,%d\n", channel, x1, y1, x2, y2, color); 68 | 69 | channel_info * led_channel = get_channel(channel); 70 | cairo_surface_flush(led_channel->surface); 71 | unsigned int* pixels = (unsigned int*)cairo_image_surface_get_data(led_channel->surface); //get pointer to pixel data 72 | unsigned int pixel_stride = led_channel->pixel_stride; 73 | int width = led_channel->width; 74 | int height = led_channel->height; 75 | 76 | color = convert_cairo_color(color); 77 | 78 | dx = x2 - x1; 79 | dy = y2 - y1; 80 | dx1 = fabs(dx); 81 | dy1 = fabs(dy); 82 | px = 2 * dy1 - dx1; 83 | py = 2 * dx1 - dy1; 84 | if (dy1 <= dx1) 85 | { 86 | if (dx >= 0) 87 | { 88 | x = x1; 89 | y = y1; 90 | xe = x2; 91 | } 92 | else 93 | { 94 | x = x2; 95 | y = y2; 96 | xe = x1; 97 | } 98 | if (y < height && x < width) pixels[y * pixel_stride + x] = color; 99 | for (i = 0;x < xe;i++) 100 | { 101 | x = x + 1; 102 | if (px < 0) 103 | { 104 | px = px + 2 * dy1; 105 | } 106 | else 107 | { 108 | if ((dx < 0 && dy < 0) || (dx > 0 && dy > 0)) 109 | { 110 | y = y + 1; 111 | } 112 | else 113 | { 114 | y = y - 1; 115 | } 116 | px = px + 2 * (dy1 - dx1); 117 | } 118 | if (y < height && x < width) pixels[y * pixel_stride + x] = color; 119 | } 120 | } 121 | else 122 | { 123 | if (dy >= 0) 124 | { 125 | x = x1; 126 | y = y1; 127 | ye = y2; 128 | } 129 | else 130 | { 131 | x = x2; 132 | y = y2; 133 | ye = y1; 134 | } 135 | if (y < height && x < width) pixels[y * pixel_stride + x] = color; 136 | for (i = 0;y < ye;i++) 137 | { 138 | y = y + 1; 139 | if (py <= 0) 140 | { 141 | py = py + 2 * dx1; 142 | } 143 | else 144 | { 145 | if ((dx < 0 && dy < 0) || (dx > 0 && dy > 0)) 146 | { 147 | x = x + 1; 148 | } 149 | else 150 | { 151 | x = x - 1; 152 | } 153 | py = py + 2 * (dx1 - dy1); 154 | } 155 | if (y < height && x < width) pixels[y * pixel_stride + x] = color; 156 | } 157 | } 158 | 159 | cairo_surface_mark_dirty_rectangle(led_channel->surface, (x1 > x2) ? x2 : x1, (y1 > y2) ? y2 : y1, dx, dy); 160 | 161 | } -------------------------------------------------------------------------------- /2D/line.h: -------------------------------------------------------------------------------- 1 | #ifndef _2D_LINE_H 2 | #define _2D_LINE_H 3 | #include "../ws2812svr.h" 4 | 5 | void draw_line(thread_context* context, char* args); 6 | void draw_sharp_line(thread_context* context, char* args); 7 | 8 | #endif -------------------------------------------------------------------------------- /2D/message_board.h: -------------------------------------------------------------------------------- 1 | #ifndef _2D_MESSAGE_BOARD_H 2 | #define _2D_MESSAGE_BOARD_H 3 | #include "../ws2812svr.h" 4 | void message_board(thread_context* context, char* args); 5 | 6 | 7 | #endif -------------------------------------------------------------------------------- /2D/print_text.c: -------------------------------------------------------------------------------- 1 | #include "print_text.h" 2 | //prints text at x,y 3 | //pixel_color ,,,,,,,,, 4 | void print_text(thread_context* context, char* args) { 5 | int channel = 0, x = 0, y = 0, color=0, font_size=8,font_anti_alias = CAIRO_ANTIALIAS_NONE, options = 0, cairo_op = CAIRO_OPERATOR_SOURCE; 6 | char text[MAX_VAL_LEN] = { 0 }; 7 | char font[MAX_VAL_LEN] = { 0 }; 8 | 9 | args = read_channel(args, &channel); 10 | 11 | 12 | if (is_valid_2D_channel_number(channel)) { 13 | 14 | args = read_int(args, &x); 15 | args = read_int(args, &y); 16 | args = read_str(args, text, sizeof(text)); 17 | args = read_color_arg(args, &color, 4); 18 | args = read_int(args, &font_size); 19 | args = read_int(args, &font_anti_alias); 20 | args = read_int(args, &options); 21 | args = read_str(args, font, sizeof(font)); 22 | args = read_int(args, &cairo_op); 23 | 24 | if (font[0] == 0) strcpy(font, DEFAULT_FONT); 25 | 26 | if (debug) printf("print text %d,%d,%d,%s,%d,%d,%d,%d,%s,%d\n", channel, x, y, text, color, font_size, font_anti_alias, options, font, cairo_op); 27 | 28 | channel_info * led_channel = get_channel(channel); 29 | cairo_t* cr = led_channel->cr; 30 | 31 | cairo_save(cr); 32 | cairo_set_operator(cr, cairo_op); 33 | set_cairo_color_rgba(cr, color); 34 | 35 | cairo_font_options_t* font_options = cairo_font_options_create(); 36 | cairo_font_options_set_antialias(font_options, font_anti_alias); //CAIRO_ANTIALIAS_NONE 37 | 38 | FT_Face ft_face; 39 | bool using_freetype_lib = false; 40 | cairo_font_face_t* cairo_ft_face; 41 | 42 | if (file_exists(font)) { //check if file exists and load from file 43 | 44 | if (!init_ft_lib(context)) { 45 | cairo_restore(cr); 46 | return; 47 | } 48 | 49 | FT_Error status = FT_New_Face(context->ft_lib, font, 0, &ft_face); 50 | if (status != 0) { 51 | fprintf(stderr, "Error %d opening font %s.\n", status, font); 52 | cairo_restore(cr); 53 | return; 54 | } 55 | cairo_ft_face = cairo_ft_font_face_create_for_ft_face(ft_face, 0); 56 | 57 | cairo_set_font_face(cr, cairo_ft_face); 58 | using_freetype_lib = true; 59 | 60 | if (debug) printf("using free type file %s.\n", font); 61 | 62 | } else { 63 | if (options & 1) cairo_select_font_face(cr, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); 64 | else cairo_select_font_face(cr, font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); 65 | if (options & 2) cairo_font_options_set_hint_style(font_options, CAIRO_HINT_STYLE_NONE); 66 | 67 | if (debug) printf("Cairo font family %s.\n", font); 68 | } 69 | 70 | /*status = FT_Init_FreeType(&value); 71 | if (status != 0) { 72 | fprintf(stderr, "Error %d opening library.\n", status); 73 | } 74 | status = FT_New_Face(value, font, 0, &face); 75 | if (status != 0) { 76 | fprintf(stderr, "Error %d opening %s.\n", status, font); 77 | } 78 | ct = cairo_ft_font_face_create_for_ft_face(face, 0);*/ 79 | 80 | 81 | 82 | 83 | cairo_set_font_options(cr, font_options); 84 | 85 | cairo_set_font_size(cr, font_size); 86 | 87 | cairo_move_to(cr, x, y); 88 | cairo_show_text(cr, text); 89 | cairo_font_options_destroy(font_options); 90 | 91 | 92 | 93 | 94 | if (using_freetype_lib) { 95 | //https://www.cairographics.org/manual/cairo-FreeType-Fonts.html#cairo-ft-font-face-create-for-ft-face 96 | static const cairo_user_data_key_t key; 97 | cairo_status_t status = cairo_font_face_set_user_data(cairo_ft_face, &key, ft_face, (cairo_destroy_func_t)FT_Done_Face); 98 | 99 | if (status) { 100 | cairo_font_face_destroy(cairo_ft_face); 101 | FT_Done_Face(ft_face); 102 | } 103 | } 104 | 105 | cairo_restore(cr); 106 | 107 | } else { 108 | fprintf(stderr, ERROR_INVALID_2D_CHANNEL); 109 | } 110 | } -------------------------------------------------------------------------------- /2D/print_text.h: -------------------------------------------------------------------------------- 1 | #ifndef _2D_PRINT_TEXT_H 2 | #define _2D_PRINT_TEXT_H 3 | #include "../ws2812svr.h" 4 | 5 | void print_text(thread_context* context, char* args); 6 | 7 | #endif -------------------------------------------------------------------------------- /2D/rectangle.c: -------------------------------------------------------------------------------- 1 | 2 | #include "rectangle.h" 3 | //draw_rectangle 4 | //draw_rectangle ,,,,,,, 5 | void draw_rectangle(thread_context* context, char* args) { 6 | int channel = 0, fill_color = COLOR_TRANSPARENT, border_color= COLOR_TRANSPARENT; 7 | double x = 0.0, y = 0.0, width = 10.0, height = 10.0, border_width = 1.0; 8 | bool fill_color_empty = true; 9 | 10 | args = read_channel(args, &channel); 11 | 12 | if (is_valid_2D_channel_number(channel)) { 13 | 14 | args = read_double(args, &x); 15 | args = read_double(args, &y); 16 | args = read_double(args, &width); 17 | args = read_double(args, &height); 18 | args = read_color_arg_empty(args, &fill_color, 4, &fill_color_empty); 19 | args = read_double(args, &border_width); 20 | args = read_color_arg(args, &border_color, 4); 21 | //cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); 22 | 23 | if (debug) printf("draw_rectangle %d,%d,%d,%d,%d,%d,%d,%d\n", channel, x, y, width, height, color, border_width, border_color); 24 | 25 | channel_info * led_channel = get_channel(channel); 26 | cairo_t* cr = led_channel->cr; 27 | 28 | if (border_width > 0.0) { 29 | cairo_set_line_width(cr, border_width); 30 | set_cairo_color_rgba(cr, border_color); 31 | } 32 | 33 | cairo_rectangle(cr, x, y, width, height); 34 | 35 | if (border_width > 0.0) { 36 | if (!fill_color_empty) cairo_stroke_preserve(cr); 37 | else cairo_stroke(cr); 38 | } 39 | 40 | if (!fill_color_empty) { 41 | set_cairo_color_rgba(cr, fill_color); 42 | cairo_fill(cr); 43 | } 44 | 45 | cairo_fill(cr); 46 | 47 | } else { 48 | fprintf(stderr, ERROR_INVALID_2D_CHANNEL); 49 | } 50 | } -------------------------------------------------------------------------------- /2D/rectangle.h: -------------------------------------------------------------------------------- 1 | #ifndef _2D_RECTANGLE_H 2 | #define _2D_RECTANGLE_H 3 | #include "../ws2812svr.h" 4 | 5 | void draw_rectangle(thread_context* context, char* args); 6 | 7 | #endif -------------------------------------------------------------------------------- /2D/screenshot.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "screenshot.h" 7 | 8 | //take a screen shot 9 | //take_screen_shot ,,,,,,,,,, 10 | void take_screenshot(thread_context* context, char* args) { 11 | char display[MAX_VAL_LEN]; 12 | int channel = 0, src_x=0, src_y=0, src_width=0, src_height=0, interval=0; 13 | double dst_x = 0.0, dst_y = 0.0, dst_width = 0.0, dst_height = 0.0; 14 | 15 | args = read_channel(args, &channel); 16 | 17 | if (is_valid_2D_channel_number(channel)) { 18 | channel_info * led_channel = get_channel(channel); 19 | dst_width = led_channel->width; 20 | dst_height = led_channel->height; 21 | src_width = dst_width; 22 | src_height = dst_height; 23 | 24 | strcpy(display, ":0"); 25 | 26 | args = read_str(args, display, MAX_VAL_LEN); 27 | args = read_double(args, &dst_x); 28 | args = read_double(args, &dst_y); 29 | args = read_int(args, &src_x); 30 | args = read_int(args, &src_y); 31 | args = read_double(args, &dst_width); 32 | args = read_double(args, &dst_height); 33 | args = read_int(args, &src_width); 34 | args = read_int(args, &src_height); 35 | args = read_int(args, &interval); 36 | 37 | Display* disp; 38 | Window root; 39 | cairo_surface_t* src_surface; 40 | int scr; 41 | 42 | if (debug) printf("take_screenshot %d, %s, %d, %d, %d,%d,%d,%d,%d,%d,%d\n", channel, display, dst_x, dst_y, src_x, src_y, dst_width, dst_height, src_width, src_height, interval); 43 | 44 | /* try to connect to display, exit if it's NULL */ 45 | disp = XOpenDisplay(display); 46 | if (disp == NULL) { 47 | fprintf(stderr, "Given display cannot be found %s\n", display); 48 | return; 49 | } 50 | 51 | double xScale = dst_width / (double)src_width; 52 | double yScale = dst_height / (double)src_height; 53 | 54 | cairo_t* cr = led_channel->cr; 55 | 56 | scr = DefaultScreen(disp); 57 | 58 | root = DefaultRootWindow(disp); 59 | 60 | cairo_save(cr); 61 | cairo_scale(cr, xScale, yScale); 62 | 63 | while (!context->end_current_command) { 64 | src_surface = cairo_xlib_surface_create(disp, root, DefaultVisual(disp, scr), DisplayWidth(disp, scr), DisplayHeight(disp, scr)); 65 | cairo_set_source_surface(cr, src_surface, (dst_x / xScale - src_x), (dst_y / yScale - src_y)); 66 | cairo_rectangle(cr, dst_x / xScale, dst_y / yScale, dst_width / xScale, dst_height / yScale); 67 | cairo_fill(cr); 68 | cairo_surface_destroy(src_surface); 69 | 70 | if (interval == 0) { 71 | break; 72 | } else { 73 | usleep(interval * 1000); 74 | render_channel(channel); 75 | if (debug) printf("Render screenshot.\n"); 76 | } 77 | } 78 | 79 | cairo_restore(cr); 80 | 81 | /*cairo_set_source_surface(cr, src_surface, (dst_x / xScale - src_x) , (dst_y / yScale - src_y)); 82 | 83 | cairo_rectangle(cr, dst_x / xScale, dst_y / yScale, dst_width / xScale, dst_height / yScale); 84 | cairo_fill(cr); 85 | 86 | while (interval != 0) { 87 | usleep(interval*1000); 88 | cairo_fill(cr); 89 | render_channel(channel); 90 | 91 | }*/ 92 | 93 | 94 | 95 | //cairo_surface_destroy(src_surface); 96 | 97 | } else { 98 | fprintf(stderr, ERROR_INVALID_2D_CHANNEL); 99 | } 100 | } -------------------------------------------------------------------------------- /2D/screenshot.h: -------------------------------------------------------------------------------- 1 | #ifndef _2D_SCREENSHOT_H 2 | #define _2D_SCREENSHOT_H 3 | #include "../ws2812svr.h" 4 | 5 | void take_screenshot(thread_context* context, char* args); 6 | 7 | #endif -------------------------------------------------------------------------------- /2D/set_pixel.c: -------------------------------------------------------------------------------- 1 | #include "set_pixel.h" 2 | //sets a pixel at x,y location 3 | //pixel_color ,,,, 4 | void set_pixel_color(thread_context* context, char* args) { 5 | int channel = 0, x = 0, y = 0, z = 0, color = 255; 6 | 7 | args = read_channel(args, &channel); 8 | args = read_int(args, &x); 9 | args = read_int(args, &y); 10 | args = read_int(args, &z); 11 | 12 | 13 | 14 | if (is_valid_2D_channel_number(channel)) { 15 | 16 | args = read_color_arg(args, &color, 4); 17 | if (debug) printf("set_pixel_color %d, %d, %d, %d, %d\n", channel, x, y, z, color); 18 | channel_info * led_channel = get_channel(channel); 19 | 20 | if (led_channel->surface != NULL) { 21 | cairo_surface_flush(led_channel->surface); 22 | unsigned int * pixels = (unsigned int*)cairo_image_surface_get_data(led_channel->surface); //get pointer to pixel data 23 | pixels[y * led_channel->pixel_stride + x] = convert_cairo_color((unsigned int) color); 24 | cairo_surface_mark_dirty_rectangle(led_channel->surface, x, y, 1, 1); 25 | } else { 26 | ws2811_led_t*** led_string = get_2D_led_string(channel); 27 | if (led_string!=NULL && led_string[y][x]!=NULL) led_string[y][x]->color = color; 28 | } 29 | } else { 30 | fprintf(stderr, ERROR_INVALID_2D_CHANNEL); 31 | } 32 | } -------------------------------------------------------------------------------- /2D/set_pixel.h: -------------------------------------------------------------------------------- 1 | #ifndef _2D_SET_PIXEL_H 2 | #define _2D_SET_PIXEL_H 3 | #include "../ws2812svr.h" 4 | void set_pixel_color(thread_context* context, char* args); 5 | #endif -------------------------------------------------------------------------------- /2D/text_input.h: -------------------------------------------------------------------------------- 1 | #ifndef _2D_TEXT_INPUT_H 2 | #define _2D_TEXT_INPUT_H 3 | #include "../ws2812svr.h" 4 | 5 | void text_input(thread_context* context, char* args); 6 | 7 | #endif -------------------------------------------------------------------------------- /BCM2835-ARM-Peripherals.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/BCM2835-ARM-Peripherals.pdf -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | 2 | # Version 7.4 3 | * Bug fixes with virtual channels 4 | * Improve audio signal processing 5 | * Add support to stream audio samples to multiple threads 6 | * Fix bugs in documentation 7 | * Python code for the Raspberry Pi Pico W to operate as a slave network channel. 8 | 9 | # Version 7.3 10 | * Add new command "wave" as alternative to "pulses", it renders a low pass audio wave directly to the strip. 11 | 12 | # Version 7.2 13 | * Add new hardware version for Raspberry Pi 4 and Raspberry Pi Zero. 14 | 15 | # Version 7.1 16 | * Fix cairo crash after sending to many characters in the text_input command. 17 | 18 | # Version 7.0 19 | * render command will now render ALL channels if no channel argument is used or 0 as channel number is used (for backwards compatibility) 20 | 21 | # Version 6.9 22 | * Add new command wait_ready_signal. 23 | 24 | # Version 6.8 25 | * make read_png function work with multiple threads at same time 26 | * all brightness arguments now expect number 0-255 27 | 28 | # Version 6.7 29 | * Fix bug with SPI rendering for SK9822 30 | 31 | # Version 6.5 32 | * Add function to render video from camera directly on a 2D panel 33 | * Add function to generate ambilight effect from camera/HDMI capture input 34 | * Improve code by generating header files and splitting files 35 | * Remove the need to enable audio or 2D graphics at compile time 36 | * Support for Raspberry Pi Zero 2 W 37 | * Update documentation 38 | 39 | # Version 6.3 40 | * Fixed bug with SK6812 and 2D panels 41 | * Update documentation 42 | 43 | # Version 6.2 44 | * Added support for audio packets through UDP/named pipe 45 | 46 | # Version 6.1 47 | * Added functions to make LEDs react to audio input 48 | 49 | # Version 6.0 50 | * Added support for 2D graphics 51 | * Added virtual channels 52 | 53 | # Version 5.0 54 | * Fix flickering when using multiple threads and 2xws2811 led strings 55 | 56 | # Version 5.0 57 | * support for new Raspberry Pi 4 revisions 58 | * support added for SK9822 chip 59 | 60 | # Version 4.0 61 | 62 | * now possible to run multiple threads in the background executing different commands at the same time. 63 | * threads can be started from all input methods (TCP, CLI, named pipe). 64 | * added thread synchronization and termination commands. 65 | * new progress bar effect (progress command). 66 | * readpng, readjpg support for horizontal flip of odd rows. 67 | * no need to enter a value for optional commands, for example: progress 1,1,0,,,,,1 will use default values for arguments in ,,,,, 68 | * do ... loop supported from direct console input (CLI). -------------------------------------------------------------------------------- /audio/light_organ.c: -------------------------------------------------------------------------------- 1 | #include "light_organ.h" 2 | #include "record.h" 3 | #include 4 | //light_organ ,,,,,,,,, 5 | //https://github.com/yellobyte/LED-Strip-Light-Organ/blob/main/Software/src/main.cpp 6 | void light_organ(thread_context* context, char* args) { 7 | const unsigned int MAX_COLORS = 255; 8 | int channel = 0; 9 | int duration = 0; 10 | int delay = 25; 11 | int len = 0, start = 0; 12 | unsigned int next_color = 255; 13 | unsigned int colors[MAX_COLORS]; 14 | int color_count = 0; 15 | int color_mode = 2; //default some random colors 16 | int color_change_delay = 60; //60 sec change color 17 | int random_width = 0; //makes random bars in the light organ instead of full filled 18 | float gain = 6.0; 19 | int i; 20 | 21 | if (!context->audio_capture.capturing) { 22 | fprintf(stderr, "Error audio capture is not running on this thread. Use the record_audio command to start capturing first!\n"); 23 | return; 24 | } 25 | 26 | args = read_channel(args, &channel); 27 | 28 | if (is_valid_channel_number(channel)) { 29 | //args = read_float(args, &threshold); 30 | args = read_int(args, &color_mode); 31 | 32 | switch (color_mode) { 33 | case 0: //fixed color 34 | args = read_color_arg(args, &next_color, get_color_size(channel)); 35 | colors[0] = next_color; 36 | break; 37 | case 1: //color sequence 38 | if (*args == ',') args++; 39 | while (color_count < MAX_COLORS && *args != ',' && *args != 0) { 40 | args = read_color(args, &colors[color_count], get_color_size(channel)); 41 | color_count++; 42 | } 43 | next_color = colors[0]; 44 | break; 45 | case 2: //random colors 46 | if (*args == ',') args++; 47 | while (color_count < MAX_COLORS && *args != ',' && *args != 0) { 48 | args = read_color(args, &colors[color_count], get_color_size(channel)); 49 | color_count++; 50 | } 51 | if (color_count == 0) { 52 | colors[0] = color(255, 0, 0); 53 | colors[1] = color(255, 255, 0); 54 | colors[2] = color(0, 255, 255); 55 | colors[3] = color(0, 255, 0); 56 | colors[4] = color(255, 128, 0); 57 | colors[5] = color(255, 0, 128); 58 | colors[6] = color(0, 0, 255); 59 | color_count = 7; 60 | } 61 | next_color = colors[0]; 62 | break; 63 | case 3: //don't care about color 64 | 65 | break; 66 | default: 67 | fprintf(stderr, "Error invalid color mode %d\n", color_mode); 68 | return; 69 | break; 70 | } 71 | 72 | args = read_int(args, &color_change_delay); 73 | args = read_int(args, &duration); 74 | args = read_int(args, &delay); 75 | args = read_int(args, &start); 76 | args = read_int(args, &len); 77 | args = read_int(args, &random_width); 78 | args = read_float(args, &gain); 79 | 80 | if (debug) printf("light_organ %d,%d,%d,%d,%d,%d,%d,%d,%d\n", channel, color_mode, color_count, color_change_delay, duration, delay, start, len, random_width); 81 | 82 | if (start >= get_led_count(channel)) start = 0; 83 | if ((start + len) > get_led_count(channel)) len = get_led_count(channel) - start; 84 | if (len == 0) len = get_led_count(channel); 85 | 86 | ws2811_led_t* leds = get_led_string(channel); 87 | unsigned int start_time = time(0); 88 | unsigned int color_time = time(0); 89 | unsigned int next_color_time = color_time; 90 | unsigned int color_index = 0; 91 | unsigned int current_color = next_color; 92 | 93 | volatile float low_pass_buffer=0; //here the record function will store the number of times threshold was reached 94 | context->audio_capture.capture_dst_buffer = (void*)&low_pass_buffer; 95 | context->audio_capture.dsp_mode = DSP_MODE_AVG; 96 | 97 | int loops = 0; 98 | int width = 1; 99 | if (len > 10 ){ 100 | width = rand() % (len/10); 101 | } 102 | while ((((time(0) - start_time) < duration) || duration == 0) && context->end_current_command == 0) { 103 | float low_pass_value; 104 | 105 | pthread_mutex_lock(&context->audio_capture.buffer_mutex); 106 | low_pass_value = low_pass_buffer; 107 | pthread_mutex_unlock(&context->audio_capture.buffer_mutex); 108 | 109 | unsigned int intensity = 255.0 * low_pass_value * gain; 110 | 111 | if (color_mode!=3 && next_color_time <= time(0)) { 112 | switch (color_mode) { 113 | case 0: //fixed color 114 | break; 115 | case 1: //color sequence 116 | next_color = colors[color_index]; 117 | color_index++; 118 | if (color_index == color_count) color_index = 0; 119 | break; 120 | case 2: //random color from color list 121 | color_index = (float)color_count * ((float)rand() / (float)RAND_MAX); 122 | next_color = colors[color_index]; 123 | break; 124 | } 125 | next_color_time = time(0) + color_change_delay; 126 | for (i = 0;i < len;i++) { 127 | leds[start + i].color = next_color; 128 | } 129 | } 130 | 131 | if (random_width){ 132 | if (loops == 10){ 133 | if (len < 10){ 134 | width = rand() % (len/10); 135 | }else{ 136 | width = 1; 137 | } 138 | loops=0; 139 | } 140 | for (i = 0;i < len;i++) { 141 | if ((i % (len/10)) >= width){ 142 | leds[start + i].brightness = intensity; 143 | }else{ 144 | leds[start + i].brightness = 0; 145 | } 146 | } 147 | loops++; 148 | }else{ 149 | for (i = 0;i < len;i++) { 150 | leds[start + i].brightness = intensity; 151 | } 152 | } 153 | 154 | render_channel(channel); 155 | usleep(delay * 1000); 156 | 157 | } 158 | context->audio_capture.dsp_mode = DSP_MODE_NONE; 159 | } 160 | else { 161 | fprintf(stderr, ERROR_INVALID_CHANNEL); 162 | } 163 | } -------------------------------------------------------------------------------- /audio/light_organ.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIO_LIGHT_ORGAN_H 2 | #define AUDIO_LIGHT_ORGAN_H 3 | #include "../ws2812svr.h" 4 | void light_organ(thread_context* context, char* args); 5 | #endif -------------------------------------------------------------------------------- /audio/pulses.c: -------------------------------------------------------------------------------- 1 | #include "pulses.h" 2 | #include "record.h" 3 | #include 4 | //audio_pulses ,,,,,,,,,, 5 | void audio_pulses(thread_context* context, char* args) { 6 | const unsigned int MAX_COLORS = 255; 7 | int channel=0; 8 | int duration = 0; 9 | int delay = 25; 10 | int len = 0, start = 0; 11 | int direction = 0; 12 | int min_brightness = 10; 13 | unsigned int next_color = 255; 14 | unsigned int colors[MAX_COLORS]; 15 | int color_count = 0; 16 | int color_mode = 2; //default some random colors 17 | int color_change_count = 200; //5 sec with delay = 25 18 | int color_change_delay = 5; 19 | float threshold=0.1; 20 | 21 | if (!context->audio_capture.capturing) { 22 | fprintf(stderr, "Error audio capture is not running on this thread. Use the record_audio command to start capturing first!\n"); 23 | return; 24 | } 25 | 26 | args = read_channel(args, &channel); 27 | 28 | if (is_valid_channel_number(channel)) { 29 | args = read_float(args, &threshold); 30 | args = read_int(args, &color_mode); 31 | 32 | switch (color_mode) { 33 | case 0: //fixed color 34 | args = read_color_arg(args, &next_color, get_color_size(channel)); 35 | colors[0] = next_color; 36 | break; 37 | case 1: //color sequence 38 | if (*args == ',') args++; 39 | while (color_count < MAX_COLORS && *args!=',' && *args!=0) { 40 | args = read_color(args, &colors[color_count], get_color_size(channel)); 41 | color_count++; 42 | } 43 | next_color = colors[0]; 44 | break; 45 | case 2: //random colors 46 | if (*args == ',') args++; 47 | while (color_count < MAX_COLORS && *args != ',' && *args != 0) { 48 | args = read_color(args, &colors[color_count], get_color_size(channel)); 49 | color_count++; 50 | } 51 | if (color_count == 0) { 52 | colors[0] = color(255, 0, 0); 53 | colors[1] = color(255, 255, 0); 54 | colors[2] = color(0, 255, 255); 55 | colors[3] = color(0, 255, 0); 56 | colors[4] = color(255, 128, 0); 57 | colors[5] = color(255, 0, 128); 58 | colors[6] = color(0, 0, 255); 59 | color_count = 7; 60 | } 61 | next_color = colors[0]; 62 | break; 63 | case 3: //don't care about colors 64 | break; 65 | default: 66 | fprintf(stderr, "Error invalid color mode %d\n", color_mode); 67 | return; 68 | break; 69 | } 70 | 71 | args = read_int(args, &delay); 72 | args = read_int(args, &color_change_delay); 73 | args = read_int(args, &direction); 74 | args = read_int(args, &duration); 75 | args = read_int(args, &min_brightness); 76 | args = read_int(args, &start); 77 | args = read_int(args, &len); 78 | 79 | if (debug) printf("audio_pulses %d,%f,%d,%d (%d),%d,%d,%d,%d,%d,%d,%d\n", channel, threshold, color_mode, next_color, color_count, delay, color_change_delay, direction, duration, min_brightness, start, len); 80 | 81 | if (start >= get_led_count(channel)) start = 0; 82 | if ((start + len) > get_led_count(channel)) len = get_led_count(channel) - start; 83 | if (len == 0) len = get_led_count(channel); 84 | 85 | color_change_count = color_change_delay * 1000 / delay; 86 | 87 | context->audio_capture.threshold = threshold; 88 | 89 | ws2811_led_t* leds = get_led_string(channel); 90 | unsigned int start_time = time(0); 91 | unsigned int loop_count = 0; 92 | unsigned int color_index = 0; 93 | unsigned int current_color = next_color; 94 | 95 | volatile unsigned int threshold_reached_buffer=0; //here the record function will store the number of times threshold was reached 96 | context->audio_capture.capture_dst_buffer = (void*)&threshold_reached_buffer; 97 | context->audio_capture.dsp_mode = DSP_MODE_THRESHOLD; 98 | 99 | while ((((time(0) - start_time) < duration) || duration == 0) && context->end_current_command == 0) { 100 | unsigned int threshold_reached; 101 | 102 | pthread_mutex_lock(&context->audio_capture.buffer_mutex); 103 | threshold_reached = threshold_reached_buffer; 104 | threshold_reached_buffer = 0; 105 | pthread_mutex_unlock(&context->audio_capture.buffer_mutex); 106 | 107 | unsigned int intensity = 255 * threshold_reached / (context->audio_capture.channel_count * context->audio_capture.dsp_buffer_sample_count); 108 | 109 | if (intensity < min_brightness) intensity = 0; 110 | 111 | //if (debug) printf("intensity: %d\n", intensity); 112 | 113 | //move all leds 1 position 114 | unsigned int n; 115 | if (direction) { 116 | for (n = 0;n < len - 1;n++) { 117 | if (color_mode != 3) leds[start + n].color = leds[start + n + 1].color; 118 | leds[start + n].brightness = leds[start + n + 1].brightness; 119 | } 120 | } else { 121 | for (n = len - 1; n > 0; n--) { 122 | if (color_mode != 3) leds[start + n].color = leds[start + n - 1].color; 123 | leds[start + n].brightness = leds[start + n - 1].brightness; 124 | } 125 | } 126 | 127 | //set first or last led to new intensity 128 | if (direction) { 129 | if (color_mode != 3) leds[start + len - 1].color = next_color; 130 | leds[start + len - 1].brightness = intensity; 131 | } else { 132 | if (color_mode != 3) leds[start].color = next_color; 133 | leds[start].brightness = intensity; 134 | } 135 | 136 | render_channel(channel); 137 | usleep(delay * 1000); 138 | 139 | if (loop_count >= color_change_count) { 140 | switch (color_mode) { 141 | case 1: 142 | next_color = colors[color_index]; 143 | color_index++; 144 | if (color_index == color_count) color_index = 0; 145 | break; 146 | case 2: 147 | color_index = (float)color_count * ((float)rand() / (float)RAND_MAX); 148 | next_color = colors[color_index]; 149 | break; 150 | case 3: //don't care 151 | case 0: 152 | break; 153 | } 154 | loop_count = 0; 155 | } 156 | 157 | loop_count++; 158 | } 159 | context->audio_capture.dsp_mode = DSP_MODE_NONE; 160 | } else { 161 | fprintf(stderr, ERROR_INVALID_CHANNEL); 162 | } 163 | } -------------------------------------------------------------------------------- /audio/pulses.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIO_PULSES_H 2 | #define AUDIO_PULSES_H 3 | #include "../ws2812svr.h" 4 | 5 | void audio_pulses(thread_context* context, char* args); 6 | 7 | #endif -------------------------------------------------------------------------------- /audio/record.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIO_RECORD_H 2 | #define AUDIO_RECORD_H 3 | 4 | #include "../ws2812svr.h" 5 | 6 | #define AUDIO_CAPTURE_FORMAT SND_PCM_FORMAT_FLOAT_LE 7 | #define DSP_MODE_NONE 0 8 | #define DSP_MODE_THRESHOLD 1 9 | #define DSP_MODE_AVG 2 10 | 11 | void record_audio(thread_context* context, char* args); 12 | void filter_audio(thread_context* context, char* args); 13 | #endif -------------------------------------------------------------------------------- /audio/test.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/audio/test.wav -------------------------------------------------------------------------------- /audio/vu_meter.c: -------------------------------------------------------------------------------- 1 | #include "vu_meter.h" 2 | #include "record.h" 3 | #include 4 | #include 5 | //vu_meter ,[,],,,,,,, 6 | void vu_meter(thread_context* context, char* args) { 7 | const unsigned int MAX_COLORS = 255; 8 | int channel = 0; 9 | int duration = 0; 10 | int delay = 25; 11 | int len = 0, start = 0; 12 | unsigned int next_color = 255; 13 | unsigned int colors[MAX_COLORS]; 14 | int color_count = 0; 15 | int color_mode = 4; //default classic VU meter 16 | int color_change_delay = 60; //60 sec change color 17 | int brightness = 255; 18 | float gain = 1.0; 19 | int i; 20 | 21 | if (!context->audio_capture.capturing) { 22 | fprintf(stderr, "Error audio capture is not running on this thread. Use the record_audio command to start capturing first!\n"); 23 | return; 24 | } 25 | 26 | args = read_channel(args, &channel); 27 | 28 | if (is_valid_channel_number(channel)) { 29 | //args = read_float(args, &threshold); 30 | args = read_int(args, &color_mode); 31 | 32 | switch (color_mode) { 33 | case 0: //fixed color 34 | args = read_color_arg(args, &next_color, get_color_size(channel)); 35 | colors[0] = next_color; 36 | color_count = 1; 37 | break; 38 | case 1: //color sequence 39 | if (*args == ',') args++; 40 | while (color_count < MAX_COLORS && *args != ',' && *args != 0) { 41 | args = read_color(args, &colors[color_count], get_color_size(channel)); 42 | color_count++; 43 | } 44 | next_color = colors[0]; 45 | break; 46 | case 2: //random colors 47 | if (*args == ',') args++; 48 | while (color_count < MAX_COLORS && *args != ',' && *args != 0) { 49 | args = read_color(args, &colors[color_count], get_color_size(channel)); 50 | color_count++; 51 | } 52 | if (color_count == 0) { 53 | colors[0] = color(255, 0, 0); 54 | colors[1] = color(255, 255, 0); 55 | colors[2] = color(0, 255, 255); 56 | colors[3] = color(0, 255, 0); 57 | colors[4] = color(255, 128, 0); 58 | colors[5] = color(255, 0, 128); 59 | colors[6] = color(0, 0, 255); 60 | color_count = 7; 61 | } 62 | next_color = colors[0]; 63 | break; 64 | case 3: //don't care about color 65 | break; 66 | case 4: //create green - orange - yellow - red classic VU meter, this is done when we know the start and length 67 | break; 68 | default: 69 | fprintf(stderr, "Error invalid color mode %d\n", color_mode); 70 | return; 71 | break; 72 | } 73 | 74 | if (debug) { 75 | printf("color count: %d\n", color_count); 76 | for (i = 0;i < color_count;i++) { 77 | printf("Color %d=%d\n", i, colors[i]); 78 | } 79 | } 80 | 81 | args = read_int(args, &color_change_delay); 82 | args = read_int(args, &duration); 83 | args = read_int(args, &delay); 84 | args = read_int(args, &brightness); 85 | args = read_int(args, &start); 86 | args = read_int(args, &len); 87 | args = read_float(args, &gain); 88 | 89 | if (debug) printf("vu_meter %d, %d, %d, %d, %d, %d, %d, %d\n", color_mode, color_change_delay, duration, delay, brightness, start, len, gain); 90 | 91 | if (start >= get_led_count(channel)) start = 0; 92 | if ((start + len) > get_led_count(channel)) len = get_led_count(channel) - start; 93 | if (len == 0) len = get_led_count(channel); 94 | 95 | 96 | ws2811_led_t* leds = get_led_string(channel); 97 | 98 | unsigned int start_time = time(0); 99 | unsigned int color_time = time(0); 100 | unsigned int next_color_time = color_time; 101 | unsigned int color_index = 0; 102 | unsigned int current_color = next_color; 103 | 104 | volatile float low_pass_buffer=0; //here the record function will store the number of times threshold was reached 105 | context->audio_capture.capture_dst_buffer = (void*)&low_pass_buffer; 106 | context->audio_capture.dsp_mode = DSP_MODE_AVG; 107 | 108 | const float REFERENCE = 32768; 109 | float MIN_DB = 20 * log10(1.0 / REFERENCE); 110 | float MAX_DB = 0; 111 | 112 | if (color_mode == 4) { //generate classic VU meter colors 113 | 114 | for (i = 0;i < len;i++) { 115 | 116 | int perc = 100 * i / len; 117 | 118 | if (perc > 85) { 119 | leds[start + i].color = color(255, 0, 0); 120 | }else if (perc > 80) { 121 | leds[start + i].color = color(255, 128, 0); 122 | }else if (perc > 75) { 123 | leds[start + i].color = color(255, 255, 0); 124 | }else if (perc > 70) { 125 | leds[start + i].color = color(128, 255, 0); 126 | }else { 127 | leds[start + i].color = color(0, 255, 0); 128 | } 129 | } 130 | } 131 | 132 | while ((((time(0) - start_time) < duration) || duration == 0) && context->end_current_command == 0) { 133 | float low_pass_value; 134 | 135 | pthread_mutex_lock(&context->audio_capture.buffer_mutex); 136 | low_pass_value = low_pass_buffer; 137 | pthread_mutex_unlock(&context->audio_capture.buffer_mutex); 138 | 139 | //https://forums.codeguru.com/showthread.php?445227-RESOLVED-VU-Meter 140 | float db = low_pass_value > 0 ? 20 * log10(low_pass_value * gain) : -1000000; 141 | int nLEDS = (int)((db - MIN_DB) * len / (MAX_DB - MIN_DB)); 142 | 143 | 144 | if (color_mode != 3 && color_mode !=4 && next_color_time <= time(0)) { 145 | switch (color_mode) { 146 | case 0: //fixed color 147 | break; 148 | case 1: //color sequence 149 | next_color = colors[color_index]; 150 | color_index++; 151 | if (color_index == color_count) color_index = 0; 152 | break; 153 | case 2: //random color from color list 154 | color_index = (float)color_count * ((float)rand() / (float)RAND_MAX); 155 | next_color = colors[color_index]; 156 | break; 157 | } 158 | next_color_time = time(0) + color_change_delay; 159 | for (i = 0;i < len;i++) { 160 | leds[start + i].color = next_color; 161 | } 162 | } 163 | 164 | for (i = 0;i < len;i++) { 165 | if (i <= nLEDS) { 166 | leds[start + i].brightness = brightness; 167 | } else { 168 | leds[start + i].brightness = 0; 169 | } 170 | } 171 | 172 | render_channel(channel); 173 | usleep(delay * 1000); 174 | 175 | } 176 | context->audio_capture.dsp_mode = DSP_MODE_NONE; 177 | } 178 | else { 179 | fprintf(stderr, ERROR_INVALID_CHANNEL); 180 | } 181 | } -------------------------------------------------------------------------------- /audio/vu_meter.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIO_VU_METER_H 2 | #define AUDIO_VU_METER_H 3 | #include "../ws2812svr.h" 4 | 5 | void vu_meter(thread_context* context, char* args); 6 | 7 | #endif -------------------------------------------------------------------------------- /audio/wave.c: -------------------------------------------------------------------------------- 1 | #include "wave.h" 2 | #include "record.h" 3 | #include 4 | #include 5 | //audio_wave ,,,,,,,,,, 6 | //prints low pass audio wave directly on the strip 7 | void audio_wave(thread_context* context, char* args) { 8 | const unsigned int MAX_COLORS = 255; 9 | int channel=0; 10 | int duration = 0; 11 | int delay = 35; 12 | int len = 0, start = 0; 13 | int direction = 0; 14 | unsigned int next_color = 255; 15 | unsigned int colors[MAX_COLORS]; 16 | int min_brightness = 20; 17 | int color_count = 0; 18 | int color_mode = 2; //default some random colors 19 | int color_change_count = 200; //5 sec with delay = 25 20 | int color_change_delay = 5; 21 | float gain=4.0; 22 | 23 | if (!context->audio_capture.capturing) { 24 | fprintf(stderr, "Error audio capture is not running on this thread. Use the record_audio command to start capturing first!\n"); 25 | return; 26 | } 27 | 28 | args = read_channel(args, &channel); 29 | 30 | if (is_valid_channel_number(channel)) { 31 | args = read_float(args, &gain); 32 | args = read_int(args, &color_mode); 33 | 34 | switch (color_mode) { 35 | case 0: //fixed color 36 | args = read_color_arg(args, &next_color, get_color_size(channel)); 37 | colors[0] = next_color; 38 | break; 39 | case 1: //color sequence 40 | if (*args == ',') args++; 41 | while (color_count < MAX_COLORS && *args!=',' && *args!=0) { 42 | args = read_color(args, &colors[color_count], get_color_size(channel)); 43 | color_count++; 44 | } 45 | next_color = colors[0]; 46 | break; 47 | case 2: //random colors 48 | if (*args == ',') args++; 49 | while (color_count < MAX_COLORS && *args != ',' && *args != 0) { 50 | args = read_color(args, &colors[color_count], get_color_size(channel)); 51 | color_count++; 52 | } 53 | if (color_count == 0) { 54 | colors[0] = color(255, 0, 0); 55 | colors[1] = color(255, 255, 0); 56 | colors[2] = color(0, 255, 255); 57 | colors[3] = color(0, 255, 0); 58 | colors[4] = color(255, 128, 0); 59 | colors[5] = color(255, 0, 128); 60 | colors[6] = color(0, 0, 255); 61 | color_count = 7; 62 | } 63 | next_color = colors[0]; 64 | break; 65 | case 3: //don't care about colors 66 | break; 67 | default: 68 | fprintf(stderr, "Error invalid color mode %d\n", color_mode); 69 | return; 70 | break; 71 | } 72 | 73 | args = read_int(args, &delay); 74 | args = read_int(args, &color_change_delay); 75 | args = read_int(args, &direction); 76 | args = read_int(args, &duration); 77 | args = read_int(args, &min_brightness); 78 | args = read_int(args, &start); 79 | args = read_int(args, &len); 80 | 81 | if (debug) printf("audio_pulses %d,%f,%d,%d (%d),%d,%d,%d,%d,%d,%d,%d\n", channel, gain, color_mode, next_color, color_count, delay, color_change_delay, direction, duration, min_brightness, start, len); 82 | 83 | if (start >= get_led_count(channel)) start = 0; 84 | if ((start + len) > get_led_count(channel)) len = get_led_count(channel) - start; 85 | if (len == 0) len = get_led_count(channel); 86 | 87 | color_change_count = color_change_delay * 1000 / delay; 88 | 89 | context->audio_capture.threshold = 0; 90 | 91 | ws2811_led_t* leds = get_led_string(channel); 92 | unsigned int start_time = time(0); 93 | unsigned int loop_count = 0; 94 | unsigned int color_index = 0; 95 | unsigned int current_color = next_color; 96 | 97 | volatile float low_pass_buffer=0; //here the record function will store the number of times threshold was reached 98 | context->audio_capture.capture_dst_buffer = (void*)&low_pass_buffer; 99 | context->audio_capture.dsp_mode = DSP_MODE_AVG; 100 | 101 | //const float REFERENCE = 32768; 102 | //float MIN_DB = 20 * log10(1.0 / REFERENCE); 103 | //float MAX_DB = 0; 104 | 105 | while ((((time(0) - start_time) < duration) || duration == 0) && context->end_current_command == 0) { 106 | float low_pass_value; 107 | 108 | pthread_mutex_lock(&context->audio_capture.buffer_mutex); 109 | low_pass_value = low_pass_buffer * gain; 110 | pthread_mutex_unlock(&context->audio_capture.buffer_mutex); 111 | 112 | //float db = low_pass_value > 0 ? 20 * log10(low_pass_value) : -1000000; 113 | ///unsigned int intensity = (int)((db - MIN_DB) * 255.0 / (MAX_DB - MIN_DB)); 114 | 115 | unsigned int intensity = 255.0 * low_pass_value; 116 | 117 | if (intensity < min_brightness) intensity = 0; 118 | 119 | //move all leds 1 position 120 | unsigned int n; 121 | if (direction) { 122 | for (n = 0;n < len - 1;n++) { 123 | if (color_mode != 3) leds[start + n].color = leds[start + n + 1].color; 124 | leds[start + n].brightness = leds[start + n + 1].brightness; 125 | } 126 | } else { 127 | for (n = len - 1; n > 0; n--) { 128 | if (color_mode != 3) leds[start + n].color = leds[start + n - 1].color; 129 | leds[start + n].brightness = leds[start + n - 1].brightness; 130 | } 131 | } 132 | 133 | //set first or last led to new intensity 134 | if (direction) { 135 | if (color_mode != 3) leds[start + len - 1].color = next_color; 136 | leds[start + len - 1].brightness = intensity; 137 | } else { 138 | if (color_mode != 3) leds[start].color = next_color; 139 | leds[start].brightness = intensity; 140 | } 141 | 142 | render_channel(channel); 143 | usleep(delay * 1000); 144 | 145 | if (loop_count >= color_change_count) { 146 | switch (color_mode) { 147 | case 1: 148 | next_color = colors[color_index]; 149 | color_index++; 150 | if (color_index == color_count) color_index = 0; 151 | break; 152 | case 2: 153 | color_index = (float)color_count * ((float)rand() / (float)RAND_MAX); 154 | next_color = colors[color_index]; 155 | break; 156 | case 3: //don't care 157 | case 0: 158 | break; 159 | } 160 | loop_count = 0; 161 | } 162 | 163 | loop_count++; 164 | } 165 | context->audio_capture.dsp_mode = DSP_MODE_NONE; 166 | } else { 167 | fprintf(stderr, ERROR_INVALID_CHANNEL); 168 | } 169 | } -------------------------------------------------------------------------------- /audio/wave.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIO_WAVE_H 2 | #define AUDIO_WAVE_H 3 | #include "../ws2812svr.h" 4 | 5 | void audio_wave(thread_context* context, char* args); 6 | 7 | #endif -------------------------------------------------------------------------------- /clk.h: -------------------------------------------------------------------------------- 1 | /* 2 | * clk.h 3 | * 4 | * Copyright (c) 2014 Jeremy Garff 5 | * 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without modification, are permitted 9 | * provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, this list of 12 | * conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 14 | * of conditions and the following disclaimer in the documentation and/or other materials 15 | * provided with the distribution. 16 | * 3. Neither the name of the owner nor the names of its contributors may be used to endorse 17 | * or promote products derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 24 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | */ 29 | 30 | #ifndef __CLK_H__ 31 | #define __CLK_H__ 32 | 33 | #include 34 | 35 | typedef struct { 36 | uint32_t ctl; 37 | #define CM_CLK_CTL_PASSWD (0x5a << 24) 38 | #define CM_CLK_CTL_MASH(val) ((val & 0x3) << 9) 39 | #define CM_CLK_CTL_FLIP (1 << 8) 40 | #define CM_CLK_CTL_BUSY (1 << 7) 41 | #define CM_CLK_CTL_KILL (1 << 5) 42 | #define CM_CLK_CTL_ENAB (1 << 4) 43 | #define CM_CLK_CTL_SRC_GND (0 << 0) 44 | #define CM_CLK_CTL_SRC_OSC (1 << 0) 45 | #define CM_CLK_CTL_SRC_TSTDBG0 (2 << 0) 46 | #define CM_CLK_CTL_SRC_TSTDBG1 (3 << 0) 47 | #define CM_CLK_CTL_SRC_PLLA (4 << 0) 48 | #define CM_CLK_CTL_SRC_PLLC (5 << 0) 49 | #define CM_CLK_CTL_SRC_PLLD (6 << 0) 50 | #define CM_CLK_CTL_SRC_HDMIAUX (7 << 0) 51 | uint32_t div; 52 | #define CM_CLK_DIV_PASSWD (0x5a << 24) 53 | #define CM_CLK_DIV_DIVI(val) ((val & 0xfff) << 12) 54 | #define CM_CLK_DIV_DIVF(val) ((val & 0xfff) << 0) 55 | } __attribute__((packed, aligned(4))) cm_clk_t; 56 | 57 | 58 | /* 59 | * PWM and PCM clock offsets from https://www.scribd.com/doc/127599939/BCM2835-Audio-clocks 60 | * 61 | */ 62 | #define CM_PCM_OFFSET (0x00101098) 63 | #define CM_PWM_OFFSET (0x001010a0) 64 | 65 | 66 | #endif /* __CLK_H__ */ -------------------------------------------------------------------------------- /dma.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dma.c 3 | * 4 | * Copyright (c) 2014 Jeremy Garff 5 | * 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without modification, are permitted 9 | * provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, this list of 12 | * conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 14 | * of conditions and the following disclaimer in the documentation and/or other materials 15 | * provided with the distribution. 16 | * 3. Neither the name of the owner nor the names of its contributors may be used to endorse 17 | * or promote products derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 24 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | */ 29 | 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | #include "dma.h" 42 | 43 | 44 | // DMA address mapping by DMA number index 45 | static const uint32_t dma_offset[] = 46 | { 47 | DMA0_OFFSET, 48 | DMA1_OFFSET, 49 | DMA2_OFFSET, 50 | DMA3_OFFSET, 51 | DMA4_OFFSET, 52 | DMA5_OFFSET, 53 | DMA6_OFFSET, 54 | DMA7_OFFSET, 55 | DMA8_OFFSET, 56 | DMA9_OFFSET, 57 | DMA10_OFFSET, 58 | DMA11_OFFSET, 59 | DMA12_OFFSET, 60 | DMA13_OFFSET, 61 | DMA14_OFFSET, 62 | DMA15_OFFSET, 63 | }; 64 | 65 | 66 | uint32_t dmanum_to_offset(int dmanum) 67 | { 68 | int array_size = sizeof(dma_offset) / sizeof(dma_offset[0]); 69 | 70 | if (dmanum >= array_size) 71 | { 72 | return 0; 73 | } 74 | 75 | return dma_offset[dmanum]; 76 | } 77 | 78 | 79 | -------------------------------------------------------------------------------- /dma.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dma.h 3 | * 4 | * Copyright (c) 2014 Jeremy Garff 5 | * 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without modification, are permitted 9 | * provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, this list of 12 | * conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 14 | * of conditions and the following disclaimer in the documentation and/or other materials 15 | * provided with the distribution. 16 | * 3. Neither the name of the owner nor the names of its contributors may be used to endorse 17 | * or promote products derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 24 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | */ 29 | 30 | #ifndef __DMA_H__ 31 | #define __DMA_H__ 32 | 33 | #include 34 | 35 | /* 36 | * DMA Control Block in Main Memory 37 | * 38 | * Note: Must start at a 256 byte aligned address. 39 | * Use corresponding register field definitions. 40 | */ 41 | typedef struct 42 | { 43 | uint32_t ti; 44 | uint32_t source_ad; 45 | uint32_t dest_ad; 46 | uint32_t txfr_len; 47 | uint32_t stride; 48 | uint32_t nextconbk; 49 | uint32_t resvd_0x18[2]; 50 | } __attribute__((packed, aligned(4))) dma_cb_t; 51 | 52 | /* 53 | * DMA register set 54 | */ 55 | typedef struct 56 | { 57 | uint32_t cs; 58 | #define RPI_DMA_CS_RESET (1 << 31) 59 | #define RPI_DMA_CS_ABORT (1 << 30) 60 | #define RPI_DMA_CS_DISDEBUG (1 << 29) 61 | #define RPI_DMA_CS_WAIT_OUTSTANDING_WRITES (1 << 28) 62 | #define RPI_DMA_CS_PANIC_PRIORITY(val) ((val & 0xf) << 20) 63 | #define RPI_DMA_CS_PRIORITY(val) ((val & 0xf) << 16) 64 | #define RPI_DMA_CS_ERROR (1 << 8) 65 | #define RPI_DMA_CS_WAITING_OUTSTANDING_WRITES (1 << 6) 66 | #define RPI_DMA_CS_DREQ_STOPS_DMA (1 << 5) 67 | #define RPI_DMA_CS_PAUSED (1 << 4) 68 | #define RPI_DMA_CS_DREQ (1 << 3) 69 | #define RPI_DMA_CS_INT (1 << 2) 70 | #define RPI_DMA_CS_END (1 << 1) 71 | #define RPI_DMA_CS_ACTIVE (1 << 0) 72 | uint32_t conblk_ad; 73 | uint32_t ti; 74 | #define RPI_DMA_TI_NO_WIDE_BURSTS (1 << 26) 75 | #define RPI_DMA_TI_WAITS(val) ((val & 0x1f) << 21) 76 | #define RPI_DMA_TI_PERMAP(val) ((val & 0x1f) << 16) 77 | #define RPI_DMA_TI_BURST_LENGTH(val) ((val & 0xf) << 12) 78 | #define RPI_DMA_TI_SRC_IGNORE (1 << 11) 79 | #define RPI_DMA_TI_SRC_DREQ (1 << 10) 80 | #define RPI_DMA_TI_SRC_WIDTH (1 << 9) 81 | #define RPI_DMA_TI_SRC_INC (1 << 8) 82 | #define RPI_DMA_TI_DEST_IGNORE (1 << 7) 83 | #define RPI_DMA_TI_DEST_DREQ (1 << 6) 84 | #define RPI_DMA_TI_DEST_WIDTH (1 << 5) 85 | #define RPI_DMA_TI_DEST_INC (1 << 4) 86 | #define RPI_DMA_TI_WAIT_RESP (1 << 3) 87 | #define RPI_DMA_TI_TDMODE (1 << 1) 88 | #define RPI_DMA_TI_INTEN (1 << 0) 89 | uint32_t source_ad; 90 | uint32_t dest_ad; 91 | uint32_t txfr_len; 92 | #define RPI_DMA_TXFR_LEN_YLENGTH(val) ((val & 0xffff) << 16) 93 | #define RPI_DMA_TXFR_LEN_XLENGTH(val) ((val & 0xffff) << 0) 94 | uint32_t stride; 95 | #define RPI_DMA_STRIDE_D_STRIDE(val) ((val & 0xffff) << 16) 96 | #define RPI_DMA_STRIDE_S_STRIDE(val) ((val & 0xffff) << 0) 97 | uint32_t nextconbk; 98 | uint32_t debug; 99 | } __attribute__((packed, aligned(4))) dma_t; 100 | 101 | 102 | #define DMA0_OFFSET (0x00007000) 103 | #define DMA1_OFFSET (0x00007100) 104 | #define DMA2_OFFSET (0x00007200) 105 | #define DMA3_OFFSET (0x00007300) 106 | #define DMA4_OFFSET (0x00007400) 107 | #define DMA5_OFFSET (0x00007500) 108 | #define DMA6_OFFSET (0x00007600) 109 | #define DMA7_OFFSET (0x00007700) 110 | #define DMA8_OFFSET (0x00007800) 111 | #define DMA9_OFFSET (0x00007900) 112 | #define DMA10_OFFSET (0x00007a00) 113 | #define DMA11_OFFSET (0x00007b00) 114 | #define DMA12_OFFSET (0x00007c00) 115 | #define DMA13_OFFSET (0x00007d00) 116 | #define DMA14_OFFSET (0x00007e00) 117 | #define DMA15_OFFSET (0x00e05000) 118 | 119 | 120 | #define PAGE_SIZE (1 << 12) 121 | #define PAGE_MASK (~(PAGE_SIZE - 1)) 122 | #define PAGE_OFFSET(page) (page & (PAGE_SIZE - 1)) 123 | 124 | 125 | uint32_t dmanum_to_offset(int dmanum); 126 | 127 | #endif /* __DMA_H__ */ -------------------------------------------------------------------------------- /effects/add_random.c: -------------------------------------------------------------------------------- 1 | #include "add_random.h" 2 | 3 | #include 4 | //generates random colors 5 | //random ,,, 6 | void add_random(thread_context * context, char * args){ 7 | char value[MAX_VAL_LEN]; 8 | int channel=0; 9 | unsigned int start=0, len=0; 10 | char component='L'; //L is brightness level 11 | int use_r=1, use_g=1, use_b=1, use_w=1, use_l=1; 12 | 13 | if (is_valid_channel_number(channel)){ 14 | len = get_led_count(channel); 15 | } 16 | 17 | args = read_channel(args, & channel); 18 | if (is_valid_channel_number(channel)){ 19 | len = get_led_count(channel); 20 | } 21 | args = read_int(args, & start); 22 | args = read_int(args, & len); 23 | if (args!=NULL && *args!=0){ 24 | args = read_val(args, value, MAX_VAL_LEN); 25 | use_r=0, use_g=0, use_b=0, use_w=0, use_l=0; 26 | unsigned char i; 27 | for (i=0;i=get_led_count(channel)) start=0; 51 | if ((start+len)>get_led_count(channel)) len=get_led_count(channel)-start; 52 | 53 | if (debug) printf("random %d,%d,%d\n", channel, start, len); 54 | 55 | ws2811_led_t * leds = get_led_string(channel); 56 | //unsigned int colors = ledstring[channel].color_size; 57 | unsigned char r=0,g=0,b=0,w=0,l=0; 58 | unsigned int i; 59 | for (i=0; i,,,,,, 4 | void blink (thread_context * context, char * args){ 5 | int channel=0, color1=0, color2=0xFFFFFF,delay=1000, count=10; 6 | unsigned int start=0, len=0; 7 | 8 | if (is_valid_channel_number(channel)){ 9 | len = get_led_count(channel); 10 | } 11 | 12 | args = read_channel(args, & channel); 13 | if (is_valid_channel_number(channel)){ 14 | len = get_led_count(channel); 15 | } 16 | 17 | if (is_valid_channel_number(channel)) args = read_color_arg(args, & color1, get_color_size(channel)); 18 | if (is_valid_channel_number(channel)) args = read_color_arg(args, & color2, get_color_size(channel)); 19 | args = read_int(args, & delay); 20 | args = read_int(args, & count); 21 | args = read_int(args, & start); 22 | args = read_int(args, & len); 23 | 24 | 25 | if (is_valid_channel_number(channel)){ 26 | 27 | if (start>=get_led_count(channel)) start=0; 28 | if ((start+len)>get_led_count(channel)) len=get_led_count(channel)-start; 29 | 30 | if (delay<=0) delay=100; 31 | 32 | if (debug) printf("blink %d, %d, %d, %d, %d, %d, %d\n", channel, color1, color2, delay, count, start, len); 33 | 34 | ws2811_led_t * leds = get_led_string(channel); 35 | int i,blinks; 36 | for (blinks=0; blinksend_current_command) break; //signal to exit this command 47 | } 48 | }else{ 49 | fprintf(stderr,ERROR_INVALID_CHANNEL); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /effects/blink.h: -------------------------------------------------------------------------------- 1 | #ifndef EFFECT_BLINK_H 2 | #define EFFECT_BLINK_H 3 | #include "../ws2812svr.h" 4 | 5 | void blink (thread_context * context, char * args); 6 | 7 | #endif -------------------------------------------------------------------------------- /effects/brightness.c: -------------------------------------------------------------------------------- 1 | #include "brightness.h" 2 | //dims leds 3 | //brightness ,,, (brightness: 0-255) 4 | void brightness(thread_context * context, char * args){ 5 | int channel=0, brightness=255; 6 | unsigned int start=0, len=0; 7 | if (is_valid_channel_number(channel)){ 8 | len = get_led_count(channel); 9 | } 10 | 11 | args = read_channel(args, & channel); 12 | if (is_valid_channel_number(channel)) len = get_led_count(channel); 13 | args = read_int(args, & brightness); 14 | args = read_int(args, & start); 15 | args = read_int(args, & len); 16 | 17 | if (is_valid_channel_number(channel)){ 18 | if (brightness<0 || brightness>0xFF) brightness=255; 19 | 20 | if (start>=get_led_count(channel)) start=0; 21 | if ((start+len)>get_led_count(channel)) len=get_led_count(channel)-start; 22 | 23 | if (debug) printf("Changing brightness %d, %d, %d, %d\n", channel, brightness, start, len); 24 | 25 | ws2811_led_t * leds = get_led_string(channel); 26 | unsigned int i; 27 | for (i=start;i,,,,,,,,, 4 | //channel = 1 5 | //duration = time in seconds, or 0 4ever 6 | //color = color to use 7 | //count = number of leds 8 | //direction = scroll direction 9 | //delay = delay between moving the leds, speed 10 | //start = start index led (default 0) 11 | //len = length of the chaser (default enitre strip) 12 | //brightness = brightness of the chasing leds 13 | //loops = max number of chasing loops, 0 = 4ever, default = 0 14 | void chaser(thread_context * context, char * args){ 15 | unsigned int channel=0, direction=1, duration=10, delay=10, color=255, brightness=255, loops=0; 16 | int i, n, index, len=0, count=1, start=0; 17 | 18 | args = read_channel(args, & channel); 19 | 20 | if (is_valid_channel_number(channel)){ 21 | len = get_led_count(channel); 22 | args = read_int(args, & duration); 23 | args = read_color_arg(args, & color, get_color_size(channel)); 24 | args = read_int(args, & count); 25 | args = read_int(args, & direction); 26 | args = read_int(args, & delay); 27 | args = read_int(args, & start); 28 | args = read_int(args, & len); 29 | args = read_brightness(args, & brightness); 30 | args = read_int(args, & loops); 31 | } 32 | 33 | if (is_valid_channel_number(channel)){ 34 | if (start>=get_led_count(channel)) start=0; 35 | if ((start+len)>get_led_count(channel)) len=get_led_count(channel)-start; 36 | if (len==0) len = 1; 37 | if (count>len) count = len; 38 | 39 | 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); 40 | 41 | ws2811_led_t * org_leds = malloc(len * sizeof(ws2811_led_t)); 42 | ws2811_led_t * leds = get_led_string(channel); 43 | memcpy(org_leds, &leds[start], len * sizeof(ws2811_led_t)); //create a backup of original leds 44 | 45 | int loop_count=0; 46 | 47 | unsigned int start_time = time(0); 48 | while (((((time(0) - start_time) < duration) || duration==0) && (loops==0 || loops < loop_count)) && context->end_current_command==0){ 49 | ws2811_led_t tmp_led; 50 | 51 | for (n=0;n0 || (index > 0 && index < len)){ 54 | index = (index + len) % len; 55 | leds[start + index].color = color; 56 | leds[start + index].brightness = brightness; 57 | } 58 | } 59 | 60 | render_channel(channel); 61 | usleep(delay * 1000); 62 | 63 | for (n=0;n,,,,, 4 | //start and stop = color values on color wheel (0-255) 5 | void color_change(thread_context * context, char * args) { 6 | int channel=0, count=1,start=0,stop=255,startled=0, len=0, duration=10000, delay=10; 7 | 8 | if (is_valid_channel_number(channel)) len=get_led_count(channel); 9 | args = read_channel(args, & channel); 10 | if (is_valid_channel_number(channel)) len=get_led_count(channel); 11 | args = read_int(args, & start); 12 | args = read_int(args, & stop); 13 | args = read_int(args, & duration); 14 | args = read_int(args, & startled); 15 | args = read_int(args, & len); 16 | 17 | if (is_valid_channel_number(channel)){ 18 | if (start<0 || start > 255) start=0; 19 | if (stop<0 || stop > 255) stop = 255; 20 | if (startled<0) startled=0; 21 | if (startled+len> get_led_count(channel)) len = get_led_count(channel)-startled; 22 | 23 | if (debug) printf("color_change %d,%d,%d,%d,%d,%d\n", channel, start, stop, duration, startled, len); 24 | 25 | int numPixels = len; //get_led_count(channel);; 26 | int i, j; 27 | ws2811_led_t * leds = get_led_string(channel); 28 | 29 | unsigned long long start_time = time_ms(); 30 | unsigned long long curr_time = time_ms() - start_time; 31 | 32 | while (curr_time < duration){ 33 | unsigned int color = deg2color(abs(stop-start) * curr_time / duration + start); 34 | 35 | for(i=0; iend_current_command) break; //signal to exit this command 43 | } 44 | 45 | 46 | 47 | }else{ 48 | fprintf(stderr,ERROR_INVALID_CHANNEL); 49 | } 50 | } -------------------------------------------------------------------------------- /effects/color_change.h: -------------------------------------------------------------------------------- 1 | #ifndef EFFECT_COLOR_CHANGE_H 2 | #define EFFECT_COLOR_CHANGE_H 3 | #include "../ws2812svr.h" 4 | 5 | void color_change(thread_context * context, char * args); 6 | 7 | #endif -------------------------------------------------------------------------------- /effects/fade.c: -------------------------------------------------------------------------------- 1 | #include "fade.h" 2 | //causes a fade effect in time 3 | //fade ,,,,,, 4 | void fade (thread_context * context, char * args){ 5 | int channel=0, brightness=255,step=1,startbrightness=0, endbrightness=255; 6 | unsigned int start=0, len=0, delay=50; 7 | 8 | if (is_valid_channel_number(channel)){ 9 | len = get_led_count(channel); 10 | } 11 | 12 | args = read_channel(args, & channel); 13 | if (is_valid_channel_number(channel)){ 14 | len = get_led_count(channel); 15 | } 16 | args = read_int(args, & startbrightness); 17 | args = read_int(args, & endbrightness); 18 | args = read_int(args, & delay); 19 | args = read_int(args, & step); 20 | args = read_int(args, & start); 21 | args = read_int(args, & len); 22 | 23 | 24 | if (is_valid_channel_number(channel)){ 25 | if (startbrightness>0xFF) startbrightness=255; 26 | if (endbrightness>0xFF) endbrightness=255; 27 | 28 | if (start>=get_led_count(channel)) start=0; 29 | if ((start+len)>get_led_count(channel)) len=get_led_count(channel)-start; 30 | 31 | if (step==0) step = 1; 32 | if (startbrightness>endbrightness){ //swap 33 | if (step > 0) step = -step; 34 | }else{ 35 | if (step < 0) step = -step; 36 | } 37 | 38 | if (debug) printf("fade %d, %d, %d, %d, %d, %d, %d\n", channel, startbrightness, endbrightness, delay, step,start,len); 39 | 40 | ws2811_led_t * leds = get_led_string(channel); 41 | int i,brightness; 42 | for (brightness=startbrightness; (startbrightness > endbrightness ? brightness>=endbrightness: brightness<=endbrightness) ;brightness+=step){ 43 | for (i=start;iend_current_command) break; //signal to exit this command 49 | } 50 | }else{ 51 | fprintf(stderr,ERROR_INVALID_CHANNEL); 52 | } 53 | } -------------------------------------------------------------------------------- /effects/fade.h: -------------------------------------------------------------------------------- 1 | #ifndef EFFECT_FADE_H 2 | #define EFFECT_FADE_H 3 | #include "../ws2812svr.h" 4 | 5 | void fade (thread_context * context, char * args); 6 | 7 | #endif -------------------------------------------------------------------------------- /effects/fill.c: -------------------------------------------------------------------------------- 1 | #include "fill.h" 2 | //fills leds with certain color 3 | //fill ,,,, 4 | void fill(thread_context * context, char * args){ 5 | char op=0; 6 | int channel=0,start=0,len=-1; 7 | unsigned int fill_color=0; 8 | 9 | args = read_channel(args, & channel); 10 | if (is_valid_channel_number(channel)) args = read_color_arg(args, & fill_color, get_color_size(channel)); 11 | args = read_int(args, & start); 12 | args = read_int(args, & len); 13 | args = read_operation(args, & op); 14 | 15 | 16 | if (is_valid_channel_number(channel)){ 17 | if (start<0 || start>=get_led_count(channel)) start=0; 18 | if (len<=0 || (start+len)>get_led_count(channel)) len=get_led_count(channel)-start; 19 | 20 | if (debug) printf("fill %d,%d,%d,%d,%d\n", channel, fill_color, start, len,op); 21 | 22 | ws2811_led_t * leds = get_led_string(channel); 23 | unsigned int i; 24 | for (i=start;i,,,,,,, 4 | //direction = 0/1 fly in from left or right default 1 5 | //delay = delay in ms between moving pixel, default 10ms 6 | //brightness = the final brightness of the leds that fly in 7 | //start = where to start effect default 0 8 | //len = number of leds from start default length of strip 9 | //start_brightness = initial brightness for all leds default is 0 (black) 10 | //color = final color of the leds default is to use the current color 11 | //first have to call "fill ," to initialze a color if you leave color default value 12 | void fly_in(thread_context * context, char * args) { 13 | int channel=0,start=0, len=0, brightness=255, delay=10, direction=1, start_brightness=0, use_color=0; 14 | unsigned int color, tmp_color, repl_color; 15 | 16 | args = read_channel(args, & channel); 17 | if (is_valid_channel_number(channel)) len=get_led_count(channel); 18 | args = read_int(args, & direction); 19 | args = read_int(args, & delay); 20 | args = read_int(args, & brightness); 21 | args = read_int(args, & start); 22 | args = read_int(args, & len); 23 | args = read_int(args, & start_brightness); 24 | use_color = (args!=NULL && (*args)!=0); 25 | 26 | if (is_valid_channel_number(channel)){ 27 | args = read_color_arg(args, & color, get_color_size(channel)); 28 | if (start<0) start=0; 29 | if (start+len> get_led_count(channel)) len = get_led_count(channel)-start; 30 | 31 | 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); 32 | 33 | int numPixels = len; //get_led_count(channel);; 34 | int i, j; 35 | ws2811_led_t * leds = get_led_string(channel); 36 | 37 | for (i=0;iend_current_command) break; //signal to exit this command 72 | } 73 | if (direction){ 74 | leds[start+len-i-1].brightness = brightness; 75 | leds[start+len-i-1].color = repl_color; 76 | }else{ 77 | leds[start+i].brightness = brightness; 78 | leds[start+i].color = repl_color; 79 | } 80 | render_channel(channel); 81 | usleep(delay * 1000); 82 | if (context->end_current_command) break; //signal to exit this command 83 | } 84 | 85 | }else{ 86 | fprintf(stderr,ERROR_INVALID_CHANNEL); 87 | } 88 | } -------------------------------------------------------------------------------- /effects/fly_in.h: -------------------------------------------------------------------------------- 1 | #ifndef EFFECT_FLY_IN_H 2 | #define EFFECT_FLY_IN_H 3 | #include "../ws2812svr.h" 4 | 5 | void fly_in(thread_context * context, char * args); 6 | 7 | #endif -------------------------------------------------------------------------------- /effects/fly_out.c: -------------------------------------------------------------------------------- 1 | #include "fly_out.h" 2 | //fly out pixels from left or right filling entire string with black or a color/brightness 3 | //fly_out ,,,,,,, 4 | //direction = 0/1 fly out from left or right default 1 5 | //delay = delay in ms between moving pixel, default 10ms 6 | //brightness = the final brightness of the leds that fly in 7 | //start = where to start effect default 0 8 | //len = number of leds from start default length of strip 9 | //end_brightness = brightness for all leds at the end, default is 0 = black 10 | //color = final color of the leds default is to use the current color 11 | //first have to call "fill ," to initialze a color in each led before start fly_out 12 | void fly_out(thread_context * context, char * args) { 13 | int channel=0,start=0, len=0, delay=10, direction=1, brightness=255, use_color=0, end_brightness=0; 14 | unsigned int color, tmp_color, repl_color; 15 | 16 | args = read_channel(args, & channel); 17 | if (is_valid_channel_number(channel)) len=get_led_count(channel); 18 | args = read_int(args, & direction); 19 | args = read_int(args, & delay); 20 | args = read_int(args, & brightness); 21 | args = read_int(args, & start); 22 | args = read_int(args, & len); 23 | args = read_int(args, & end_brightness); 24 | use_color = (args!=NULL && (*args)!=0); 25 | 26 | if (is_valid_channel_number(channel)){ 27 | args = read_color_arg(args, & color, get_color_size(channel)); 28 | if (start<0) start=0; 29 | if (start+len> get_led_count(channel)) len = get_led_count(channel)-start; 30 | 31 | 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); 32 | 33 | int numPixels = len; //get_led_count(channel);; 34 | int i, j; 35 | ws2811_led_t * leds = get_led_string(channel); 36 | 37 | render_channel(channel); 38 | for (i=0;iend_current_command) break; //signal to exit this command 72 | } 73 | 74 | if (context->end_current_command) break; //signal to exit this command 75 | render_channel(channel); 76 | usleep(delay * 1000); 77 | 78 | } 79 | 80 | }else{ 81 | fprintf(stderr,ERROR_INVALID_CHANNEL); 82 | } 83 | } -------------------------------------------------------------------------------- /effects/fly_out.h: -------------------------------------------------------------------------------- 1 | #ifndef EFFECT_FLY_OUT_H 2 | #define EFFECT_FLY_OUT_H 3 | #include "../ws2812svr.h" 4 | 5 | void fly_out(thread_context * context, char * args) ; 6 | 7 | #endif -------------------------------------------------------------------------------- /effects/gradient.c: -------------------------------------------------------------------------------- 1 | #include "gradient.h" 2 | #include 3 | //generates a brightness gradient pattern of a color component or brightness level 4 | //gradient ,,,,, 5 | void gradient (thread_context * context, char * args){ 6 | char value[MAX_VAL_LEN]; 7 | int channel=0, startlevel=0,endlevel=255; 8 | unsigned int start=0, len=0; 9 | char component='L'; //L is brightness level 10 | 11 | if (is_valid_channel_number(channel)){ 12 | len = get_led_count(channel); 13 | } 14 | 15 | args = read_channel(args, & channel); 16 | if (is_valid_channel_number(channel)){ 17 | len = get_led_count(channel); 18 | } 19 | args = read_val(args, value, MAX_VAL_LEN); 20 | component=toupper(value[0]); 21 | args = read_int(args, & startlevel); 22 | args = read_int(args, & endlevel); 23 | args = read_int(args, & start); 24 | args = read_int(args, & len); 25 | 26 | 27 | if (is_valid_channel_number(channel)){ 28 | if (startlevel>0xFF) startlevel=255; 29 | if (endlevel>0xFF) endlevel=255; 30 | 31 | if (start>=get_led_count(channel)) start=0; 32 | if ((start+len)>get_led_count(channel)) len=get_led_count(channel)-start; 33 | 34 | 35 | float step = 1.0*(endlevel-startlevel) / (float)(len-1); 36 | 37 | if (debug) printf("gradient %d, %c, %d, %d, %d,%d\n", channel, component, startlevel, endlevel, start,len); 38 | 39 | ws2811_led_t * leds = get_led_string(channel); 40 | 41 | float flevel = startlevel; 42 | int i; 43 | for (i=0; i100) value=100; 6 | if (direction){ 7 | value = (float)len * value / 100.0f; 8 | for (i=0;i default 1 23 | // default 1, start 0% --> stop 100% (0 to reverse) 24 | // delay to use between increase, default 1s, use 0 to not automatically fill progress bar 25 | // start at this led default 0 26 | // use this ammount of leds for progress bar 27 | // the brightness value for leds that are turned on, default 255 28 | // the brightness value for leds that are turned off, default 0 29 | // set progress bar to this value in % (0-100), use a delay of 0 30 | void progress(thread_context * context, char * args) { 31 | int channel=0,start=0, len=0, brightness_on=255, brightness_off=0, delay=1000, direction=1; 32 | float value =0.0; 33 | unsigned int color, tmp_color, repl_color; 34 | 35 | args = read_channel(args, & channel); 36 | if (is_valid_channel_number(channel)) len=get_led_count(channel); 37 | args = read_int(args, & direction); 38 | args = read_int(args, & delay); 39 | args = read_int(args, & start); 40 | args = read_int(args, & len); 41 | args = read_int(args, & brightness_on); 42 | args = read_int(args, & brightness_off); 43 | args = read_float(args, & value); 44 | 45 | if (is_valid_channel_number(channel)){ 46 | if (start<0) start=0; 47 | if (start+len> get_led_count(channel)) len = get_led_count(channel)-start; 48 | 49 | 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); 50 | 51 | int i; 52 | ws2811_led_t * leds = get_led_string(channel); 53 | 54 | if (delay==0){ 55 | if (value<0) value=0; 56 | set_progress(leds, direction, start, len, value, brightness_on, brightness_off); 57 | }else{ 58 | for (i=0;i<=len;i++){ 59 | set_progress(leds, direction, start, len, 100.0f * (float)i/(float)len, brightness_on, brightness_off); 60 | render_channel(channel); 61 | usleep(delay * 1000); 62 | if (context->end_current_command) break; //signal to exit this command 63 | } 64 | } 65 | 66 | }else{ 67 | fprintf(stderr,ERROR_INVALID_CHANNEL); 68 | } 69 | } -------------------------------------------------------------------------------- /effects/progress.h: -------------------------------------------------------------------------------- 1 | #ifndef EFFECT_PROGRESS_H 2 | #define EFFECT_PROGRESS_H 3 | #include "../ws2812svr.h" 4 | 5 | void progress(thread_context * context, char * args); 6 | 7 | #endif -------------------------------------------------------------------------------- /effects/rainbow.c: -------------------------------------------------------------------------------- 1 | #include "rainbow.h" 2 | //fills pixels with rainbow effect 3 | //count tells how many rainbows you want 4 | //rainbow ,,,,, 5 | //start and stop = color values on color wheel (0-255) 6 | void rainbow(thread_context * context, char * args) { 7 | int channel=0, count=1,start=0,stop=255,startled=0, len=0; 8 | 9 | if (is_valid_channel_number(channel)) len=get_led_count(channel); 10 | args = read_channel(args, & channel); 11 | if (is_valid_channel_number(channel)) len=get_led_count(channel); 12 | args = read_int(args, & count); 13 | args = read_int(args, & start); 14 | args = read_int(args, & stop); 15 | args = read_int(args, & startled); 16 | args = read_int(args, & len); 17 | 18 | if (is_valid_channel_number(channel)){ 19 | if (start<0 || start > 255) start=0; 20 | if (stop<0 || stop > 255) stop = 255; 21 | if (startled<0) startled=0; 22 | if (startled+len> get_led_count(channel)) len = get_led_count(channel)-startled; 23 | 24 | if (debug) printf("Rainbow %d,%d,%d,%d,%d,%d\n", channel, count,start,stop,startled,len); 25 | 26 | int numPixels = len; //ledstring.channel[channel].count;; 27 | int i, j; 28 | ws2811_led_t * leds = get_led_string(channel); 29 | for(i=0; i,,,,,,,,,, 50 | //duration = total max duration of effect 51 | //count = max number of leds that will fade in or out at same time 52 | //delay = delay between changes in brightness 53 | //step = ammount of brightness to increase between delays 54 | //inc_dec = if 1 brightness will start at and decrease to initial brightness of the led, else it will start low and go up 55 | // sync_delay = random delay to make the fading appear out of sync. set to 0 to make all LEDs start fade in/out at the same time 56 | //start = start at led position 57 | //len = stop at led position 58 | //color = use specific color, after blink effect color will return to initial 59 | //brightness = max brightness of blinking led 60 | void random_fade_in_out(thread_context * context, char * args){ 61 | 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; 62 | fade_in_out_led_status *led_status; 63 | 64 | if (is_valid_channel_number(channel)){ 65 | len = get_led_count(channel);; 66 | } 67 | 68 | args = read_channel(args, & channel); 69 | if (is_valid_channel_number(channel)){ 70 | len = get_led_count(channel); 71 | count = len / 3; 72 | args = read_int(args, & duration); 73 | args = read_int(args, & count); 74 | args = read_int(args, & delay); 75 | args = read_int(args, & step); 76 | args = read_int(args, & sync_delay); 77 | args = read_int(args, & inc_dec); 78 | args = read_int(args, & brightness); 79 | args = read_int(args, & start); 80 | args = read_int(args, & len); 81 | change_color = args!=NULL && *args!=0; 82 | args = read_color_arg(args, & color, get_color_size(channel)); 83 | args = read_brightness(args, & brightness); 84 | 85 | if (start>=get_led_count(channel)) start=0; 86 | if ((start+len)>get_led_count(channel)) len=get_led_count(channel)-start; 87 | if (count>len) count = len; 88 | 89 | 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); 90 | 91 | led_status = (fade_in_out_led_status *)malloc(count * sizeof(fade_in_out_led_status)); 92 | ws2811_led_t * leds = get_led_string(channel); 93 | 94 | render_channel(channel); 95 | 96 | for (i=0; iend_current_command==0){ 111 | for (i=0;i= led_status[i].start_brightness)){ 118 | leds[led_status[i].led_index].brightness = led_status[i].start_brightness; 119 | if (change_color) leds[led_status[i].led_index].color = led_status[i].start_color; 120 | int index=find_random_free_led_index(led_status, count, start, len); 121 | if (index!=-1){ 122 | led_status[i].led_index = index; 123 | led_status[i].brightness = brightness; 124 | led_status[i].start_brightness = leds[led_status[i].led_index].brightness; 125 | led_status[i].start_color = leds[led_status[i].led_index].color; 126 | led_status[i].delay = sync_delay ? (rand() % sync_delay) : 0; 127 | } 128 | } 129 | } 130 | }else{ 131 | led_status[i].delay--; 132 | } 133 | } 134 | render_channel(channel); 135 | usleep(delay * 1000); 136 | } 137 | 138 | for (i=0;i,,,,,,, 5 | //offset = where to start in JPEG file 6 | //DELAY = delay ms between 2 reads of LEN pixels, default=0 if 0 only bytes at will be read 7 | void readjpg(thread_context * context, char * args){ 8 | struct jpeg_decompress_struct cinfo; 9 | struct my_error_mgr jerr; 10 | 11 | char value[MAX_VAL_LEN]; 12 | int channel=0; 13 | char filename[MAX_VAL_LEN]; 14 | unsigned int start=0, len=1, offset=0, flip_rows=0, row_index=0; 15 | int op=0,delay=0; 16 | 17 | args = read_channel(args, & channel); 18 | if (is_valid_channel_number(channel)) len = get_led_count(channel); 19 | args = read_str(args, filename, sizeof(filename)); 20 | args = read_int(args, &start); 21 | args = read_int(args, &len); 22 | args = read_int(args, &offset); 23 | args = read_str(args, value, sizeof(value)); 24 | if (strcmp(value, "OR")==0) op=1; 25 | else if (strcmp(value, "AND")==0) op=2; 26 | else if (strcmp(value, "XOR")==0) op=3; 27 | else if (strcmp(value, "NOT")==0) op=4; 28 | args = read_int(args, &delay); 29 | if (len<=0) len =1; 30 | 31 | if (is_valid_channel_number(channel)){ 32 | FILE * infile; /* source file */ 33 | int row_stride; /* physical row width in output buffer */ 34 | 35 | 36 | if (debug) printf("readjpg %d,%s,%d,%d,%d,%d,%d\n", channel, filename, start, len, offset, op, delay); 37 | 38 | if ((infile = fopen(filename, "rb")) == NULL) { 39 | fprintf(stderr, "Error: can't open %s\n", filename); 40 | return; 41 | } 42 | 43 | // We set up the normal JPEG error routines, then override error_exit. 44 | cinfo.err = jpeg_std_error(&jerr.pub); 45 | jerr.pub.error_exit = my_error_exit; 46 | // Establish the setjmp return context for my_error_exit to use. 47 | if (setjmp(jerr.setjmp_buffer)) { 48 | /* If we get here, the JPEG code has signaled an error. 49 | * We need to clean up the JPEG object, close the input file, and return. 50 | */ 51 | jpeg_destroy_decompress(&cinfo); 52 | fclose(infile); 53 | return; 54 | } 55 | 56 | // Now we can initialize the JPEG decompression object. 57 | jpeg_create_decompress(&cinfo); 58 | jpeg_stdio_src(&cinfo, infile); 59 | 60 | jpeg_read_header(&cinfo, TRUE); 61 | jpeg_start_decompress(&cinfo); 62 | 63 | row_stride = cinfo.output_width * cinfo.output_components; 64 | 65 | JSAMPARRAY buffer; // Output row buffer 66 | int i=0,jpg_idx=0,led_idx; //pixel index for current row, jpeg image, led string 67 | buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); 68 | 69 | ws2811_led_t * leds = get_led_string(channel); 70 | 71 | if (start>=get_led_count(channel)) start=0; 72 | if ((start+len)> get_led_count(channel)) len= get_led_count(channel)-start; 73 | 74 | led_idx=start; //start at this led index 75 | 76 | int eofstring=0; 77 | while (eofstring==0 && cinfo.output_scanline < cinfo.output_height && context->end_current_command==0) { 78 | jpeg_read_scanlines(&cinfo, buffer, 1); 79 | for(i=0;i=offset){ //check jpeg offset 81 | unsigned char r,g,b; 82 | r = buffer[0][i*cinfo.output_components]; 83 | g = buffer[0][i*cinfo.output_components+1]; 84 | b = buffer[0][i*cinfo.output_components+2]; 85 | if (cinfo.output_components==1){ //grayscale image 86 | g = r; 87 | b = r; 88 | } 89 | if (flip_rows){ //this will horizontaly flip the row 90 | if (row_index & 1){ 91 | led_idx = start + cinfo.image_width * row_index + (cinfo.image_width - i); 92 | } 93 | } 94 | if (led_idx= start + len){ 117 | if (delay!=0){//reset led index if we are at end of led string and delay 118 | led_idx=start; 119 | row_index=0; 120 | render_channel(channel); 121 | usleep(delay * 1000); 122 | }else{ 123 | eofstring=1; 124 | break; 125 | } 126 | } 127 | } 128 | if (context->end_current_command) break; //signal to exit this command 129 | jpg_idx++; 130 | } 131 | row_index++; 132 | } 133 | 134 | jpeg_finish_decompress(&cinfo); 135 | jpeg_destroy_decompress(&cinfo); 136 | fclose(infile); 137 | } 138 | } -------------------------------------------------------------------------------- /effects/read_jpg.h: -------------------------------------------------------------------------------- 1 | #ifndef EFFECT_READ_JPG_H 2 | #define EFFECT_READ_JPG_H 3 | #include "../ws2812svr.h" 4 | 5 | void readjpg(thread_context * context, char * args); 6 | 7 | #endif -------------------------------------------------------------------------------- /effects/read_png.c: -------------------------------------------------------------------------------- 1 | #include "read_png.h" 2 | #include "../readpng.h" 3 | //read PNG image and put pixel data to LEDS 4 | //readpng ,,,,,,,, 5 | //offset = where to start in PNG file 6 | //backcolor = color to use for transparent area, FF0000 = RED 7 | //P = use the PNG backcolor (default) 8 | //W = use the alpha data for the White leds in RGBW LED strips 9 | //DELAY = delay ms between 2 reads of LEN pixels, default=0 if 0 only bytes at will be read 10 | void readpng(thread_context * context,char * args){ 11 | //struct jpeg_decompress_struct cinfo; 12 | //struct my_error_mgr jerr; 13 | 14 | char value[MAX_VAL_LEN]; 15 | int channel=0; 16 | char filename[MAX_VAL_LEN]; 17 | unsigned int start=0, len=0, offset=0,flip_rows=0; 18 | int op=0; 19 | int backcolor=0; 20 | int backcolortype=0; //0 = use PNG backcolor, 1 = use given backcolor, 2 = no backcolor but use alpha for white leds 21 | int delay=0; 22 | int row_index=0; 23 | 24 | args = read_channel(args, & channel); 25 | if (is_valid_channel_number(channel)) len = get_led_count(channel); 26 | args = read_str(args, filename, sizeof(filename)); 27 | args = read_str(args, value, sizeof(filename)); 28 | if (strlen(value)>=6){ 29 | if (is_valid_channel_number(channel)){ 30 | read_color(value, & backcolor, get_color_size(channel)); 31 | backcolortype=1; 32 | } 33 | }else if (strcmp(value, "W")==0){ 34 | backcolortype=2; 35 | } 36 | args = read_int(args, &start); 37 | args = read_int(args, &len); 38 | args = read_int(args, &offset); 39 | args = read_str(args, value, sizeof(value)); 40 | if (strcmp(value, "OR")==0) op=1; 41 | else if (strcmp(value, "AND")==0) op=2; 42 | else if (strcmp(value, "XOR")==0) op=3; 43 | else if (strcmp(value, "NOT")==0) op=4; 44 | args = read_int(args, &delay); 45 | args = read_int(args, &flip_rows); 46 | 47 | if (is_valid_channel_number(channel)){ 48 | FILE * infile; /* source file */ 49 | png_object png; 50 | int rc; 51 | uch bg_red=0, bg_green=0, bg_blue=0; 52 | 53 | if (start<0) start=0; 54 | if (start+len> get_led_count(channel)) len = get_led_count(channel) -start; 55 | int color_size = get_color_size(channel); 56 | 57 | if (debug) printf("readpng %d,%s,%d,%d,%d,%d,%d,%d\n", channel, filename, backcolor, start, len,offset,op, delay); 58 | 59 | if ((infile = fopen(filename, "rb")) == NULL) { 60 | fprintf(stderr, "Error: can't open %s\n", filename); 61 | return; 62 | } 63 | 64 | if ((rc = readpng_init(infile, &png)) != 0) { 65 | switch (rc) { 66 | case 1: 67 | fprintf(stderr, "[%s] is not a PNG file: incorrect signature.\n", filename); 68 | break; 69 | case 2: 70 | fprintf(stderr, "[%s] has bad IHDR (libpng longjmp).\n", filename); 71 | break; 72 | case 4: 73 | fprintf(stderr, "Read PNG insufficient memory.\n"); 74 | break; 75 | default: 76 | fprintf(stderr, "Unknown readpng_init() error.\n"); 77 | break; 78 | } 79 | fclose(infile); 80 | return; 81 | } 82 | 83 | //get the background color (for transparency support) 84 | if (backcolortype==0){ 85 | bg_red = png.background_red; 86 | bg_green = png.background_green; 87 | bg_blue = png.background_blue; 88 | }else{ 89 | bg_red = get_red(backcolor); 90 | bg_green = get_green(backcolor); 91 | bg_blue = get_blue(backcolor); 92 | } 93 | 94 | //read entire image data 95 | uch * image_data = readpng_get_image(& png, 2.2); 96 | 97 | if (image_data) { 98 | int row=0, led_idx=0, png_idx=0, i=0; 99 | uch r, g, b, a; 100 | uch *src; 101 | 102 | ws2811_led_t * leds = get_led_string(channel); 103 | 104 | if (start>=get_led_count(channel)) start=0; 105 | if ((start+len)> get_led_count(channel)) len= get_led_count(channel) -start; 106 | 107 | led_idx=start; //start at this led index 108 | //load all pixels 109 | for (row = 0; row < png.height; row++) { 110 | src = image_data + row * png.rowbytes; 111 | 112 | for (i = png.width; i > 0; --i) { 113 | r = *src++; 114 | g = *src++; 115 | b = *src++; 116 | 117 | if (png.channels != 3){ 118 | a = *src++; 119 | if (backcolortype!=2){ 120 | r = alpha_component(r, bg_red,a); 121 | g = alpha_component(g, bg_green,a); 122 | b = alpha_component(b, bg_blue,a); 123 | } 124 | } 125 | if (png_idx>=offset){ 126 | 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,png.channels,png_idx); 127 | if (led_idx < start + len){ 128 | int fill_color; 129 | if (backcolortype==2 && color_size>3){ 130 | fill_color=color_rgbw(r,g,b,a); 131 | }else{ 132 | fill_color=color(r,g,b); 133 | } 134 | 135 | if (flip_rows){ //this will horizontaly flip the row 136 | if (row_index & 1){ 137 | led_idx = start + png.width * row_index + (png.width - i); 138 | } 139 | } 140 | 141 | switch (op){ 142 | case 0: 143 | leds[led_idx].color=fill_color; 144 | break; 145 | case 1: 146 | leds[i].color|=fill_color; 147 | break; 148 | case 2: 149 | leds[i].color&=fill_color; 150 | break; 151 | case 3: 152 | leds[i].color^=fill_color; 153 | break; 154 | case 4: 155 | leds[i].color=~fill_color; 156 | break; 157 | } 158 | 159 | } 160 | led_idx++; 161 | if ( led_idx>=start + len){ 162 | if (delay!=0){//reset led index if we are at end of led string and delay 163 | led_idx=start; 164 | row_index=0; 165 | render_channel(channel); 166 | usleep(delay * 1000); 167 | }else{ 168 | row = png.height; //exit reading 169 | i=0; 170 | break; 171 | } 172 | } 173 | } 174 | png_idx++; 175 | if (context->end_current_command) break; //signal to exit this command 176 | } 177 | if (context->end_current_command) break; 178 | row_index++; 179 | } 180 | readpng_cleanup(&png); 181 | }else{ 182 | readpng_cleanup(&png); 183 | fprintf(stderr, "Unable to decode PNG image\n"); 184 | } 185 | fclose(infile); 186 | } 187 | } -------------------------------------------------------------------------------- /effects/read_png.h: -------------------------------------------------------------------------------- 1 | #ifndef EFFECT_READ_PNG_H 2 | #define EFFECT_READ_PNG_H 3 | #include "../ws2812svr.h" 4 | 5 | void readpng(thread_context * context,char * args); 6 | 7 | #endif -------------------------------------------------------------------------------- /effects/rotate.c: -------------------------------------------------------------------------------- 1 | #include "rotate.h" 2 | 3 | void rotate_strip(thread_context * context, int channel, int nplaces, int direction, unsigned int new_color, int use_new_color, int new_brightness){ 4 | ws2811_led_t tmp_led; 5 | ws2811_led_t* leds = get_led_string(channel); 6 | unsigned int led_count = get_led_count(channel); 7 | unsigned int n,i; 8 | for(n=0;n0;i--){ 23 | leds[i] = leds[i-1]; 24 | } 25 | if (use_new_color){ 26 | leds[0].color=new_color; 27 | leds[0].brightness=new_brightness; 28 | }else{ 29 | leds[0]=tmp_led; 30 | } 31 | } 32 | } 33 | } 34 | 35 | //shifts all colors 1 position 36 | //rotate ,,,, 37 | //if new color is set then the last led will have this color instead of the color of the first led 38 | void rotate(thread_context * context, char * args){ 39 | int channel=0, nplaces=1, direction=1; 40 | unsigned int new_color=0, new_brightness=255; 41 | int use_new_color=0; 42 | 43 | args = read_channel(args, & channel); 44 | args = read_int(args, & nplaces); 45 | args = read_int(args, & direction); 46 | if (is_valid_channel_number(channel)){ 47 | use_new_color= (args!=NULL && *args!=0); 48 | args = read_color_arg(args, & new_color, get_color_size(channel)); 49 | read_brightness(args, & new_brightness); 50 | } 51 | 52 | if (debug) printf("Rotate %d %d %d %d %d\n", channel, nplaces, direction, new_color, new_brightness); 53 | 54 | if (is_valid_channel_number(channel)){ 55 | rotate_strip(context, channel, nplaces, direction, new_color, use_new_color, new_brightness); 56 | }else{ 57 | fprintf(stderr,ERROR_INVALID_CHANNEL); 58 | } 59 | } -------------------------------------------------------------------------------- /effects/rotate.h: -------------------------------------------------------------------------------- 1 | #ifndef EFFECT_ROTATE_H 2 | #define EFFECT_ROTATE_H 3 | #include "../ws2812svr.h" 4 | 5 | void rotate(thread_context * context, char * args); 6 | 7 | #endif -------------------------------------------------------------------------------- /enhanced_led_board-7.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/enhanced_led_board-7.ttf -------------------------------------------------------------------------------- /examples/ambilight.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - Ambilight 7 | 8 | 9 |

10 | With the ambilight command you can create LED background effect for you TV. 11 |

12 | 13 |

14 | This example we use a LED strip of 200 LEDs and a HDMI capture card.
15 | 50 LEDs are mounted on each side (Y) of the TV and 100 LEDs on the top (X).
16 | The LEDs must be attached to your TV in the order displayed in the picture below (LED 0 is connected to the Raspberry):
17 |
18 |

Picture by Stephan Legachev - Eigen werk, CC BY 3.0, Link
19 |

20 | 21 |

Optional you can add LEDs at the bottom of your TV, in this case you must specify the type parameter for the ambilight command = 2.

22 | 23 |
24 | 25 | setup 1,200,3 26 | init 27 | debug 1 28 | brightness 1,128 29 | ambilight 1,"/dev/video0", 100, 50, 640, 360 30 | 31 |
32 | 33 |

34 | NOTE:
35 | The ambilight command has width and height parameters, use these parameters to reduce the video output of the HDMI capture card.
36 | The lower the video output of the card the lower the CPU usage of your Raspberry will be and the higher the frame rate.
37 | Ideal the image_width and image_height are the same as leds_x and leds_y but sometimes there is a lower limit on frame dimensions the card can output (something like 640x360).
38 |

39 | 40 | 41 |

For capturing HDMI I'd recommend this type of capture card (you can buy on AliExpress):
42 |

43 | 44 |

Back

45 | 46 | -------------------------------------------------------------------------------- /examples/ambilight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/examples/ambilight.png -------------------------------------------------------------------------------- /examples/camera.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - Capture video 7 | 8 | 9 |

10 | You can capture video and paint it directly on your 2D matrix. You need to install the Raspberry Pi camera or USB camera / HDMI capture device that supports v4l2 MJPEG output. 11 | This example creates a 500x800 display and captures images from /dev/video0 (default Raspberry Pi camera). 12 |

13 | 14 |
15 | 16 | setup 1,400000,3 17 | init 18 | config_2D 1,500,800,0,500,800 19 | camera 1,"/dev/video0",0,0,500,800 20 | 21 |
22 | 23 |

24 | For capturing HDMI I'd recommend this type of capture card (which you can buy on AliExpress):
25 |

26 | 27 |

Back

28 | 29 | -------------------------------------------------------------------------------- /examples/circle.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - Draw a circle 7 | 8 | 9 |

10 | This shows how to draw a circle in the center with radius 2.5 pixels, filled with red and a blue border of 1 pixel.
11 | Connect a 8x8 LED panel to PWM0 output. 12 |

13 | 14 |
15 | 16 | setup 1,64,3 17 | init 18 | brightness 1,32 19 | config_2D 1,8,8,3,8,8 20 | draw_circle 1,3.5,3.5,2.5,FF0000,1,0000FF 21 | render 22 | 23 |
24 | 25 |

Back

26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/fill.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - fill 7 | 8 | 9 |

10 | Add a LED string of 10 LEDs with WS2812 chip on PWM0 (GPIO 12) output of the Raspberry Pi.
11 | Execute these commads to fill your LED string with green color 12 |

13 | 14 |
15 | setup 1,10,5 16 | init 17 | fill 1,00FF00 18 | render 19 |
20 |

Back

21 | 22 | -------------------------------------------------------------------------------- /examples/gpio.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - Wait for GPIO 7 | 8 | 9 |

10 | In this example waits for GPIO 23 to become high and generates a strobe light effect.
11 |

12 | 13 |
14 | 15 | setup 1,4,3 16 | init 17 | fill 1,FF0000 18 | render 19 | do 20 | wait_gpio 23 21 | 22 | do 23 | fill 1,FFFFFF 24 | render 25 | delay 50 26 | fill 1,000000 27 | render 28 | delay 50 29 | loop 50 30 | 31 | loop 32 | 33 |
34 | 35 |

Back

36 | 37 | 38 | -------------------------------------------------------------------------------- /examples/hdmi_capture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/examples/hdmi_capture.jpg -------------------------------------------------------------------------------- /examples/image.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - Render image 7 | 8 | 9 |

10 | You can render PNG,JPG and (animated) GIFs directly on your LED screen. 11 | Don't forget to compile with JPG support (default) on if you want to render JPG files. 12 | In this example an 8x8 display is used to first render a PNG and then render animated gif test.gif. 13 |

14 | 15 |
16 | 17 | setup 1,64,3 18 | init 19 | brightness 1, 32 20 | config_2D 1,8,8,3,8,8 21 | draw_image 1,examples/test.png 22 | render 23 | draw_image 1,examples/test.gif 24 | 25 |
26 | 27 |

28 | Use double quotes (") if your file name contains spaces or a , character.
29 | draw_image 1,"path to file with spaces or ," 30 |

31 | 32 |

Back

33 | 34 | -------------------------------------------------------------------------------- /examples/index.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server Examples 7 | 8 | 9 | 10 |

1D commands

11 | 22 | 23 |

2D commands

24 | 36 | 37 | 38 |

Audio interface

39 | 46 | 47 |

Special commands

48 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /examples/light_organ.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - light organ 7 | 8 | 9 |

10 | This will make the entire strip blink on the rhythm of the music.
11 | First a rainbow is rendered into the strip and color mode of the light_organ command is set to 3 which will keep the rainbow and only change the intensity of the LEDs. 12 |

13 | 14 |
15 | 16 | setup 1,120,3 17 | init 18 | record_audio "plughw:CARD=Device,DEV=0" 19 | rainbow 1 20 | light_organ 1,3 21 | 22 |
23 | 24 |

Back

25 | 26 | -------------------------------------------------------------------------------- /examples/line.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - Draw a line 7 | 8 | 9 |

10 | In this example we will draw 2 lines of 32 pixels on an 8x32 display.
11 | There are 2 commands to draw lines:
12 |

    13 |
  • draw_line: draws a line with cairo library, with anti aliasing. This may not produce sharp 1 pixel lines, read more
  • 14 |
  • draw_sharp_line: draws a line with Bresenham algorithm, no anti aliasing
  • 15 |
16 |

17 | 18 |
19 | 20 | setup 1,256,3 21 | init 22 | brightness 1,32 23 | config_2D 1,32,8,3,32,8 24 | draw_line 1,0,0.5,31.5,0.5,1,FF0000 25 | draw_sharp_line 1,0,6,31,6,1,00FF00 26 | render 27 | 28 |
29 | 30 |

31 | NOTE: draw_sharp_line doesn't support alpha transparency and all parameters must be integers. 32 |

33 | 34 |

Back

35 | 36 | 37 | -------------------------------------------------------------------------------- /examples/master_slave.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - Master Slave 7 | 8 | 9 |

10 | With master - slave commands you can connect one WS2812 server instance to multiple Raspberry Pis. 11 | This enables you to connect as many LED strings as you want using multiple Raspberry Pis which are connected by Wifi or Ethernet. 12 |

13 | 14 | First on the slave 1 execute these commands: 15 |
16 | 17 | setup 1,256,3 18 | init 19 | slave_listen 1, 8000 20 | 21 |
22 | 23 | on slave 2 execute the same commands: 24 |
25 | 26 | setup 1,512,3 27 | init 28 | do 29 | slave_listen 1, 8000 30 | loop 31 | 32 |
33 | 34 |

35 | slave_listen will now wait for the master to connect to port 8000. 36 | When the master disconnects the command will end, you can put it in a do ... loop structure to automatically start listening again. 37 |

38 | 39 |

40 | On the master Raspberry, this is the Raspberry that will control ALL LED strings and run the main command script. 41 | The master must be able to connect to the slaves by network connection (TCP protocol). 42 | Setup a LED string of 256 LEDs on the master: 43 |

44 | 45 |
46 | 47 | setup 1,256,100,"192.168.0.2",8000 48 | setup 2,512,100,"192.168.0.3",8000 49 | init 50 | fill 1,FF0000 51 | fill 2,00FF00 52 | render 1 53 | render 2 54 | 55 |
56 | 57 |

58 | The master will connect to 192.168.0.2, this is the IP of the slave 1 Raspberry. 59 | The master will connect to 192.168.0.3, this is the IP of the slave 2 Raspberry. 60 | Then the master will fill channel 1 with red color, channel 2 with blue and the render commands will transfer the data to the slave Raspberries. 61 | The slave Raspberry will eventually render it to the LED string. 62 |

63 | 64 |

65 | NOTE: If you want to use 2 channels on the same slave, put the slave_listen in different threads. 66 |

67 | 68 | 69 |

Back

70 | 71 | -------------------------------------------------------------------------------- /examples/master_slave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/examples/master_slave.png -------------------------------------------------------------------------------- /examples/master_slave_fade.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - Master slave fade 7 | 8 | 9 |

10 | This example uses one master Raspberry pi 3 connected with 3 slave Raspberry Pi Zero W.
11 | Each Raspberry Zero has connected 50 LEDs, the master 300 LEDs and they will all fade on/off at the same time using synchronized threads.
12 | The slave Raspberry Pis are connected with wifi and have IP address 192.168.0.81, 192.168.0.82, 192.168.0.83 13 |

14 | 15 |

First initialize the slaves with this code:

16 |
17 | 18 | setup 1,50,5 19 | init 20 | do 21 | slave_listen 1,8000 22 | loop 23 | 24 |
25 | 26 |

Now run this code on the master.
27 | 300 LEDs connected to the master are setup in channel 1.
28 | The other LEDs are setup in channel 2-4 as a slave virtual channel, connecting to each Raspberry Pi Zero. 29 |

30 |
31 | 32 | setup 1,300,3 33 | setup 2,50,100, "192.168.0.81", 8000 34 | setup 3,50,100, "192.168.0.82", 8000 35 | setup 4,50,100, "192.168.0.83", 8000 36 | init 37 | 38 | thread_start 1 39 | fill 1,FF0000 40 | do 41 | fade 1, 0, 255, 40 42 | signal_thread 2,1 43 | signal_thread 3,1 44 | signal_thread 4,1 45 | fade 1, 255, 0, 40 46 | signal_thread 2,1 47 | signal_thread 3,1 48 | signal_thread 4,1 49 | loop 50 | thread_stop 51 | 52 | thread_start 2 53 | fill 2,FF0000 54 | do 55 | fade 2, 0, 255, 40 56 | wait_signal 57 | fade 2, 255, 0, 40 58 | wait_signal 59 | loop 60 | thread_stop 61 | 62 | thread_start 3 63 | fill 3,FF0000 64 | do 65 | fade 3, 0, 255, 40 66 | wait_signal 67 | fade 3, 255, 0, 40 68 | wait_signal 69 | loop 70 | thread_stop 71 | 72 | thread_start 4 73 | fill 4, FF0000 74 | do 75 | fade 4, 0, 255, 40 76 | wait_signal 77 | fade 4, 255, 0, 40 78 | wait_signal 79 | loop 80 | thread_stop 81 | 82 |
83 | 84 |

Back

85 | 86 | -------------------------------------------------------------------------------- /examples/message_board.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - message board 7 | 8 | 9 |

10 | This command makes green text message scroll.
11 | Connect a 8x32 LED panel to PWM0 output. 12 |

13 | 14 |
15 | 16 | setup 1,256,3 17 | init 18 | brightness 1,32 19 | config_2D 1,32,8,3,32,8 20 | init_layer 1,0,1,0,1,0 21 | message_board 1,0,8,32,8,0,00FF00,000000,50,0,"HELLO WORLD",8,,0,"enhanced_led_board-7.ttf" 22 | 23 |
24 | 25 |

26 | NOTE: Put double quotes around your text, use \" if you need a double quote in your text. For special characters use UTF-8 encoding and a font that supports them. 27 |

28 | 29 | If you want to print message on a background image like in the youtube example. You need 2 extra layers for that, one you render the background image (red-green.png) and the other the text is rendered, then both are combined and only where there is text the background image will be visible and rendered on the bottom layer 30 | Use code: 31 |
32 | 33 | setup 1,256,3 34 | init 35 | brightness 1, 32 36 | config_2D 1,32,8,3,32,8 37 | init_layer 1,1,1,0,1,0 38 | change_layer 1,1 39 | draw_image 1,examples/red-green.png 40 | init_layer 1,2,8,0,1,0 41 | change_layer 1,2 42 | message_board 1,0,8,32,8,0,FFFFFF,,50,0,"HELLO WORLD",8,,0,"enhanced_led_board-7.ttf" 43 | 44 |
45 | 46 |

Back

47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/multi_layer.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - use of layers 7 | 8 | 9 |

10 | This example first draws a red-green picture on the main background, then initializes a new layer with paint operator CAIRO_OPERATOR_DEST_IN and paints text on it.
11 | The CAIRO_OPERATOR_DEST_IN will display the main background image where the text is.
12 | Requires a 32x8 WS2812 LED panel. 13 |

14 | 15 |
16 | 17 | setup 1,256,3 18 | init 19 | brightness 1, 32 20 | config_2D 1,32,8,3,32,8 21 | draw_image 1,examples/red-green.png 22 | init_layer 1,1,8,0,1,0 23 | change_layer 1,1 24 | print_text 1,0,8,"HELLO WORLD", FFFFFF,8,1,0,"enhanced_led_board-7.ttf" 25 | render 26 | 27 |
28 | 29 |

Back

30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /examples/multichannel.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - rotating colors 7 | 8 | 9 |

10 | Add a LED string of 300 LEDs WS2812 chip on PWM0 (GPIO 12) output of the Raspberry Pi.
11 | Add a LED string of 50 LEDs WS2812 on PWM1 (GPIO 13) output.
12 | Add a LED string of 30 SK9822 to SPI 1 interface MOSI and CLK.
13 | Execute these commads to fill first string with RED, second with GREEN and third blue. 14 |

15 | 16 |
17 | setup 1,300,3 18 | setup 2,50,3,0,255,19 19 | setup 3,30,12 20 | init 21 | fill 1,FF0000 22 | fill 2,00FF00 23 | fill 3,0000FF 24 | render 1 25 | render 2 26 | render 3 27 |
28 | 29 |

Use CTRL+C key to stop the rotating and return to command line.

30 | 31 |

Back

32 | 33 | -------------------------------------------------------------------------------- /examples/panel_type_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/examples/panel_type_0.png -------------------------------------------------------------------------------- /examples/panel_type_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/examples/panel_type_1.png -------------------------------------------------------------------------------- /examples/panel_type_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/examples/panel_type_2.png -------------------------------------------------------------------------------- /examples/panel_type_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/examples/panel_type_3.png -------------------------------------------------------------------------------- /examples/print_text.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - message board 7 | 8 | 9 |

10 | This command prints text on an 8x32 display. 11 |

12 | 13 |
14 | 15 | setup 1,256,3 16 | init 17 | brightness 1,32 18 | config_2D 1,32,8,3,32,8 19 | init_layer 1,0,1,0,1,0 20 | debug 1 21 | print_text 1,0,8,"HELLO WORLD", FF0000,8,1,0,"enhanced_led_board-7.ttf" 22 | render 23 | 24 |
25 | 26 |

27 | NOTE: Put double quotes around your text, use \" if you need a double quote in your text. For special characters use UTF-8 encoding and a font that supports them. 28 |

29 | 30 | The next example will print text with gradient colored letters, using extra layer and a background picture. 31 |
32 | 33 | setup 1,256,3 34 | init 35 | brightness 1, 32 36 | config_2D 1,32,8,3,32,8 37 | draw_image 1,examples/red-green.png 38 | init_layer 1,1,8,0,1,0 39 | change_layer 1,1 40 | print_text 1,0,8,"HELLO", FF0000,8,1,0,"enhanced_led_board-7.ttf" 41 | render 42 | 43 |
44 | 45 |

Back

46 | 47 | -------------------------------------------------------------------------------- /examples/pulses.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - pulses 7 | 8 | 9 |

10 | This will make some kind of music level driven chaser. 11 |

12 | 13 |
14 | 15 | setup 1,120,3 16 | init 17 | record_audio "plughw:CARD=Device,DEV=0" 18 | rainbow 1 19 | pulses 1 20 | 21 |
22 | 23 |

Back

24 | 25 | -------------------------------------------------------------------------------- /examples/rainbow_easy.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - simple rainbow 7 | 8 | 9 |

10 | Add a LED string of 10 LEDs with WS2812 chip on PWM0 (GPIO 12) output of the Raspberry Pi.
11 | Execute these commads to render a rainbow. 12 |

13 | 14 |
15 | setup 1,10,5 16 | init 17 | rainbow 18 | render 19 |
20 | 21 |

22 | If colors do not match, try a different LED type (change the 5 in the setup command). 23 |

24 |

Back

25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/record_audio.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - recording audio 7 | 8 | 9 |

10 | You'll need a USB sound interface to record audio or HDMI capture device to capture audio from another Raspberry or computer. 11 | ALSA must be installed as sound system for your Raspberry (but this is installed by default). 12 | 13 | Now you need to list the available audio record devices with: 14 |

15 | 16 | arecord -L 17 | 18 |
19 | 20 | It will list all available audio devices, search for the line that begins with "plughw". For example: plughw:CARD=Device,DEV=0 this is the device name we need to initialize recording.
21 | Then you can start recording audio with these commands for example a 120 led string: 22 |

23 | 24 |
25 | 26 | setup 1,120,3 27 | init 28 | record_audio "plughw:CARD=Device,DEV=0" 29 | 30 |
31 | 32 |

33 | Now audio will be recorded in internal buffer and you can start using audio effect commands.
34 |

35 | 36 | Example: 37 | 38 |
39 | 40 | setup 1,50,3,0,255,18 41 | init 42 | record_audio "plughw:CARD=Capture,DEV=0",48000,2 43 | filter_audio 1,100 44 | do 45 | light_organ 1,2,,10,60,,,,,10 46 | vu_meter 1,,,60 47 | pulses 1,0.02,2,,,10,,60 48 | loop 49 | 50 |
51 | 52 |

53 | With the filter_audio command you can apply a simple low pass, high pass or band pass filter. 54 |

55 | 56 |

57 | -The recording is thread dependend, if you want to create a second thread you'll also need to start a record command in that thread first. But you can forward recorded samples to other threads.
58 | -If you get error "Cannot set parameters (Invalid argument)." this mostly means that the audio device doesn't support the requested sample rate. Try to launch the record command with different sample rate like:
59 |

60 | 61 | record_audio "plughw:CARD=Capture,DEV=0",48000,2 62 | 63 |
64 |

65 | 66 |

Back

67 | 68 | 69 | -------------------------------------------------------------------------------- /examples/rectangle.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - Draw a rectangle 7 | 8 | 9 |

10 | This command paints a rectangle of 4x4 with fill color green and no border.
11 | Connect a 8x8 LED panel to PWM0 output. 12 |

13 | 14 |
15 | 16 | setup 1,64,3 17 | init 18 | brightness 1,32 19 | config_2D 1,8,8,3,8,8 20 | draw_rectangle 1,2,2,4,4,00FF00,0 21 | render 22 | 23 |
24 | 25 |

Back

26 | 27 | -------------------------------------------------------------------------------- /examples/red-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/examples/red-green.png -------------------------------------------------------------------------------- /examples/rgb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/examples/rgb.jpg -------------------------------------------------------------------------------- /examples/rgb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/examples/rgb.png -------------------------------------------------------------------------------- /examples/rotating_colors.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - rotating colors 7 | 8 | 9 |

10 | Add a LED string of 10 LEDs with WS2812 chip on PWM0 (GPIO 12) output of the Raspberry Pi.
11 | Execute these commads to create RED - YELLOW - GREEN - BLUE rotating effect. 12 |

13 | 14 |
15 | setup 1,10,5 16 | init 17 | #first set the led colors 18 | do 19 | rotate 1,2,1,FF0000 20 | rotate 1,2,1,FFFF00 21 | rotate 1,2,1,00FF00 22 | rotate 1,2,1,0000FF 23 | loop 3 24 | 25 | render 1 26 | 27 | #now make them rotate 28 | do 29 | rotate 1,2 30 | delay 1000 31 | render 1 32 | loop 33 |
34 | 35 |

Use CTRL+C key to stop the rotating and return to command line.

36 | 37 |

Back

38 | 39 | -------------------------------------------------------------------------------- /examples/run_script.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - run script 7 | 8 | 9 |

10 | In this runs external script my_script.sh with the system command.
11 | 12 |

13 | 14 |

15 | By default the system command is disabled, you must start the ws2812svr program with the -s parameter!
16 | sudo ./ws2812svr -s
17 | If you run it as a service, you must edit the /etc/ws2812svr.conf file and change: allow_system_cmd=1 18 |

19 | 20 |
21 | 22 | setup 1,30,3 23 | init 24 | fill 1,FF0000 25 | render 26 | system ./my_script.sh 27 | fill 1,00FF00 28 | render 29 | delay 1000 30 | fill 1,0000FF 31 | render 32 | delay 1000 33 | 34 |
35 | 36 |

Back

37 | 38 | 39 | -------------------------------------------------------------------------------- /examples/screenshot.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - 2D take screenshot 7 | 8 | 9 |

10 | If 2D graphics are enabled you can take a screenshot of the Raspberry Pi desktop.
11 | In this example a screenshot of the Raspberry Pi start button is taken and rendered on 4 panels of 8x32 LEDs (total 32x32 display). 12 |

13 | 14 |
15 | 16 | setup 1,1024,3 17 | init 18 | brightness 1,32 19 | config_2D 1,32,32,3,32,8 20 | take_screenshot 1,:0,0,0,8,4,32,32,32,32 21 | 22 |
23 | 24 |

25 | NOTE: The ws2812svr executable must have access to the desktop (run from command window on the desktop, it cannot be executed from ssh in this case). 26 |

27 | 28 |

Back

29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/setup_2D.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - setting up 2D 7 | 8 | 9 |

10 | Connect a 2D panel with WS2812 LEDs to your Raspberry pi. It's possible to chain many panels together and create a large display.
11 | First you need to do a normal setup with total LEDs in all connected panels.
12 | The config_2D command will create a conversion table in the background taking the x and y location and convert it to LED position in the normal 1D string. 13 | There are 4 supported LED configurations and a 5th type which allows you to create your own conversion table in a text file.
14 | At this moment the first pixel (0,0) must always be at the left top of the screen.

15 | 16 |
    17 |
  • Panel type 0:
    18 | Row by row and the end of each row is connected to the beginning of the next row.
    19 | 20 |
  • 21 |
  • Panel type 1:
    22 | Row by row but even rows are connected left to right and odd rows right to left.
    23 | 24 |
  • 25 |
  • Panel type 2:
    26 | Panels with LEDs configured as columns.
    27 | 28 |
  • 29 |
  • Panel type 3:
    30 | Panels with LEDs configured as columns but odd panel rows are rotated 180�.
    31 | 32 |
  • 33 |
  • Panel type 4:
    34 | Custom pixel locations defined in a text file. This text file looks like:
    35 |
    36 | 37 | x,y=index 38 | 0,0=3 39 | 1,0=4 40 | 2,0=5 41 | 3,0=10 42 | 4,0=11 43 | 5,0=6 44 | 45 |
    46 | Here x and y is the pixel coordinates and index is the location of the LED at x,y in the 1D string. (Do not include x,y=index in the file.) 47 |
  • 48 |
49 |

50 | 51 |

The following commands configure a 32x16 pixel display with 2 32x8 pixel displays.

52 | 53 |
54 | 55 | setup 1,512,3 56 | init 57 | brightness 1,32 58 | config_2D 1,32,16,3,32,8 59 | 60 |
61 | 62 |

Back

63 | 64 | 65 | -------------------------------------------------------------------------------- /examples/stream_audio_multiple_threads.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - recording audio to multiple threads 7 | 8 | 9 | 10 |

11 | You can use one thread to record audio and stream it to other threads, each of these threads can be connected to a LED string that runs a different effect like light organ, pulses, etc... 12 |
13 | In this example the main thread will only be used to record/capture audio from the sound card. The main thread will feed the samples to thread 1 and thread 2.
14 | Thread 1 and 2 will apply a different filter and different effect. 15 |

16 | 17 | setup 1,300,3,0,255,18 18 | setup 2,100,5,0,255,19 19 | init 20 | 21 | record_audio "plughw:CARD=Capture,DEV=0",48000,2 22 | 23 | thread_start 1 24 | record_audio "thread://0" 25 | filter_audio 1,100 26 | do 27 | light_organ 1 28 | loop 29 | thread_stop 30 | 31 | thread_start 2 32 | record_audio "thread://0" 33 | filter_audio 2,0,1500 34 | do 35 | vu_meter 2,,,60 36 | loop 37 | thread_stop 38 | 39 | #keep main thread running! 40 | do 41 | delay 100 42 | loop 43 | 44 |
45 | 46 |

Back

47 | 48 | -------------------------------------------------------------------------------- /examples/style.css: -------------------------------------------------------------------------------- 1 | .commands { 2 | white-space: pre; 3 | color: gray; 4 | } -------------------------------------------------------------------------------- /examples/sync_threads.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - synchronizing threads 7 | 8 | 9 |

10 | In case you have 2 LED strings and you want both LED strings to execute some effects but they should start / end at the same time. You can do this with threads and at some point synchronize them.
11 | Add a LED string of 256 LEDs WS2812 chip on PWM0 (GPIO 12) output of the Raspberry Pi.
12 | Add a LED string of 64 LEDs WS2812 on PWM1 (GPIO 13) output.
13 | The following commands will fade both LED strings in / out at the same time. 14 |

15 | 16 |
17 | 18 | setup 1,256,3 19 | setup 2,64,3,0,255,19 20 | init 21 | brightness 1, 32 22 | brightness 2, 32 23 | fill 1,00FF00 24 | fill 2,0000FF 25 | 26 | thread_start 1 27 | do 28 | fade 1,0,32,100 29 | wait_signal 30 | fade 1,32,0,100 31 | wait_signal 32 | loop 33 | thread_stop 34 | 35 | thread_start 2 36 | do 37 | fade 2,0,32,100 38 | signal_thread 1,1 39 | fade 2,32,0,100 40 | signal_thread 1,1 41 | loop 42 | thread_stop 43 | 44 |
45 | 46 |

47 | The wait_signal in thread 1 will wait until it receives a signal to continue. This signal comes from thread 2 with the signal_thread 1,1 command. 48 |

49 | 50 | 51 |

Back

52 | 53 | -------------------------------------------------------------------------------- /examples/test.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/examples/test.gif -------------------------------------------------------------------------------- /examples/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/examples/test.png -------------------------------------------------------------------------------- /examples/text_input.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - TCP socket scrolling text 7 | 8 | 9 |

10 | This example creates a TCP socket listening on port 9000, text send to this socket will be displayed as a scrolling text message board.
11 | Requires a 32x8 pixel LED board. 12 |

13 | 14 |
15 | 16 | setup 1,256,3 17 | init 18 | debug 1 19 | brightness 1, 32 20 | config_2D 1,32,8,3,32,8 21 | text_input 1,0,8,32,8,9000,0,FF0000,000000,50,8,1,0,"enhanced_led_board-7.ttf" 22 | 23 | 24 |
25 | 26 | Now use the netcat (sudo apt-get install netcat) command to connect to port 9000 and send the text you want to appear scrolling on the display. 27 | 28 |
29 | 30 | nc localhost 9000 31 | HELLO WORLD 32 | 33 |
34 | 35 |

36 | Replace localhost by the IP of your Raspberry if you want to connect remotely.
37 | Currently only ASCI characters are supported UTF-8 may produce unwanted effects. 38 |

39 | 40 | 41 |

Back

42 | 43 | -------------------------------------------------------------------------------- /examples/threads.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - threads 7 | 8 | 9 |

10 | Add a LED string of 300 LEDs WS2812 chip on PWM0 (GPIO 12) output of the Raspberry Pi.
11 | Add a LED string of 50 LEDs WS2812 on PWM1 (GPIO 13) output.
12 | Add a LED string of 30 SK9822 to SPI 1 interface MOSI and CLK.
13 | The following commands will create 3 threads (a thread is something that will run commands in parallel in the background). 14 | The first string will run the chaser effect, the second will change between red, green and blue color and the third will fade in/out. 15 |

16 | 17 |
18 | 19 | setup 1,300,3 20 | setup 2,50,3,0,255,19 21 | setup 3,30,12 22 | init 23 | 24 | thread_start 1 25 | chaser 1,0,FF0000 26 | thread_stop 27 | 28 | thread_start 2 29 | do 30 | fill 2,FF0000 31 | render 2 32 | delay 1000 33 | fill 2,00FF00 34 | render 2 35 | delay 1000 36 | fill 2,0000FF 37 | render 2 38 | delay 1000 39 | loop 40 | thread_stop 41 | 42 | thread_start 3 43 | fill 3,00FF00 44 | do 45 | fade 3,0,255,100 46 | fade 3,255,0,100 47 | loop 48 | thread_stop 49 | 50 |
51 | 52 |

53 | To stop one of the 3 threads you can use the kill_thread command. 54 | For example to stop the color changing in thread 2 you type: 55 |

56 | 57 |
58 | 59 | kill_thread 2,1 60 | 61 |
62 | 63 |

To stop thread 1 you need to abort the chaser command because it will run forever. You can do this by setting the kill type to 0

64 | 65 |
66 | 67 | kill_thread 1,0 68 | 69 |
70 | 71 |

If you want to wait for a thread to finish all it's commands you use the wait_thread.
NOTE: in this example all threads will run forever and this command will never return.

72 | 73 |
74 | 75 | wait_thread 76 | 77 |
78 | 79 |

80 | When connecting through a socket (from PHP/website script) you should use threads to make the commands run in the background. 81 | For example:
82 | Start the server with tcp and the setup command: 83 |

84 | 85 |
86 | 87 | sudo ./ws2812svr -tcp 9999 -i "setup 1,299,3; init;" 88 | 89 |
90 | 91 |

From PHP send first commands:

92 |
93 | 94 | <?php 95 | send_to_leds("thread_start 1,0; 96 | <YOUR EFFECT COMMANDS HERE> 97 | thread_stop; 98 | "); 99 | 100 | function send_to_leds ($data) { 101 | $sock = fsockopen("127.0.0.1", 9999); 102 | fwrite($sock, $data); 103 | fclose($sock); 104 | } 105 | 106 | ?> 107 | 108 |
109 | 110 |

Next call to the PHP page:

111 |
112 | 113 | <?php 114 | send_to_leds("thread_start 1,0; 115 | <YOUR NEXT EFFECT COMMANDS HERE> 116 | thread_stop; 117 | "); 118 | ?> 119 | 120 |
121 | 122 |

If you want to synchronize effects between multiple threads see this example.

123 | 124 |

Threads another way

125 | This example uses threads in a different way to make 5 LED strips change in color at the same time.
126 | Strip 3,4,5 are connected to Raspberry Pi Zero over the network using remote slave channels. 127 |

128 |

129 | 130 | setup 1,250,5,0,255,18 131 | setup 2,300,3,0,255,19 132 | setup 3,100,100,"192.168.0.81",8000 133 | setup 4,120,100,"192.168.0.82",8000 134 | setup 5,150,100,"192.168.0.83",8000 135 | init 136 | 137 | thread_start 1 138 | color_change 1, 0, 190, 20000 139 | thread_stop 140 | 141 | thread_start 2 142 | color_change 2, 0, 190, 20000 143 | thread_stop 144 | 145 | thread_start 3 146 | color_change 3, 0, 190, 20000 147 | thread_stop 148 | 149 | thread_start 4 150 | color_change 4, 0, 190, 20000 151 | thread_stop 152 | 153 | thread_start 5 154 | color_change 5, 0, 190, 20000 155 | thread_stop 156 | 157 | #now wait for all effects to complete 158 | 159 | wait_thread_exit 1 160 | wait_thread_exit 2 161 | wait_thread_exit 3 162 | wait_thread_exit 4 163 | wait_thread_exit 5 164 | 165 | 166 |
167 |

168 | 169 |

Back

170 | 171 | -------------------------------------------------------------------------------- /examples/vu_meter.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WS2812 Server - vu meter 7 | 8 | 9 |

10 | This will render a volume level meter on your LED strip.
11 | The louder the music more LEDs will be turned on. 12 |

13 | 14 |
15 | 16 | setup 1,120,3 17 | init 18 | record_audio "plughw:CARD=Device,DEV=0" 19 | vu_meter 1 20 | 21 |
22 | 23 |

Back

24 | 25 | 26 | -------------------------------------------------------------------------------- /fifo.c: -------------------------------------------------------------------------------- 1 | #include "fifo.h" 2 | 3 | size_t fifo_count (fifo_buf_t * fifo){ 4 | if (fifo->head >= fifo->tail){ 5 | return fifo->head - fifo->tail; 6 | }else{ 7 | return fifo->max - fifo->tail + fifo->head; 8 | } 9 | } 10 | 11 | size_t fifo_available(fifo_buf_t * fifo){ 12 | return fifo->max - fifo_count(fifo); 13 | } 14 | 15 | size_t write_buffer(fifo_buf_t * fifo, void * source, size_t len){ 16 | size_t size_to_end = fifo->max - fifo->head; //standard buffer is free until the end 17 | if (fifo->tail >= fifo->head) size_to_end = fifo->tail - fifo->head; //check if reading is behind writing, buffer is only free until write pointer 18 | 19 | if (len <= size_to_end){ //check if we can write in 1 time and buffer is free 20 | memcpy(&fifo->buffer[fifo->head], source, len); 21 | fifo->head +=len; 22 | if (len == size_to_end) fifo->head=0; 23 | if (fifo->tail==fifo->head) fifo->full=true; 24 | return len; 25 | }else{ 26 | //copy to end of buffer 27 | memcpy(&fifo->buffer[fifo->head], source, size_to_end); 28 | source+=size_to_end; 29 | len -= size_to_end; 30 | size_t available = fifo->tail; 31 | if (available > len) { 32 | available = len; 33 | }else if (available == len){ 34 | fifo->full = true; 35 | }else{ 36 | 37 | } 38 | memcpy(fifo->buffer, source, available); 39 | fifo->head = available; 40 | return size_to_end + available; 41 | } 42 | } 43 | 44 | size_t read_buffer(fifo_buf_t * fifo, void * destination, size_t max_len){ 45 | size_t end = fifo->head; //first find the end of the buffer (max or head) 46 | if (fifo->full || fifo->head < fifo->tail) end = fifo->max; //head is beyond end 47 | 48 | size_t read_bytes = end - fifo->tail; //we can read this ammount of bytes from buffer 49 | 50 | if (read_bytes > 0){ 51 | if (read_bytes > max_len) read_bytes = max_len; //check if we can store that ammount 52 | memcpy(destination, &fifo->buffer[fifo->tail], read_bytes); 53 | 54 | fifo->tail+=read_bytes; 55 | if (fifo->tail>=fifo->max) fifo->tail = 0; 56 | fifo->full=false; 57 | 58 | //check if destination buffer is not full and more data available in the beginning of the buffer 59 | if (read_bytes < max_len && fifo->head > fifo->tail){ 60 | size_t read_more = fifo->head; //we will read more bytes from beginning of buffer 61 | if (read_more + read_bytes > max_len) read_more = max_len - read_bytes; //check if destination buffer is large enough to read all available data 62 | memcpy(&destination[read_bytes], fifo->buffer, read_more); //copy 63 | fifo->tail+=read_more; 64 | return read_bytes + read_more; //return total bytes read 65 | } 66 | } 67 | 68 | return read_bytes; //return total bytes read 69 | 70 | /* if (fifo->head > fifo->tail){ 71 | available = fifo->head - fifo->tail; 72 | if (available > max_len) available = max_len; 73 | memcpy(destination, &fifo->buffer[fifo->tail], available); 74 | 75 | fifo->tail +=available; 76 | if (fifo->tail > fifo->max) fifo->tail=0; 77 | 78 | }else{ 79 | available = fifo->max - fifo->tail + fifo->head; 80 | memcpy(destination, &fifo->buffer[fifo->tail], available); 81 | 82 | 83 | } 84 | 85 | 86 | 87 | 88 | size_t read = min (fifo_available(fifo), max_len); 89 | memcpy(destination, fifo->buffer, read); 90 | return read;*/ 91 | } 92 | -------------------------------------------------------------------------------- /fifo.h: -------------------------------------------------------------------------------- 1 | #ifndef FIFO_BUFFER 2 | #define FIFO_BUFFER 3 | 4 | #include 5 | //https://embeddedartistry.com/blog/2017/05/17/creating-a-circular-buffer-in-c-and-c/ 6 | //https://github.com/cgaebel/pipe 7 | 8 | struct fifo_buf_t { 9 | void * buffer; 10 | size_t head; 11 | size_t tail; 12 | size_t max; //of the buffer 13 | bool full; 14 | bool blocking; 15 | }; 16 | 17 | 18 | void create_buffer(fifo_buf_t * fifo, size_t item_size, size_t count, bool blocking); 19 | 20 | size_t read_buffer(fifo_buf_t * fifo, void * destination, size_t max_len); 21 | 22 | size_t write_buffer(fifo_buf_t * fifo, void * source, size_t len); 23 | 24 | 25 | 26 | #endif -------------------------------------------------------------------------------- /gifdec.h: -------------------------------------------------------------------------------- 1 | #ifndef GIFDEC_H 2 | #define GIFDEC_H 3 | 4 | #include 5 | #include 6 | 7 | typedef struct gd_Palette { 8 | int size; 9 | uint8_t colors[0x100 * 3]; 10 | } gd_Palette; 11 | 12 | typedef struct gd_GCE { 13 | uint16_t delay; 14 | uint8_t tindex; 15 | uint8_t disposal; 16 | int input; 17 | int transparency; 18 | } gd_GCE; 19 | 20 | typedef struct gd_GIF { 21 | int fd; 22 | off_t anim_start; 23 | uint16_t width, height; 24 | uint16_t depth; 25 | uint16_t loop_count; 26 | gd_GCE gce; 27 | gd_Palette* palette; 28 | gd_Palette lct, gct; 29 | void (*plain_text)( 30 | struct gd_GIF* gif, uint16_t tx, uint16_t ty, 31 | uint16_t tw, uint16_t th, uint8_t cw, uint8_t ch, 32 | uint8_t fg, uint8_t bg 33 | ); 34 | void (*comment)(struct gd_GIF* gif); 35 | void (*application)(struct gd_GIF* gif, char id[8], char auth[3]); 36 | uint16_t fx, fy, fw, fh; 37 | uint8_t bgindex; 38 | uint8_t* canvas, * frame; 39 | } gd_GIF; 40 | 41 | gd_GIF* gd_open_gif(const char* fname); 42 | int gd_get_frame(gd_GIF* gif); 43 | void gd_render_frame(gd_GIF* gif, uint8_t* buffer); 44 | int gd_is_bgcolor(gd_GIF* gif, uint8_t color[3]); 45 | void gd_rewind(gd_GIF* gif); 46 | void gd_close_gif(gd_GIF* gif); 47 | 48 | #endif /* GIFDEC_H */ -------------------------------------------------------------------------------- /gpio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gpio.h 3 | * 4 | * Copyright (c) 2014 Jeremy Garff 5 | * 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without modification, are permitted 9 | * provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, this list of 12 | * conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 14 | * of conditions and the following disclaimer in the documentation and/or other materials 15 | * provided with the distribution. 16 | * 3. Neither the name of the owner nor the names of its contributors may be used to endorse 17 | * or promote products derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 24 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | */ 29 | 30 | #ifndef __GPIO_H__ 31 | #define __GPIO_H__ 32 | 33 | #include 34 | 35 | typedef struct 36 | { 37 | uint32_t fsel[6]; // GPIO Function Select 38 | uint32_t resvd_0x18; 39 | uint32_t set[2]; // GPIO Pin Output Set 40 | uint32_t resvd_0x24; 41 | uint32_t clr[2]; // GPIO Pin Output Clear 42 | uint32_t resvd_0x30; 43 | uint32_t lev[2]; // GPIO Pin Level 44 | uint32_t resvd_0x3c; 45 | uint32_t eds[2]; // GPIO Pin Event Detect Status 46 | uint32_t resvd_0x48; 47 | uint32_t ren[2]; // GPIO Pin Rising Edge Detect Enable 48 | uint32_t resvd_0x54; 49 | uint32_t fen[2]; // GPIO Pin Falling Edge Detect Enable 50 | uint32_t resvd_0x60; 51 | uint32_t hen[2]; // GPIO Pin High Detect Enable 52 | uint32_t resvd_0x6c; 53 | uint32_t len[2]; // GPIO Pin Low Detect Enable 54 | uint32_t resvd_0x78; 55 | uint32_t aren[2]; // GPIO Pin Async Rising Edge Detect 56 | uint32_t resvd_0x84; 57 | uint32_t afen[2]; // GPIO Pin Async Falling Edge Detect 58 | uint32_t resvd_0x90; 59 | uint32_t pud; // GPIO Pin Pull up/down Enable 60 | uint32_t pudclk[2]; // GPIO Pin Pull up/down Enable Clock 61 | uint32_t resvd_0xa0[4]; 62 | uint32_t test; 63 | } __attribute__((packed, aligned(4))) gpio_t; 64 | 65 | 66 | #define GPIO_OFFSET (0x00200000) 67 | 68 | #define GPIO_ALT_FUNC0 0 69 | #define GPIO_ALT_FUNC1 1 70 | #define GPIO_ALT_FUNC2 2 71 | #define GPIO_ALT_FUNC3 3 72 | #define GPIO_ALT_FUNC4 4 73 | #define GPIO_ALT_FUNC5 5 74 | #define GPIO_FUNC_IN 6 75 | #define GPIO_FUNC_OUT 7 76 | 77 | static inline void gpio_function_set(volatile gpio_t* gpio, uint8_t pin, uint8_t function) 78 | { 79 | int regnum = pin / 10; 80 | int offset = (pin % 10) * 3; 81 | uint8_t funcmap[] = { 4, 5, 6, 7, 3, 2, 0, 1 }; // See datasheet for mapping 82 | 83 | if (function > 5) 84 | { 85 | return; 86 | } 87 | 88 | gpio->fsel[regnum] &= ~(0x7 << offset); 89 | gpio->fsel[regnum] |= ((funcmap[function]) << offset); 90 | } 91 | 92 | static inline void gpio_level_set(volatile gpio_t* gpio, uint8_t pin, uint8_t level) 93 | { 94 | int regnum = pin >> 5; 95 | int offset = (pin & 0x1f); 96 | 97 | if (level) 98 | { 99 | gpio->set[regnum] = (1 << offset); 100 | } 101 | else 102 | { 103 | gpio->clr[regnum] = (1 << offset); 104 | } 105 | } 106 | 107 | static inline int gpio_level_read(volatile gpio_t* gpio, uint8_t pin) 108 | { 109 | int regnum = pin >> 5; 110 | int offset = (pin & 0x1f); 111 | 112 | return (gpio->lev[regnum] & (1 << offset))!=0 ? 1 : 0; 113 | } 114 | 115 | static inline void gpio_output_set(volatile gpio_t* gpio, uint8_t pin, uint8_t output) 116 | { 117 | int regnum = pin / 10; 118 | int offset = (pin % 10) * 3; 119 | uint8_t function = output ? 1 : 0; // See datasheet for mapping 120 | 121 | gpio->fsel[regnum] &= ~(0x7 << offset); 122 | gpio->fsel[regnum] |= ((function & 0x7) << offset); 123 | } 124 | 125 | #endif /* __GPIO_H__ */ -------------------------------------------------------------------------------- /jpghelper.c: -------------------------------------------------------------------------------- 1 | #include "jpghelper.h" 2 | 3 | /* 4 | * Here's the routine that will replace the standard error_exit method: 5 | */ 6 | void my_error_exit (j_common_ptr cinfo){ 7 | /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ 8 | my_error_ptr myerr = (my_error_ptr) cinfo->err; 9 | 10 | /* Always display the message. */ 11 | /* We could postpone this until after returning, if we chose. */ 12 | (*cinfo->err->output_message) (cinfo); 13 | 14 | /* Return control to the setjmp point */ 15 | longjmp(myerr->setjmp_buffer, 1); 16 | } 17 | 18 | void jpg_init_source(j_decompress_ptr cinfo) { 19 | 20 | } 21 | 22 | boolean jpg_fill_input_buffer(j_decompress_ptr cinfo){ 23 | ERREXIT(cinfo, JERR_INPUT_EMPTY); 24 | return TRUE; 25 | } 26 | 27 | void jpg_skip_input_data(j_decompress_ptr cinfo, long num_bytes){ 28 | struct jpeg_source_mgr* src = (struct jpeg_source_mgr*)cinfo->src; 29 | 30 | if (num_bytes > 0) { 31 | src->next_input_byte += (size_t)num_bytes; 32 | src->bytes_in_buffer -= (size_t)num_bytes; 33 | } 34 | } 35 | 36 | void jpg_term_source(j_decompress_ptr cinfo) { 37 | 38 | } -------------------------------------------------------------------------------- /jpghelper.h: -------------------------------------------------------------------------------- 1 | #ifndef JPG_HELPER_H 2 | #define JPG_HELPER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //from https://github.com/LuaDist/libjpeg/blob/master/example.c 11 | 12 | struct my_error_mgr { 13 | struct jpeg_error_mgr pub; /* "public" fields */ 14 | 15 | jmp_buf setjmp_buffer; /* for return to caller */ 16 | }; 17 | 18 | typedef struct my_error_mgr * my_error_ptr; 19 | 20 | //helper functions for JPG library 21 | void my_error_exit (j_common_ptr cinfo); 22 | void jpg_init_source(j_decompress_ptr cinfo); 23 | boolean jpg_fill_input_buffer(j_decompress_ptr cinfo); 24 | void jpg_skip_input_data(j_decompress_ptr cinfo, long num_bytes); 25 | void jpg_term_source(j_decompress_ptr cinfo); 26 | 27 | #endif -------------------------------------------------------------------------------- /mailbox.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2012, Broadcom Europe Ltd. 3 | All rights reserved. 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the copyright holder nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY 18 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | 28 | #define MAJOR_NUM 100 29 | #define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM, 0, char *) 30 | 31 | #define DEV_MEM "/dev/mem" 32 | #define DEV_GPIOMEM "/dev/gpiomem" 33 | 34 | int mbox_open(void); 35 | void mbox_close(int file_desc); 36 | 37 | unsigned get_version(int file_desc); 38 | unsigned mem_alloc(int file_desc, unsigned size, unsigned align, unsigned flags); 39 | unsigned mem_free(int file_desc, unsigned handle); 40 | unsigned mem_lock(int file_desc, unsigned handle); 41 | unsigned mem_unlock(int file_desc, unsigned handle); 42 | void *mapmem(unsigned base, unsigned size, const char *mem_dev); 43 | void *unmapmem(void *addr, unsigned size); 44 | 45 | unsigned execute_code(int file_desc, unsigned code, unsigned r0, unsigned r1, unsigned r2, unsigned r3, unsigned r4, unsigned r5); 46 | unsigned execute_qpu(int file_desc, unsigned num_qpus, unsigned control, unsigned noflush, unsigned timeout); 47 | unsigned qpu_enable(int file_desc, unsigned enable); -------------------------------------------------------------------------------- /master_slave.h: -------------------------------------------------------------------------------- 1 | #ifndef MASTER_SLAVE_H 2 | #define MASTER_SLAVE_H 3 | 4 | #include "ws2812svr.h" 5 | 6 | #define SLAVE_SIGNATURE 0xFB 7 | #define SLAVE_PROTOCOL_VERSION 0x1 8 | #define SLAVE_COMMAND_RENDER 0x1 9 | #define SLAVE_COMMAND_CMD_OK 0x2 10 | 11 | typedef struct { 12 | unsigned char signature; 13 | unsigned char version; 14 | unsigned short reserved; 15 | unsigned int command; 16 | unsigned int flags; 17 | unsigned int packet_nr; 18 | unsigned int data_size; 19 | } slave_channel_packet; 20 | 21 | void close_slave_channel(channel_info * channel); 22 | bool connect_slave_channel(channel_info * channel); 23 | void render_slave_channel(channel_info * channel); 24 | void slave_listen(thread_context * context, char * args); 25 | 26 | 27 | #endif -------------------------------------------------------------------------------- /pcm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pcm.c 3 | * 4 | * Copyright (c) 2014 Jeremy Garff 5 | * PCM version Copyright (c) 2016 Ton van Overbeek 6 | * 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without modification, are permitted 10 | * provided that the following conditions are met: 11 | * 12 | * 1. Redistributions of source code must retain the above copyright notice, this list of 13 | * conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | * of conditions and the following disclaimer in the documentation and/or other materials 16 | * provided with the distribution. 17 | * 3. Neither the name of the owner nor the names of its contributors may be used to endorse 18 | * or promote products derived from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 22 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 25 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | */ 30 | 31 | 32 | #include 33 | #include "pcm.h" 34 | 35 | 36 | // Mapping of Pin to alternate function for PCM_CLK 37 | const pcm_pin_table_t pcm_pin_clk[] = 38 | { 39 | { 40 | .pinnum = 18, 41 | .altnum = 0, 42 | }, 43 | { 44 | .pinnum = 28, 45 | .altnum = 2, 46 | }, 47 | }; 48 | 49 | // Mapping of Pin to alternate function for PCM_FS 50 | const pcm_pin_table_t pcm_pin_fs[] = 51 | { 52 | { 53 | .pinnum = 19, 54 | .altnum = 0, 55 | }, 56 | { 57 | .pinnum = 29, 58 | .altnum = 2, 59 | }, 60 | }; 61 | 62 | // Mapping of Pin to alternate function for PCM_DIN 63 | const pcm_pin_table_t pcm_pin_din[] = 64 | { 65 | { 66 | .pinnum = 20, 67 | .altnum = 0, 68 | }, 69 | { 70 | .pinnum = 30, 71 | .altnum = 2, 72 | }, 73 | }; 74 | 75 | // Mapping of Pin to alternate function for PCM_DOUT 76 | const pcm_pin_table_t pcm_pin_dout[] = 77 | { 78 | { 79 | .pinnum = 21, 80 | .altnum = 0, 81 | }, 82 | { 83 | .pinnum = 31, 84 | .altnum = 2, 85 | }, 86 | }; 87 | 88 | const pcm_pin_tables_t pcm_pin_tables[NUM_PCMFUNS] = 89 | { 90 | { 91 | .pins = pcm_pin_clk, 92 | .count = sizeof(pcm_pin_clk) / sizeof(pcm_pin_clk[0]), 93 | }, 94 | { 95 | .pins = pcm_pin_fs, 96 | .count = sizeof(pcm_pin_fs) / sizeof(pcm_pin_fs[0]), 97 | }, 98 | { 99 | .pins = pcm_pin_din, 100 | .count = sizeof(pcm_pin_din) / sizeof(pcm_pin_din[0]), 101 | }, 102 | { 103 | .pins = pcm_pin_dout, 104 | .count = sizeof(pcm_pin_dout) / sizeof(pcm_pin_dout[0]), 105 | }, 106 | }; 107 | 108 | 109 | int pcm_pin_alt(int pcmfun, int pinnum) 110 | { 111 | if (pcmfun < 0 || pcmfun > 3) { 112 | return -1; 113 | } 114 | const pcm_pin_tables_t *pintable = &pcm_pin_tables[pcmfun]; 115 | int i; 116 | 117 | for (i = 0; i < pintable->count; i++) 118 | { 119 | if (pintable->pins[i].pinnum == pinnum) 120 | { 121 | return pintable->pins[i].altnum; 122 | } 123 | } 124 | 125 | return -1; 126 | } 127 | 128 | -------------------------------------------------------------------------------- /php/colormap.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/php/colormap.gif -------------------------------------------------------------------------------- /pico w/code.py: -------------------------------------------------------------------------------- 1 | from ipaddress import IPv4Address 2 | import time 3 | import os 4 | import wifi 5 | import socketpool 6 | import microcontroller 7 | import struct 8 | import neopixel 9 | import board 10 | 11 | #by default al settings are loaded from settings.toml except the pin number 12 | 13 | #define the pin where LED string is attached 14 | pixel_pin = board.GP0 # os.getenv("PIN") how to load pin from settings?? 15 | 16 | #define wifi SSID password, dhcp and IP 17 | WIFI_SSID = os.getenv('WIFI_SSID') 18 | WIFI_PASSWORD = os.getenv('WIFI_PASSWORD') 19 | use_dhcp = os.getenv("USE_DHCP") 20 | ip = IPv4Address(os.getenv("IP")) 21 | netmask = IPv4Address(os.getenv("NETMASK")) 22 | gateway = IPv4Address(os.getenv("GATEWAY")) 23 | port = os.getenv("PORT") 24 | 25 | #define number of LEDs in your string here 26 | pixel_count = os.getenv("PIXEL_COUNT") 27 | 28 | #define here number of colors per pixel, default is 3 (RGB), use 4 if you use RGBW pixels 29 | pixel_color_size = os.getenv("PIXEL_COLOR_COUNT") 30 | 31 | #define here the pixel color order, RGB, RGBW, ... 32 | pixel_order = os.getenv("PIXEL_COLOR_ORDER") #neopixel.RGB 33 | 34 | #https://circuitpython-jake.readthedocs.io/en/latest/shared-bindings/socket/__init__.html 35 | #https://docs.circuitpython.org/projects/neopixel/en/latest/ 36 | 37 | #typedef struct { 38 | # unsigned char signature; 0 39 | # unsigned char version; 1 40 | # unsigned short reserved; 2 41 | # unsigned int command; 3 42 | # unsigned int flags; 4 43 | # unsigned int packet_nr; 5 44 | # unsigned int data_size; 6 45 | #} slave_channel_packet; 46 | 47 | SLAVE_PACKET_SIZE = 20 48 | SLAVE_SIGNATURE = 0xFB 49 | SLAVE_PROTOCOL_VERSION = 0x1 50 | SLAVE_COMMAND_RENDER = 0x1 51 | SLAVE_COMMAND_CMD_OK = 0x2 52 | 53 | pixels = neopixel.NeoPixel(pixel_pin, pixel_count, pixel_order=pixel_order, auto_write=False) 54 | pixels.show() 55 | 56 | print("INIT OK") 57 | wifi.radio.connect(WIFI_SSID, WIFI_PASSWORD) 58 | if use_dhcp: 59 | print("Finding IP address") 60 | print(wifi.radio.ipv4_address) 61 | else: 62 | print("Using Fixed IP ", ip) 63 | wifi.radio.set_ipv4_address(ipv4 = ip, netmask = netmask, gateway= gateway) 64 | 65 | pool = socketpool.SocketPool(wifi.radio) 66 | 67 | print("Creating socket") 68 | sock = pool.socket(pool.AF_INET, pool.SOCK_STREAM) 69 | 70 | host = str(wifi.radio.ipv4_address) 71 | sock.bind((host, port)) 72 | sock.listen(1) 73 | print("Accepting connections at ", host, ":", port) 74 | 75 | 76 | def send_slave_packet(conn: socketpool.Socket, command: int, flags: int, packet_nr: int): 77 | packet = struct.pack("BBHIIII", SLAVE_SIGNATURE, SLAVE_PROTOCOL_VERSION, 0, command, flags, packet_nr, 0) 78 | conn.send(packet) 79 | 80 | def receive_slave_packet(conn, buff): 81 | #https://docs.python.org/3/library/struct.html 82 | packet = struct.unpack("BBHIIII", bytes(buff)) 83 | if (packet[0]== SLAVE_SIGNATURE and packet[3]==SLAVE_COMMAND_RENDER): 84 | data_size = packet[6] 85 | led_data = bytearray(data_size) 86 | conn.recv_into(led_data, data_size) 87 | for i in range(pixel_count): 88 | pixels[i] = struct.unpack_from("BBB", bytes(led_data), i * pixel_color_size) 89 | pixels.show() 90 | send_slave_packet(conn, SLAVE_COMMAND_CMD_OK, 0, packet[5]) 91 | 92 | while True: 93 | try: 94 | conn, addr = sock.accept() 95 | print("Connected by ", addr) 96 | buff = bytearray(SLAVE_PACKET_SIZE) 97 | conn.setblocking(True) 98 | numbytes = conn.recv_into(buff, SLAVE_PACKET_SIZE) 99 | while numbytes > 0: 100 | if numbytes == SLAVE_PACKET_SIZE: 101 | receive_slave_packet(conn, buff) 102 | numbytes = conn.recv_into(buff, SLAVE_PACKET_SIZE) 103 | except OSError as e: 104 | print("Error: ", e) 105 | except Exception as e: 106 | print("Unknown error ", e) 107 | microcontroller.reset() -------------------------------------------------------------------------------- /pico w/lib/adafruit_pixelbuf.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/pico w/lib/adafruit_pixelbuf.mpy -------------------------------------------------------------------------------- /pico w/lib/neopixel.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-2015/rpi-ws2812-server/e76291fda909487fa199fd4129510dc3440ae4c6/pico w/lib/neopixel.mpy -------------------------------------------------------------------------------- /pico w/settings.toml: -------------------------------------------------------------------------------- 1 | #define WIFI_PASSWORD and WIFI_SSID, network settings here 2 | WIFI_SSID="" 3 | WIFI_PASSWORD="" 4 | USE_DHCP=0 5 | IP="192.168.0.82" 6 | NETMASK="255.255.255.0" 7 | GATEWAY="192.168.0.1" 8 | PORT=8000 9 | 10 | #define IP and port 11 | 12 | #define number of pixels 13 | PIXEL_COUNT=120 14 | 15 | #define number of colors in 1 LED 16 | PIXEL_COLOR_COUNT=3 17 | 18 | #define color order in the LED/data (RGB, RGBW) 19 | PIXEL_COLOR_ORDER="GRB" 20 | 21 | #GPIO pin number to send data 22 | PIN=0 23 | 24 | #always add empty line to the settings file 25 | -------------------------------------------------------------------------------- /pico w/vs.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "python.languageServer": "Pylance", 9 | "circuitpython.board.version": "8.0.0-beta.6", 10 | "circuitpython.board.vid": "0x2E8A", 11 | "circuitpython.board.pid": "0x101E", 12 | "python.linting.pylintEnabled": false, 13 | "python.analysis.diagnosticSeverityOverrides": { 14 | "reportMissingModuleSource": "none" 15 | }, 16 | "python.analysis.extraPaths": [ 17 | "c:\\Users\\Tom\\.vscode\\extensions\\joedevivo.vscode-circuitpython-0.1.19-win32-x64\\boards\\0x2E8A\\0x101E", 18 | "c:\\Users\\Tom\\.vscode\\extensions\\joedevivo.vscode-circuitpython-0.1.19-win32-x64\\stubs", 19 | "c:\\Users\\Tom\\AppData\\Roaming\\Code\\User\\globalStorage\\joedevivo.vscode-circuitpython\\bundle\\20221229\\adafruit-circuitpython-bundle-py-20221229\\lib" 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /pwm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pwm.c 3 | * 4 | * Copyright (c) 2014 Jeremy Garff 5 | * 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without modification, are permitted 9 | * provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, this list of 12 | * conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 14 | * of conditions and the following disclaimer in the documentation and/or other materials 15 | * provided with the distribution. 16 | * 3. Neither the name of the owner nor the names of its contributors may be used to endorse 17 | * or promote products derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 24 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | */ 29 | 30 | 31 | #include 32 | 33 | #include "ws2811.h" 34 | 35 | #include "pwm.h" 36 | 37 | 38 | // Mapping of Pin to alternate function for PWM channel 0 39 | const pwm_pin_table_t pwm_pin_chan0[] = 40 | { 41 | { 42 | .pinnum = 12, 43 | .altnum = 0, 44 | }, 45 | { 46 | .pinnum = 18, 47 | .altnum = 5, 48 | }, 49 | { 50 | .pinnum = 40, 51 | .altnum = 0, 52 | }, 53 | }; 54 | 55 | // Mapping of Pin to alternate function for PWM channel 1 56 | const pwm_pin_table_t pwm_pin_chan1[] = 57 | { 58 | { 59 | .pinnum = 13, 60 | .altnum = 0, 61 | }, 62 | { 63 | .pinnum = 19, 64 | .altnum = 5, 65 | }, 66 | { 67 | .pinnum = 41, 68 | .altnum = 0, 69 | }, 70 | { 71 | .pinnum = 45, 72 | .altnum = 0, 73 | }, 74 | }; 75 | 76 | const pwm_pin_tables_t pwm_pin_tables[RPI_PWM_CHANNELS] = 77 | { 78 | { 79 | .pins = pwm_pin_chan0, 80 | .count = sizeof(pwm_pin_chan0) / sizeof(pwm_pin_chan0[0]), 81 | }, 82 | { 83 | .pins = pwm_pin_chan1, 84 | .count = sizeof(pwm_pin_chan1) / sizeof(pwm_pin_chan1[0]), 85 | }, 86 | }; 87 | 88 | 89 | int pwm_pin_alt(int chan, int pinnum) 90 | { 91 | const pwm_pin_tables_t *pintable = &pwm_pin_tables[chan]; 92 | int i; 93 | 94 | for (i = 0; i < pintable->count; i++) 95 | { 96 | if (pintable->pins[i].pinnum == pinnum) 97 | { 98 | return pintable->pins[i].altnum; 99 | } 100 | } 101 | 102 | return -1; 103 | } 104 | 105 | -------------------------------------------------------------------------------- /pwm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pwm.h 3 | * 4 | * Copyright (c) 2014 Jeremy Garff 5 | * 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without modification, are permitted 9 | * provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, this list of 12 | * conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 14 | * of conditions and the following disclaimer in the documentation and/or other materials 15 | * provided with the distribution. 16 | * 3. Neither the name of the owner nor the names of its contributors may be used to endorse 17 | * or promote products derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 24 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | */ 29 | 30 | #ifndef __PWM_H__ 31 | #define __PWM_H__ 32 | 33 | 34 | /* 35 | * 36 | * Pin mappint of alternate pin configuration for PWM 37 | * 38 | * GPIO ALT PWM0 ALT PWM1 39 | * 40 | * 12 0 41 | * 13 0 42 | * 18 5 43 | * 19 5 44 | * 40 0 45 | * 41 0 46 | * 45 0 47 | * 52 1 48 | * 53 1 49 | * 50 | */ 51 | 52 | 53 | #define RPI_PWM_CHANNELS 2 54 | 55 | 56 | typedef struct 57 | { 58 | uint32_t ctl; 59 | #define RPI_PWM_CTL_MSEN2 (1 << 15) 60 | #define RPI_PWM_CTL_USEF2 (1 << 13) 61 | #define RPI_PWM_CTL_POLA2 (1 << 12) 62 | #define RPI_PWM_CTL_SBIT2 (1 << 11) 63 | #define RPI_PWM_CTL_RPTL2 (1 << 10) 64 | #define RPI_PWM_CTL_MODE2 (1 << 9) 65 | #define RPI_PWM_CTL_PWEN2 (1 << 8) 66 | #define RPI_PWM_CTL_MSEN1 (1 << 7) 67 | #define RPI_PWM_CTL_CLRF1 (1 << 6) 68 | #define RPI_PWM_CTL_USEF1 (1 << 5) 69 | #define RPI_PWM_CTL_POLA1 (1 << 4) 70 | #define RPI_PWM_CTL_SBIT1 (1 << 3) 71 | #define RPI_PWM_CTL_RPTL1 (1 << 2) 72 | #define RPI_PWM_CTL_MODE1 (1 << 1) 73 | #define RPI_PWM_CTL_PWEN1 (1 << 0) 74 | uint32_t sta; 75 | #define RPI_PWM_STA_STA4 (1 << 12) 76 | #define RPI_PWM_STA_STA3 (1 << 11) 77 | #define RPI_PWM_STA_STA2 (1 << 10) 78 | #define RPI_PWM_STA_STA1 (1 << 9) 79 | #define RPI_PWM_STA_BERR (1 << 8) 80 | #define RPI_PWM_STA_GAP04 (1 << 7) 81 | #define RPI_PWM_STA_GAP03 (1 << 6) 82 | #define RPI_PWM_STA_GAP02 (1 << 5) 83 | #define RPI_PWM_STA_GAP01 (1 << 4) 84 | #define RPI_PWM_STA_RERR1 (1 << 3) 85 | #define RPI_PWM_STA_WERR1 (1 << 2) 86 | #define RPI_PWM_STA_EMPT1 (1 << 1) 87 | #define RPI_PWM_STA_FULL1 (1 << 0) 88 | uint32_t dmac; 89 | #define RPI_PWM_DMAC_ENAB (1 << 31) 90 | #define RPI_PWM_DMAC_PANIC(val) ((val & 0xff) << 8) 91 | #define RPI_PWM_DMAC_DREQ(val) ((val & 0xff) << 0) 92 | uint32_t resvd_0x0c; 93 | uint32_t rng1; 94 | uint32_t dat1; 95 | uint32_t fif1; 96 | uint32_t resvd_0x1c; 97 | uint32_t rng2; 98 | uint32_t dat2; 99 | } __attribute__((packed, aligned(4))) pwm_t; 100 | 101 | 102 | #define PWM_OFFSET (0x0020c000) 103 | #define PWM_PERIPH_PHYS (0x7e20c000) 104 | 105 | 106 | typedef struct 107 | { 108 | int pinnum; 109 | int altnum; 110 | } pwm_pin_table_t; 111 | 112 | typedef struct 113 | { 114 | const int count; 115 | const pwm_pin_table_t *pins; 116 | } pwm_pin_tables_t; 117 | 118 | 119 | int pwm_pin_alt(int chan, int pinnum); 120 | 121 | 122 | #endif /* __PWM_H__ */ 123 | -------------------------------------------------------------------------------- /readpng.h: -------------------------------------------------------------------------------- 1 | #ifndef READ_PNG_H 2 | #define READ_PNG_H 3 | 4 | #include "png.h" /* libpng header; includes zlib.h */ 5 | #include 6 | /*--------------------------------------------------------------------------- 7 | 8 | rpng - simple PNG display program readpng.h 9 | 10 | --------------------------------------------------------------------------- 11 | 12 | Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. 13 | 14 | This software is provided "as is," without warranty of any kind, 15 | express or implied. In no event shall the author or contributors 16 | be held liable for any damages arising in any way from the use of 17 | this software. 18 | 19 | The contents of this file are DUAL-LICENSED. You may modify and/or 20 | redistribute this software according to the terms of one of the 21 | following two licenses (at your option): 22 | 23 | 24 | LICENSE 1 ("BSD-like with advertising clause"): 25 | 26 | Permission is granted to anyone to use this software for any purpose, 27 | including commercial applications, and to alter it and redistribute 28 | it freely, subject to the following restrictions: 29 | 30 | 1. Redistributions of source code must retain the above copyright 31 | notice, disclaimer, and this list of conditions. 32 | 2. Redistributions in binary form must reproduce the above copyright 33 | notice, disclaimer, and this list of conditions in the documenta- 34 | tion and/or other materials provided with the distribution. 35 | 3. All advertising materials mentioning features or use of this 36 | software must display the following acknowledgment: 37 | 38 | This product includes software developed by Greg Roelofs 39 | and contributors for the book, "PNG: The Definitive Guide," 40 | published by O'Reilly and Associates. 41 | 42 | 43 | LICENSE 2 (GNU GPL v2 or later): 44 | 45 | This program is free software; you can redistribute it and/or modify 46 | it under the terms of the GNU General Public License as published by 47 | the Free Software Foundation; either version 2 of the License, or 48 | (at your option) any later version. 49 | 50 | This program is distributed in the hope that it will be useful, 51 | but WITHOUT ANY WARRANTY; without even the implied warranty of 52 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 53 | GNU General Public License for more details. 54 | 55 | You should have received a copy of the GNU General Public License 56 | along with this program; if not, write to the Free Software Foundation, 57 | Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 58 | 59 | ---------------------------------------------------------------------------*/ 60 | 61 | #ifndef TRUE 62 | # define TRUE 1 63 | # define FALSE 0 64 | #endif 65 | 66 | #ifndef MAX 67 | # define MAX(a,b) ((a) > (b)? (a) : (b)) 68 | # define MIN(a,b) ((a) < (b)? (a) : (b)) 69 | #endif 70 | 71 | #ifdef DEBUG 72 | # define Trace(x) {fprintf x ; fflush(stderr); fflush(stdout);} 73 | #else 74 | # define Trace(x) ; 75 | #endif 76 | 77 | typedef unsigned char uch; 78 | typedef unsigned short ush; 79 | typedef unsigned long ulg; 80 | 81 | typedef struct { 82 | png_uint_32 width; 83 | png_uint_32 height; 84 | int bit_depth; 85 | int color_type; 86 | bool has_background; 87 | uch background_red; 88 | uch background_green; 89 | uch background_blue; 90 | int channels; 91 | ulg rowbytes; 92 | png_structp png_ptr; 93 | png_infop info_ptr; 94 | uch *image_data; 95 | } png_object; 96 | 97 | /* prototypes for public functions in readpng.c */ 98 | 99 | void readpng_version_info(void); 100 | 101 | //initializes a new png object structure contains all info needed to read png image 102 | int readpng_init(FILE *infile, png_object * png); 103 | 104 | //int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight); 105 | 106 | //int readpng_get_bgcolor(uch *bg_red, uch *bg_green, uch *bg_blue); 107 | 108 | uch *readpng_get_image(png_object * png, double display_exponent); 109 | 110 | void readpng_cleanup(png_object * png); 111 | #endif -------------------------------------------------------------------------------- /rpihw.h: -------------------------------------------------------------------------------- 1 | /* 2 | * rpihw.h 3 | * 4 | * Copyright (c) 2014 Jeremy Garff 5 | * 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without modification, are permitted 9 | * provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, this list of 12 | * conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list 14 | * of conditions and the following disclaimer in the documentation and/or other materials 15 | * provided with the distribution. 16 | * 3. Neither the name of the owner nor the names of its contributors may be used to endorse 17 | * or promote products derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 24 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | */ 29 | 30 | 31 | #ifndef __RPIHW_H__ 32 | #define __RPIHW_H__ 33 | 34 | #include 35 | 36 | typedef struct { 37 | uint32_t type; 38 | #define RPI_HWVER_TYPE_UNKNOWN 0 39 | #define RPI_HWVER_TYPE_PI1 1 40 | #define RPI_HWVER_TYPE_PI2 2 41 | #define RPI_HWVER_TYPE_PI4 3 42 | uint32_t hwver; 43 | uint32_t periph_base; 44 | uint32_t videocore_base; 45 | char* desc; 46 | } rpi_hw_t; 47 | 48 | 49 | const rpi_hw_t* rpi_hw_detect(void); 50 | 51 | 52 | #endif /* __RPIHW_H__ */ -------------------------------------------------------------------------------- /sk9822.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __SK9822_H__ 3 | #define __SK9822_H__ 4 | 5 | #define RPI_MAX_SPI_DEVICE 16 6 | #define SK9822_MAX_CHANNELS RPI_MAX_SPI_DEVICE 7 | 8 | //https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #include 15 | #include 16 | #include "ws2811.h" 17 | 18 | // 3 color R, G and B ordering 19 | #define SK9822_STRIP_RGB 0x00100800 20 | #define SK9822_STRIP_RBG 0x00100008 21 | #define SK9822_STRIP_GRB 0x00081000 22 | #define SK9822_STRIP_GBR 0x00080010 23 | #define SK9822_STRIP_BRG 0x00001008 24 | #define SK9822_STRIP_BGR 0x00000810 25 | 26 | // predefined fixed LED types 27 | #define SK9822_STRIP SK9822_STRIP_BGR 28 | 29 | #define SK9822_RETURN_STATES(X) \ 30 | X(0, SK9822_SUCCESS, "Success"), \ 31 | X(-1, SK9822_ERROR_GENERIC, "Generic failure"), \ 32 | X(-2, SK9822_ERROR_OUT_OF_MEMORY, "Out of memory"), \ 33 | X(-11, SK9822_ERROR_ILLEGAL_GPIO, "Selected GPIO not possible"), \ 34 | X(-13, SK9822_ERROR_SPI_SETUP, "Unable to initialize SPI"), \ 35 | X(-14, SK9822_ERROR_SPI_TRANSFER, "SPI transfer error"), \ 36 | X(-15, SK9822_ERROR_HW_NOT_SUPPORTED, "Hardware version not supported"), \ 37 | X(-16, SK9822_ERROR_SPI_GPIO, "Cannot use wanted SPI GPIO pin") 38 | 39 | #define SK9822_RETURN_STATES_ENUM(state, name, str) name = state 40 | #define SK9822_RETURN_STATES_STRING(state, name, str) str 41 | 42 | #define SK9822_DEFAULT_SPI_GPIO -1 43 | #define SK9822_DEFAULT_SPI_SPEED 20000000 //20MHz clock speed 44 | 45 | typedef enum { 46 | SK9822_RETURN_STATES(SK9822_RETURN_STATES_ENUM), 47 | 48 | SK9822_RETURN_STATE_COUNT 49 | } sk9822_return_t; 50 | 51 | 52 | /*typedef struct 53 | { 54 | uint32_t color; 55 | uint32_t brightness; 56 | } sk9822_led_t;*/ 57 | 58 | #define sk9822_led_t ws2811_led_t 59 | 60 | typedef struct 61 | { 62 | int color_size; //3 = RGB, 4 = RGBW 63 | int gpionum; //alt GPIO configuration, DEFAULT_SPI_GPIO for default 64 | int invert; //< Invert output signal 65 | int count; //< Number of LEDs, 0 if channel is unused 66 | int strip_type; //< Strip color layout 67 | sk9822_led_t* leds; //< LED buffers, allocated by driver based on count 68 | uint8_t brightness; //< Brightness value between 0 and 255 69 | uint8_t wshift; //< White shift value 70 | uint8_t rshift; //< Red shift value 71 | uint8_t gshift; //< Green shift value 72 | uint8_t bshift; //< Blue shift value 73 | uint8_t* gamma; //< Gamma correction table 74 | int spi_fd; //SPI file 75 | uint32_t spi_speed; //SPI clock speed 76 | char spi_dev[PATH_MAX]; //SPI device file name 77 | uint8_t* raw; //raw SPI data 78 | int raw_size; //num bytes in raw buffer 79 | void* gpio; //pointer to GPIO pin if not default 80 | }sk9822_channel_t; 81 | 82 | typedef struct 83 | { 84 | sk9822_channel_t channels[RPI_MAX_SPI_DEVICE]; 85 | } sk9822_t; 86 | 87 | void create_sk9822(sk9822_t* sk9822); 88 | sk9822_return_t sk9822_init(sk9822_t* sk9822); 89 | void sk9822_fini(sk9822_t* sk9822); 90 | sk9822_return_t sk9822_render_channel(sk9822_channel_t* channel); 91 | sk9822_return_t sk9822_render(sk9822_t* ws2811); 92 | const char* sk9822_get_return_t_str(const sk9822_return_t state); 93 | 94 | #ifdef __cplusplus 95 | } 96 | #endif 97 | 98 | #endif -------------------------------------------------------------------------------- /sockets.c: -------------------------------------------------------------------------------- 1 | #include "sockets.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | //return true if socket is still connected 12 | bool socket_connected(socket_t socket_fd){ 13 | int error = 0; 14 | socklen_t len = sizeof (error); 15 | int retval = getsockopt (socket_fd, SOL_SOCKET, SO_ERROR, &error, &len); 16 | if (retval != 0) { 17 | fprintf(stderr, "Error getting socket error code: %s\n", strerror(retval)); 18 | } 19 | if (error != 0) { 20 | fprintf(stderr, "Socket error: %s\n", strerror(error)); 21 | } 22 | return retval == 0 && error == 0; 23 | } 24 | 25 | //waits until the buffer is total received wanted_size 26 | //returns > 0: number of bytes received 27 | //returns < 0: connection closed 28 | int receive_complete_buffer(socket_t socket, void * buffer, unsigned int wanted_size){ 29 | int received = 1; //start 30 | int total_received=0; 31 | while (wanted_size>total_received && received > 0){ 32 | received = read(socket, buffer, wanted_size); 33 | if (received > 0){ 34 | total_received+=received; 35 | buffer +=received; 36 | } 37 | } 38 | if (received <= 0) return received; 39 | return total_received; 40 | } 41 | 42 | //sends a complete buffer over the socket 43 | //returns total bytes transferred or < 0 on error 44 | int send_complete_buffer(socket_t socket, void * buffer, unsigned int size, int flags){ 45 | int sent = 0; 46 | int total_sent = 0; 47 | 48 | while (size > 0){ 49 | sent = send(socket, buffer, size >= 2048 ? 2048 : size, flags); 50 | if (sent < 0) return sent; //error 51 | buffer +=sent; 52 | size -= sent; 53 | total_sent +=sent; 54 | } 55 | 56 | return total_sent; 57 | 58 | } 59 | 60 | //converts IP or hostname to binary in_addr structure 61 | int hostname_to_ip(char * hostname , struct in_addr * addr) { 62 | struct hostent *he; 63 | struct in_addr **addr_list; 64 | int i; 65 | 66 | if ( (he = gethostbyname( hostname ) ) == NULL){ // get the host info 67 | return 1; 68 | } 69 | 70 | addr_list = (struct in_addr **) he->h_addr_list; 71 | 72 | for(i = 0; addr_list[i] != NULL; i++) { 73 | memcpy(addr, addr_list[i], sizeof(struct in_addr));//Return the first one; 74 | return 0; 75 | } 76 | 77 | return 1; 78 | } 79 | 80 | int bytes_available(socket_t socket_fd){ 81 | int count; 82 | ioctl(socket_fd, FIONREAD, &count); 83 | return count; 84 | } 85 | 86 | -------------------------------------------------------------------------------- /sockets.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKETS_HELPER_H 2 | #define SOCKETS_HELPER_H 3 | 4 | #include 5 | #include 6 | typedef int socket_t; 7 | 8 | bool socket_connected(socket_t socket_fd); 9 | int send_complete_buffer(socket_t socket, void * buffer, unsigned int size, int flags); 10 | int receive_complete_buffer(socket_t socket, void * buffer, unsigned int wanted_size); 11 | int hostname_to_ip(char * hostname , struct in_addr * addr); 12 | int bytes_available(socket_t socket_fd); 13 | 14 | #endif -------------------------------------------------------------------------------- /spi.cpp: -------------------------------------------------------------------------------- 1 | #include "spi.h" 2 | #include 3 | #include //Needed for SPI port 4 | #include //Needed for SPI port 5 | #include 6 | //http://elinux.org/RPi_SPI 7 | //----- SET SPI MODE ----- 8 | //SPI_MODE_0 (0,0) CPOL = 0, CPHA = 0, Clock idle low, data is clocked in on rising edge, output data (change) on falling edge 9 | //SPI_MODE_1 (0,1) CPOL = 0, CPHA = 1, Clock idle low, data is clocked in on falling edge, output data (change) on rising edge 10 | //SPI_MODE_2 (1,0) CPOL = 1, CPHA = 0, Clock idle high, data is clocked in on falling edge, output data (change) on rising edge 11 | //SPI_MODE_3 (1,1) CPOL = 1, CPHA = 1, Clock idle high, data is clocked in on rising, edge output data (change) on falling edge 12 | 13 | spi_device_handle spi_open_device (const char * spi_device, unsigned char spi_bitsPerWord, int spi_speed, unsigned char spi_mode){ 14 | spi_device_handle dev; 15 | int status_value; 16 | 17 | dev = open(spi_device, O_RDWR); 18 | if (dev < 0) return 0; 19 | 20 | status_value = ioctl((int)dev, SPI_IOC_WR_MODE, &spi_mode); 21 | if(status_value < 0) return 0; 22 | 23 | status_value = ioctl((int)dev, SPI_IOC_RD_MODE, &spi_mode); 24 | if(status_value < 0) return 0; 25 | 26 | status_value = ioctl((int)dev, SPI_IOC_WR_BITS_PER_WORD, &spi_bitsPerWord); 27 | if(status_value < 0) return 0; 28 | 29 | status_value = ioctl((int)dev, SPI_IOC_RD_BITS_PER_WORD, &spi_bitsPerWord); 30 | if(status_value < 0)return 0; 31 | 32 | status_value = ioctl((int)dev, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed); 33 | if(status_value < 0) return 0; 34 | 35 | status_value = ioctl((int)dev, SPI_IOC_RD_MAX_SPEED_HZ, &spi_speed); 36 | if(status_value < 0) return 0; 37 | 38 | return dev; 39 | } 40 | 41 | 42 | int spi_write_and_read (spi_device_handle spi_device, unsigned char * data_out, unsigned char * data_in, int length){ 43 | struct spi_ioc_transfer spi; 44 | 45 | memset(&spi, 0, sizeof(spi)); 46 | 47 | spi.tx_buf = (unsigned long)(data_out); // transmit from "data" 48 | spi.rx_buf = (unsigned long)(data_in) ; // receive into "data" 49 | spi.len = length; 50 | 51 | return ioctl((int) spi_device, SPI_IOC_MESSAGE(1), &spi) ; //1 SPI operation 52 | } 53 | 54 | 55 | int spi_write_and_read_delayed (spi_device_handle spi_device, unsigned char * data_out, unsigned char * data_in, int length, int delay){ 56 | struct spi_ioc_transfer spi[length]; 57 | 58 | memset(&spi, 0, sizeof(spi)); 59 | 60 | //one spi transfer for each byte 61 | for (int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | int main() { 14 | Display* disp; 15 | Window root; 16 | cairo_surface_t* src_surface; 17 | int scr; 18 | 19 | unsigned char* data; 20 | int width = 1024; 21 | int height = 768; 22 | 23 | int stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, width); 24 | 25 | data = (unsigned char*)malloc(stride * height * sizeof(unsigned char)); 26 | 27 | cairo_surface_t * dst_surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_RGB24, width, height, stride); 28 | 29 | cairo_t * cr = cairo_create(dst_surface); 30 | 31 | int src_y = 16; 32 | int src_x = 32; 33 | 34 | int src_width = 200; 35 | int src_height = 200; 36 | 37 | int dst_x = 200; 38 | int dst_y = 250; 39 | 40 | int dst_width = src_width / 2; 41 | int dst_height = src_height / 2; 42 | 43 | /* try to connect to display, exit if it's NULL */ 44 | disp = XOpenDisplay(":0"); 45 | if (disp == NULL) { 46 | fprintf(stderr, "Given display cannot be found %s\n", ":0"); 47 | return -1; 48 | } 49 | 50 | scr = DefaultScreen(disp); 51 | root = DefaultRootWindow(disp); 52 | 53 | src_surface = cairo_xlib_surface_create(disp, root, DefaultVisual(disp, scr), DisplayWidth(disp, scr), DisplayHeight(disp, scr)); 54 | 55 | float xScale = (float)dst_width / (float)src_width; 56 | float yScale = (float)dst_height / (float)src_height; 57 | 58 | cairo_save(cr); 59 | cairo_scale(cr, xScale, yScale); 60 | cairo_set_source_surface(cr, src_surface, (dst_x / xScale - src_x) , (dst_y / yScale- src_y) );// 61 | 62 | cairo_rectangle(cr, dst_x / xScale, dst_y / yScale, dst_width / xScale, dst_height / yScale); 63 | cairo_fill(cr); 64 | cairo_restore(cr); 65 | 66 | cairo_surface_destroy(src_surface); 67 | 68 | cairo_surface_write_to_png(dst_surface, "test.png"); 69 | 70 | return 0; 71 | } -------------------------------------------------------------------------------- /ws2812svr.conf: -------------------------------------------------------------------------------- 1 | #mode must be first setting in file! 2 | mode=tcp 3 | port=9999 4 | file=/home/pi/test.txt 5 | pipe=/dev/leds 6 | init= 7 | allow_system_cmd=0 -------------------------------------------------------------------------------- /ws2812svr.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=WS2812 Server 3 | After=network.target 4 | 5 | [Service] 6 | # Change this to match your install directory 7 | # Send stdout and stderr to /dev/null because RAM might overflow otherwise 8 | ExecStart=/usr/local/bin/ws2812svr -c /etc/ws2812svr.conf > /dev/null 2&>1 9 | Restart=on-failure 10 | User=root 11 | 12 | [Install] 13 | WantedBy=multi-user.target --------------------------------------------------------------------------------