diff --git a/components/cpputils b/components/cpputils index 8249861..0b4ba83 160000 --- a/components/cpputils +++ b/components/cpputils @@ -1 +1 @@ -Subproject commit 82498617f25c05f7abf9cd27fb47b8ec8b4af25d +Subproject commit 0b4ba837428bff91f1b42696675043884dab8be3 diff --git a/components/espasynchttpreq b/components/espasynchttpreq index 8b05591..ba852bb 160000 --- a/components/espasynchttpreq +++ b/components/espasynchttpreq @@ -1 +1 @@ -Subproject commit 8b055917027671b50dc1ed4634ba43149bf3dce6 +Subproject commit ba852bbbf4f272533fef7a8a3ecc70d4a2176d3e diff --git a/components/espcpputils b/components/espcpputils index 3a3e4bc..850a42a 160000 --- a/components/espcpputils +++ b/components/espcpputils @@ -1 +1 @@ -Subproject commit 3a3e4bc04436a053407eb95ce1c42dbb48ea0ba6 +Subproject commit 850a42adc4b3271e8f8446cedea6c4419bf11848 diff --git a/components/espwifistack b/components/espwifistack index 3479226..6eb911c 160000 --- a/components/espwifistack +++ b/components/espwifistack @@ -1 +1 @@ -Subproject commit 34792268a8909d7f937977027348f47edb3c5875 +Subproject commit 6eb911c8eac2d50f5aa7e3cc35e4f691e59832a9 diff --git a/main/bluetoothmode.h b/main/bluetoothmode.h index 8e3b30e..a14662f 100644 --- a/main/bluetoothmode.h +++ b/main/bluetoothmode.h @@ -2,7 +2,6 @@ #include -namespace { #ifdef FEATURE_BLUETOOTH enum class BluetoothMode : uint8_t { @@ -11,4 +10,3 @@ enum class BluetoothMode : uint8_t Slave }; #endif -} diff --git a/main/can.cpp b/main/can.cpp index e69de29..ae278ca 100644 --- a/main/can.cpp +++ b/main/can.cpp @@ -0,0 +1,455 @@ +#include "can.h" + +// system includes +#include +#include + +// esp-idf +#include +#include +#include + +// 3rdparty lib includes +#include +#include + +// local includes +#include "bobbycar-can.h" +#include "globals.h" +#include "buttons.h" + +namespace can { +namespace { +constexpr const char * const TAG = "BOBBYCAN"; +} // namespace + +std::optional can_gas, can_brems; +espchrono::millis_clock::time_point last_can_gas{}, last_can_brems{}; +CanButtonsState lastButtonsState; + +void initCan() +{ + ESP_LOGI(TAG, "called"); + + twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(GPIO_NUM_21, GPIO_NUM_22, TWAI_MODE_NORMAL); + twai_timing_config_t t_config TWAI_TIMING_CONFIG_250KBITS(); + twai_filter_config_t f_config TWAI_FILTER_CONFIG_ACCEPT_ALL(); +// { +// // +// .acceptance_code = 0b00000000000, +// .acceptance_mask = 0b00001111111, +// .single_filter = true +// }; + + if (const auto result = twai_driver_install(&g_config, &t_config, &f_config); result == ESP_OK) + { + ESP_LOGI(TAG, "twai_driver_install() succeeded"); + } + else + { + ESP_LOGE(TAG, "twai_driver_install() failed with %s", esp_err_to_name(result)); + return; + } + + if (const auto result = twai_start(); result == ESP_OK) + { + ESP_LOGI(TAG, "twai_start() succeeded"); + } + else + { + ESP_LOGE(TAG, "twai_start() failed with %s", esp_err_to_name(result)); + + if (const auto result = twai_driver_uninstall(); result == ESP_OK) + { + ESP_LOGI(TAG, "twai_driver_uninstall() succeeded"); + } + else + { + ESP_LOGE(TAG, "twai_driver_uninstall() failed with %s", esp_err_to_name(result)); + } + + return; + } +} + +namespace { + +template +bool parseMotorControllerCanMessage(const twai_message_t &message, Controller &controller) +{ + switch (message.identifier) + { + using namespace bobbycar::protocol::can; + case MotorController::Feedback::DcLink: + controller.feedback.left.dcLink = *((int16_t*)message.data); + return true; + case MotorController::Feedback::DcLink: + controller.feedback.right.dcLink = *((int16_t*)message.data); + return true; + case MotorController::Feedback::Speed: + controller.feedback.left.speed = *((int16_t*)message.data); + return true; + case MotorController::Feedback::Speed: + controller.feedback.right.speed = *((int16_t*)message.data); + return true; + case MotorController::Feedback::Error: + controller.feedback.left.error = *((int8_t*)message.data); + return true; + case MotorController::Feedback::Error: + controller.feedback.right.error = *((int8_t*)message.data); + return true; + case MotorController::Feedback::Angle: + controller.feedback.left.angle = *((int16_t*)message.data); + return true; + case MotorController::Feedback::Angle: + controller.feedback.right.angle = *((int16_t*)message.data); + return true; + case MotorController::Feedback::DcPhaA: + controller.feedback.left.dcPhaA = *((int16_t*)message.data); + return true; + case MotorController::Feedback::DcPhaA: + controller.feedback.right.dcPhaA = *((int16_t*)message.data); + return true; + case MotorController::Feedback::DcPhaB: + controller.feedback.left.dcPhaB = *((int16_t*)message.data); + return true; + case MotorController::Feedback::DcPhaB: + controller.feedback.right.dcPhaB = *((int16_t*)message.data); + return true; + case MotorController::Feedback::DcPhaC: + controller.feedback.left.dcPhaC = *((int16_t*)message.data); + return true; + case MotorController::Feedback::DcPhaC: + controller.feedback.right.dcPhaC = *((int16_t*)message.data); + return true; + case MotorController::Feedback::Chops: + controller.feedback.left.chops = *((uint16_t*)message.data); + return true; + case MotorController::Feedback::Chops: + controller.feedback.right.chops = *((uint16_t*)message.data); + return true; + case MotorController::Feedback::Hall: + controller.feedback.left.hallA = *((uint8_t*)message.data) & 1; + controller.feedback.left.hallB = *((uint8_t*)message.data) & 2; + controller.feedback.left.hallC = *((uint8_t*)message.data) & 4; + return true; + case MotorController::Feedback::Hall: + controller.feedback.right.hallA = *((uint8_t*)message.data) & 1; + controller.feedback.right.hallB = *((uint8_t*)message.data) & 2; + controller.feedback.right.hallC = *((uint8_t*)message.data) & 4; + return true; + case MotorController::Feedback::Voltage: + case MotorController::Feedback::Voltage: + controller.feedback.batVoltage = *((int16_t*)message.data); + return true; + case MotorController::Feedback::Temp: + case MotorController::Feedback::Temp: + controller.feedback.boardTemp = *((int16_t*)message.data); + return true; + } + + return false; +} + +bool parseBoardcomputerCanMessage(const twai_message_t &message) +{ + switch (message.identifier) + { + using namespace bobbycar::protocol::can; + case Boardcomputer::Command::ButtonPress: + { + const auto canButtonBits = *((uint16_t*)message.data); + CanButtonsState newState { + .up = bool(canButtonBits & Boardcomputer::ButtonUp), + .down = bool(canButtonBits & Boardcomputer::ButtonDown), + .confirm = bool(canButtonBits & Boardcomputer::ButtonConfirm), + .back = bool(canButtonBits & Boardcomputer::ButtonBack), + .profile0 = bool(canButtonBits & Boardcomputer::ButtonProfile0), + .profile1 = bool(canButtonBits & Boardcomputer::ButtonProfile1), + .profile2 = bool(canButtonBits & Boardcomputer::ButtonProfile2), + .profile3 = bool(canButtonBits & Boardcomputer::ButtonProfile3), + }; + + if (lastButtonsState.up != newState.up) + InputDispatcher::upButton(newState.up); + + if (lastButtonsState.down != newState.down) + InputDispatcher::downButton(newState.down); + + if (lastButtonsState.confirm != newState.confirm) + InputDispatcher::confirmButton(newState.confirm); + + if (lastButtonsState.back != newState.back) + InputDispatcher::backButton(newState.back); + + if (lastButtonsState.profile0 != newState.profile0) + InputDispatcher::profileButton(0, newState.profile0); + + if (lastButtonsState.profile1 != newState.profile1) + InputDispatcher::profileButton(1, newState.profile1); + + if (lastButtonsState.profile2 != newState.profile2) + InputDispatcher::profileButton(2, newState.profile2); + + if (lastButtonsState.profile3 != newState.profile3) + InputDispatcher::profileButton(3, newState.profile3); + + lastButtonsState = newState; + break; + } + case Boardcomputer::Command::RawGas: + can_gas = *((int16_t*)message.data); + last_can_gas = espchrono::millis_clock::now(); + break; + case Boardcomputer::Command::RawBrems: + can_brems = *((int16_t*)message.data); + last_can_brems = espchrono::millis_clock::now(); + break; + } + + return false; +} +} // namespace + +bool tryParseCanInput() +{ + twai_message_t message; + const auto timeout = std::chrono::ceil(espchrono::milliseconds32{settings.controllerHardware.canReceiveTimeout}).count(); + if (const auto result = twai_receive(&message, timeout); result != ESP_OK) + { + if (result != ESP_ERR_TIMEOUT) + { + ESP_LOGE(TAG, "twai_receive() failed with %s", esp_err_to_name(result)); + } + + if (espchrono::millis_clock::now() - controllers.front.lastCanFeedback > 100ms) + controllers.front.feedbackValid = false; + + if (espchrono::millis_clock::now() - controllers.back.lastCanFeedback > 100ms) + controllers.back.feedbackValid = false; + + return false; + } + + Controller &front = settings.controllerHardware.swapFrontBack ? controllers.back : controllers.front; + Controller &back = settings.controllerHardware.swapFrontBack ? controllers.front : controllers.back; + + if (parseMotorControllerCanMessage(message, front)) + { + if (espchrono::millis_clock::now() - back.lastCanFeedback > 100ms) + back.feedbackValid = false; + + front.lastCanFeedback = espchrono::millis_clock::now(); + front.feedbackValid = true; + return true; + } + else + { + if (espchrono::millis_clock::now() - front.lastCanFeedback > 100ms) + front.feedbackValid = false; + } + + if (parseMotorControllerCanMessage(message, back)) + { + back.lastCanFeedback = espchrono::millis_clock::now(); + back.feedbackValid = true; + return true; + } + else + { + if (espchrono::millis_clock::now() - back.lastCanFeedback > 100ms) + back.feedbackValid = false; + } + + if (parseBoardcomputerCanMessage(message)) + return true; + + ESP_LOGW(TAG, "Unknown CAN info received .identifier = %u", message.identifier); + + return true; +} + +void parseCanInput() +{ + for (int i = 0; i < 4; i++) + if (!tryParseCanInput()) + break; +} + +void sendCanCommands() +{ + constexpr auto send = [](uint32_t addr, auto value){ + twai_message_t message; + message.identifier = addr; + message.flags = TWAI_MSG_FLAG_SS; + message.data_length_code = sizeof(value); + std::fill(std::begin(message.data), std::end(message.data), 0); + std::memcpy(message.data, &value, sizeof(value)); + + const auto timeout = std::chrono::ceil(espchrono::milliseconds32{settings.controllerHardware.canTransmitTimeout}).count(); + const auto result = twai_transmit(&message, timeout); + if (result != ESP_OK && result != ESP_ERR_TIMEOUT) + { + ESP_LOGE(TAG, "ERROR: twai_transmit() failed with %s", esp_err_to_name(result)); + } + return result; + }; + + const bool swap = settings.controllerHardware.swapFrontBack; + const Controller *front = + (swap ? settings.controllerHardware.sendBackCanCmd : settings.controllerHardware.sendFrontCanCmd ) ? + (swap ? &controllers.back : &controllers.front) : + nullptr; + const Controller *back = + (swap ? settings.controllerHardware.sendFrontCanCmd : settings.controllerHardware.sendBackCanCmd ) ? + (swap ? &controllers.front : &controllers.back) : + nullptr; + + using namespace bobbycar::protocol::can; + + if (front) send(MotorController::Command::InpTgt, front->command.left.pwm); + if (front) send(MotorController::Command::InpTgt, front->command.right.pwm); + if (back) send(MotorController::Command::InpTgt, back->command.left.pwm); + if (back) send(MotorController::Command::InpTgt, back->command.right.pwm); + + uint16_t buttonLeds{}; + if (const auto index = settingsPersister.currentlyOpenProfileIndex()) + switch (*index) + { + case 0: buttonLeds |= Boardcomputer::ButtonProfile0; break; + case 1: buttonLeds |= Boardcomputer::ButtonProfile1; break; + case 2: buttonLeds |= Boardcomputer::ButtonProfile2; break; + case 3: buttonLeds |= Boardcomputer::ButtonProfile3; break; + } + + static struct { + struct { + uint8_t freq = 0; + uint8_t pattern = 0; + } front, back; + uint16_t buttonLeds{}; + } lastValues; + + static int i{}; + + if ((front && front->command.buzzer.freq != lastValues.front.freq ) || + (front && front->command.buzzer.pattern != lastValues.front.pattern ) || + (back && back->command.buzzer.freq != lastValues.back.freq) || + (back && back->command.buzzer.pattern != lastValues.back.pattern)) + i = 10; + else if (buttonLeds != lastValues.buttonLeds) + i = 12; + + switch (i++) + { + case 0: + if (front) send(MotorController::Command::Enable, front->command.left.enable); + if (front) send(MotorController::Command::Enable, front->command.right.enable); + if (back) send(MotorController::Command::Enable, back->command.left.enable); + if (back) send(MotorController::Command::Enable, back->command.right.enable); + break; + case 1: + if (front) send(MotorController::Command::CtrlTyp, front->command.left.ctrlTyp); + if (front) send(MotorController::Command::CtrlTyp, front->command.right.ctrlTyp); + if (back) send(MotorController::Command::CtrlTyp, back->command.left.ctrlTyp); + if (back) send(MotorController::Command::CtrlTyp, back->command.right.ctrlTyp); + break; + case 2: + if (front) send(MotorController::Command::CtrlMod, front->command.left.ctrlMod); + if (front) send(MotorController::Command::CtrlMod, front->command.right.ctrlMod); + if (back) send(MotorController::Command::CtrlMod, back->command.left.ctrlMod); + if (back) send(MotorController::Command::CtrlMod, back->command.right.ctrlMod); + break; + case 3: +#if defined(HAS_SIMPLIFIED) + SIMPLIFIED_IMOTMAX +#endif + if (front) send(MotorController::Command::IMotMax, front->command.left.iMotMax); + if (front) send(MotorController::Command::IMotMax, front->command.right.iMotMax); + if (back) send(MotorController::Command::IMotMax, back->command.left.iMotMax); + if (back) send(MotorController::Command::IMotMax, back->command.right.iMotMax); + break; + case 4: +#if defined(HAS_SIMPLIFIED) + SIMPLIFIED_IDCMAX +#endif + if (front) send(MotorController::Command::IDcMax, front->command.left.iDcMax); + if (front) send(MotorController::Command::IDcMax, front->command.right.iDcMax); + if (back) send(MotorController::Command::IDcMax, back->command.left.iDcMax); + if (back) send(MotorController::Command::IDcMax, back->command.right.iDcMax); + break; + case 5: +#if defined(HAS_SIMPLIFIED) + SIMPLIFIED_NMOTMAX +#endif + if (front) send(MotorController::Command::NMotMax, front->command.left.nMotMax); + if (front) send(MotorController::Command::NMotMax, front->command.right.nMotMax); + if (back) send(MotorController::Command::NMotMax, back->command.left.nMotMax); + if (back) send(MotorController::Command::NMotMax, back->command.right.nMotMax); + break; + case 6: +#if defined(HAS_SIMPLIFIED) + SIMPLIFIED_FIELDWEAKMAX +#endif + if (front) send(MotorController::Command::FieldWeakMax, front->command.left.fieldWeakMax); + if (front) send(MotorController::Command::FieldWeakMax, front->command.right.fieldWeakMax); + if (back) send(MotorController::Command::FieldWeakMax, back->command.left.fieldWeakMax); + if (back) send(MotorController::Command::FieldWeakMax, back->command.right.fieldWeakMax); + break; + case 7: + if (front) send(MotorController::Command::PhaseAdvMax, front->command.left.phaseAdvMax); + if (front) send(MotorController::Command::PhaseAdvMax, front->command.right.phaseAdvMax); + if (back) send(MotorController::Command::PhaseAdvMax, back->command.left.phaseAdvMax); + if (back) send(MotorController::Command::PhaseAdvMax, back->command.right.phaseAdvMax); + break; + case 8: + if (front) send(MotorController::Command::CruiseCtrlEna, front->command.left.cruiseCtrlEna); + if (front) send(MotorController::Command::CruiseCtrlEna, front->command.right.cruiseCtrlEna); + if (back) send(MotorController::Command::CruiseCtrlEna, back->command.left.cruiseCtrlEna); + if (back) send(MotorController::Command::CruiseCtrlEna, back->command.right.cruiseCtrlEna); + break; + case 9: + if (front) send(MotorController::Command::CruiseMotTgt, front->command.left.nCruiseMotTgt); + if (front) send(MotorController::Command::CruiseMotTgt, front->command.right.nCruiseMotTgt); + if (back) send(MotorController::Command::CruiseMotTgt, back->command.left.nCruiseMotTgt); + if (back) send(MotorController::Command::CruiseMotTgt, back->command.right.nCruiseMotTgt); + break; + case 10: + if (front && send(MotorController::Command::BuzzerFreq, front->command.buzzer.freq) == ESP_OK) + lastValues.front.freq = front->command.buzzer.freq; +// if (front && send(MotorController::Command::BuzzerFreq, front->command.buzzer.freq) == ESP_OK) +// lastValues.front.freq = front->command.buzzer.freq; + if (back && send(MotorController::Command::BuzzerFreq, back->command.buzzer.freq) == ESP_OK) + lastValues.back.freq = back->command.buzzer.freq; +// if (back && send(MotorController::Command::BuzzerFreq, back->command.buzzer.freq) == ESP_OK) +// lastValues.back.freq = back->command.buzzer.freq; + if (front && send(MotorController::Command::BuzzerPattern, front->command.buzzer.pattern) == ESP_OK) + lastValues.front.pattern = front->command.buzzer.pattern; +// if (front && send(MotorController::Command::BuzzerPattern, front->command.buzzer.pattern) == ESP_OK) +// lastValues.front.pattern = front->command.buzzer.pattern; + if (back && send(MotorController::Command::BuzzerPattern, back->command.buzzer.pattern) == ESP_OK) + lastValues.back.pattern = back->command.buzzer.pattern; +// if (back && send(MotorController::Command::BuzzerPattern, back->command.buzzer.pattern) == ESP_OK) +// lastValues.back.pattern = back->command.buzzer.pattern; + break; + case 11: + if (front) send(MotorController::Command::Led, front->command.led); + //if (front) send(MotorController::Command::Led, front->command.led); + if (back) send(MotorController::Command::Led, back->command.led); + //if (back) send(MotorController::Command::Led, back->command.led); + if (front) send(MotorController::Command::Poweroff, front->command.poweroff); + //if (front) send(MotorController::Command::Poweroff, front->command.poweroff); + if (back) send(MotorController::Command::Poweroff, back->command.poweroff); + //if (back) send(MotorController::Command::Poweroff, back->command.poweroff); + break; + case 12: + if (send(Boardcomputer::Feedback::ButtonLeds, buttonLeds) == ESP_OK) + lastValues.buttonLeds = buttonLeds; + [[fallthrough]]; + default: + i=0; + break; + } +} + +} // namespace can diff --git a/main/can.h b/main/can.h index 8a6bc9b..68e10bc 100644 --- a/main/can.h +++ b/main/can.h @@ -1,21 +1,11 @@ #pragma once -#include +// system includes #include +#include -#include -#include -#include - -#include - +// 3rdparty lib includes #include -#include - -#include "bobbycar-can.h" - -#include "globals.h" -#include "buttons.h" #ifdef CAN_PLUGIN #pragma message "Activating Can Plugin" @@ -24,9 +14,8 @@ namespace can { -namespace { -std::optional can_gas, can_brems; -espchrono::millis_clock::time_point last_can_gas{}, last_can_brems{}; +extern std::optional can_gas, can_brems; +extern espchrono::millis_clock::time_point last_can_gas, last_can_brems; struct CanButtonsState { @@ -39,428 +28,10 @@ struct CanButtonsState bool profile2{}; bool profile3{}; }; -CanButtonsState lastButtonsState; +extern CanButtonsState lastButtonsState; -void initCan() -{ - ESP_LOGI(TAG, "called"); - - twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(GPIO_NUM_21, GPIO_NUM_22, TWAI_MODE_NORMAL); - twai_timing_config_t t_config TWAI_TIMING_CONFIG_250KBITS(); - twai_filter_config_t f_config TWAI_FILTER_CONFIG_ACCEPT_ALL(); -// { -// // -// .acceptance_code = 0b00000000000, -// .acceptance_mask = 0b00001111111, -// .single_filter = true -// }; - - if (const auto result = twai_driver_install(&g_config, &t_config, &f_config); result == ESP_OK) - { - ESP_LOGI(TAG, "twai_driver_install() succeeded"); - } - else - { - ESP_LOGE(TAG, "twai_driver_install() failed with %s", esp_err_to_name(result)); - return; - } - - if (const auto result = twai_start(); result == ESP_OK) - { - ESP_LOGI(TAG, "twai_start() succeeded"); - } - else - { - ESP_LOGE(TAG, "twai_start() failed with %s", esp_err_to_name(result)); - - if (const auto result = twai_driver_uninstall(); result == ESP_OK) - { - ESP_LOGI(TAG, "twai_driver_uninstall() succeeded"); - } - else - { - ESP_LOGE(TAG, "twai_driver_uninstall() failed with %s", esp_err_to_name(result)); - } - - return; - } -} - -template -bool parseMotorControllerCanMessage(const twai_message_t &message, Controller &controller) -{ - switch (message.identifier) - { - using namespace bobbycar::protocol::can; - case MotorController::Feedback::DcLink: - controller.feedback.left.dcLink = *((int16_t*)message.data); - return true; - case MotorController::Feedback::DcLink: - controller.feedback.right.dcLink = *((int16_t*)message.data); - return true; - case MotorController::Feedback::Speed: - controller.feedback.left.speed = *((int16_t*)message.data); - return true; - case MotorController::Feedback::Speed: - controller.feedback.right.speed = *((int16_t*)message.data); - return true; - case MotorController::Feedback::Error: - controller.feedback.left.error = *((int8_t*)message.data); - return true; - case MotorController::Feedback::Error: - controller.feedback.right.error = *((int8_t*)message.data); - return true; - case MotorController::Feedback::Angle: - controller.feedback.left.angle = *((int16_t*)message.data); - return true; - case MotorController::Feedback::Angle: - controller.feedback.right.angle = *((int16_t*)message.data); - return true; - case MotorController::Feedback::DcPhaA: - controller.feedback.left.dcPhaA = *((int16_t*)message.data); - return true; - case MotorController::Feedback::DcPhaA: - controller.feedback.right.dcPhaA = *((int16_t*)message.data); - return true; - case MotorController::Feedback::DcPhaB: - controller.feedback.left.dcPhaB = *((int16_t*)message.data); - return true; - case MotorController::Feedback::DcPhaB: - controller.feedback.right.dcPhaB = *((int16_t*)message.data); - return true; - case MotorController::Feedback::DcPhaC: - controller.feedback.left.dcPhaC = *((int16_t*)message.data); - return true; - case MotorController::Feedback::DcPhaC: - controller.feedback.right.dcPhaC = *((int16_t*)message.data); - return true; - case MotorController::Feedback::Chops: - controller.feedback.left.chops = *((uint16_t*)message.data); - return true; - case MotorController::Feedback::Chops: - controller.feedback.right.chops = *((uint16_t*)message.data); - return true; - case MotorController::Feedback::Hall: - controller.feedback.left.hallA = *((uint8_t*)message.data) & 1; - controller.feedback.left.hallB = *((uint8_t*)message.data) & 2; - controller.feedback.left.hallC = *((uint8_t*)message.data) & 4; - return true; - case MotorController::Feedback::Hall: - controller.feedback.right.hallA = *((uint8_t*)message.data) & 1; - controller.feedback.right.hallB = *((uint8_t*)message.data) & 2; - controller.feedback.right.hallC = *((uint8_t*)message.data) & 4; - return true; - case MotorController::Feedback::Voltage: - case MotorController::Feedback::Voltage: - controller.feedback.batVoltage = *((int16_t*)message.data); - return true; - case MotorController::Feedback::Temp: - case MotorController::Feedback::Temp: - controller.feedback.boardTemp = *((int16_t*)message.data); - return true; - } - - return false; -} - -bool parseBoardcomputerCanMessage(const twai_message_t &message) -{ - switch (message.identifier) - { - using namespace bobbycar::protocol::can; - case Boardcomputer::Command::ButtonPress: - { - const auto canButtonBits = *((uint16_t*)message.data); - CanButtonsState newState { - .up = bool(canButtonBits & Boardcomputer::ButtonUp), - .down = bool(canButtonBits & Boardcomputer::ButtonDown), - .confirm = bool(canButtonBits & Boardcomputer::ButtonConfirm), - .back = bool(canButtonBits & Boardcomputer::ButtonBack), - .profile0 = bool(canButtonBits & Boardcomputer::ButtonProfile0), - .profile1 = bool(canButtonBits & Boardcomputer::ButtonProfile1), - .profile2 = bool(canButtonBits & Boardcomputer::ButtonProfile2), - .profile3 = bool(canButtonBits & Boardcomputer::ButtonProfile3), - }; - - if (lastButtonsState.up != newState.up) - InputDispatcher::upButton(newState.up); - - if (lastButtonsState.down != newState.down) - InputDispatcher::downButton(newState.down); - - if (lastButtonsState.confirm != newState.confirm) - InputDispatcher::confirmButton(newState.confirm); - - if (lastButtonsState.back != newState.back) - InputDispatcher::backButton(newState.back); - - if (lastButtonsState.profile0 != newState.profile0) - InputDispatcher::profileButton(0, newState.profile0); - - if (lastButtonsState.profile1 != newState.profile1) - InputDispatcher::profileButton(1, newState.profile1); - - if (lastButtonsState.profile2 != newState.profile2) - InputDispatcher::profileButton(2, newState.profile2); - - if (lastButtonsState.profile3 != newState.profile3) - InputDispatcher::profileButton(3, newState.profile3); - - lastButtonsState = newState; - break; - } - case Boardcomputer::Command::RawGas: - can_gas = *((int16_t*)message.data); - last_can_gas = espchrono::millis_clock::now(); - break; - case Boardcomputer::Command::RawBrems: - can_brems = *((int16_t*)message.data); - last_can_brems = espchrono::millis_clock::now(); - break; - } - - return false; -} - -bool tryParseCanInput() -{ - twai_message_t message; - const auto timeout = std::chrono::ceil(espchrono::milliseconds32{settings.controllerHardware.canReceiveTimeout}).count(); - if (const auto result = twai_receive(&message, timeout); result != ESP_OK) - { - if (result != ESP_ERR_TIMEOUT) - { - ESP_LOGE(TAG, "twai_receive() failed with %s", esp_err_to_name(result)); - } - - if (espchrono::millis_clock::now() - controllers.front.lastCanFeedback > 100ms) - controllers.front.feedbackValid = false; - - if (espchrono::millis_clock::now() - controllers.back.lastCanFeedback > 100ms) - controllers.back.feedbackValid = false; - - return false; - } - - Controller &front = settings.controllerHardware.swapFrontBack ? controllers.back : controllers.front; - Controller &back = settings.controllerHardware.swapFrontBack ? controllers.front : controllers.back; - - if (parseMotorControllerCanMessage(message, front)) - { - if (espchrono::millis_clock::now() - back.lastCanFeedback > 100ms) - back.feedbackValid = false; - - front.lastCanFeedback = espchrono::millis_clock::now(); - front.feedbackValid = true; - return true; - } - else - { - if (espchrono::millis_clock::now() - front.lastCanFeedback > 100ms) - front.feedbackValid = false; - } - - if (parseMotorControllerCanMessage(message, back)) - { - back.lastCanFeedback = espchrono::millis_clock::now(); - back.feedbackValid = true; - return true; - } - else - { - if (espchrono::millis_clock::now() - back.lastCanFeedback > 100ms) - back.feedbackValid = false; - } - - if (parseBoardcomputerCanMessage(message)) - return true; - - ESP_LOGW(TAG, "Unknown CAN info received .identifier = %u", message.identifier); - - return true; -} - -void parseCanInput() -{ - for (int i = 0; i < 4; i++) - if (!tryParseCanInput()) - break; -} - -void sendCanCommands() -{ - constexpr auto send = [](uint32_t addr, auto value){ - twai_message_t message; - message.identifier = addr; - message.flags = TWAI_MSG_FLAG_SS; - message.data_length_code = sizeof(value); - std::fill(std::begin(message.data), std::end(message.data), 0); - std::memcpy(message.data, &value, sizeof(value)); - - const auto timeout = std::chrono::ceil(espchrono::milliseconds32{settings.controllerHardware.canTransmitTimeout}).count(); - const auto result = twai_transmit(&message, timeout); - if (result != ESP_OK && result != ESP_ERR_TIMEOUT) - { - ESP_LOGE(TAG, "ERROR: twai_transmit() failed with %s", esp_err_to_name(result)); - } - return result; - }; - - const bool swap = settings.controllerHardware.swapFrontBack; - const Controller *front = - (swap ? settings.controllerHardware.sendBackCanCmd : settings.controllerHardware.sendFrontCanCmd ) ? - (swap ? &controllers.back : &controllers.front) : - nullptr; - const Controller *back = - (swap ? settings.controllerHardware.sendFrontCanCmd : settings.controllerHardware.sendBackCanCmd ) ? - (swap ? &controllers.front : &controllers.back) : - nullptr; - - using namespace bobbycar::protocol::can; - - if (front) send(MotorController::Command::InpTgt, front->command.left.pwm); - if (front) send(MotorController::Command::InpTgt, front->command.right.pwm); - if (back) send(MotorController::Command::InpTgt, back->command.left.pwm); - if (back) send(MotorController::Command::InpTgt, back->command.right.pwm); - - uint16_t buttonLeds{}; - if (const auto index = settingsPersister.currentlyOpenProfileIndex()) - switch (*index) - { - case 0: buttonLeds |= Boardcomputer::ButtonProfile0; break; - case 1: buttonLeds |= Boardcomputer::ButtonProfile1; break; - case 2: buttonLeds |= Boardcomputer::ButtonProfile2; break; - case 3: buttonLeds |= Boardcomputer::ButtonProfile3; break; - } - - static struct { - struct { - uint8_t freq = 0; - uint8_t pattern = 0; - } front, back; - uint16_t buttonLeds{}; - } lastValues; - - static int i{}; - - if ((front && front->command.buzzer.freq != lastValues.front.freq ) || - (front && front->command.buzzer.pattern != lastValues.front.pattern ) || - (back && back->command.buzzer.freq != lastValues.back.freq) || - (back && back->command.buzzer.pattern != lastValues.back.pattern)) - i = 10; - else if (buttonLeds != lastValues.buttonLeds) - i = 12; - - switch (i++) - { - case 0: - if (front) send(MotorController::Command::Enable, front->command.left.enable); - if (front) send(MotorController::Command::Enable, front->command.right.enable); - if (back) send(MotorController::Command::Enable, back->command.left.enable); - if (back) send(MotorController::Command::Enable, back->command.right.enable); - break; - case 1: - if (front) send(MotorController::Command::CtrlTyp, front->command.left.ctrlTyp); - if (front) send(MotorController::Command::CtrlTyp, front->command.right.ctrlTyp); - if (back) send(MotorController::Command::CtrlTyp, back->command.left.ctrlTyp); - if (back) send(MotorController::Command::CtrlTyp, back->command.right.ctrlTyp); - break; - case 2: - if (front) send(MotorController::Command::CtrlMod, front->command.left.ctrlMod); - if (front) send(MotorController::Command::CtrlMod, front->command.right.ctrlMod); - if (back) send(MotorController::Command::CtrlMod, back->command.left.ctrlMod); - if (back) send(MotorController::Command::CtrlMod, back->command.right.ctrlMod); - break; - case 3: -#if defined(HAS_SIMPLIFIED) - SIMPLIFIED_IMOTMAX -#endif - if (front) send(MotorController::Command::IMotMax, front->command.left.iMotMax); - if (front) send(MotorController::Command::IMotMax, front->command.right.iMotMax); - if (back) send(MotorController::Command::IMotMax, back->command.left.iMotMax); - if (back) send(MotorController::Command::IMotMax, back->command.right.iMotMax); - break; - case 4: -#if defined(HAS_SIMPLIFIED) - SIMPLIFIED_IDCMAX -#endif - if (front) send(MotorController::Command::IDcMax, front->command.left.iDcMax); - if (front) send(MotorController::Command::IDcMax, front->command.right.iDcMax); - if (back) send(MotorController::Command::IDcMax, back->command.left.iDcMax); - if (back) send(MotorController::Command::IDcMax, back->command.right.iDcMax); - break; - case 5: -#if defined(HAS_SIMPLIFIED) - SIMPLIFIED_NMOTMAX -#endif - if (front) send(MotorController::Command::NMotMax, front->command.left.nMotMax); - if (front) send(MotorController::Command::NMotMax, front->command.right.nMotMax); - if (back) send(MotorController::Command::NMotMax, back->command.left.nMotMax); - if (back) send(MotorController::Command::NMotMax, back->command.right.nMotMax); - break; - case 6: -#if defined(HAS_SIMPLIFIED) - SIMPLIFIED_FIELDWEAKMAX -#endif - if (front) send(MotorController::Command::FieldWeakMax, front->command.left.fieldWeakMax); - if (front) send(MotorController::Command::FieldWeakMax, front->command.right.fieldWeakMax); - if (back) send(MotorController::Command::FieldWeakMax, back->command.left.fieldWeakMax); - if (back) send(MotorController::Command::FieldWeakMax, back->command.right.fieldWeakMax); - break; - case 7: - if (front) send(MotorController::Command::PhaseAdvMax, front->command.left.phaseAdvMax); - if (front) send(MotorController::Command::PhaseAdvMax, front->command.right.phaseAdvMax); - if (back) send(MotorController::Command::PhaseAdvMax, back->command.left.phaseAdvMax); - if (back) send(MotorController::Command::PhaseAdvMax, back->command.right.phaseAdvMax); - break; - case 8: - if (front) send(MotorController::Command::CruiseCtrlEna, front->command.left.cruiseCtrlEna); - if (front) send(MotorController::Command::CruiseCtrlEna, front->command.right.cruiseCtrlEna); - if (back) send(MotorController::Command::CruiseCtrlEna, back->command.left.cruiseCtrlEna); - if (back) send(MotorController::Command::CruiseCtrlEna, back->command.right.cruiseCtrlEna); - break; - case 9: - if (front) send(MotorController::Command::CruiseMotTgt, front->command.left.nCruiseMotTgt); - if (front) send(MotorController::Command::CruiseMotTgt, front->command.right.nCruiseMotTgt); - if (back) send(MotorController::Command::CruiseMotTgt, back->command.left.nCruiseMotTgt); - if (back) send(MotorController::Command::CruiseMotTgt, back->command.right.nCruiseMotTgt); - break; - case 10: - if (front && send(MotorController::Command::BuzzerFreq, front->command.buzzer.freq) == ESP_OK) - lastValues.front.freq = front->command.buzzer.freq; -// if (front && send(MotorController::Command::BuzzerFreq, front->command.buzzer.freq) == ESP_OK) -// lastValues.front.freq = front->command.buzzer.freq; - if (back && send(MotorController::Command::BuzzerFreq, back->command.buzzer.freq) == ESP_OK) - lastValues.back.freq = back->command.buzzer.freq; -// if (back && send(MotorController::Command::BuzzerFreq, back->command.buzzer.freq) == ESP_OK) -// lastValues.back.freq = back->command.buzzer.freq; - if (front && send(MotorController::Command::BuzzerPattern, front->command.buzzer.pattern) == ESP_OK) - lastValues.front.pattern = front->command.buzzer.pattern; -// if (front && send(MotorController::Command::BuzzerPattern, front->command.buzzer.pattern) == ESP_OK) -// lastValues.front.pattern = front->command.buzzer.pattern; - if (back && send(MotorController::Command::BuzzerPattern, back->command.buzzer.pattern) == ESP_OK) - lastValues.back.pattern = back->command.buzzer.pattern; -// if (back && send(MotorController::Command::BuzzerPattern, back->command.buzzer.pattern) == ESP_OK) -// lastValues.back.pattern = back->command.buzzer.pattern; - break; - case 11: - if (front) send(MotorController::Command::Led, front->command.led); - //if (front) send(MotorController::Command::Led, front->command.led); - if (back) send(MotorController::Command::Led, back->command.led); - //if (back) send(MotorController::Command::Led, back->command.led); - if (front) send(MotorController::Command::Poweroff, front->command.poweroff); - //if (front) send(MotorController::Command::Poweroff, front->command.poweroff); - if (back) send(MotorController::Command::Poweroff, back->command.poweroff); - //if (back) send(MotorController::Command::Poweroff, back->command.poweroff); - break; - case 12: - if (send(Boardcomputer::Feedback::ButtonLeds, buttonLeds) == ESP_OK) - lastValues.buttonLeds = buttonLeds; - [[fallthrough]]; - default: - i=0; - break; - } -} -} // namespace +void initCan(); +bool tryParseCanInput(); +void parseCanInput(); +void sendCanCommands(); } // namespace can diff --git a/main/cloud.h b/main/cloud.h index a4ba268..e56aca8 100644 --- a/main/cloud.h +++ b/main/cloud.h @@ -8,6 +8,7 @@ #include #include #include +#include // local includes #include "globals.h" diff --git a/main/controller.cpp b/main/controller.cpp index e69de29..2f467c2 100644 --- a/main/controller.cpp +++ b/main/controller.cpp @@ -0,0 +1,30 @@ +#include "controller.h" + +Controller::Controller( +#ifdef FEATURE_SERIAL + HardwareSerial &serial, +#endif + bool &enableLeft, bool &enableRight, bool &invertLeft, bool &invertRight, + int16_t &voltageCalib30V, int16_t &voltageCalib50V +) : + #ifdef FEATURE_SERIAL + serial{serial}, + #endif + enableLeft{enableLeft}, enableRight{enableRight}, invertLeft{invertLeft}, invertRight{invertRight}, + voltageCalib30V{voltageCalib30V}, voltageCalib50V{voltageCalib50V} +{ +} + +float Controller::getCalibratedVoltage(bool applyCalibration) const +{ + float voltage = feedback.batVoltage; + if (applyCalibration) + { + voltage = ((voltage - float(voltageCalib30V)) * (20.f / (float(voltageCalib50V) - float(voltageCalib30V))) + 30.f); + } + else + { + voltage = voltage / 100.; + } + return voltage; +} diff --git a/main/controller.h b/main/controller.h index cc415b6..4c39302 100644 --- a/main/controller.h +++ b/main/controller.h @@ -23,22 +23,14 @@ class HardwareSerial; #endif -namespace { - -struct Controller { +struct Controller +{ Controller( #ifdef FEATURE_SERIAL HardwareSerial &serial, #endif bool &enableLeft, bool &enableRight, bool &invertLeft, bool &invertRight, - int16_t &voltageCalib30V, int16_t &voltageCalib50V) : -#ifdef FEATURE_SERIAL - serial{serial}, -#endif - enableLeft{enableLeft}, enableRight{enableRight}, invertLeft{invertLeft}, invertRight{invertRight}, - voltageCalib30V{voltageCalib30V}, voltageCalib50V{voltageCalib50V} - { - } + int16_t &voltageCalib30V, int16_t &voltageCalib50V); // Controller(const Controller &) = delete; // Controller &operator=(const Controller &) = delete; @@ -61,18 +53,5 @@ struct Controller { FeedbackParser parser{serial, feedbackValid, feedback}; #endif - float getCalibratedVoltage(bool applyCalibration) const - { - float voltage = feedback.batVoltage; - if (applyCalibration) - { - voltage = ((voltage - float(voltageCalib30V)) * (20.f / (float(voltageCalib50V) - float(voltageCalib30V))) + 30.f); - } - else - { - voltage = voltage / 100.; - } - return voltage; - } + float getCalibratedVoltage(bool applyCalibration) const; }; -} diff --git a/main/esptexthelpers.h b/main/esptexthelpers.h index 39aaae8..b5a47ee 100644 --- a/main/esptexthelpers.h +++ b/main/esptexthelpers.h @@ -9,35 +9,34 @@ // local includes #include "textinterface.h" -namespace { //template //using EspStatusTextHelper = StatusTextHelper; -class HeapTotal8Text : public virtual TextInterface { public: std::string text() const override { +class HeapTotal8Text : public virtual espgui::TextInterface { public: std::string text() const override { return fmt::format("HeapTotal8: {}", heap_caps_get_total_size(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); }}; -class HeapFree8Text : public virtual TextInterface { public: std::string text() const override { +class HeapFree8Text : public virtual espgui::TextInterface { public: std::string text() const override { return fmt::format("HeapFree8: {}", heap_caps_get_free_size(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); }}; -class HeapMinFree8Text : public virtual TextInterface { public: std::string text() const override { +class HeapMinFree8Text : public virtual espgui::TextInterface { public: std::string text() const override { return fmt::format("HeapMinFree8: {}", heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); }}; -class HeapLargest8Text : public virtual TextInterface { public: std::string text() const override { +class HeapLargest8Text : public virtual espgui::TextInterface { public: std::string text() const override { return fmt::format("HeapLargest8: {}", heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); }}; -class HeapTotal32Text : public virtual TextInterface { public: std::string text() const override { +class HeapTotal32Text : public virtual espgui::TextInterface { public: std::string text() const override { return fmt::format("HeapTotal32: {}", heap_caps_get_total_size(MALLOC_CAP_INTERNAL|MALLOC_CAP_32BIT)); }}; -class HeapFree32Text : public virtual TextInterface { public: std::string text() const override { +class HeapFree32Text : public virtual espgui::TextInterface { public: std::string text() const override { return fmt::format("HeapFree32: {}", heap_caps_get_free_size(MALLOC_CAP_INTERNAL|MALLOC_CAP_32BIT)); }}; -class HeapMinFree32Text : public virtual TextInterface { public: std::string text() const override { +class HeapMinFree32Text : public virtual espgui::TextInterface { public: std::string text() const override { return fmt::format("HeapMinFree32: {}", heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL|MALLOC_CAP_32BIT)); }}; -class HeapLargest32Text : public virtual TextInterface { public: std::string text() const override { +class HeapLargest32Text : public virtual espgui::TextInterface { public: std::string text() const override { return fmt::format("HeapLargest32: {}", heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL|MALLOC_CAP_32BIT)); }}; -class LastRebootReasonText : public virtual TextInterface { public: std::string text() const override { +class LastRebootReasonText : public virtual espgui::TextInterface { public: std::string text() const override { std::string reset_reason_string; switch (esp_reset_reason()) { case 0: @@ -80,32 +79,32 @@ class LastRebootReasonText : public virtual TextInterface { public: std::string return fmt::format("Last Reboot Reason: {}", reset_reason_string); }}; constexpr char TEXT_ESPCHIPREVISION[] = "Chip revision: "; -using EspChipRevisionText = StaticText; //EspStatusTextHelper; +using EspChipRevisionText = espgui::StaticText; //EspStatusTextHelper; constexpr char TEXT_ESPCPUFREQMHZ[] = "Cpu freq MHz: "; -using EspCpuFreqMHzText = StaticText; //EspStatusTextHelper; +using EspCpuFreqMHzText = espgui::StaticText; //EspStatusTextHelper; constexpr char TEXT_ESPCYCLECOUNT[] = "Cycle count: "; -using EspCycleCountText = StaticText; //EspStatusTextHelper; +using EspCycleCountText = espgui::StaticText; //EspStatusTextHelper; constexpr char TEXT_ESPSDKVERSION[] = "Sdk version: "; -using EspSdkVersionText = StaticText; //EspStatusTextHelper; +using EspSdkVersionText = espgui::StaticText; //EspStatusTextHelper; constexpr char TEXT_ESPFLASHCHIPSIZE[] = "Flash chip size: "; -using EspFlashChipSizeText = StaticText; //EspStatusTextHelper; +using EspFlashChipSizeText = espgui::StaticText; //EspStatusTextHelper; constexpr char TEXT_ESPFLASHCHIPSPEED[] = "Flash chip speed: "; -using EspFlashChipSpeedText = StaticText; //EspStatusTextHelper; +using EspFlashChipSpeedText = espgui::StaticText; //EspStatusTextHelper; constexpr char TEXT_ESPFLASHCHIPMODE[] = "Flash chip mode: "; -using EspFlashChipModeText = StaticText; //EspStatusTextHelper; // TODO: improve stringifying +using EspFlashChipModeText = espgui::StaticText; //EspStatusTextHelper; // TODO: improve stringifying constexpr char TEXT_ESPSKETCHSIZE[] = "Sketch size: "; -using EspSketchSizeText = StaticText; //StaticallyCachedText>; // caching because of slow +using EspSketchSizeText = espgui::StaticText; //StaticallyCachedText>; // caching because of slow constexpr char TEXT_ESPSKETCHMD5[] = "Sketch MD5: "; -using EspSketchMd5Text = StaticText; //StaticallyCachedText>; // caching because of slow +using EspSketchMd5Text = espgui::StaticText; //StaticallyCachedText>; // caching because of slow constexpr char TEXT_ESPFREESKETCHSPACE[] = "Free sketch space: "; -using EspFreeSketchSpaceText = StaticText; //EspStatusTextHelper; -} +using EspFreeSketchSpaceText = espgui::StaticText; //EspStatusTextHelper; + diff --git a/main/globals.cpp b/main/globals.cpp index e69de29..7907e66 100644 --- a/main/globals.cpp +++ b/main/globals.cpp @@ -0,0 +1,43 @@ +#include "globals.h" + +std::optional raw_gas, raw_brems; +std::optional gas, brems; + +#ifdef FEATURE_GAMETRAK +int16_t raw_gametrakX{}; +int16_t raw_gametrakY{}; +int16_t raw_gametrakDist{}; +float gametrakX; +float gametrakY; +float gametrakDist; +#endif +float avgSpeed{}; +float avgSpeedKmh{}; +float sumCurrent{}; + +char deviceName[32] = STRING(DEVICE_PREFIX) "_ERR"; + +bool simplified = +#if defined(HAS_SIMPLIFIED) + true +#else + false +#endif +; + +Settings settings; +StringSettings stringSettings; +SettingsPersister settingsPersister; + +std::array ledstrip_custom_colors; + +Controllers controllers; + +Performance performance; + +#ifdef FEATURE_BLUETOOTH +BluetoothSerial bluetoothSerial; +#endif + +ModeInterface *lastMode{}; +ModeInterface *currentMode{}; diff --git a/main/globals.h b/main/globals.h index 8aa2aa8..5c251a9 100644 --- a/main/globals.h +++ b/main/globals.h @@ -27,35 +27,34 @@ #include "settingspersister.h" #include "macros_bobbycar.h" -using namespace espgui; - -namespace { -std::optional raw_gas, raw_brems; -std::optional gas, brems; +extern std::optional raw_gas, raw_brems; +extern std::optional gas, brems; #ifdef FEATURE_GAMETRAK -int16_t raw_gametrakX, raw_gametrakY, raw_gametrakDist; -float gametrakX, gametrakY, gametrakDist; +extern int16_t raw_gametrakX; +extern int16_t raw_gametrakY; +extern int16_t raw_gametrakDist; +extern float gametrakX; +extern float gametrakY; +extern float gametrakDist; #endif -float avgSpeed, avgSpeedKmh, sumCurrent; +extern float avgSpeed; +extern float avgSpeedKmh; +extern float sumCurrent; -char deviceName[32] = STRING(DEVICE_PREFIX) "_ERR"; +extern char deviceName[32]; #ifdef GLOBALS_PLUGIN #include GLOBALS_PLUGIN #endif -#if defined(HAS_SIMPLIFIED) -bool simplified = true; -#else -bool simplified = false; -#endif +extern bool simplified; -Settings settings; -StringSettings stringSettings; -SettingsPersister settingsPersister; +extern Settings settings; +extern StringSettings stringSettings; +extern SettingsPersister settingsPersister; -std::array ledstrip_custom_colors = {}; +extern std::array ledstrip_custom_colors; class Controllers : public std::array { @@ -86,22 +85,23 @@ public: Controller &back{operator[](1)}; }; -Controllers controllers; +extern Controllers controllers; struct FrontControllerGetter { static Controller &get() { return controllers.front; }}; struct BackControllerGetter { static Controller &get() { return controllers.back; }}; -struct { +struct Performance { espchrono::millis_clock::time_point lastTime; int current{}; int last{}; -} performance; +}; +extern Performance performance; #ifdef FEATURE_BLUETOOTH -BluetoothSerial bluetoothSerial; +extern BluetoothSerial bluetoothSerial; #endif -ModeInterface *lastMode{}; -ModeInterface *currentMode{}; +extern ModeInterface *lastMode; +extern ModeInterface *currentMode; #ifdef FEATURE_LEDBACKLIGHT constexpr const bool ledBacklightInverted = @@ -112,4 +112,3 @@ constexpr const bool ledBacklightInverted = #endif ; #endif -} diff --git a/main/modeinterface.h b/main/modeinterface.h index 398e02d..0724663 100644 --- a/main/modeinterface.h +++ b/main/modeinterface.h @@ -1,9 +1,7 @@ #pragma once -#include - -namespace { -class ModeInterface { +class ModeInterface +{ public: virtual ~ModeInterface() = default; @@ -13,4 +11,4 @@ public: virtual const char *displayName() const = 0; }; -} + diff --git a/main/modes/defaultmode.cpp b/main/modes/defaultmode.cpp index e69de29..e34f1fc 100644 --- a/main/modes/defaultmode.cpp +++ b/main/modes/defaultmode.cpp @@ -0,0 +1,153 @@ +#include "defaultmode.h" + +namespace modes { +DefaultMode defaultMode; +} // namespace modes + +void DefaultMode::start() +{ + Base::start(); +} + +void DefaultMode::update() +{ + if (!gas || !brems) + { + start(); + + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; + motor.ctrlMod = bobbycar::protocol::ControlMode::OpenMode; + motor.pwm = 0; + motor.cruiseCtrlEna = false; + motor.nCruiseMotTgt = 0; + } + } + else + { + float local_gas = *gas; + float local_brems = *brems; + + if (waitForGasLoslass) + { + if (local_gas < 50) + waitForGasLoslass = false; + else + local_gas = 0; + } + + if (waitForBremsLoslass) + { + if (local_brems < 50) + waitForBremsLoslass = false; + else + local_brems = 0; + } + + const auto gas_processed = settings.defaultMode.squareGas ? (local_gas * local_gas) / 1000.f : local_gas; + const auto brems_processed = settings.defaultMode.squareBrems ? (local_brems * local_brems) / 1000 : local_brems; + + const auto now = espchrono::millis_clock::now(); + + float pwm; + if (gas_processed >= settings.defaultMode.add_schwelle) + { + pwm = (gas_processed/1000.*settings.defaultMode.gas1_wert) + (brems_processed/1000.*settings.defaultMode.brems1_wert); + + if ((settings.defaultMode.enableSmoothingUp || settings.defaultMode.enableSmoothingDown) && (pwm > 1000. || lastPwm > 1000.)) + { + if (lastPwm < pwm && settings.defaultMode.enableSmoothingUp) + { + pwm = std::min(pwm, lastPwm + (settings.defaultMode.smoothing * std::chrono::milliseconds{now - lastTime}.count() / 100.f)); + if (pwm < 1000.) + pwm = 1000.; + } + else if (lastPwm > pwm && settings.defaultMode.enableSmoothingDown) + { + pwm = std::max(pwm, lastPwm - (settings.defaultMode.smoothing * std::chrono::milliseconds{now - lastTime}.count() / 100.f)); + } + } + } + else + { + pwm = (gas_processed/1000.*settings.defaultMode.gas2_wert) - (brems_processed/1000.*settings.defaultMode.brems2_wert); + if ( + (settings.defaultMode.enableFieldWeakSmoothingUp || settings.defaultMode.enableFieldWeakSmoothingDown) && + (lastPwm > settings.defaultMode.fwSmoothLowerLimit) && + brems_processed > 0) + { + if (lastPwm < pwm && settings.defaultMode.enableFieldWeakSmoothingUp) + { + auto effective_smoothing = settings.defaultMode.smoothing; + auto difference_to_target = std::abs(pwm-lastPwm); + effective_smoothing *= std::max((difference_to_target / 500),0.5f); + + pwm = std::min(pwm, lastPwm + (effective_smoothing * std::chrono::milliseconds{now - lastTime}.count() / 100.f)); + } + else if (lastPwm > pwm && settings.defaultMode.enableFieldWeakSmoothingDown) + { + auto effective_smoothing = settings.defaultMode.smoothing; + auto difference_to_target = std::abs(pwm-lastPwm); + effective_smoothing *= std::max((difference_to_target / 500),0.5f); + + pwm = std::max(pwm, lastPwm - (effective_smoothing * std::chrono::milliseconds{now - lastTime}.count() / 100.f)); + } + } + } + + lastPwm = pwm; + lastTime = now; + + auto pair = split(settings.defaultMode.modelMode); + + if (settings.hybrid.enable) + { + auto activationLimit = settings.hybrid.activationLimit; + auto deactivationLimit = settings.hybrid.deactivationLimit; + auto diff = std::abs(activationLimit - deactivationLimit); + + if (diff < 20) + { + int half = (diff / 2) + 0.5; + deactivationLimit -= half; + activationLimit += half; + } + + if (!hybridModeActivated && (pwm > activationLimit)) + { + hybridModeActivated = true; + } + else if (hybridModeActivated && (pwm < deactivationLimit)) + { + hybridModeActivated = false; + } + + if (hybridModeActivated) + { + pair = split(settings.hybrid.hybridMode); + } + } + + for (bobbycar::protocol::serial::MotorState &motor : motorsInController(controllers.front)) + { + motor.ctrlTyp = pair.first; + motor.ctrlMod = pair.second; + motor.pwm = pwm / 100. * settings.defaultMode.frontPercentage; + motor.cruiseCtrlEna = false; + motor.nCruiseMotTgt = 0; + } + for (bobbycar::protocol::serial::MotorState &motor : motorsInController(controllers.back)) + { + motor.ctrlTyp = pair.first; + motor.ctrlMod = pair.second; + motor.pwm = pwm / 100. * settings.defaultMode.backPercentage; + motor.cruiseCtrlEna = false; + motor.nCruiseMotTgt = 0; + } + } + + fixCommonParams(); + + sendCommands(); +} diff --git a/main/modes/defaultmode.h b/main/modes/defaultmode.h index e97a8be..3d80e1c 100644 --- a/main/modes/defaultmode.h +++ b/main/modes/defaultmode.h @@ -1,16 +1,16 @@ #pragma once +// system includes #include -#include - +// 3rdparty lib includes #include +// local includes #include "modeinterface.h" #include "globals.h" #include "utils.h" -namespace { class DefaultMode : public ModeInterface { using Base = ModeInterface; @@ -31,154 +31,5 @@ private: }; namespace modes { -DefaultMode defaultMode; -} - -void DefaultMode::start() -{ - Base::start(); -} - -void DefaultMode::update() -{ - if (!gas || !brems) - { - start(); - - for (bobbycar::protocol::serial::MotorState &motor : motors()) - { - motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; - motor.ctrlMod = bobbycar::protocol::ControlMode::OpenMode; - motor.pwm = 0; - motor.cruiseCtrlEna = false; - motor.nCruiseMotTgt = 0; - } - } - else - { - float local_gas = *gas; - float local_brems = *brems; - - if (waitForGasLoslass) - { - if (local_gas < 50) - waitForGasLoslass = false; - else - local_gas = 0; - } - - if (waitForBremsLoslass) - { - if (local_brems < 50) - waitForBremsLoslass = false; - else - local_brems = 0; - } - - const auto gas_processed = settings.defaultMode.squareGas ? (local_gas * local_gas) / 1000.f : local_gas; - const auto brems_processed = settings.defaultMode.squareBrems ? (local_brems * local_brems) / 1000 : local_brems; - - const auto now = espchrono::millis_clock::now(); - - float pwm; - if (gas_processed >= settings.defaultMode.add_schwelle) - { - pwm = (gas_processed/1000.*settings.defaultMode.gas1_wert) + (brems_processed/1000.*settings.defaultMode.brems1_wert); - - if ((settings.defaultMode.enableSmoothingUp || settings.defaultMode.enableSmoothingDown) && (pwm > 1000. || lastPwm > 1000.)) - { - if (lastPwm < pwm && settings.defaultMode.enableSmoothingUp) - { - pwm = std::min(pwm, lastPwm + (settings.defaultMode.smoothing * std::chrono::milliseconds{now - lastTime}.count() / 100.f)); - if (pwm < 1000.) - pwm = 1000.; - } - else if (lastPwm > pwm && settings.defaultMode.enableSmoothingDown) - { - pwm = std::max(pwm, lastPwm - (settings.defaultMode.smoothing * std::chrono::milliseconds{now - lastTime}.count() / 100.f)); - } - } - } - else - { - pwm = (gas_processed/1000.*settings.defaultMode.gas2_wert) - (brems_processed/1000.*settings.defaultMode.brems2_wert); - if ( - (settings.defaultMode.enableFieldWeakSmoothingUp || settings.defaultMode.enableFieldWeakSmoothingDown) && - (lastPwm > settings.defaultMode.fwSmoothLowerLimit) && - brems_processed > 0) - { - if (lastPwm < pwm && settings.defaultMode.enableFieldWeakSmoothingUp) - { - auto effective_smoothing = settings.defaultMode.smoothing; - auto difference_to_target = std::abs(pwm-lastPwm); - effective_smoothing *= std::max((difference_to_target / 500),0.5f); - - pwm = std::min(pwm, lastPwm + (effective_smoothing * std::chrono::milliseconds{now - lastTime}.count() / 100.f)); - } - else if (lastPwm > pwm && settings.defaultMode.enableFieldWeakSmoothingDown) - { - auto effective_smoothing = settings.defaultMode.smoothing; - auto difference_to_target = std::abs(pwm-lastPwm); - effective_smoothing *= std::max((difference_to_target / 500),0.5f); - - pwm = std::max(pwm, lastPwm - (effective_smoothing * std::chrono::milliseconds{now - lastTime}.count() / 100.f)); - } - } - } - - lastPwm = pwm; - lastTime = now; - - auto pair = split(settings.defaultMode.modelMode); - - if (settings.hybrid.enable) - { - auto activationLimit = settings.hybrid.activationLimit; - auto deactivationLimit = settings.hybrid.deactivationLimit; - auto diff = std::abs(activationLimit - deactivationLimit); - - if (diff < 20) - { - int half = (diff / 2) + 0.5; - deactivationLimit -= half; - activationLimit += half; - } - - if (!hybridModeActivated && (pwm > activationLimit)) - { - hybridModeActivated = true; - } - else if (hybridModeActivated && (pwm < deactivationLimit)) - { - hybridModeActivated = false; - } - - if (hybridModeActivated) - { - pair = split(settings.hybrid.hybridMode); - } - } - - for (bobbycar::protocol::serial::MotorState &motor : motorsInController(controllers.front)) - { - motor.ctrlTyp = pair.first; - motor.ctrlMod = pair.second; - motor.pwm = pwm / 100. * settings.defaultMode.frontPercentage; - motor.cruiseCtrlEna = false; - motor.nCruiseMotTgt = 0; - } - for (bobbycar::protocol::serial::MotorState &motor : motorsInController(controllers.back)) - { - motor.ctrlTyp = pair.first; - motor.ctrlMod = pair.second; - motor.pwm = pwm / 100. * settings.defaultMode.backPercentage; - motor.cruiseCtrlEna = false; - motor.nCruiseMotTgt = 0; - } - } - - fixCommonParams(); - - sendCommands(); -} -} +extern DefaultMode defaultMode; +} // namespace modes diff --git a/main/modes/gametrakmode.cpp b/main/modes/gametrakmode.cpp index e69de29..cc79fe6 100644 --- a/main/modes/gametrakmode.cpp +++ b/main/modes/gametrakmode.cpp @@ -0,0 +1,84 @@ +#include "gametrakmode.h" + +// local includes +#include "globals.h" +#include "utils.h" +#include "defaultmode.h" + +namespace { +template +constexpr const T& clamp( const T& v, const T& lo, const T& hi ) +{ + assert( !(hi < lo) ); + return (v < lo) ? lo : (hi < v) ? hi : v; +} +} // namespace + +#ifdef FEATURE_GAMETRAK +namespace modes { +GametrakMode gametrakMode; +} // namespace modes + +void GametrakMode::start() +{ + Base::start(); + m_flag = false; +} + +void GametrakMode::update() +{ + if (!gas || !brems) + { + start(); + + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; + motor.ctrlMod = bobbycar::protocol::ControlMode::OpenMode; + motor.pwm = 0; + motor.cruiseCtrlEna = false; + motor.nCruiseMotTgt = 0; + } + } + else + { + if (*gas > 500. || *brems > 500.) + { + modes::defaultMode.waitForGasLoslass = true; + modes::defaultMode.waitForBremsLoslass = true; + currentMode = &modes::defaultMode; + return; + } + + int16_t pwm; + if (gametrakDist < 150) + { + pwm = 0; + m_flag = false; + } + else + { + if (m_flag || gametrakDist >= 400) + { + m_flag = true; + pwm = clamp((gametrakDist - 400) / 2, -200, 200); + } + else + pwm = 0; + } + + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; + motor.ctrlMod = bobbycar::protocol::ControlMode::Speed; + motor.pwm = pwm; + motor.cruiseCtrlEna = false; + motor.nCruiseMotTgt = 0; + } + } + + fixCommonParams(); + + sendCommands(); +} +#endif diff --git a/main/modes/gametrakmode.h b/main/modes/gametrakmode.h index 99f1e0f..92317b3 100644 --- a/main/modes/gametrakmode.h +++ b/main/modes/gametrakmode.h @@ -1,22 +1,9 @@ #pragma once -namespace { -template -constexpr const T& clamp( const T& v, const T& lo, const T& hi ) -{ - assert( !(hi < lo) ); - return (v < lo) ? lo : (hi < v) ? hi : v; -} -} - -#include "modeinterface.h" -#include "globals.h" -#include "utils.h" -#include "defaultmode.h" - +// local includes #include "bobbycar-common.h" +#include "modeinterface.h" -namespace { #ifdef FEATURE_GAMETRAK class GametrakMode : public ModeInterface { @@ -33,70 +20,6 @@ private: }; namespace modes { -GametrakMode gametrakMode; -} - -void GametrakMode::start() -{ - Base::start(); - m_flag = false; -} - -void GametrakMode::update() -{ - if (!gas || !brems) - { - start(); - - for (bobbycar::protocol::serial::MotorState &motor : motors()) - { - motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; - motor.ctrlMod = bobbycar::protocol::ControlMode::OpenMode; - motor.pwm = 0; - motor.cruiseCtrlEna = false; - motor.nCruiseMotTgt = 0; - } - } - else - { - if (*gas > 500. || *brems > 500.) - { - modes::defaultMode.waitForGasLoslass = true; - modes::defaultMode.waitForBremsLoslass = true; - currentMode = &modes::defaultMode; - return; - } - - int16_t pwm; - if (gametrakDist < 150) - { - pwm = 0; - m_flag = false; - } - else - { - if (m_flag || gametrakDist >= 400) - { - m_flag = true; - pwm = clamp((gametrakDist - 400) / 2, -200, 200); - } - else - pwm = 0; - } - - for (bobbycar::protocol::serial::MotorState &motor : motors()) - { - motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; - motor.ctrlMod = bobbycar::protocol::ControlMode::Speed; - motor.pwm = pwm; - motor.cruiseCtrlEna = false; - motor.nCruiseMotTgt = 0; - } - } - - fixCommonParams(); - - sendCommands(); -} +extern GametrakMode gametrakMode; +} // namespace modes #endif -} diff --git a/main/modes/ignoreinputmode.cpp b/main/modes/ignoreinputmode.cpp index e69de29..5f87739 100644 --- a/main/modes/ignoreinputmode.cpp +++ b/main/modes/ignoreinputmode.cpp @@ -0,0 +1,21 @@ +#include "ignoreinputmode.h" + +// local includes +#include "globals.h" +#include "utils.h" + +void IgnoreInputMode::update() +{ + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + motor.ctrlTyp = m_ctrlTyp; + motor.ctrlMod = m_ctrlMod; + motor.pwm = m_pwm; + motor.cruiseCtrlEna = false; + motor.nCruiseMotTgt = 0; + } + + fixCommonParams(); + + sendCommands(); +} diff --git a/main/modes/ignoreinputmode.h b/main/modes/ignoreinputmode.h index a4e2e11..fe4d675 100644 --- a/main/modes/ignoreinputmode.h +++ b/main/modes/ignoreinputmode.h @@ -1,12 +1,9 @@ #pragma once -#include "modeinterface.h" -#include "globals.h" -#include "utils.h" - +// local includes #include "bobbycar-common.h" +#include "modeinterface.h" -namespace { class IgnoreInputMode : public ModeInterface { public: @@ -24,20 +21,3 @@ private: const bobbycar::protocol::ControlType m_ctrlTyp; const bobbycar::protocol::ControlMode m_ctrlMod; }; - -void IgnoreInputMode::update() -{ - for (bobbycar::protocol::serial::MotorState &motor : motors()) - { - motor.ctrlTyp = m_ctrlTyp; - motor.ctrlMod = m_ctrlMod; - motor.pwm = m_pwm; - motor.cruiseCtrlEna = false; - motor.nCruiseMotTgt = 0; - } - - fixCommonParams(); - - sendCommands(); -} -} diff --git a/main/modes/larsmmode.cpp b/main/modes/larsmmode.cpp index e69de29..3b24d89 100644 --- a/main/modes/larsmmode.cpp +++ b/main/modes/larsmmode.cpp @@ -0,0 +1,112 @@ +#include "larsmmode.h" + +// local includes +#include "globals.h" +#include "utils.h" + +namespace modes { +LarsmMode larsmMode; +} // namespace modes + +void LarsmMode::start() +{ + Base::start(); + + adc1_filtered = 0.f; + adc2_filtered = 0.f; + speed = 0; + weak = 0.f; +} + +void LarsmMode::update() +{ + if (!gas || !brems) + { + start(); + + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; + motor.ctrlMod = bobbycar::protocol::ControlMode::OpenMode; + motor.pwm = 0; + motor.cruiseCtrlEna = false; + motor.nCruiseMotTgt = 0; + } + } + else + { + for (uint8_t i = 0; i < settings.larsmMode.iterations; i++) // run multiple times to emulate higher refreshrate + { + // ####### larsm's bobby car code ####### + + // LOW-PASS FILTER (fliessender Mittelwert) + adc1_filtered = adc1_filtered * 0.9 + *gas * 0.1; // ADC1, TX, rechts, vorwaerts, blau + adc2_filtered = adc2_filtered * 0.9 + *brems * 0.1; // ADC2, RX, links, rueckwearts, gruen + + // magic numbers die ich nicht mehr nachvollziehen kann, faehrt sich aber gut ;-) + #define LOSLASS_BREMS_ACC 0.996f // naeher an 1 = gemaechlicher + #define DRUECK_ACC2 (1.0f - LOSLASS_BREMS_ACC + 0.001f) // naeher an 0 = gemaechlicher + #define DRUECK_ACC1 (1.0f - LOSLASS_BREMS_ACC + 0.001f) // naeher an 0 = gemaechlicher + //die + 0.001f gleichen float ungenauigkeiten aus. + + #define ADC1_MIN 0 + #define ADC2_MIN 0 + #define ADC1_MAX 1000 + #define ADC2_MAX 1000 + + #define ADC2_DELTA (ADC2_MAX - ADC2_MIN) + #define ADC1_DELTA (ADC1_MAX - ADC1_MIN) + + #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) + + if (settings.larsmMode.mode == LarsmModeMode::Mode1) { // Mode 1, links: 3 kmh + speed = (float)speed * LOSLASS_BREMS_ACC // bremsen wenn kein poti gedrueckt + - (CLAMP(*brems - ADC2_MIN, 0, ADC2_DELTA) / (ADC2_DELTA / 280.0f)) * DRUECK_ACC2 // links gedrueckt = zusatzbremsen oder rueckwaertsfahren + + (CLAMP(*gas - ADC1_MIN, 0, ADC1_DELTA) / (ADC1_DELTA / 350.0f)) * DRUECK_ACC1; // vorwaerts gedrueckt = beschleunigen 12s: 350=3kmh + weak = 0; + + } else if (settings.larsmMode.mode == LarsmModeMode::Mode2) { // Mode 2, default: 6 kmh + speed = (float)speed * LOSLASS_BREMS_ACC + - (CLAMP(*brems - ADC2_MIN, 0, ADC2_DELTA) / (ADC2_DELTA / 310.0f)) * DRUECK_ACC2 + + (CLAMP(*gas - ADC1_MIN, 0, ADC1_DELTA) / (ADC1_DELTA / 420.0f)) * DRUECK_ACC1; // 12s: 400=5-6kmh 450=7kmh + weak = 0; + + } else if (settings.larsmMode.mode == LarsmModeMode::Mode3) { // Mode 3, rechts: 12 kmh + speed = (float)speed * LOSLASS_BREMS_ACC + - (CLAMP(*brems - ADC2_MIN, 0, ADC2_DELTA) / (ADC2_DELTA / 340.0f)) * DRUECK_ACC2 + + (CLAMP(*gas - ADC1_MIN, 0, ADC1_DELTA) / (ADC1_DELTA / 600.0f)) * DRUECK_ACC1; // 12s: 600=12kmh + weak = 0; + + } else if (settings.larsmMode.mode == LarsmModeMode::Mode4) { // Mode 4, l + r: full kmh + // Feldschwaechung wird nur aktiviert wenn man schon sehr schnell ist. So gehts: Rechts voll druecken und warten bis man schnell ist, dann zusaetzlich links schnell voll druecken. + if (adc2_filtered > (ADC2_MAX - 450) && speed > 800) { // field weakening at high speeds + speed = (float)speed * LOSLASS_BREMS_ACC + + (CLAMP(*gas - ADC1_MIN, 0, ADC1_DELTA) / (ADC1_DELTA / 1000.0f)) * DRUECK_ACC1; + weak = weak * 0.95 + 400.0 * 0.05; // sanftes hinzuschalten des turbos, 12s: 400=29kmh + } else { //normale fahrt ohne feldschwaechung + speed = (float)speed * LOSLASS_BREMS_ACC + - (CLAMP(*brems - ADC2_MIN, 0, ADC2_DELTA) / (ADC2_DELTA / 340.0f)) * DRUECK_ACC2 + + (CLAMP(*gas - ADC1_MIN, 0, ADC1_DELTA) / (ADC1_DELTA / 1000.0f)) * DRUECK_ACC1; // 12s: 1000=22kmh + weak = weak * 0.95; // sanftes abschalten des turbos + } + // weak should never exceed 400 or 450 MAX!! + } + + speed = CLAMP(speed, -1000, 1000); // clamp output + } + + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + const auto pair = split(settings.larsmMode.modelMode); + motor.ctrlTyp = pair.first; + motor.ctrlMod = pair.second; + motor.pwm = speed + weak; + motor.cruiseCtrlEna = false; + motor.nCruiseMotTgt = 0; + } + } + + fixCommonParams(); + + sendCommands(); +} diff --git a/main/modes/larsmmode.h b/main/modes/larsmmode.h index a866a41..08e28c0 100644 --- a/main/modes/larsmmode.h +++ b/main/modes/larsmmode.h @@ -1,12 +1,9 @@ #pragma once -#include "modeinterface.h" -#include "globals.h" -#include "utils.h" - +// local includes #include "bobbycar-common.h" +#include "modeinterface.h" -namespace { class LarsmMode : public ModeInterface { using Base = ModeInterface; @@ -25,109 +22,5 @@ private: }; namespace modes { -LarsmMode larsmMode; -} - -void LarsmMode::start() -{ - Base::start(); - - adc1_filtered = 0.f; - adc2_filtered = 0.f; - speed = 0; - weak = 0.f; -} - -void LarsmMode::update() -{ - if (!gas || !brems) - { - start(); - - for (bobbycar::protocol::serial::MotorState &motor : motors()) - { - motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; - motor.ctrlMod = bobbycar::protocol::ControlMode::OpenMode; - motor.pwm = 0; - motor.cruiseCtrlEna = false; - motor.nCruiseMotTgt = 0; - } - } - else - { - for (uint8_t i = 0; i < settings.larsmMode.iterations; i++) // run multiple times to emulate higher refreshrate - { - // ####### larsm's bobby car code ####### - - // LOW-PASS FILTER (fliessender Mittelwert) - adc1_filtered = adc1_filtered * 0.9 + *gas * 0.1; // ADC1, TX, rechts, vorwaerts, blau - adc2_filtered = adc2_filtered * 0.9 + *brems * 0.1; // ADC2, RX, links, rueckwearts, gruen - - // magic numbers die ich nicht mehr nachvollziehen kann, faehrt sich aber gut ;-) - #define LOSLASS_BREMS_ACC 0.996f // naeher an 1 = gemaechlicher - #define DRUECK_ACC2 (1.0f - LOSLASS_BREMS_ACC + 0.001f) // naeher an 0 = gemaechlicher - #define DRUECK_ACC1 (1.0f - LOSLASS_BREMS_ACC + 0.001f) // naeher an 0 = gemaechlicher - //die + 0.001f gleichen float ungenauigkeiten aus. - - #define ADC1_MIN 0 - #define ADC2_MIN 0 - #define ADC1_MAX 1000 - #define ADC2_MAX 1000 - - #define ADC2_DELTA (ADC2_MAX - ADC2_MIN) - #define ADC1_DELTA (ADC1_MAX - ADC1_MIN) - - #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) - - if (settings.larsmMode.mode == LarsmModeMode::Mode1) { // Mode 1, links: 3 kmh - speed = (float)speed * LOSLASS_BREMS_ACC // bremsen wenn kein poti gedrueckt - - (CLAMP(*brems - ADC2_MIN, 0, ADC2_DELTA) / (ADC2_DELTA / 280.0f)) * DRUECK_ACC2 // links gedrueckt = zusatzbremsen oder rueckwaertsfahren - + (CLAMP(*gas - ADC1_MIN, 0, ADC1_DELTA) / (ADC1_DELTA / 350.0f)) * DRUECK_ACC1; // vorwaerts gedrueckt = beschleunigen 12s: 350=3kmh - weak = 0; - - } else if (settings.larsmMode.mode == LarsmModeMode::Mode2) { // Mode 2, default: 6 kmh - speed = (float)speed * LOSLASS_BREMS_ACC - - (CLAMP(*brems - ADC2_MIN, 0, ADC2_DELTA) / (ADC2_DELTA / 310.0f)) * DRUECK_ACC2 - + (CLAMP(*gas - ADC1_MIN, 0, ADC1_DELTA) / (ADC1_DELTA / 420.0f)) * DRUECK_ACC1; // 12s: 400=5-6kmh 450=7kmh - weak = 0; - - } else if (settings.larsmMode.mode == LarsmModeMode::Mode3) { // Mode 3, rechts: 12 kmh - speed = (float)speed * LOSLASS_BREMS_ACC - - (CLAMP(*brems - ADC2_MIN, 0, ADC2_DELTA) / (ADC2_DELTA / 340.0f)) * DRUECK_ACC2 - + (CLAMP(*gas - ADC1_MIN, 0, ADC1_DELTA) / (ADC1_DELTA / 600.0f)) * DRUECK_ACC1; // 12s: 600=12kmh - weak = 0; - - } else if (settings.larsmMode.mode == LarsmModeMode::Mode4) { // Mode 4, l + r: full kmh - // Feldschwaechung wird nur aktiviert wenn man schon sehr schnell ist. So gehts: Rechts voll druecken und warten bis man schnell ist, dann zusaetzlich links schnell voll druecken. - if (adc2_filtered > (ADC2_MAX - 450) && speed > 800) { // field weakening at high speeds - speed = (float)speed * LOSLASS_BREMS_ACC - + (CLAMP(*gas - ADC1_MIN, 0, ADC1_DELTA) / (ADC1_DELTA / 1000.0f)) * DRUECK_ACC1; - weak = weak * 0.95 + 400.0 * 0.05; // sanftes hinzuschalten des turbos, 12s: 400=29kmh - } else { //normale fahrt ohne feldschwaechung - speed = (float)speed * LOSLASS_BREMS_ACC - - (CLAMP(*brems - ADC2_MIN, 0, ADC2_DELTA) / (ADC2_DELTA / 340.0f)) * DRUECK_ACC2 - + (CLAMP(*gas - ADC1_MIN, 0, ADC1_DELTA) / (ADC1_DELTA / 1000.0f)) * DRUECK_ACC1; // 12s: 1000=22kmh - weak = weak * 0.95; // sanftes abschalten des turbos - } - // weak should never exceed 400 or 450 MAX!! - } - - speed = CLAMP(speed, -1000, 1000); // clamp output - } - - for (bobbycar::protocol::serial::MotorState &motor : motors()) - { - const auto pair = split(settings.larsmMode.modelMode); - motor.ctrlTyp = pair.first; - motor.ctrlMod = pair.second; - motor.pwm = speed + weak; - motor.cruiseCtrlEna = false; - motor.nCruiseMotTgt = 0; - } - } - - fixCommonParams(); - - sendCommands(); -} -} +extern LarsmMode larsmMode; +} // namespace modes diff --git a/main/modes/remotecontrolmode.cpp b/main/modes/remotecontrolmode.cpp index e69de29..a8819fc 100644 --- a/main/modes/remotecontrolmode.cpp +++ b/main/modes/remotecontrolmode.cpp @@ -0,0 +1,54 @@ +#include "remotecontrolmode.h" + +// local includes +#include "globals.h" +#include "utils.h" +#include "defaultmode.h" + +using namespace std::chrono_literals; + +namespace modes { +RemoteControlMode remoteControlMode; +} // namespace modes + +void RemoteControlMode::update() +{ + if (!m_remoteCommand || espchrono::ago(m_timestamp) > 500ms) + { + start(); + + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; + motor.ctrlMod = bobbycar::protocol::ControlMode::OpenMode; + motor.pwm = 0; + motor.cruiseCtrlEna = false; + motor.nCruiseMotTgt = 0; + } + } + else + { + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; + motor.ctrlMod = bobbycar::protocol::ControlMode::Torque; + motor.cruiseCtrlEna = false; + motor.nCruiseMotTgt = 0; + } + + controllers.front.command.left.pwm = m_remoteCommand->frontLeft; + controllers.front.command.right.pwm = m_remoteCommand->frontRight; + controllers.back.command.left.pwm = m_remoteCommand->backLeft; + controllers.back.command.right.pwm = m_remoteCommand->backRight; + } + + fixCommonParams(); + + sendCommands(); +} + +void RemoteControlMode::setCommand(const RemoteCommand &command) +{ + m_remoteCommand = command; + m_timestamp = espchrono::millis_clock::now(); +} diff --git a/main/modes/remotecontrolmode.h b/main/modes/remotecontrolmode.h index 61141ef..a29f69f 100644 --- a/main/modes/remotecontrolmode.h +++ b/main/modes/remotecontrolmode.h @@ -9,15 +9,8 @@ // local includes #include "bobbycar-common.h" - #include "modeinterface.h" -#include "globals.h" -#include "utils.h" -#include "defaultmode.h" -using namespace std::chrono_literals; - -namespace { struct RemoteCommand { int16_t frontLeft{}; int16_t frontRight{}; @@ -41,48 +34,5 @@ public: }; namespace modes { -RemoteControlMode remoteControlMode; -} - -void RemoteControlMode::update() -{ - if (!m_remoteCommand || espchrono::ago(m_timestamp) > 500ms) - { - start(); - - for (bobbycar::protocol::serial::MotorState &motor : motors()) - { - motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; - motor.ctrlMod = bobbycar::protocol::ControlMode::OpenMode; - motor.pwm = 0; - motor.cruiseCtrlEna = false; - motor.nCruiseMotTgt = 0; - } - } - else - { - for (bobbycar::protocol::serial::MotorState &motor : motors()) - { - motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; - motor.ctrlMod = bobbycar::protocol::ControlMode::Torque; - motor.cruiseCtrlEna = false; - motor.nCruiseMotTgt = 0; - } - - controllers.front.command.left.pwm = m_remoteCommand->frontLeft; - controllers.front.command.right.pwm = m_remoteCommand->frontRight; - controllers.back.command.left.pwm = m_remoteCommand->backLeft; - controllers.back.command.right.pwm = m_remoteCommand->backRight; - } - - fixCommonParams(); - - sendCommands(); -} - -void RemoteControlMode::setCommand(const RemoteCommand &command) -{ - m_remoteCommand = command; - m_timestamp = espchrono::millis_clock::now(); -} -} +extern RemoteControlMode remoteControlMode; +} // namespace modes diff --git a/main/modes/tempomatmode.cpp b/main/modes/tempomatmode.cpp index e69de29..1d9cdab 100644 --- a/main/modes/tempomatmode.cpp +++ b/main/modes/tempomatmode.cpp @@ -0,0 +1,60 @@ +#include "tempomatmode.h" + +// local includes +#include "globals.h" +#include "utils.h" +#include "defaultmode.h" + +namespace modes { +TempomatMode tempomatMode; +} // namespace modes + +void TempomatMode::start() +{ + Base::start(); + nCruiseMotTgt = avgSpeed; +} + +void TempomatMode::update() +{ + if (!gas || !brems) + { + start(); + + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; + motor.ctrlMod = bobbycar::protocol::ControlMode::OpenMode; + motor.pwm = 0; + motor.cruiseCtrlEna = false; + motor.nCruiseMotTgt = 0; + } + } + else + { + if (*gas > 500. && *brems > 500.) + { + nCruiseMotTgt = 0; + modes::defaultMode.waitForGasLoslass = true; + modes::defaultMode.waitForBremsLoslass = true; + currentMode = &modes::defaultMode; + return; + } + + nCruiseMotTgt += (*gas/1000.) - (*brems/1000.); + + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + const auto pair = split(settings.tempomatMode.modelMode); + motor.ctrlTyp = pair.first; + motor.ctrlMod = pair.second; + motor.pwm = 0; + motor.cruiseCtrlEna = true; + motor.nCruiseMotTgt = nCruiseMotTgt; + } + } + + fixCommonParams(); + + sendCommands(); +} diff --git a/main/modes/tempomatmode.h b/main/modes/tempomatmode.h index cdc1147..884294e 100644 --- a/main/modes/tempomatmode.h +++ b/main/modes/tempomatmode.h @@ -1,15 +1,12 @@ #pragma once +// system includes #include +// local includes #include "bobbycar-common.h" - #include "modeinterface.h" -#include "globals.h" -#include "utils.h" -#include "defaultmode.h" -namespace { class TempomatMode : public ModeInterface { using Base = ModeInterface; @@ -24,56 +21,5 @@ public: }; namespace modes { -TempomatMode tempomatMode; -} - -void TempomatMode::start() -{ - Base::start(); - nCruiseMotTgt = avgSpeed; -} - -void TempomatMode::update() -{ - if (!gas || !brems) - { - start(); - - for (bobbycar::protocol::serial::MotorState &motor : motors()) - { - motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; - motor.ctrlMod = bobbycar::protocol::ControlMode::OpenMode; - motor.pwm = 0; - motor.cruiseCtrlEna = false; - motor.nCruiseMotTgt = 0; - } - } - else - { - if (*gas > 500. && *brems > 500.) - { - nCruiseMotTgt = 0; - modes::defaultMode.waitForGasLoslass = true; - modes::defaultMode.waitForBremsLoslass = true; - currentMode = &modes::defaultMode; - return; - } - - nCruiseMotTgt += (*gas/1000.) - (*brems/1000.); - - for (bobbycar::protocol::serial::MotorState &motor : motors()) - { - const auto pair = split(settings.tempomatMode.modelMode); - motor.ctrlTyp = pair.first; - motor.ctrlMod = pair.second; - motor.pwm = 0; - motor.cruiseCtrlEna = true; - motor.nCruiseMotTgt = nCruiseMotTgt; - } - } - - fixCommonParams(); - - sendCommands(); -} -} +extern TempomatMode tempomatMode; +} // namespace modes diff --git a/main/presets.cpp b/main/presets.cpp index e69de29..abeeae5 100644 --- a/main/presets.cpp +++ b/main/presets.cpp @@ -0,0 +1,53 @@ +#include "presets.h" + +namespace presets { +StringSettings makeDefaultStringSettings() +{ + using ConfiguredWifi = StringSettings::ConfiguredWifi; +#ifdef FEATURE_OTA + using ConfiguredOtaServer = StringSettings::ConfiguredOtaServer; +#endif + + return { + .wifis = std::array { + ConfiguredWifi { .ssid = {}, .key = {} }, + ConfiguredWifi { .ssid = {}, .key = {} }, + ConfiguredWifi { .ssid = {}, .key = {} }, + ConfiguredWifi { .ssid = {}, .key = {} }, + ConfiguredWifi { .ssid = {}, .key = {} }, + ConfiguredWifi { .ssid = {}, .key = {} }, + ConfiguredWifi { .ssid = {}, .key = {} }, + ConfiguredWifi { .ssid = {}, .key = {} }, + ConfiguredWifi { .ssid = {}, .key = {} }, + ConfiguredWifi { .ssid = {}, .key = {} } + }, +#ifdef FEATURE_CLOUD + .cloudUrl = {}, +#endif +#ifdef FEATURE_OTA + .otaUrl = {}, +#endif +#ifdef FEATURE_GARAGE + .garageUrl = {}, +#endif +#ifdef FEATURE_NTP + .timeServer = "europe.pool.ntp.org", +#endif +#ifdef FEATURE_OTA + .otaServers = std::array { + ConfiguredOtaServer { .name = {}, .url = {} }, + ConfiguredOtaServer { .name = {}, .url = {} }, + ConfiguredOtaServer { .name = {}, .url = {} }, + ConfiguredOtaServer { .name = {}, .url = {} }, + ConfiguredOtaServer { .name = {}, .url = {} }, +// ConfiguredOtaServer { .name = {}, .url = {} }, +// ConfiguredOtaServer { .name = {}, .url = {} }, +// ConfiguredOtaServer { .name = {}, .url = {} }, +// ConfiguredOtaServer { .name = {}, .url = {} }, +// ConfiguredOtaServer { .name = {}, .url = {} }, + }, + .otaServerUrl = {}, +#endif + }; +} +} // namespace presets diff --git a/main/presets.h b/main/presets.h index b2687c3..1b4a037 100644 --- a/main/presets.h +++ b/main/presets.h @@ -302,53 +302,5 @@ constexpr Settings defaultSettings { .lockscreen = defaultLockscreen }; -StringSettings makeDefaultStringSettings() -{ - using ConfiguredWifi = StringSettings::ConfiguredWifi; -#ifdef FEATURE_OTA - using ConfiguredOtaServer = StringSettings::ConfiguredOtaServer; -#endif - - return { - .wifis = std::array { - ConfiguredWifi { .ssid = {}, .key = {} }, - ConfiguredWifi { .ssid = {}, .key = {} }, - ConfiguredWifi { .ssid = {}, .key = {} }, - ConfiguredWifi { .ssid = {}, .key = {} }, - ConfiguredWifi { .ssid = {}, .key = {} }, - ConfiguredWifi { .ssid = {}, .key = {} }, - ConfiguredWifi { .ssid = {}, .key = {} }, - ConfiguredWifi { .ssid = {}, .key = {} }, - ConfiguredWifi { .ssid = {}, .key = {} }, - ConfiguredWifi { .ssid = {}, .key = {} } - }, -#ifdef FEATURE_CLOUD - .cloudUrl = {}, -#endif -#ifdef FEATURE_OTA - .otaUrl = {}, -#endif -#ifdef FEATURE_GARAGE - .garageUrl = {}, -#endif -#ifdef FEATURE_NTP - .timeServer = "europe.pool.ntp.org", -#endif -#ifdef FEATURE_OTA - .otaServers = std::array { - ConfiguredOtaServer { .name = {}, .url = {} }, - ConfiguredOtaServer { .name = {}, .url = {} }, - ConfiguredOtaServer { .name = {}, .url = {} }, - ConfiguredOtaServer { .name = {}, .url = {} }, - ConfiguredOtaServer { .name = {}, .url = {} },/* - ConfiguredOtaServer { .name = {}, .url = {} }, - ConfiguredOtaServer { .name = {}, .url = {} }, - ConfiguredOtaServer { .name = {}, .url = {} }, - ConfiguredOtaServer { .name = {}, .url = {} }, - ConfiguredOtaServer { .name = {}, .url = {} },*/ - }, - .otaServerUrl = {}, -#endif - }; -} -} +StringSettings makeDefaultStringSettings(); +} // namespace presets diff --git a/main/settings.h b/main/settings.h index 55f94a9..0f714d4 100644 --- a/main/settings.h +++ b/main/settings.h @@ -22,7 +22,6 @@ #endif #include "unifiedmodelmode.h" -namespace { enum class LarsmModeMode : uint8_t { Mode1, Mode2, Mode3, Mode4 }; struct Settings @@ -358,4 +357,3 @@ void Settings::executeForEveryProfileSetting(T &&callable) callable("larsm.mode", larsmMode.mode); callable("larsm.iters", larsmMode.iterations); } -} diff --git a/main/settingspersister.cpp b/main/settingspersister.cpp index e69de29..605e7d5 100644 --- a/main/settingspersister.cpp +++ b/main/settingspersister.cpp @@ -0,0 +1,438 @@ +#include "settingspersister.h" + +// system includes +#include + +// esp-idf includes +#include +#include +#ifdef FEATURE_NTP +#include +#include +#endif + +// 3rdparty lib includes +#include +#include +#include +#include + +// local includes +#include "settings.h" +#ifdef FEATURE_BLUETOOTH +#include "bluetoothmode.h" +#endif +#include "unifiedmodelmode.h" +#include "settings.h" +#include "stringsettings.h" + +bool SettingsPersister::init() +{ + if (esp_err_t result = nvs_flash_init(); + cpputils::is_in(result, ESP_ERR_NVS_NO_FREE_PAGES, ESP_ERR_NVS_NEW_VERSION_FOUND)) + { + ESP_LOGE("BOBBY", "nvs_flash_init() failed with %s, trying to erase...", esp_err_to_name(result)); + return erase(); + } + else if (result != ESP_OK) + { + ESP_LOGE("BOBBY", "nvs_flash_init() failed with %s", esp_err_to_name(result)); + return false; + } + + return true; +} + +bool SettingsPersister::erase() +{ + closeProfile(); + closeCommon(); + + bool result{true}; + + if (esp_err_t result = nvs_flash_erase(); result != ESP_OK) + { + ESP_LOGE("BOBBY", "nvs_flash_erase() failed with %s", esp_err_to_name(result)); + result = false; + } + + if (esp_err_t result = nvs_flash_init(); result != ESP_OK) + { + ESP_LOGE("BOBBY", "nvs_flash_init() failed with %s", esp_err_to_name(result)); + result = false; + } + + return result; +} + +bool SettingsPersister::openCommon() +{ + closeCommon(); + + nvs_handle handle; + if (esp_err_t result = nvs_open("bobbycar", NVS_READWRITE, &handle); result != ESP_OK) + { + ESP_LOGE("BOBBY", "nvs_open() COMMON %s failed with %s", "bobbycar", esp_err_to_name(result)); + return false; + } + + m_handle = handle; + + return true; +} + +void SettingsPersister::closeCommon() +{ + if (!m_handle) + return; + + nvs_close(m_handle); + + m_handle = {}; +} + +bool SettingsPersister::openProfile(uint8_t index) +{ + closeProfile(); + + nvs_handle handle; + const auto name = fmt::format("bobbycar{}", index); + if (esp_err_t result = nvs_open(name.c_str(), NVS_READWRITE, &handle); result != ESP_OK) + { + ESP_LOGE("BOBBY", "nvs_open() PROFILE %s failed with %s", name.c_str(), esp_err_to_name(result)); + return false; + } + + m_profile = {handle, index}; + + return true; +} + +void SettingsPersister::closeProfile() +{ + if (!m_profile) + return; + + nvs_close(m_profile->handle); + + m_profile = std::nullopt; +} + +template struct nvsGetterHelper; +template<> struct nvsGetterHelper { static constexpr auto nvs_get = &nvs_get_i8; }; +template<> struct nvsGetterHelper { static constexpr auto nvs_get = &nvs_get_u8; }; +template<> struct nvsGetterHelper { static constexpr auto nvs_get = &nvs_get_i16; }; +template<> struct nvsGetterHelper { static constexpr auto nvs_get = &nvs_get_u16; }; +template<> struct nvsGetterHelper { static constexpr auto nvs_get = &nvs_get_i32; }; +template<> struct nvsGetterHelper { static constexpr auto nvs_get = &nvs_get_u32; }; +template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, std::string* out_value) +{ + size_t length; + if (const esp_err_t result = nvs_get_str(handle, key, nullptr, &length); result != ESP_OK) + return result; + + char buf[length]; + if (const esp_err_t result = nvs_get_str(handle, key, buf, &length); result != ESP_OK) + return result; + + *out_value = buf; + + return ESP_OK; +}}; +template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, bool* out_value) +{ + uint8_t tempValue; + esp_err_t err = nvs_get_u8(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = tempValue; + return err; +}}; +template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, bobbycar::protocol::ControlType* out_value) +{ + uint8_t tempValue; + esp_err_t err = nvs_get_u8(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = bobbycar::protocol::ControlType(tempValue); + return err; +}}; +template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, bobbycar::protocol::ControlMode* out_value) +{ + uint8_t tempValue; + esp_err_t err = nvs_get_u8(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = bobbycar::protocol::ControlMode(tempValue); + return err; +}}; +template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, LarsmModeMode* out_value) +{ + uint8_t tempValue; + esp_err_t err = nvs_get_u8(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = LarsmModeMode(tempValue); + return err; +}}; +#ifdef FEATURE_BLUETOOTH +template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, BluetoothMode* out_value) +{ + uint8_t tempValue; + esp_err_t err = nvs_get_u8(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = BluetoothMode(tempValue); + return err; +}}; +#endif +template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, UnifiedModelMode* out_value) +{ + uint8_t tempValue; + esp_err_t err = nvs_get_u8(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = UnifiedModelMode(tempValue); + return err; +}}; +template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, wifi_mode_t* out_value) +{ + uint8_t tempValue; + esp_err_t err = nvs_get_u8(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = wifi_mode_t(tempValue); + return err; +}}; +template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::DayLightSavingMode* out_value) +{ + uint8_t tempValue; + esp_err_t err = nvs_get_u8(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = espchrono::DayLightSavingMode(tempValue); + return err; +}}; +template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::milliseconds32* out_value) +{ + int32_t tempValue; + esp_err_t err = nvs_get_i32(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = espchrono::milliseconds32(tempValue); + return err; +}}; +template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::seconds32* out_value) +{ + int32_t tempValue; + esp_err_t err = nvs_get_i32(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = espchrono::seconds32(tempValue); + return err; +}}; +template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::minutes32* out_value) +{ + int32_t tempValue; + esp_err_t err = nvs_get_i32(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = espchrono::minutes32(tempValue); + return err; +}}; +template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::hours32* out_value) +{ + int32_t tempValue; + esp_err_t err = nvs_get_i32(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = espchrono::hours32(tempValue); + return err; +}}; +#ifdef FEATURE_NTP +template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, sntp_sync_mode_t* out_value) +{ + uint8_t tempValue; + esp_err_t err = nvs_get_u8(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = sntp_sync_mode_t(tempValue); + return err; +}}; +#endif +template<> struct nvsGetterHelper> { static esp_err_t nvs_get(nvs_handle handle, const char* key, std::array* out_value) +{ + uint32_t tempValue; + esp_err_t err = nvs_get_u32(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = std::bit_cast>(tempValue); + return err; +}}; +template<> struct nvsGetterHelper> { static esp_err_t nvs_get(nvs_handle handle, const char* key, std::array* out_value) +{ + uint32_t tempValue; + esp_err_t err = nvs_get_u32(handle, key, &tempValue); + if (err == ESP_OK) + *out_value = std::bit_cast>(tempValue); + return err; +}}; + +template +bool SettingsPersister::load(T &settings) +{ + bool result{true}; + + if (m_handle) + { + settings.executeForEveryCommonSetting([&](const char *key, auto &value) + { + if (esp_err_t result = nvsGetterHelper>::nvs_get(m_handle, key, &value); result != ESP_OK) + { + if (result != ESP_ERR_NVS_NOT_FOUND) + ESP_LOGE("BOBBY", "nvs_get() COMMON %s failed with %s", key, esp_err_to_name(result)); + result = false; + } + }); + } + else + { + ESP_LOGW("BOBBY", "common nvs handle not valid!"); + result = false; + } + + if (m_profile) + { + settings.executeForEveryProfileSetting([&](const char *key, auto &value) + { + if (esp_err_t result = nvsGetterHelper>::nvs_get(m_profile->handle, key, &value); result != ESP_OK) + { + if (result != ESP_ERR_NVS_NOT_FOUND) + ESP_LOGE("BOBBY", "nvs_get() PROFILE %s failed with %s", key, esp_err_to_name(result)); + result = false; + } + }); + } + else + { + ESP_LOGW("BOBBY", "no profile open currently!"); + result = false; + } + + return result; +} + +template bool SettingsPersister::load(Settings &settings); +template bool SettingsPersister::load(StringSettings &settings); + +template struct nvsSetterHelper; +template<> struct nvsSetterHelper { static constexpr auto nvs_set = &nvs_set_i8; }; +template<> struct nvsSetterHelper { static constexpr auto nvs_set = &nvs_set_u8; }; +template<> struct nvsSetterHelper { static constexpr auto nvs_set = &nvs_set_i16; }; +template<> struct nvsSetterHelper { static constexpr auto nvs_set = &nvs_set_u16; }; +template<> struct nvsSetterHelper { static constexpr auto nvs_set = &nvs_set_i32; }; +template<> struct nvsSetterHelper { static constexpr auto nvs_set = &nvs_set_u32; }; +template<> struct nvsSetterHelper { static constexpr auto nvs_set = &nvs_set_u8; }; +template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, const std::string &value) +{ + return nvs_set_str(handle, key, value.c_str()); +}}; +template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, bobbycar::protocol::ControlType value) +{ + return nvs_set_u8(handle, key, uint8_t(value)); +}}; +template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, bobbycar::protocol::ControlMode value) +{ + return nvs_set_u8(handle, key, uint8_t(value)); +}}; +template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, LarsmModeMode value) +{ + return nvs_set_u8(handle, key, uint8_t(value)); +}}; +#ifdef FEATURE_BLUETOOTH +template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, BluetoothMode value) +{ + return nvs_set_u8(handle, key, uint8_t(value)); +}}; +#endif +template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, UnifiedModelMode value) +{ + return nvs_set_u8(handle, key, uint8_t(value)); +}}; +template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, wifi_mode_t value) +{ + return nvs_set_u8(handle, key, uint8_t(value)); +}}; +template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::DayLightSavingMode value) +{ + return nvs_set_u8(handle, key, uint8_t(value)); +}}; +template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::milliseconds32 value) +{ + return nvs_set_i32(handle, key, value.count()); +}}; +template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::seconds32 value) +{ + return nvs_set_i32(handle, key, value.count()); +}}; +template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::minutes32 value) +{ + return nvs_set_i32(handle, key, value.count()); +}}; +template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::hours32 value) +{ + return nvs_set_i32(handle, key, value.count()); +}}; +#ifdef FEATURE_NTP +template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, sntp_sync_mode_t value) +{ + return nvs_set_u8(handle, key, uint8_t(value)); +}}; +#endif +template<> struct nvsSetterHelper> { static esp_err_t nvs_set(nvs_handle handle, const char* key, std::array value) +{ + return nvs_set_u32(handle, key, std::bit_cast(value)); +}}; +template<> struct nvsSetterHelper> { static esp_err_t nvs_set(nvs_handle handle, const char* key, std::array value) +{ + return nvs_set_u32(handle, key, std::bit_cast(value)); +}}; + +template +bool SettingsPersister::save(T &settings) +{ + bool result{true}; + + if (m_handle) + { + settings.executeForEveryCommonSetting([&](const char *key, const auto &value) + { + if (esp_err_t result = nvsSetterHelper>::nvs_set(m_handle, key, value); result != ESP_OK) + { + ESP_LOGE("BOBBY", "nvs_set() COMMON %s failed with %s", key, esp_err_to_name(result)); + result = false; + } + }); + } + else + { + ESP_LOGW("BOBBY", "common nvs handle not valid!"); + result = false; + } + + if (m_profile) + { + settings.executeForEveryProfileSetting([&](const char *key, const auto &value) + { + if (esp_err_t result = nvsSetterHelper>::nvs_set(m_profile->handle, key, value); result != ESP_OK) + { + ESP_LOGE("BOBBY", "nvs_set() PROFILE %s failed with %s", key, esp_err_to_name(result)); + result = false; + } + }); + } + else + { + ESP_LOGW("BOBBY", "no profile open currently!"); + result = false; + } + + return result; +} + +template bool SettingsPersister::save(Settings &settings); +template bool SettingsPersister::save(StringSettings &settings); + +std::optional SettingsPersister::currentlyOpenProfileIndex() const +{ + if (m_profile) + return m_profile->profileIndex; + + return std::nullopt; +} diff --git a/main/settingspersister.h b/main/settingspersister.h index 1702a85..02dfe92 100644 --- a/main/settingspersister.h +++ b/main/settingspersister.h @@ -1,32 +1,9 @@ #pragma once // system includes -#include #include - -// esp-idf includes -#include -#include #include -#ifdef FEATURE_NTP -#include -#include -#endif -// 3rdparty lib includes -#include -#include -#include -#include - -// local includes -#include "settings.h" -#ifdef FEATURE_BLUETOOTH -#include "bluetoothmode.h" -#endif -#include "unifiedmodelmode.h" - -namespace { class SettingsPersister { public: @@ -55,409 +32,3 @@ private: }; std::optional m_profile; }; - -bool SettingsPersister::init() -{ - if (esp_err_t result = nvs_flash_init(); - cpputils::is_in(result, ESP_ERR_NVS_NO_FREE_PAGES, ESP_ERR_NVS_NEW_VERSION_FOUND)) - { - ESP_LOGE("BOBBY", "nvs_flash_init() failed with %s, trying to erase...", esp_err_to_name(result)); - return erase(); - } - else if (result != ESP_OK) - { - ESP_LOGE("BOBBY", "nvs_flash_init() failed with %s", esp_err_to_name(result)); - return false; - } - - return true; -} - -bool SettingsPersister::erase() -{ - closeProfile(); - closeCommon(); - - bool result{true}; - - if (esp_err_t result = nvs_flash_erase(); result != ESP_OK) - { - ESP_LOGE("BOBBY", "nvs_flash_erase() failed with %s", esp_err_to_name(result)); - result = false; - } - - if (esp_err_t result = nvs_flash_init(); result != ESP_OK) - { - ESP_LOGE("BOBBY", "nvs_flash_init() failed with %s", esp_err_to_name(result)); - result = false; - } - - return result; -} - -bool SettingsPersister::openCommon() -{ - closeCommon(); - - nvs_handle handle; - if (esp_err_t result = nvs_open("bobbycar", NVS_READWRITE, &handle); result != ESP_OK) - { - ESP_LOGE("BOBBY", "nvs_open() COMMON %s failed with %s", "bobbycar", esp_err_to_name(result)); - return false; - } - - m_handle = handle; - - return true; -} - -void SettingsPersister::closeCommon() -{ - if (!m_handle) - return; - - nvs_close(m_handle); - - m_handle = {}; -} - -bool SettingsPersister::openProfile(uint8_t index) -{ - closeProfile(); - - nvs_handle handle; - const auto name = fmt::format("bobbycar{}", index); - if (esp_err_t result = nvs_open(name.c_str(), NVS_READWRITE, &handle); result != ESP_OK) - { - ESP_LOGE("BOBBY", "nvs_open() PROFILE %s failed with %s", name.c_str(), esp_err_to_name(result)); - return false; - } - - m_profile = {handle, index}; - - return true; -} - -void SettingsPersister::closeProfile() -{ - if (!m_profile) - return; - - nvs_close(m_profile->handle); - - m_profile = std::nullopt; -} - -template struct nvsGetterHelper; -template<> struct nvsGetterHelper { static constexpr auto nvs_get = &nvs_get_i8; }; -template<> struct nvsGetterHelper { static constexpr auto nvs_get = &nvs_get_u8; }; -template<> struct nvsGetterHelper { static constexpr auto nvs_get = &nvs_get_i16; }; -template<> struct nvsGetterHelper { static constexpr auto nvs_get = &nvs_get_u16; }; -template<> struct nvsGetterHelper { static constexpr auto nvs_get = &nvs_get_i32; }; -template<> struct nvsGetterHelper { static constexpr auto nvs_get = &nvs_get_u32; }; -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, std::string* out_value) -{ - size_t length; - if (const esp_err_t result = nvs_get_str(handle, key, nullptr, &length); result != ESP_OK) - return result; - - char buf[length]; - if (const esp_err_t result = nvs_get_str(handle, key, buf, &length); result != ESP_OK) - return result; - - *out_value = buf; - - return ESP_OK; -}}; -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, bool* out_value) -{ - uint8_t tempValue; - esp_err_t err = nvs_get_u8(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = tempValue; - return err; -}}; -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, bobbycar::protocol::ControlType* out_value) -{ - uint8_t tempValue; - esp_err_t err = nvs_get_u8(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = bobbycar::protocol::ControlType(tempValue); - return err; -}}; -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, bobbycar::protocol::ControlMode* out_value) -{ - uint8_t tempValue; - esp_err_t err = nvs_get_u8(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = bobbycar::protocol::ControlMode(tempValue); - return err; -}}; -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, LarsmModeMode* out_value) -{ - uint8_t tempValue; - esp_err_t err = nvs_get_u8(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = LarsmModeMode(tempValue); - return err; -}}; -#ifdef FEATURE_BLUETOOTH -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, BluetoothMode* out_value) -{ - uint8_t tempValue; - esp_err_t err = nvs_get_u8(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = BluetoothMode(tempValue); - return err; -}}; -#endif -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, UnifiedModelMode* out_value) -{ - uint8_t tempValue; - esp_err_t err = nvs_get_u8(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = UnifiedModelMode(tempValue); - return err; -}}; -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, wifi_mode_t* out_value) -{ - uint8_t tempValue; - esp_err_t err = nvs_get_u8(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = wifi_mode_t(tempValue); - return err; -}}; -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::DayLightSavingMode* out_value) -{ - uint8_t tempValue; - esp_err_t err = nvs_get_u8(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = espchrono::DayLightSavingMode(tempValue); - return err; -}}; -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::milliseconds32* out_value) -{ - int32_t tempValue; - esp_err_t err = nvs_get_i32(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = espchrono::milliseconds32(tempValue); - return err; -}}; -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::seconds32* out_value) -{ - int32_t tempValue; - esp_err_t err = nvs_get_i32(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = espchrono::seconds32(tempValue); - return err; -}}; -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::minutes32* out_value) -{ - int32_t tempValue; - esp_err_t err = nvs_get_i32(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = espchrono::minutes32(tempValue); - return err; -}}; -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, espchrono::hours32* out_value) -{ - int32_t tempValue; - esp_err_t err = nvs_get_i32(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = espchrono::hours32(tempValue); - return err; -}}; -#ifdef FEATURE_NTP -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, sntp_sync_mode_t* out_value) -{ - uint8_t tempValue; - esp_err_t err = nvs_get_u8(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = sntp_sync_mode_t(tempValue); - return err; -}}; -#endif -template<> struct nvsGetterHelper> { static esp_err_t nvs_get(nvs_handle handle, const char* key, std::array* out_value) -{ - uint32_t tempValue; - esp_err_t err = nvs_get_u32(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = std::bit_cast>(tempValue); - return err; -}}; -template<> struct nvsGetterHelper> { static esp_err_t nvs_get(nvs_handle handle, const char* key, std::array* out_value) -{ - uint32_t tempValue; - esp_err_t err = nvs_get_u32(handle, key, &tempValue); - if (err == ESP_OK) - *out_value = std::bit_cast>(tempValue); - return err; -}}; - -template -bool SettingsPersister::load(T &settings) -{ - bool result{true}; - - if (m_handle) - { - settings.executeForEveryCommonSetting([&](const char *key, auto &value) - { - if (esp_err_t result = nvsGetterHelper>::nvs_get(m_handle, key, &value); result != ESP_OK) - { - if (result != ESP_ERR_NVS_NOT_FOUND) - ESP_LOGE("BOBBY", "nvs_get() COMMON %s failed with %s", key, esp_err_to_name(result)); - result = false; - } - }); - } - else - { - ESP_LOGW("BOBBY", "common nvs handle not valid!"); - result = false; - } - - if (m_profile) - { - settings.executeForEveryProfileSetting([&](const char *key, auto &value) - { - if (esp_err_t result = nvsGetterHelper>::nvs_get(m_profile->handle, key, &value); result != ESP_OK) - { - if (result != ESP_ERR_NVS_NOT_FOUND) - ESP_LOGE("BOBBY", "nvs_get() PROFILE %s failed with %s", key, esp_err_to_name(result)); - result = false; - } - }); - } - else - { - ESP_LOGW("BOBBY", "no profile open currently!"); - result = false; - } - - return result; -} - -template struct nvsSetterHelper; -template<> struct nvsSetterHelper { static constexpr auto nvs_set = &nvs_set_i8; }; -template<> struct nvsSetterHelper { static constexpr auto nvs_set = &nvs_set_u8; }; -template<> struct nvsSetterHelper { static constexpr auto nvs_set = &nvs_set_i16; }; -template<> struct nvsSetterHelper { static constexpr auto nvs_set = &nvs_set_u16; }; -template<> struct nvsSetterHelper { static constexpr auto nvs_set = &nvs_set_i32; }; -template<> struct nvsSetterHelper { static constexpr auto nvs_set = &nvs_set_u32; }; -template<> struct nvsSetterHelper { static constexpr auto nvs_set = &nvs_set_u8; }; -template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, const std::string &value) -{ - return nvs_set_str(handle, key, value.c_str()); -}}; -template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, bobbycar::protocol::ControlType value) -{ - return nvs_set_u8(handle, key, uint8_t(value)); -}}; -template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, bobbycar::protocol::ControlMode value) -{ - return nvs_set_u8(handle, key, uint8_t(value)); -}}; -template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, LarsmModeMode value) -{ - return nvs_set_u8(handle, key, uint8_t(value)); -}}; -#ifdef FEATURE_BLUETOOTH -template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, BluetoothMode value) -{ - return nvs_set_u8(handle, key, uint8_t(value)); -}}; -#endif -template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, UnifiedModelMode value) -{ - return nvs_set_u8(handle, key, uint8_t(value)); -}}; -template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, wifi_mode_t value) -{ - return nvs_set_u8(handle, key, uint8_t(value)); -}}; -template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::DayLightSavingMode value) -{ - return nvs_set_u8(handle, key, uint8_t(value)); -}}; -template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::milliseconds32 value) -{ - return nvs_set_i32(handle, key, value.count()); -}}; -template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::seconds32 value) -{ - return nvs_set_i32(handle, key, value.count()); -}}; -template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::minutes32 value) -{ - return nvs_set_i32(handle, key, value.count()); -}}; -template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, espchrono::hours32 value) -{ - return nvs_set_i32(handle, key, value.count()); -}}; -#ifdef FEATURE_NTP -template<> struct nvsSetterHelper { static esp_err_t nvs_set(nvs_handle handle, const char* key, sntp_sync_mode_t value) -{ - return nvs_set_u8(handle, key, uint8_t(value)); -}}; -#endif -template<> struct nvsSetterHelper> { static esp_err_t nvs_set(nvs_handle handle, const char* key, std::array value) -{ - return nvs_set_u32(handle, key, std::bit_cast(value)); -}}; -template<> struct nvsSetterHelper> { static esp_err_t nvs_set(nvs_handle handle, const char* key, std::array value) -{ - return nvs_set_u32(handle, key, std::bit_cast(value)); -}}; - -template -bool SettingsPersister::save(T &settings) -{ - bool result{true}; - - if (m_handle) - { - settings.executeForEveryCommonSetting([&](const char *key, const auto &value) - { - if (esp_err_t result = nvsSetterHelper>::nvs_set(m_handle, key, value); result != ESP_OK) - { - ESP_LOGE("BOBBY", "nvs_set() COMMON %s failed with %s", key, esp_err_to_name(result)); - result = false; - } - }); - } - else - { - ESP_LOGW("BOBBY", "common nvs handle not valid!"); - result = false; - } - - if (m_profile) - { - settings.executeForEveryProfileSetting([&](const char *key, const auto &value) - { - if (esp_err_t result = nvsSetterHelper>::nvs_set(m_profile->handle, key, value); result != ESP_OK) - { - ESP_LOGE("BOBBY", "nvs_set() PROFILE %s failed with %s", key, esp_err_to_name(result)); - result = false; - } - }); - } - else - { - ESP_LOGW("BOBBY", "no profile open currently!"); - result = false; - } - - return result; -} - -std::optional SettingsPersister::currentlyOpenProfileIndex() const -{ - if (m_profile) - return m_profile->profileIndex; - - return std::nullopt; -} -} diff --git a/main/stringsettings.h b/main/stringsettings.h index 1a63f18..82fac93 100644 --- a/main/stringsettings.h +++ b/main/stringsettings.h @@ -4,7 +4,6 @@ #include #include -namespace { struct StringSettings { struct ConfiguredWifi { @@ -30,7 +29,6 @@ struct StringSettings std::string timeServer; #endif - template void executeForEveryCommonSetting(T &&callable); @@ -96,17 +94,17 @@ void StringSettings::executeForEveryCommonSetting(T &&callable) callable("otaName3", otaServers[3].name); callable("otaUrl3", otaServers[3].url); callable("otaName4", otaServers[4].name); - callable("otaUrl4", otaServers[4].url);/* - callable("otaName5", otaServers[5].name); - callable("otaUrl5", otaServers[5].url); - callable("otaName6", otaServers[6].name); - callable("otaUrl6", otaServers[6].url); - callable("otaName7", otaServers[7].name); - callable("otaUrl7", otaServers[7].url); - callable("otaName8", otaServers[8].name); - callable("otaUrl8", otaServers[8].url); - callable("otaName9", otaServers[9].name); - callable("otaUrl9", otaServers[9].url);*/ + callable("otaUrl4", otaServers[4].url); +// callable("otaName5", otaServers[5].name); +// callable("otaUrl5", otaServers[5].url); +// callable("otaName6", otaServers[6].name); +// callable("otaUrl6", otaServers[6].url); +// callable("otaName7", otaServers[7].name); +// callable("otaUrl7", otaServers[7].url); +// callable("otaName8", otaServers[8].name); +// callable("otaUrl8", otaServers[8].url); +// callable("otaName9", otaServers[9].name); +// callable("otaUrl9", otaServers[9].url); callable("otaserver", otaServerUrl); #endif @@ -116,4 +114,3 @@ template void StringSettings::executeForEveryProfileSetting(T &&callable) { } -} diff --git a/main/unifiedmodelmode.cpp b/main/unifiedmodelmode.cpp index e69de29..00aa0d8 100644 --- a/main/unifiedmodelmode.cpp +++ b/main/unifiedmodelmode.cpp @@ -0,0 +1,20 @@ +#include "unifiedmodelmode.h" + +std::pair split(UnifiedModelMode mode) +{ + using bobbycar::protocol::ControlType; + using bobbycar::protocol::ControlMode; + + switch (mode) + { + case UnifiedModelMode::Commutation: return std::make_pair(ControlType::Commutation, ControlMode::Voltage); + case UnifiedModelMode::Sinusoidal: return std::make_pair(ControlType::Sinusoidal, ControlMode::Voltage); + case UnifiedModelMode::FocVoltage: return std::make_pair(ControlType::FieldOrientedControl, ControlMode::Voltage); + case UnifiedModelMode::FocSpeed: return std::make_pair(ControlType::FieldOrientedControl, ControlMode::Speed); + case UnifiedModelMode::FocTorque: return std::make_pair(ControlType::FieldOrientedControl, ControlMode::Torque); + } + + //Serial.printf("Unknown UnifiedModelMode: %i\r\n", int(mode)); + + return std::make_pair(ControlType::FieldOrientedControl, ControlMode::OpenMode); +} diff --git a/main/unifiedmodelmode.h b/main/unifiedmodelmode.h index 105a2c4..76251dd 100644 --- a/main/unifiedmodelmode.h +++ b/main/unifiedmodelmode.h @@ -1,10 +1,11 @@ #pragma once +// system includes #include +// local includes #include "bobbycar-common.h" -namespace { enum class UnifiedModelMode : uint8_t { Commutation, @@ -14,22 +15,4 @@ enum class UnifiedModelMode : uint8_t FocTorque }; -std::pair split(UnifiedModelMode mode) -{ - using bobbycar::protocol::ControlType; - using bobbycar::protocol::ControlMode; - - switch (mode) - { - case UnifiedModelMode::Commutation: return std::make_pair(ControlType::Commutation, ControlMode::Voltage); - case UnifiedModelMode::Sinusoidal: return std::make_pair(ControlType::Sinusoidal, ControlMode::Voltage); - case UnifiedModelMode::FocVoltage: return std::make_pair(ControlType::FieldOrientedControl, ControlMode::Voltage); - case UnifiedModelMode::FocSpeed: return std::make_pair(ControlType::FieldOrientedControl, ControlMode::Speed); - case UnifiedModelMode::FocTorque: return std::make_pair(ControlType::FieldOrientedControl, ControlMode::Torque); - } - - //Serial.printf("Unknown UnifiedModelMode: %i\r\n", int(mode)); - - return std::make_pair(ControlType::FieldOrientedControl, ControlMode::OpenMode); -} -} +std::pair split(UnifiedModelMode mode); diff --git a/main/utils.cpp b/main/utils.cpp index e69de29..b148e7a 100644 --- a/main/utils.cpp +++ b/main/utils.cpp @@ -0,0 +1,308 @@ +#include "utils.h" + +using namespace std::chrono_literals; + +bool currentlyReverseBeeping; +bool reverseBeepToggle; +espchrono::millis_clock::time_point lastReverseBeepToggle; + +float convertToKmh(float val) +{ + return val /* / settings.controllerHardware.numMagnetPoles */ / 60.f * settings.controllerHardware.wheelDiameter / 1000.f * 3.14159265359f * 3.6f; +} + +float convertFromKmh(float val) +{ + return val /* * settings.controllerHardware.numMagnetPoles */ * 60.f / settings.controllerHardware.wheelDiameter * 1000.f / 3.14159265359f / 3.6f; +} + +float convertToInch(float val) +{ + return val / 25.4f; +} + +float convertFromInch(float val) +{ + return val * 25.4f; +} + +float fixCurrent(int16_t value) +{ + return -value/50.; +} + +float fixBoardTemp(int16_t value) +{ + return value/10.; +} + +std::string hallString(const bobbycar::protocol::serial::MotorFeedback &motor) +{ + return std::string{} + (motor.hallA ? '1' : '0') + (motor.hallB ? '1' : '0') + (motor.hallC ? '1' : '0'); +} + +std::string to_string(bobbycar::protocol::ControlType value) +{ + switch (value) + { + using namespace bobbycar::protocol; + case ControlType::Commutation: return "Commutation"; + case ControlType::Sinusoidal: return "Sinusoidal"; + case ControlType::FieldOrientedControl: return "FieldOrientedControl"; + } + return fmt::format("Unknown ControlType({})", std::to_underlying(value)); +} + +std::string to_string(bobbycar::protocol::ControlMode value) +{ + switch (value) + { + using namespace bobbycar::protocol; + case ControlMode::OpenMode: return "OpenMode"; + case ControlMode::Voltage: return "Voltage"; + case ControlMode::Speed: return "Speed"; + case ControlMode::Torque: return "Torque"; + } + return fmt::format("Unknown ControlMode({})", std::to_underlying(value)); +} + +std::array, 2> motorsInController(Controller &controller) +{ + return {std::ref(controller.command.left), std::ref(controller.command.right)}; +} + +std::array, 2> motorsInController(const Controller &controller) +{ + return {std::ref(controller.command.left), std::ref(controller.command.right)}; +} + +std::array, 2> motorFeedbacksInController(Controller &controller) +{ + return {std::ref(controller.feedback.left), std::ref(controller.feedback.right)}; +} + +std::array, 2> motorFeedbacksInController(const Controller &controller) +{ + return {std::ref(controller.feedback.left), std::ref(controller.feedback.right)}; +} + +std::array, 4> motors() +{ + return { + std::ref(controllers.front.command.left), std::ref(controllers.front.command.right), + std::ref(controllers.back.command.left), std::ref(controllers.back.command.right) + }; +} + +void fixCommonParams() +{ + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + motor.iMotMax = settings.limits.iMotMax; + motor.iDcMax = settings.limits.iDcMax; + motor.nMotMax = settings.limits.nMotMax; + motor.fieldWeakMax = settings.limits.fieldWeakMax; + motor.phaseAdvMax = settings.limits.phaseAdvMax; + } + + if (settings.buzzer.reverseBeep) + { + const auto x = motors(); + const auto shouldBeep = std::all_of(std::begin(x), std::end(x), [](const bobbycar::protocol::serial::MotorState &motor){ return motor.pwm < 0; }); + + if (shouldBeep != currentlyReverseBeeping) + { + if (shouldBeep) + { + reverseBeepToggle = true; + lastReverseBeepToggle = espchrono::millis_clock::now(); + for (auto &controller : controllers) + controller.command.buzzer = {.freq=settings.buzzer.reverseBeepFreq0, .pattern=0}; + } + else + for (auto &controller : controllers) + controller.command.buzzer = {}; + + currentlyReverseBeeping = shouldBeep; + } + else if (shouldBeep && espchrono::millis_clock::now() - lastReverseBeepToggle >= std::chrono::milliseconds{reverseBeepToggle?settings.buzzer.reverseBeepDuration0:settings.buzzer.reverseBeepDuration1}) + { + reverseBeepToggle = !reverseBeepToggle; + + for (auto &controller : controllers) + controller.command.buzzer = {.freq=uint8_t(reverseBeepToggle?settings.buzzer.reverseBeepFreq0:settings.buzzer.reverseBeepFreq1), .pattern=0}; + + lastReverseBeepToggle = espchrono::millis_clock::now(); + } + } + else if (currentlyReverseBeeping) + { + for (auto &controller : controllers) + controller.command.buzzer = {}; + currentlyReverseBeeping = false; + } + + controllers.front.command.left.enable = settings.controllerHardware.enableFrontLeft; + controllers.front.command.right.enable = settings.controllerHardware.enableFrontRight; + controllers.back.command.left.enable = settings.controllerHardware.enableBackLeft; + controllers.back.command.right.enable = settings.controllerHardware.enableBackRight; + + if (settings.controllerHardware.invertFrontLeft) + { + controllers.front.command.left.pwm = -controllers.front.command.left.pwm; + controllers.front.command.left.nCruiseMotTgt = -controllers.front.command.left.nCruiseMotTgt; + } + if (settings.controllerHardware.invertFrontRight) + { + controllers.front.command.right.pwm = -controllers.front.command.right.pwm; + controllers.front.command.right.nCruiseMotTgt = -controllers.front.command.right.nCruiseMotTgt; + } + if (settings.controllerHardware.invertBackLeft) + { + controllers.back.command.left.pwm = -controllers.back.command.left.pwm; + controllers.back.command.left.nCruiseMotTgt = -controllers.back.command.left.nCruiseMotTgt; + } + if (settings.controllerHardware.invertBackRight) + { + controllers.back.command.right.pwm = -controllers.back.command.right.pwm; + controllers.back.command.right.nCruiseMotTgt = -controllers.back.command.right.nCruiseMotTgt; + } +} + +void sendCommands() +{ +#ifdef FEATURE_SERIAL + using namespace bobbycar::protocol::serial; + for (Controller &controller : controllers) + { + controller.command.start = Command::VALID_HEADER; + controller.command.checksum = calculateChecksum(controller.command); + controller.serial.get().write((uint8_t *) &controller.command, sizeof(controller.command)); + } +#endif +#ifdef FEATURE_CAN + can::sendCanCommands(); +#endif +} + +#ifdef FEATURE_SERIAL +void updateSwapFrontBack() +{ + controllers.front.serial = settings.controllerHardware.swapFrontBack ? Serial2 : Serial1; + controllers.back.serial = settings.controllerHardware.swapFrontBack ? Serial1 : Serial2; +} +#endif + +bool loadSettings() +{ + bool result{true}; + if (!settingsPersister.load(settings)) + result = false; + if (!settingsPersister.load(stringSettings)) + result = false; + return result; +} + +bool saveSettings() +{ + if (simplified) return true; + bool result{true}; + if (!settingsPersister.save(settings)) + result = false; + if (!settingsPersister.save(stringSettings)) + result = false; + return result; +} + +void updateAccumulators() +{ + avgSpeed = 0.f; + sumCurrent = 0.f; + uint8_t count{0}; + + for (const Controller &controller : controllers) + { + if (!controller.feedbackValid) + continue; + + avgSpeed += + controller.feedback.left.speed * (controller.invertLeft ? -1 : 1) + + controller.feedback.right.speed * (controller.invertRight ? -1 : 1); + + sumCurrent += + controller.feedback.left.dcLink + + controller.feedback.right.dcLink; + + count +=2; + } + + if (count) + avgSpeed /= count; + + sumCurrent = fixCurrent(sumCurrent); + + avgSpeedKmh = convertToKmh(avgSpeed); +} + +void readPotis() +{ + [[maybe_unused]] + constexpr auto sampleMultipleTimes = [](int pin){ + analogRead(pin); + double sum{}; + const auto sampleCount = settings.boardcomputerHardware.sampleCount; + for (int i = 0; i < sampleCount; i++) + sum += analogRead(pin); + return sum / sampleCount; + }; + + raw_gas = std::nullopt; + raw_brems = std::nullopt; + +#ifdef FEATURE_CAN + const auto now = espchrono::millis_clock::now(); + + if (can::can_gas) + { + if (now - can::last_can_gas < 100ms) + raw_gas = *can::can_gas; + else + can::can_gas = std::nullopt; + } + + if (can::can_brems) + { + if (now - can::last_can_brems < 100ms) + raw_brems = *can::can_brems; + else + can::can_brems = std::nullopt; + } +#endif + +#ifdef FEATURE_ADC_IN + if (!raw_gas) + raw_gas = sampleMultipleTimes(PINS_GAS); + if (!raw_brems) + raw_brems = sampleMultipleTimes(PINS_BREMS); +#endif + + if (raw_gas) + gas = cpputils::mapValueClamped(*raw_gas, settings.boardcomputerHardware.gasMin, settings.boardcomputerHardware.gasMax, 0., 1000.); + else + gas = std::nullopt; + if (raw_brems) + brems = cpputils::mapValueClamped(*raw_brems, settings.boardcomputerHardware.bremsMin, settings.boardcomputerHardware.bremsMax, 0., 1000.); + else + brems = std::nullopt; + +#ifdef FEATURE_GAMETRAK + raw_gametrakX = sampleMultipleTimes(PINS_GAMETRAKX); + gametrakX = cpputils::mapValueClamped(raw_gametrakX, settings.boardcomputerHardware.gametrakXMin, settings.boardcomputerHardware.gametrakXMax, 0., 1000.); + + raw_gametrakY = sampleMultipleTimes(PINS_GAMETRAKY); + gametrakY = cpputils::mapValueClamped(raw_gametrakY, settings.boardcomputerHardware.gametrakYMin, settings.boardcomputerHardware.gametrakYMax, 0., 1000.); + + raw_gametrakDist = sampleMultipleTimes(PINS_GAMETRAKDIST); + gametrakDist = cpputils::mapValueClamped(raw_gametrakDist, settings.boardcomputerHardware.gametrakDistMin, settings.boardcomputerHardware.gametrakDistMax, 0., 1000.); +#endif +} diff --git a/main/utils.h b/main/utils.h index d65f413..fe15667 100644 --- a/main/utils.h +++ b/main/utils.h @@ -29,309 +29,30 @@ #include "can.h" #endif -namespace { -bool currentlyReverseBeeping; -bool reverseBeepToggle; -espchrono::millis_clock::time_point lastReverseBeepToggle; +extern bool currentlyReverseBeeping; +extern bool reverseBeepToggle; +extern espchrono::millis_clock::time_point lastReverseBeepToggle; -float convertToKmh(float val) -{ - return val /* / settings.controllerHardware.numMagnetPoles */ / 60.f * settings.controllerHardware.wheelDiameter / 1000.f * 3.14159265359f * 3.6f; -} - -float convertFromKmh(float val) -{ - return val /* * settings.controllerHardware.numMagnetPoles */ * 60.f / settings.controllerHardware.wheelDiameter * 1000.f / 3.14159265359f / 3.6f; -} - -float convertToInch(float val) -{ - return val / 25.4f; -} - -float convertFromInch(float val) -{ - return val * 25.4f; -} - -float fixCurrent(int16_t value) -{ - return -value/50.; -} - -float fixBoardTemp(int16_t value) -{ - return value/10.; -} - -std::string hallString(const bobbycar::protocol::serial::MotorFeedback &motor) -{ - return std::string{} + (motor.hallA ? '1' : '0') + (motor.hallB ? '1' : '0') + (motor.hallC ? '1' : '0'); -} - -std::string to_string(bobbycar::protocol::ControlType value) -{ - switch (value) - { - using namespace bobbycar::protocol; - case ControlType::Commutation: return "Commutation"; - case ControlType::Sinusoidal: return "Sinusoidal"; - case ControlType::FieldOrientedControl: return "FieldOrientedControl"; - } - return fmt::format("Unknown ControlType({})", std::to_underlying(value)); -} - -std::string to_string(bobbycar::protocol::ControlMode value) -{ - switch (value) - { - using namespace bobbycar::protocol; - case ControlMode::OpenMode: return "OpenMode"; - case ControlMode::Voltage: return "Voltage"; - case ControlMode::Speed: return "Speed"; - case ControlMode::Torque: return "Torque"; - } - return fmt::format("Unknown ControlMode({})", std::to_underlying(value)); -} - -std::array, 2> motorsInController(Controller &controller) -{ - return {std::ref(controller.command.left), std::ref(controller.command.right)}; -} - -std::array, 2> motorsInController(const Controller &controller) -{ - return {std::ref(controller.command.left), std::ref(controller.command.right)}; -} - -std::array, 2> motorFeedbacksInController(Controller &controller) -{ - return {std::ref(controller.feedback.left), std::ref(controller.feedback.right)}; -} - -std::array, 2> motorFeedbacksInController(const Controller &controller) -{ - return {std::ref(controller.feedback.left), std::ref(controller.feedback.right)}; -} - -std::array, 4> motors() -{ - return { - std::ref(controllers.front.command.left), std::ref(controllers.front.command.right), - std::ref(controllers.back.command.left), std::ref(controllers.back.command.right) - }; -} - -void fixCommonParams() -{ - for (bobbycar::protocol::serial::MotorState &motor : motors()) - { - motor.iMotMax = settings.limits.iMotMax; - motor.iDcMax = settings.limits.iDcMax; - motor.nMotMax = settings.limits.nMotMax; - motor.fieldWeakMax = settings.limits.fieldWeakMax; - motor.phaseAdvMax = settings.limits.phaseAdvMax; - } - - if (settings.buzzer.reverseBeep) - { - const auto x = motors(); - const auto shouldBeep = std::all_of(std::begin(x), std::end(x), [](const bobbycar::protocol::serial::MotorState &motor){ return motor.pwm < 0; }); - - if (shouldBeep != currentlyReverseBeeping) - { - if (shouldBeep) - { - reverseBeepToggle = true; - lastReverseBeepToggle = espchrono::millis_clock::now(); - for (auto &controller : controllers) - controller.command.buzzer = {.freq=settings.buzzer.reverseBeepFreq0, .pattern=0}; - } - else - for (auto &controller : controllers) - controller.command.buzzer = {}; - - currentlyReverseBeeping = shouldBeep; - } - else if (shouldBeep && espchrono::millis_clock::now() - lastReverseBeepToggle >= std::chrono::milliseconds{reverseBeepToggle?settings.buzzer.reverseBeepDuration0:settings.buzzer.reverseBeepDuration1}) - { - reverseBeepToggle = !reverseBeepToggle; - - for (auto &controller : controllers) - controller.command.buzzer = {.freq=uint8_t(reverseBeepToggle?settings.buzzer.reverseBeepFreq0:settings.buzzer.reverseBeepFreq1), .pattern=0}; - - lastReverseBeepToggle = espchrono::millis_clock::now(); - } - } - else if (currentlyReverseBeeping) - { - for (auto &controller : controllers) - controller.command.buzzer = {}; - currentlyReverseBeeping = false; - } - - controllers.front.command.left.enable = settings.controllerHardware.enableFrontLeft; - controllers.front.command.right.enable = settings.controllerHardware.enableFrontRight; - controllers.back.command.left.enable = settings.controllerHardware.enableBackLeft; - controllers.back.command.right.enable = settings.controllerHardware.enableBackRight; - - if (settings.controllerHardware.invertFrontLeft) - { - controllers.front.command.left.pwm = -controllers.front.command.left.pwm; - controllers.front.command.left.nCruiseMotTgt = -controllers.front.command.left.nCruiseMotTgt; - } - if (settings.controllerHardware.invertFrontRight) - { - controllers.front.command.right.pwm = -controllers.front.command.right.pwm; - controllers.front.command.right.nCruiseMotTgt = -controllers.front.command.right.nCruiseMotTgt; - } - if (settings.controllerHardware.invertBackLeft) - { - controllers.back.command.left.pwm = -controllers.back.command.left.pwm; - controllers.back.command.left.nCruiseMotTgt = -controllers.back.command.left.nCruiseMotTgt; - } - if (settings.controllerHardware.invertBackRight) - { - controllers.back.command.right.pwm = -controllers.back.command.right.pwm; - controllers.back.command.right.nCruiseMotTgt = -controllers.back.command.right.nCruiseMotTgt; - } -} - -void sendCommands() -{ +float convertToKmh(float val); +float convertFromKmh(float val); +float convertToInch(float val); +float convertFromInch(float val); +float fixCurrent(int16_t value); +float fixBoardTemp(int16_t value); +std::string hallString(const bobbycar::protocol::serial::MotorFeedback &motor); +std::string to_string(bobbycar::protocol::ControlType value); +std::string to_string(bobbycar::protocol::ControlMode value); +std::array, 2> motorsInController(Controller &controller); +std::array, 2> motorsInController(const Controller &controller); +std::array, 2> motorFeedbacksInController(Controller &controller); +std::array, 2> motorFeedbacksInController(const Controller &controller); +std::array, 4> motors(); +void fixCommonParams(); +void sendCommands(); #ifdef FEATURE_SERIAL - using namespace bobbycar::protocol::serial; - for (Controller &controller : controllers) - { - controller.command.start = Command::VALID_HEADER; - controller.command.checksum = calculateChecksum(controller.command); - controller.serial.get().write((uint8_t *) &controller.command, sizeof(controller.command)); - } +void updateSwapFrontBack(); #endif -#ifdef FEATURE_CAN - can::sendCanCommands(); -#endif -} - -#ifdef FEATURE_SERIAL -void updateSwapFrontBack() -{ - controllers.front.serial = settings.controllerHardware.swapFrontBack ? Serial2 : Serial1; - controllers.back.serial = settings.controllerHardware.swapFrontBack ? Serial1 : Serial2; -} -#endif - -bool loadSettings() -{ - bool result{true}; - if (!settingsPersister.load(settings)) - result = false; - if (!settingsPersister.load(stringSettings)) - result = false; - return result; -} - -bool saveSettings() -{ - if (simplified) return true; - bool result{true}; - if (!settingsPersister.save(settings)) - result = false; - if (!settingsPersister.save(stringSettings)) - result = false; - return result; -} - -void updateAccumulators() -{ - avgSpeed = 0.f; - sumCurrent = 0.f; - uint8_t count{0}; - - for (const Controller &controller : controllers) - { - if (!controller.feedbackValid) - continue; - - avgSpeed += - controller.feedback.left.speed * (controller.invertLeft ? -1 : 1) + - controller.feedback.right.speed * (controller.invertRight ? -1 : 1); - - sumCurrent += - controller.feedback.left.dcLink + - controller.feedback.right.dcLink; - - count +=2; - } - - if (count) - avgSpeed /= count; - - sumCurrent = fixCurrent(sumCurrent); - - avgSpeedKmh = convertToKmh(avgSpeed); -} - -void readPotis() -{ - [[maybe_unused]] - constexpr auto sampleMultipleTimes = [](int pin){ - analogRead(pin); - double sum{}; - const auto sampleCount = settings.boardcomputerHardware.sampleCount; - for (int i = 0; i < sampleCount; i++) - sum += analogRead(pin); - return sum / sampleCount; - }; - - raw_gas = std::nullopt; - raw_brems = std::nullopt; - -#ifdef FEATURE_CAN - const auto now = espchrono::millis_clock::now(); - - if (can::can_gas) - { - if (now - can::last_can_gas < 100ms) - raw_gas = *can::can_gas; - else - can::can_gas = std::nullopt; - } - - if (can::can_brems) - { - if (now - can::last_can_brems < 100ms) - raw_brems = *can::can_brems; - else - can::can_brems = std::nullopt; - } -#endif - -#ifdef FEATURE_ADC_IN - if (!raw_gas) - raw_gas = sampleMultipleTimes(PINS_GAS); - if (!raw_brems) - raw_brems = sampleMultipleTimes(PINS_BREMS); -#endif - - if (raw_gas) - gas = cpputils::mapValueClamped(*raw_gas, settings.boardcomputerHardware.gasMin, settings.boardcomputerHardware.gasMax, 0., 1000.); - else - gas = std::nullopt; - if (raw_brems) - brems = cpputils::mapValueClamped(*raw_brems, settings.boardcomputerHardware.bremsMin, settings.boardcomputerHardware.bremsMax, 0., 1000.); - else - brems = std::nullopt; - -#ifdef FEATURE_GAMETRAK - raw_gametrakX = sampleMultipleTimes(PINS_GAMETRAKX); - gametrakX = cpputils::mapValueClamped(raw_gametrakX, settings.boardcomputerHardware.gametrakXMin, settings.boardcomputerHardware.gametrakXMax, 0., 1000.); - - raw_gametrakY = sampleMultipleTimes(PINS_GAMETRAKY); - gametrakY = cpputils::mapValueClamped(raw_gametrakY, settings.boardcomputerHardware.gametrakYMin, settings.boardcomputerHardware.gametrakYMax, 0., 1000.); - - raw_gametrakDist = sampleMultipleTimes(PINS_GAMETRAKDIST); - gametrakDist = cpputils::mapValueClamped(raw_gametrakDist, settings.boardcomputerHardware.gametrakDistMin, settings.boardcomputerHardware.gametrakDistMax, 0., 1000.); -#endif -} -} +bool loadSettings(); +bool saveSettings(); +void updateAccumulators(); +void readPotis(); diff --git a/main/wifi_bobbycar.cpp b/main/wifi_bobbycar.cpp index e69de29..54d67bb 100644 --- a/main/wifi_bobbycar.cpp +++ b/main/wifi_bobbycar.cpp @@ -0,0 +1,99 @@ +#include "wifi_bobbycar.h" + +// system includes +#include + +// esp-idf includes +#include + +// 3rdparty lib includes +#include + +// local includes +#include "globals.h" + +namespace { +wifi_stack::config wifi_create_config(); +std::optional wifi_create_sta_config(); +std::optional wifi_create_ap_config(); +} + +void wifi_begin() +{ + wifi_stack::init(wifi_create_config()); +} + +void wifi_update() +{ + wifi_stack::update(wifi_create_config()); +} + +esp_err_t wifi_scan() +{ + const auto &sta_config = wifi_create_sta_config(); + if (!sta_config) + { + ESP_LOGE("BOBBY", "no sta enabled"); + return ESP_FAIL; + } + + if (const auto result = wifi_stack::begin_scan(*sta_config); !result) + { + ESP_LOGE("BOBBY", "begin_scan() failed with %.*s", result.error().size(), result.error().data()); + return ESP_FAIL; + } + + return ESP_OK; +} + +namespace { +wifi_stack::config wifi_create_config() +{ + return wifi_stack::config { + .sta = wifi_create_sta_config(), + .ap = wifi_create_ap_config() + }; +} + +std::optional wifi_create_sta_config() +{ + if (!settings.wifiSettings.wifiEnabled) + return std::nullopt; + + return wifi_stack::sta_config { + .hostname = deviceName, + .wifis = std::array { + wifi_stack::wifi_entry { .ssid = stringSettings.wifis[0].ssid, .key = stringSettings.wifis[0].key }, + wifi_stack::wifi_entry { .ssid = stringSettings.wifis[1].ssid, .key = stringSettings.wifis[1].key }, + wifi_stack::wifi_entry { .ssid = stringSettings.wifis[2].ssid, .key = stringSettings.wifis[2].key }, + wifi_stack::wifi_entry { .ssid = stringSettings.wifis[3].ssid, .key = stringSettings.wifis[3].key }, + wifi_stack::wifi_entry { .ssid = stringSettings.wifis[4].ssid, .key = stringSettings.wifis[4].key }, + wifi_stack::wifi_entry { .ssid = stringSettings.wifis[5].ssid, .key = stringSettings.wifis[5].key }, + wifi_stack::wifi_entry { .ssid = stringSettings.wifis[6].ssid, .key = stringSettings.wifis[6].key }, + wifi_stack::wifi_entry { .ssid = stringSettings.wifis[7].ssid, .key = stringSettings.wifis[7].key }, + wifi_stack::wifi_entry { .ssid = stringSettings.wifis[8].ssid, .key = stringSettings.wifis[8].key }, + wifi_stack::wifi_entry { .ssid = stringSettings.wifis[9].ssid, .key = stringSettings.wifis[9].key } + }, + .min_rssi = -90 + }; +} + +std::optional wifi_create_ap_config() +{ + return wifi_stack::ap_config { + .hostname = deviceName, + .ssid = deviceName, + .key = STRING(AP_PASSWORD), + .static_ip = { + .ip = {10, 0, 0, 1}, + .subnet = {255, 255, 255, 0}, + .gateway = {10, 0, 0, 1}, + }, + .channel = 1, + .authmode = WIFI_AUTH_WPA2_PSK, + .ssid_hidden = false, + .max_connection = 4, + .beacon_interval = 100 + }; +} +} // namespace diff --git a/main/wifi_bobbycar.h b/main/wifi_bobbycar.h index d2a2860..c754338 100644 --- a/main/wifi_bobbycar.h +++ b/main/wifi_bobbycar.h @@ -1,70 +1,10 @@ #pragma once // esp-idf includes -#include +#include -// 3rdparty lib includes -#include +void wifi_begin(); -// local includes -#include "globals.h" +void wifi_update(); -namespace { -wifi_stack::config wifi_create_config() -{ - return wifi_stack::config { - .hostname = deviceName, - .sta = { - .enabled = settings.wifiSettings.wifiEnabled, - .wifis = std::array { - wifi_stack::wifi_entry { .ssid = stringSettings.wifis[0].ssid, .key = stringSettings.wifis[0].key }, - wifi_stack::wifi_entry { .ssid = stringSettings.wifis[1].ssid, .key = stringSettings.wifis[1].key }, - wifi_stack::wifi_entry { .ssid = stringSettings.wifis[2].ssid, .key = stringSettings.wifis[2].key }, - wifi_stack::wifi_entry { .ssid = stringSettings.wifis[3].ssid, .key = stringSettings.wifis[3].key }, - wifi_stack::wifi_entry { .ssid = stringSettings.wifis[4].ssid, .key = stringSettings.wifis[4].key }, - wifi_stack::wifi_entry { .ssid = stringSettings.wifis[5].ssid, .key = stringSettings.wifis[5].key }, - wifi_stack::wifi_entry { .ssid = stringSettings.wifis[6].ssid, .key = stringSettings.wifis[6].key }, - wifi_stack::wifi_entry { .ssid = stringSettings.wifis[7].ssid, .key = stringSettings.wifis[7].key }, - wifi_stack::wifi_entry { .ssid = stringSettings.wifis[8].ssid, .key = stringSettings.wifis[8].key }, - wifi_stack::wifi_entry { .ssid = stringSettings.wifis[9].ssid, .key = stringSettings.wifis[9].key } - }, - .min_rssi = -90 - }, - .ap = { - .ssid = deviceName, - .key = STRING(AP_PASSWORD), - .static_ip = { - .ip = {10, 0, 0, 1}, - .subnet = {255, 255, 255, 0}, - .gateway = {10, 0, 0, 1}, - }, - .channel = 1, - .authmode = WIFI_AUTH_WPA2_PSK, - .ssid_hidden = false, - .max_connection = 4, - .beacon_interval = 100 - } - }; -} - -void wifi_begin() -{ - wifi_stack::init(wifi_create_config()); -} - -void wifi_update() -{ - wifi_stack::update(wifi_create_config()); -} - -esp_err_t wifi_scan() -{ - if (const auto result = wifi_stack::begin_scan(wifi_create_config()); result != ESP_OK) - { - ESP_LOGE("BOBBY", "begin_scan() failed with %s", esp_err_to_name(result)); - return result; - } - - return ESP_OK; -} -} // namespace +esp_err_t wifi_scan();