blinkenstrip

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

main.c (15945B)


      1 /*
      2   Copyright © 2021 Gerd Beuster <gerd@frombelow.net>
      3 
      4   Licensed under the Apache License, Version 2.0 (the "License");
      5   you may not use this file except in compliance with the License.
      6   You may obtain a copy of the License at
      7 
      8       http://www.apache.org/licenses/LICENSE-2.0
      9 
     10   Unless required by applicable law or agreed to in writing, software
     11   distributed under the License is distributed on an "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13   See the License for the specific language governing permissions and
     14   limitations under the License.
     15 
     16 
     17 */
     18 
     19 /* {{{ Includes and definitions */
     20 
     21 #include "main.h"
     22 #include "debug.h"
     23 #include "nvs_flash.h"
     24 #include "led.h"
     25 #include <string.h>
     26 
     27 #define delay(ms) (vTaskDelay(ms/portTICK_RATE_MS))
     28 
     29 
     30 /* }}} */
     31 
     32 /* {{{ Processing of HTML pages */
     33 
     34 /* Page templates */                                  
     35                                   
     36 const static char http_html_hdr[] =
     37   "HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n";
     38 
     39 const static char http_index_template_html[] =
     40 #include "html_templates/index.html"
     41 
     42 const static char http_config_template_html[] =
     43 #include "html_templates/config.html"
     44   
     45 const static char http_reset_html[] =
     46 #include "html_templates/reset.html"
     47 
     48 /* Request handlers */
     49 
     50 static void handler_index_html(struct netconn *conn, char *base_url_begin,
     51                                char *base_url_end, char *parameters){
     52   /* Send the HTML header
     53    * subtract 1 from the size, since we don't send the \0 in the string
     54    * NETCONN_NOCOPY: our data is const static, so no need to copy it
     55    */
     56   netconn_write(conn, http_html_hdr, sizeof(http_html_hdr)-1, NETCONN_NOCOPY);
     57   // Process request (update state)
     58   char *val_start, *val_end;
     59   if(url_key_value(parameters, "mode", &val_start, &val_end)){
     60     uint8_t val_length = val_end-val_start;
     61     xSemaphoreTake(blinkenstrip_state_changed_semaphore, portMAX_DELAY);
     62     blinkenstrip_state_has_changed = true;
     63     if(strncmp("sequence", val_start, val_length) == 0)
     64       blinkenstrip_state = BLINKENSTRIP_STATE_UNICOLOR_RAINBOW;
     65     else if(strncmp("blink", val_start, val_length) == 0)
     66       blinkenstrip_state = BLINKENSTRIP_STATE_RANDOM_ON_OFF;
     67     else if(strncmp("running", val_start, val_length) == 0)
     68       blinkenstrip_state = BLINKENSTRIP_STATE_RUNNING_DOT;
     69     else if(strncmp("cellular", val_start, val_length) == 0)
     70       blinkenstrip_state = BLINKENSTRIP_STATE_CELLULAR_AUTOMATON;
     71     else if(strncmp("lines", val_start, val_length) == 0)
     72       blinkenstrip_state = BLINKENSTRIP_STATE_LINE_BY_LINE;
     73     else if(strncmp("worm", val_start, val_length) == 0)
     74       blinkenstrip_state = BLINKENSTRIP_STATE_WORM;
     75     else if(strncmp("rgb", val_start, val_length) == 0){
     76       blinkenstrip_state = BLINKENSTRIP_STATE_UNICOLOR_RGB;
     77       if(url_key_value(parameters, "red", &val_start, &val_end)){
     78         *val_end ='\0';
     79         led_color_rgb.red = max_brightness < atol(val_start) ?
     80           max_brightness : atol(val_start);
     81         *val_end ='&';
     82       }
     83       if(url_key_value(parameters, "green", &val_start, &val_end)){
     84         *val_end ='\0';
     85         led_color_rgb.green = max_brightness < atol(val_start) ?
     86           max_brightness : atol(val_start);
     87         *val_end ='&';
     88       }
     89       if(url_key_value(parameters, "blue", &val_start, &val_end)){
     90         *val_end ='\0';
     91         led_color_rgb.blue = max_brightness < atol(val_start) ?
     92           max_brightness : atol(val_start);
     93         *val_end ='&';
     94       }
     95     }
     96     else if(strncmp("experimental", val_start, val_length) == 0)
     97       blinkenstrip_state = BLINKENSTRIP_STATE_EXPERIMENTAL;
     98     xSemaphoreGive(blinkenstrip_state_changed_semaphore);
     99   }
    100   /* Return index page based on index_template_html. We have to fill
    101      out the template. We have to set the maximal values for the RGB
    102      sliders in the template. We allocating memory, we add 3 bytes to
    103      the length of the buffer for this. (Numbers may have up to 3
    104      digits, but two are already reserved because of the "%d"s in the
    105      template). We also add space for the name of the app. */
    106   size_t http_index_html_len = (sizeof(http_index_template_html) +
    107                                 sizeof(app_name)*3 + 3);
    108   char *http_index_html = malloc(http_index_html_len);
    109   snprintf(http_index_html, http_index_html_len, http_index_template_html,
    110            app_name, app_name,
    111            max_brightness, max_brightness, max_brightness);
    112   netconn_write(conn, http_index_html, strlen(http_index_html)-1,
    113                 NETCONN_NOCOPY);
    114   free(http_index_html);
    115 }
    116 
    117 static void handler_config_html(struct netconn *conn, char *base_url_begin,
    118                                 char *base_url_end, char *parameters){
    119   /* Request for config.html */
    120   netconn_write(conn, http_html_hdr, sizeof(http_html_hdr)-1, NETCONN_NOCOPY);
    121   /* Check if the user supplied values. If yes, we store the
    122      values and reset. If not, we show config.html. */
    123   char *val_start, *val_end;
    124   if(url_key_value(parameters, "app_name", &val_start, &val_end)){
    125     /* We got values. Store them and reset. */
    126     nvs_flash_init();
    127     nvs_handle flash_handle;
    128     nvs_open("blinkenstrip", NVS_READWRITE, &flash_handle);
    129     *(val_end) = '\0'; // Terminate string
    130     nvs_set_str(flash_handle, "app_name", val_start);
    131     *(val_end) = '&'; // Restore parameters
    132     url_key_value(parameters, "essid", &val_start, &val_end);
    133     *(val_end) = '\0'; // Terminate string
    134     nvs_set_str(flash_handle, "wifi_essid", val_start);
    135     *(val_end) = '&'; // Restore parameters
    136     url_key_value(parameters, "password", &val_start, &val_end);
    137     *(val_end) = '\0'; // Terminate string
    138     if(strlen(val_start) >= 8) {
    139       nvs_set_str(flash_handle, "wifi_password", val_start);
    140     };
    141     *(val_end) = '&'; // Restore parameters
    142     url_key_value(parameters, "ap", &val_start, &val_end);
    143     *(val_end) = '\0'; // Terminate string
    144     nvs_set_u8(flash_handle, "wifi_ap", !strcmp(val_start, "yes"));
    145     *(val_end) = '&'; // Restore parameters
    146     url_key_value(parameters, "led_strip_w", &val_start, &val_end);
    147     *(val_end) = '\0'; // Terminate string
    148     nvs_set_u16(flash_handle, "led_strip_w", atol(val_start));
    149     *(val_end) = '&'; // Restore parameters
    150     url_key_value(parameters, "led_strip_h", &val_start, &val_end);
    151     *(val_end) = '\0'; // Terminate string
    152     nvs_set_u16(flash_handle, "led_strip_h", atol(val_start));
    153     *(val_end) = '&'; // Restore parameters
    154     url_key_value(parameters, "snake", &val_start, &val_end);
    155     *(val_end) = '\0'; // Terminate string
    156     nvs_set_u8(flash_handle, "snake", !strcmp(val_start, "yes"));
    157     *(val_end) = '&'; // Restore parameters
    158     url_key_value(parameters, "wrap_around", &val_start, &val_end);
    159     *(val_end) = '\0'; // Terminate string
    160     nvs_set_u8(flash_handle, "wrap_around", !strcmp(val_start, "yes"));
    161     *(val_end) = '&'; // Restore parameters
    162     url_key_value(parameters, "number_of_worms", &val_start, &val_end);
    163     *(val_end) = '\0'; // Terminate string
    164     nvs_set_u8(flash_handle, "number_of_worms", (uint8_t) atol(val_start));
    165     *(val_end) = '&'; // Restore parameters
    166     url_key_value(parameters, "max_brightness", &val_start, &val_end);
    167     *(val_end) = '\0'; // Terminate string
    168     nvs_set_u8(flash_handle, "max_brightness", (uint8_t) atol(val_start));
    169     *(val_end) = '&'; // Restore parameters
    170 
    171     nvs_commit(flash_handle);
    172     nvs_close(flash_handle);
    173     /* Perform reset. Since we reset, it is not necessary to
    174        update our internal configuration variables, since this
    175        will be done once we start again after the reset. */
    176     netconn_write(conn, http_reset_html, strlen(http_reset_html)-1,
    177                   NETCONN_NOCOPY);
    178     /* Since we want to perform a reset, we have to close the
    179        connection right here. */
    180     netconn_close(conn);
    181     delay(1000);
    182     esp_restart();
    183   }
    184   else {
    185     /* Return config page based on config_template_html. We have to
    186        fill out the template. This requires creation of a buffer of
    187        apropriate size.  The numbers in the size calculation are: 3
    188        characters each for number of horizontal leds, vertical leds,
    189        number of worms, and max brightness, plus length of string
    190        "checked" *4 which will be a parameter for radio buttons. We
    191        subtract 7*2 bytes for the format variables ("%s") in the
    192        template file. */
    193     size_t http_config_html_len = (sizeof(http_config_template_html) +
    194                                    sizeof(app_name)*3 +
    195                                    sizeof(wifi_essid) +
    196                                    sizeof(wifi_password) +
    197                                    strlen("checked")*4 + 4*3 - 7*2);
    198     char *http_config_html = malloc(http_config_html_len);
    199     snprintf(http_config_html, http_config_html_len,
    200              http_config_template_html, app_name, app_name, app_name,
    201              wifi_essid, wifi_password,
    202              wifi_ap ? "checked" : "", wifi_ap ? "" : "checked",
    203              led_strip_w, led_strip_h,
    204              snake ? "checked" : "", snake ? "" : "checked",
    205              wrap_around ? "checked" : "", wrap_around ? "" : "checked",
    206              number_of_worms,
    207              max_brightness);
    208     netconn_write(conn, http_config_html, strlen(http_config_html)-1,
    209                   NETCONN_NOCOPY);
    210     free(http_config_html);
    211   }
    212 }
    213 
    214 /* }}} */
    215 
    216 /* {{{ main */
    217 
    218 void read_configuration_from_flash(){
    219   // All global configuration variables are defined in led.h (some
    220   // refactoring required ...)
    221   nvs_flash_init();
    222   nvs_handle flash_handle;
    223   nvs_open("blinkenstrip", NVS_READWRITE, &flash_handle);
    224   size_t required_size;
    225   bool flash_changed = false;
    226   esp_err_t err = nvs_get_str(flash_handle, "app_name", NULL, &required_size);
    227   if(err != ESP_OK){
    228     /* Not yet initialized. Use default. */
    229     nvs_set_str(flash_handle, "app_name", CONFIG_APP_NAME);
    230     nvs_get_str(flash_handle, "app_name", NULL, &required_size);
    231     flash_changed = true;
    232   }
    233   app_name = malloc(required_size);
    234   nvs_get_str(flash_handle, "app_name", app_name, &required_size);
    235   err = nvs_get_str(flash_handle, "wifi_essid", NULL, &required_size);
    236   if(err != ESP_OK){
    237     /* Not yet initialized. Use default. */
    238     nvs_set_str(flash_handle, "wifi_essid", CONFIG_WIFI_SSID);
    239     nvs_get_str(flash_handle, "wifi_essid", NULL, &required_size);
    240     flash_changed = true;
    241   }
    242   wifi_essid = malloc(required_size);
    243   nvs_get_str(flash_handle, "wifi_essid", wifi_essid, &required_size);
    244   err = nvs_get_str(flash_handle, "wifi_password", NULL, &required_size);
    245   wifi_password = malloc(required_size);
    246   if(err != ESP_OK){
    247     /* Not yet initialized. Use default. */
    248     nvs_set_str(flash_handle, "wifi_password", CONFIG_WIFI_PASSWORD);
    249     nvs_get_str(flash_handle, "wifi_password", NULL, &required_size);
    250     flash_changed = true;
    251   }
    252   nvs_get_str(flash_handle, "wifi_password", wifi_password, &required_size);
    253   if(nvs_get_u8(flash_handle, "wifi_ap", &wifi_ap) != ESP_OK){
    254     /* Not yet initialized. Use default. */
    255     #ifdef CONFIG_WIFI_AP
    256     wifi_ap = true;
    257     #else
    258     wifi_ap = false;
    259     #endif
    260     nvs_set_u8(flash_handle, "wifi_ap", wifi_ap);
    261     flash_changed = true;
    262   }
    263   if(nvs_get_u16(flash_handle, "led_strip_w", &led_strip_w) != ESP_OK){
    264     /* Not yet initialized. Use default. */
    265     led_strip_w = CONFIG_LED_STRIP_WIDTH;
    266     nvs_set_u16(flash_handle, "led_strip_w", led_strip_w);
    267     flash_changed = true;
    268   }
    269   if(nvs_get_u16(flash_handle, "led_strip_h", &led_strip_h) != ESP_OK){
    270     /* Not yet initialized. Use default. */
    271     led_strip_h = CONFIG_LED_STRIP_HEIGHT;
    272     nvs_set_u16(flash_handle, "led_strip_h", led_strip_h);
    273     flash_changed = true;
    274   }
    275   if(nvs_get_u8(flash_handle, "snake", &snake) != ESP_OK){
    276     /* Not yet initialized. Use default. */
    277     #ifdef CONFIG_LED_STRIP_SNAKE
    278     snake = true;
    279     #else
    280     snake = false;
    281     #endif
    282     nvs_set_u8(flash_handle, "snake", snake);
    283     flash_changed = true;
    284   }
    285   if(nvs_get_u8(flash_handle, "wrap_around", &wrap_around) != ESP_OK){
    286     /* Not yet initialized. Use default. */
    287     #ifdef CONFIG_LED_STRIP_WRAP_AROUND
    288     wrap_around = true;
    289     #else
    290     wrap_around = false;
    291     #endif
    292     nvs_set_u8(flash_handle, "wrap_around", wrap_around);
    293     flash_changed = true;
    294   }
    295   if(nvs_get_u8(flash_handle, "number_of_worms", &number_of_worms) != ESP_OK){
    296     /* Not yet initialized. Use default. */
    297     number_of_worms = CONFIG_NUMBER_OF_WORMS;
    298     nvs_set_u8(flash_handle, "number_of_worms", number_of_worms);
    299     flash_changed = true;
    300   }
    301   if(nvs_get_u8(flash_handle, "max_brightness", &max_brightness) != ESP_OK){
    302     /* Not yet initialized. Use default. */
    303     max_brightness = CONFIG_MAX_BRIGHTNESS;
    304     nvs_set_u8(flash_handle, "max_brightness", max_brightness);
    305     flash_changed = true;
    306   }
    307   if(nvs_get_u8(flash_handle, "blinkenstrip_state", (uint8_t *) &blinkenstrip_state) != ESP_OK){
    308     /* Not yet initialized. Use default. */
    309     blinkenstrip_state = BLINKENSTRIP_STATE_RANDOM_ON_OFF;
    310     nvs_set_u8(flash_handle, "blinkenstrip_state", blinkenstrip_state);
    311     flash_changed = true;
    312   }
    313   if(nvs_get_u8(flash_handle, "led_col_red", &led_color_rgb.red) != ESP_OK){
    314     /* Not yet initialized. Use default. */
    315     led_color_rgb.red = 0xFF;
    316     nvs_set_u8(flash_handle, "led_col_red", led_color_rgb.red);
    317     flash_changed = true;
    318   }
    319   if(nvs_get_u8(flash_handle, "led_col_green", &led_color_rgb.green) != ESP_OK){
    320     /* Not yet initialized. Use default. */
    321     led_color_rgb.green = 0xFF;
    322     nvs_set_u8(flash_handle, "led_col_green", led_color_rgb.green);
    323     flash_changed = true;
    324   }
    325   if(nvs_get_u8(flash_handle, "led_col_blue", &led_color_rgb.blue) != ESP_OK){
    326     /* Not yet initialized. Use default. */
    327     led_color_rgb.blue = 0xFF;
    328     nvs_set_u8(flash_handle, "led_col_blue", led_color_rgb.blue);
    329     flash_changed = true;
    330   }
    331   if(flash_changed){
    332     nvs_commit(flash_handle);
    333   }
    334   nvs_close(flash_handle);
    335   DEBUG_MSG(DEBUG, ("app_name: %s\n", app_name));
    336   DEBUG_MSG(DEBUG, ("wifi_essid: %s\n", wifi_essid));
    337   DEBUG_MSG(DEBUG, ("wifi_password: %s\n", wifi_password));
    338   DEBUG_MSG(DEBUG, ("wifi_ap: %d\n", wifi_ap));
    339   DEBUG_MSG(DEBUG, ("led_strip_w: %d\n", led_strip_w));
    340   DEBUG_MSG(DEBUG, ("led_strip_h: %d\n", led_strip_h));
    341   DEBUG_MSG(DEBUG, ("snake: %d\n", snake));
    342   DEBUG_MSG(DEBUG, ("wrap_around: %d\n", wrap_around));
    343   DEBUG_MSG(DEBUG, ("number_of_worms: %d\n", number_of_worms));
    344   DEBUG_MSG(DEBUG, ("max_brightness: %d\n", max_brightness));
    345   DEBUG_MSG(DEBUG, ("blinkenstrip_state: %d (%d, %d, %d)\n", blinkenstrip_state,
    346                     led_color_rgb.red, led_color_rgb.green, led_color_rgb.blue));
    347 }
    348 
    349 // Factory reset is triggered if factory reset pins are connected.
    350 void check_for_factory_reset(){
    351   gpio_pad_select_gpio(CONFIG_PIN_FACTORY_RESET_A);
    352   gpio_set_direction(CONFIG_PIN_FACTORY_RESET_A, GPIO_MODE_OUTPUT);
    353   gpio_set_level(CONFIG_PIN_FACTORY_RESET_A, 1);
    354   gpio_pad_select_gpio(CONFIG_PIN_FACTORY_RESET_B);
    355   gpio_pullup_dis(CONFIG_PIN_FACTORY_RESET_B);
    356   gpio_set_direction(CONFIG_PIN_FACTORY_RESET_B, GPIO_MODE_INPUT);
    357   if(gpio_get_level(CONFIG_PIN_FACTORY_RESET_B)){
    358     DEBUG_MSG(DEBUG, ("Reset pin is HIGH!\n"));
    359     /* RESET pins are connect. Clear NV memory! */
    360     nvs_flash_init();
    361     nvs_handle flash_handle;
    362     nvs_open("blinkenstrip", NVS_READWRITE, &flash_handle);
    363     nvs_erase_all(flash_handle);
    364     nvs_commit(flash_handle);
    365     nvs_close(flash_handle);
    366     DEBUG_MSG(DEBUG, ("NV memory cleared!\n"));
    367     delay(5000);
    368   }
    369   else{
    370     DEBUG_MSG(DEBUG, ("Reset pin is LOW!\n"));
    371     gpio_set_level(CONFIG_PIN_FACTORY_RESET_A, 0);
    372   }
    373 }
    374 
    375 int app_main(void) {
    376   check_for_factory_reset();
    377   read_configuration_from_flash();
    378 
    379   initialise_wifi(wifi_ap, wifi_essid, wifi_password);
    380 
    381   xTaskCreate(&http_server, "http_server", 4096, NULL, 5, &http_server_task);
    382   vTaskSuspend(http_server_task);
    383   xTaskCreate(&led_controller, "main_led_task", 4096, NULL, 5, NULL);
    384   return 0;
    385 }
    386 
    387 /* }}} */