From 8598e019d43cb5a8761f0a4b5d5a71e3e809e401 Mon Sep 17 00:00:00 2001 From: Markus Ransberger Date: Thu, 31 Aug 2023 01:27:05 +0200 Subject: [PATCH] Replace timing values with microsecond variants. --- include/wordclock_constants.h | 28 ++--- include/wordclock_esp8266.h | 13 ++- src/wordclock_esp8266.cpp | 198 ++++++++++++++++++---------------- 3 files changed, 125 insertions(+), 114 deletions(-) diff --git a/include/wordclock_constants.h b/include/wordclock_constants.h index f1d4cc9..644b771 100644 --- a/include/wordclock_constants.h +++ b/include/wordclock_constants.h @@ -36,21 +36,21 @@ typedef enum #define NIGHTMODE_END_HR 7 #define NIGHTMODE_END_MIN 0 -// Timings in ms -#define PERIOD_ANIMATION 200 -#define PERIOD_HEARTBEAT 1000 -#define PERIOD_MATRIX_UPDATE 100 -#define PERIOD_NIGHTMODE_CHECK 20000 -#define PERIOD_NTP_UPDATE 30000 -#define PERIOD_PONG 10 -#define PERIOD_SNAKE 50 -#define PERIOD_STATE_CHANGE 10000 -#define PERIOD_TETRIS 50 -#define PERIOD_TIME_VISU_UPDATE 1000 -#define TIMEOUT_LEDDIRECT 5000 +// Timings in us +#define PERIOD_ANIMATION_US (200 * 1000) // 200ms +#define PERIOD_HEARTBEAT_US (1 * 1000 * 1000) // 1s +#define PERIOD_MATRIX_UPDATE_US (100 * 1000) // 100ms +#define PERIOD_NIGHTMODE_CHECK_US (20 * 1000 * 1000) // 20s +#define PERIOD_NTP_UPDATE_US (30 * 1000 * 1000) // 30s +#define PERIOD_PONG_US (10 * 1000) // 10ms +#define PERIOD_SNAKE_US (50 * 1000) // 50ms +#define PERIOD_STATE_CHANGE_US (10 * 1000 * 1000) // 10s +#define PERIOD_TETRIS_US (50 * 1000) // 50ms +#define PERIOD_TIME_VISU_UPDATE_US (1 * 1000 * 1000) // 1s +#define TIMEOUT_LEDDIRECT_US (5 * 1000 * 1000) // 5s -#define SHORT_PRESS_MS 100 -#define LONG_PRESS_MS 2000 +#define SHORT_PRESS_US (100 * 1000) // 100ms +#define LONG_PRESS_US (2 * 1000 * 1000) // 2s // Current limit #define CURRENT_LIMIT_LED 2500 // limit the total current consumed by LEDs (mA) diff --git a/include/wordclock_esp8266.h b/include/wordclock_esp8266.h index 3fdbf93..43ba150 100644 --- a/include/wordclock_esp8266.h +++ b/include/wordclock_esp8266.h @@ -12,10 +12,10 @@ extern ESP8266WebServer webserver; typedef struct { - int nightmode_start_hour; - int nightmode_start_min; - int nightmode_end_hour; - int nightmode_end_min; + int start_hour; + int start_min; + int end_hour; + int end_min; } NightModeTimes_st; typedef enum @@ -30,11 +30,10 @@ typedef enum NUM_STATES } ClockState_en; -#define CURRENT_TIME_MS (system_get_time() / 1000) // use ESP time interface - int EEPROM_read_address(int address); String leading_zero2digit(int value); void check_night_mode(void); +void check_wifi_status(void); void EEPROM_write_to_address(int address, int value); void handle_button(void); void handle_command(void); @@ -42,7 +41,7 @@ void handle_current_state(void); void handle_data_request(void); void handle_led_direct(void); void load_main_color(void); -void ntp_time_update(unsigned long *last_ntp_update); +void ntp_time_update(uint32 *last_ntp_update_us); void on_state_entry(uint8_t state); void send_heartbeat(void); void set_main_color(uint8_t red, uint8_t green, uint8_t blue); diff --git a/src/wordclock_esp8266.cpp b/src/wordclock_esp8266.cpp index d112a32..aad01d1 100644 --- a/src/wordclock_esp8266.cpp +++ b/src/wordclock_esp8266.cpp @@ -48,20 +48,20 @@ const String state_names[] = {"Clock", "DiClock", "Spiral", "Tetris", "Snake", "PingPong", "Hearts"}; // PERIODS for each state (different for stateAutoChange or Manual mode) -const uint16_t PERIODS[2][NUM_STATES] = {{PERIOD_TIME_VISU_UPDATE, // stateAutoChange = 0 - PERIOD_TIME_VISU_UPDATE, - PERIOD_ANIMATION, - PERIOD_TETRIS, - PERIOD_SNAKE, - PERIOD_PONG, - PERIOD_ANIMATION}, - {PERIOD_TIME_VISU_UPDATE, // stateAutoChange = 1 - PERIOD_TIME_VISU_UPDATE, - PERIOD_ANIMATION, - PERIOD_ANIMATION, - PERIOD_ANIMATION, - PERIOD_PONG, - PERIOD_ANIMATION}}; +const uint32_t PERIODS[2][NUM_STATES] = {{PERIOD_TIME_VISU_UPDATE_US, // stateAutoChange = 0 + PERIOD_TIME_VISU_UPDATE_US, + PERIOD_ANIMATION_US, + PERIOD_TETRIS_US, + PERIOD_SNAKE_US, + PERIOD_PONG_US, + PERIOD_ANIMATION_US}, + {PERIOD_TIME_VISU_UPDATE_US, // stateAutoChange = 1 + PERIOD_TIME_VISU_UPDATE_US, + PERIOD_ANIMATION_US, + PERIOD_ANIMATION_US, + PERIOD_ANIMATION_US, + PERIOD_PONG_US, + PERIOD_ANIMATION_US}}; // ---------------------------------------------------------------------------------- // GLOBAL VARIABLES @@ -84,7 +84,7 @@ UDPLogger logger; // Statics static bool spiral_direction = false; -static unsigned long last_led_direct = 0; // time of last direct LED command (=> fall back to normal mode after timeout) +static uint32 last_led_direct_us = 0; // time of last direct LED command (=> fall back to normal mode after timeout) static WiFiUDP wifi_udp; static NTPClientPlus ntp_client = NTPClientPlus(wifi_udp, NTP_SERVER_URL, 1, true); @@ -107,7 +107,7 @@ NightModeTimes_st night_mode_times = { NIGHTMODE_END_HR, NIGHTMODE_END_MIN}; -uint32_t heartbeat_counter = 0; // for heartbeat on-time in seconds +uint32_t heartbeat_counter = 0; // for heartbeat on-time in seconds // ---------------------------------------------------------------------------------- // SETUP @@ -145,17 +145,19 @@ void setup() led_matrix.set_min_indicator(15, colors_24bit[6]); led_matrix.draw_on_matrix_instant(); - /** Use WiFiMaanger for handling initial Wifi setup **/ - // Local intialization. Once its business is done, there is no need to keep it around - WiFiManager wifiManager; + /* Use WiFiMaanger for handling initial Wifi setup */ + WiFiManager wifiManager; // Local intialization. Once its business is done, there is no need to keep it around /* fetches ssid and pass from eeprom and tries to connect. if it does not connect it starts an access point with * the specified name and goes into a blocking loop awaiting configuration. */ wifiManager.autoConnect(AP_SSID); - // if you get here you have connected to the WiFi + // If you get here you have connected to the WiFi Serial.printf("Connected, IP address: "); Serial.println(WiFi.localIP()); + // ESP8266 tries to reconnect automatically when the connection is lost + WiFi.setAutoReconnect(true); + WiFi.persistent(true); // Turn off minutes leds led_matrix.set_min_indicator(15, 0); @@ -217,6 +219,7 @@ void setup() led_matrix.flush(); led_matrix.draw_on_matrix_instant(); } + // setup NTP ntp_client.setupNTPClient(); logger.log_string("NTP running"); @@ -240,30 +243,30 @@ void setup() random_tetris(true); // Read nightmode setting from EEPROM - night_mode_times.nightmode_start_hour = EEPROM_read_address(ADR_NM_START_H); - night_mode_times.nightmode_start_min = EEPROM_read_address(ADR_NM_START_M); - night_mode_times.nightmode_end_hour = EEPROM_read_address(ADR_NM_END_H); - night_mode_times.nightmode_end_min = EEPROM_read_address(ADR_NM_END_M); + night_mode_times.start_hour = EEPROM_read_address(ADR_NM_START_H); + night_mode_times.start_min = EEPROM_read_address(ADR_NM_START_M); + night_mode_times.end_hour = EEPROM_read_address(ADR_NM_END_H); + night_mode_times.end_min = EEPROM_read_address(ADR_NM_END_M); - if (night_mode_times.nightmode_start_hour < 0 || night_mode_times.nightmode_start_hour > 23) + if (night_mode_times.start_hour < 0 || night_mode_times.start_hour > 23) { - night_mode_times.nightmode_start_hour = NIGHTMODE_START_HR; + night_mode_times.start_hour = NIGHTMODE_START_HR; } - if (night_mode_times.nightmode_start_min < 0 || night_mode_times.nightmode_start_min > 59) + if (night_mode_times.start_min < 0 || night_mode_times.start_min > 59) { - night_mode_times.nightmode_start_min = NIGHTMODE_START_MIN; + night_mode_times.start_min = NIGHTMODE_START_MIN; } - if (night_mode_times.nightmode_end_hour < 0 || night_mode_times.nightmode_end_hour > 23) + if (night_mode_times.end_hour < 0 || night_mode_times.end_hour > 23) { - night_mode_times.nightmode_end_hour = NIGHTMODE_END_HR; + night_mode_times.end_hour = NIGHTMODE_END_HR; } - if (night_mode_times.nightmode_end_min < 0 || night_mode_times.nightmode_end_min > 59) + if (night_mode_times.end_min < 0 || night_mode_times.end_min > 59) { - night_mode_times.nightmode_end_min = NIGHTMODE_END_MIN; + night_mode_times.end_min = NIGHTMODE_END_MIN; } - logger.log_string("Nightmode starts at: " + String(night_mode_times.nightmode_start_hour) + ":" + String(night_mode_times.nightmode_start_min)); - logger.log_string("Nightmode ends at: " + String(night_mode_times.nightmode_end_hour) + ":" + String(night_mode_times.nightmode_end_min)); + logger.log_string("Nightmode starts at: " + String(night_mode_times.start_hour) + ":" + String(night_mode_times.start_min)); + logger.log_string("Nightmode ends at: " + String(night_mode_times.end_hour) + ":" + String(night_mode_times.end_min)); // Read brightness setting from EEPROM, lower limit is 10 so that the LEDs are not completely off brightness = EEPROM_read_address(ADR_BRIGHTNESS); @@ -280,59 +283,62 @@ void setup() // ---------------------------------------------------------------------------------- void loop() { - unsigned long current_time_ms = CURRENT_TIME_MS; + uint32 current_time_us = system_get_time(); // Timestamp variables - static unsigned long last_animation_step = 0; // time of last animation step - static unsigned long last_matrix_update = 0; // time of last Matrix update - static unsigned long last_heartbeat = 0; // time of last heartbeat sending - static unsigned long last_nightmode_check = 0; // time of last nightmode check - static unsigned long last_ntp_update = 0; // time of last NTP update - static unsigned long last_state_change = 0; // time of last state change + static uint32 last_animation_step_us = 0; // time of last animation step + static uint32 last_matrix_update_us = 0; // time of last Matrix update + static uint32 last_heartbeat_us = 0; // time of last heartbeat sending + static uint32 last_nightmode_check_us = 0; // time of last nightmode check + static uint32 last_ntp_update_us = 0; // time of last NTP update + static uint32 last_state_change_us = 0; // time of last state change handleOTA(); // handle OTA webserver.handleClient(); // handle webserver // send regularly heartbeat messages via UDP multicast - if ((current_time_ms - last_heartbeat) > PERIOD_HEARTBEAT) + if ((current_time_us - last_heartbeat_us) > PERIOD_HEARTBEAT_US) { send_heartbeat(); // send heartbeat update - last_heartbeat = CURRENT_TIME_MS; + last_heartbeat_us = system_get_time(); } - if (!night_mode && ((current_time_ms - last_animation_step) > PERIODS[state_auto_change][current_state]) && ((current_time_ms - last_led_direct) > TIMEOUT_LEDDIRECT)) + if (!night_mode && ((current_time_us - last_animation_step_us) > PERIODS[state_auto_change][current_state]) && ((current_time_us - last_led_direct_us) > TIMEOUT_LEDDIRECT_US)) { handle_current_state(); // handle current state - last_animation_step = CURRENT_TIME_MS; + last_animation_step_us = system_get_time(); delay(10); } - if ((current_time_ms - last_matrix_update) > PERIOD_MATRIX_UPDATE) + if ((current_time_us - last_matrix_update_us) > PERIOD_MATRIX_UPDATE_US) { update_matrix(); // update matrix - last_matrix_update = CURRENT_TIME_MS; + last_matrix_update_us = system_get_time(); delay(10); } handle_button(); // handle button press - if (!night_mode && state_auto_change && (current_time_ms - last_state_change > PERIOD_STATE_CHANGE)) + if (state_auto_change && !night_mode && ((current_time_us - last_state_change_us) > PERIOD_STATE_CHANGE_US)) // this feature could be removed... { update_state_machine(); // handle state changes - last_state_change = CURRENT_TIME_MS; + last_state_change_us = system_get_time(); } - if ((current_time_ms - last_ntp_update) > PERIOD_NTP_UPDATE) + if ((current_time_us - last_ntp_update_us) > PERIOD_NTP_UPDATE_US) { - ntp_time_update(&last_ntp_update); // ntp time update + check_wifi_status(); // check WiFi status before NTP update + delay(10); + + ntp_time_update(&last_ntp_update_us); // ntp time update delay(10); } - if ((current_time_ms - last_nightmode_check) > PERIOD_NIGHTMODE_CHECK) + if ((current_time_us - last_nightmode_check_us) > PERIOD_NIGHTMODE_CHECK_US) { check_night_mode(); // check night mode - last_nightmode_check = CURRENT_TIME_MS; + last_nightmode_check_us = system_get_time(); } } @@ -432,7 +438,7 @@ void handle_current_state() } /** - * @brief Update matrix colors, should be called in loop() + * @brief Update matrix colors, should be called in loop(). * * @param None */ @@ -443,28 +449,34 @@ void update_matrix() } /** - * @brief Send heartbeat, should be called in loop() + * @brief Send heartbeat, should be called in loop(). * * @param None */ void send_heartbeat() { logger.log_string("Heartbeat, state: " + state_names[current_state] + ", FreeHeap: " + ESP.getFreeHeap() + - ", HeapFrag: " + ESP.getHeapFragmentation() + ", MaxFreeBlock: " + ESP.getMaxFreeBlockSize() + + ", HeapFrag: " + ESP.getHeapFragmentation() + ", MaxFreeBlock: " + ESP.getMaxFreeBlockSize() + "\nCounter: " + heartbeat_counter + ", Hours: " + (float)(heartbeat_counter) / 3600.0 + "\n"); heartbeat_counter++; +} +/** + * @brief Check WiFi status and try to reconnect if needed. Should be called in loop() before NTP update. + * + * @param None + */ +void check_wifi_status() +{ // Check wifi status if (WiFi.status() != WL_CONNECTED) { - Serial.println("WiFi connection lost!"); - led_matrix.grid_add_pixel(0, 5, colors_24bit[1]); - led_matrix.draw_on_matrix_instant(); + Serial.println("WiFi connection lost! Trying to reconnect automatically..."); } } /** - * @brief Night mode check, should be called in loop() + * @brief Night mode check, should be called in loop(). * * @param None */ @@ -474,22 +486,22 @@ void check_night_mode() int hours = ntp_client.getHours24(); int minutes = ntp_client.getMinutes(); - if (hours == night_mode_times.nightmode_start_hour && minutes == night_mode_times.nightmode_start_min) + if (hours == night_mode_times.start_hour && minutes == night_mode_times.start_min) { set_night_mode(true); } - else if (hours == night_mode_times.nightmode_end_hour && minutes == night_mode_times.nightmode_end_min) + else if (hours == night_mode_times.end_hour && minutes == night_mode_times.end_min) { set_night_mode(false); } } /** - * @brief NTP time update, should be called in loop() + * @brief NTP time update, should be called in loop(). * * @param None */ -void ntp_time_update(unsigned long *last_ntp_update) +void ntp_time_update(uint32 *last_ntp_update_us) { // NTP time update int ntp_retval = ntp_client.updateNTP(); @@ -504,14 +516,14 @@ void ntp_time_update(unsigned long *last_ntp_update) logger.log_string("Date: " + ntp_client.getFormattedDate()); logger.log_string("TimeOffset (seconds): " + String(ntp_client.getTimeOffset())); logger.log_string("Summertime: " + String(ntp_client.updateSWChange())); - *last_ntp_update = CURRENT_TIME_MS; + *last_ntp_update_us = system_get_time(); watchdog_counter = 30; break; } case NTP_UPDATE_TIMEOUT: { logger.log_string("NTP-Update not successful. Reason: Timeout"); - *last_ntp_update += 10000; + *last_ntp_update_us += 10000000; watchdog_counter--; break; } @@ -522,7 +534,7 @@ void ntp_time_update(unsigned long *last_ntp_update) logger.log_string("Date: " + ntp_client.getFormattedDate()); logger.log_string("TimeOffset (seconds): " + String(ntp_client.getTimeOffset())); logger.log_string("Summertime: " + String(ntp_client.updateSWChange())); - *last_ntp_update += 10000; + *last_ntp_update_us += 10000000; watchdog_counter--; break; } @@ -530,7 +542,7 @@ void ntp_time_update(unsigned long *last_ntp_update) default: { logger.log_string("NTP-Update not successful. Reason: NTP time not valid (<1970)"); - *last_ntp_update += 10000; + *last_ntp_update_us += 10000000; watchdog_counter--; break; } @@ -666,7 +678,7 @@ void handle_led_direct() } led_matrix.draw_on_matrix_instant(); - last_led_direct = CURRENT_TIME_MS; + last_led_direct_us = system_get_time(); } webserver.send(200, "text/plain", message); } @@ -680,26 +692,26 @@ void handle_button() { bool button_pressed = !digitalRead(BUTTON_PIN); static bool last_button_state = false; - static unsigned long button_press_start = 0; // time of push button press start + static uint32 button_press_start = 0; // time of push button press start // check rising edge if (button_pressed == true && last_button_state == false) { // button press start logger.log_string("Button press started"); - button_press_start = CURRENT_TIME_MS; + button_press_start = system_get_time(); } // check falling edge if (button_pressed == false && last_button_state == true) { // button press ended - if ((CURRENT_TIME_MS - button_press_start) > LONG_PRESS_MS) + if ((system_get_time() - button_press_start) > LONG_PRESS_US) { // longpress -> nightmode logger.log_string("Button press ended - long press"); set_night_mode(true); } - else if ((CURRENT_TIME_MS - button_press_start) > SHORT_PRESS_MS) + else if ((system_get_time() - button_press_start) > SHORT_PRESS_US) { // shortpress -> state change logger.log_string("Button press ended - short press"); @@ -823,40 +835,40 @@ void handle_command() { String time_str = webserver.arg(0) + "-"; logger.log_string("Nightmode setting change via Webserver to: " + time_str); - night_mode_times.nightmode_start_hour = split(time_str, '-', 0).toInt(); - night_mode_times.nightmode_start_min = split(time_str, '-', 1).toInt(); - night_mode_times.nightmode_end_hour = split(time_str, '-', 2).toInt(); - night_mode_times.nightmode_end_min = split(time_str, '-', 3).toInt(); + night_mode_times.start_hour = split(time_str, '-', 0).toInt(); + night_mode_times.start_min = split(time_str, '-', 1).toInt(); + night_mode_times.end_hour = split(time_str, '-', 2).toInt(); + night_mode_times.end_min = split(time_str, '-', 3).toInt(); brightness = split(time_str, '-', 4).toInt(); if (brightness < 10) { brightness = 10; } - if (night_mode_times.nightmode_start_hour < 0 || night_mode_times.nightmode_start_hour > 23) + if (night_mode_times.start_hour < 0 || night_mode_times.start_hour > 23) { - night_mode_times.nightmode_start_hour = NIGHTMODE_START_HR; + night_mode_times.start_hour = NIGHTMODE_START_HR; } - if (night_mode_times.nightmode_start_min < 0 || night_mode_times.nightmode_start_min > 59) + if (night_mode_times.start_min < 0 || night_mode_times.start_min > 59) { - night_mode_times.nightmode_start_min = NIGHTMODE_START_MIN; + night_mode_times.start_min = NIGHTMODE_START_MIN; } - if (night_mode_times.nightmode_end_hour < 0 || night_mode_times.nightmode_end_hour > 23) + if (night_mode_times.end_hour < 0 || night_mode_times.end_hour > 23) { - night_mode_times.nightmode_end_hour = NIGHTMODE_END_HR; + night_mode_times.end_hour = NIGHTMODE_END_HR; } - if (night_mode_times.nightmode_end_min < 0 || night_mode_times.nightmode_end_min > 59) + if (night_mode_times.end_min < 0 || night_mode_times.end_min > 59) { - night_mode_times.nightmode_end_min = NIGHTMODE_END_MIN; + night_mode_times.end_min = NIGHTMODE_END_MIN; } - EEPROM_write_to_address(ADR_NM_START_H, night_mode_times.nightmode_start_hour); - EEPROM_write_to_address(ADR_NM_START_M, night_mode_times.nightmode_start_min); - EEPROM_write_to_address(ADR_NM_END_H, night_mode_times.nightmode_end_hour); - EEPROM_write_to_address(ADR_NM_END_M, night_mode_times.nightmode_end_min); + EEPROM_write_to_address(ADR_NM_START_H, night_mode_times.start_hour); + EEPROM_write_to_address(ADR_NM_START_M, night_mode_times.start_min); + EEPROM_write_to_address(ADR_NM_END_H, night_mode_times.end_hour); + EEPROM_write_to_address(ADR_NM_END_M, night_mode_times.end_min); EEPROM_write_to_address(ADR_BRIGHTNESS, brightness); - logger.log_string("Nightmode starts at: " + String(night_mode_times.nightmode_start_hour) + ":" + String(night_mode_times.nightmode_start_min)); - logger.log_string("Nightmode ends at: " + String(night_mode_times.nightmode_end_hour) + ":" + String(night_mode_times.nightmode_end_min)); + logger.log_string("Nightmode starts at: " + String(night_mode_times.start_hour) + ":" + String(night_mode_times.start_min)); + logger.log_string("Nightmode ends at: " + String(night_mode_times.end_hour) + ":" + String(night_mode_times.end_min)); logger.log_string("Brightness: " + String(brightness)); led_matrix.set_brightness(brightness); } @@ -969,9 +981,9 @@ void handle_data_request() message += ","; message += "\"night_mode\":\"" + String(night_mode) + "\""; message += ","; - message += "\"nightModeStart\":\"" + leading_zero2digit(night_mode_times.nightmode_start_hour) + "-" + leading_zero2digit(night_mode_times.nightmode_start_min) + "\""; + message += "\"nightModeStart\":\"" + leading_zero2digit(night_mode_times.start_hour) + "-" + leading_zero2digit(night_mode_times.start_min) + "\""; message += ","; - message += "\"nightModeEnd\":\"" + leading_zero2digit(night_mode_times.nightmode_end_hour) + "-" + leading_zero2digit(night_mode_times.nightmode_end_min) + "\""; + message += "\"nightModeEnd\":\"" + leading_zero2digit(night_mode_times.end_hour) + "-" + leading_zero2digit(night_mode_times.end_min) + "\""; message += ","; message += "\"brightness\":\"" + String(brightness) + "\""; }