diff --git a/.gitignore b/.gitignore index 7bb6a68..48faaee 100644 --- a/.gitignore +++ b/.gitignore @@ -527,7 +527,7 @@ node_modules/ **/*.Server/ModelManifest.xml _Pvt_Extensions -# Paket dependency manager +# Paket dependency controller .paket/paket.exe paket-files/ diff --git a/bgeigiecast/api_connector.cpp b/bgeigiecast/api_connector.cpp index 1bdf413..144a78d 100644 --- a/bgeigiecast/api_connector.cpp +++ b/bgeigiecast/api_connector.cpp @@ -1,68 +1,105 @@ #include "api_connector.h" #include "debugger.h" +#include "identifiers.h" + +#define API_SEND(alert) (alert ? API_SEND_FREQUENCY_SECONDS_ALERT : API_SEND_FREQUENCY_SECONDS) +#define API_SEND_DEV(alert) (alert ? API_SEND_FREQUENCY_SECONDS_ALERT_DEV : API_SEND_FREQUENCY_SECONDS_DEV) +#define API_SEND_FREQUENCY(alert, dev) (((dev ? API_SEND_DEV(alert) : API_SEND(alert)) * 1000) - 2000) + +ApiReporter::ApiReporter(LocalStorage& config) : + Handler(k_handler_api_reporter), + _config(config), + _saved_readings(), + _last_send(), + _merged_reading(), + _current_default_response(e_api_reporter_idle), + _alert() { +} -#define API_SEND_FREQUENCY (API_SEND_FREQUENCY_MINUTES * 60 * 1000) +bool ApiReporter::is_connected() const { + return WiFi.status() == WL_CONNECTED; +} -ApiConnector::ApiConnector(EspConfig& config, ApiConnectionObserver* observer) : IApiConnector(config, observer) { +bool ApiReporter::time_to_send() const { + return millis() - _last_send > API_SEND_FREQUENCY(_alert, _config.get_use_dev()); } -bool ApiConnector::start_connect(bool initial) { - if(is_connected()) { - return true; +void ApiReporter::save_reading() { + DEBUG_PRINTLN("Could not upload reading, trying again later"); + if(_merged_reading.valid_reading()) { + _saved_readings.add(_merged_reading); } +} - const char* ssid = _config.get_wifi_ssid(); - if(!ssid) { - DEBUG_PRINTLN("No SSID to connect to!"); - return false; - } +void ApiReporter::reset() { + _last_send = millis(); + _merged_reading.reset(); +} - DEBUG_PRINTLN(); +bool ApiReporter::activate(bool retry) { + if(is_connected()) { + return true; + } - if(initial) { + if(retry) { + WiFi.reconnect(); + } else { + const char* ssid = _config.get_wifi_ssid(); + if(!ssid) { + DEBUG_PRINTLN("No SSID to connect to!"); + return false; + } const char* password = _config.get_wifi_password(); DEBUG_PRINT("Connecting to ssid "); DEBUG_PRINTLN(ssid); password ? WiFi.begin(ssid, password) : WiFi.begin(ssid); - _merged_reading.reset(); - _last_send = millis(); - } else { - WiFi.reconnect(); } return is_connected(); } -void ApiConnector::stop() { +void ApiReporter::deactivate() { + reset(); WiFi.disconnect(true, true); WiFi.mode(WIFI_MODE_NULL); } -bool ApiConnector::test() { - WiFiClient client; - bool success = client.connect(API_HOST, 80) != 0; - client.stop(); - return success; -} +int8_t ApiReporter::handle_produced_work(const worker_status_t& worker_reports) { + const auto& reader = worker_reports.at(k_worker_bgeigie_connector); + if(!reader.is_fresh()) { + return _current_default_response; + } + const auto& reading = reader.get(); + _merged_reading += reading; + if(!time_to_send()) { + return _current_default_response; + } -bool ApiConnector::is_connected() { - return WiFi.status() == WL_CONNECTED; + _last_send = millis(); + if(_config.get_use_home_location()) { + _merged_reading.apply_home_location(_config.get_home_latitude(), _config.get_home_longitude()); + } + + if(_merged_reading.valid_reading()) { + _current_default_response = send_reading(reading); + } else { + return e_api_reporter_error_invalid_reading; + } + reset(); } -bool ApiConnector::send_reading() { +ApiReporter::ApiHandlerStatus ApiReporter::send_reading(const Reading& reading) { char json_str[200]; if(!_merged_reading.as_json(json_str)) { // This whole reading is invalid DEBUG_PRINTLN("Unable to send reading, its not valid at all!"); - schedule_event(e_a_api_post_failed); - return false; + return e_api_reporter_error_invalid_reading; } - if(!is_connected()) { + if(!is_connected() && !activate(true)) { DEBUG_PRINTLN("Unable to send, lost connection"); - schedule_event(e_a_api_post_failed); - return false; + return e_api_reporter_error_not_connected; } HTTPClient http; @@ -77,9 +114,8 @@ bool ApiConnector::send_reading() { //Specify destination for HTTP request if(!http.begin(url)) { DEBUG_PRINTLN("Unable to begin url connection"); - save_reading(); http.end(); //Free resources - return false; + return e_api_reporter_error_remote_not_available; } char content_length[5]; @@ -96,18 +132,22 @@ bool ApiConnector::send_reading() { int httpResponseCode = http.POST(json_str); //Send the actual POST request - if(httpResponseCode > 0) { + if(httpResponseCode >= 200 && httpResponseCode < 300) { String response = http.getString(); + DEBUG_PRINTLN("POST successfull"); DEBUG_PRINT(httpResponseCode); DEBUG_PRINTLN(response); - schedule_event(e_a_reading_posted); http.end(); //Free resources - return true; + return e_api_reporter_send_success; + } else if(httpResponseCode > 0) { + DEBUG_PRINTLN("Remote error on sending POST"); + http.end(); //Free resources + return e_api_reporter_error_server_rejected_post; } else { - DEBUG_PRINTLN("Error on sending POST"); - // Failed to send - schedule_event(e_a_api_post_failed); + DEBUG_PRINTLN("Remote not available"); http.end(); //Free resources - return false; + // Failed to send + return e_api_reporter_error_remote_not_available; + } } diff --git a/bgeigiecast/api_connector.h b/bgeigiecast/api_connector.h index 93ed0dd..bbd87bc 100644 --- a/bgeigiecast/api_connector.h +++ b/bgeigiecast/api_connector.h @@ -4,48 +4,85 @@ #include #include -#include "i_api_connector.h" +#include + +#include "local_storage.h" +#include "reading.h" +#include "user_config.h" +#include "circular_buffer.h" /** * Connects over WiFi to the API to send readings */ -class ApiConnector : public IApiConnector { +class ApiReporter : public Handler { public: - explicit ApiConnector(EspConfig& config, ApiConnectionObserver* observer = nullptr); - virtual ~ApiConnector() = default; + enum ApiHandlerStatus { + e_api_reporter_idle, + e_api_reporter_send_success, + e_api_reporter_error_invalid_reading, + e_api_reporter_error_not_connected, + e_api_reporter_error_remote_not_available, + e_api_reporter_error_server_rejected_post, + }; + + explicit ApiReporter(LocalStorage& config); + virtual ~ApiReporter() = default; /** - * Initialize the connection - * @param initial: set to false if its for reconnect / connect in error - * @return true if connection with the wifi was made + * Check if the connection is up + * @return true if connected */ - bool start_connect(bool initial) override; + bool is_connected() const; + protected: /** - * Disconnect + * Check if enough time has passed to send the latest reading to api + * @return */ - void stop() override; + bool time_to_send() const; /** - * Test the connection to the API + * reset the api time and merged readings */ - bool test() override; + void reset(); /** - * Check if the connection is up - * @return true if connected + * Initialize the connection + * @param initial: set to false if its for reconnect / connect in error + * @return true if connection with the wifi was made */ - bool is_connected() override; + bool activate(bool retry) override; - protected: + /** + * Stop the connection + */ + void deactivate() override; + + int8_t handle_produced_work(const worker_status_t& worker_reports) override; + /** + * When a reading cannot be send to the API, we save it to send later.. + * @param reading: reading to save + */ + virtual void save_reading() final; + + private: /** * Send a reading to the API * @param reading: reading to send * @return: true if the API call was successful */ - bool send_reading() override; + ApiHandlerStatus send_reading(const Reading& reading); + + + LocalStorage& _config; + CircularBuffer _saved_readings; + uint32_t _last_send; + Reading _merged_reading; + ApiHandlerStatus _current_default_response; + + bool _alert; }; #endif //BGEIGIECAST_APICONNECTOR_H diff --git a/bgeigiecast/bgeigie_connector.cpp b/bgeigiecast/bgeigie_connector.cpp index 0624993..17aecb6 100644 --- a/bgeigiecast/bgeigie_connector.cpp +++ b/bgeigiecast/bgeigie_connector.cpp @@ -1,20 +1,22 @@ #include "bgeigie_connector.h" -#include "user_config.h" #include "debugger.h" +#include "identifiers.h" -BGeigieConnector::BGeigieConnector(Stream& serial_connection) : _serial_connection(serial_connection), _buffer("") { +BGeigieConnector::BGeigieConnector(Stream& serial_connection) : + Worker(k_worker_bgeigie_connector, Reading(), 4000), + _serial_connection(serial_connection), + _buffer("") { } -bool BGeigieConnector::get_reading(Reading& out) { +int8_t BGeigieConnector::produce_data() { while(_serial_connection.available() > 0) { char c = static_cast(_serial_connection.read()); _buffer += c; if(c == '\n') { -// DEBUG_PRINT("New reading: "); DEBUG_PRINT(_buffer); - out = _buffer.c_str(); _buffer = ""; - return true; + data = _buffer.c_str(); + return data.get_status() | k_reading_parsed ? WorkerStatus::e_worker_data_read : WorkerStatus::e_worker_error; } } - return false; + return WorkerStatus::e_worker_idle; } diff --git a/bgeigiecast/bgeigie_connector.h b/bgeigiecast/bgeigie_connector.h index c0005ef..7002d26 100644 --- a/bgeigiecast/bgeigie_connector.h +++ b/bgeigiecast/bgeigie_connector.h @@ -3,22 +3,20 @@ #include +#include + #include "reading.h" /** * Connect the system to the bGeigieNano to read sensor data */ -class BGeigieConnector { +class BGeigieConnector : public Worker { public: explicit BGeigieConnector(Stream& _serial_connection); virtual ~BGeigieConnector() = default; - /** - * Get a reading from serial - * @param out: output for the reading - * @return: true if a reading was read - */ - bool get_reading(Reading& out); + private: + int8_t produce_data() override; private: Stream& _serial_connection; diff --git a/bgeigiecast/bgeigiecast.ino b/bgeigiecast/bgeigiecast.ino index 5393325..031f881 100644 --- a/bgeigiecast/bgeigiecast.ino +++ b/bgeigiecast/bgeigiecast.ino @@ -39,44 +39,31 @@ Contact: Jelle Bouwhuis (email jellebouwhuis@outlook.com) and Rob Oudendijk (rob #ifndef UNIT_TEST #include -#include "bluetooth_connector.h" +#include +#include "bluetooth_reporter.h" #include "api_connector.h" #include "debugger.h" #include "controller.h" +#include "bgeigie_connector.h" +#include "configuration_server.h" +#include "mode_led.h" HardwareSerial& bGeigieSerialConnection = Serial2; -void controller_sleep(uint32_t millis_to_sleep) { - esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); - esp_sleep_enable_timer_wakeup(millis_to_sleep * 1000); - - DEBUG_PRINTLN("-----\nEntering sleep"); - DEBUG_FLUSH(); - esp_light_sleep_start(); - DEBUG_PRINTLN("Woke up from sleep\n-----"); - - switch(esp_sleep_get_wakeup_cause()) { - case ESP_SLEEP_WAKEUP_TIMER: - break; - case ESP_SLEEP_WAKEUP_GPIO: - gpio_wakeup_disable((gpio_num_t) MODE_BUTTON_PIN); - gpio_wakeup_enable((gpio_num_t) MODE_BUTTON_PIN, - digitalRead(MODE_BUTTON_PIN) ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL); - break; - default: - break; - } -} +LocalStorage config; +Controller controller(config); -EspConfig config; -ApiConnector api_conn(config); -BluetoohConnector bt_conn; -#if USE_SLEEP -Controller controller(config, bGeigieSerialConnection, api_conn, bt_conn, &controller_sleep); -#else -Controller controller(config, bGeigieSerialConnection, api_conn, bt_conn); -#endif +// Workers +BGeigieConnector bgeigie_connector(bGeigieSerialConnection); +ConfigWebServer config_server(config); + +// Data handlers +BluetoothReporter bluetooth_reporter(config); +ApiReporter api_reporter(config); + +// Report handlers +ModeLED mode_led(config); void setup() { DEBUG_BEGIN(SERIAL_BAUD); @@ -85,30 +72,22 @@ void setup() { // Start serial connection to bGeigie controller bGeigieSerialConnection.begin(BGEIGIE_CONNECTION_BAUD); - // Set gpio pin configurations - gpio_config_t io_conf{ - .pin_bit_mask = 1ULL< -#include -#include -#include "bluetooth_connector.h" +#include "bluetooth_reporter.h" #include "debugger.h" +#include "identifiers.h" -BluetoohConnector::BluetoohConnector() : pServer(nullptr), initialized(false), pDataRXCharacteristic(nullptr) { +BluetoothReporter::BluetoothReporter(LocalStorage& config) + : Handler(k_handler_bluetooth_reporter), config(config), pServer(nullptr), pDataRXCharacteristic(nullptr) { } -bool BluetoohConnector::init(uint16_t device_id) { - if(initialized) { - return true; +bool BluetoothReporter::activate(bool) { + if(!pServer) { + pServer = BLEDevice::createServer(); + + create_ble_profile_service(pServer); + create_ble_device_service(pServer); + create_ble_data_service(pServer); + + BLEAdvertising* pAdvertising = BLEDevice::getAdvertising(); + pAdvertising->addServiceUUID(SERVICE_PROFILE_UUID); + pAdvertising->addServiceUUID(SERVICE_DEVICE_UUID); + pAdvertising->addServiceUUID(SERVICE_DATA_UUID); + pAdvertising->setScanResponse(true); + pAdvertising->setMinPreferred(0x06); + pAdvertising->setMinPreferred(0x12); } - char deviceName[16]; - sprintf(deviceName, "bGeigie%d", device_id); - - BLEDevice::init(deviceName); - pServer = BLEDevice::createServer(); - - create_ble_profile_service(pServer); - create_ble_device_service(pServer); - create_ble_data_service(pServer); - - BLEAdvertising* pAdvertising = BLEDevice::getAdvertising(); - pAdvertising->addServiceUUID(SERVICE_PROFILE_UUID); - pAdvertising->addServiceUUID(SERVICE_DEVICE_UUID); - pAdvertising->addServiceUUID(SERVICE_DATA_UUID); - pAdvertising->setScanResponse(true); - pAdvertising->setMinPreferred(0x06); - pAdvertising->setMinPreferred(0x12); + if(!BLEDevice::getInitialized() && config.get_device_id()) { + char deviceName[16]; + sprintf(deviceName, "bGeigie%d", config.get_device_id()); + BLEDevice::init(deviceName); + DEBUG_PRINT("Bluetooth initialized, device: "); + DEBUG_PRINTLN(deviceName); + } - BLEDevice::startAdvertising(); - initialized = true; + return BLEDevice::getInitialized(); +} - DEBUG_PRINT("Bluetooth initialized, device: "); - DEBUG_PRINTLN(deviceName); - return true; +void BluetoothReporter::deactivate() { + BLEDevice::deinit(); } -void BluetoohConnector::create_ble_profile_service(BLEServer* pServer) { - if(initialized) { - return; +int8_t BluetoothReporter::handle_produced_work(const worker_status_t& worker_reports) { + const auto& reading_stat = worker_reports.at(k_worker_bgeigie_connector); + if(!reading_stat.is_fresh()) { + return Status::e_handler_idle; } + // Fresh reading is produced + const auto& reading = reading_stat.get(); + return send_reading(reading) ? Status::e_handler_data_reported : Status::e_handler_no_clients; +} + +void BluetoothReporter::create_ble_profile_service(BLEServer* pServer) { BLEService* pProfileService = pServer->createService(SERVICE_PROFILE_UUID); BLECharacteristic* pProfileNameCharacteristic = pProfileService->createCharacteristic( CHARACTERISTIC_PROFILE_NAME_UUID, @@ -58,10 +66,7 @@ void BluetoohConnector::create_ble_profile_service(BLEServer* pServer) { pProfileService->start(); } -void BluetoohConnector::create_ble_device_service(BLEServer* pServer) { - if(initialized) { - return; - } +void BluetoothReporter::create_ble_device_service(BLEServer* pServer) { BLEService* pDeviceService = pServer->createService(SERVICE_DEVICE_UUID); // Manufacturer name @@ -108,10 +113,7 @@ void BluetoohConnector::create_ble_device_service(BLEServer* pServer) { pDeviceService->start(); } -void BluetoohConnector::create_ble_data_service(BLEServer* pServer) { - if(initialized) { - return; - } +void BluetoothReporter::create_ble_data_service(BLEServer* pServer) { BLEService* pDataService = pServer->createService(SERVICE_DATA_UUID); // DB Addr @@ -158,10 +160,7 @@ void BluetoohConnector::create_ble_data_service(BLEServer* pServer) { pDataService->start(); } -bool BluetoohConnector::send_reading(Reading& reading) { - if(!initialized) { - init(reading.get_device_id()); - } +bool BluetoothReporter::send_reading(const Reading& reading) const { if(pServer->getConnectedCount()) { // No clients to send data to return false; diff --git a/bgeigiecast/bluetooth_connector.h b/bgeigiecast/bluetooth_reporter.h similarity index 53% rename from bgeigiecast/bluetooth_connector.h rename to bgeigiecast/bluetooth_reporter.h index 4b08b87..e164588 100644 --- a/bgeigiecast/bluetooth_connector.h +++ b/bgeigiecast/bluetooth_reporter.h @@ -3,40 +3,43 @@ #include -#include "bluetooth_connector.h" +#include + #include "bluetooth_settings.h" #include "reading.h" +#include "local_storage.h" /** * Setups up bluetooth endpoint for the device, allowing it to send readings over bluetooth */ -class BluetoohConnector { +class BluetoothReporter : public Handler { public: - BluetoohConnector(); - virtual ~BluetoohConnector() = default; - - /** - * Initialize the bluetooth, using device id as name - * @param device_id : id of the bgeigie device - */ - virtual bool init(uint16_t device_id); - - /** - * Send a new reading over bluetooth - * @param reading : reading object to send - */ - virtual bool send_reading(Reading& reading); + typedef enum Status { + e_handler_idle = -1, + e_handler_data_reported, + e_handler_no_clients, + } Status; + + explicit BluetoothReporter(LocalStorage& config); + virtual ~BluetoothReporter() = default; + + protected: + bool activate(bool retry) override; + void deactivate() override; + int8_t handle_produced_work(const worker_status_t& worker_reports) override; private: + + bool send_reading(const Reading& reading) const; + void create_ble_profile_service(BLEServer* pServer); void create_ble_device_service(BLEServer* pServer); void create_ble_data_service(BLEServer* pServer); + LocalStorage& config; BLEServer* pServer; - bool initialized; BLECharacteristic* pDataRXCharacteristic; uint8_t addr[BLE_DATA_ADDR_SIZE] = BLE_DATA_ADDR; - }; #endif //BGEIGIECAST_BLUETOOTH_CONNECTOR_H diff --git a/bgeigiecast/button.cpp b/bgeigiecast/button.cpp index 230b36b..29ebcdf 100644 --- a/bgeigiecast/button.cpp +++ b/bgeigiecast/button.cpp @@ -15,10 +15,7 @@ Button::Button(uint8_t pin, uint8_t pull_type) : _pull_type_mode(pull_type == PULLDOWN ? HIGH : LOW), _observer(nullptr), _current_state(false), - _last_state_change(0), - _on_button_down_fn(nullptr), - _on_button_release_fn(nullptr), - _on_button_pressed_fn(nullptr) { + _last_state_change(0) { } Button::~Button() { @@ -49,12 +46,9 @@ bool Button::state_changed(int state, uint32_t time) { if(_current_state) { if(_observer) { _observer->on_button_down(this); } - if(_on_button_down_fn) { _on_button_down_fn(this); } } else if(_last_state_change != 0) { // Ignore initial presses at startups if(_observer) { _observer->on_button_release(this); } - if(_on_button_release_fn) { _on_button_release_fn(this); } if(_observer) { _observer->on_button_pressed(this, time - _last_state_change); } - if(_on_button_pressed_fn) { _on_button_pressed_fn(this, time - _last_state_change); } } _last_state_change = time; return true; @@ -64,18 +58,6 @@ uint8_t Button::get_pin() const { return _pin; } -void Button::set_on_button_down_fn(on_button_down_fn_t on_button_down_fn) { - _on_button_down_fn = on_button_down_fn; -} - -void Button::set_on_button_release_fn(on_button_release_fn_t on_button_release_fn) { - _on_button_release_fn = on_button_release_fn; -} - -void Button::set_on_button_pressed_fn(on_button_pressed_fn_t on_button_pressed_fn) { - _on_button_pressed_fn = on_button_pressed_fn; -} - uint32_t Button::get_last_state_change() const { return _last_state_change; } diff --git a/bgeigiecast/button.h b/bgeigiecast/button.h index 857012f..cb5eafa 100644 --- a/bgeigiecast/button.h +++ b/bgeigiecast/button.h @@ -13,10 +13,6 @@ class ButtonObserver; class Button { public: - typedef void(* on_button_down_fn_t)(Button*); - typedef void(* on_button_release_fn_t)(Button*); - typedef void(* on_button_pressed_fn_t)(Button*, uint32_t); - explicit Button(uint8_t pin, uint8_t pull_type = PULLUP); virtual ~Button(); @@ -57,33 +53,12 @@ class Button { */ void set_observer(ButtonObserver* observer); - /** - * Set a callback function for button down events - * @param on_button_down_fn: callback function - */ - void set_on_button_down_fn(on_button_down_fn_t on_button_down_fn); - - /** - * Set a callback function for button release events - * @param on_button_down_fn: callback function - */ - void set_on_button_release_fn(on_button_release_fn_t on_button_release_fn); - - /** - * Set a callback function for button pressed events - * @param on_button_down_fn: callback function - */ - void set_on_button_pressed_fn(on_button_pressed_fn_t on_button_pressed_fn); private: uint8_t _pin; bool _pull_type_mode; ButtonObserver* _observer; bool _current_state; uint32_t _last_state_change; - - on_button_down_fn_t _on_button_down_fn; - on_button_release_fn_t _on_button_release_fn; - on_button_pressed_fn_t _on_button_pressed_fn; }; /** diff --git a/bgeigiecast/conf_server.cpp b/bgeigiecast/configuration_server.cpp similarity index 85% rename from bgeigiecast/conf_server.cpp rename to bgeigiecast/configuration_server.cpp index 47c69c9..cad2e1d 100644 --- a/bgeigiecast/conf_server.cpp +++ b/bgeigiecast/configuration_server.cpp @@ -1,10 +1,13 @@ #include #include -#include "conf_server.h" +#include "configuration_server.h" #include "user_config.h" -#include "esp_config.h" +#include "local_storage.h" #include "debugger.h" #include "http_pages.h" +#include "identifiers.h" + +#define RETRY_TIMEOUT 2000 template T clamp(T2 val, T min, T max) { @@ -12,58 +15,59 @@ T clamp(T2 val, T min, T max) { return _val < min ? min : _val > max ? max : _val; } -ConfigWebServer::ConfigWebServer(EspConfig& config) : _server(SERVER_WIFI_PORT), _config(config), _running(false) { -} +uint32_t last_retry = 0; +uint8_t retry_count = 0; -ConfigWebServer::~ConfigWebServer() { - stop(); +ConfigWebServer::ConfigWebServer(LocalStorage& config) + : Worker(k_worker_configuration_server, {false, false}, 0), + _server(SERVER_WIFI_PORT), + _config(config), + _running(false) { } -bool ConfigWebServer::connect(bool try_wifi) { +bool ConfigWebServer::activate(bool retry) { + if(retry && millis() - last_retry < RETRY_TIMEOUT) { + return false; + } auto device_id = _config.get_device_id(); - - if(!_config.get_device_id()) { + if(!device_id) { DEBUG_PRINTLN("Can't start config without device id!"); return false; } char host_ssid[16]; sprintf(host_ssid, ACCESS_POINT_SSID, device_id); + if(retry) { + WiFi.disconnect(true, true); + retry_count++; + } else { + retry_count = 0; + MDNS.begin(host_ssid); + delay(100); + } - MDNS.begin(host_ssid); - - delay(100); - - if(try_wifi && _config.get_wifi_ssid()) { - for(int i = 0; i < 3; ++i) { - connect_wifi(); - - auto time = millis(); - while(millis() - time < 2000) { - if(WiFi.status() == WL_CONNECTED) { - DEBUG_PRINTF("Connected to %s, IP address: %s\n", _config.get_wifi_ssid(), WiFi.localIP().toString().c_str()); - HttpPages::internet_access = true; - return true; - } - } + if(retry_count < 3 && _config.get_wifi_ssid()) { + connect_wifi(); + if(WiFi.status() == WL_CONNECTED) { + DEBUG_PRINTF("Connected to %s, IP address: %s\n", _config.get_wifi_ssid(), WiFi.localIP().toString().c_str()); + HttpPages::internet_access = true; + add_urls(); + return true; } - - WiFi.disconnect(true, true); + return false; } return start_ap_server(host_ssid); } -void ConfigWebServer::stop() { - if(_running) { - _running = false; - _server.stop(); - WiFi.softAPdisconnect(true); - delay(20); - } +void ConfigWebServer::deactivate() { + _server.close(); + _server.stop(); + WiFi.softAPdisconnect(true); + delay(20); } -void ConfigWebServer::handle_requests() { +int8_t ConfigWebServer::produce_data() { _server.handleClient(); } @@ -93,13 +97,11 @@ bool ConfigWebServer::start_ap_server(const char* host_ssid) { delay(100); + add_urls(); return true; } -void ConfigWebServer::start_server() { - if(_running) { - return; - } +void ConfigWebServer::add_urls() { // Home _server.on("/", HTTP_GET, [this]() { _server.sendHeader("Connection", "close"); @@ -175,6 +177,7 @@ void ConfigWebServer::start_server() { }); _server.on("/reboot", [this]() { // Reboot + deactivate(); ESP.restart(); }); @@ -190,11 +193,6 @@ void ConfigWebServer::start_server() { }); _server.begin(); - _running = true; -} - -bool ConfigWebServer::running() const { - return _running; } void ConfigWebServer::handle_save() { diff --git a/bgeigiecast/conf_server.h b/bgeigiecast/configuration_server.h similarity index 69% rename from bgeigiecast/conf_server.h rename to bgeigiecast/configuration_server.h index 3bdd879..61f7cf1 100644 --- a/bgeigiecast/conf_server.h +++ b/bgeigiecast/configuration_server.h @@ -4,42 +4,47 @@ #include #include -#include "esp_config.h" +#include + +#include "local_storage.h" + + +struct ServerStatus { + bool connected; + bool running; +}; /** * Class to host a web server for configuring the ESP32. Will set up an access * point based on user_config.h "Access point settings". */ -class ConfigWebServer { +class ConfigWebServer : public Worker { public: - explicit ConfigWebServer(EspConfig& config); - virtual ~ConfigWebServer(); + explicit ConfigWebServer(LocalStorage& config); + virtual ~ConfigWebServer() = default; /** - * Initialize the web server, does nothing if it is already initialized. - * @return true if initialization was success + * Checks if there are requests and handles them */ - bool connect(bool try_wifi = true); + int8_t produce_data(); /** - * Stop the web server + * Initialize the web server and endpoints */ - void stop(); + void add_urls(); + protected: /** - * Checks if there are requests and handles them + * Initialize the web server, does nothing if it is already initialized. + * @return true if initialization was success */ - void handle_requests(); + bool activate(bool retry) override; /** - * Initialize the web server and endpoints + * Stops the web server */ - void start_server(); + void deactivate() override; - /** - * if the server is running - */ - bool running() const; private: /** @@ -65,7 +70,7 @@ class ConfigWebServer { void handle_update_uploading(); WebServer _server; - EspConfig& _config; + LocalStorage& _config; bool _running; }; diff --git a/bgeigiecast/controller.cpp b/bgeigiecast/controller.cpp index 6eeef54..fa58be9 100644 --- a/bgeigiecast/controller.cpp +++ b/bgeigiecast/controller.cpp @@ -1,39 +1,32 @@ #include "sm_c_concete_states.h" #include "controller.h" -#include "reading.h" +#include "identifiers.h" #define BUTTON_LONG_PRESSED_MILLIS_TRESHOLD 4000 -Controller::Controller(EspConfig& config, - Stream& bgeigie_connection, - IApiConnector& api_connector, - BluetoohConnector& bluetooth_connector, - sleep_fn_t sleep_fn) : - Context(), +Controller::Controller(LocalStorage& config) : ButtonObserver(), + Context(), + Aggregator(), + Handler(k_handler_controller_handler), _config(config), - _reporter(config, bgeigie_connection, api_connector, bluetooth_connector), - _ap_server(config), - _mode_button(MODE_BUTTON_PIN), - _mode_led(config), - _sleep_fn(sleep_fn) { + _mode_button(MODE_BUTTON_PIN) { } void Controller::setup_state_machine() { set_state(new InitializeState(*this)); - _reporter.setup_state_machine(); } void Controller::run() { Context::run(); - _reporter.run(); + Aggregator::run(); } void Controller::initialize() { - _config.set_all(); _mode_button.activate(); _mode_button.set_observer(this); - _reporter.set_observer(this); + + register_handler(*this); schedule_event(Event_enum::e_c_controller_initialized); } @@ -50,19 +43,6 @@ void Controller::on_button_pressed(Button* button, uint32_t millis_pressed) { } } -void Controller::set_reporter_outputs(bool bt, bool api) { - _reporter.set_report_output(bt, api); -} - -void Controller::sleep() { - if(_sleep_fn && _reporter.is_idle()) { - uint32_t till_next = _reporter.time_till_next_reading(millis()); - if(till_next > 0) { - _sleep_fn(till_next); - } - } -} - void Controller::reset_system() { _config.reset_defaults(); DEBUG_PRINTLN("\n RESTARTING ESP...\n"); @@ -73,20 +53,16 @@ void Controller::save_state(SavableState state) { _config.set_saved_state(state, false); } -SavableState Controller::get_saved_state() { +Controller::SavableState Controller::get_saved_state() { return static_cast(_config.get_saved_state()); } -void Controller::reading_reported(Reporter::ReporterStatus status) { - switch(status) { - case Reporter::k_reporter_failed: - schedule_event(e_c_report_failed); - break; - case Reporter::k_reporter_success: - schedule_event(e_c_report_success); - break; - case Reporter::k_reporter_no_change: - // No change - break; +int8_t Controller::handle_produced_work(const worker_status_t& worker_reports) { + auto current_state = get_current_state()->get_state_id(); + if(current_state == ControllerState::k_state_InitReadingState) { + if(worker_reports.at(k_worker_bgeigie_connector).is_fresh()) { + schedule_event(e_c_reading_initialized); + } } + return current_state; } diff --git a/bgeigiecast/controller.h b/bgeigiecast/controller.h index 312b0b8..8634f02 100644 --- a/bgeigiecast/controller.h +++ b/bgeigiecast/controller.h @@ -1,27 +1,25 @@ #ifndef BGEIGIECAST_CONTROLLER_HPP #define BGEIGIECAST_CONTROLLER_HPP +#include +#include + #include "button.h" #include "sm_context.h" -#include "conf_server.h" -#include "bgeigie_connector.h" -#include "i_api_connector.h" -#include "bluetooth_connector.h" -#include "mode_led.h" -#include "reporter.h" +#include "local_storage.h" /** * Main controller for the system, implements state machine to run */ -class Controller : public Context, private ButtonObserver, private ReporterObserver { +class Controller : private ButtonObserver, public Context, public Aggregator, private Handler { public: - typedef void (* sleep_fn_t)(uint32_t millis_to_sleep); - Controller(EspConfig& config, - Stream& bgeigie_connection, - IApiConnector& api_connector, - BluetoohConnector& bluetooth_connector, - sleep_fn_t sleep_fn = nullptr); + typedef enum { + k_savable_MobileMode, + k_savable_FixedMode + } SavableState; + + Controller(LocalStorage& config); virtual ~Controller() = default; /** @@ -29,36 +27,26 @@ class Controller : public Context, private ButtonObserver, private ReporterObser */ void setup_state_machine(); - /** - * Initialize the controller and all of its components - */ - void initialize(); - /** * Override the context run to also run the reporter state machine */ void run() override; /** - * + * Callback for the button */ - void set_reporter_outputs(bool bt, bool api); + void on_button_pressed(Button* button, uint32_t millis) override; - /** - * Go to sleep till next reading is expected. - */ - void sleep(); + protected: + int8_t handle_produced_work(const worker_status_t& worker_reports) override; + + private: /** * Reset and restart the system */ void reset_system(); - /** - * Callback for the button - */ - void on_button_pressed(Button* button, uint32_t millis) override; - /** * Save a state to the memory * @param state @@ -70,27 +58,20 @@ class Controller : public Context, private ButtonObserver, private ReporterObser */ SavableState get_saved_state(); - private: - void reading_reported(Reporter::ReporterStatus status) override; + /** + * Initialize the controller and all of its components + */ + void initialize(); - private: - EspConfig& _config; - Reporter _reporter; - ConfigWebServer _ap_server; + LocalStorage& _config; Button _mode_button; - ModeLED _mode_led; - - sleep_fn_t _sleep_fn; friend class InitializeState; friend class InitReadingState; friend class PostInitializeState; - friend class SetupServerState; - friend class ServerActiveState; friend class MobileModeState; - friend class ConnectedState; - friend class DisconnectedState; - friend class ConnectionErrorState; + friend class FixedModeState; + friend class ResetState; }; #endif //BGEIGIECAST_CONTROLLER_HPP diff --git a/bgeigiecast/i_api_connector.cpp b/bgeigiecast/i_api_connector.cpp deleted file mode 100644 index a7ac63b..0000000 --- a/bgeigiecast/i_api_connector.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include - -#include "i_api_connector.h" -#include "sm_a_concrete_states.h" - -#define API_SEND(alert) (alert ? API_SEND_FREQUENCY_SECONDS_ALERT : API_SEND_FREQUENCY_SECONDS) -#define API_SEND_DEV(alert) (alert ? API_SEND_FREQUENCY_SECONDS_ALERT_DEV : API_SEND_FREQUENCY_SECONDS_DEV) -#define API_SEND_FREQUENCY(alert, dev) (((dev ? API_SEND_DEV(alert) : API_SEND(alert)) * 1000) - 2000) - -IApiConnector::IApiConnector(EspConfig& config, ApiConnectionObserver* observer) : - _config(config), - _saved_readings(), - _last_send(0), - _merged_reading(), - _observer(observer), - _alert(false) { -} - -bool IApiConnector::time_to_send() const { - return millis() - _last_send > API_SEND_FREQUENCY(_alert, _config.get_use_dev()); -} - -void IApiConnector::init_reading_report(Reading& reading) { - set_state(new ApiProcessReadingState(*this, reading)); - _alert = reading.get_cpm() > 100; // TODO: configurable value -} - -void IApiConnector::process_reading(Reading& reading) { - _merged_reading += reading; - if(time_to_send()) { - _last_send = millis(); - if(_config.get_use_home_location()) { - _merged_reading.apply_home_location(_config.get_home_latitude(), _config.get_home_longitude()); - } - if(_merged_reading.valid_reading()) { - schedule_event(e_a_report_reading); - } else { - // Invalid reading, no need to send this. - schedule_event(e_a_not_reporting); - _merged_reading.reset(); - } - } else { - schedule_event(e_a_not_reporting); - } -} - -void IApiConnector::save_reading() { - DEBUG_PRINTLN("Could not upload reading, trying again later"); - if(_merged_reading.valid_reading()) { - _saved_readings.add(_merged_reading); - } - schedule_event(e_a_reading_saved); -} - -void IApiConnector::set_observer(ApiConnectionObserver* observer) { - _observer = observer; -} - -void IApiConnector::reset() { - _last_send = millis(); - _merged_reading.reset(); -} diff --git a/bgeigiecast/i_api_connector.h b/bgeigiecast/i_api_connector.h deleted file mode 100644 index 339d3b4..0000000 --- a/bgeigiecast/i_api_connector.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef BGEIGIECAST_I_APICONNECTOR_H -#define BGEIGIECAST_I_APICONNECTOR_H - -#include - -#include "circular_buffer.h" -#include "user_config.h" -#include "esp_config.h" -#include "reading.h" -#include "sm_context.h" - -class ApiConnectionObserver; - -/** - * Abstract class to be used in controller as a Api connector - */ -class IApiConnector : public Context { - public: - - typedef enum { - k_report_skipped, - k_report_failed, - k_report_success, - } ReportApiStatus; - - explicit IApiConnector(EspConfig& config, ApiConnectionObserver* observer = nullptr); - virtual ~IApiConnector() = default; - - /** - * - * Initialize the connection - * @param initial: set to false if its for reconnect / connect in error - * @return true if connection with the wifi was made - */ - virtual bool start_connect(bool initial) = 0; - - /** - * Disconnect - */ - virtual void stop() = 0; - - /** - * Test the connection to the API - */ - virtual bool test() = 0; - - /** - * Check if the connection is up - * @return true if connected - */ - virtual bool is_connected() = 0; - - /** - * Initialize the process of a new reading. - * @param reading: new reading to process - */ - virtual void init_reading_report(Reading& reading) final; - - /** - * Check if enough time has passed to send the latest reading to api - * @return - */ - bool time_to_send() const; - - /** - * reset the api time and merged readings - */ - void reset(); - - void set_observer(ApiConnectionObserver* _observer); - protected: - - /** - * Process a new reading. will merge with existing readings and if its time, it will be posted to the API - * @param reading: new reading to process - */ - virtual void process_reading(Reading& reading) final; - - /** - * Send a reading to the API - * @param reading: reading to send - * @return: true if the API call was successful - */ - virtual bool send_reading() = 0; - - /** - * When a reading cannot be send to the API, we save it to send later.. - * @param reading: reading to save - */ - virtual void save_reading() final; - - EspConfig& _config; - CircularBuffer _saved_readings; - uint32_t _last_send; - Reading _merged_reading; - - ApiConnectionObserver* _observer; - - bool _alert; - - // To access the saved readings - friend class ApiReportDoneState; - friend class ApiProcessReadingState; - friend class PublishApiState; - friend class ApiReportFailedState; - friend class ApiProcessReadingState; - -}; - -class ApiConnectionObserver { - public: - virtual void api_reported(IApiConnector::ReportApiStatus status) = 0; -}; - -#endif //BGEIGIECAST_I_APICONNECTOR_H diff --git a/bgeigiecast/identifiers.h b/bgeigiecast/identifiers.h new file mode 100644 index 0000000..ccad23e --- /dev/null +++ b/bgeigiecast/identifiers.h @@ -0,0 +1,17 @@ +#ifndef BGEIGIECAST_IDENTIFIERS_H_ +#define BGEIGIECAST_IDENTIFIERS_H_ + +enum DataWorkers { + k_worker_bgeigie_connector = 0, + k_worker_configuration_server, +}; + +enum DataHandlers { + k_handler_controller_handler = 0, + k_handler_storage_handler, + k_handler_bluetooth_reporter, + k_handler_api_reporter, +}; + + +#endif //BGEIGIECAST_IDENTIFIERS_H_ diff --git a/bgeigiecast/esp_config.cpp b/bgeigiecast/local_storage.cpp similarity index 72% rename from bgeigiecast/esp_config.cpp rename to bgeigiecast/local_storage.cpp index f94a3ec..813b3a9 100644 --- a/bgeigiecast/esp_config.cpp +++ b/bgeigiecast/local_storage.cpp @@ -1,9 +1,11 @@ -#include -#include -#include -#include "esp_config.h" +#include "local_storage.h" #include "debugger.h" +#include "identifiers.h" +#include "reading.h" +#include "controller.h" + +#define D_SAVED_STATE Controller::k_savable_MobileMode const char* memory_name = "data"; @@ -22,7 +24,9 @@ const char* key_home_latitude = "home_latitude"; const char* key_last_longtitude = "last_longtitude"; const char* key_last_latitude = "last_latitude"; -EspConfig::EspConfig() : +LocalStorage::LocalStorage() : + Handler(k_handler_storage_handler), + _memory(), _device_id(0), _ap_password(""), _wifi_ssid(""), @@ -36,11 +40,10 @@ EspConfig::EspConfig() : _home_longitude(0), _home_latitude(0), _last_longitude(0), - _last_latitude(0), - _memory() { + _last_latitude(0) { } -void EspConfig::reset_defaults() { +void LocalStorage::reset_defaults() { if(clear()) { set_device_id(D_DEVICE_ID, true); set_ap_password(D_ACCESS_POINT_PASSWORD, true); @@ -59,99 +62,63 @@ void EspConfig::reset_defaults() { } } -uint16_t EspConfig::get_device_id() const { +uint16_t LocalStorage::get_device_id() const { return _device_id; } -const char* EspConfig::get_ap_password() const { +const char* LocalStorage::get_ap_password() const { return _ap_password; } -const char* EspConfig::get_wifi_ssid() const { +const char* LocalStorage::get_wifi_ssid() const { return _wifi_ssid; } -const char* EspConfig::get_wifi_password() const { +const char* LocalStorage::get_wifi_password() const { return _wifi_password; } -const char* EspConfig::get_api_key() const { +const char* LocalStorage::get_api_key() const { return _api_key; } -uint8_t EspConfig::get_saved_state() const { +int8_t LocalStorage::get_saved_state() const { return _saved_state; } -bool EspConfig::is_led_color_blind() const { +bool LocalStorage::is_led_color_blind() const { return _led_color_blind; } -uint8_t EspConfig::get_led_color_intensity() const { +uint8_t LocalStorage::get_led_color_intensity() const { return _led_color_intensity; } -bool EspConfig::get_use_dev() const { +bool LocalStorage::get_use_dev() const { return _use_dev; } -bool EspConfig::get_use_home_location() const { +bool LocalStorage::get_use_home_location() const { return _use_home_location; } -double EspConfig::get_home_longitude() const { +double LocalStorage::get_home_longitude() const { return _home_longitude; } -double EspConfig::get_home_latitude() const { +double LocalStorage::get_home_latitude() const { return _home_latitude; } -double EspConfig::get_last_longitude() const { +double LocalStorage::get_last_longitude() const { return _last_longitude; } -double EspConfig::get_last_latitude() const { +double LocalStorage::get_last_latitude() const { return _last_latitude; } -void EspConfig::set_all() { - _memory.begin(memory_name, true); - _device_id = _memory.getUShort(key_device_id, D_DEVICE_ID); - if(_memory.getString(key_ap_password, _ap_password, CONFIG_VAL_MAX) == 0) { - strcpy(_ap_password, D_ACCESS_POINT_PASSWORD); - } - if(_memory.getString(key_wifi_ssid, _wifi_ssid, CONFIG_VAL_MAX) == 0) { - strcpy(_wifi_ssid, D_WIFI_SSID); - } - if(_memory.getString(key_wifi_password, _wifi_password, CONFIG_VAL_MAX) == 0) { - strcpy(_wifi_password, D_WIFI_PASSWORD); - } - if(_memory.getString(key_api_key, _api_key, CONFIG_VAL_MAX) == 0) { - strcpy(_api_key, D_APIKEY); - } - _use_dev = _memory.getBool(key_use_dev, D_USE_DEV_SERVER); - _led_color_blind = _memory.getBool(key_led_color_blind, D_LED_COLOR_BLIND); - _led_color_intensity = _memory.getUChar(key_led_color_intensity, D_LED_COLOR_INTENSITY); - _saved_state = _memory.getUChar(key_saved_state, D_SAVED_STATE); - _use_home_location = _memory.getBool(key_led_color_blind, false); - _home_longitude = _memory.getDouble(key_home_longtitude, 0); - _home_latitude = _memory.getDouble(key_home_latitude, 0); - _last_longitude = _memory.getDouble(key_last_longtitude, 0); - _last_latitude = _memory.getDouble(key_last_latitude, 0); - _memory.end(); -} - -bool EspConfig::clear() { - if(_memory.begin(memory_name)) { - _memory.clear(); - _memory.end(); - return true; - } - return false; -} - -void EspConfig::set_device_id(uint16_t device_id, bool force) { +void LocalStorage::set_device_id(uint16_t device_id, bool force) { if(force || (device_id != _device_id)) { if(_memory.begin(memory_name)) { _device_id = device_id; @@ -163,7 +130,7 @@ void EspConfig::set_device_id(uint16_t device_id, bool force) { } } -void EspConfig::set_ap_password(const char* ap_password, bool force) { +void LocalStorage::set_ap_password(const char* ap_password, bool force) { if(force || (ap_password != nullptr && strlen(ap_password) < CONFIG_VAL_MAX)) { if(_memory.begin(memory_name)) { strcpy(_ap_password, ap_password); @@ -175,7 +142,7 @@ void EspConfig::set_ap_password(const char* ap_password, bool force) { } } -void EspConfig::set_wifi_ssid(const char* wifi_ssid, bool force) { +void LocalStorage::set_wifi_ssid(const char* wifi_ssid, bool force) { if(force || (wifi_ssid != nullptr && strlen(wifi_ssid) < CONFIG_VAL_MAX)) { if(_memory.begin(memory_name)) { strcpy(_wifi_ssid, wifi_ssid); @@ -187,7 +154,7 @@ void EspConfig::set_wifi_ssid(const char* wifi_ssid, bool force) { } } -void EspConfig::set_wifi_password(const char* wifi_password, bool force) { +void LocalStorage::set_wifi_password(const char* wifi_password, bool force) { if(force || (wifi_password != nullptr && strlen(wifi_password) < CONFIG_VAL_MAX)) { if(_memory.begin(memory_name)) { strcpy(_wifi_password, wifi_password); @@ -199,7 +166,7 @@ void EspConfig::set_wifi_password(const char* wifi_password, bool force) { } } -void EspConfig::set_api_key(const char* api_key, bool force) { +void LocalStorage::set_api_key(const char* api_key, bool force) { if(force || (api_key != nullptr && strlen(api_key) < CONFIG_VAL_MAX)) { if(_memory.begin(memory_name)) { strcpy(_api_key, api_key); @@ -211,7 +178,7 @@ void EspConfig::set_api_key(const char* api_key, bool force) { } } -void EspConfig::set_use_dev(bool use_dev, bool force) { +void LocalStorage::set_use_dev(bool use_dev, bool force) { if(force || (use_dev != _use_dev)) { if(_memory.begin(memory_name)) { _use_dev = use_dev; @@ -223,7 +190,7 @@ void EspConfig::set_use_dev(bool use_dev, bool force) { } } -void EspConfig::set_led_color_blind(bool led_color_blind, bool force) { +void LocalStorage::set_led_color_blind(bool led_color_blind, bool force) { if(force || (led_color_blind != _led_color_blind)) { if(_memory.begin(memory_name)) { _led_color_blind = led_color_blind; @@ -235,7 +202,7 @@ void EspConfig::set_led_color_blind(bool led_color_blind, bool force) { } } -void EspConfig::set_led_color_intensity(uint8_t led_color_intensity, bool force) { +void LocalStorage::set_led_color_intensity(uint8_t led_color_intensity, bool force) { if(force || (led_color_intensity != _led_color_intensity)) { if(_memory.begin(memory_name)) { _led_color_intensity = led_color_intensity; @@ -245,14 +212,13 @@ void EspConfig::set_led_color_intensity(uint8_t led_color_intensity, bool force) DEBUG_PRINTLN("unable to save new value for key_led_color_intensity"); } } - } -void EspConfig::set_saved_state(uint8_t saved_state, bool force) { +void LocalStorage::set_saved_state(uint8_t saved_state, bool force) { if(force || (saved_state != _saved_state)) { if(_memory.begin(memory_name)) { _saved_state = saved_state; - _memory.putUChar(key_saved_state, saved_state); + _memory.putChar(key_saved_state, saved_state); _memory.end(); } else { DEBUG_PRINTLN("unable to save new value for init_fixed"); @@ -260,7 +226,7 @@ void EspConfig::set_saved_state(uint8_t saved_state, bool force) { } } -void EspConfig::set_use_home_location(bool use_home_location, bool force) { +void LocalStorage::set_use_home_location(bool use_home_location, bool force) { if(force || (use_home_location != _use_home_location)) { if(_memory.begin(memory_name)) { _use_home_location = use_home_location; @@ -272,7 +238,7 @@ void EspConfig::set_use_home_location(bool use_home_location, bool force) { } } -void EspConfig::set_home_longitude(double home_longtitude, bool force) { +void LocalStorage::set_home_longitude(double home_longtitude, bool force) { if(_memory.begin(memory_name)) { _home_longitude = home_longtitude; _memory.putDouble(key_home_longtitude, home_longtitude); @@ -282,7 +248,7 @@ void EspConfig::set_home_longitude(double home_longtitude, bool force) { } } -void EspConfig::set_home_latitude(double home_latitude, bool force) { +void LocalStorage::set_home_latitude(double home_latitude, bool force) { if(_memory.begin(memory_name)) { _home_latitude = home_latitude; _memory.putDouble(key_home_latitude, home_latitude); @@ -292,7 +258,7 @@ void EspConfig::set_home_latitude(double home_latitude, bool force) { } } -void EspConfig::set_last_longitude(double last_longitude, bool force) { +void LocalStorage::set_last_longitude(double last_longitude, bool force) { if(_memory.begin(memory_name)) { _last_longitude = last_longitude; _memory.putDouble(key_last_longtitude, last_longitude); @@ -302,7 +268,7 @@ void EspConfig::set_last_longitude(double last_longitude, bool force) { } } -void EspConfig::set_last_latitude(double last_latitude, bool force) { +void LocalStorage::set_last_latitude(double last_latitude, bool force) { if(_memory.begin(memory_name)) { _last_latitude = last_latitude; _memory.putDouble(key_last_latitude, last_latitude); @@ -311,3 +277,55 @@ void EspConfig::set_last_latitude(double last_latitude, bool force) { DEBUG_PRINTLN("unable to save new value for key_last_latitude"); } } + +bool LocalStorage::clear() { + if(_memory.begin(memory_name)) { + _memory.clear(); + _memory.end(); + return true; + } + return false; +} + +bool LocalStorage::activate(bool) { + _memory.begin(memory_name, true); + _device_id = _memory.getUShort(key_device_id, D_DEVICE_ID); + if(_memory.getString(key_ap_password, _ap_password, CONFIG_VAL_MAX) == 0) { + strcpy(_ap_password, D_ACCESS_POINT_PASSWORD); + } + if(_memory.getString(key_wifi_ssid, _wifi_ssid, CONFIG_VAL_MAX) == 0) { + strcpy(_wifi_ssid, D_WIFI_SSID); + } + if(_memory.getString(key_wifi_password, _wifi_password, CONFIG_VAL_MAX) == 0) { + strcpy(_wifi_password, D_WIFI_PASSWORD); + } + if(_memory.getString(key_api_key, _api_key, CONFIG_VAL_MAX) == 0) { + strcpy(_api_key, D_APIKEY); + } + _use_dev = _memory.getBool(key_use_dev, D_USE_DEV_SERVER); + _led_color_blind = _memory.getBool(key_led_color_blind, D_LED_COLOR_BLIND); + _led_color_intensity = _memory.getUChar(key_led_color_intensity, D_LED_COLOR_INTENSITY); + _saved_state = _memory.getChar(key_saved_state, D_SAVED_STATE); + _use_home_location = _memory.getBool(key_led_color_blind, false); + _home_longitude = _memory.getDouble(key_home_longtitude, 0); + _home_latitude = _memory.getDouble(key_home_latitude, 0); + _last_longitude = _memory.getDouble(key_last_longtitude, 0); + _last_latitude = _memory.getDouble(key_last_latitude, 0); + _memory.end(); + return true; +} + +int8_t LocalStorage::handle_produced_work(const worker_status_t& worker_reports) { + // Get reading data to store + const auto& reader = worker_reports.at(k_worker_bgeigie_connector); + if(reader.is_fresh()) { + const auto& reading = reader.get(); + set_device_id(reading.get_device_id(), false); + if(reading.get_status() & k_reading_gps_ok) { + set_last_latitude(reading.get_latitude(), false); + set_last_longitude(reading.get_longitude(), false); + } + return HandlerStatus::e_handler_data_handled; + } + return HandlerStatus::e_handler_idle; +} diff --git a/bgeigiecast/esp_config.h b/bgeigiecast/local_storage.h similarity index 90% rename from bgeigiecast/esp_config.h rename to bgeigiecast/local_storage.h index 431da6b..49f2b71 100644 --- a/bgeigiecast/esp_config.h +++ b/bgeigiecast/local_storage.h @@ -3,20 +3,17 @@ #include +#include + #define CONFIG_VAL_MAX 32 /** * Configurations for the ESP32, stored in the flash memory */ -class EspConfig { +class LocalStorage : public Handler{ public: - EspConfig(); - virtual ~EspConfig() = default; - - /** - * Read all settings - */ - virtual void set_all(); + LocalStorage(); + virtual ~LocalStorage() = default; /** * Reset settings to default (defined in user_config) @@ -32,7 +29,7 @@ class EspConfig { virtual bool get_use_dev() const final; virtual bool is_led_color_blind() const final; virtual uint8_t get_led_color_intensity() const final; - virtual uint8_t get_saved_state() const final; + virtual int8_t get_saved_state() const final; virtual bool get_use_home_location() const final; virtual double get_home_longitude() const final; @@ -58,7 +55,14 @@ class EspConfig { protected: virtual bool clear(); + /** + * Read all settings + */ + bool activate(bool) override; + int8_t handle_produced_work(const worker_status_t& worker_reports) override; private: + Preferences _memory; + // Device uint16_t _device_id; @@ -78,7 +82,7 @@ class EspConfig { uint8_t _led_color_intensity; // Flag if fixed or mobile mode is started after init - uint8_t _saved_state; + int8_t _saved_state; // Home location configs bool _use_home_location; @@ -87,9 +91,6 @@ class EspConfig { double _last_longitude; double _last_latitude; - - Preferences _memory; - }; #endif //BGEIGIECAST_ESP_CONFIG_H diff --git a/bgeigiecast/mode_led.cpp b/bgeigiecast/mode_led.cpp index 4daadf6..a2e9339 100644 --- a/bgeigiecast/mode_led.cpp +++ b/bgeigiecast/mode_led.cpp @@ -6,13 +6,16 @@ // Set this to true if we use anode LED #define RGB_STATE_LED_REVERSED true -ModeLED::ModeLED(EspConfig& config) : +ModeLED::ModeLED(LocalStorage& config) : RGBLed(RGB_LED_PIN_R, RGB_LED_PIN_G, RGB_LED_PIN_B, RGB_STATE_LED_REVERSED), + Supervisor(), _config(config), - _blink_state(false), + color(ModeColor::mode_color_off), + frequency(0), + percentage_on(0), _colorTypes{ - // Normal Colorblind - // R G B R G B + // Normal Colorblind + // R G B , R G B {{000, 000, 000}, {000, 000, 000}}, // off {{063, 127, 063}, {063, 127, 063}}, // init {{063, 000, 063}, {063, 000, 063}}, // init config @@ -24,26 +27,43 @@ ModeLED::ModeLED(EspConfig& config) : } { } -void ModeLED::set_color(ModeLED::ModeColor color) { +void ModeLED::set_color(ModeLED::ModeColor _color, double _frequency, uint8_t _percentage_on) { DEBUG_PRINT("Changed LED to "); - DEBUG_PRINTLN(color); - set(_config.is_led_color_blind() ? _colorTypes[color].color_blind : _colorTypes[color].normal); + DEBUG_PRINTLN(_color); + color = _color; + if (frequency > 0){ + frequency = _frequency; + percentage_on = _percentage_on; + } + else { + // If not blinking, set here. Else the loop will take care of the setter + set(_config.is_led_color_blind() ? _colorTypes[color].color_blind : _colorTypes[color].normal); + } } -void ModeLED::blink(ModeLED::ModeColor color, double frequency, double percentage_on) { - // Blink LED - double blink_millis = 1000 / frequency; - uint32_t cycle_now = millis() % static_cast(blink_millis); - uint32_t threshold = static_cast(blink_millis * (percentage_on / 100)); - if(cycle_now < threshold && !_blink_state) { - set_color(color); - _blink_state = true; - } else if(cycle_now > threshold && _blink_state) { - set_color(ModeLED::ModeColor::off); - _blink_state = false; +void ModeLED::loop() { + if(frequency > 0) { + // Blink LED + double blink_millis = 1000 / frequency; + auto cycle_now = millis() % static_cast(blink_millis); + auto threshold = static_cast(blink_millis * (percentage_on / 100.0)); + if(cycle_now < threshold) { + set_color(color); + } else if(cycle_now > threshold) { + set_color(ModeLED::mode_color_off); + } } } uint8_t ModeLED::get_intensity() const { return _config.get_led_color_intensity(); } + +bool ModeLED::activate() { + init(); + return true; +} + +void ModeLED::handle_report(const Report& report) { + // TODO +} diff --git a/bgeigiecast/mode_led.h b/bgeigiecast/mode_led.h index 68880f8..4d7786b 100644 --- a/bgeigiecast/mode_led.h +++ b/bgeigiecast/mode_led.h @@ -2,32 +2,45 @@ #define BGEIGIECAST_STATE_LED_H #include "rgb_led.h" -#include "esp_config.h" +#include "local_storage.h" + +#include /** - * Controls the LED to visualize the current state + * Controls the LED to visualize the current mode */ -class ModeLED : private RGBLed { +class ModeLED : private RGBLed, public Supervisor { public: typedef enum { - off, - init, - init_config, - config, - mobile, - fixed_connecting, - fixed_active, - fixed_error, - COUNT + mode_color_off, + mode_color_init, + mode_color_init_config, + mode_color_config, + mode_color_mobile, + mode_color_fixed_connecting, + mode_color_fixed_active, + mode_color_fixed_error, + mode_color_COUNT } ModeColor; - explicit ModeLED(EspConfig& config); + explicit ModeLED(LocalStorage& config); virtual ~ModeLED() = default; - void set_color(ModeColor color); + /** + * Set color + * @param color : color type (ModeColor) + * @param frequency : times per second to update if blink (0 for not blinking) + * - example, frequency of 1 will blink once a second + * @param percentage_on : if frequency > 0, it will + * - example, percentage of 25 with 1 frequency, will 0.25 second LED on then 0.75 second LED off + */ + void set_color(ModeColor color, double frequency = 0, uint8_t percentage_on = 50); + + void loop(); - void blink(ModeColor color, double frequency, double percentage_on = 50); + void handle_report(const Report& report) override; + bool activate() override; private: typedef struct { RGB normal; @@ -36,9 +49,11 @@ class ModeLED : private RGBLed { uint8_t get_intensity() const override; - const EspConfig& _config; - bool _blink_state; - const ColorType _colorTypes[ModeColor::COUNT]; + const LocalStorage& _config; + ModeColor color; + double frequency; + uint8_t percentage_on; + const ColorType _colorTypes[ModeColor::mode_color_COUNT]; }; #endif //BGEIGIECAST_STATE_LED_H diff --git a/bgeigiecast/reading.cpp b/bgeigiecast/reading.cpp index 175985a..1e81763 100644 --- a/bgeigiecast/reading.cpp +++ b/bgeigiecast/reading.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include "reading.h" @@ -7,15 +8,44 @@ #define EXPECTED_PARSE_RESULT_COUNT 15 #define VALID_BGEIGIE_ID(id) (id >= 1000 && id < 10000) +#define HOME_LOCATION_PRECISION_KM 0.2 -#define LONG_LAT_PRECISION 0.001 - +/** + * Convert degree minutes to decimal degree + * @param dm + * @return + */ double dm_to_dd(double dm) { double degree = static_cast(dm / 100); double minutes = dm - (degree * 100); return degree + minutes / 60; } +/** + * Calculate distance using haversine formula + * @param lon1 + * @param lat1 + * @param lon2 + * @param lat2 + * @return distance in km + */ +double calc_distance(double lon1, double lat1, double lon2, double lat2) { + //This portion converts the current and destination GPS coords from decDegrees to Radians + lon1 *= (PI / 180); + lon2 *= (PI / 180); + lat1 *= (PI / 180); + lat2 *= (PI / 180); + + //This portion calculates the differences for the Radian latitudes and longitudes and saves them to variables + double dlon = lon2 - lon1; + double dlat = lat2 - lat1; + + //This portion is the Haversine Formula for distance between two points. Returned value is in KM + double a = (sq(sin(dlat / 2))) + cos(lat1) * cos(lat2) * (sq(sin(dlon / 2))); + double e = 2 * atan2(sqrt(a), sqrt(1 - a)); + return 6371.00 * e; +} + Reading::Reading() : _reading_str(""), _status(0x0), @@ -169,8 +199,7 @@ void Reading::reset() { } void Reading::apply_home_location(double home_lat, double home_long) { - if(_latitude < home_lat + LONG_LAT_PRECISION && _latitude > home_lat - LONG_LAT_PRECISION - && _longitude < home_long + LONG_LAT_PRECISION && _longitude > home_long - LONG_LAT_PRECISION) { + if(calc_distance(_longitude, _latitude, home_long, home_lat) < HOME_LOCATION_PRECISION_KM) { DEBUG_PRINTF("Gps in home location, setting reading location to %.5f , %.5f\n", home_lat, home_long); _latitude = home_lat; _longitude = home_long; @@ -237,39 +266,51 @@ bool Reading::valid_reading() const { const char* Reading::get_reading_str() const { return _reading_str; } + uint8_t Reading::get_status() const { return _status; } + uint16_t Reading::get_device_id() const { return _device_id; } + uint32_t Reading::get_fixed_device_id() const { return 60000 + _device_id; } + const char* Reading::get_iso_timestr() const { return _iso_timestr; } + uint16_t Reading::get_cpm() const { return _cpm; } + uint16_t Reading::get_cpb() const { return _cpb; } + uint16_t Reading::get_total_count() const { return _total_count; } + double Reading::get_latitude() const { return _latitude; } + double Reading::get_longitude() const { return _longitude; } + double Reading::get_altitude() const { return _altitude; } + int Reading::get_sat_count() const { return _sat_count; } + float Reading::get_precision() const { return _precision; } diff --git a/bgeigiecast/reporter.cpp b/bgeigiecast/reporter.cpp deleted file mode 100644 index f6dae93..0000000 --- a/bgeigiecast/reporter.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "reporter.h" -#include "sm_r_concrete_states.h" - -// Every 5 seconds -#define BGEIGIE_MEASUREMENTS_SECONDS 5 -#define BGEIGIE_READING_SLACK 500 -#define READING_DELAY (BGEIGIE_MEASUREMENTS_SECONDS * 1000) - BGEIGIE_READING_SLACK - -Reporter::Reporter(EspConfig& config, - Stream& bgeigie_connection, - IApiConnector& api_connector, - BluetoohConnector& bluetooth_connector, - ReporterObserver* observer) : - _bgeigie_connector(bgeigie_connection), - _config(config), - _api_connector(api_connector), - _bluetooth(bluetooth_connector), - _observer(observer), _reading(), - _last_reading_moment(0), - _report_bt(false), - _report_api(false), - _idle(false) { - _api_connector.set_observer(this); -} - -void Reporter::setup_state_machine() { - set_state(new ReporterIdleState(*this)); -} - -void Reporter::set_report_output(bool bt, bool api) { - _report_bt = bt; - _report_api = api; - if(_report_api) { - _api_connector.reset(); - } -} - -uint32_t Reporter::time_till_next_reading(uint32_t current) const { - return _last_reading_moment != 0 && current - _last_reading_moment < READING_DELAY ? READING_DELAY - - (current - _last_reading_moment) : 0; -} - -void Reporter::get_new_reading() { - if(_bgeigie_connector.get_reading(_reading)) { - _last_reading_moment = millis(); - _reading.get_status() & k_reading_parsed - ? schedule_event(e_r_reading_received) : schedule_event(e_r_reading_invalid); - if(_reading.get_device_id() > 0) { - _config.set_device_id(_reading.get_device_id(), false); - } - _config.set_last_latitude(_reading.get_latitude(), false); - _config.set_last_longitude(_reading.get_longitude(), false); - } -} - -bool Reporter::is_idle() const { - return _idle; -} - -void Reporter::init_bluetooth_connector() { - if(_reading.get_status() & k_reading_parsed) { - _bluetooth.init(_reading.get_device_id()); - schedule_event(e_r_bluetooth_initialized); - } -} - -void Reporter::run_bluetooth_connector() { - _bluetooth.send_reading(_reading) ? schedule_event(e_r_reading_reported_bt) : schedule_event(e_r_reading_skipped_bt); -} - -void Reporter::init_api_connector() { - _api_connector.init_reading_report(_reading); - schedule_event(e_r_api_connector_initialized); -} - -void Reporter::run_api_connector() { - _api_connector.run(); -} - -void Reporter::set_observer(ReporterObserver* observer) { - _observer = observer; -} - -void Reporter::api_reported(IApiConnector::ReportApiStatus status) { - switch(status) { - case IApiConnector::k_report_success: - schedule_event(e_r_reading_reported_api_success); - break; - case IApiConnector::k_report_skipped: - schedule_event(e_r_reading_reported_api_no_change); - break; - case IApiConnector::k_report_failed: - schedule_event(e_r_reading_reported_api_failed); - break; - } -} - -void Reporter::report_complete(ReporterStatus status) { - if(_observer) { - _observer->reading_reported(status); - } - schedule_event(e_r_reading_reported); -} - -const Reading& Reporter::get_last_reading() const { - return _reading; -} diff --git a/bgeigiecast/reporter.h b/bgeigiecast/reporter.h deleted file mode 100644 index 45f0c58..0000000 --- a/bgeigiecast/reporter.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef BGEIGIECAST_REPORTER_H -#define BGEIGIECAST_REPORTER_H - -#include - -#include "bluetooth_connector.h" -#include "i_api_connector.h" -#include "bgeigie_connector.h" -#include "sm_context.h" - -class ReporterObserver; - -/** - * The reporter will receive instructions to get and report readings from the bgeigie to the api / bluetooth - */ -class Reporter : public Context, private ApiConnectionObserver { - public: - - /** - * - */ - typedef enum { - k_reporter_no_change, - k_reporter_failed, - k_reporter_success, - } ReporterStatus; - - /** - * Create a new reporter - * @param config : config connection to be used for the reporter and outgoing connections - * @param bgeigie_connection : Stream connected to the bGeigieNano (Serial) - * @param api_connector : Wifi connector to the API - * @param bluetooth_connector : Bluetooth connector - * @param observer : Some instance to report to, default null - */ - Reporter(EspConfig& config, - Stream& bgeigie_connection, - IApiConnector& api_connector, - BluetoohConnector& bluetooth_connector, - ReporterObserver* observer = nullptr); - virtual ~Reporter() = default; - - /** - * Set initial state for the state machine, - */ - void setup_state_machine(); - - /** - * Set to which outputs the reporter should report to - * @param bt : report over bluetooth (boolean) - * @param api : report to api (boolean) - */ - void set_report_output(bool bt, bool api); - - uint32_t time_till_next_reading(uint32_t current) const; - - bool is_idle() const; - - void set_observer(ReporterObserver* _observer); - - const Reading& get_last_reading() const; - - private: - void api_reported(IApiConnector::ReportApiStatus status) override; - - /** - * Get new reading from the bgeigie connector - */ - void get_new_reading(); - - /** - * Initialize the bluetooth connection - */ - void init_bluetooth_connector(); - - /** - * publish the reading over bluetooth - */ - void run_bluetooth_connector(); - - /** - * Initialize the API connector state machine - */ - void init_api_connector(); - - /** - * Run the api connector state machine - */ - void run_api_connector(); - - void report_complete(ReporterStatus status); - - BGeigieConnector _bgeigie_connector; - EspConfig& _config; - IApiConnector& _api_connector; - BluetoohConnector& _bluetooth; - - ReporterObserver* _observer; - - Reading _reading; - uint32_t _last_reading_moment; - - bool _report_bt; - bool _report_api; - - bool _idle; - - // Friend list - friend class ReporterIdleState; - friend class GetReadingState; - friend class ReporterDoneState; - friend class InitBluetoothState; - friend class PublishBluetoothState; - friend class InitApiState; - friend class ReportApiState; - friend class ReporterDoneState; -}; - -/** - * Observing the reporter, gets callback one report is done - */ -class ReporterObserver { - public: - virtual void reading_reported(Reporter::ReporterStatus status) = 0; -}; - -#endif //BGEIGIECAST_REPORTER_H diff --git a/bgeigiecast/rgb_led.cpp b/bgeigiecast/rgb_led.cpp index 237eb92..3dc75c3 100644 --- a/bgeigiecast/rgb_led.cpp +++ b/bgeigiecast/rgb_led.cpp @@ -8,13 +8,17 @@ #define CHANNEL_RESOLUTION 8 RGBLed::RGBLed(uint8_t pin_r, uint8_t pin_g, uint8_t pin_b, bool reversed) : _reversed(reversed), config_intensity(30) { + ledcAttachPin(pin_r, CHANNEL_R); + ledcAttachPin(pin_g, CHANNEL_G); + ledcAttachPin(pin_b, CHANNEL_B); +} + +void RGBLed::init() { // Connect pins to channels ledcSetup(CHANNEL_R, CHANNEL_FREQUENCY, CHANNEL_RESOLUTION); - ledcAttachPin(pin_r, CHANNEL_R); ledcSetup(CHANNEL_G, CHANNEL_FREQUENCY, CHANNEL_RESOLUTION); - ledcAttachPin(pin_g, CHANNEL_G); ledcSetup(CHANNEL_B, CHANNEL_FREQUENCY, CHANNEL_RESOLUTION); - ledcAttachPin(pin_b, CHANNEL_B); + off(); } void RGBLed::set(const RGB& values) { @@ -53,4 +57,4 @@ void RGBLed::set_channel(uint8_t channel, uint8_t value) { uint32_t modified_value = static_cast((get_intensity() / 255.0) * value); // using 256 below because when its inverted 255 will still be very dim, 256 will be 100% turned off. ledcWrite(channel, _reversed ? (256 - modified_value) : modified_value); -} \ No newline at end of file +} diff --git a/bgeigiecast/rgb_led.h b/bgeigiecast/rgb_led.h index 3e7aad7..ffdee1a 100644 --- a/bgeigiecast/rgb_led.h +++ b/bgeigiecast/rgb_led.h @@ -23,6 +23,8 @@ class RGBLed { void set(const RGB& values); + void init(); + void off(); void set_r(uint8_t value); diff --git a/bgeigiecast/sm_a_concrete_states.cpp b/bgeigiecast/sm_a_concrete_states.cpp deleted file mode 100644 index 2760f6b..0000000 --- a/bgeigiecast/sm_a_concrete_states.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include "sm_a_concrete_states.h" - -// region ApiProcessReadingState - -ApiProcessReadingState::ApiProcessReadingState(IApiConnector& context, Reading& reading) - : ApiReporterState(context), _reading(reading) {} - -void ApiProcessReadingState::entry_action() { -#if DEBUG_LOG_STATE_TRANSITIONS - DEBUG_PRINTLN("-- API entered state Process"); -#endif -} - -void ApiProcessReadingState::do_activity() { - api_connector.process_reading(_reading); -} - -void ApiProcessReadingState::exit_action() {} - -void ApiProcessReadingState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_a_report_reading: - api_connector.set_state(new ConnectWiFiState(api_connector)); - break; - case e_a_not_reporting: - api_connector.set_state(new ApiReportDoneState(api_connector, IApiConnector::k_report_skipped)); - break; - default: - ApiReporterState::handle_event(event_id); - break; - } -} - -// endregion - -// region ConnectWiFiState - - -#define RETRY_CONNECTION 1000 -#define CONNECTION_TIMEOUT 3000 - -ConnectWiFiState::ConnectWiFiState(IApiConnector& context) - : ApiReporterState(context), _start_time(0), _last_connect_try(0) {} - -void ConnectWiFiState::entry_action() { -#if DEBUG_LOG_STATE_TRANSITIONS - DEBUG_PRINTLN("-- API entered state Connecting"); -#endif - api_connector.start_connect(true); - _start_time = millis(); - _last_connect_try = millis(); -} - -void ConnectWiFiState::do_activity() { - if(api_connector.is_connected()) { - api_connector.schedule_event(e_a_wifi_connected); - } else if(millis() - _last_connect_try > RETRY_CONNECTION) { - _last_connect_try = millis(); - api_connector.start_connect(false); - } else if(millis() - _start_time > CONNECTION_TIMEOUT) { - api_connector.schedule_event(e_a_wifi_connection_error); - } -} - -void ConnectWiFiState::exit_action() {} - -void ConnectWiFiState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_a_wifi_connected: - api_connector.set_state(new PublishApiState(api_connector)); - break; - case e_a_wifi_connection_error: - api_connector.set_state(new ApiReportFailedState(api_connector)); - break; - default: - ApiReporterState::handle_event(event_id); - break; - } -} - -// endregion - -// region PublishApiState - -PublishApiState::PublishApiState(IApiConnector& context) : ApiReporterState(context) {} - -void PublishApiState::entry_action() {} - -void PublishApiState::do_activity() { - api_connector.send_reading(); -} - -void PublishApiState::exit_action() {} - -void PublishApiState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_a_api_post_failed: - api_connector.set_state(new ApiReportFailedState(api_connector)); - break; - case e_a_reading_posted: - if(api_connector._saved_readings.get_count() > 0) { - api_connector._merged_reading = api_connector._saved_readings.get(); - api_connector.set_state(new PublishApiState(api_connector)); - } else { - api_connector.set_state(new ApiReportDoneState(api_connector, IApiConnector::k_report_success)); - } - break; - default: - ApiReporterState::handle_event(event_id); - break; - } -} - -// endregion - -// region ApiReportFailedState - -ApiReportFailedState::ApiReportFailedState(IApiConnector& context) : ApiReporterState(context) {} - -void ApiReportFailedState::entry_action() { -#if DEBUG_LOG_STATE_TRANSITIONS - DEBUG_PRINTLN("-- API entered state Failed"); -#endif -} - -void ApiReportFailedState::do_activity() { - api_connector.save_reading(); -} - -void ApiReportFailedState::exit_action() {} - -void ApiReportFailedState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_a_reading_saved: - api_connector.set_state(new ApiReportDoneState(api_connector, IApiConnector::k_report_failed)); - break; - default: - ApiReporterState::handle_event(event_id); - break; - } -} - -// endregion - -// region ApiReportDoneState - -ApiReportDoneState::ApiReportDoneState(IApiConnector& context, IApiConnector::ReportApiStatus status) - : ApiReporterState(context), status(status) {} - -void ApiReportDoneState::entry_action() { -#if DEBUG_LOG_STATE_TRANSITIONS - DEBUG_PRINTLN("-- API entered state Done"); -#endif - if(status == IApiConnector::k_report_failed || status == IApiConnector::k_report_success) { - api_connector._merged_reading.reset(); - } - if(api_connector._observer) { - api_connector._observer->api_reported(status); - } -} - -void ApiReportDoneState::do_activity() {} - -void ApiReportDoneState::exit_action() {} - -void ApiReportDoneState::handle_event(Event_enum event_id) { - switch(event_id) { - default: - ApiReporterState::handle_event(event_id); - break; - } -} - -// endregion \ No newline at end of file diff --git a/bgeigiecast/sm_a_concrete_states.h b/bgeigiecast/sm_a_concrete_states.h deleted file mode 100644 index 13d11b2..0000000 --- a/bgeigiecast/sm_a_concrete_states.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef BGEIGIECAST_SM_A_CONCRETE_STATES_H -#define BGEIGIECAST_SM_A_CONCRETE_STATES_H - -#include "sm_a_state.h" - -class ApiProcessReadingState : public ApiReporterState { - public: - explicit ApiProcessReadingState(IApiConnector& context, Reading& reading); - virtual ~ApiProcessReadingState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; - - private: - Reading& _reading; -}; - -class ConnectWiFiState : public ApiReporterState { - public: - explicit ConnectWiFiState(IApiConnector& context); - virtual ~ConnectWiFiState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; - private: - uint32_t _start_time; - uint32_t _last_connect_try; -}; - -class PublishApiState : public ApiReporterState { - public: - explicit PublishApiState(IApiConnector& context); - virtual ~PublishApiState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; -}; - -class ApiReportFailedState : public ApiReporterState { - public: - explicit ApiReportFailedState(IApiConnector& context); - virtual ~ApiReportFailedState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; -}; - -class ApiReportDoneState : public ApiReporterState { - public: - explicit ApiReportDoneState(IApiConnector& context, IApiConnector::ReportApiStatus status); - virtual ~ApiReportDoneState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; - private: - IApiConnector::ReportApiStatus status; -}; - -#endif //BGEIGIECAST_SM_A_CONCRETE_STATES_H diff --git a/bgeigiecast/sm_a_state.h b/bgeigiecast/sm_a_state.h deleted file mode 100644 index e69eef3..0000000 --- a/bgeigiecast/sm_a_state.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef BGEIGIECAST_SM_R_STATE_H -#define BGEIGIECAST_SM_R_STATE_H - -#include "i_api_connector.h" -#include "sm_state.h" - -/** - * State with api connector context, so the states can control the api connection - */ -class ApiReporterState : public State { - public: - explicit ApiReporterState(IApiConnector& context) : api_connector(context) {}; - virtual ~ApiReporterState() = default; - protected: - IApiConnector& api_connector; -}; - -#endif //BGEIGIECAST_SM_R_STATE_H diff --git a/bgeigiecast/sm_c_concete_states.cpp b/bgeigiecast/sm_c_concete_states.cpp index be91feb..080bd19 100644 --- a/bgeigiecast/sm_c_concete_states.cpp +++ b/bgeigiecast/sm_c_concete_states.cpp @@ -1,4 +1,7 @@ +#include + #include "sm_c_concete_states.h" +#include "identifiers.h" // region InitializeState @@ -33,23 +36,14 @@ void InitializeState::handle_event(Event_enum event_id) { // region InitReadingState -#define BLINK_FREQUENCY 1 -#define BLINK_DURATION_PERCENTAGE 10 - InitReadingState::InitReadingState(Controller& context) : ControllerState(context) { } void InitReadingState::entry_action() { DEBUG_PRINTLN("-- Entered state Initialize reading"); - controller._mode_led.set_color(ModeLED::ModeColor::init); } void InitReadingState::do_activity() { - controller._mode_led.blink(ModeLED::ModeColor::init, BLINK_FREQUENCY, BLINK_DURATION_PERCENTAGE); - controller._reporter.run(); - if(controller._reporter.get_last_reading().get_device_id()) { - controller.schedule_event(e_c_reading_initialized); - } } void InitReadingState::exit_action() { @@ -77,7 +71,6 @@ PostInitializeState::PostInitializeState(Controller& context) : ControllerState( void PostInitializeState::entry_action() { DEBUG_PRINTLN("-- Entered state PostInitialize"); - controller._mode_led.set_color(ModeLED::ModeColor::init); timer = millis(); } @@ -93,11 +86,20 @@ void PostInitializeState::exit_action() { void PostInitializeState::handle_event(Event_enum event_id) { switch(event_id) { case e_c_button_pressed: - controller.set_state(new SetupServerState(controller)); - break; - case e_c_post_init_time_passed: - controller.set_state(new InitActiveState(controller)); + controller.set_state(new ConfigurationModeState(controller)); + break; + case e_c_post_init_time_passed: { + switch(controller.get_saved_state()) { + case Controller::k_savable_FixedMode: + controller.set_state(new FixedModeState(controller)); + break; + case Controller::k_savable_MobileMode: + default: + controller.set_state(new MobileModeState(controller)); + break; + } break; + } default: ControllerState::handle_event(event_id); break; @@ -108,10 +110,10 @@ void PostInitializeState::handle_event(Event_enum event_id) { // region ConfigModeState -ConfigModeState::ConfigModeState(Controller& context) : ControllerState(context) { +ConfigurationModeState::ConfigurationModeState(Controller& context) : ControllerState(context) { } -void ConfigModeState::handle_event(Event_enum event_id) { +void ConfigurationModeState::handle_event(Event_enum event_id) { switch(event_id) { default: ControllerState::handle_event(event_id); @@ -119,158 +121,48 @@ void ConfigModeState::handle_event(Event_enum event_id) { } } -// endregion - -// region SetupServerState - -SetupServerState::SetupServerState(Controller& context) : ConfigModeState(context) { -} - -void SetupServerState::entry_action() { - DEBUG_PRINTLN("-- Entered state SetupServer"); - controller._mode_led.set_color(ModeLED::ModeColor::init_config); -} - -void SetupServerState::do_activity() { - if(controller._ap_server.connect()) { - controller.schedule_event(Event_enum::e_c_server_initialized); - } -} - -void SetupServerState::exit_action() { -} - -void SetupServerState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_c_server_initialized: - controller.set_state(new ServerActiveState(controller)); - break; - default: - ConfigModeState::handle_event(event_id); - break; - } -} - -// endregion - -// region ServerActiveState - -ServerActiveState::ServerActiveState(Controller& context) : ConfigModeState(context) { -} - -void ServerActiveState::entry_action() { - DEBUG_PRINTLN("-- Entered state ServerActive"); - controller._mode_led.set_color(ModeLED::ModeColor::config); - controller._ap_server.start_server(); -} - -void ServerActiveState::do_activity() { - controller._ap_server.handle_requests(); -} - -void ServerActiveState::exit_action() { - controller._ap_server.stop(); -} - -void ServerActiveState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_c_button_pressed: - controller.set_state(new InitActiveState(controller)); - break; - default: - ConfigModeState::handle_event(event_id); - break; - } +void ConfigurationModeState::entry_action() { +// controller.set_worker_active(k_worker_configuration_server, true); } -// endregion - -// region ActiveState - -ActiveState::ActiveState(Controller& context) : ControllerState(context) { -} +void ConfigurationModeState::do_activity() { -void ActiveState::do_activity() { - controller.sleep(); } -void ActiveState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_c_button_long_pressed: - controller.set_state(new ResetState(controller)); - break; - default: - ControllerState::handle_event(event_id); - break; - } -} - -// endregion - -// region InitActiveState - -InitActiveState::InitActiveState(Controller& context) : ActiveState(context) { -} - -void InitActiveState::entry_action() { - DEBUG_PRINTLN("-- Entered state ActiveInit"); -} - -void InitActiveState::do_activity() { - switch(controller.get_saved_state()) { - case k_savable_FixedMode: - controller.set_state(new DisconnectedState(controller)); - break; - case k_savable_MobileMode: - default: - controller.set_state(new MobileModeState(controller)); - break; - } -} - -void InitActiveState::exit_action() { - -} - -void InitActiveState::handle_event(Event_enum event_id) { - switch(event_id) { - default: - ActiveState::handle_event(event_id); - break; - } +void ConfigurationModeState::exit_action() { +// controller.set_worker_active(k_worker_configuration_server, true); } // endregion // region MobileModeState -MobileModeState::MobileModeState(Controller& context) : ActiveState(context) { +MobileModeState::MobileModeState(Controller& context) : ControllerState(context) { } void MobileModeState::entry_action() { DEBUG_PRINTLN("-- Entered state MobileMode"); - controller.save_state(k_savable_MobileMode); - controller._mode_led.set_color(ModeLED::ModeColor::mobile); - controller.set_reporter_outputs(true, false); + controller.save_state(Controller::k_savable_MobileMode); +// controller.set_handler_active(k_handler_bluetooth_reporter, true); } void MobileModeState::do_activity() { - ActiveState::do_activity(); } void MobileModeState::exit_action() { +// controller.set_handler_active(k_handler_bluetooth_reporter, false); } void MobileModeState::handle_event(Event_enum event_id) { switch(event_id) { case e_c_button_pressed: - controller.set_state(new DisconnectedState(controller)); + controller.set_state(new FixedModeState(controller)); break; case e_c_report_success: // Success, no need to do anything break; default: - ActiveState::handle_event(event_id); + ControllerState::handle_event(event_id); break; } } @@ -280,122 +172,27 @@ void MobileModeState::handle_event(Event_enum event_id) { // region FixedModeState -FixedModeState::FixedModeState(Controller& context) : ActiveState(context) { +FixedModeState::FixedModeState(Controller& context) : ControllerState(context) { } -void FixedModeState::do_activity() { - ActiveState::do_activity(); -} - -void FixedModeState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_c_button_pressed: - controller.set_state(new MobileModeState(controller)); - break; - default: - ActiveState::handle_event(event_id); - break; - } -} +void FixedModeState::entry_action() { -// endregion - -// region DisconnectedState - -DisconnectedState::DisconnectedState(Controller& context) : FixedModeState(context), state_entry_moment(0) { -} - -void DisconnectedState::entry_action() { - DEBUG_PRINTLN("-- Entered state FixedMode, Disconnected"); - controller.save_state(k_savable_FixedMode); - controller._mode_led.set_color(ModeLED::ModeColor::fixed_connecting); - controller.set_reporter_outputs(true, true); -} - -void DisconnectedState::do_activity() { - FixedModeState::do_activity(); -} - -void DisconnectedState::exit_action() { -} - -void DisconnectedState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_c_report_success: - controller.set_state(new ConnectedState(controller)); - break; - case e_c_report_failed: - controller.set_state(new ConnectionErrorState(controller)); - break; - default: - FixedModeState::handle_event(event_id); - break; - } } -// endregion - -// region ConnectedState - -ConnectedState::ConnectedState(Controller& context) : FixedModeState(context) { -} - -void ConnectedState::entry_action() { - DEBUG_PRINTLN("-- Entered state Connected"); - controller._mode_led.set_color(ModeLED::ModeColor::fixed_active); -} - -void ConnectedState::do_activity() { - FixedModeState::do_activity(); -} - -void ConnectedState::exit_action() { -} - -void ConnectedState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_c_report_failed: - controller.set_state(new DisconnectedState(controller)); - break; - case e_c_report_success: - // Success, no need to do anything already in connected state - break; - default: - FixedModeState::handle_event(event_id); - break; - } -} - -// endregion - -// region ConnectionErrorState - -ConnectionErrorState::ConnectionErrorState(Controller& context) : FixedModeState(context), timer(0) { -} - -void ConnectionErrorState::entry_action() { - DEBUG_PRINTLN("-- Entered state ConnectionError"); - controller._mode_led.set_color(ModeLED::ModeColor::fixed_error); - timer = millis(); +void FixedModeState::do_activity() { } -void ConnectionErrorState::do_activity() { - FixedModeState::do_activity(); -} +void FixedModeState::exit_action() { -void ConnectionErrorState::exit_action() { } -void ConnectionErrorState::handle_event(Event_enum event_id) { +void FixedModeState::handle_event(Event_enum event_id) { switch(event_id) { - case e_c_report_success: - controller.set_state(new ConnectedState(controller)); - break; - case e_c_report_failed: - // Failed, Nothing happening already in connection error state + case e_c_button_pressed: + controller.set_state(new MobileModeState(controller)); break; default: - FixedModeState::handle_event(event_id); + ControllerState::handle_event(event_id); break; } } diff --git a/bgeigiecast/sm_c_concete_states.h b/bgeigiecast/sm_c_concete_states.h index f304092..d958553 100644 --- a/bgeigiecast/sm_c_concete_states.h +++ b/bgeigiecast/sm_c_concete_states.h @@ -8,6 +8,8 @@ class InitializeState : public ControllerState { explicit InitializeState(Controller& context); virtual ~InitializeState() = default; + int8_t get_state_id() const override { return k_state_InitializeState;} + void entry_action() override; void do_activity() override; void exit_action() override; @@ -19,10 +21,15 @@ class InitReadingState : public ControllerState { explicit InitReadingState(Controller& context); virtual ~InitReadingState() = default; + int8_t get_state_id() const override { return k_state_InitReadingState;} + void entry_action() override; void do_activity() override; void exit_action() override; void handle_event(Event_enum event_id) override; + + private: + uint32_t timer; }; class PostInitializeState : public ControllerState { @@ -30,28 +37,23 @@ class PostInitializeState : public ControllerState { explicit PostInitializeState(Controller& context); virtual ~PostInitializeState() = default; + int8_t get_state_id() const override { return k_state_PostInitializeState;} + void entry_action() override; void do_activity() override; void exit_action() override; void handle_event(Event_enum event_id) override; private: - uint32_t timer; }; -class ConfigModeState : public ControllerState { +class ConfigurationModeState : public ControllerState { public: - explicit ConfigModeState(Controller& context); - virtual ~ConfigModeState() = default; + explicit ConfigurationModeState(Controller& context); + virtual ~ConfigurationModeState() = default; - void handle_event(Event_enum event_id) override; -}; - -class SetupServerState : public ConfigModeState { - public: - explicit SetupServerState(Controller& context); - virtual ~SetupServerState() = default; + int8_t get_state_id() const override { return k_state_ConfigurationModeState;} void entry_action() override; void do_activity() override; @@ -59,45 +61,13 @@ class SetupServerState : public ConfigModeState { void handle_event(Event_enum event_id) override; }; -class ServerActiveState : public ConfigModeState { - public: - explicit ServerActiveState(Controller& context); - virtual ~ServerActiveState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; -}; - -class ActiveState : public ControllerState { - public: - explicit ActiveState(Controller& context); - virtual ~ActiveState() = default; - - void do_activity() override; - - void handle_event(Event_enum event_id) override; -}; - -class InitActiveState : public ActiveState { - public: - explicit InitActiveState(Controller& context); - virtual ~InitActiveState() = default; - - void do_activity() override; - void entry_action() override; - void exit_action() override; - - void handle_event(Event_enum event_id) override; - -}; - -class MobileModeState : public ActiveState { +class MobileModeState : public ControllerState { public: explicit MobileModeState(Controller& context); virtual ~MobileModeState() = default; + int8_t get_state_id() const override { return k_state_MobileModeState;} + void entry_action() override; void do_activity() override; void exit_action() override; @@ -105,55 +75,18 @@ class MobileModeState : public ActiveState { }; -class FixedModeState : public ActiveState { +class FixedModeState : public ControllerState { public: explicit FixedModeState(Controller& context); virtual ~FixedModeState() = default; - void do_activity() override; - - void handle_event(Event_enum event_id) override; - -}; - -class DisconnectedState : public FixedModeState { - public: - explicit DisconnectedState(Controller& context); - virtual ~DisconnectedState() = default; + int8_t get_state_id() const override { return k_state_FixedModeState;} void entry_action() override; void do_activity() override; void exit_action() override; void handle_event(Event_enum event_id) override; - private: - uint32_t state_entry_moment; -}; - -class ConnectedState : public FixedModeState { - public: - explicit ConnectedState(Controller& context); - virtual ~ConnectedState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; - -}; - -class ConnectionErrorState : public FixedModeState { - public: - explicit ConnectionErrorState(Controller& context); - virtual ~ConnectionErrorState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; - - private: - uint32_t timer; }; class ResetState : public ControllerState { @@ -161,6 +94,8 @@ class ResetState : public ControllerState { explicit ResetState(Controller& context); virtual ~ResetState() = default; + int8_t get_state_id() const override { return k_state_ResetState;} + void entry_action() override; void do_activity() override; void exit_action() override; diff --git a/bgeigiecast/sm_c_state.h b/bgeigiecast/sm_c_state.h index 3e5bbb9..0eae4fb 100644 --- a/bgeigiecast/sm_c_state.h +++ b/bgeigiecast/sm_c_state.h @@ -3,14 +3,26 @@ #include "debugger.h" #include "controller.h" +#include "sm_state.h" /** * State with controller context, so the states can control the system */ class ControllerState : public State { public: + enum StateId { + k_state_InitializeState, + k_state_InitReadingState, + k_state_PostInitializeState, + k_state_ConfigurationModeState, + k_state_MobileModeState, + k_state_FixedModeState, + k_state_ResetState, + }; + explicit ControllerState(Controller& context) : controller(context) {}; virtual ~ControllerState() = default; + protected: Controller& controller; }; diff --git a/bgeigiecast/sm_events.h b/bgeigiecast/sm_events.h index 6bf04b2..695e375 100644 --- a/bgeigiecast/sm_events.h +++ b/bgeigiecast/sm_events.h @@ -10,36 +10,8 @@ typedef enum { e_c_controller_initialized, e_c_reading_initialized, e_c_post_init_time_passed, - e_c_server_initialized, e_c_report_success, - e_c_report_failed, - - // Reporter events - e_r_reading_expected, - e_r_reading_received, - e_r_reading_invalid, - e_r_reading_reported, - - e_r_bluetooth_initialized, - e_r_api_connector_initialized, - e_r_reading_reported_bt, - e_r_reading_skipped_bt, - e_r_reading_reported_api_no_change, - e_r_reading_reported_api_success, - e_r_reading_reported_api_failed, - - // Api conn states - e_a_report_reading, - e_a_not_reporting, - e_a_wifi_connected, - e_a_api_available, - e_a_reading_posted, - - e_a_wifi_connection_error, - e_a_api_unavailable, - e_a_api_post_failed, - e_a_reading_saved, } Event_enum; diff --git a/bgeigiecast/sm_r_concrete_states.cpp b/bgeigiecast/sm_r_concrete_states.cpp deleted file mode 100644 index 413d116..0000000 --- a/bgeigiecast/sm_r_concrete_states.cpp +++ /dev/null @@ -1,262 +0,0 @@ -#include "sm_r_concrete_states.h" - -// region ReporterIdleState - -ReporterIdleState::ReporterIdleState(Reporter& context) : ReporterState(context) { -} - -void ReporterIdleState::entry_action() { -#if DEBUG_LOG_STATE_TRANSITIONS - DEBUG_PRINTLN("-- Reporter entered state Idle"); -#endif - reporter._idle = true; -} - -void ReporterIdleState::do_activity() { - if(reporter.time_till_next_reading(millis()) == 0) { - reporter.schedule_event(e_r_reading_expected); - } -} - -void ReporterIdleState::exit_action() { - reporter._idle = false; -} - -void ReporterIdleState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_r_reading_expected: - reporter.set_state(new GetReadingState(reporter)); - break; - default: - ReporterState::handle_event(event_id); - break; - } -} - -// endregion - -// region GetReadingState - -GetReadingState::GetReadingState(Reporter& context) : ReporterState(context) { - -} - -void GetReadingState::entry_action() { -#if DEBUG_LOG_STATE_TRANSITIONS - DEBUG_PRINTLN("-- Reporter entered state Get reading"); -#endif -} - -void GetReadingState::do_activity() { - reporter.get_new_reading(); -} - -void GetReadingState::exit_action() { -} - -void GetReadingState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_r_reading_received: - if(reporter._report_bt) { - reporter.set_state(new InitBluetoothState(reporter)); - } else if(reporter._report_api) { - reporter.set_state(new InitApiState(reporter)); - } else { - reporter.set_state(new ReporterIdleState(reporter)); - } - break; - case e_r_reading_invalid: - reporter.set_state(new ReporterIdleState(reporter)); - break; - default: - ReporterState::handle_event(event_id); - break; - } -} - -// endregion - -// region ReportReadingState - -ReportReadingState::ReportReadingState(Reporter& context) : ReporterState(context) { -} - -void ReportReadingState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_r_reading_reported: - reporter.set_state(new ReporterIdleState(reporter)); - break; - default: - ReporterState::handle_event(event_id); - break; - } -} - -// endregion - -// region InitBluetoothState - -InitBluetoothState::InitBluetoothState(Reporter& context) : ReportReadingState(context) { - -} -void InitBluetoothState::entry_action() { -#if DEBUG_LOG_STATE_TRANSITIONS - DEBUG_PRINTLN("-- Reporter entered state Init Bluetooth"); -#endif -} - -void InitBluetoothState::do_activity() { - reporter.init_bluetooth_connector(); -} - -void InitBluetoothState::exit_action() { - -} - -void InitBluetoothState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_r_bluetooth_initialized: - reporter.set_state(new PublishBluetoothState(reporter)); - break; - default: - ReportReadingState::handle_event(event_id); - break; - } -} - -// endregion - -// region PublishBluetoothState - -PublishBluetoothState::PublishBluetoothState(Reporter& context) : ReportReadingState(context) { -} - -void PublishBluetoothState::entry_action() { -#if DEBUG_LOG_STATE_TRANSITIONS - DEBUG_PRINTLN("-- Reporter entered state Publish Bluetooth"); -#endif -} - -void PublishBluetoothState::do_activity() { - reporter.run_bluetooth_connector(); -} - -void PublishBluetoothState::exit_action() { -} - -void PublishBluetoothState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_r_reading_skipped_bt: - case e_r_reading_reported_bt: - if(reporter._report_api) { - reporter.set_state(new InitApiState(reporter)); - } else { - reporter.set_state(new ReporterDoneState(reporter, Reporter::k_reporter_success)); - } - break; - default: - ReportReadingState::handle_event(event_id); - break; - } -} - -// endregion - -// region InitApiState - -InitApiState::InitApiState(Reporter& context) : ReportReadingState(context) { -} - -void InitApiState::entry_action() { -#if DEBUG_LOG_STATE_TRANSITIONS - DEBUG_PRINTLN("-- Reporter entered state Init api"); -#endif -} - -void InitApiState::do_activity() { - reporter.init_api_connector(); -} - -void InitApiState::exit_action() { -} - -void InitApiState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_r_api_connector_initialized: - reporter.set_state(new ReportApiState(reporter)); - break; - default: - ReportReadingState::handle_event(event_id); - break; - } -} - -// endregion - -// region ReportApiState - -ReportApiState::ReportApiState(Reporter& context) : ReportReadingState(context) { -} - -void ReportApiState::entry_action() { -#if DEBUG_LOG_STATE_TRANSITIONS - DEBUG_PRINTLN("-- Reporter entered state Publish Api"); -#endif -} - -void ReportApiState::do_activity() { - reporter.run_api_connector(); -} - -void ReportApiState::exit_action() { -} - -void ReportApiState::handle_event(Event_enum event_id) { - switch(event_id) { - case e_r_reading_reported_api_no_change: - reporter.set_state(new ReporterDoneState(reporter, Reporter::k_reporter_no_change)); - break; - case e_r_reading_reported_api_success: - reporter.set_state(new ReporterDoneState(reporter, Reporter::k_reporter_success)); - break; - case e_r_reading_reported_api_failed: - reporter.set_state(new ReporterDoneState(reporter, Reporter::k_reporter_failed)); - break; - default: - ReportReadingState::handle_event(event_id); - break; - } -} - -// endregion - -// region ReporterDoneState - -ReporterDoneState::ReporterDoneState(Reporter& context, Reporter::ReporterStatus status) - : ReportReadingState(context), status(status) { - -} - -void ReporterDoneState::entry_action() { -#if DEBUG_LOG_STATE_TRANSITIONS - DEBUG_PRINTLN("-- Reporter entered state Done"); -#endif -} - -void ReporterDoneState::do_activity() { - reporter.report_complete(status); -} - -void ReporterDoneState::exit_action() { - -} - -void ReporterDoneState::handle_event(Event_enum event_id) { - switch(event_id) { - default: - ReportReadingState::handle_event(event_id); - break; - } -} - -// endregion \ No newline at end of file diff --git a/bgeigiecast/sm_r_concrete_states.h b/bgeigiecast/sm_r_concrete_states.h deleted file mode 100644 index 32b9d47..0000000 --- a/bgeigiecast/sm_r_concrete_states.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef BGEIGIECAST_SM_R_CONCRETE_STATES_H -#define BGEIGIECAST_SM_R_CONCRETE_STATES_H - -#include "sm_r_state.h" - -class ReporterIdleState : public ReporterState { - public: - explicit ReporterIdleState(Reporter& context); - virtual ~ReporterIdleState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; -}; - -class GetReadingState : public ReporterState { - public: - explicit GetReadingState(Reporter& context); - virtual ~GetReadingState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; -}; - -class ReportReadingState : public ReporterState { - public: - explicit ReportReadingState(Reporter& context); - virtual ~ReportReadingState() = default; - - void handle_event(Event_enum event_id) override; -}; - -class InitBluetoothState : public ReportReadingState { - public: - explicit InitBluetoothState(Reporter& context); - virtual ~InitBluetoothState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; -}; - -class PublishBluetoothState : public ReportReadingState { - public: - explicit PublishBluetoothState(Reporter& context); - virtual ~PublishBluetoothState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; -}; - -class InitApiState : public ReportReadingState { - public: - explicit InitApiState(Reporter& context); - virtual ~InitApiState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; -}; - -class ReportApiState : public ReportReadingState { - public: - explicit ReportApiState(Reporter& context); - virtual ~ReportApiState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; -}; - -class ReporterDoneState : public ReportReadingState { - public: - explicit ReporterDoneState(Reporter& context, Reporter::ReporterStatus status); - virtual ~ReporterDoneState() = default; - - void entry_action() override; - void do_activity() override; - void exit_action() override; - void handle_event(Event_enum event_id) override; - private: - Reporter::ReporterStatus status; - -}; - -#endif //BGEIGIECAST_SM_R_CONCRETE_STATES_H diff --git a/bgeigiecast/sm_r_state.h b/bgeigiecast/sm_r_state.h deleted file mode 100644 index 0f03fd9..0000000 --- a/bgeigiecast/sm_r_state.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef BGEIGIECAST_SM_R_STATE_H -#define BGEIGIECAST_SM_R_STATE_H - -#include "reporter.h" -#include "sm_state.h" - -/** - * State with reporter context, so the states can control the reporter - */ -class ReporterState : public State { - public: - explicit ReporterState(Reporter& context) : reporter(context) {}; - virtual ~ReporterState() = default; - protected: - Reporter& reporter; -}; - -#endif //BGEIGIECAST_SM_R_STATE_H diff --git a/bgeigiecast/sm_state.h b/bgeigiecast/sm_state.h index fbdc096..2d669c7 100644 --- a/bgeigiecast/sm_state.h +++ b/bgeigiecast/sm_state.h @@ -4,11 +4,6 @@ #include "sm_events.h" #include "debugger.h" -typedef enum { - k_savable_MobileMode, - k_savable_FixedMode -} SavableState; - /** * Abstract state for the state machine pattern */ @@ -17,6 +12,12 @@ class State { State() = default;; virtual ~State() = default; + /** + * Get some unique identifier of the state + * @return + */ + virtual int8_t get_state_id() const = 0; + /** * Action when entering this state */ diff --git a/bgeigiecast/user_config.h b/bgeigiecast/user_config.h index 1a48036..7098df9 100644 --- a/bgeigiecast/user_config.h +++ b/bgeigiecast/user_config.h @@ -5,10 +5,8 @@ /** System config **/ #define ENABLE_DEBUG 1 -#define DEBUG_LOG_STATE_TRANSITIONS 0 #define SERIAL_BAUD 115200 #define BGEIGIE_CONNECTION_BAUD 9600 -#define USE_SLEEP 0 #define POST_INITIALIZE_DURATION 4000 @@ -17,7 +15,7 @@ #define RGB_LED_PIN_G A4 #define RGB_LED_PIN_B A5 -#define MODE_BUTTON_PIN 0 +#define MODE_BUTTON_PIN 0u /** API connector settings **/ @@ -46,6 +44,5 @@ #define D_USE_DEV_SERVER true #define D_LED_COLOR_BLIND false #define D_LED_COLOR_INTENSITY 30 -#define D_SAVED_STATE 0 #endif \ No newline at end of file diff --git a/designs/software/components.puml b/designs/software/components.puml index 6505aa3..29d61b1 100644 --- a/designs/software/components.puml +++ b/designs/software/components.puml @@ -17,19 +17,19 @@ component bGeigieNano\n { component Controller component Reporter component ConfigServer - component ApiConnector + component ApiReporter component Bluetooth - component EspConfig + component Configuration ''' For ordering ''' - ConfigServer -[hidden]> EspConfig + ConfigServer -[hidden]> Configuration '''''' Controller -( serverControl serverControl - ConfigServer dataReports )- Reporter config )-u- ConfigServer - config - EspConfig + config - Configuration deviceConfig -d- ConfigServer espMode -d- Controller Controller -l-( reporterControl @@ -37,11 +37,11 @@ component bGeigieNano\n { IBL )-u- Reporter IBL -d- Bluetooth IAP )-u- Reporter - IAP -d- ApiConnector - ApiConnector -u-( config + IAP -d- ApiReporter + ApiReporter -u-( config liveData -u- Bluetooth - api )-u- ApiConnector + api )-u- ApiReporter } bGeigieController - dataReports diff --git a/platformio.ini b/platformio.ini index dfd1fee..afbb0de 100644 --- a/platformio.ini +++ b/platformio.ini @@ -24,7 +24,8 @@ test_ignore = test_led test_state_machine test_stability - +lib_deps = + SensorReporter=https://github.com/Claypuppet/SensorReporter.git [env:bGeigieCast] board = esp32doit-devkit-v1 diff --git a/test/test_http_pages/test_request_handling.cpp b/test/test_http_pages/test_request_handling.cpp index d3ea1e2..58cb431 100644 --- a/test/test_http_pages/test_request_handling.cpp +++ b/test/test_http_pages/test_request_handling.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include "../test_config.h" #include