diff --git a/lib/fallback_log/include/fallback_log.h b/lib/fallback_log/include/fallback_log.h index a61d6ab..64ed9d7 100644 --- a/lib/fallback_log/include/fallback_log.h +++ b/lib/fallback_log/include/fallback_log.h @@ -14,8 +14,8 @@ * The MIT license can be found in the project root and at https://opensource.org/licenses/MIT. */ -#ifndef SRC_FALLBACK_LOG_H_ -#define SRC_FALLBACK_LOG_H_ +#ifndef LIB_FALLBACK_TIMER_INCLUDE_FALLBACK_LOG_H_ +#define LIB_FALLBACK_TIMER_INCLUDE_FALLBACK_LOG_H_ #include #include @@ -77,4 +77,4 @@ #endif #endif -#endif /* SRC_FALLBACK_LOG_H_ */ +#endif /* LIB_FALLBACK_TIMER_INCLUDE_FALLBACK_LOG_H_ */ diff --git a/lib/fallback_timer/README.md b/lib/fallback_timer/README.md new file mode 100644 index 0000000..450257c --- /dev/null +++ b/lib/fallback_timer/README.md @@ -0,0 +1,5 @@ +# Fallback Timer +This tiny library contains an ESP8266 NonOS definition of the ESP RTOS `esp_timer_get_time` function. +This fallback version only works on the ESP8266 NonOS SDK. + +**Warning**: This implementation only works if its called more than once every hour. diff --git a/lib/fallback_timer/include/fallback_timer.h b/lib/fallback_timer/include/fallback_timer.h new file mode 100644 index 0000000..eda433c --- /dev/null +++ b/lib/fallback_timer/include/fallback_timer.h @@ -0,0 +1,43 @@ +/* + * fallback_timer.h + * + * This file contains the header definition for an ESP8266 NonOS fallback definition of the ESP RTOS esp_timer_get_time function. + * + * This fallback relies on being called more than once each hour to function. + * + * Created on: Sep 15, 2024 + * + * Copyright (C) 2023 ToMe25. + * This project is licensed under the MIT License. + * The MIT license can be found in the project root and at https://opensource.org/licenses/MIT. + */ + +#ifndef LIB_FALLBACK_TIMER_INCLUDE_FALLBACK_TIMER_H_ +#define LIB_FALLBACK_TIMER_INCLUDE_FALLBACK_TIMER_H_ + +// Platform IO seems to ignore the platform specification in a local library.json. +#ifdef ESP8266 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Returns the time in microseconds since the ESP was started. + * + * Needs to be called at least once each hour to function. + * + * @return The time in microseconds since the ESP first started. + */ +int64_t esp_timer_get_time(); + + +#ifdef __cplusplus +} +#endif + +#endif /* ESP8266 */ + +#endif /* LIB_FALLBACK_TIMER_INCLUDE_FALLBACK_TIMER_H_ */ diff --git a/lib/fallback_timer/library.json b/lib/fallback_timer/library.json new file mode 100644 index 0000000..4dd813e --- /dev/null +++ b/lib/fallback_timer/library.json @@ -0,0 +1,7 @@ +{ + "name": "FallbackTimer", + "description": "A simple library containing a fallback definition of esp_timer_get_time.", + "version": "1.0.0", + "license": "MIT", + "platforms": [ "espressif8266" ] +} diff --git a/lib/fallback_timer/src/fallback_timer.c b/lib/fallback_timer/src/fallback_timer.c new file mode 100644 index 0000000..2609a3f --- /dev/null +++ b/lib/fallback_timer/src/fallback_timer.c @@ -0,0 +1,40 @@ +/* + * fallback_timer.h + * + * This file contains the implementation for an ESP8266 NonOS fallback definition of the ESP RTOS esp_timer_get_time function. + * + * This fallback relies on being called more than once each hour to function. + * + * Created on: Sep 15, 2024 + * + * Copyright (C) 2023 ToMe25. + * This project is licensed under the MIT License. + * The MIT license can be found in the project root and at https://opensource.org/licenses/MIT. + */ + +// Platform IO seems to ignore the platform specification in a local library.json. +#ifdef ESP8266 + +#include "fallback_timer.h" +#include + +/** + * The current time collected when esp_timer_get_time was last called. + */ +uint32_t last_time = 0; + +/** + * The number of times the current system time overflowed already. + */ +uint32_t time_overflows = 0; + +int64_t esp_timer_get_time() { + const uint32_t now = system_get_time(); + if (now < last_time) { + time_overflows++; + } + last_time = now; + return (((int64_t) time_overflows) << 32) + now; +} + +#endif /* ESP8266 */ diff --git a/src/AsyncTrackingFallbackWebHandler.cpp b/src/AsyncTrackingFallbackWebHandler.cpp index b8b191c..28acb31 100644 --- a/src/AsyncTrackingFallbackWebHandler.cpp +++ b/src/AsyncTrackingFallbackWebHandler.cpp @@ -15,6 +15,9 @@ #endif #include #include +#ifdef ESP8266 +#include +#endif web::AsyncTrackingFallbackWebHandler::AsyncTrackingFallbackWebHandler( const String &uri, HTTPFallbackRequestHandler fallback) : @@ -27,11 +30,13 @@ web::AsyncTrackingFallbackWebHandler::~AsyncTrackingFallbackWebHandler() { } -web::HTTPRequestHandler web::AsyncTrackingFallbackWebHandler::_getHandler(const WebRequestMethod method) const { +web::HTTPRequestHandler web::AsyncTrackingFallbackWebHandler::_getHandler( + const WebRequestMethod method) const { return _handlers[utils::get_msb((WebRequestMethodComposite) method)]; } -void web::AsyncTrackingFallbackWebHandler::setHandler(const WebRequestMethodComposite methods, HTTPRequestHandler handler) { +void web::AsyncTrackingFallbackWebHandler::setHandler( + const WebRequestMethodComposite methods, HTTPRequestHandler handler) { for (size_t i = 0; i < _handlers.size(); i++) { if (methods & (1 << i)) { _handlers[i] = handler; @@ -66,7 +71,7 @@ bool web::AsyncTrackingFallbackWebHandler::canHandle(AsyncWebServerRequest *requ } void web::AsyncTrackingFallbackWebHandler::handleRequest(AsyncWebServerRequest *request) { - const size_t start = micros(); + const uint64_t start = (uint64_t) esp_timer_get_time(); ResponseData response(request->beginResponse(500), 0, 500); HTTPRequestHandler handler = _getHandler((WebRequestMethod) request->method()); if (handler) { @@ -76,19 +81,19 @@ void web::AsyncTrackingFallbackWebHandler::handleRequest(AsyncWebServerRequest * delete response.response; response = _fallbackHandler(getHandledMethods(), request); } else { - log_w("The handler for uri \"%s\" didn't have a handler for request type %s, and didn't have a fallback handler.", + log_w( + "The handler for uri \"%s\" didn't have a handler for request type %s, and didn't have a fallback handler.", _uri.c_str(), request->methodToString()); } #if ENABLE_PROMETHEUS_PUSH == 1 || ENABLE_PROMETHEUS_SCRAPE_SUPPORT == 1 prom::http_requests_total[request->url()][ { (WebRequestMethod) request->method(), response.status_code }]++; #endif - const size_t mid = micros(); + const uint64_t mid = (uint64_t) esp_timer_get_time(); request->send(response.response); - const size_t end = micros(); - log_d("Handling a request to \"%s\" took %luus + %luus.", - request->url().c_str(), (long unsigned int ) (mid - start), - (long unsigned int ) (end - mid)); + const uint64_t end = (uint64_t) esp_timer_get_time(); + log_d("Handling a request to \"%s\" took %lluus + %lluus.", + request->url().c_str(), (mid - start), (end - mid)); } bool web::AsyncTrackingFallbackWebHandler::isRequestHandlerTrivial() { diff --git a/src/main.cpp b/src/main.cpp index b27c8ed..e86fe3f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,8 +16,9 @@ #if ENABLE_ARDUINO_OTA == 1 #include #endif -#if defined(ESP8266) +#if ESP8266 #include +#include #endif #include @@ -229,7 +230,7 @@ void onWiFiEvent(WiFiEvent_t id) { #endif void loop() { - const uint64_t start = millis(); + const uint64_t start = (uint64_t) esp_timer_get_time() / 1000; if (loop_iterations % 4 == 0) { if (sensors::SENSOR_HANDLER.getTimeSinceMeasurement() == -1 @@ -301,7 +302,7 @@ void loop() { mqtt::loop(); loop_iterations++; - const uint64_t end = millis(); + const uint64_t end = (uint64_t) esp_timer_get_time() / 1000; delay(max(0, 500 - int16_t(end - start))); } diff --git a/src/prometheus.cpp b/src/prometheus.cpp index 8e6060a..189caf9 100644 --- a/src/prometheus.cpp +++ b/src/prometheus.cpp @@ -9,7 +9,7 @@ */ #include "prometheus.h" -#if ENABLE_DEEP_SLEEP_MODE == 1 +#if ENABLE_DEEP_SLEEP_MODE == 1 || ENABLE_PROMETHEUS_PUSH == 1 #include "main.h" #endif #include "sensor_handler.h" @@ -378,7 +378,7 @@ void prom::pushMetrics() { } #if ENABLE_DEEP_SLEEP_MODE != 1 - uint64_t now = millis(); + const uint64_t now = (uint64_t) esp_timer_get_time() / 1000; if (now - last_push >= PROMETHEUS_PUSH_INTERVAL * 1000) { #endif tcpClient = new AsyncClient(); @@ -423,7 +423,7 @@ void prom::pushMetrics() { uint32_t code = atoi(status_code); if (code == 200) { #if ENABLE_DEEP_SLEEP_MODE != 1 - uint64_t now = millis(); + const uint64_t now = (uint64_t) esp_timer_get_time() / 1000; if (now - last_push >= (PROMETHEUS_PUSH_INTERVAL + 10) * 1000) { log_i("Successfully pushed again after %lums.", now - last_push); diff --git a/src/sensor_handler.cpp b/src/sensor_handler.cpp index 473ccbd..2c806ae 100644 --- a/src/sensor_handler.cpp +++ b/src/sensor_handler.cpp @@ -16,6 +16,9 @@ #elif SENSOR_TYPE == SENSOR_TYPE_DALLAS #include "sensors/DallasHandler.h" #endif +#ifdef ESP8266 +#include +#endif namespace sensors { @@ -43,13 +46,13 @@ const std::string SensorHandler::getLastHumidityString() { } int64_t SensorHandler::getTimeSinceMeasurement() { - uint32_t now = millis(); + const uint64_t now = (uint64_t) esp_timer_get_time() / 1000; if (_last_finished_request == -1) { return -1; } else if (_last_finished_request < 0) { log_d("Invalid time of last measurement: %lldms.", _last_finished_request); return -1; - } else if (_last_finished_request > now) { + } else if ((uint64_t) _last_finished_request > now) { log_d("Invalid time since last measurement: %lldms.", now - _last_finished_request); return -1; } @@ -58,13 +61,13 @@ int64_t SensorHandler::getTimeSinceMeasurement() { } int64_t SensorHandler::getTimeSinceValidMeasurement() { - uint32_t now = millis(); + const uint64_t now = (uint64_t) esp_timer_get_time() / 1000; if (_last_valid_request == -1) { return -1; } else if (_last_valid_request < 0) { log_d("Invalid time of last valid measurement: %lldms.", _last_valid_request); return -1; - } else if (_last_valid_request > now) { + } else if ((uint64_t) _last_valid_request > now) { log_d("Invalid time since last valid measurement: %lldms.", now - _last_valid_request); return -1; } diff --git a/src/sensors/DHTHandler.cpp b/src/sensors/DHTHandler.cpp index e2bb295..f42be16 100644 --- a/src/sensors/DHTHandler.cpp +++ b/src/sensors/DHTHandler.cpp @@ -10,6 +10,9 @@ #include "sensors/DHTHandler.h" #include +#ifdef ESP8266 +#include +#endif namespace sensors { @@ -27,8 +30,8 @@ bool DHTHandler::begin() { } bool DHTHandler::requestMeasurement() { - const uint32_t now = millis(); - if (_last_request == -1 || now - (uint32_t) _last_request >= MIN_INTERVAL) { + const uint64_t now = (uint64_t) esp_timer_get_time() / 1000; + if (_last_request == -1 || now - (uint64_t) _last_request >= MIN_INTERVAL) { _last_request = now; if (!_dht.read(false)) { _temperature = _humidity = NAN; @@ -52,8 +55,8 @@ bool DHTHandler::requestMeasurement() { return true; } else { log_i("Attempted to read sensor data before minimum delay."); - log_d("Min delay: %ums, Time since measurement: %ums", - (uint32_t) MIN_INTERVAL, (now - (uint32_t) _last_request)); + log_d("Min delay: %hums, Time since measurement: %llums", + MIN_INTERVAL, (now - (uint64_t) _last_request)); return false; } } diff --git a/src/sensors/DallasHandler.cpp b/src/sensors/DallasHandler.cpp index c4c7825..2430b49 100644 --- a/src/sensors/DallasHandler.cpp +++ b/src/sensors/DallasHandler.cpp @@ -10,6 +10,9 @@ #include "sensors/DallasHandler.h" #include +#ifdef ESP8266 +#include +#endif namespace sensors { @@ -40,12 +43,12 @@ bool DallasHandler::begin() { } bool DallasHandler::requestMeasurement() { - uint32_t now = millis(); - if (_last_request == -1 || now - (uint32_t) _last_request >= MIN_INTERVAL) { + uint64_t now = (uint64_t) esp_timer_get_time() / 1000; + if (_last_request == -1 || now - (uint64_t) _last_request >= MIN_INTERVAL) { // Read previous measurements, if they weren't read yet. if (_last_request > _last_finished_request) { getTemperature(); - now = millis(); + now = (uint64_t) esp_timer_get_time() / 1000; } _last_request = now; @@ -66,8 +69,8 @@ bool DallasHandler::requestMeasurement() { return true; } else { log_i("Attempted to read sensor data before minimum delay."); - log_d("Min delay: %ums, Time since measurement: %ums", - (uint32_t) MIN_INTERVAL, (now - (uint32_t) _last_request)); + log_d("Min delay: %hums, Time since measurement: %llums", MIN_INTERVAL, + (now - (uint64_t) _last_request)); return false; } } @@ -77,8 +80,9 @@ bool DallasHandler::supportsTemperature() const { } float DallasHandler::getTemperature() { + const uint64_t now = (uint64_t) esp_timer_get_time() / 1000; if (_last_request > _last_finished_request - && millis() - (uint32_t) _last_request >= MIN_INTERVAL) { + && now - (uint64_t) _last_request >= MIN_INTERVAL) { DeviceAddress address; if (!_sensors.getAddress(address, SENSOR_INDEX)) { log_w("Failed to get address for sensor %u.", SENSOR_INDEX); @@ -116,8 +120,9 @@ float DallasHandler::getTemperature() { } float DallasHandler::getLastTemperature() { + const uint64_t now = (uint64_t) esp_timer_get_time() / 1000; if (_last_request > _last_finished_request - && millis() - _last_request >= MIN_INTERVAL) { + && now - (uint64_t) _last_request >= MIN_INTERVAL) { getTemperature(); } return _last_valid_temperature; diff --git a/src/webhandler.cpp b/src/webhandler.cpp index 7435cbd..1302a5b 100644 --- a/src/webhandler.cpp +++ b/src/webhandler.cpp @@ -22,6 +22,9 @@ #include #endif #include +#if ENABLE_TIMINGS_API == 1 && defined(ESP8266) +#include +#endif #endif /* ENABLE_WEB_SERVER == 1 */ #if ENABLE_WEB_SERVER == 1 @@ -80,7 +83,7 @@ void web::setup() { #if ENABLE_TIMINGS_API == 1 registerRequestHandler("/timings/since_startup_ms", HTTP_GET, [](AsyncWebServerRequest *request) -> ResponseData { - const String str = String(millis()); + const String str = String(esp_timer_get_time() / 1000); AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", str.c_str()); response->addHeader("Cache-Control", CACHE_CONTROL_NOCACHE); @@ -110,7 +113,6 @@ void web::setup() { registerStaticHandler("/timings/info", "text/plain", "This directory contains various timing informations.\n" "A list of these endpoints is currently not available.\n" - "The precision of these timings may not be ideal because the millis function returns an unsigned 32 bit interger that wraps after ~50 days.\n" "All endpoints return values in milliseconds."); registerRedirect("/timings", "/timings/info");