diff --git a/include/config.h b/include/config.h index b0148e7..4d753f3 100644 --- a/include/config.h +++ b/include/config.h @@ -1,5 +1,4 @@ #pragma once - #include #include #include @@ -45,8 +44,8 @@ static const ConfigDef configdefs[] = { {"apMask", ConfigType::STRING, String("255.255.255.0")}, {"stopApTime", ConfigType::SHORT, int16_t(0)}, {"cpuSpeed", ConfigType::SHORT, int16_t(160)}, - {"ledBrightness", ConfigType::BYTE, uint8_t(96)}, - {"ledRgbBrightness", ConfigType::BYTE, uint8_t(96)}, + {"ledBrightness", ConfigType::SHORT, int16_t(96)}, + {"ledRgbBrightness", ConfigType::SHORT, int16_t(96)}, {"tempFormat", ConfigType::CHAR, 'C'}, {"switchBank", ConfigType::BYTE, uint8_t(0)}, {"key1", ConfigType::BYTE, uint8_t(1)}, @@ -76,6 +75,7 @@ private: Preferences& prefs; std::map values; std::map defs; + [[noreturn]] void error_abort() const; public: explicit Config(Preferences& prefs); void load(); @@ -92,4 +92,8 @@ public: float getFloat(const char* key) const; char getChar(const char* key) const; const String& getString(const char* key) const; + const char* getCString(const char* key) const; + }; + +extern Config config; diff --git a/include/hash.h b/include/hash.h new file mode 100644 index 0000000..f5f5aaf --- /dev/null +++ b/include/hash.h @@ -0,0 +1,4 @@ +#pragma once +#include + +String get_sha256(String payload); diff --git a/include/led.h b/include/led.h new file mode 100644 index 0000000..1a57cfa --- /dev/null +++ b/include/led.h @@ -0,0 +1,8 @@ +#pragma once + +extern int16_t led_brightness; +extern int16_t rgb_brightness; + +void led_init(); +void led_test(); +void led_blink(uint8_t channel, uint8_t count, int16_t brightness, uint32_t interval_ms); diff --git a/include/main.h b/include/main.h index 7072124..f334882 100644 --- a/include/main.h +++ b/include/main.h @@ -1,5 +1,7 @@ #pragma once #include +#include "Nmea2kTwai.h" +#include "N2kDeviceList.h" #define STRINGIFY_IMPL(x) #x #define STRINGIFY(x) STRINGIFY_IMPL(x) @@ -40,11 +42,23 @@ #define KEY_6 GPIO_NUM_10 // D7 #define KEY_DST GPIO_NUM_17 // D8 +// LEDC / PWM channels +#define LEDC_BUZZER 0 +#define LEDC_LED_A 1 +#define LEDC_LED_B 2 +#define LEDC_LED_C 3 +#define LEDC_RGBLED_R 4 +#define LEDC_RGBLED_G 5 +#define LEDC_RGBLED_B 6 + +#define LEDC_BASE_FREQ 5000 +#define LEDC_RES_BUZZER 8 // 8bit: 0..255 +#define LEDC_RES_LED 12 // 12bit: 0..4095 + +// #define LEDC_TIMER_8_BIT 8 + // Buzzer #define BUZZER GPIO_NUM_43 // TX -#define LEDC_CHANNEL 0 -#define LEDC_TIMER_8_BIT 8 -#define LEDC_BASE_FREQ 5000 // LEDS #define LED_A GPIO_NUM_3 // A2 @@ -99,13 +113,17 @@ struct ButtonEvent { ButtonPressType pressType; }; +extern Nmea2kTwai &NMEA2000; +extern tN2kDeviceList *pN2kDeviceList; + +extern char globalmode; + extern uint64_t chipid; -extern uint8_t led_brightness; -extern uint8_t rgb_brightness; +extern int16_t led_brightness; +extern int16_t rgb_brightness; extern uint8_t keycode[6]; extern uint8_t longcode[6]; extern float temp; extern float hum; -String uptime_with_unit(); diff --git a/include/webserver.h b/include/webserver.h index 3be2ffc..1ac944f 100644 --- a/include/webserver.h +++ b/include/webserver.h @@ -1,7 +1,5 @@ #pragma once - #include - #include extern AsyncWebServer server; diff --git a/src/config.cpp b/src/config.cpp index ebf5375..e87bf1d 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1,8 +1,12 @@ #include "config.h" +#include "esp_rom_uart.h" // for uart wait idle // Logging static const char* TAG = "CFG"; +Preferences preferences; // persistent storage for configuration +Config config(preferences); // configuration object + Config::Config(Preferences& prefs) : prefs(prefs) { @@ -13,12 +17,19 @@ Config::Config(Preferences& prefs) } +[[noreturn]] void Config::error_abort() const { + ESP_LOGD(TAG, "Rebooting in about 2 seconds"); + esp_rom_uart_tx_wait_idle(0); + delay(2000); // to have a chance to read + abort(); +} + void Config::load() { - ESP_LOGI(TAG, "Loading configuration"); + ESP_LOGD(TAG, "Loading configuration"); prefs.begin(PREF_NAME, true); for (const auto& def : configdefs) { if (prefs.isKey(def.key)) { - ESP_LOGI(TAG, "Config option '%s' loaded from NVS", def.key); + ESP_LOGD(TAG, "Config option '%s' loaded from NVS", def.key); switch (def.type) { case ConfigType::BYTE: values[def.key] = (uint8_t)prefs.getUChar(def.key, std::get(def.defval)); @@ -43,7 +54,7 @@ void Config::load() { break; } } else { - ESP_LOGI(TAG, "Using default for '%s'", def.key); + ESP_LOGD(TAG, "Using default for '%s'", def.key); switch (def.type) { case ConfigType::BYTE: values[def.key] = std::get(def.defval); @@ -204,36 +215,36 @@ uint8_t Config::getByte(const char* key) const { auto it = values.find(key); if (it == values.end()) { ESP_LOGE(TAG, "Missing config key: %s", key); - abort(); + error_abort(); } if (auto v = std::get_if(&it->second)) return *v; ESP_LOGE(TAG, "Type mismatch for key: %s", key); - abort(); + error_abort(); } int16_t Config::getShort(const char* key) const { auto it = values.find(key); if (it == values.end()) { ESP_LOGE(TAG, "Missing config key: %s", key); - abort(); + error_abort(); } if (auto v = std::get_if(&it->second)) return *v; ESP_LOGE(TAG, "Type mismatch for key: %s", key); - abort(); + error_abort(); } int32_t Config::getInt(const char* key) const { auto it = values.find(key); if (it == values.end()) { ESP_LOGE(TAG, "Missing config key: %s", key); - abort(); + error_abort(); } if (auto v = std::get_if(&it->second)) return *v; ESP_LOGE(TAG, "Type mismatch for key: %s", key); - abort(); + error_abort(); } bool Config::getBool(const char* key) const { @@ -251,34 +262,38 @@ float Config::getFloat(const char* key) const { auto it = values.find(key); if (it == values.end()) { ESP_LOGE(TAG, "Missing config key: %s", key); - abort(); + error_abort(); } if (auto v = std::get_if(&it->second)) return *v; ESP_LOGE(TAG, "Type mismatch for key: %s", key); - abort(); + error_abort(); } char Config::getChar(const char* key) const { auto it = values.find(key); if (it == values.end()) { ESP_LOGE(TAG, "Missing config key: %s", key); - abort(); + error_abort(); } if (auto v = std::get_if(&it->second)) return *v; ESP_LOGE(TAG, "Type mismatch for key: %s", key); - abort(); + error_abort(); } const String& Config::getString(const char* key) const { auto it = values.find(key); if (it == values.end()) { ESP_LOGE(TAG, "Missing config key: %s", key); - abort(); + error_abort(); } if (auto v = std::get_if(&it->second)) return *v; ESP_LOGE(TAG, "Type mismatch for key: %s", key); - abort(); + error_abort(); +} + +const char* Config::getCString(const char* key) const { + return getString(key).c_str(); } diff --git a/src/hash.cpp b/src/hash.cpp new file mode 100644 index 0000000..6bfb2ec --- /dev/null +++ b/src/hash.cpp @@ -0,0 +1,32 @@ +#include "hash.h" +#include "mbedtls/md.h" // for SHA256 + +String get_sha256(String payload) { + byte shaResult[32]; + mbedtls_md_context_t ctx; + mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256; + mbedtls_md_init(&ctx); + mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0); + mbedtls_md_starts(&ctx); + mbedtls_md_update(&ctx, (const unsigned char *) payload.c_str(), payload.length()); + mbedtls_md_finish(&ctx, shaResult); + mbedtls_md_free(&ctx); + // convert to hex string + char buffer[sizeof(shaResult)*2 + 1]; + const char hexmap[] = "0123456789abcdef"; + for (int i = 0; i < sizeof(shaResult); i++) { + buffer[i*2] = hexmap[(shaResult[i] >> 4) & 0x0F]; + buffer[i*2+1] = hexmap[shaResult[i] & 0x0F]; + } + buffer[sizeof(buffer) - 1] = '\0'; + String hash = String(buffer); + + Serial.print("SHA256 payload: "); + Serial.print(payload); + Serial.println(); + Serial.print("SHA256-Hash: "); + Serial.print(hash); + Serial.println(); + + return hash; +} diff --git a/src/led.cpp b/src/led.cpp new file mode 100644 index 0000000..963d18e --- /dev/null +++ b/src/led.cpp @@ -0,0 +1,95 @@ +#include "main.h" +#include "led.h" + +// Logging +static const char* TAG = "LED"; + +int16_t led_brightness = 512; // analog pin with ledc: 0 .. 4095 +int16_t rgb_brightness = 768; + +void led_init() { + + // internal user led (red) + digitalWrite(LED_USER, HIGH); + delay(1000); + digitalWrite(LED_USER, LOW); + + // LEDC + ledcSetup(LEDC_BUZZER, LEDC_BASE_FREQ, LEDC_RES_BUZZER); + ledcSetup(LEDC_LED_A, LEDC_BASE_FREQ, LEDC_RES_LED); + ledcSetup(LEDC_LED_B, LEDC_BASE_FREQ, LEDC_RES_LED); + ledcSetup(LEDC_LED_C, LEDC_BASE_FREQ, LEDC_RES_LED); + ledcSetup(LEDC_RGBLED_R, LEDC_BASE_FREQ, LEDC_RES_LED); + ledcSetup(LEDC_RGBLED_G, LEDC_BASE_FREQ, LEDC_RES_LED); + ledcSetup(LEDC_RGBLED_B, LEDC_BASE_FREQ, LEDC_RES_LED); + + ledcAttachPin(LED_A, LEDC_LED_A); + ledcAttachPin(LED_B, LEDC_LED_B); + ledcAttachPin(LED_C, LEDC_LED_C); + ledcAttachPin(RGBLED_R, LEDC_RGBLED_R); + ledcAttachPin(RGBLED_G, LEDC_RGBLED_G); + ledcAttachPin(RGBLED_B, LEDC_RGBLED_B); + +} + +void led_test() { + // all led one after another to test functionality + + ESP_LOGI(TAG, "LED test started"); + + // Onbard RGB LED, inverted mode + digitalWrite(LED_IR, LOW); + digitalWrite(LED_IG, HIGH); + digitalWrite(LED_IB, HIGH); + delay(500); + digitalWrite(LED_IR, HIGH); + digitalWrite(LED_IG, LOW); + delay(500); + digitalWrite(LED_IG, HIGH); + digitalWrite(LED_IB, LOW); + delay(500); + digitalWrite(LED_IB, HIGH); + + // destination leds + ledcWrite(LEDC_LED_A, 0); + delay(250); + // test every led + ledcWrite(LEDC_LED_A, led_brightness); + ledcWrite(LEDC_LED_B, 0); + ledcWrite(LEDC_LED_C, 0); + delay(500); + ledcWrite(LEDC_LED_A, 0); + ledcWrite(LEDC_LED_B, led_brightness); + delay(500); + ledcWrite(LEDC_LED_B, 0); + ledcWrite(LEDC_LED_C, led_brightness); + delay(500); + ledcWrite(LEDC_LED_C, 0); + + // enclosure rgb led (common cathode, so low is off) + ledcWrite(LEDC_RGBLED_R, rgb_brightness); + ledcWrite(LEDC_RGBLED_G, 0); + ledcWrite(LEDC_RGBLED_B, 0); + delay(700); + ledcWrite(LEDC_RGBLED_R, 0); + ledcWrite(LEDC_RGBLED_G, rgb_brightness); + delay(700); + ledcWrite(LEDC_RGBLED_G, 0); + ledcWrite(LEDC_RGBLED_B, rgb_brightness); + delay(700); + ledcWrite(LEDC_RGBLED_B, 0); + + ESP_LOGI(TAG, "LED test finished"); + +} + +void led_blink(uint8_t channel, uint8_t count, int16_t brightness, uint32_t interval_ms) { + ledcWrite(channel, 0); + for (uint16_t i = 0; i < count; i++) { + delay(interval_ms); + ledcWrite(channel, brightness); + delay(interval_ms); + ledcWrite(channel, 0); + } + delay(interval_ms); +} diff --git a/src/main.cpp b/src/main.cpp index c516434..5c26661 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,8 @@ #include "main.h" #include "config.h" #include "webserver.h" +#include "led.h" +#include "hash.h" #include #include #include @@ -8,14 +10,12 @@ #include #include #include -#include "Nmea2kTwai.h" -#include "N2kDeviceList.h" #include -#include "mbedtls/md.h" // for SHA256 #include // for cpu frequency #include "driver/rtc_io.h" // for wakeup from deep sleep #include "esp_app_format.h" // for custom fw descriptor +#include "esp_rom_uart.h" // for uart wait idle // ESP-IDF firmware descriptor __attribute__((section(".rodata_custom_desc"))) esp_app_desc_t custom_app_desc = { @@ -31,53 +31,18 @@ __attribute__((section(".rodata_custom_desc"))) esp_app_desc_t custom_app_desc = {} }; -String get_sha256(String payload) { - byte shaResult[32]; - mbedtls_md_context_t ctx; - mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256; - mbedtls_md_init(&ctx); - mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0); - mbedtls_md_starts(&ctx); - mbedtls_md_update(&ctx, (const unsigned char *) payload.c_str(), payload.length()); - mbedtls_md_finish(&ctx, shaResult); - mbedtls_md_free(&ctx); - // convert to hex string - char buffer[sizeof(shaResult)*2 + 1]; - const char hexmap[] = "0123456789abcdef"; - for (int i = 0; i < sizeof(shaResult); i++) { - buffer[i*2] = hexmap[(shaResult[i] >> 4) & 0x0F]; - buffer[i*2+1] = hexmap[shaResult[i] & 0x0F]; - } - buffer[sizeof(buffer) - 1] = '\0'; - String hash = String(buffer); - - Serial.print("SHA256 payload: "); - Serial.print(payload); - Serial.println(); - Serial.print("SHA256-Hash: "); - Serial.print(hash); - Serial.println(); - - return hash; -} - // Logging static const char* TAG = "MAIN"; -Preferences preferences; // persistent storage for configuration -Config config(preferences); // configuration object - uint64_t chipid = ESP.getEfuseMac(); const char* wifi_ssid = "OBPKP61"; const char* wifi_pass = "keypad61"; -bool apEnabled = false; -// AsyncWebServer server(80); +bool ap_enabled = false; unsigned long firstStart = 0; unsigned long lastSensor = 0; unsigned long lastPrint = 0; -unsigned long counter = 0; bool rgb_r = false; bool rgb_g = false; @@ -85,13 +50,11 @@ bool rgb_b = false; int cpuspeed = 240; // MHz -char globalmode = 'K'; // (K)eyboard | (A)utopilot | (L)ogbook -char mode = 'N'; // (N)ormal | (C)onfig -char ledmode = 'D'; // (D)ay | (N)ight -char audiomode = 'E'; // (E)nabled | (D)isabled +RTC_DATA_ATTR char globalmode = 'K'; // (K)eyboard | (A)utopilot | (L)ogbook +char mode = 'N'; // (N)ormal | (C)onfig -> do not store for reset! +RTC_DATA_ATTR char ledmode = 'D'; // (D)ay | (N)ight +RTC_DATA_ATTR char audiomode = 'E'; // (E)nabled | (D)isabled RTC_DATA_ATTR char destination = 'A'; // A | B | C im RTC-Speicher überlebt deep sleep -uint8_t led_brightness = 16; // analog pin: 0 .. 255 -uint8_t rgb_brightness = 64; uint buzzerpower = 50; // TBD make use of this @@ -103,7 +66,7 @@ bool sht_available = false; float temp = 0.0; float hum = 0.0; -int nodeid; // NMEA2000 id on bus +uint8_t nodeid; // NMEA2000 id on bus Nmea2kTwai &NMEA2000=*(new Nmea2kTwai(CAN_TX, CAN_RX, CAN_RECOVERY_PERIOD)); tN2kDeviceList *pN2kDeviceList; @@ -112,77 +75,6 @@ String processor(const String& var) { return ""; } -String uptime_with_unit() { - int64_t uptime = esp_timer_get_time() / 1000000; - String uptime_unit; - if (uptime < 120) { - uptime_unit = " seconds"; - } else { - if (uptime < 2 * 3600) { - uptime /= 60; - uptime_unit = " minutes"; - } else if (uptime < 2 * 3600 * 24) { - uptime /= 3600; - uptime_unit = " hours"; - } else { - uptime /= 86400; - uptime_unit = " days"; - } - } - return String(uptime) + " " + uptime_unit; -} - -void ledtest() { - // all led one after another to test functionality - - Serial.println("LED test started"); - - // Onbard RGB LED, inverted mode - digitalWrite(LED_IR, LOW); - digitalWrite(LED_IG, HIGH); - digitalWrite(LED_IB, HIGH); - delay(500); - digitalWrite(LED_IR, HIGH); - digitalWrite(LED_IG, LOW); - delay(500); - digitalWrite(LED_IG, HIGH); - digitalWrite(LED_IB, LOW); - delay(500); - digitalWrite(LED_IB, HIGH); - - // destination leds - analogWrite(LED_A, 0); - delay(250); - // test every led - analogWrite(LED_A, led_brightness); - analogWrite(LED_B, 0); - analogWrite(LED_C, 0); - delay(500); - analogWrite(LED_A, 0); - analogWrite(LED_B, led_brightness); - delay(500); - analogWrite(LED_B, 0); - analogWrite(LED_C, led_brightness); - delay(500); - analogWrite(LED_C, 0); - - // enclosure rgb led (common cathode, so low is off) - analogWrite(RGBLED_R, rgb_brightness); - analogWrite(RGBLED_G, 0); - analogWrite(RGBLED_B, 0); - delay(700); - analogWrite(RGBLED_R, 0); - analogWrite(RGBLED_G, rgb_brightness); - delay(700); - analogWrite(RGBLED_G, 0); - analogWrite(RGBLED_B, rgb_brightness); - delay(700); - analogWrite(RGBLED_B, 0); - - Serial.println("LED test finished"); - -} - TaskHandle_t ledTaskHandle = NULL; TaskHandle_t sensorTaskHandle = NULL; TaskHandle_t keyTaskHandle = NULL; @@ -191,17 +83,17 @@ QueueHandle_t ledQueue = NULL; QueueHandle_t keyQueue = NULL; void ledTask(void *parameter) { - Serial.println("Starting LED task"); + ESP_LOGI(TAG, "Starting LED task"); for (;;) { vTaskDelay(5000); - analogWrite(RGBLED_G, 10); // a short activity flash + ledcWrite(LEDC_RGBLED_G, 160); // a short activity flash vTaskDelay(20); - analogWrite(RGBLED_G, 0); + ledcWrite(LEDC_RGBLED_G, 0); } } void sensorTask(void *parameter) { - Serial.println("Starting sensor task"); + ESP_LOGI(TAG, "Starting sensor task"); for (;;) { vTaskDelay(10000); // nothing yet } @@ -211,7 +103,7 @@ void keyTask(void *parameter) { // short key press <= 1s // medium key press >1s and < 3s // long key press >= 3s - Serial.println("Starting keyboard task"); + ESP_LOGI(TAG, "Starting keyboard task"); constexpr uint8_t NUM_BUTTONS = 7; constexpr gpio_num_t buttonPins[NUM_BUTTONS] = { @@ -268,12 +160,12 @@ void keyTask(void *parameter) { } void stopApTimerCallback(TimerHandle_t xTimer) { - Serial.println("reached AP switchoff time: accesspoint switched off "); + ESP_LOGI(TAG, "reached AP switchoff time: accesspoint switched off "); WiFi.softAPdisconnect(true); } void cpuFreqTimerCallback(TimerHandle_t xTimer) { - Serial.println("after 3 minutes: set CPU frequency to 160MHz"); + ESP_LOGI(TAG, "after 3 minutes: set CPU frequency to 160MHz"); setCpuFrequencyMhz(cpuspeed); } @@ -315,10 +207,10 @@ void setup() { pinMode(KEY_6, INPUT_PULLUP); pinMode(KEY_DST, INPUT_PULLUP); - // Early signal system activity - analogWrite(RGBLED_R, 255); - analogWrite(RGBLED_G, 0); - analogWrite(RGBLED_B, 0); + // Early signal system activity, red while booting + digitalWrite(RGBLED_R, HIGH); + digitalWrite(RGBLED_G, LOW); + digitalWrite(RGBLED_B, LOW); // Arduino ESP32 logging esp_log_level_set("*", ESP_LOG_INFO); @@ -348,7 +240,7 @@ void setup() { esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); if (cause == ESP_SLEEP_WAKEUP_EXT0) { - ESP_LOGI(TAG, " Wake up by key"); + ESP_LOGI(TAG, "Wake up by key"); } else { destination = 'A'; } @@ -356,9 +248,10 @@ void setup() { // N2K basics nodeid = N2K_DEFAULT_NODEID; ESP_LOGI(TAG, "N2K default node is %d", nodeid); - preferences.begin(PREF_NAME, false); - nodeid = preferences.getInt("LastNodeId", N2K_DEFAULT_NODEID); - preferences.end(); + //preferences.begin(PREF_NAME, false); + //nodeid = preferences.getInt("LastNodeId", N2K_DEFAULT_NODEID); + //preferences.end(); + nodeid = config.getByte("LastNodeId"); ESP_LOGI(TAG, "N2K node id set to %d from preferences", nodeid); //cpuspeed = preferences.getInt("cpuSpeed", 160); @@ -392,37 +285,10 @@ void setup() { IPAddress ap_gateway(ap_addr); WiFi.softAPConfig(ap_addr, ap_gateway, ap_subnet); - apEnabled = true; + ap_enabled = true; // Initialize WebGUI webserver_init(); - - server.on("/api/devicelist", HTTP_GET, [](AsyncWebServerRequest *request){ - // NMEA2000 device list - AsyncResponseStream *response = request->beginResponseStream("application/json"); - response->print("["); - bool first = true; - for (int i = 0; i <= 252; i++) { - const tNMEA2000::tDevice *d = pN2kDeviceList->FindDeviceBySource(i); - if (d == nullptr) { - continue; - } - uint64_t NAME = d->GetName(); - char hex_name[17]; - snprintf(hex_name, sizeof(hex_name), "%08X%08X", (uint32_t)(NAME >> 32), (uint32_t)(NAME & 0xFFFFFFFF)); - if (!first) { - response->print(","); - } else { - first = false; - } - // TODO last seen? - response->printf("{\"source\":%d,\"name\":\"%s\",\"manuf\":\"%d\",\"model\":\"%s\"}", - i, hex_name, d->GetManufacturerCode(), d->GetModelID()); - } - response->print("]"); - request->send(response); - }); - // Start HTTP Webserver server.begin(); @@ -486,52 +352,50 @@ void setup() { // Debug: NMEA2000.EnableForward(true); NMEA2000.Open(); - // internal user led (red) - digitalWrite(LED_USER, HIGH); - delay(1000); - digitalWrite(LED_USER, LOW); + + + led_init(); // Buzzer - ledcSetup(LEDC_CHANNEL, LEDC_BASE_FREQ, LEDC_TIMER_8_BIT); - ledcAttachPin(BUZZER, LEDC_CHANNEL); + ledcAttachPin(BUZZER, LEDC_BUZZER); // Test tone while booting // Buzzer 12V, 2500Hz +/- 200Hz, 30mA, ca. 90dB - if (ledcWriteTone(LEDC_CHANNEL, 2300) == 0) { + if (ledcWriteTone(LEDC_BUZZER, 2300) == 0) { Serial.println("Error setting buzzer tone"); } else { delay(50); - ledcWriteTone(LEDC_CHANNEL, 0); // Buzzer off + ledcWriteTone(LEDC_BUZZER, 0); // Buzzer off } // Startup sequence: test all led and short beep buzzer - analogWrite(RGBLED_R, 0); // boot status off + digitalWrite(RGBLED_R, LOW); // boot status off delay(500); - ledtest(); + led_test(); // select current destination switch (destination) { case 'A': - analogWrite(LED_A, led_brightness); + ledcWrite(LEDC_LED_A, led_brightness); break; case 'B': - analogWrite(LED_B, led_brightness); + ledcWrite(LEDC_LED_B, led_brightness); break; case 'C': - analogWrite(LED_C, led_brightness); + ledcWrite(LEDC_LED_C, led_brightness); break; } // I²C - Serial.print("SHT31_LIB_VERSION: "); - Serial.println(SHT31_LIB_VERSION); + // Serial.print("SHT31_LIB_VERSION: "); + // Serial.println(SHT31_LIB_VERSION); + ESP_LOGI(TAG, "SHT31_LIB_VERSION: %s", SHT31_LIB_VERSION); Wire.begin(I2C_SDA, I2C_SCL); Wire.setClock(I2C_SPEED); uint16_t stat = sht.readStatus(); // stat = ffff anscheinend Fehler // = 8010 läuft anscheinend sht_available = (stat == 0x8010); - Serial.print(stat, HEX); - Serial.println(); + ESP_LOGI(TAG, "SHT31 state=0x%X", stat); // Additional tests String passhash = get_sha256("secretTEST"); @@ -553,10 +417,10 @@ void setup() { ledQueue = xQueueCreate(5, sizeof(uint8_t)); if (esp_sleep_is_valid_wakeup_gpio(KEY_DST)) { - Serial.println("DST-Taste ist als Wakeup-Pin konfiguriert"); + ESP_LOGI(TAG, "DST-key configured as wakeup-pin"); esp_sleep_enable_ext0_wakeup(KEY_DST, 0); } else { - Serial.println("Keine Wakeup-Funktion vorhanden! Deep-sleep deaktiviert."); + ESP_LOGI(TAG, "No wakeup feature available! Deep-sleep disabled."); } if (cpuspeed < 240) { @@ -584,19 +448,19 @@ void setup() { } void shortBeep() { - ledcWriteTone(LEDC_CHANNEL, 2500); + ledcWriteTone(LEDC_BUZZER, 2500); delay(15); - ledcWriteTone(LEDC_CHANNEL, 0); + ledcWriteTone(LEDC_BUZZER, 0); } void atariKeyclick() { - ledcWriteTone(LEDC_CHANNEL, 3200); + ledcWriteTone(LEDC_BUZZER, 3200); delayMicroseconds(3000); - ledcWriteTone(LEDC_CHANNEL, 0); + ledcWriteTone(LEDC_BUZZER, 0); delayMicroseconds(800); - ledcWriteTone(LEDC_CHANNEL, 3200); + ledcWriteTone(LEDC_BUZZER, 3200); delayMicroseconds(2000); - ledcWriteTone(LEDC_CHANNEL, 0); + ledcWriteTone(LEDC_BUZZER, 0); } void print_n2k_devicelist() { @@ -658,7 +522,7 @@ void send_sensor_temphum(float temp_k, float hum_perc) { unsigned char instance = 0; tN2kTempSource temp_src = N2kts_OutsideTemperature; // 1=outside, 2=inside tN2kHumiditySource hum_src = N2khs_OutsideHumidity; // 0=inside, 1=outside - Serial.printf("Sending temp=%f K, hum=%f %%\n", temp_k, hum_perc); + ESP_LOGI(TAG, "Sending temp=%f K, hum=%f %%", temp_k, hum_perc); SetN2kPGN130312(N2kMsg, SID, instance, temp_src, temp_k); NMEA2000.SendMsg(N2kMsg); SetN2kPGN130313(N2kMsg, SID, instance, hum_src, hum_perc); @@ -670,55 +534,37 @@ void loop() { ButtonEvent event; if (xQueueReceive(keyQueue, &event, 0) == pdPASS) { - Serial.print("Button "); - Serial.print(event.buttonId); - Serial.print(" -> "); - switch (event.pressType) { - case ButtonPressType::SHORT: - Serial.println("SHORT"); - break; - case ButtonPressType::MEDIUM: - Serial.println("MEDIUM"); - break; - case ButtonPressType::LONG: - Serial.println("LONG"); - break; - default: - Serial.print("UNBEKANNT: "); - Serial.println(static_cast(event.pressType)); - break; - } if (event.buttonId == BUTTON_DST) { + // destination / mode button if (event.pressType == ButtonPressType::SHORT) { if (mode == 'N') { // switch destination only in normal mode if (destination == 'A') { destination = 'B'; - analogWrite(LED_A, 0); - analogWrite(LED_B, led_brightness); + ledcWrite(LEDC_LED_A, 0); + ledcWrite(LEDC_LED_B, led_brightness); } else if (destination == 'B') { destination = 'C'; - analogWrite(LED_B, 0); - analogWrite(LED_C, led_brightness); + ledcWrite(LEDC_LED_B, 0); + ledcWrite(LEDC_LED_C, led_brightness); } else { destination = 'A'; - analogWrite(LED_C, 0); - analogWrite(LED_A, led_brightness); + ledcWrite(LEDC_LED_C, 0); + ledcWrite(LEDC_LED_A, led_brightness); } - Serial.print("New destination="); - Serial.println(destination); + ESP_LOGI(TAG, "New destination=%s", destination); } } else if (event.pressType == ButtonPressType::LONG) { shortBeep(); // switch config mode if (mode == 'N') { mode = 'C'; - analogWrite(RGBLED_B, rgb_brightness); // blue status indicator - Serial.println("Entering config mode"); + ledcWrite(LEDC_RGBLED_B, rgb_brightness); // blue status indicator + ESP_LOGI(TAG, "Entering config mode"); } else { mode = 'N'; - analogWrite(RGBLED_B, 0); - Serial.println("Leaving config mode"); + ledcWrite(LEDC_RGBLED_B, 0); + ESP_LOGI(TAG, "Leaving config mode"); } } } else { @@ -742,71 +588,48 @@ void loop() { switch (event.buttonId) { case BUTTON_1: // switch day/night mode if (ledmode == 'D') { - Serial.println("Night mode enabled"); + ESP_LOGI(TAG, "Night mode enabled"); ledmode = 'N'; } else { - Serial.println("Day mode enabled"); + ESP_LOGI(TAG, "Day mode enabled"); ledmode = 'D'; } break; case BUTTON_2: // switch audio on/off if (audiomode == 'E') { - Serial.println("Disabled audio"); + ESP_LOGI(TAG, "Disabled audio"); audiomode = 'D'; } else { - Serial.println("Enabled audio"); + ESP_LOGI(TAG, "Enabled audio"); audiomode = 'E'; } break; case BUTTON_3: // switch accesspoint on/off - if (apEnabled) { - Serial.println("Disable Accesspoint"); + if (ap_enabled) { + ESP_LOGI(TAG, "Disable Accesspoint"); WiFi.softAPdisconnect(true); - apEnabled = false; + ap_enabled = false; } else { Serial.println("Enable Accesspoint"); WiFi.softAP(wifi_ssid, wifi_pass); - apEnabled = true; + ap_enabled = true; } break; case BUTTON_4: // reserved break; case BUTTON_5: // reset - Serial.println("Device reset"); - analogWrite(RGBLED_B, 0); - delay(500); - analogWrite(RGBLED_G, 255); - delay(500); - analogWrite(RGBLED_G, 0); - delay(500); - analogWrite(RGBLED_G, 255); - delay(500); - analogWrite(RGBLED_G, 0); - delay(500); - analogWrite(RGBLED_G, 255); - delay(500); + ESP_LOGI(TAG, "Device reset"); + esp_rom_uart_tx_wait_idle(0); + led_blink(LEDC_RGBLED_G, 3, 4095, 500); ESP.restart(); break; case BUTTON_6: // deep sleep - Serial.println("Going into deep sleep"); - Serial.flush(); - analogWrite(RGBLED_B, 0); - delay(500); - analogWrite(RGBLED_B, 255); - delay(500); - analogWrite(RGBLED_B, 0); - delay(500); - analogWrite(RGBLED_B, 255); - delay(500); - analogWrite(RGBLED_B, 0); - delay(500); - analogWrite(RGBLED_B, 255); - delay(500); - + ESP_LOGI(TAG, "Going into deep sleep"); + esp_rom_uart_tx_wait_idle(0); + led_blink(LEDC_RGBLED_B, 3, 4095, 500); rtc_gpio_pullup_en(KEY_DST); rtc_gpio_pulldown_dis(KEY_DST); esp_deep_sleep_start(); - break; } } @@ -816,7 +639,7 @@ void loop() { NMEA2000.loop(); NMEA2000.ParseMessages(); - if (millis() - lastSensor >= 5000) { + if ((millis() - lastSensor >= 5000) and sht_available) { lastSensor = millis(); sht.read(); temp = sht.getTemperature(); // °C @@ -826,12 +649,5 @@ void loop() { send_sensor_temphum(temp + 273.15, hum); } - // development heartbeat - if (millis() - lastPrint >= 1000) { - lastPrint = millis(); - counter++; - Serial.printf("Loop counter: %lu\n", counter); - } - - delay(1); // 1ms für freertos + delay(1); // 1ms for FreeRTOS } diff --git a/src/webserver.cpp b/src/webserver.cpp index cae2e91..15ca3ce 100644 --- a/src/webserver.cpp +++ b/src/webserver.cpp @@ -1,4 +1,5 @@ #include "main.h" +#include "config.h" #include "webserver.h" #include #include @@ -42,6 +43,26 @@ void send_embedded_file(String name, AsyncWebServerRequest *request) } } +String uptime_with_unit() { + int64_t uptime = esp_timer_get_time() / 1000000; + String uptime_unit; + if (uptime < 120) { + uptime_unit = " seconds"; + } else { + if (uptime < 2 * 3600) { + uptime /= 60; + uptime_unit = " minutes"; + } else if (uptime < 2 * 3600 * 24) { + uptime /= 3600; + uptime_unit = " hours"; + } else { + uptime /= 86400; + uptime_unit = " days"; + } + } + return String(uptime) + " " + uptime_unit; +} + void webserver_init() { // Route for root / web page @@ -76,24 +97,24 @@ void webserver_init() { server.on("/api/config", HTTP_GET, [](AsyncWebServerRequest *request){ StaticJsonDocument<512> doc; - doc["systemName"] = "Keypad1"; + doc["systemName"] = config.getString("systemName"); + doc["systemMode"] = String(config.getChar("systemMode")); doc["logLevel"] = 0; doc["version"] = VERSION; - doc["fwtype"] = "unknown"; + doc["fwtype"] = "unknown"; // TODO ? doc["salt"] = "secret"; doc["AdminPassword"] = "********"; - doc["useAdminPass"] = false; - doc["apEnable"] = true; - doc["apIp"] = "192.168.15.1"; - doc["apMask"] = "255.255.255.0"; + doc["useAdminPass"] = "false"; //config.getBool("useAdminPass") ? "true" : "false"; + doc["apEnable"] = "true"; + doc["apIp"] = config.getString("apIp"); + doc["apMask"] = config.getString("apMask"); doc["apPassword"] = "********"; - doc["stopApTime"] = 0; + doc["stopApTime"] = config.getShort("stopApTime"); doc["cpuSpeed"] = 160; - doc["tempFormat"] = "C"; + doc["tempFormat"] = String(config.getChar("tempFormat")); doc["ledBrightness"] = led_brightness; doc["ledRgbBrightness"] = rgb_brightness; - doc["tempFormat"] = "C"; - doc["switchBank"] = 0; + doc["switchBank"] = config.getByte("switchBank"); doc["key1"] = keycode[BUTTON_1]; doc["key2"] = keycode[BUTTON_2]; doc["key3"] = keycode[BUTTON_3]; @@ -106,7 +127,7 @@ void webserver_init() { doc["key4long"] = longcode[BUTTON_4]; doc["key5long"] = longcode[BUTTON_5]; doc["key6long"] = longcode[BUTTON_6]; - doc["envInterval"] = 5; + doc["envInterval"] = 5; // config.getShort("envInterval"); String out; serializeJson(doc, out); request->send(200, "application/json", out); @@ -122,16 +143,12 @@ void webserver_init() { server.on("/api/status", HTTP_GET, [](AsyncWebServerRequest *request){ StaticJsonDocument<200> doc; - doc["version"] = VERSION; - int cpu_freq = esp_clk_cpu_freq() / 1000000; doc["cpuspeed"] = String(cpu_freq) + "MHz"; - char ssid[13]; snprintf(ssid, 13, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid); doc["chipid"] = String(ssid); - doc["uptime"] = uptime_with_unit(); doc["heap"]=(long)xPortGetFreeHeapSize(); doc["temp"] = String(temp, 1); @@ -147,6 +164,9 @@ void webserver_init() { doc["version"] = VERSION; doc["build_date"] = BUILD_DATE; doc["build_time"] = BUILD_TIME; + String out; + serializeJson(doc, out); + request->send(200, "application/json", out); }); server.on("/api/setconfig", HTTP_POST, [](AsyncWebServerRequest *request){ @@ -187,4 +207,30 @@ void webserver_init() { }); + server.on("/api/devicelist", HTTP_GET, [](AsyncWebServerRequest *request){ + // NMEA2000 device list + AsyncResponseStream *response = request->beginResponseStream("application/json"); + response->print("["); + bool first = true; + for (int i = 0; i <= 252; i++) { + const tNMEA2000::tDevice *d = pN2kDeviceList->FindDeviceBySource(i); + if (d == nullptr) { + continue; + } + uint64_t NAME = d->GetName(); + char hex_name[17]; + snprintf(hex_name, sizeof(hex_name), "%08X%08X", (uint32_t)(NAME >> 32), (uint32_t)(NAME & 0xFFFFFFFF)); + if (!first) { + response->print(","); + } else { + first = false; + } + // TODO last seen? + response->printf("{\"source\":%d,\"name\":\"%s\",\"manuf\":\"%d\",\"model\":\"%s\"}", + i, hex_name, d->GetManufacturerCode(), d->GetModelID()); + } + response->print("]"); + request->send(response); + }); + } diff --git a/web/config.json b/web/config.json index 752ec4c..4cfe729 100644 --- a/web/config.json +++ b/web/config.json @@ -25,7 +25,7 @@ "name": "logLevel", "label": "Log level", "type": "list", - "default": "0", + "default": 0, "list": [ {"l":"Off (0)","v":0}, {"l":"Error (1)","v":1},