blinkenstrip

Documentation: http://frombelow.net/projects/blinkenstrip/
Clone: git clone https://git.frombelow.net/blinkenstrip.git
Log | Files | Refs | README | LICENSE

led.c (18077B)


      1 /* 
      2   Function unicolor_rainbow based on
      3   <https://www.esp32.com/viewtopic.php?t=589#> ((c) Lucas Bruder
      4   <LBruder@me.com> 2016)
      5 
      6   Everything else copyright © 2021 Gerd Beuster <gerd@frombelow.net>
      7 
      8   Licensed under the Apache License, Version 2.0 (the "License");
      9   you may not use this file except in compliance with the License.
     10   You may obtain a copy of the License at
     11 
     12       http://www.apache.org/licenses/LICENSE-2.0
     13 
     14   Unless required by applicable law or agreed to in writing, software
     15   distributed under the License is distributed on an "AS IS" BASIS,
     16   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17   See the License for the specific language governing permissions and
     18   limitations under the License.
     19 */
     20 
     21 /* {{{ Includes and definitions */
     22 
     23 #include "led.h"
     24 #include "debug.h"
     25 #include "freertos/task.h"
     26 #include "nvs_flash.h"
     27 #include "math.h"
     28 
     29 /* }}} */
     30 
     31 void store_state_if_changed() {
     32   if(blinkenstrip_state_has_changed) {
     33     nvs_handle flash_handle;
     34     nvs_open("blinkenstrip", NVS_READWRITE, &flash_handle);
     35     nvs_set_u8(flash_handle, "blinkenstrip_state", blinkenstrip_state);
     36     nvs_set_u8(flash_handle, "led_col_red", led_color_rgb.red);
     37     nvs_set_u8(flash_handle, "led_col_green", led_color_rgb.green);
     38     nvs_set_u8(flash_handle, "led_col_blue", led_color_rgb.blue);
     39     nvs_commit(flash_handle);
     40     nvs_close(flash_handle);
     41     DEBUG_MSG(DEBUG, ("Wrote new state (%d / (%d, %d, %d)) to flash.\n",
     42                       blinkenstrip_state, led_color_rgb.red, led_color_rgb.green, led_color_rgb.blue));
     43   }
     44 }
     45 
     46 /* {{{ Unicolor patterns */
     47 
     48 void unicolor(struct led_color_t led_color){
     49   store_state_if_changed();
     50   for (uint32_t index = 0; index < led_strip_length; index++) {
     51     led_strip_set_pixel_color(&led_strip, index, &led_color);
     52   }
     53   led_strip_show(&led_strip);
     54   blinkenstrip_state_has_changed = false;
     55 }
     56 
     57 const uint8_t lights[360]={
     58   0,   0,   0,   0,   0,   1,   1,   2,
     59   2,   3,   4,   5,   6,   7,   8,   9,
     60   11,  12,  13,  15,  17,  18,  20,  22,
     61   24,  26,  28,  30,  32,  35,  37,  39,
     62   42,  44,  47,  49,  52,  55,  58,  60,
     63   63,  66,  69,  72,  75,  78,  81,  85,
     64   88,  91,  94,  97, 101, 104, 107, 111,
     65   114, 117, 121, 124, 127, 131, 134, 137,
     66   141, 144, 147, 150, 154, 157, 160, 163,
     67   167, 170, 173, 176, 179, 182, 185, 188,
     68   191, 194, 197, 200, 202, 205, 208, 210,
     69   213, 215, 217, 220, 222, 224, 226, 229,
     70   231, 232, 234, 236, 238, 239, 241, 242,
     71   244, 245, 246, 248, 249, 250, 251, 251,
     72   252, 253, 253, 254, 254, 255, 255, 255,
     73   255, 255, 255, 255, 254, 254, 253, 253,
     74   252, 251, 251, 250, 249, 248, 246, 245,
     75   244, 242, 241, 239, 238, 236, 234, 232,
     76   231, 229, 226, 224, 222, 220, 217, 215,
     77   213, 210, 208, 205, 202, 200, 197, 194,
     78   191, 188, 185, 182, 179, 176, 173, 170,
     79   167, 163, 160, 157, 154, 150, 147, 144,
     80   141, 137, 134, 131, 127, 124, 121, 117,
     81   114, 111, 107, 104, 101,  97,  94,  91,
     82   88,  85,  81,  78,  75,  72,  69,  66,
     83   63,  60,  58,  55,  52,  49,  47,  44,
     84   42,  39,  37,  35,  32,  30,  28,  26,
     85   24,  22,  20,  18,  17,  15,  13,  12,
     86   11,   9,   8,   7,   6,   5,   4,   3,
     87   2,   2,   1,   1,   0,   0,   0,   0,
     88   0,   0,   0,   0,   0,   0,   0,   0,
     89   0,   0,   0,   0,   0,   0,   0,   0,
     90   0,   0,   0,   0,   0,   0,   0,   0,
     91   0,   0,   0,   0,   0,   0,   0,   0,
     92   0,   0,   0,   0,   0,   0,   0,   0,
     93   0,   0,   0,   0,   0,   0,   0,   0,
     94   0,   0,   0,   0,   0,   0,   0,   0,
     95   0,   0,   0,   0,   0,   0,   0,   0,
     96   0,   0,   0,   0,   0,   0,   0,   0,
     97   0,   0,   0,   0,   0,   0,   0,   0,
     98   0,   0,   0,   0,   0,   0,   0,   0,
     99   0,   0,   0,   0,   0,   0,   0,   0,
    100   0,   0,   0,   0,   0,   0,   0,   0,
    101   0,   0,   0,   0,   0,   0,   0,   0,
    102   0,   0,   0,   0,   0,   0,   0,   0};
    103 
    104 void unicolor_rainbow(){
    105 
    106   static int rgb_red=0;
    107   static int rgb_green=120;
    108   static int rgb_blue=240;
    109 
    110   static struct led_color_t led_color = {
    111     .red = 5,
    112     .green = 0,
    113     .blue = 0,
    114   };
    115 
    116   store_state_if_changed();
    117   for (uint32_t index = 0; index < led_strip_length; index++) {
    118     led_strip_set_pixel_color(&led_strip, index, &led_color);
    119   }
    120   led_strip_show(&led_strip);
    121 
    122   led_color.red   = lights[rgb_red] * max_brightness / 0xFF;
    123   led_color.green = lights[rgb_green] * max_brightness / 0xFF;
    124   led_color.blue  = lights[rgb_blue] * max_brightness / 0xFF;
    125 
    126   rgb_red += 1;
    127   rgb_green += 1;
    128   rgb_blue += 1;
    129 
    130   if (rgb_red >= 360) rgb_red=0;
    131   if (rgb_green >= 360) rgb_green=0;
    132   if (rgb_blue >= 360) rgb_blue=0;
    133 
    134   blinkenstrip_state_has_changed = false;
    135 }
    136 
    137 /* }}} */
    138 
    139 /* {{{ Random on/off */
    140 
    141 uint32_t get_random_number(uint32_t n){
    142   uint32_t r;
    143   do{
    144     r = esp_random();
    145   } while(r > (RAND_MAX - (RAND_MAX % n)));
    146   return(r % n);
    147 }
    148 
    149 void random_on_off(){
    150   if(blinkenstrip_state_has_changed){
    151     // Initalize state
    152     for (uint32_t index = 0; index < led_strip_length; index++) {
    153       led_strip_set_pixel_color(&led_strip, index,
    154                                 (struct led_color_t *) &led_color_blue);
    155     }
    156     store_state_if_changed();
    157     blinkenstrip_state_has_changed = false;
    158   }
    159   else{
    160     // Update state
    161     // Copy over "old" strip
    162     struct led_color_t c;
    163     for (uint32_t index = 0; index < led_strip_length; index++) {
    164       led_strip_get_pixel_color(&led_strip, index, &c);
    165       led_strip_set_pixel_color(&led_strip, index, &c);
    166     }
    167     // Randomly switch an LED to green or blue.
    168     uint32_t switch_led = get_random_number(led_strip_length);
    169     if (get_random_number(2)){
    170       led_strip_set_pixel_color(&led_strip, switch_led,
    171                                 (struct led_color_t *) &led_color_blue);
    172     }
    173     else{
    174       led_strip_set_pixel_color(&led_strip, switch_led,
    175                                 (struct led_color_t *) &led_color_green);
    176     }
    177   }
    178   led_strip_show(&led_strip);
    179 }
    180 
    181 /* }}} */
    182 
    183 /* {{{ Running dot */
    184 
    185 void running_dot(){
    186   static uint32_t position = 0;
    187   store_state_if_changed();
    188   blinkenstrip_state_has_changed = false;
    189   for (uint32_t index = 0; index < led_strip_length; index++) {
    190     led_strip_set_pixel_color(&led_strip, index,
    191                               (struct led_color_t *) &led_color_blue);
    192   }
    193   led_strip_set_pixel_color(&led_strip, position,
    194                             (struct led_color_t *) &led_color_red);
    195   position = (position + 1) % led_strip_length;
    196   blinkenstrip_state_has_changed = false;
    197   led_strip_show(&led_strip);
    198 };
    199 
    200 /* }}} */
    201 
    202 /* {{{ Cellular Automaton */
    203 
    204 int32_t xy2i(int32_t x, int32_t y) {
    205   int32_t i = y * led_strip_w;
    206   if ((y % 2) && snake) {
    207     i += led_strip_w - x - 1;
    208   }
    209   else {
    210     i += x;
    211   }
    212   return(i);
    213 }
    214 
    215 
    216 bool cell_is_on(struct led_strip_t led_strip, int32_t x, int32_t y){
    217   static struct led_color_t c;
    218   x = (x + led_strip_w) % led_strip_w;
    219   y = (y + led_strip_h) % led_strip_h;
    220   led_strip_get_pixel_color(&led_strip, xy2i(x, y),
    221                             &c);
    222   return((c.red == cell_on.red) &&
    223          (c.green == cell_on.green) &&
    224          (c.blue == cell_on.blue));
    225 };
    226 
    227 void cellular_automaton(){
    228   static uint8_t number_of_updates = 0;
    229   static bool stable_pattern = false;
    230   // Since we get a stable pattern after sometime, we restart with a
    231   // new random cellular automaton after a fixed number of steps or
    232   // when we detect a stable situation.
    233   store_state_if_changed();
    234   if(blinkenstrip_state_has_changed || stable_pattern ||
    235      (number_of_updates == 100)) {
    236     // Initialize with random values
    237     for (uint32_t index = 0; index < led_strip_length; index++) {
    238       if (get_random_number(2)){
    239         led_strip_set_pixel_color(&led_strip, index,
    240                                   (struct led_color_t *) &cell_on);
    241       }
    242       else{
    243         led_strip_set_pixel_color(&led_strip, index,
    244                                   (struct led_color_t *) &cell_off);
    245       }
    246     }
    247     led_strip_show(&led_strip);
    248     number_of_updates = 0;
    249     blinkenstrip_state_has_changed = false;
    250     stable_pattern = false;
    251   }
    252   // Update automaton
    253   if((!stable_pattern) && (number_of_updates++ < 100)){
    254     // Cycle over all cells
    255     for (int32_t y = 0; y < led_strip_h; y++){
    256       for (int32_t x = 0; x < led_strip_w; x++){
    257         // Count neighbors
    258         uint8_t neighbors = 0;
    259         for (int32_t y_neighbor = 0; y_neighbor < 3; y_neighbor++){
    260           for (int32_t x_neighbor = 0; x_neighbor < 3; x_neighbor++){
    261             if (((x_neighbor != 1) || (y_neighbor != 1)) &&
    262                 (cell_is_on(led_strip, x-x_neighbor+1, y-y_neighbor+1))){
    263               neighbors++;
    264             }
    265           }
    266         }
    267         // Update cell
    268         uint32_t index = xy2i(x, y);
    269         if (neighbors < 2) {
    270           led_strip_set_pixel_color(&led_strip, index,
    271                                     (struct led_color_t *) &cell_off);
    272         }
    273         else if (neighbors > 3) {
    274           led_strip_set_pixel_color(&led_strip, index,
    275                                     (struct led_color_t *) &cell_off);
    276         }
    277         else if  (neighbors == 3) {
    278           led_strip_set_pixel_color(&led_strip, index,
    279                                     (struct led_color_t *) &cell_on);
    280         }
    281         else {
    282           struct led_color_t c;
    283           led_strip_get_pixel_color(&led_strip, index, &c);
    284           led_strip_set_pixel_color(&led_strip, index, &c);
    285         }
    286       }
    287     }
    288     // Check if pattern has changed since last update.
    289     // (We will exit the loop if the pattern becomes stable)
    290     stable_pattern = true;
    291     for(uint32_t i = 0; (i < led_strip_length) && stable_pattern; i++){
    292       stable_pattern = 
    293         (led_strip.led_strip_buf_1[i].red ==
    294          led_strip.led_strip_buf_2[i].red) &&
    295         (led_strip.led_strip_buf_1[i].green ==
    296          led_strip.led_strip_buf_2[i].green) &&
    297         (led_strip.led_strip_buf_1[i].blue ==
    298          led_strip.led_strip_buf_2[i].blue);
    299     }
    300     led_strip_show(&led_strip);
    301     vTaskDelay(600 / portTICK_PERIOD_MS);
    302   }
    303 }
    304 
    305 /* }}} */
    306 
    307 /* {{{ Line-by-line switch */
    308 
    309 void set_row_color(struct led_color_t led_color, uint32_t row) {
    310   for (uint32_t index = 0; index < led_strip_w; index++) {
    311     led_strip_set_pixel_color(&led_strip, xy2i(index, row),
    312                               &led_color);
    313   }
    314 }
    315 
    316 void set_column_color(struct led_color_t led_color, uint32_t column) {
    317   for (uint32_t index = 0; index < led_strip_h; index++) {
    318     led_strip_set_pixel_color(&led_strip, xy2i(column, index),
    319                               &led_color);
    320   }
    321 }
    322 
    323 void line_by_line() {
    324   static bool change_row = true; // Switch in rows or in columns?
    325   static void (*switch_command)(struct led_color_t led_color, uint32_t row);
    326   const uint8_t color_cycle[] = {
    327     max_brightness, max_brightness, 0 // Yellow
    328     , 0, max_brightness, max_brightness // Turquoise
    329     , 0, 0, max_brightness // Blue
    330   };
    331   const uint8_t color_cycle_length = sizeof(color_cycle);
    332 
    333   static uint8_t pos_in_color_cycle = 0;
    334   static uint32_t switch_line = 0;
    335   static struct led_color_t old_color;
    336   static struct led_color_t new_color;
    337   store_state_if_changed();
    338   if (switch_line == 0) {
    339     old_color.red = color_cycle[pos_in_color_cycle];
    340     old_color.green = color_cycle[pos_in_color_cycle+1];
    341     old_color.blue = color_cycle[pos_in_color_cycle+2];
    342     pos_in_color_cycle = (pos_in_color_cycle + 3) % color_cycle_length;
    343     new_color.red = color_cycle[pos_in_color_cycle];
    344     new_color.green = color_cycle[pos_in_color_cycle+1];
    345     new_color.blue = color_cycle[pos_in_color_cycle+2];
    346     change_row = !change_row;
    347     if(change_row){
    348       switch_command = set_row_color;
    349     }
    350     else{
    351       switch_command = set_column_color;
    352     }
    353   }
    354   for (uint8_t row = 0; row < led_strip_h; row++) {
    355     if (row > switch_line) {
    356       (*switch_command)(old_color, row);
    357     }
    358     else if  (row == switch_line) {
    359       (*switch_command)(led_color_red, row);
    360     }
    361     else {
    362       (*switch_command)(new_color, row);
    363     }
    364   }
    365   switch_line = (switch_line + 1) % led_strip_h;
    366   led_strip_show(&led_strip);
    367   blinkenstrip_state_has_changed = false;
    368 }
    369 
    370 /* }}} */
    371 
    372 /* {{{ Worm */
    373 
    374 // Positions and running directions of worms (allocated in main_led_task)
    375 int8_t *worm_direction;
    376 uint16_t *worm_pos;
    377 
    378 void worm() {
    379   // Percentage of max_brightness relative to full brightness
    380   float mb_perc = ((float) max_brightness) / 0xFF;
    381   /* const float mb_perc = 1; */
    382   struct led_color_t scanner_pattern[] =
    383     {{round(0x00*mb_perc), round(0x00*mb_perc), round(0x00*mb_perc)},
    384      {round(0x00*mb_perc), round(0x20*mb_perc), round(0x00*mb_perc)},
    385      {round(0x20*mb_perc), round(0x20*mb_perc), round(0x00*mb_perc)},
    386      {round(0xFF*mb_perc), round(0x00*mb_perc), round(0x00*mb_perc)},
    387      {round(0xFF*mb_perc), round(0x00*mb_perc), round(0x00*mb_perc)},
    388      {round(0xFF*mb_perc), round(0x00*mb_perc), round(0x00*mb_perc)},
    389      {round(0xFF*mb_perc), round(0x00*mb_perc), round(0x00*mb_perc)},
    390      {round(0xFF*mb_perc), round(0x00*mb_perc), round(0x00*mb_perc)},
    391      {round(0x20*mb_perc), round(0x20*mb_perc), round(0x00*mb_perc)},
    392      {round(0x00*mb_perc), round(0x20*mb_perc), round(0x00*mb_perc)},
    393      {round(0x00*mb_perc), round(0x00*mb_perc), round(0x00*mb_perc)}};
    394   const uint8_t scanner_pattern_length =  (sizeof(scanner_pattern) /
    395                                            sizeof(struct led_color_t));
    396   store_state_if_changed();
    397   if(blinkenstrip_state_has_changed){
    398     // Initalize state
    399     for (uint32_t index = 0; index < led_strip_length; index++) {
    400       led_strip_set_pixel_color(&led_strip, index,
    401                                 (struct led_color_t *) &led_color_black);
    402     }
    403     for (uint8_t w = 0; w < number_of_worms; w++) {
    404       worm_direction[w] = get_random_number(2)*2-1;
    405       worm_pos[w] = get_random_number(led_strip_length-scanner_pattern_length);
    406     }
    407     blinkenstrip_state_has_changed = false;
    408   }
    409   else{
    410     // Update state
    411     // Copy over "old" strip
    412     struct led_color_t c;
    413     for (uint32_t index = 0; index < led_strip_length; index++) {
    414       led_strip_get_pixel_color(&led_strip, index, &c);
    415       led_strip_set_pixel_color(&led_strip, index, &c);
    416     }
    417     // Worms
    418     for (uint8_t w = 0; w < number_of_worms; w++) {
    419       for (uint8_t i = 0; i < scanner_pattern_length; i++) {
    420         led_strip_set_pixel_color(&led_strip,
    421                                   (worm_pos[w]+i) % led_strip_length,
    422                                   &scanner_pattern[i]);
    423       }
    424       if (!get_random_number(50)) {
    425         worm_direction[w] *= -1;
    426       }
    427       if (!wrap_around) {
    428         // Switch direction if we hit the end of the strip
    429         if (worm_pos[w] == 0){
    430           worm_direction[w] = 1;
    431         }
    432         if ((worm_pos[w] + scanner_pattern_length) == led_strip_length) {
    433           worm_direction[w] = -1;
    434         }
    435       }
    436       worm_pos[w] = (worm_pos[w] + worm_direction[w]) % led_strip_length;
    437     };
    438     // Randomly switch an LED to blue
    439     uint32_t switch_led = get_random_number(led_strip_length);
    440     if (!get_random_number(4)){
    441       led_strip_set_pixel_color(&led_strip, switch_led,
    442                                 (struct led_color_t *) &led_color_blue);
    443     }
    444   }
    445   led_strip_show(&led_strip);
    446 }
    447 
    448 /* }}} */
    449 
    450 void experiment() {
    451   /* empty */
    452 }
    453 
    454 /* {{{ main */
    455 
    456 void led_controller(void *args) {
    457 
    458   // Define standard colors
    459   led_color_red.red = max_brightness;
    460   led_color_red.green = 0x00;
    461   led_color_red.blue = 0x00;
    462   led_color_green.red = 0x00;
    463   led_color_green.green = max_brightness;
    464   led_color_green.blue = 0x00;
    465   led_color_blue.red = 0x00;
    466   led_color_blue.green = 0x00;
    467   led_color_blue.blue = max_brightness;
    468   led_color_yellow.red = max_brightness;
    469   led_color_yellow.green = max_brightness;
    470   led_color_yellow.blue = 0x00;
    471   led_color_white.red = max_brightness;
    472   led_color_white.green = max_brightness;
    473   led_color_white.blue = max_brightness;
    474   led_color_black.red = 0x00;
    475   led_color_black.green = 0x00;
    476   led_color_black.blue = 0x00;
    477 
    478   // Define colors for cellular automaton
    479   cell_on.red = 0x00;
    480   cell_on.green = max_brightness;
    481   cell_on.blue = 0x00;
    482   cell_off.red = 0x00;
    483   cell_off.green = 0x00;
    484   cell_off.blue = max_brightness / 2;
    485 
    486   // Initialize data structures for worm
    487   worm_direction = calloc(number_of_worms, sizeof(int8_t)); // Yes, size is 1 byte ...
    488   worm_pos = calloc(number_of_worms, sizeof(uint16_t)); // Yes, size is 2 bytes ...
    489 
    490   // Initialize data structures for LED strip
    491   led_strip_length = led_strip_w * led_strip_h;
    492   led_strip_buf_1 = malloc(led_strip_length * sizeof(struct led_color_t));
    493   led_strip_buf_2 = malloc(led_strip_length * sizeof(struct led_color_t));
    494   led_strip.rgb_led_type = RGB_LED_TYPE_WS2812;
    495   led_strip.rmt_channel = RMT_CHANNEL_1;
    496   led_strip.rmt_interrupt_num = LED_STRIP_RMT_INTR_NUM;
    497   led_strip.gpio = CONFIG_WS2811_DATA_PIN;
    498   led_strip.led_strip_buf_1 = led_strip_buf_1;
    499   led_strip.led_strip_buf_2 = led_strip_buf_2;
    500   led_strip.led_strip_length = led_strip_length;
    501 
    502   blinkenstrip_state_changed_semaphore = xSemaphoreCreateBinary();
    503   xSemaphoreGive(blinkenstrip_state_changed_semaphore);
    504   assert(blinkenstrip_state_changed_semaphore);
    505   led_strip.access_semaphore = xSemaphoreCreateBinary();
    506   assert(led_strip.access_semaphore);
    507   bool led_init_ok = led_strip_init(&led_strip);
    508   assert(led_init_ok);
    509 
    510   blinkenstrip_state_has_changed = true;
    511   while (true) {
    512     xSemaphoreTake(blinkenstrip_state_changed_semaphore, portMAX_DELAY);
    513     switch(blinkenstrip_state){
    514     case BLINKENSTRIP_STATE_UNICOLOR_RAINBOW:
    515       unicolor_rainbow(); break;
    516     case BLINKENSTRIP_STATE_RANDOM_ON_OFF:
    517       random_on_off(); break;
    518     case BLINKENSTRIP_STATE_RUNNING_DOT:
    519       running_dot(); break;
    520     case BLINKENSTRIP_STATE_CELLULAR_AUTOMATON:
    521       cellular_automaton(); break;
    522     case BLINKENSTRIP_STATE_LINE_BY_LINE:
    523       line_by_line(); break;
    524     case BLINKENSTRIP_STATE_WORM:
    525       worm(); break;
    526     case BLINKENSTRIP_STATE_UNICOLOR_RGB:
    527       if(blinkenstrip_state_has_changed)
    528         unicolor(led_color_rgb);
    529       break;
    530     case BLINKENSTRIP_STATE_EXPERIMENTAL:
    531       experiment(); break;
    532     }
    533     xSemaphoreGive(blinkenstrip_state_changed_semaphore);
    534     vTaskDelay(60 / portTICK_PERIOD_MS);
    535   }
    536 }
    537 
    538 /* }}} */