system.cpp
1 #include <boot/system.h> 2 3 #include <config.h> 4 #include "provisioning.h" 5 #include <i2c.h> 6 #include <storage.h> 7 #include <networking/wifi.h> 8 #include "../networking/sntp.h" 9 #include "../networking/telnet.h" 10 #include "../networking/ota.h" 11 #include "../networking/update.h" 12 #include "../networking/ble.h" 13 #include "../programs/buttons.h" 14 #include <led.h> 15 #include "../power/sleep.h" 16 #include "../programs/shell/shell.h" 17 #include "../programs/ssh/ssh_server.h" 18 #include "../services/http.h" 19 #include "../services/data_logger.h" 20 #include "../services/ws_shell.h" 21 #include <identity.h> 22 #include <manager.h> 23 24 #include <Arduino.h> 25 #include <freertos/timers.h> 26 #include <Wire.h> 27 28 namespace { 29 30 void initialize_hardware(void) { 31 Serial.println(F("[system] booting...")); 32 33 LED.init(); 34 LED.fadeIn(colors::Gold, 600); 35 36 hardware::i2c::initialize(); 37 hardware::storage::initialize(); 38 power::sleep::initialize(); 39 services::identity::initialize(); 40 } 41 42 void initialize_services_and_programs(void) { 43 sensors::manager::initialize(); 44 45 #if CERATINA_BLE_ENABLED 46 networking::ble::initialize(); 47 #endif 48 49 programs::shell::initialize(); 50 programs::buttons::initialize(); 51 programs::buttons::onLongPressStart([](uint8_t index) { 52 Serial.printf("[buttons] long press on GPIO %d — requesting sleep\n", index); 53 SleepCommand command = {}; 54 power::sleep::requestConfigured(&command); 55 }); 56 services::data_logger::initialize(); 57 } 58 59 void initialize_storage(void) { 60 if (hardware::storage::ensureLittleFS()) { 61 StorageQuery query = { 62 .kind = StorageKind::LittleFS, 63 .snapshot = {}, 64 }; 65 if (hardware::storage::accessSnapshot(&query)) { 66 Serial.printf("[fs] LittleFS: %u/%u KB used\n", 67 (unsigned)(query.snapshot.used_bytes / 1024), 68 (unsigned)(query.snapshot.total_bytes / 1024)); 69 LED.set(colors::Yellow); 70 } 71 } 72 } 73 74 void run_provisioning_policy(void) { 75 networking::update::checkSDOnBoot(); 76 77 if (boot::provisioning::isEnabled() && !boot::provisioning::isProvisioned()) { 78 Serial.println(F("[prov] not provisioned — starting BLE provisioning")); 79 LED.set(colors::Magenta); 80 boot::provisioning::start(); 81 } 82 } 83 84 void connect_networking(void) { 85 networking::wifi::ap::enable(); 86 87 if (networking::wifi::sta::connect()) { 88 LED.set(colors::Green); 89 Serial.printf("[wifi] connected, heap: %u bytes free\n", ESP.getFreeHeap()); 90 } else { 91 Serial.println(F("[wifi] STA not connected — AP remains active for provisioning")); 92 LED.set(colors::DarkOrange); 93 } 94 } 95 96 void heartbeat_callback(TimerHandle_t) { 97 uint32_t heap = ESP.getFreeHeap(); 98 char buf[64]; 99 snprintf(buf, sizeof(buf), "{\"uptime\":%lu,\"heap\":%u}", 100 millis() / 1000, heap); 101 services::http::emitEvent(buf, "heartbeat", millis()); 102 103 if (heap < 20000) { 104 Serial.printf("[WARN] low heap: %u bytes free (min: %u)\n", 105 heap, ESP.getMinFreeHeap()); 106 } 107 } 108 109 void system_task(void *pvParameters) { 110 (void)pvParameters; 111 112 initialize_hardware(); 113 initialize_services_and_programs(); 114 initialize_storage(); 115 run_provisioning_policy(); 116 connect_networking(); 117 boot::system::startServices(); 118 119 TimerHandle_t heartbeat = xTimerCreate("heartbeat", pdMS_TO_TICKS(5000), 120 pdTRUE, nullptr, heartbeat_callback); 121 xTimerStart(heartbeat, 0); 122 123 for (;;) { 124 services::http::service(); 125 programs::shell::service(); 126 services::ws_shell::service(); 127 networking::telnet::service(); 128 networking::ota::service(); 129 programs::buttons::service(); 130 power::sleep::service(); 131 132 #if CERATINA_BLE_ENABLED 133 networking::ble::service(); 134 #endif 135 136 vTaskDelay(pdMS_TO_TICKS(config::system::SHELL_SERVICE_MS)); 137 } 138 } 139 140 } 141 142 void boot::system::startServices() { 143 static bool sntp_done = false; 144 static bool ssh_done = false; 145 static bool http_done = false; 146 static bool telnet_done = false; 147 static bool ota_done = false; 148 149 if (!sntp_done) sntp_done = networking::sntp::sync(); 150 if (!ssh_done) ssh_done = services::sshd::initialize(); 151 if (!http_done) { services::http::initialize(); http_done = true; } 152 if (!telnet_done) { networking::telnet::initialize(); telnet_done = true; } 153 if (!ota_done) { networking::ota::initialize(); ota_done = true; } 154 } 155 156 void boot::system::startTask() { 157 xTaskCreatePinnedToCore(system_task, "system", config::system::TASK_STACK, 158 nullptr, 1, nullptr, 1); 159 }