diff --git a/platformio.ini b/platformio.ini index ab9feff..555e5b5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -63,10 +63,12 @@ build_flags = -DTFT_RST=2 -DSPI_FREQUENCY=27000000 -DDEFAULT_SWAPSCREENBYTES=false + -DFEATURE_SERIAL -DPINS_RX1=4 -DPINS_TX1=5 -DPINS_RX2=25 -DPINS_TX2=26 + -DFEATURE_ADC_IN -DFEATURE_MOSFETS -DPINS_MOSFET0=18 -DPINS_MOSFET1=19 @@ -96,16 +98,18 @@ platform = ${common_env_data.platform} board = ${common_env_data.board} framework = ${common_env_data.framework} platform_packages = ${common_env_data.platform_packages} -board_build.partitions = partitions_4M_ota.csv +board_build.partitions = partitions_16M_ota.csv lib_deps = ${common_env_data.lib_deps} - ${webserver_common.lib_deps} +; ${webserver_common.lib_deps} lib_compat_mode = ${common_env_data.lib_compat_mode} build_unflags = ${common_env_data.build_unflags} build_flags = ${common_env_data.build_flags} - -DPINS_GAS=33 + -DFEATURE_ADC_IN + -DPINS_GAS=34 -DPINS_BREMS=35 +; -DPINS_LED=23 -DILI9341_DRIVER=1 -DTFT_MOSI=13 -DTFT_SCLK=15 @@ -114,10 +118,12 @@ build_flags = -DTFT_RST=2 -DSPI_FREQUENCY=27000000 -DDEFAULT_SWAPSCREENBYTES=false - -DPINS_RX1=4 - -DPINS_TX1=5 - -DPINS_RX2=22 - -DPINS_TX2=23 + -DFEATURE_CAN +; -DFEATURE_SERIAL +; -DPINS_RX1=4 +; -DPINS_TX1=5 +; -DPINS_RX2=22 +; -DPINS_TX2=23 ${default_wheels_inverted.build_flags} -DDEFAULT_WHEELDIAMETER=255 ; -DFEATURE_MOSFETS @@ -127,30 +133,30 @@ build_flags = ${default_limits.build_flags} -DDEVICE_PREFIX=bobbyquad -DAP_PASSWORD=Passwort_123 - ${webserver_common.build_flags} +; ${webserver_common.build_flags} ; -DFEATURE_ARDUINOOTA ; -DFEATURE_WEBOTA -DFEATURE_DPAD_5WIRESW - -DPINS_DPAD_5WIRESW_OUT=32 - -DPINS_DPAD_5WIRESW_IN1=25 - -DPINS_DPAD_5WIRESW_IN2=26 - -DPINS_DPAD_5WIRESW_IN3=27 - -DPINS_DPAD_5WIRESW_IN4=21 - -DDPAD_5WIRESW_UP=4 + -DPINS_DPAD_5WIRESW_OUT=18 + -DPINS_DPAD_5WIRESW_IN1=19 + -DPINS_DPAD_5WIRESW_IN2=27 + -DPINS_DPAD_5WIRESW_IN3=32 + -DPINS_DPAD_5WIRESW_IN4=33 + -DDPAD_5WIRESW_UP=6 -DDPAD_5WIRESW_DOWN=3 -DDPAD_5WIRESW_CONFIRM=7 - -DDPAD_5WIRESW_BACK=0 + -DDPAD_5WIRESW_BACK=2 -DDPAD_5WIRESW_PROFILE0=1 -DDPAD_5WIRESW_PROFILE1=5 - -DDPAD_5WIRESW_PROFILE2=2 - -DDPAD_5WIRESW_PROFILE3=6 + -DDPAD_5WIRESW_PROFILE2=0 + -DDPAD_5WIRESW_PROFILE3=4 ; -DDPAD_5WIRESW_DEBUG - -DDEFAULT_GASMIN=750 - -DDEFAULT_GASMAX=3700 - -DDEFAULT_BREMSMIN=880 - -DDEFAULT_BREMSMAX=4000 -; -DFEATURE_BLUETOOTH -; -DFEATURE_BMS + -DDEFAULT_GASMIN=150 + -DDEFAULT_GASMAX=1300 + -DDEFAULT_BREMSMIN=200 + -DDEFAULT_BREMSMAX=1500 + -DFEATURE_BLUETOOTH + -DFEATURE_BMS ; -DFEATURE_GAMETRAK ; -DPINS_GAMETRAKX=34 ; -DPINS_GAMETRAKY=39 @@ -161,7 +167,7 @@ build_flags = ; -DDEFAULT_GAMETRAKYMAX=4095 ; -DDEFAULT_GAMETRAKDISTMIN=0 ; -DDEFAULT_GAMETRAKDISTMAX=4095 - -DFEATURE_CLOUD +; -DFEATURE_CLOUD [env:feedc0de_usb] platform = ${feedc0de.platform} @@ -330,10 +336,12 @@ build_flags = ${default_wheels_inverted.build_flags} -DDEFAULT_WHEELDIAMETER=165 ; TODO: actually assign pins + -DFEATURE_SERIAL -DPINS_RX1=22 -DPINS_TX1=25 -DPINS_RX2=23 -DPINS_TX2=34 + -DFEATURE_ADC_IN -DPINS_GAS=35 -DPINS_BREMS=33 -DDEFAULT_GASMIN=0 @@ -409,6 +417,7 @@ lib_compat_mode = ${common_env_data.lib_compat_mode} build_unflags = ${common_env_data.build_unflags} build_flags = ${common_env_data.build_flags} + -DFEATURE_ADC_IN -DPINS_GAS=33 -DPINS_BREMS=35 -DILI9341_DRIVER=1 @@ -419,6 +428,7 @@ build_flags = -DTFT_RST=2 -DSPI_FREQUENCY=27000000 -DDEFAULT_SWAPSCREENBYTES=false + -DFEATURE_SERIAL -DPINS_RX1=4 -DPINS_TX1=5 -DPINS_RX2=25 diff --git a/src/actions/switchprofileaction.h b/src/actions/switchprofileaction.h index 797e4c2..26e6eb9 100644 --- a/src/actions/switchprofileaction.h +++ b/src/actions/switchprofileaction.h @@ -3,25 +3,16 @@ #include #include "actioninterface.h" -#include "globals.h" -#include "presets.h" +#include "settingsutils.h" namespace { -template +template class SwitchProfileAction : public virtual ActionInterface { public: void triggered() override { - settings = presets::defaultSettings; - - if (settingsPersister.openProfile(profile)) - { - if (!settingsPersister.load(settings)) - Serial.println("SwitchProfileAction::triggered() load failed"); - } - else - Serial.println("SwitchProfileAction::triggered() openProfile failed"); + switchProfile(index); } }; } diff --git a/src/actions/updateswapfrontbackaction.h b/src/actions/updateswapfrontbackaction.h index ac51e1a..f423d06 100644 --- a/src/actions/updateswapfrontbackaction.h +++ b/src/actions/updateswapfrontbackaction.h @@ -4,9 +4,11 @@ #include "utils.h" namespace { +#ifdef FEATURE_SERIAL class UpdateSwapFrontBackAction : public virtual ActionInterface { public: void triggered() override { updateSwapFrontBack(); } }; +#endif } diff --git a/src/bluetoothtexthelpers.h b/src/bluetoothtexthelpers.h index e869087..3f82122 100644 --- a/src/bluetoothtexthelpers.h +++ b/src/bluetoothtexthelpers.h @@ -19,21 +19,21 @@ using BluetoothHasClientText = BluetoothStatusTextHelper; struct BluetoothConnectedText : public virtual TextInterface { public: - String text() const override { return String{"connected: "} + toString(bluetoothSerial.connected()); } + std::string text() const override { return std::string{"connected: "} + to_string(bluetoothSerial.connected()); } }; //constexpr char TEXT_BLUETOOTHISREADY[] = "Is ready: "; //using BluetoothIsReadyText = BluetoothStatusTextHelper; struct BluetoothIsReadyText : public virtual TextInterface { public: - String text() const override { return String{"isReady: "} + toString(bluetoothSerial.isReady()); } + std::string text() const override { return std::string{"isReady: "} + to_string(bluetoothSerial.isReady()); } }; //constexpr char TEXT_BLUETOOTHISREADYMASTER[] = "Is ready (M): "; //using BluetoothIsReadyMasterText = BluetoothStatusTextHelper; class BluetoothIsReadyMasterText : public virtual TextInterface { public: - String text() const override { return String{"isReady (M): "} + toString(bluetoothSerial.isReady(true)); } + std::string text() const override { return std::string{"isReady (M): "} + to_string(bluetoothSerial.isReady(true)); } }; #endif } diff --git a/src/bobby_webserver.h b/src/bobby_webserver.h index addbbac..b3aba7c 100644 --- a/src/bobby_webserver.h +++ b/src/bobby_webserver.h @@ -10,6 +10,7 @@ #include "changevaluedisplay.h" #include "displays/updatedisplay.h" //#include "esputils.h" +#include "buttons.h" namespace { #ifdef FEATURE_WEBSERVER @@ -80,7 +81,7 @@ void initWebserver() if (const auto *textInterface = constCurrentDisplay->asTextInterface()) { HtmlTag h2Tag{"h2", response}; - response->print(textInterface->text()); + response->print(textInterface->text().c_str()); } if (const auto *menuDisplay = constCurrentDisplay->asMenuDisplay()) @@ -97,7 +98,7 @@ void initWebserver() response->print(">print(i); response->print("\">"); - response->print(menuItem.text()); + response->print(menuItem.text().c_str()); response->print(""); i++; @@ -106,7 +107,7 @@ void initWebserver() else if (const auto *changeValueDisplay = constCurrentDisplay->asChangeValueDisplayInterface()) { response->print("
"); - response->print("shownValue()} + "\" />"); + response->print(("shownValue()) + "\" />").c_str()); response->print(""); response->print("
"); } @@ -276,7 +277,7 @@ void initWebserver() if (!Update.begin(size, command)) Update.printError(Serial); - String type; + std::string type; if (ArduinoOTA.getCommand() == U_FLASH) type = "sketch"; else if (ArduinoOTA.getCommand() == U_SPIFFS) // U_SPIFFS diff --git a/src/bobbycar-protocol b/src/bobbycar-protocol index 39f76cb..2c6fb11 160000 --- a/src/bobbycar-protocol +++ b/src/bobbycar-protocol @@ -1 +1 @@ -Subproject commit 39f76cb62b32da2ea8d7a7154e1b2854dbf792ab +Subproject commit 2c6fb114f2ea6e3aed243acea1afd28ca34938c9 diff --git a/src/buttons.h b/src/buttons.h new file mode 100644 index 0000000..4e340e3 --- /dev/null +++ b/src/buttons.h @@ -0,0 +1,80 @@ +#pragma once + +// Arduino includes +#include + +// local includes +#include "types.h" +#include "settingsutils.h" + +namespace { + +int rotated{}; +bool requestFullRedraw{}; + +bool confirmButtonPressed{}; +bool confirmButtonLongPressed{}; +bool backButtonPressed{}; +bool backButtonLongPressed{}; + +class InputDispatcher +{ +public: + static void rotate(int offset) + { + rotated += offset; + } + + static void confirmButton(bool pressed) + { + static millis_t pressBegin = 0; + + const auto now = millis(); + + if (pressed) + pressBegin = now; + else + { + const auto duration = now - pressBegin; + + if (duration < 500) + confirmButtonPressed = true; + else if (duration < 2000) + confirmButtonLongPressed = true; + else + requestFullRedraw = true; + + pressBegin = 0; + } + } + + static void backButton(bool pressed) + { + static millis_t pressBegin = 0; + + const auto now = millis(); + + if (pressed) + pressBegin = now; + else + { + const auto duration = now - pressBegin; + + if (duration < 500) + backButtonPressed = true; + else + backButtonLongPressed = true; + + pressBegin = 0; + } + } + + static void profileButton(uint8_t index, bool pressed) + { + if (!pressed) + return; + + switchProfile(index); + } +}; +} diff --git a/src/can.h b/src/can.h new file mode 100644 index 0000000..dd1513f --- /dev/null +++ b/src/can.h @@ -0,0 +1,421 @@ +#pragma once + +#include +#include + +#include +#include + +#include + +#include "bobbycar-protocol/bobbycar-can.h" + +#include "types.h" +#include "globals.h" +#include "buttons.h" + +namespace can { +namespace { +std::optional can_gas, can_brems; +millis_t last_can_gas{}, last_can_brems{}; + +struct CanButtonsState +{ + bool up{}; + bool down{}; + bool confirm{}; + bool back{}; + bool profile0{}; + bool profile1{}; + bool profile2{}; + bool profile3{}; +}; +CanButtonsState lastButtonsState; + +void initCan() +{ + Serial.println("initCan()"); + + can_general_config_t g_config = CAN_GENERAL_CONFIG_DEFAULT(GPIO_NUM_21, GPIO_NUM_22, CAN_MODE_NORMAL); + can_timing_config_t t_config CAN_TIMING_CONFIG_250KBITS(); + can_filter_config_t f_config CAN_FILTER_CONFIG_ACCEPT_ALL(); +// { +// // +// .acceptance_code = 0b00000000000, +// .acceptance_mask = 0b00001111111, +// .single_filter = true +// }; + + if (const auto result = can_driver_install(&g_config, &t_config, &f_config); result == ESP_OK) + { + Serial.printf("CAN info can_driver_install() succeeded\r\n"); + } + else + { + Serial.printf("CAN err can_driver_install() failed with %s\r\n", esp_err_to_name(result)); + return; + } + + if (const auto result = can_start(); result == ESP_OK) + { + Serial.printf("CAN info can_start() succeeded\r\n"); + } + else + { + Serial.printf("CAN err can_start() failed with %s\r\n", esp_err_to_name(result)); + + if (const auto result = can_driver_uninstall(); result == ESP_OK) + { + Serial.printf("CAN info can_driver_uninstall() succeeded\r\n"); + } + else + { + Serial.printf("CAN err can_driver_uninstall() failed with %s\r\n", esp_err_to_name(result)); + } + + return; + } +} + +template +bool parseMotorControllerCanMessage(const can_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 can_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) + if (newState.up) + InputDispatcher::rotate(-1); + + if (lastButtonsState.down != newState.down) + if (newState.down) + InputDispatcher::rotate(1); + + 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 = millis(); + break; + case Boardcomputer::Command::RawBrems: + can_brems = *((int16_t*)message.data); + last_can_brems = millis(); + break; + } + + return false; +} + +bool tryParseCanInput() +{ + can_message_t message; + if (const auto result = can_receive(&message, pdMS_TO_TICKS(50)); result != ESP_OK) + { + if (millis() - controllers.front.lastCanFeedback > 100) + controllers.front.feedbackValid = false; + + if (millis() - controllers.back.lastCanFeedback > 100) + controllers.back.feedbackValid = false; + + if (result != ESP_ERR_TIMEOUT) + Serial.printf("CAN err can_receive() failed with %s\r\n", esp_err_to_name(result)); + + 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 (millis() - back.lastCanFeedback > 100) + back.feedbackValid = false; + + front.lastCanFeedback = millis(); + front.feedbackValid = true; + return true; + } + else + { + if (millis() - front.lastCanFeedback > 100) + front.feedbackValid = false; + } + + if (parseMotorControllerCanMessage(message, back)) + { + back.lastCanFeedback = millis(); + back.feedbackValid = true; + return true; + } + else + { + if (millis() - back.lastCanFeedback > 100) + back.feedbackValid = false; + } + + if (parseBoardcomputerCanMessage(message)) + return true; + + //Serial.printf("WARNING Unknown CAN info received .identifier = %u\r\n", 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){ + can_message_t message; + message.identifier = addr; + message.flags = CAN_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 result = can_transmit(&message, pdMS_TO_TICKS(200)); + if (result != ESP_OK && result != ESP_ERR_TIMEOUT) + Serial.printf("ERROR: can_transmit() failed with %s\r\n", esp_err_to_name(result)); + return result; + }; + + const Controller &front = settings.controllerHardware.swapFrontBack ? controllers.back : controllers.front; + const Controller &back = settings.controllerHardware.swapFrontBack ? controllers.front : controllers.back; + + using namespace bobbycar::protocol::can; + + send(MotorController::Command::InpTgt, front.command.left.pwm); + send(MotorController::Command::InpTgt, front.command.right.pwm); + send(MotorController::Command::InpTgt, back.command.left.pwm); + 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.command.buzzer.freq != lastValues.front.freq || + front.command.buzzer.pattern != lastValues.front.pattern || + back.command.buzzer.freq != lastValues.back.freq || + back.command.buzzer.pattern != lastValues.back.pattern) + i = 8; + else if (buttonLeds != lastValues.buttonLeds) + i = 10; + + switch (i++) + { + case 0: + send(MotorController::Command::Enable, front.command.left.enable); + send(MotorController::Command::Enable, front.command.right.enable); + send(MotorController::Command::Enable, back.command.left.enable); + send(MotorController::Command::Enable, back.command.right.enable); + break; + case 1: + send(MotorController::Command::CtrlTyp, front.command.left.ctrlTyp); + send(MotorController::Command::CtrlTyp, front.command.right.ctrlTyp); + send(MotorController::Command::CtrlTyp, back.command.left.ctrlTyp); + send(MotorController::Command::CtrlTyp, back.command.right.ctrlTyp); + break; + case 2: + send(MotorController::Command::CtrlMod, front.command.left.ctrlMod); + send(MotorController::Command::CtrlMod, front.command.right.ctrlMod); + send(MotorController::Command::CtrlMod, back.command.left.ctrlMod); + send(MotorController::Command::CtrlMod, back.command.right.ctrlMod); + break; + case 3: + send(MotorController::Command::IMotMax, front.command.left.iMotMax); + send(MotorController::Command::IMotMax, front.command.right.iMotMax); + send(MotorController::Command::IMotMax, back.command.left.iMotMax); + send(MotorController::Command::IMotMax, back.command.right.iMotMax); + break; + case 4: + send(MotorController::Command::IDcMax, front.command.left.iDcMax); + send(MotorController::Command::IDcMax, front.command.right.iDcMax); + send(MotorController::Command::IDcMax, back.command.left.iDcMax); + send(MotorController::Command::IDcMax, back.command.right.iDcMax); + break; + case 5: + send(MotorController::Command::NMotMax, front.command.left.nMotMax); + send(MotorController::Command::NMotMax, front.command.right.nMotMax); + send(MotorController::Command::NMotMax, back.command.left.nMotMax); + send(MotorController::Command::NMotMax, back.command.right.nMotMax); + break; + case 6: + send(MotorController::Command::FieldWeakMax, front.command.left.fieldWeakMax); + send(MotorController::Command::FieldWeakMax, front.command.right.fieldWeakMax); + send(MotorController::Command::FieldWeakMax, back.command.left.fieldWeakMax); + send(MotorController::Command::FieldWeakMax, back.command.right.fieldWeakMax); + break; + case 7: + send(MotorController::Command::PhaseAdvMax, front.command.left.phaseAdvMax); + send(MotorController::Command::PhaseAdvMax, front.command.right.phaseAdvMax); + send(MotorController::Command::PhaseAdvMax, back.command.left.phaseAdvMax); + send(MotorController::Command::PhaseAdvMax, back.command.right.phaseAdvMax); + break; + case 8: + if (send(MotorController::Command::BuzzerFreq, front.command.buzzer.freq) == ESP_OK) + lastValues.front.freq = front.command.buzzer.freq; +// if (send(MotorController::Command::BuzzerFreq, front.command.buzzer.freq) == ESP_OK) +// lastValues.front.freq = front.command.buzzer.freq; + if (send(MotorController::Command::BuzzerFreq, back.command.buzzer.freq) == ESP_OK) + lastValues.back.freq = back.command.buzzer.freq; +// if (send(MotorController::Command::BuzzerFreq, back.command.buzzer.freq) == ESP_OK) +// lastValues.back.freq = back.command.buzzer.freq; + if (send(MotorController::Command::BuzzerPattern, front.command.buzzer.pattern) == ESP_OK) + lastValues.front.pattern = front.command.buzzer.pattern; +// if (send(MotorController::Command::BuzzerPattern, front.command.buzzer.pattern) == ESP_OK) +// lastValues.front.pattern = front.command.buzzer.pattern; + if (send(MotorController::Command::BuzzerPattern, back.command.buzzer.pattern) == ESP_OK) + lastValues.back.pattern = back.command.buzzer.pattern; +// if (send(MotorController::Command::BuzzerPattern, back.command.buzzer.pattern) == ESP_OK) +// lastValues.back.pattern = back.command.buzzer.pattern; + break; + case 9: + send(MotorController::Command::Led, front.command.led); + //send(MotorController::Command::Led, front.command.led); + send(MotorController::Command::Led, back.command.led); + //send(MotorController::Command::Led, back.command.led); + send(MotorController::Command::Poweroff, front.command.poweroff); + //send(MotorController::Command::Poweroff, front.command.poweroff); + send(MotorController::Command::Poweroff, back.command.poweroff); + //send(MotorController::Command::Poweroff, back.command.poweroff); + break; + case 10: + if (send(Boardcomputer::Feedback::ButtonLeds, buttonLeds) == ESP_OK) + lastValues.buttonLeds = buttonLeds; + default: + i=0; + break; + } +} +} // namespace +} // namespace can diff --git a/src/changevaluedisplay.h b/src/changevaluedisplay.h index 9c42589..45f87e7 100644 --- a/src/changevaluedisplay.h +++ b/src/changevaluedisplay.h @@ -119,7 +119,7 @@ void ChangeValueDisplay::redraw() tft.setTextColor(TFT_WHITE, TFT_BLACK); tft.setTextFont(7); - m_valueLabel.redraw(String{m_value}); + m_valueLabel.redraw(std::to_string(m_value)); } template diff --git a/src/changevaluedisplay_controlmode.h b/src/changevaluedisplay_controlmode.h index 6176fdc..3c36d3a 100644 --- a/src/changevaluedisplay_controlmode.h +++ b/src/changevaluedisplay_controlmode.h @@ -10,9 +10,9 @@ namespace { template<> -class ChangeValueDisplay : +class ChangeValueDisplay : public MenuDisplay, - public virtual AccessorInterface, + public virtual AccessorInterface, public virtual ActionInterface { using Base = MenuDisplay; @@ -23,8 +23,9 @@ public: void start() override; }; -ChangeValueDisplay::ChangeValueDisplay() +ChangeValueDisplay::ChangeValueDisplay() { + using bobbycar::protocol::ControlMode; constructMenuItem, StaticText>>(ControlMode::OpenMode, *this, *this); constructMenuItem, StaticText>>(ControlMode::Voltage, *this, *this); constructMenuItem, StaticText>>(ControlMode::Speed, *this, *this); @@ -32,12 +33,13 @@ ChangeValueDisplay::ChangeValueDisplay() constructMenuItem, StaticMenuItemIcon<&icons::back>>>(*this); } -void ChangeValueDisplay::start() +void ChangeValueDisplay::start() { Base::start(); switch (const auto value = getValue()) { + using bobbycar::protocol::ControlMode; case ControlMode::OpenMode: setSelectedIndex(0); break; case ControlMode::Voltage: setSelectedIndex(1); break; case ControlMode::Speed: setSelectedIndex(2); break; diff --git a/src/changevaluedisplay_controltype.h b/src/changevaluedisplay_controltype.h index 2ff213a..f90cb46 100644 --- a/src/changevaluedisplay_controltype.h +++ b/src/changevaluedisplay_controltype.h @@ -10,9 +10,9 @@ namespace { template<> -class ChangeValueDisplay : +class ChangeValueDisplay : public MenuDisplay, - public virtual AccessorInterface, + public virtual AccessorInterface, public virtual ActionInterface { using Base = MenuDisplay; @@ -23,20 +23,22 @@ public: void start() override; }; -ChangeValueDisplay::ChangeValueDisplay() +ChangeValueDisplay::ChangeValueDisplay() { + using bobbycar::protocol::ControlType; constructMenuItem, StaticText>>(ControlType::Commutation, *this, *this); constructMenuItem, StaticText>>(ControlType::Sinusoidal, *this, *this); constructMenuItem, StaticText>>(ControlType::FieldOrientedControl, *this, *this); constructMenuItem, StaticMenuItemIcon<&icons::back>>>(*this); } -void ChangeValueDisplay::start() +void ChangeValueDisplay::start() { Base::start(); switch (const auto value = getValue()) { + using bobbycar::protocol::ControlType; case ControlType::Commutation: setSelectedIndex(0); break; case ControlType::Sinusoidal: setSelectedIndex(1); break; case ControlType::FieldOrientedControl: setSelectedIndex(2); break; diff --git a/src/controller.h b/src/controller.h index 770b080..a177977 100644 --- a/src/controller.h +++ b/src/controller.h @@ -2,29 +2,50 @@ #include -#include "bobbycar-protocol/protocol.h" +#include "bobbycar-protocol/bobbycar-common.h" +#include "bobbycar-protocol/bobbycar-serial.h" +#include "types.h" + +#ifdef FEATURE_SERIAL #include "feedbackparser.h" +#endif +#ifdef FEATURE_SERIAL class HardwareSerial; +#endif namespace { struct Controller { - Controller(HardwareSerial &serial, bool &enableLeft, bool &enableRight, bool &invertLeft, bool &invertRight) : - serial{serial}, enableLeft{enableLeft}, enableRight{enableRight}, invertLeft{invertLeft}, invertRight{invertRight} + Controller( +#ifdef FEATURE_SERIAL + HardwareSerial &serial, +#endif + bool &enableLeft, bool &enableRight, bool &invertLeft, bool &invertRight) : +#ifdef FEATURE_SERIAL + serial{serial}, +#endif + enableLeft{enableLeft}, enableRight{enableRight}, invertLeft{invertLeft}, invertRight{invertRight} { } // Controller(const Controller &) = delete; // Controller &operator=(const Controller &) = delete; +#ifdef FEATURE_SERIAL std::reference_wrapper serial; +#endif bool &enableLeft, &enableRight, &invertLeft, &invertRight; - Command command{}; + bobbycar::protocol::serial::Command command{}; +#ifdef FEATURE_CAN + millis_t lastCanFeedback{}; +#endif bool feedbackValid{}; - Feedback feedback{}; + bobbycar::protocol::serial::Feedback feedback{}; +#ifdef FEATURE_SERIAL FeedbackParser parser{serial, feedbackValid, feedback}; +#endif }; } diff --git a/src/debugtexthelpers.h b/src/debugtexthelpers.h index 0a9d96c..dfe144e 100644 --- a/src/debugtexthelpers.h +++ b/src/debugtexthelpers.h @@ -11,14 +11,14 @@ struct ControllerTexts ControllerTexts() = delete; ~ControllerTexts() = delete; - struct BuzzerFreqText : public virtual TextInterface { public: String text() const override { return String{"buzzerFreq: "} + toString(controller::get().command.buzzer.freq); } }; - struct BuzzerPatternText : public virtual TextInterface { public: String text() const override { return String{"buzzerPattern: "} + toString(controller::get().command.buzzer.pattern); } }; - struct PoweroffText : public virtual TextInterface { public: String text() const override { return String{"poweroff: "} + toString(controller::get().command.poweroff); } }; - struct LedText : public virtual TextInterface { public: String text() const override { return String{"led: "} + toString(controller::get().command.led); } }; + struct BuzzerFreqText : public virtual TextInterface { public: std::string text() const override { return "buzzerFreq: " + std::to_string(controller::get().command.buzzer.freq); } }; + struct BuzzerPatternText : public virtual TextInterface { public: std::string text() const override { return "buzzerPattern: " + std::to_string(controller::get().command.buzzer.pattern); } }; + struct PoweroffText : public virtual TextInterface { public: std::string text() const override { return "poweroff: " + std::to_string(controller::get().command.poweroff); } }; + struct LedText : public virtual TextInterface { public: std::string text() const override { return "led: " + std::to_string(controller::get().command.led); } }; private: - struct LeftCommandGetter { static const MotorState &get() { return controller::get().command.left; } }; - struct RightCommandGetter { static const MotorState &get() { return controller::get().command.right; } }; + struct LeftCommandGetter { static const bobbycar::protocol::serial::MotorState &get() { return controller::get().command.left; } }; + struct RightCommandGetter { static const bobbycar::protocol::serial::MotorState &get() { return controller::get().command.right; } }; template struct CommandTexts @@ -26,30 +26,30 @@ private: CommandTexts() = delete; ~CommandTexts() = delete; - struct EnableText : public virtual TextInterface { public: String text() const override { return String{"enable: "} + toString(MotorStateGetter::get().enable); } }; - struct PwmText : public virtual TextInterface { public: String text() const override { return String{"pwm: "} + toString(MotorStateGetter::get().pwm); } }; - struct CtrlTypText : public virtual TextInterface { public: String text() const override { return String{"ctrlTyp: "} + toString(MotorStateGetter::get().ctrlTyp); } }; - struct CtrlModText : public virtual TextInterface { public: String text() const override { return String{"ctrlMod: "} + toString(MotorStateGetter::get().ctrlMod); } }; - struct IMotMaxText : public virtual TextInterface { public: String text() const override { return String{"iMotMax: "} + toString(MotorStateGetter::get().iMotMax); } }; - struct IDcMaxText : public virtual TextInterface { public: String text() const override { return String{"iDcMax: "} + toString(MotorStateGetter::get().iDcMax); } }; - struct NMotMaxText : public virtual TextInterface { public: String text() const override { return String{"nMotMax: "} + toString(MotorStateGetter::get().nMotMax); } }; - struct FieldWeakMaxText : public virtual TextInterface { public: String text() const override { return String{"fieldWeakMax: "} + toString(MotorStateGetter::get().fieldWeakMax); } }; - struct PhaseAdvMaxText : public virtual TextInterface { public: String text() const override { return String{"phaseAdvMax: "} + toString(MotorStateGetter::get().phaseAdvMax); } }; + struct EnableText : public virtual TextInterface { public: std::string text() const override { return "enable: " + std::to_string(MotorStateGetter::get().enable); } }; + struct PwmText : public virtual TextInterface { public: std::string text() const override { return "pwm: " + std::to_string(MotorStateGetter::get().pwm); } }; + struct CtrlTypText : public virtual TextInterface { public: std::string text() const override { return "ctrlTyp: " + to_string(MotorStateGetter::get().ctrlTyp); } }; + struct CtrlModText : public virtual TextInterface { public: std::string text() const override { return "ctrlMod: " + to_string(MotorStateGetter::get().ctrlMod); } }; + struct IMotMaxText : public virtual TextInterface { public: std::string text() const override { return "iMotMax: " + std::to_string(MotorStateGetter::get().iMotMax); } }; + struct IDcMaxText : public virtual TextInterface { public: std::string text() const override { return "iDcMax: " + std::to_string(MotorStateGetter::get().iDcMax); } }; + struct NMotMaxText : public virtual TextInterface { public: std::string text() const override { return "nMotMax: " + std::to_string(MotorStateGetter::get().nMotMax); } }; + struct FieldWeakMaxText : public virtual TextInterface { public: std::string text() const override { return "fieldWeakMax: " + std::to_string(MotorStateGetter::get().fieldWeakMax); } }; + struct PhaseAdvMaxText : public virtual TextInterface { public: std::string text() const override { return "phaseAdvMax: " + std::to_string(MotorStateGetter::get().phaseAdvMax); } }; }; public: using LeftCommand = CommandTexts; using RightCommand = CommandTexts; - struct BatVoltageText : public virtual TextInterface { public: String text() const override { auto line = String{"batVoltage: "}; if (controller::get().feedbackValid) line += toString(controller::get().feedback.batVoltage); return line; } }; - struct BatVoltageFixedText : public virtual TextInterface { public: String text() const override { auto line = String{"batVoltage: "}; if (controller::get().feedbackValid) line += toString(fixBatVoltage(controller::get().feedback.batVoltage)) + 'V'; return line; } }; - struct BoardTempText : public virtual TextInterface { public: String text() const override { auto line = String{"boardTemp: "}; if (controller::get().feedbackValid) line += toString(controller::get().feedback.boardTemp); return line; } }; - struct BoardTempFixedText : public virtual TextInterface { public: String text() const override { auto line = String{"boardTemp: "}; if (controller::get().feedbackValid) line += toString(fixBoardTemp(controller::get().feedback.boardTemp)) + 'C'; return line; } }; - struct TimeoutCntSerialText : public virtual TextInterface { public: String text() const override { auto line = String{"timeoutCntSerial: "}; if (controller::get().feedbackValid) line += toString(controller::get().feedback.timeoutCntSerial); return line; } }; + struct BatVoltageText : public virtual TextInterface { public: std::string text() const override { std::string line{"batVoltage: "}; if (controller::get().feedbackValid) line += std::to_string(controller::get().feedback.batVoltage); return line; } }; + struct BatVoltageFixedText : public virtual TextInterface { public: std::string text() const override { std::string line{"batVoltage: "}; if (controller::get().feedbackValid) line += std::to_string(fixBatVoltage(controller::get().feedback.batVoltage)) + 'V'; return line; } }; + struct BoardTempText : public virtual TextInterface { public: std::string text() const override { std::string line{"boardTemp: "}; if (controller::get().feedbackValid) line += std::to_string(controller::get().feedback.boardTemp); return line; } }; + struct BoardTempFixedText : public virtual TextInterface { public: std::string text() const override { std::string line{"boardTemp: "}; if (controller::get().feedbackValid) line += std::to_string(fixBoardTemp(controller::get().feedback.boardTemp)) + 'C'; return line; } }; + struct TimeoutCntSerialText : public virtual TextInterface { public: std::string text() const override { std::string line{"timeoutCntSerial: "}; if (controller::get().feedbackValid) line += std::to_string(controller::get().feedback.timeoutCntSerial); return line; } }; private: - struct LeftFeedbackGetter { static const MotorFeedback &get() { return controller::get().feedback.left; } }; - struct RightFeedbackGetter { static const MotorFeedback &get() { return controller::get().feedback.right; } }; + struct LeftFeedbackGetter { static const bobbycar::protocol::serial::MotorFeedback &get() { return controller::get().feedback.left; } }; + struct RightFeedbackGetter { static const bobbycar::protocol::serial::MotorFeedback &get() { return controller::get().feedback.right; } }; template struct FeedbackTexts @@ -57,14 +57,20 @@ private: FeedbackTexts() = delete; ~FeedbackTexts() = delete; - struct AngleText : public virtual TextInterface { public: String text() const override { auto line = String{"angle: "}; if (controller::get().feedbackValid) line += toString(MotorFeedbackGetter::get().angle); return line; } }; - struct SpeedText : public virtual TextInterface { public: String text() const override { auto line = String{"speed: "}; if (controller::get().feedbackValid) line += toString(MotorFeedbackGetter::get().speed); return line; } }; - struct SpeedKmhText : public virtual TextInterface { public: String text() const override { auto line = String{"speed kmh: "}; if (controller::get().feedbackValid) line += toString(convertToKmh(MotorFeedbackGetter::get().speed)); return line; } }; - struct ErrorText : public virtual TextInterface { public: String text() const override { auto line = String{"error: "}; if (controller::get().feedbackValid) line += toString(MotorFeedbackGetter::get().error); return line; } }; - struct CurrentText : public virtual TextInterface { public: String text() const override { auto line = String{"current: "}; if (controller::get().feedbackValid) line += toString(MotorFeedbackGetter::get().current); return line; } }; - struct CurrentFixedText : public virtual TextInterface { public: String text() const override { auto line = String{"current: "}; if (controller::get().feedbackValid) line += toString(fixCurrent(MotorFeedbackGetter::get().current)) + 'A'; return line; } }; - struct ChopsText : public virtual TextInterface { public: String text() const override { auto line = String{"chops: "}; if (controller::get().feedbackValid) line += toString(MotorFeedbackGetter::get().chops); return line; } }; - struct HallText : public virtual TextInterface { public: String text() const override { auto line = String{"hall: "}; if (controller::get().feedbackValid) line += hallString(MotorFeedbackGetter::get()); return line; } }; + struct AngleText : public virtual TextInterface { public: std::string text() const override { std::string line{"angle: "}; if (controller::get().feedbackValid) line += std::to_string(MotorFeedbackGetter::get().angle); return line; } }; + struct SpeedText : public virtual TextInterface { public: std::string text() const override { std::string line{"speed: "}; if (controller::get().feedbackValid) line += std::to_string(MotorFeedbackGetter::get().speed); return line; } }; + struct SpeedKmhText : public virtual TextInterface { public: std::string text() const override { std::string line{"speed kmh: "}; if (controller::get().feedbackValid) line += std::to_string(convertToKmh(MotorFeedbackGetter::get().speed)); return line; } }; + struct ErrorText : public virtual TextInterface { public: std::string text() const override { std::string line{"error: "}; if (controller::get().feedbackValid) line += std::to_string(MotorFeedbackGetter::get().error); return line; } }; + struct DcLinkText : public virtual TextInterface { public: std::string text() const override { std::string line{"dcLink: "}; if (controller::get().feedbackValid) line += std::to_string(MotorFeedbackGetter::get().dcLink); return line; } }; + struct DcLinkFixedText : public virtual TextInterface { public: std::string text() const override { std::string line{"dcLink: "}; if (controller::get().feedbackValid) line += std::to_string(fixCurrent(MotorFeedbackGetter::get().dcLink)) + 'A'; return line; } }; + struct DcPhaAText : public virtual TextInterface { public: std::string text() const override { std::string line{"dcPhaA: "}; if (controller::get().feedbackValid) line += std::to_string(MotorFeedbackGetter::get().dcPhaA); return line; } }; + struct DcPhaAFixedText : public virtual TextInterface { public: std::string text() const override { std::string line{"dcPhaA: "}; if (controller::get().feedbackValid) line += std::to_string(fixCurrent(MotorFeedbackGetter::get().dcPhaA)) + 'A'; return line; } }; + struct DcPhaBText : public virtual TextInterface { public: std::string text() const override { std::string line{"dcPhaB: "}; if (controller::get().feedbackValid) line += std::to_string(MotorFeedbackGetter::get().dcPhaB); return line; } }; + struct DcPhaBFixedText : public virtual TextInterface { public: std::string text() const override { std::string line{"dcPhaB: "}; if (controller::get().feedbackValid) line += std::to_string(fixCurrent(MotorFeedbackGetter::get().dcPhaB)) + 'A'; return line; } }; + struct DcPhaCText : public virtual TextInterface { public: std::string text() const override { std::string line{"dcPhaC: "}; if (controller::get().feedbackValid) line += std::to_string(MotorFeedbackGetter::get().dcPhaC); return line; } }; + struct DcPhaCFixedText : public virtual TextInterface { public: std::string text() const override { std::string line{"dcPhaC: "}; if (controller::get().feedbackValid) line += std::to_string(fixCurrent(MotorFeedbackGetter::get().dcPhaC)) + 'A'; return line; } }; + struct ChopsText : public virtual TextInterface { public: std::string text() const override { std::string line{"chops: "}; if (controller::get().feedbackValid) line += std::to_string(MotorFeedbackGetter::get().chops); return line; } }; + struct HallText : public virtual TextInterface { public: std::string text() const override { std::string line{"hall: "}; if (controller::get().feedbackValid) line += hallString(MotorFeedbackGetter::get()); return line; } }; }; public: diff --git a/src/display.h b/src/display.h index a68cdb4..59d270a 100644 --- a/src/display.h +++ b/src/display.h @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace { class TextInterface; diff --git a/src/displays/bmsdisplay.h b/src/displays/bmsdisplay.h index ed4642c..95184f9 100644 --- a/src/displays/bmsdisplay.h +++ b/src/displays/bmsdisplay.h @@ -92,11 +92,11 @@ void BmsDisplay::redraw() if (bluetoothSerial.hasClient()) { - m_voltageLabel.redraw(String{bms::voltage} + 'V'); - m_capacityLabel.redraw(String{int(bms::capacity)} + "mAh"); - m_socLabel.redraw(String{bms::soc} + '%'); - m_powerLabel.redraw(String{bms::power} + 'W'); - m_currentLabel.redraw(String{bms::current} + 'A'); + m_voltageLabel.redraw(std::to_string(bms::voltage) + 'V'); + m_capacityLabel.redraw(std::to_string(int(bms::capacity)) + "mAh"); + m_socLabel.redraw(std::to_string(bms::soc) + '%'); + m_powerLabel.redraw(std::to_string(bms::power) + 'W'); + m_currentLabel.redraw(std::to_string(bms::current) + 'A'); } else { @@ -107,18 +107,18 @@ void BmsDisplay::redraw() m_currentLabel.clear(); } - m_speedLabel.redraw(String{avgSpeedKmh} + "kmh"); + m_speedLabel.redraw(std::to_string(avgSpeedKmh) + "kmh"); if (bluetoothSerial.hasClient()) - m_powerPerSpeedLabel.redraw(String{avgSpeedKmh < 1 ? 0 : bms::power / avgSpeedKmh} + "W/kmh"); + m_powerPerSpeedLabel.redraw(std::to_string(avgSpeedKmh < 1 ? 0 : bms::power / avgSpeedKmh) + "W/kmh"); else m_powerPerSpeedLabel.clear(); for (int i = 0; i < 12; i++) - m_battLabels[i].redraw(String{bms::batt[i]}); + m_battLabels[i].redraw(std::to_string(bms::batt[i])); if (bluetoothSerial.hasClient()) - m_cycleLabel.redraw(String{bms::cycle} + "AH"); + m_cycleLabel.redraw(std::to_string(bms::cycle) + "AH"); else m_cycleLabel.clear(); } diff --git a/src/displays/calibratedisplay.h b/src/displays/calibratedisplay.h index 0da3fe3..4be0c20 100644 --- a/src/displays/calibratedisplay.h +++ b/src/displays/calibratedisplay.h @@ -1,8 +1,7 @@ #pragma once #include - -#include +#include #include "display.h" #include "actions/switchscreenaction.h" @@ -43,7 +42,7 @@ private: const bool m_bootup{false}; ModeInterface *m_oldMode; - IgnoreInputMode m_mode{0, ControlType::FieldOrientedControl, ControlMode::Torque}; + IgnoreInputMode m_mode{0, bobbycar::protocol::ControlType::FieldOrientedControl, bobbycar::protocol::ControlMode::Torque}; std::array m_labels {{ Label{25, 72}, // 100, 23 @@ -80,7 +79,7 @@ private: Status m_status; int16_t m_gasMin, m_gasMax, m_bremsMin, m_bremsMax; - float m_gas, m_brems; + std::optional m_gas, m_brems; }; CalibrateDisplay::CalibrateDisplay(bool bootup) : @@ -95,8 +94,8 @@ void CalibrateDisplay::start() m_selectedButton = 0; m_status = Status::Begin; copyFromSettings(); - m_gas = 0.f; - m_brems = 0.f; + m_gas = std::nullopt; + m_brems = std::nullopt; } void CalibrateDisplay::initScreen() @@ -125,41 +124,48 @@ void CalibrateDisplay::initScreen() void CalibrateDisplay::update() { - m_gas = scaleBetween(raw_gas, m_gasMin, m_gasMax, 0., 1000.); - m_brems = scaleBetween(raw_brems, m_bremsMin, m_bremsMax, 0., 1000.); + if (raw_gas) + m_gas = scaleBetween(*raw_gas, m_gasMin, m_gasMax, 0., 1000.); + else + m_gas = std::nullopt; + + if (raw_brems) + m_brems = scaleBetween(*raw_brems, m_bremsMin, m_bremsMax, 0., 1000.); + else + m_brems = std::nullopt; } void CalibrateDisplay::redraw() { - m_labels[0].redraw(toString(m_gas)); - m_labels[1].redraw(toString(raw_gas)); + m_labels[0].redraw(m_gas ? std::to_string(*m_gas) : "?"); + m_labels[1].redraw(raw_gas ? std::to_string(*raw_gas) : "?"); if (m_status == Status::GasMin) tft.setTextColor(TFT_RED, TFT_BLACK); - m_labels[2].redraw(toString(m_gasMin)); + m_labels[2].redraw(std::to_string(m_gasMin)); if (m_status == Status::GasMin) tft.setTextColor(TFT_WHITE, TFT_BLACK); if (m_status == Status::GasMax) tft.setTextColor(TFT_RED, TFT_BLACK); - m_labels[3].redraw(toString(m_gasMax)); + m_labels[3].redraw(std::to_string(m_gasMax)); if (m_status == Status::GasMax) tft.setTextColor(TFT_WHITE, TFT_BLACK); - m_progressBars[0].redraw(m_gas); + m_progressBars[0].redraw(m_gas ? *m_gas : 0); - m_labels[4].redraw(toString(m_brems)); - m_labels[5].redraw(toString(raw_brems)); + m_labels[4].redraw(m_brems ? std::to_string(*m_brems) : "?"); + m_labels[5].redraw(raw_brems ? std::to_string(*raw_brems) : "?"); if (m_status == Status::BremsMin) tft.setTextColor(TFT_RED, TFT_BLACK); - m_labels[6].redraw(toString(m_bremsMin)); + m_labels[6].redraw(std::to_string(m_bremsMin)); if (m_status == Status::BremsMin) tft.setTextColor(TFT_WHITE, TFT_BLACK); if (m_status == Status::BremsMax) tft.setTextColor(TFT_RED, TFT_BLACK); - m_labels[7].redraw(toString(m_bremsMax)); + m_labels[7].redraw(std::to_string(m_bremsMax)); if (m_status == Status::BremsMax) tft.setTextColor(TFT_WHITE, TFT_BLACK); - m_progressBars[1].redraw(m_brems); + m_progressBars[1].redraw(m_brems ? *m_brems : 0); m_labels[8].redraw([&](){ switch (m_status) @@ -175,7 +181,8 @@ void CalibrateDisplay::redraw() }()); { - const auto color = m_status == Status::Confirm && (m_gas > 100 || m_brems > 100) ? TFT_DARKGREY : TFT_WHITE; + const auto failed = !m_gas || !m_brems || (m_status == Status::Confirm && (*m_gas > 100 || *m_brems > 100)); + const auto color = failed ? TFT_DARKGREY : TFT_WHITE; tft.setTextColor(color, TFT_BLACK); m_labels[9].redraw([&](){ switch (m_status) @@ -256,17 +263,20 @@ void CalibrateDisplay::confirm() switch (m_selectedButton) { case 0: // left button pressed + if (!raw_gas || !raw_brems || !m_gas || !m_brems) + return; + switch (m_status) { case Status::Begin: m_status = Status::GasMin; break; case Status::GasMin: - m_gasMin = raw_gas; + m_gasMin = *raw_gas; m_status = Status::GasMax; break; case Status::GasMax: - m_gasMax = raw_gas; + m_gasMax = *raw_gas; m_status = Status::BremsMin; { const auto dead = (m_gasMax - m_gasMin)/20; @@ -275,11 +285,11 @@ void CalibrateDisplay::confirm() } break; case Status::BremsMin: - m_bremsMin = raw_brems; + m_bremsMin = *raw_brems; m_status = Status::BremsMax; break; case Status::BremsMax: - m_bremsMax = raw_brems; + m_bremsMax = *raw_brems; m_status = Status::Confirm; { const auto dead = (m_bremsMax - m_bremsMin)/20; @@ -288,7 +298,7 @@ void CalibrateDisplay::confirm() } break; case Status::Confirm: - if (m_gas > 100 || m_brems > 100) + if (*m_gas > 100 || *m_brems > 100) return; copyToSettings(); saveSettings(); diff --git a/src/displays/dpad5wiredebugdisplay.h b/src/displays/dpad5wiredebugdisplay.h index cd03c25..c0137be 100644 --- a/src/displays/dpad5wiredebugdisplay.h +++ b/src/displays/dpad5wiredebugdisplay.h @@ -65,7 +65,7 @@ void DPad5WireDebugDisplay::initScreen() void DPad5WireDebugDisplay::redraw() { - m_labelRaw.redraw(String{} + + m_labelRaw.redraw(std::string{} + (std::get<0>(dpad5wire::lastState) ? '1' : '0') + ' ' + (std::get<1>(dpad5wire::lastState) ? '1' : '0') + ' ' + (std::get<2>(dpad5wire::lastState) ? '1' : '0') + ' ' + @@ -83,8 +83,8 @@ void DPad5WireDebugDisplay::redraw() m_labelProfile1.redraw(std::get(dpad5wire::lastState) ? "1" : "0"); m_labelProfile2.redraw(std::get(dpad5wire::lastState) ? "1" : "0"); m_labelProfile3.redraw(std::get(dpad5wire::lastState) ? "1" : "0"); - m_labelGas.redraw(String{raw_gas}); - m_labelBrems.redraw(String{raw_brems}); + m_labelGas.redraw(raw_gas ? std::to_string(*raw_gas) : "?"); + m_labelBrems.redraw(raw_brems ? std::to_string(*raw_brems) : "?"); } #endif } diff --git a/src/displays/gametrakcalibratedisplay.h b/src/displays/gametrakcalibratedisplay.h index 5b9b090..66a8ae0 100644 --- a/src/displays/gametrakcalibratedisplay.h +++ b/src/displays/gametrakcalibratedisplay.h @@ -1,8 +1,7 @@ #pragma once #include - -#include +#include #include "display.h" #include "actions/switchscreenaction.h" @@ -63,14 +62,14 @@ void GametrakCalibrateDisplay::initScreen() void GametrakCalibrateDisplay::redraw() { - m_labels[0].redraw(String{gametrakX}); - m_labels[1].redraw(String{raw_gametrakX}); + m_labels[0].redraw(std::to_string(gametrakX)); + m_labels[1].redraw(std::to_string(raw_gametrakX)); - m_labels[2].redraw(String{gametrakY}); - m_labels[3].redraw(String{raw_gametrakY}); + m_labels[2].redraw(std::to_string(gametrakY)); + m_labels[3].redraw(std::to_string(raw_gametrakY)); - m_labels[4].redraw(String{gametrakDist}); - m_labels[5].redraw(String{raw_gametrakDist}); + m_labels[4].redraw(std::to_string(gametrakDist)); + m_labels[5].redraw(std::to_string(raw_gametrakDist)); m_progressBars[0].redraw(gametrakX); m_progressBars[1].redraw(gametrakY); diff --git a/src/displays/lockscreen.h b/src/displays/lockscreen.h index 68f17d6..4aa6e36 100644 --- a/src/displays/lockscreen.h +++ b/src/displays/lockscreen.h @@ -50,7 +50,7 @@ private: int m_rotated; ModeInterface *m_oldMode; - IgnoreInputMode m_mode{0, ControlType::FieldOrientedControl, ControlMode::Speed}; + IgnoreInputMode m_mode{0, bobbycar::protocol::ControlType::FieldOrientedControl, bobbycar::protocol::ControlMode::Speed}; }; void Lockscreen::start() @@ -92,7 +92,7 @@ void Lockscreen::initScreen() drawRect(0, 1, TFT_YELLOW); drawRect(0, 2, TFT_YELLOW); - m_labels[0].redraw(String(m_numbers[0])); + m_labels[0].redraw(std::to_string(m_numbers[0])); } void Lockscreen::redraw() @@ -115,7 +115,7 @@ void Lockscreen::redraw() std::for_each(std::begin(m_labels) + 1, std::end(m_labels), [](auto &label){ label.redraw({}); }); } - m_labels[m_currentIndex].redraw(String{m_numbers[m_currentIndex]}); + m_labels[m_currentIndex].redraw(std::to_string(m_numbers[m_currentIndex])); drawRect(m_currentIndex, 1, TFT_YELLOW); drawRect(m_currentIndex, 2, TFT_YELLOW); @@ -132,7 +132,7 @@ void Lockscreen::redraw() else if (m_numbers[m_currentIndex] > 9) m_numbers[m_currentIndex]-=10; - m_labels[m_currentIndex].redraw(String(m_numbers[m_currentIndex])); + m_labels[m_currentIndex].redraw(std::to_string(m_numbers[m_currentIndex])); m_rotated = 0; } diff --git a/src/displays/menus/boardcomputerhardwaresettingsmenu.h b/src/displays/menus/boardcomputerhardwaresettingsmenu.h index 382c4f5..af0db44 100644 --- a/src/displays/menus/boardcomputerhardwaresettingsmenu.h +++ b/src/displays/menus/boardcomputerhardwaresettingsmenu.h @@ -24,11 +24,23 @@ class SettingsMenu; namespace { struct GasText : public virtual TextInterface { public: - String text() const override { return String{"gas: "} + raw_gas + ": " + gas; } + std::string text() const override + { + return std::string{"gas: "} + + (raw_gas ? std::to_string(*raw_gas) : "?") + + ": " + + (gas ? std::to_string(*gas) : "?"); + } }; struct BremsText : public virtual TextInterface { public: - String text() const override { return String{"brems: "} + raw_brems + ": " + brems; } + std::string text() const override + { + return std::string{"brems: "} + + (raw_brems ? std::to_string(*raw_brems) : "?") + + ": " + + (brems ? std::to_string(*brems) : "?"); + } }; using SampleCountChangeScreen = makeComponent< @@ -80,15 +92,15 @@ using DPadDebounceChangeScreen = makeComponent< #ifdef FEATURE_GAMETRAK struct GametrakXText : public virtual TextInterface { public: - String text() const override { return String{"gametrakX: "} + raw_gametrakX + ": " + gametrakX; } + std::string text() const override { return std::string{"gametrakX: "} + std::to_string(raw_gametrakX) + ": " + std::to_string(gametrakX); } }; struct GametrakYText : public virtual TextInterface { public: - String text() const override { return String{"gametrakY: "} + raw_gametrakY + ": " + gametrakY; } + std::string text() const override { return std::string{"gametrakY: "} + std::to_string(raw_gametrakY) + ": " + std::to_string(gametrakY); } }; struct GametrakDistText : public virtual TextInterface { public: - String text() const override { return String{"gametrakDist: "} + raw_gametrakDist + ": " + gametrakDist; } + std::string text() const override { return std::string{"gametrakDist: "} + std::to_string(raw_gametrakDist) + ": " + std::to_string(gametrakDist); } }; using GametrakXMinChangeScreen = makeComponent< diff --git a/src/displays/menus/dynamicdebugmenu.h b/src/displays/menus/dynamicdebugmenu.h index 4ce6480..dc911bf 100644 --- a/src/displays/menus/dynamicdebugmenu.h +++ b/src/displays/menus/dynamicdebugmenu.h @@ -2,7 +2,7 @@ // Arduino includes #include -#include +#include // local includes #include "menudisplay.h" @@ -26,12 +26,12 @@ namespace { class RandomText : public virtual TextInterface { public: - String text() const override + std::string text() const override { const auto now = millis(); if (!m_nextUpdate || now >= m_nextUpdate) { - m_title = String{"Dynamic text: "} + random(0, 100); + m_title = std::string{"Dynamic text: "} + std::to_string(random(0, 100)); m_nextUpdate = now + random(0, 1000); } @@ -40,7 +40,7 @@ public: private: mutable millis_t m_nextUpdate{}; - mutable String m_title; + mutable std::string m_title; }; class RandomColor : public virtual ColorInterface diff --git a/src/displays/menus/limitssettingsmenu.h b/src/displays/menus/limitssettingsmenu.h index d8b18c3..7c11107 100644 --- a/src/displays/menus/limitssettingsmenu.h +++ b/src/displays/menus/limitssettingsmenu.h @@ -17,44 +17,50 @@ class SettingsMenu; } // namespace namespace { +template +struct TextWithValueHelper : public virtual TextInterface +{ + std::string text() const override { return Tprefix + (' ' + std::to_string(Taccessor{}.getValue())); } +}; + using IMotMaxChangeScreen = makeComponent< ChangeValueDisplay, - StaticText, + StaticText, IMotMaxAccessor, BackActionInterface>, SwitchScreenAction >; using IDcMaxChangeScreen = makeComponent< ChangeValueDisplay, - StaticText, + StaticText, IDcMaxAccessor, BackActionInterface>, SwitchScreenAction >; using NMotMaxKmhChangeScreen = makeComponent< ChangeValueDisplay, - StaticText, + StaticText, NMotMaxKmhAccessor, BackActionInterface>, SwitchScreenAction >; using NMotMaxRpmChangeScreen = makeComponent< ChangeValueDisplay, - StaticText, + StaticText, NMotMaxRpmAccessor, BackActionInterface>, SwitchScreenAction >; using FieldWeakMaxChangeScreen = makeComponent< ChangeValueDisplay, - StaticText, + StaticText, FieldWeakMaxAccessor, BackActionInterface>, SwitchScreenAction >; using PhaseAdvMaxChangeScreen = makeComponent< ChangeValueDisplay, - StaticText, + StaticText, PhaseAdvMaxAccessor, BackActionInterface>, SwitchScreenAction @@ -68,13 +74,13 @@ class LimitsSettingsMenu : public: LimitsSettingsMenu() { - constructMenuItem, SwitchScreenAction>>(); - constructMenuItem, SwitchScreenAction>>(); - constructMenuItem, SwitchScreenAction>>(); - constructMenuItem, SwitchScreenAction>>(); - constructMenuItem, SwitchScreenAction>>(); - constructMenuItem, SwitchScreenAction>>(); - constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&icons::back>>>(); + constructMenuItem, SwitchScreenAction>>(); + constructMenuItem, SwitchScreenAction>>(); + constructMenuItem, SwitchScreenAction>>(); + constructMenuItem, SwitchScreenAction>>(); + constructMenuItem, SwitchScreenAction>>(); + constructMenuItem, SwitchScreenAction>>(); + constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&icons::back>>>(); } }; } // namespace diff --git a/src/displays/menus/mainmenu.h b/src/displays/menus/mainmenu.h index 622b946..e32cb3f 100644 --- a/src/displays/menus/mainmenu.h +++ b/src/displays/menus/mainmenu.h @@ -25,6 +25,7 @@ class SelectModeMenu; class ProfilesMenu; class PresetsMenu; class GraphsMenu; +class PowerSupplyDisplay; class BmsMenu; class SettingsMenu; class Lockscreen; @@ -49,6 +50,9 @@ public: constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&icons::presets>>>(); constructMenuItem, SwitchScreenAction>>(); constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&icons::graph>>>(); +#ifdef FEATURE_CAN + constructMenuItem, SwitchScreenAction>>(); +#endif #ifdef FEATURE_BMS constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&icons::bms>>>(); #endif diff --git a/src/displays/menus/motorfeedbackdebugmenu.h b/src/displays/menus/motorfeedbackdebugmenu.h index ec07797..f187a68 100644 --- a/src/displays/menus/motorfeedbackdebugmenu.h +++ b/src/displays/menus/motorfeedbackdebugmenu.h @@ -30,8 +30,14 @@ public: constructMenuItem, DummyAction>>(); constructMenuItem, DummyAction>>(); constructMenuItem, DummyAction>>(); - constructMenuItem, DummyAction>>(); - constructMenuItem, DummyAction>>(); + constructMenuItem, DummyAction>>(); + constructMenuItem, DummyAction>>(); + constructMenuItem, DummyAction>>(); + constructMenuItem, DummyAction>>(); + constructMenuItem, DummyAction>>(); + constructMenuItem, DummyAction>>(); + constructMenuItem, DummyAction>>(); + constructMenuItem, DummyAction>>(); constructMenuItem, DummyAction>>(); constructMenuItem, DummyAction>>(); constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&icons::back>>>(); diff --git a/src/displays/menus/wifiscanmenu.h b/src/displays/menus/wifiscanmenu.h index 1965030..cf24644 100644 --- a/src/displays/menus/wifiscanmenu.h +++ b/src/displays/menus/wifiscanmenu.h @@ -27,7 +27,7 @@ class WifiScanMenu : public MenuDisplay, public BackActionInterface, SwitchScreenAction, StaticMenuItemIcon<&icons::back>>>(); } -String WifiScanMenu::text() const +std::string WifiScanMenu::text() const { - auto text = String{menuItemCount()-1} + " found"; + auto text = std::to_string(menuItemCount()-1) + " found"; switch (WiFi.scanComplete()) { case WIFI_SCAN_RUNNING: text += " (scanning)"; break; @@ -76,7 +76,7 @@ void WifiScanMenu::update() for (std::size_t i = 0; i < n; i++) { - const auto ssid = WiFi.SSID(i); + const auto ssid = to_string(WiFi.SSID(i)); if (menuItemCount() <= i) { if (m_reusableItems.empty()) diff --git a/src/displays/metersdisplay.h b/src/displays/metersdisplay.h index a5e47a9..fa8875a 100644 --- a/src/displays/metersdisplay.h +++ b/src/displays/metersdisplay.h @@ -72,14 +72,14 @@ void MetersDisplay::redraw() tft.setTextColor(TFT_WHITE, TFT_BLACK); tft.setTextFont(2); - m_sumCurrentLabel.redraw(toString(sumCurrent) + 'A'); + m_sumCurrentLabel.redraw(std::to_string(sumCurrent) + 'A'); meters[0].redraw(fixBatVoltage(controllers.front.feedback.batVoltage), 35, 50); meters[1].redraw(fixBatVoltage(controllers.back.feedback.batVoltage), 35, 50); - meters[2].redraw(fixCurrent(controllers.front.feedback.left.current), -10, 10); - meters[3].redraw(fixCurrent(controllers.front.feedback.right.current), -10, 10); - meters[4].redraw(fixCurrent(controllers.back.feedback.left.current), -10, 10); - meters[5].redraw(fixCurrent(controllers.back.feedback.right.current), -10, 10); + meters[2].redraw(fixCurrent(controllers.front.feedback.left.dcLink), -10, 10); + meters[3].redraw(fixCurrent(controllers.front.feedback.right.dcLink), -10, 10); + meters[4].redraw(fixCurrent(controllers.back.feedback.left.dcLink), -10, 10); + meters[5].redraw(fixCurrent(controllers.back.feedback.right.dcLink), -10, 10); } void MetersDisplay::rotate(int offset) diff --git a/src/displays/powersupplydisplay.h b/src/displays/powersupplydisplay.h new file mode 100644 index 0000000..21d1c5a --- /dev/null +++ b/src/displays/powersupplydisplay.h @@ -0,0 +1,68 @@ +#pragma once + +#include + +#include "display.h" +#include "actions/switchscreenaction.h" +#include "globals.h" +#include "widgets/label.h" + +namespace { +class MainMenu; +class MetersDisplay; +class StatusDisplay; +} +namespace { +#ifdef FEATURE_CAN +class PowerSupplyDisplay : public Display +{ +public: + void initScreen() override; + void redraw() override; + + void confirm() override; + void back() override; + void rotate(int offset) override; + + Label m_voltageLabel{120, 50}; + Label m_currentLabel{120, 75}; +}; + +void PowerSupplyDisplay::initScreen() +{ + tft.fillScreen(TFT_BLACK); + tft.setTextColor(TFT_WHITE, TFT_BLACK); + + tft.setTextFont(4); + + tft.drawString("Voltage:", 0, m_voltageLabel.y()); + m_voltageLabel.start(); + tft.drawString("Current:", 0, m_currentLabel.y()); + m_currentLabel.start(); +} + +void PowerSupplyDisplay::redraw() +{ + m_voltageLabel.redraw(std::to_string(50.4) + 'V'); + m_currentLabel.redraw(std::to_string(15.1) + 'A'); +} + +void PowerSupplyDisplay::confirm() +{ + +} + +void PowerSupplyDisplay::back() +{ + +} + +void PowerSupplyDisplay::rotate(int offset) +{ +// if (offset < 0) +// switchScreen(); +// else if (offset > 0) +// switchScreen(); +} +#endif +} diff --git a/src/displays/statusdisplay.h b/src/displays/statusdisplay.h index ce48a09..a2dd0d6 100644 --- a/src/displays/statusdisplay.h +++ b/src/displays/statusdisplay.h @@ -57,7 +57,7 @@ private: {} void start(); - void redraw(const MotorFeedback &motor); + void redraw(const bobbycar::protocol::serial::MotorFeedback &motor); private: Label m_labelError; @@ -145,26 +145,26 @@ void StatusDisplay::initScreen() void StatusDisplay::redraw() { tft.setTextFont(2); - m_labelRawGas.redraw(String{raw_gas}); - m_labelGas.redraw(String{gas}); - m_progressBarGas.redraw(gas); - m_labelRawBrems.redraw(String{raw_brems}); - m_labelBrems.redraw(String{brems}); - m_progressBarBrems.redraw(brems); + m_labelRawGas.redraw(raw_gas ? std::to_string(*raw_gas) : "?"); + m_labelGas.redraw(gas ? std::to_string(*gas) : "?"); + m_progressBarGas.redraw(gas ? *gas : 0); + m_labelRawBrems.redraw(raw_brems ? std::to_string(*raw_brems) : "?"); + m_labelBrems.redraw(brems ? std::to_string(*brems) : "?"); + m_progressBarBrems.redraw(brems ? *brems : 0); m_frontStatus.redraw(controllers.front); m_backStatus.redraw(controllers.back); tft.setTextFont(2); - m_labelWifiStatus.redraw(toString(WiFi.status())); - m_labelLimit0.redraw(String{controllers.front.command.left.iMotMax} + "A"); - m_labelIpAddress.redraw(WiFi.localIP().toString()); - m_labelLimit1.redraw(String{controllers.front.command.left.iDcMax} + "A"); - m_labelPerformance.redraw(String{performance.last}); + m_labelWifiStatus.redraw(to_string(WiFi.status())); + m_labelLimit0.redraw(std::to_string(controllers.front.command.left.iMotMax) + "A"); + m_labelIpAddress.redraw(to_string(WiFi.localIP())); + m_labelLimit1.redraw(std::to_string(controllers.front.command.left.iDcMax) + "A"); + m_labelPerformance.redraw(std::to_string(performance.last)); m_labelMode.redraw(currentMode->displayName()); m_labelName.redraw(&deviceName[0]); const auto profile = settingsPersister.currentlyOpenProfileIndex(); - m_labelProfile.redraw(profile?String{*profile}:"-"); + m_labelProfile.redraw(profile ? std::to_string(*profile) : "-"); } void StatusDisplay::rotate(int offset) @@ -192,8 +192,8 @@ void StatusDisplay::BoardStatus::redraw(const Controller &controller) { tft.setTextFont(4); - m_labelLeftPwm.redraw(String{controller.command.left.pwm}); - m_labelRightPwm.redraw(String{controller.command.right.pwm}); + m_labelLeftPwm.redraw(std::to_string(controller.command.left.pwm)); + m_labelRightPwm.redraw(std::to_string(controller.command.right.pwm)); if (controller.feedbackValid != m_lastFeedbackValid || m_initialRedraw) { @@ -231,8 +231,8 @@ void StatusDisplay::BoardStatus::redraw(const Controller &controller) if (controller.feedbackValid) { - m_labelVoltage.redraw(String{fixBatVoltage(controller.feedback.batVoltage)} + 'V'); - m_labelTemperature.redraw(String{fixBoardTemp(controller.feedback.boardTemp)} + 'C'); + m_labelVoltage.redraw(std::to_string(fixBatVoltage(controller.feedback.batVoltage)) + 'V'); + m_labelTemperature.redraw(std::to_string(fixBoardTemp(controller.feedback.boardTemp)) + 'C'); m_leftMotor.redraw(controller.feedback.left); m_rightMotor.redraw(controller.feedback.right); } @@ -246,15 +246,15 @@ void StatusDisplay::BoardStatus::MotorStatus::start() m_labelHallSensors.start(); } -void StatusDisplay::BoardStatus::MotorStatus::redraw(const MotorFeedback &motor) +void StatusDisplay::BoardStatus::MotorStatus::redraw(const bobbycar::protocol::serial::MotorFeedback &motor) { tft.setTextFont(4); tft.setTextColor(motor.error?TFT_RED:TFT_GREEN, TFT_BLACK); - m_labelError.redraw(String{motor.error}); + m_labelError.redraw(std::to_string(motor.error)); tft.setTextColor(TFT_WHITE, TFT_BLACK); - m_labelCurrent.redraw(String{fixCurrent(motor.current)} + 'A'); - m_labelSpeed.redraw(String{convertToKmh(motor.speed)}); + m_labelCurrent.redraw(std::to_string(fixCurrent(motor.dcLink)) + 'A'); + m_labelSpeed.redraw(std::to_string(convertToKmh(motor.speed))); tft.setTextFont(2); m_labelHallSensors.redraw(hallString(motor)); diff --git a/src/displays/updatedisplay.h b/src/displays/updatedisplay.h index 8fbbbb1..f205043 100644 --- a/src/displays/updatedisplay.h +++ b/src/displays/updatedisplay.h @@ -1,9 +1,9 @@ #pragma once #include +#include #include -#include #include "display.h" #include "actions/switchscreenaction.h" @@ -18,12 +18,12 @@ class StatusDisplay; } namespace { -#ifdef FEATURE_ARDUINOOTA +#if defined(FEATURE_ARDUINOOTA) || defined(FEATURE_WEBOTA) class UpdateDisplay : public Display, public DummyBack { public: - UpdateDisplay(const String &title); - UpdateDisplay(String &&title); + UpdateDisplay(const std::string &title); + UpdateDisplay(std::string &&title); void start() override; void initScreen() override; @@ -38,18 +38,18 @@ public: bool m_errorValid; private: - const String m_title; + const std::string m_title; Label m_progressLabel{20, 150}; ProgressBar m_progressBar{20, 200, 200, 10, 0, 100}; }; -UpdateDisplay::UpdateDisplay(const String &title) : +UpdateDisplay::UpdateDisplay(const std::string &title) : m_title{title} {} -UpdateDisplay::UpdateDisplay(String &&title) : +UpdateDisplay::UpdateDisplay(std::string &&title) : m_title{std::move(title)} {} @@ -67,7 +67,7 @@ void UpdateDisplay::initScreen() tft.setTextFont(4); tft.setTextColor(TFT_YELLOW); - tft.drawString(m_title, 5, 5, 4); + tft.drawString(m_title.c_str(), 5, 5, 4); tft.fillRect(0, 34, tft.width(), 3, TFT_WHITE); @@ -81,7 +81,7 @@ void UpdateDisplay::initScreen() void UpdateDisplay::redraw() { - m_progressLabel.redraw(String{} + m_progress + '/' + m_total); + m_progressLabel.redraw(std::to_string(m_progress) + '/' + std::to_string(m_total)); m_progressBar.redraw(float(m_progress) / m_total * 100.f); } diff --git a/src/dpad.h b/src/dpad.h index 1d0f9da..1430f57 100644 --- a/src/dpad.h +++ b/src/dpad.h @@ -4,8 +4,8 @@ #include -#include "globals.h" #include "types.h" +#include "buttons.h" namespace { namespace dpad diff --git a/src/dpad3wire.h b/src/dpad3wire.h index 8d3efe5..1ee36a7 100644 --- a/src/dpad3wire.h +++ b/src/dpad3wire.h @@ -2,11 +2,9 @@ #include -#include "globals.h" - #include "dpad.h" -#include "globals.h" #include "types.h" +#include "buttons.h" namespace { namespace dpad3wire diff --git a/src/dpad5wire.h b/src/dpad5wire.h index 90e70b5..908e006 100644 --- a/src/dpad5wire.h +++ b/src/dpad5wire.h @@ -1,17 +1,42 @@ #pragma once -#include +#include #include -#include "globals.h" #include "types.h" -#include "actions/switchprofileaction.h" +#include "buttons.h" namespace { -namespace dpad5wire +namespace dpad5wire { +#ifdef FEATURE_DPAD_5WIRESW +class State : public std::array { -using State = std::tuple; +public: + State() : std::array{false, false, false, false, false, false, false, false} {} + State(const std::array &other) : std::array{} {} + + State &operator=(const std::array &other) + { + std::array::operator=(other); + return *this; + } + + State &operator=(const State &other) + { + std::array::operator=(other); + return *this; + } + + bool &up{this->at(DPAD_5WIRESW_UP)}; + bool &down{this->at(DPAD_5WIRESW_DOWN)}; + bool &confirm{this->at(DPAD_5WIRESW_CONFIRM)}; + bool &back{this->at(DPAD_5WIRESW_BACK)}; + bool &profile0{this->at(DPAD_5WIRESW_PROFILE0)}; + bool &profile1{this->at(DPAD_5WIRESW_PROFILE1)}; + bool &profile2{this->at(DPAD_5WIRESW_PROFILE2)}; + bool &profile3{this->at(DPAD_5WIRESW_PROFILE3)}; +}; template class Helper @@ -37,6 +62,8 @@ void Helper::begin() template State Helper::read() { + State result; + digitalWrite(OUT, LOW); pinMode(IN1, INPUT_PULLUP); @@ -46,10 +73,10 @@ State Helper::read() delay(1); - const bool result0 = digitalRead(IN1)==LOW; - const bool result1 = digitalRead(IN2)==LOW; - const bool result2 = digitalRead(IN3)==LOW; - const bool result3 = digitalRead(IN4)==LOW; + result[0] = digitalRead(IN1)==LOW; + result[1] = digitalRead(IN2)==LOW; + result[2] = digitalRead(IN3)==LOW; + result[3] = digitalRead(IN4)==LOW; digitalWrite(OUT, HIGH); @@ -60,15 +87,14 @@ State Helper::read() delay(1); - const bool result4 = digitalRead(IN1); - const bool result5 = digitalRead(IN2); - const bool result6 = digitalRead(IN3); - const bool result7 = digitalRead(IN4); + result[4] = digitalRead(IN1); + result[5] = digitalRead(IN2); + result[6] = digitalRead(IN3); + result[7] = digitalRead(IN4); - return std::make_tuple(result0, result1, result2, result3, result4, result5, result6, result7); + return result; } -#ifdef FEATURE_DPAD_5WIRESW Helper helper; State lastState; millis_t debounceUp, debounceDown, debounceConfirm, debounceBack, debounceProfile0, debounceProfile1, debounceProfile2, debounceProfile3; @@ -81,78 +107,68 @@ void init() void update() { - const auto state = helper.read(); + const auto newState = helper.read(); #ifdef DPAD_5WIRESW_DEBUG - lastState = state; + lastState = newState; return; #endif const auto now = millis(); - if (std::get(lastState) != std::get(state) && now-debounceUp > settings.boardcomputerHardware.dpadDebounce) + if (lastState.up != newState.up && now-debounceUp > settings.boardcomputerHardware.dpadDebounce) { - if (std::get(state)) + if (newState.up) InputDispatcher::rotate(-1); - std::get(lastState) = std::get(state); debounceUp = now; } - if (std::get(lastState) != std::get(state) && now-debounceDown > settings.boardcomputerHardware.dpadDebounce) + + if (lastState.down != newState.down && now-debounceDown > settings.boardcomputerHardware.dpadDebounce) { - if (std::get(state)) + if (newState.down) InputDispatcher::rotate(1); - std::get(lastState) = std::get(state); debounceDown = now; } - if (std::get(lastState) != std::get(state) && now-debounceConfirm > settings.boardcomputerHardware.dpadDebounce) + + if (lastState.confirm != newState.confirm && now-debounceConfirm > settings.boardcomputerHardware.dpadDebounce) { - InputDispatcher::confirmButton(std::get(state)); - std::get(lastState) = std::get(state); + InputDispatcher::confirmButton(std::get(newState)); debounceConfirm = now; } - if (std::get(lastState) != std::get(state) && now-debounceBack > settings.boardcomputerHardware.dpadDebounce) + + if (lastState.back != newState.back && now-debounceBack > settings.boardcomputerHardware.dpadDebounce) { - InputDispatcher::backButton(std::get(state)); - std::get(lastState) = std::get(state); + InputDispatcher::backButton(std::get(newState)); debounceBack = now; } - if (std::get(lastState) != std::get(state) && now-debounceProfile0 > settings.boardcomputerHardware.dpadDebounce) + + if (lastState.profile0 != newState.profile0 && now-debounceProfile0 > settings.boardcomputerHardware.dpadDebounce) { - if (std::get(state)) - { - SwitchProfileAction<0>{}.triggered(); - } - std::get(lastState) = std::get(state); + InputDispatcher::profileButton(0, std::get(newState)); debounceProfile0 = now; } - if (std::get(lastState) != std::get(state) && now-debounceProfile1 > settings.boardcomputerHardware.dpadDebounce) + + if (lastState.profile1 != newState.profile1 && now-debounceProfile1 > settings.boardcomputerHardware.dpadDebounce) { - if (std::get(state)) - { - SwitchProfileAction<1>{}.triggered(); - } - std::get(lastState) = std::get(state); + InputDispatcher::profileButton(1, std::get(newState)); debounceProfile1 = now; } - if (std::get(lastState) != std::get(state) && now-debounceProfile2 > settings.boardcomputerHardware.dpadDebounce) + + if (lastState.profile2 != newState.profile2 && now-debounceProfile2 > settings.boardcomputerHardware.dpadDebounce) { - if (std::get(state)) - { - SwitchProfileAction<2>{}.triggered(); - } - std::get(lastState) = std::get(state); + InputDispatcher::profileButton(2, std::get(newState)); debounceProfile2 = now; } - if (std::get(lastState) != std::get(state) && now-debounceProfile3 > settings.boardcomputerHardware.dpadDebounce) + + if (lastState.profile3 != newState.profile3 && now-debounceProfile3 > settings.boardcomputerHardware.dpadDebounce) { - if (std::get(state)) - { - SwitchProfileAction<3>{}.triggered(); - } - std::get(lastState) = std::get(state); + InputDispatcher::profileButton(3, std::get(newState)); debounceProfile3 = now; } + + lastState = newState; } #endif -} -} + +} // namespace dpad5wire +} // namespace diff --git a/src/feedbackparser.h b/src/feedbackparser.h index 037958e..9b31130 100644 --- a/src/feedbackparser.h +++ b/src/feedbackparser.h @@ -5,7 +5,7 @@ #include -#include "bobbycar-protocol/protocol.h" +#include "bobbycar-protocol/bobbycar-serial.h" #include "types.h" @@ -13,13 +13,15 @@ namespace { class FeedbackParser { public: - FeedbackParser(const std::reference_wrapper &serial, bool &feedbackValid, Feedback &feedback) : + FeedbackParser(const std::reference_wrapper &serial, bool &feedbackValid, bobbycar::protocol::serial::Feedback &feedback) : m_serial{serial}, m_feedbackValid{feedbackValid}, m_feedback{feedback} { } void update() { + using namespace bobbycar::protocol::serial; + // Check for new data availability in the Serial buffer while (m_serial.get().available()) { @@ -83,6 +85,6 @@ private: millis_t m_lastFeedback{millis()}; const std::reference_wrapper &m_serial; bool &m_feedbackValid; - Feedback &m_feedback, m_newFeedback; + bobbycar::protocol::serial::Feedback &m_feedback, m_newFeedback; }; } diff --git a/src/globals.h b/src/globals.h index 8baa4b0..f9a5f6c 100644 --- a/src/globals.h +++ b/src/globals.h @@ -3,6 +3,7 @@ // system includes #include #include +#include // Arduino includes #ifdef FEATURE_BLUETOOTH @@ -21,8 +22,9 @@ #include "types.h" namespace { -int16_t raw_gas, raw_brems; -float gas, brems; +std::optional raw_gas, raw_brems; +std::optional gas, brems; + #ifdef FEATURE_GAMETRAK int16_t raw_gametrakX, raw_gametrakY, raw_gametrakDist; float gametrakX, gametrakY, gametrakDist; @@ -41,8 +43,18 @@ class Controllers : public std::array public: explicit Controllers() : std::array{{ - Controller{Serial1, settings.controllerHardware.enableFrontLeft, settings.controllerHardware.enableFrontRight, settings.controllerHardware.invertFrontLeft, settings.controllerHardware.invertFrontRight}, - Controller{Serial2, settings.controllerHardware.enableBackLeft, settings.controllerHardware.enableBackRight, settings.controllerHardware.invertBackLeft, settings.controllerHardware.invertBackRight} + Controller { +#ifdef FEATURE_SERIAL + Serial1, +#endif + settings.controllerHardware.enableFrontLeft, settings.controllerHardware.enableFrontRight, settings.controllerHardware.invertFrontLeft, settings.controllerHardware.invertFrontRight + }, + Controller { +#ifdef FEATURE_SERIAL + Serial2, +#endif + settings.controllerHardware.enableBackLeft, settings.controllerHardware.enableBackRight, settings.controllerHardware.invertBackLeft, settings.controllerHardware.invertBackRight + } }} {} @@ -72,64 +84,4 @@ TFT_eSPI tft = TFT_eSPI(); ModeInterface *currentMode{}; std::unique_ptr currentDisplay; - -int rotated{}; -bool requestFullRedraw{}; -bool confirmButtonPressed{}; -bool confirmButtonLongPressed{}; -bool backButtonPressed{}; -bool backButtonLongPressed{}; - -class InputDispatcher -{ -public: - static void rotate(int offset) - { - rotated += offset; - } - - static void confirmButton(bool pressed) - { - static millis_t pressBegin = 0; - - const auto now = millis(); - - if (pressed) - pressBegin = now; - else - { - const auto duration = now - pressBegin; - - if (duration < 500) - confirmButtonPressed = true; - else if (duration < 2000) - confirmButtonLongPressed = true; - else - requestFullRedraw = true; - - pressBegin = 0; - } - } - - static void backButton(bool pressed) - { - static millis_t pressBegin = 0; - - const auto now = millis(); - - if (pressed) - pressBegin = now; - else - { - const auto duration = now - pressBegin; - - if (duration < 500) - backButtonPressed = true; - else - backButtonLongPressed = true; - - pressBegin = 0; - } - } -}; } diff --git a/src/htmlutils.h b/src/htmlutils.h index cf1ba2d..aeb7539 100644 --- a/src/htmlutils.h +++ b/src/htmlutils.h @@ -10,7 +10,7 @@ void breakLine(AsyncResponseStream &stream) void label(AsyncResponseStream &stream, const char *name, const char *text) { - HtmlTag label(stream, "label", String(" for=\"") + name + "\""); + HtmlTag label(stream, "label", std::string(" for=\"") + name + "\""); stream.print(text); } @@ -78,7 +78,7 @@ void checkboxInput(AsyncResponseStream &stream, bool value, const char *name, co void selectOption(AsyncResponseStream &stream, const char *value, const char *text, bool selected) { - String str{" value=\""}; + std::string str{" value=\""}; str += value; str += "\""; diff --git a/src/main.cpp b/src/main.cpp index 67d0328..4be24eb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,7 +12,8 @@ #include #include -#include "bobbycar-protocol/protocol.h" +#include "bobbycar-protocol/bobbycar-common.h" +#include "bobbycar-protocol/bobbycar-serial.h" #include "globals.h" #include "modes/defaultmode.h" @@ -62,6 +63,7 @@ #include "displays/metersdisplay.h" #include "displays/pingpongdisplay.h" #include "displays/poweroffdisplay.h" +#include "displays/powersupplydisplay.h" #include "displays/spirodisplay.h" #include "displays/starfielddisplay.h" #include "displays/statusdisplay.h" @@ -83,6 +85,9 @@ #endif #include "bobby_webserver.h" #include "types.h" +#ifdef FEATURE_CAN +#include "can.h" +#endif namespace { ModeInterface *lastMode{}; @@ -105,7 +110,7 @@ void printMemoryStats(const char *s) void cloudTask(void*) { const esp_websocket_client_config_t config = { - .uri = "--REMOVED--", + .uri = "ws://iot.wattpilot.io:8080/charger/bobbycar1", }; esp_websocket_client_handle_t handle = esp_websocket_client_init(&config); @@ -121,35 +126,35 @@ void cloudTask(void*) { if (esp_websocket_client_is_connected(handle)) { - String msg = "{" + std::string msg = "{" "\"type\": \"fullStatus\"," "\"partial\": false, " "\"status\": {" - "\"millis\":" + String{millis()} + "," + "\"millis\":" + std::to_string(millis()) + "," "\"front.valid\":" + (controllers.front.feedbackValid?"true":"false") + "," "\"back.valid\":" + (controllers.back.feedbackValid?"true":"false") + "," - "\"front.left.pwm\":" + String(controllers.front.command.left.pwm) + "," - "\"front.right.pwm\":" + String(controllers.front.command.right.pwm) + "," - "\"back.left.pwm\":" + String(controllers.back.command.left.pwm) + "," - "\"back.right.pwm\":" + String(controllers.back.command.right.pwm) + "," - "\"front.volt\":" + String(controllers.front.feedback.batVoltage) + "," - "\"back.volt\":" + String(controllers.back.feedback.batVoltage) + "," - "\"front.temp\":" + String(controllers.front.feedback.boardTemp) + "," - "\"back.temp\":" + String(controllers.back.feedback.boardTemp) + "," - "\"front.bad\":" + String(controllers.front.feedback.timeoutCntSerial) + "," - "\"back.bad\":" + String(controllers.back.feedback.timeoutCntSerial) + "," - "\"front.left.speed\":" + String(controllers.front.feedback.left.speed) + "," - "\"front.right.speed\":" + String(controllers.front.feedback.right.speed) + "," - "\"back.left.speed\":" + String(controllers.back.feedback.left.speed) + "," - "\"back.right.speed\":" + String(controllers.back.feedback.right.speed) + "," - "\"front.left.current\":" + String(controllers.front.feedback.left.current) + "," - "\"front.right.current\":" + String(controllers.front.feedback.right.current) + "," - "\"back.left.current\":" + String(controllers.back.feedback.left.current) + "," - "\"back.right.current\":" + String(controllers.back.feedback.right.current) + "," - "\"front.left.error\":" + String(controllers.front.feedback.left.error) + "," - "\"front.right.error\":" + String(controllers.front.feedback.right.error) + "," - "\"back.left.error\":" + String(controllers.back.feedback.left.error) + "," - "\"back.right.error\":" + String(controllers.back.feedback.right.error) + + "\"front.left.pwm\":" + std::to_string(controllers.front.command.left.pwm) + "," + "\"front.right.pwm\":" + std::to_string(controllers.front.command.right.pwm) + "," + "\"back.left.pwm\":" + std::to_string(controllers.back.command.left.pwm) + "," + "\"back.right.pwm\":" + std::to_string(controllers.back.command.right.pwm) + "," + "\"front.volt\":" + std::to_string(controllers.front.feedback.batVoltage) + "," + "\"back.volt\":" + std::to_string(controllers.back.feedback.batVoltage) + "," + "\"front.temp\":" + std::to_string(controllers.front.feedback.boardTemp) + "," + "\"back.temp\":" + std::to_string(controllers.back.feedback.boardTemp) + "," + "\"front.bad\":" + std::to_string(controllers.front.feedback.timeoutCntSerial) + "," + "\"back.bad\":" + std::to_string(controllers.back.feedback.timeoutCntSerial) + "," + "\"front.left.speed\":" + std::to_string(controllers.front.feedback.left.speed) + "," + "\"front.right.speed\":" + std::to_string(controllers.front.feedback.right.speed) + "," + "\"back.left.speed\":" + std::to_string(controllers.back.feedback.left.speed) + "," + "\"back.right.speed\":" + std::to_string(controllers.back.feedback.right.speed) + "," + "\"front.left.current\":" + std::to_string(controllers.front.feedback.left.current) + "," + "\"front.right.current\":" + std::to_string(controllers.front.feedback.right.current) + "," + "\"back.left.current\":" + std::to_string(controllers.back.feedback.left.current) + "," + "\"back.right.current\":" + std::to_string(controllers.back.feedback.right.current) + "," + "\"front.left.error\":" + std::to_string(controllers.front.feedback.left.error) + "," + "\"front.right.error\":" + std::to_string(controllers.front.feedback.right.error) + "," + "\"back.left.error\":" + std::to_string(controllers.back.feedback.left.error) + "," + "\"back.right.error\":" + std::to_string(controllers.back.feedback.right.error) + "}" "}"; @@ -162,7 +167,7 @@ void cloudTask(void*) else Serial.println("Not sending cloud because not connected"); - delay(1000); + delay(100); } } else @@ -181,6 +186,11 @@ void setup() Serial.setDebugOutput(true); //Serial.println("setup()"); +#ifdef PINS_LED + pinMode(PINS_LED, OUTPUT); + digitalWrite(PINS_LED, LOW); +#endif + printMemoryStats("setup()"); pinMode(3, INPUT_PULLUP); @@ -233,9 +243,11 @@ void setup() } printMemoryStats("loadSettings()"); +#ifdef FEATURE_SERIAL bootLabel.redraw("swap front back"); updateSwapFrontBack(); printMemoryStats("swapFronBack()"); +#endif bootLabel.redraw("deviceName"); { @@ -295,16 +307,22 @@ void setup() } #endif +#ifdef FEATURE_CAN + can::initCan(); +#endif + +#ifdef FEATURE_SERIAL bootLabel.redraw("front Serial begin"); controllers.front.serial.get().begin(38400, SERIAL_8N1, PINS_RX1, PINS_TX1); bootLabel.redraw("back Serial begin"); controllers.back.serial.get().begin(38400, SERIAL_8N1, PINS_RX2, PINS_TX2); +#endif - raw_gas = 0; - raw_brems = 0; - gas = 0; - brems = 0; + raw_gas = std::nullopt; + raw_brems = std::nullopt; + gas = std::nullopt; + brems = std::nullopt; for (Controller &controller : controllers) controller.command.buzzer = {}; @@ -317,9 +335,11 @@ void setup() printMemoryStats("initOta()"); #endif +#ifdef FEATURE_WEBSERVER bootLabel.redraw("webserver"); initWebserver(); printMemoryStats("initWebserver()"); +#endif bootLabel.redraw("potis"); readPotis(); @@ -337,7 +357,7 @@ void setup() return; #endif - if (gas > 200.f || brems > 200.f) + if (!gas || !brems || *gas > 200.f || *brems > 200.f) switchScreen(true); else switchScreen(); @@ -418,8 +438,14 @@ void loop() performance.lastTime = now; } +#ifdef FEATURE_CAN + can::parseCanInput(); +#endif + +#ifdef FEATURE_SERIAL for (Controller &controller : controllers) controller.parser.update(); +#endif handleSerial(); diff --git a/src/modeinterface.h b/src/modeinterface.h index 1d0c97f..398e02d 100644 --- a/src/modeinterface.h +++ b/src/modeinterface.h @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace { class ModeInterface { diff --git a/src/modes/defaultmode.h b/src/modes/defaultmode.h index f4756e4..ff10507 100644 --- a/src/modes/defaultmode.h +++ b/src/modes/defaultmode.h @@ -31,64 +31,81 @@ DefaultMode defaultMode; void DefaultMode::update() { - if (waitForGasLoslass) + if (!gas || !brems) { - if (gas < 50) - waitForGasLoslass = false; - else - gas = 0; - } + start(); - if (waitForBremsLoslass) - { - if (brems < 50) - waitForBremsLoslass = false; - else - brems = 0; - } - - const auto gas_processed = settings.defaultMode.squareGas ? (gas * gas) / 1000.f : gas; - const auto brems_processed = settings.defaultMode.squareBrems ? (brems * brems) / 1000 : brems; - - const auto now = millis(); - - 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.enableSmoothing && (pwm > 1000. || lastPwm > 1000.)) + for (bobbycar::protocol::serial::MotorState &motor : motors()) { - if (lastPwm < pwm) - { - pwm = std::min(pwm, lastPwm+(settings.defaultMode.smoothing*(now-lastTime)/100.f)); - if (pwm < 1000.) - pwm = 1000.; - } - else if (lastPwm > pwm) - { - pwm = std::max(pwm, lastPwm-(settings.defaultMode.smoothing*(now-lastTime)/100.f)); - } + motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; + motor.ctrlMod = bobbycar::protocol::ControlMode::OpenMode; + motor.pwm = 0; } } else - pwm = (gas_processed/1000.*settings.defaultMode.gas2_wert) - (brems_processed/1000.*settings.defaultMode.brems2_wert); - - lastPwm = pwm; - lastTime = now; - - const auto pair = split(settings.defaultMode.modelMode); - for (MotorState &motor : motorsInController(controllers.front)) { - motor.ctrlTyp = pair.first; - motor.ctrlMod = pair.second; - motor.pwm = pwm / 100. * settings.defaultMode.frontPercentage; - } - for (MotorState &motor : motorsInController(controllers.back)) - { - motor.ctrlTyp = pair.first; - motor.ctrlMod = pair.second; - motor.pwm = pwm / 100. * settings.defaultMode.backPercentage; + 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 = millis(); + + 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.enableSmoothing && (pwm > 1000. || lastPwm > 1000.)) + { + if (lastPwm < pwm) + { + pwm = std::min(pwm, lastPwm+(settings.defaultMode.smoothing*(now-lastTime)/100.f)); + if (pwm < 1000.) + pwm = 1000.; + } + else if (lastPwm > pwm) + { + pwm = std::max(pwm, lastPwm-(settings.defaultMode.smoothing*(now-lastTime)/100.f)); + } + } + } + else + pwm = (gas_processed/1000.*settings.defaultMode.gas2_wert) - (brems_processed/1000.*settings.defaultMode.brems2_wert); + + lastPwm = pwm; + lastTime = now; + + const auto pair = split(settings.defaultMode.modelMode); + for (bobbycar::protocol::serial::MotorState &motor : motorsInController(controllers.front)) + { + motor.ctrlTyp = pair.first; + motor.ctrlMod = pair.second; + motor.pwm = pwm / 100. * settings.defaultMode.frontPercentage; + } + for (bobbycar::protocol::serial::MotorState &motor : motorsInController(controllers.back)) + { + motor.ctrlTyp = pair.first; + motor.ctrlMod = pair.second; + motor.pwm = pwm / 100. * settings.defaultMode.backPercentage; + } } fixCommonParams(); diff --git a/src/modes/gametrakmode.h b/src/modes/gametrakmode.h index 959619b..2287280 100644 --- a/src/modes/gametrakmode.h +++ b/src/modes/gametrakmode.h @@ -14,7 +14,7 @@ constexpr const T& clamp( const T& v, const T& lo, const T& hi ) #include "utils.h" #include "defaultmode.h" -#include "bobbycar-protocol/protocol.h" +#include "bobbycar-protocol/bobbycar-common.h" namespace { #ifdef FEATURE_GAMETRAK @@ -41,36 +41,50 @@ void GametrakMode::start() void GametrakMode::update() { - if (gas > 500. || brems > 500.) + if (!gas || !brems) { - modes::defaultMode.waitForGasLoslass = true; - modes::defaultMode.waitForBremsLoslass = true; - currentMode = &modes::defaultMode; - return; - } + start(); - int16_t pwm; - if (gametrakDist < 150) - { - pwm = 0; - m_flag = false; + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; + motor.ctrlMod = bobbycar::protocol::ControlMode::OpenMode; + motor.pwm = 0; + } } else { - if (m_flag || gametrakDist >= 400) + if (*gas > 500. || *brems > 500.) { - m_flag = true; - pwm = clamp((gametrakDist - 400) / 2, -200, 200); + modes::defaultMode.waitForGasLoslass = true; + modes::defaultMode.waitForBremsLoslass = true; + currentMode = &modes::defaultMode; + return; + } + + int16_t pwm; + if (gametrakDist < 150) + { + pwm = 0; + m_flag = false; } else - pwm = 0; - } + { + if (m_flag || gametrakDist >= 400) + { + m_flag = true; + pwm = clamp((gametrakDist - 400) / 2, -200, 200); + } + else + pwm = 0; + } - for (MotorState &motor : motors()) - { - motor.ctrlTyp = ControlType::FieldOrientedControl; - motor.ctrlMod = ControlMode::Speed; - motor.pwm = pwm; + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; + motor.ctrlMod = bobbycar::protocol::ControlMode::Speed; + motor.pwm = pwm; + } } fixCommonParams(); diff --git a/src/modes/ignoreinputmode.h b/src/modes/ignoreinputmode.h index ca5343b..f22b4c0 100644 --- a/src/modes/ignoreinputmode.h +++ b/src/modes/ignoreinputmode.h @@ -4,13 +4,13 @@ #include "globals.h" #include "utils.h" -#include "bobbycar-protocol/protocol.h" +#include "bobbycar-protocol/bobbycar-common.h" namespace { class IgnoreInputMode : public ModeInterface { public: - IgnoreInputMode(int16_t pwm, ControlType ctrlTyp, ControlMode ctrlMod) : + IgnoreInputMode(int16_t pwm, bobbycar::protocol::ControlType ctrlTyp, bobbycar::protocol::ControlMode ctrlMod) : m_pwm{pwm}, m_ctrlTyp{ctrlTyp}, m_ctrlMod{ctrlMod} { } @@ -21,13 +21,13 @@ public: private: const int16_t m_pwm; - const ControlType m_ctrlTyp; - const ControlMode m_ctrlMod; + const bobbycar::protocol::ControlType m_ctrlTyp; + const bobbycar::protocol::ControlMode m_ctrlMod; }; void IgnoreInputMode::update() { - for (MotorState &motor : motors()) + for (bobbycar::protocol::serial::MotorState &motor : motors()) { motor.ctrlTyp = m_ctrlTyp; motor.ctrlMod = m_ctrlMod; diff --git a/src/modes/larsmmode.h b/src/modes/larsmmode.h index 269f62e..9ede112 100644 --- a/src/modes/larsmmode.h +++ b/src/modes/larsmmode.h @@ -4,7 +4,7 @@ #include "globals.h" #include "utils.h" -#include "bobbycar-protocol/protocol.h" +#include "bobbycar-protocol/bobbycar-common.h" namespace { class LarsmMode : public ModeInterface @@ -36,72 +36,86 @@ void LarsmMode::start() void LarsmMode::update() { - for (uint8_t i = 0; i < settings.larsmMode.iterations; i++) // run multiple times to emulate higher refreshrate + if (!gas || !brems) { - // ####### larsm's bobby car code ####### + start(); - // 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 + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; + motor.ctrlMod = bobbycar::protocol::ControlMode::OpenMode; + motor.pwm = 0; + } + } + else + { + for (uint8_t i = 0; i < settings.larsmMode.iterations; i++) // run multiple times to emulate higher refreshrate + { + // ####### larsm's bobby car code ####### - // 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. + // 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 - #define ADC1_MIN 0 - #define ADC2_MIN 0 - #define ADC1_MAX 1000 - #define ADC2_MAX 1000 + // 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 ADC2_DELTA (ADC2_MAX - ADC2_MIN) - #define ADC1_DELTA (ADC1_MAX - ADC1_MIN) + #define ADC1_MIN 0 + #define ADC2_MIN 0 + #define ADC1_MAX 1000 + #define ADC2_MAX 1000 - #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) + #define ADC2_DELTA (ADC2_MAX - ADC2_MIN) + #define ADC1_DELTA (ADC1_MAX - ADC1_MIN) - 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; + #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) - } 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; + 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::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::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::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!! + } 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 } - speed = CLAMP(speed, -1000, 1000); // clamp output - } - - for (MotorState &motor : motors()) - { - const auto pair = split(settings.larsmMode.modelMode); - motor.ctrlTyp = pair.first; - motor.ctrlMod = pair.second; - motor.pwm = speed + weak; + 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; + } } fixCommonParams(); diff --git a/src/modes/tempomatmode.h b/src/modes/tempomatmode.h index e8ef9c9..81dcff2 100644 --- a/src/modes/tempomatmode.h +++ b/src/modes/tempomatmode.h @@ -2,7 +2,7 @@ #include -#include "bobbycar-protocol/protocol.h" +#include "bobbycar-protocol/bobbycar-common.h" #include "modeinterface.h" #include "globals.h" @@ -32,23 +32,37 @@ void TempomatMode::start() void TempomatMode::update() { - if (gas > 500. && brems > 500.) + if (!gas || !brems) { - pwm = 0; - modes::defaultMode.waitForGasLoslass = true; - modes::defaultMode.waitForBremsLoslass = true; - currentMode = &modes::defaultMode; - return; + start(); + + for (bobbycar::protocol::serial::MotorState &motor : motors()) + { + motor.ctrlTyp = bobbycar::protocol::ControlType::FieldOrientedControl; + motor.ctrlMod = bobbycar::protocol::ControlMode::OpenMode; + motor.pwm = 0; + } } - - pwm += (gas/1000.) - (brems/1000.); - - for (MotorState &motor : motors()) + else { - const auto pair = split(settings.tempomatMode.modelMode); - motor.ctrlTyp = pair.first; - motor.ctrlMod = pair.second; - motor.pwm = pwm; + if (*gas > 500. && *brems > 500.) + { + pwm = 0; + modes::defaultMode.waitForGasLoslass = true; + modes::defaultMode.waitForBremsLoslass = true; + currentMode = &modes::defaultMode; + return; + } + + pwm += (*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 = pwm; + } } fixCommonParams(); diff --git a/src/ota.h b/src/ota.h index a27494a..65712e2 100644 --- a/src/ota.h +++ b/src/ota.h @@ -14,14 +14,13 @@ void initOta() { ArduinoOTA .onStart([]() { - String type; - if (ArduinoOTA.getCommand() == U_FLASH) - type = "sketch"; - else if (ArduinoOTA.getCommand() == U_SPIFFS) // U_SPIFFS - type = "filesystem"; - else - type = "unknown"; - + std::string type; + switch (ArduinoOTA.getCommand()) + { + case U_FLASH: type = "sketch"; break; + case U_SPIFFS: type = "filesystem"; break; + default: type = "unknown"; + } switchScreenImpl("Updating " + type); }) .onEnd([]() { diff --git a/src/serialhandler.h b/src/serialhandler.h index aab936d..072f2d4 100644 --- a/src/serialhandler.h +++ b/src/serialhandler.h @@ -17,7 +17,7 @@ void handleSerial() if (last_status != status) { Serial.print("Status changed to: "); - Serial.println(toString(status)); + Serial.println(to_string(status).c_str()); last_status = status; } @@ -25,7 +25,7 @@ void handleSerial() if (last_ip != ip) { Serial.print("IP changed to: "); - Serial.println(ip.toString()); + Serial.println(to_string(ip).c_str()); last_ip = ip; } diff --git a/src/settings.h b/src/settings.h index 10cf3a0..2c2ea53 100644 --- a/src/settings.h +++ b/src/settings.h @@ -4,7 +4,7 @@ #include -#include "bobbycar-protocol/protocol.h" +#include "bobbycar-protocol/bobbycar-common.h" #ifdef FEATURE_BLUETOOTH #include "bluetoothmode.h" diff --git a/src/settingsaccessors.h b/src/settingsaccessors.h index 7d2aa23..5f38cb9 100644 --- a/src/settingsaccessors.h +++ b/src/settingsaccessors.h @@ -58,7 +58,9 @@ struct WheelDiameterInchAccessor : public virtual AccessorInterface struct NumMagnetPolesAccessor : public RefAccessorSaveSettings { int16_t &getRef() const override { return settings.controllerHardware.numMagnetPoles; } }; struct SwapFrontBackAccessor : public RefAccessorSaveSettings { bool &getRef() const override { return settings.controllerHardware.swapFrontBack; } +#ifdef FEATURE_SERIAL void setValue(bool value) override { RefAccessorSaveSettings::setValue(value); updateSwapFrontBack(); }; +#endif }; struct SampleCountAccessor : public RefAccessorSaveSettings { int16_t &getRef() const override { return settings.boardcomputerHardware.sampleCount; } }; diff --git a/src/settingspersister.h b/src/settingspersister.h index 6d42e66..e6720b6 100644 --- a/src/settingspersister.h +++ b/src/settingspersister.h @@ -1,13 +1,12 @@ #pragma once #include +#include #include #include #include -#include - #include "settings.h" #ifdef FEATURE_BLUETOOTH #include "bluetoothmode.h" @@ -78,7 +77,7 @@ bool SettingsPersister::openProfile(uint8_t index) closeProfile(); nvs_handle handle; - esp_err_t err = nvs_open((String{"bobbycar"}+index).c_str(), NVS_READWRITE, &handle); + esp_err_t err = nvs_open(("bobbycar"+std::to_string(index)).c_str(), NVS_READWRITE, &handle); if (err != ESP_OK) { Serial.printf("nvs_open() returned: %s\r\n", esp_err_to_name(err)); @@ -115,20 +114,20 @@ template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle ha *out_value = tempValue; return err; }}; -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, ControlType* out_value) +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 = ControlType(tempValue); + *out_value = bobbycar::protocol::ControlType(tempValue); return err; }}; -template<> struct nvsGetterHelper { static esp_err_t nvs_get(nvs_handle handle, const char* key, ControlMode* out_value) +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 = ControlMode(tempValue); + *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) @@ -197,11 +196,11 @@ template<> struct nvsSetterHelper { static constexpr auto nvs_set = &n 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, ControlType value) +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, ControlMode 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)); }}; diff --git a/src/settingsutils.h b/src/settingsutils.h new file mode 100644 index 0000000..d4e285b --- /dev/null +++ b/src/settingsutils.h @@ -0,0 +1,23 @@ +#pragma once + +// Arduino includes +#include + +// local includes +#include "globals.h" +#include "presets.h" + +namespace { +void switchProfile(uint8_t index) +{ + settings = presets::defaultSettings; + + if (settingsPersister.openProfile(index)) + { + if (!settingsPersister.load(settings)) + Serial.println("switchProfile() load failed"); + } + else + Serial.println("switchProfile() openProfile failed"); +} +} diff --git a/src/statistics.h b/src/statistics.h index d920bd1..5313fe7 100644 --- a/src/statistics.h +++ b/src/statistics.h @@ -18,22 +18,24 @@ ContainerType gas, brems, avgSpeed, avgSpeedKmh, sumCurrent, frontVoltage, backV void pushStats() { - statistics::gas.push_back(gas); - statistics::brems.push_back(brems); + if (gas) + statistics::gas.push_back(*gas); + if (brems) + statistics::brems.push_back(*brems); statistics::avgSpeed.push_back(avgSpeed); statistics::avgSpeedKmh.push_back(avgSpeedKmh); statistics::sumCurrent.push_back(sumCurrent); if (controllers.front.feedbackValid) { statistics::frontVoltage.push_back(fixBatVoltage(controllers.front.feedback.batVoltage)); - statistics::frontLeftCurrent.push_back(fixCurrent(controllers.front.feedback.left.current)); - statistics::frontRightCurrent.push_back(fixCurrent(controllers.front.feedback.right.current)); + statistics::frontLeftCurrent.push_back(fixCurrent(controllers.front.feedback.left.dcLink)); + statistics::frontRightCurrent.push_back(fixCurrent(controllers.front.feedback.right.dcLink)); } if (controllers.back.feedbackValid) { statistics::backVoltage.push_back(fixBatVoltage(controllers.back.feedback.batVoltage)); - statistics::backLeftCurrent.push_back(fixCurrent(controllers.back.feedback.left.current)); - statistics::backRightCurrent.push_back(fixCurrent(controllers.back.feedback.right.current)); + statistics::backLeftCurrent.push_back(fixCurrent(controllers.back.feedback.left.dcLink)); + statistics::backRightCurrent.push_back(fixCurrent(controllers.back.feedback.right.dcLink)); } #ifdef FEATURE_BMS statistics::bmsVoltage.push_back(bms::voltage); diff --git a/src/textinterface.h b/src/textinterface.h index 5b9d235..a8d9321 100644 --- a/src/textinterface.h +++ b/src/textinterface.h @@ -1,11 +1,13 @@ #pragma once -#include +#include + +#include "utils.h" namespace { class TextInterface { public: - virtual String text() const = 0; + virtual std::string text() const = 0; }; template @@ -14,31 +16,32 @@ class StaticText : public virtual TextInterface public: static constexpr const char *STATIC_TEXT = Ttext; - String text() const override { return Ttext; } + std::string text() const override { return Ttext; } }; class ChangeableText : public virtual TextInterface { public: - String text() const override { return m_title; } - void setTitle(const String &title) { m_title = title; } + std::string text() const override { return m_title; } + void setTitle(std::string &&title) { m_title = std::move(title); } + void setTitle(const std::string &title) { m_title = title; } private: - String m_title; + std::string m_title; }; template class StatusTextHelper : public virtual TextInterface { public: - String text() const override { return String{Ttext} + (Tptr->*Tmethod)(); } + std::string text() const override { using std::to_string; using ::to_string; return Ttext + to_string((Tptr->*Tmethod)()); } }; template class CachedText : public virtual T { public: - String text() const override + std::string text() const override { if (!m_loaded) { @@ -51,14 +54,14 @@ public: private: mutable bool m_loaded{}; - mutable String m_text; + mutable std::string m_text; }; template class StaticallyCachedText : public virtual T { public: - String text() const override + std::string text() const override { static const auto text = T::text(); return text; diff --git a/src/texts.h b/src/texts.h index e9b36a1..e81a5f0 100644 --- a/src/texts.h +++ b/src/texts.h @@ -130,13 +130,13 @@ constexpr char TEXT_REVERSEBEEPDURATION1[] = "Reverse beep duration1"; //constexpr char TEXT_BACK[] = "Back"; //LimitsSettingsMenu -//constexpr char TEXT_LIMITSSETTINGS[] = "Common settings"; -constexpr char TEXT_SETIMOTMAX[] = "Set iMotMax"; -constexpr char TEXT_SETIDCMAX[] = "Set iDcMax"; -constexpr char TEXT_SETNMOTMAXKMH[] = "Set nMotMax (kmh)"; -constexpr char TEXT_SETNMOTMAX[] = "Set nMotMax"; -constexpr char TEXT_SETFIELDWEAKMAX[] = "Set fieldWeakMax"; -constexpr char TEXT_SETPHASEADVMAX[] = "Set phaseAdvMax"; +//constexpr char TEXT_LIMITSSETTINGS[] = "Limit settings"; +constexpr char TEXT_IMOTMAX[] = "iMotMax"; +constexpr char TEXT_IDCMAX[] = "iDcMax"; +constexpr char TEXT_NMOTMAXKMH[] = "nMotMaxKmh"; +constexpr char TEXT_NMOTMAX[] = "nMotMax"; +constexpr char TEXT_FIELDWEAKMAX[] = "fldWkMax"; +constexpr char TEXT_PHASEADVMAX[] = "phsAdvMax"; //constexpr char TEXT_BACK[] = "Back"; //DebugMenu @@ -363,4 +363,8 @@ constexpr char TEXT_WIFI_POWER_5dBm[] = "5dBm"; constexpr char TEXT_WIFI_POWER_2dBm[] = "2dBm"; constexpr char TEXT_WIFI_POWER_MINUS_1dBm[] = "-1dBm"; //constexpr char TEXT_BACK[] = "Back"; + +#ifdef FEATURE_CAN +constexpr char TEXT_POWERSUPPLY[] = "Powersupply"; +#endif } diff --git a/src/unifiedmodelmode.h b/src/unifiedmodelmode.h index 8aae672..e402ce2 100644 --- a/src/unifiedmodelmode.h +++ b/src/unifiedmodelmode.h @@ -4,7 +4,7 @@ #include -#include "bobbycar-protocol/protocol.h" +#include "bobbycar-protocol/bobbycar-common.h" namespace { enum class UnifiedModelMode : uint8_t @@ -16,8 +16,11 @@ enum class UnifiedModelMode : uint8_t FocTorque }; -std::pair split(UnifiedModelMode mode) +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); diff --git a/src/utils.h b/src/utils.h index dbfaffc..fe8184f 100644 --- a/src/utils.h +++ b/src/utils.h @@ -2,13 +2,26 @@ #include #include +#include + +#include #include -#include #include +#include + +#ifdef FEATURE_CAN +#include "bobbycar-protocol/bobbycar-can.h" +#endif +#ifdef FEATURE_SERIAL +#include "bobbycar-protocol/bobbycar-serial.h" +#endif #include "display.h" #include "globals.h" +#ifdef FEATURE_CAN +#include "can.h" +#endif // macros are a shit piece of software #define STRING2(s) #s @@ -79,50 +92,42 @@ float fixBoardTemp(int16_t value) return value/10.; } -String hallString(const MotorFeedback &motor) +std::string hallString(const bobbycar::protocol::serial::MotorFeedback &motor) { - return String{} + (motor.hallA ? '1' : '0') + (motor.hallB ? '1' : '0') + (motor.hallC ? '1' : '0'); + return std::string{} + (motor.hallA ? '1' : '0') + (motor.hallB ? '1' : '0') + (motor.hallC ? '1' : '0'); } -template -String toString(T value) +std::string to_string(const String &value) { - return String{} + value; + return std::string{value.c_str(), value.length()}; } -template<> -String toString(bool value) -{ - return value ? "true" : "false"; -} - -template<> -String toString(ControlType value) +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 String("Unknown: ") + int(value); + return "Unknown ControlType(" + std::to_string(int(value)) + ')'; } -template<> -String toString(ControlMode 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 String("Unknown: ") + int(value); + return "Unknown ControlMode(" + std::to_string(int(value)) + ')'; } -template<> -String toString(wl_status_t value) +std::string to_string(wl_status_t value) { switch (value) { @@ -136,11 +141,10 @@ String toString(wl_status_t value) case WL_DISCONNECTED: return "WL_DISCONNECTED"; } - return String("Unknown: ") + int(value); + return "Unknown wl_status_t(" + std::to_string(int(value)) + ')'; } -template<> -String toString(ota_error_t value) +std::string to_string(ota_error_t value) { switch (value) { @@ -151,30 +155,40 @@ String toString(ota_error_t value) case OTA_END_ERROR: return "OTA_END_ERROR"; } - return String("Unknown: ") + int(value); + return "Unknown ota_error_t(" + std::to_string(int(value)) + ')'; } -std::array, 2> motorsInController(Controller &controller) +std::string to_string(IPAddress value) +{ + return to_string(value.toString()); +} + +std::string to_string(IPv6Address value) +{ + return to_string(value.toString()); +} + +std::array, 2> motorsInController(Controller &controller) { return {std::ref(controller.command.left), std::ref(controller.command.right)}; } -std::array, 2> motorsInController(const Controller &controller) +std::array, 2> motorsInController(const Controller &controller) { return {std::ref(controller.command.left), std::ref(controller.command.right)}; } -std::array, 2> motorFeedbacksInController(Controller &controller) +std::array, 2> motorFeedbacksInController(Controller &controller) { return {std::ref(controller.feedback.left), std::ref(controller.feedback.right)}; } -std::array, 2> motorFeedbacksInController(const Controller &controller) +std::array, 2> motorFeedbacksInController(const Controller &controller) { return {std::ref(controller.feedback.left), std::ref(controller.feedback.right)}; } -std::array, 4> motors() +std::array, 4> motors() { return { std::ref(controllers.front.command.left), std::ref(controllers.front.command.right), @@ -184,7 +198,7 @@ std::array, 4> motors() void fixCommonParams() { - for (MotorState &motor : motors()) + for (bobbycar::protocol::serial::MotorState &motor : motors()) { motor.iMotMax = settings.limits.iMotMax; motor.iDcMax = settings.limits.iDcMax; @@ -196,7 +210,7 @@ void fixCommonParams() if (settings.reverseBeep) { const auto x = motors(); - const auto shouldBeep = std::all_of(std::begin(x), std::end(x), [](const MotorState &motor){ return motor.pwm < 0; }); + 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) { @@ -247,22 +261,30 @@ 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)); } +#endif +#ifdef FEATURE_CAN + can::sendCanCommands(); +#endif } template void switchScreen(Args&&... args); +#ifdef FEATURE_SERIAL void updateSwapFrontBack() { controllers.front.serial = settings.controllerHardware.swapFrontBack ? Serial2 : Serial1; controllers.back.serial = settings.controllerHardware.swapFrontBack ? Serial1 : Serial2; } +#endif void loadSettings() { @@ -290,8 +312,8 @@ void updateAccumulators() controller.feedback.right.speed * (controller.invertRight ? -1 : 1); sumCurrent += - controller.feedback.left.current + - controller.feedback.right.current; + controller.feedback.left.dcLink + + controller.feedback.right.dcLink; count +=2; } @@ -305,20 +327,55 @@ void updateAccumulators() } void readPotis() -{ - const auto sampleMultipleTimes = [](int pin){ +{ + [[maybe_unused]] + constexpr auto sampleMultipleTimes = [](int pin){ analogRead(pin); double sum{}; - for (int i = 0; i < settings.boardcomputerHardware.sampleCount; i++) + const auto sampleCount = settings.boardcomputerHardware.sampleCount; + for (int i = 0; i < sampleCount; i++) sum += analogRead(pin); - return sum/settings.boardcomputerHardware.sampleCount; + return sum / sampleCount; }; - raw_gas = sampleMultipleTimes(PINS_GAS); - gas = scaleBetween(raw_gas, settings.boardcomputerHardware.gasMin, settings.boardcomputerHardware.gasMax, 0., 1000.); + raw_gas = std::nullopt; + raw_brems = std::nullopt; - raw_brems = sampleMultipleTimes(PINS_BREMS); - brems = scaleBetween(raw_brems, settings.boardcomputerHardware.bremsMin, settings.boardcomputerHardware.bremsMax, 0., 1000.); +#ifdef FEATURE_CAN + const auto now = millis(); + + if (can::can_gas) + { + if (now - can::last_can_gas < 100) + raw_gas = *can::can_gas; + else + can::can_gas = std::nullopt; + } + + if (can::can_brems) + { + if (now - can::last_can_brems < 100) + 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 = scaleBetween(*raw_gas, settings.boardcomputerHardware.gasMin, settings.boardcomputerHardware.gasMax, 0., 1000.); + else + gas = std::nullopt; + if (raw_brems) + brems = scaleBetween(*raw_brems, settings.boardcomputerHardware.bremsMin, settings.boardcomputerHardware.bremsMax, 0., 1000.); + else + brems = std::nullopt; #ifdef FEATURE_GAMETRAK raw_gametrakX = sampleMultipleTimes(PINS_GAMETRAKX); diff --git a/src/widgets/graph.h b/src/widgets/graph.h index e65d040..7968885 100644 --- a/src/widgets/graph.h +++ b/src/widgets/graph.h @@ -112,7 +112,7 @@ void Graph::render(const Container &buffers, bool delta) tft.setTextFont(2); tft.setTextColor(TFT_WHITE, TFT_BLACK); for (auto iter = std::begin(m_labels); iter != std::end(m_labels); iter++) - iter->redraw(String(int(m_max+((m_min-m_max)/(m_labels.size()-1)*std::distance(std::begin(m_labels), iter))))); + iter->redraw(std::to_string(int(m_max+((m_min-m_max)/(m_labels.size()-1)*std::distance(std::begin(m_labels), iter))))); int x{leftMargin}; for (auto pixelsIter = std::begin(m_lastPixels); pixelsIter!=std::end(m_lastPixels); pixelsIter++) diff --git a/src/widgets/label.h b/src/widgets/label.h index 5171033..e41c1cb 100644 --- a/src/widgets/label.h +++ b/src/widgets/label.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "globals.h" @@ -14,14 +14,14 @@ public: int y() const { return m_y; }; void start(); - void redraw(const String &str, bool forceRedraw = false); + void redraw(const std::string &str, bool forceRedraw = false); void clear(); private: const int m_x; const int m_y; - String m_lastStr; + std::string m_lastStr; int m_lastFont; int m_lastColor; @@ -45,7 +45,7 @@ void Label::start() m_lastHeight = 0; } -void Label::redraw(const String &str, bool forceRedraw) +void Label::redraw(const std::string &str, bool forceRedraw) { if (m_lastStr == str && m_lastFont == tft.textfont && @@ -53,7 +53,7 @@ void Label::redraw(const String &str, bool forceRedraw) !forceRedraw) return; - const auto renderedWidth = tft.drawString(str, m_x, m_y); + const auto renderedWidth = tft.drawString(str.c_str(), m_x, m_y); const auto renderedHeight = tft.fontHeight(); if (renderedWidth < m_lastWidth) diff --git a/src/wifitexthelpers.h b/src/wifitexthelpers.h index 8d69367..a1964ef 100644 --- a/src/wifitexthelpers.h +++ b/src/wifitexthelpers.h @@ -8,110 +8,110 @@ namespace { struct WifiStatusBitsText : public virtual TextInterface { public: - String text() const override { return String{"statusBits: "} + WiFi.getStatusBits(); } + std::string text() const override { return "statusBits: " + std::to_string(WiFi.getStatusBits()); } }; struct WifiChannelText : public virtual TextInterface { public: - String text() const override { return String{"channel: "} + WiFi.channel(); } + std::string text() const override { return "channel: " + std::to_string(WiFi.channel()); } }; struct WifiIsConnectedText : public virtual TextInterface { public: - String text() const override { return String{"isConnected: "} + toString(WiFi.isConnected()); } + std::string text() const override { return "isConnected: " + std::to_string(WiFi.isConnected()); } }; struct WifiLocalIpText : public virtual TextInterface { public: - String text() const override { return String{"localIP: "} + WiFi.localIP().toString(); } + std::string text() const override { return "localIP: " + to_string(WiFi.localIP()); } }; struct WifiMacAddressText : public virtual TextInterface { public: - String text() const override { return String{"macAddress: "} + WiFi.macAddress(); } + std::string text() const override { return "macAddress: " + to_string(WiFi.macAddress()); } }; struct WifiSubnetMaskText : public virtual TextInterface { public: - String text() const override { return String{"subnetMask: "} + WiFi.subnetMask().toString(); } + std::string text() const override { return "subnetMask: " + to_string(WiFi.subnetMask()); } }; struct WifiGatewayIpText : public virtual TextInterface { public: - String text() const override { return String{"gatewayIP: "} + WiFi.gatewayIP().toString(); } + std::string text() const override { return "gatewayIP: " + to_string(WiFi.gatewayIP()); } }; struct WifiDnsIpText : public virtual TextInterface { public: - String text() const override { return String{"dnsIP: "} + WiFi.dnsIP().toString(); } + std::string text() const override { return "dnsIP: " + to_string(WiFi.dnsIP()); } }; struct WifiBroadcastIpText : public virtual TextInterface { public: - String text() const override { return String{"broadcastIP: "} + WiFi.broadcastIP().toString(); } + std::string text() const override { return "broadcastIP: " + to_string(WiFi.broadcastIP()); } }; struct WifiNetworkIdText : public virtual TextInterface { public: - String text() const override { return String{"networkID: "} + WiFi.networkID().toString(); } + std::string text() const override { return "networkID: " + to_string(WiFi.networkID()); } }; struct WifiSubnetCIDRText : public virtual TextInterface { public: - String text() const override { return String{"subnetCIDR: "} + WiFi.subnetCIDR(); } + std::string text() const override { return "subnetCIDR: " + to_string(WiFi.subnetCIDR()); } }; struct WifiLocalIpV6Text : public virtual TextInterface { public: - String text() const override { return String{"localIPv6: "} + WiFi.localIPv6().toString(); } + std::string text() const override { return "localIPv6: " + to_string(WiFi.localIPv6()); } }; struct WifiHostnameText : public virtual TextInterface { public: - String text() const override { return String{"hostname: "} + WiFi.getHostname(); } + std::string text() const override { return "hostname: " + to_string(WiFi.getHostname()); } }; struct WifiStatusText : public virtual TextInterface { public: - String text() const override { return String{"status: "} + toString(WiFi.status()); } + std::string text() const override { return "status: " + to_string(WiFi.status()); } }; struct WifiSsidText : public virtual TextInterface { public: - String text() const override { return String{"SSID: "} + WiFi.SSID(); } + std::string text() const override { return "SSID: " + to_string(WiFi.SSID()); } }; struct WifiPskText : public virtual TextInterface { public: - String text() const override { return String{"psk: "} + WiFi.psk(); } + std::string text() const override { return "psk: " + to_string(WiFi.psk()); } }; struct WifiBssidText : public virtual TextInterface { public: - String text() const override { return String{"BSSID: "} + WiFi.BSSIDstr(); } + std::string text() const override { return "BSSID: " + to_string(WiFi.BSSIDstr()); } }; struct WifiRssiText : public virtual TextInterface { public: - String text() const override { return String{"RSSI: "} + WiFi.RSSI(); } + std::string text() const override { return "RSSI: " + to_string(WiFi.RSSI()); } }; class WifiSoftApGetStationNumText : public virtual TextInterface { public: - String text() const override { return String{"softAPgetStationNum: "} + WiFi.softAPgetStationNum(); } + std::string text() const override { return "softAPgetStationNum: " + to_string(WiFi.softAPgetStationNum()); } }; class WifiSoftApIpText : public virtual TextInterface { public: - String text() const override { return String{"softAPIP: "} + WiFi.softAPIP().toString(); } + std::string text() const override { return "softAPIP: " + to_string(WiFi.softAPIP()); } }; class WifiSoftApBroadcastIpText : public virtual TextInterface { public: - String text() const override { return String{"softAPBroadcastIP: "} + WiFi.softAPBroadcastIP().toString(); } + std::string text() const override { return "softAPBroadcastIP: " + to_string(WiFi.softAPBroadcastIP()); } }; class WifiSoftApNetworkIdText : public virtual TextInterface { public: - String text() const override { return String{"softAPNetworkID: "} + WiFi.softAPNetworkID().toString(); } + std::string text() const override { return "softAPNetworkID: " + to_string(WiFi.softAPNetworkID()); } }; class WifiSoftApSubnetCidrText : public virtual TextInterface { public: - String text() const override { return String{"softAPSubnetCIDR: "} + WiFi.softAPSubnetCIDR(); } + std::string text() const override { return "softAPSubnetCIDR: " + std::to_string(WiFi.softAPSubnetCIDR()); } }; class WifiSoftApIpV6Text : public virtual TextInterface { public: - String text() const override { return String{"softAPIPv6: "} + WiFi.softAPIPv6().toString(); } + std::string text() const override { return "softAPIPv6: " + to_string(WiFi.softAPIPv6()); } }; class WifiSoftApHostnameText : public virtual TextInterface { public: - String text() const override { return String{"softAPgetHostname: "} + WiFi.softAPgetHostname(); } + std::string text() const override { return "softAPgetHostname: " + to_string(WiFi.softAPgetHostname()); } }; class WifiSoftApMacAddressText : public virtual TextInterface { public: - String text() const override { return String{"softAPmacAddress: "} + WiFi.softAPmacAddress(); } + std::string text() const override { return "softAPmacAddress: " + to_string(WiFi.softAPmacAddress()); } }; }