wifi scan fixes, new config parameters

This commit is contained in:
2021-08-09 23:15:26 +02:00
parent 1504fc779a
commit e88fbfd4a7
23 changed files with 397 additions and 226 deletions

View File

@ -32,8 +32,7 @@ struct NMotMaxRpmAccessor : public RefAccessorSaveSettings<int16_t> { int16_t &g
struct FieldWeakMaxAccessor : public RefAccessorSaveSettings<int16_t> { int16_t &getRef() const override { return settings.limits.fieldWeakMax; } };
struct PhaseAdvMaxAccessor : public RefAccessorSaveSettings<int16_t> { int16_t &getRef() const override { return settings.limits.phaseAdvMax; } };
struct AutoWifiModeAccessor : public RefAccessorSaveSettings<wifi_mode_t> { wifi_mode_t &getRef() const override { return settings.wifiSettings.autoWifiMode; } };
struct AutoEnableApAccessor : public RefAccessorSaveSettings<bool> { bool &getRef() const override { return settings.wifiSettings.autoEnableAp; } };
struct WifiEnabledAccessor : public RefAccessorSaveSettings<bool> { bool &getRef() const override { return settings.wifiSettings.wifiEnabled; } };
#ifdef FEATURE_BLUETOOTH
struct AutoBluetoothModeAccessor : public RefAccessorSaveSettings<BluetoothMode> { BluetoothMode &getRef() const override { return settings.bluetoothSettings.autoBluetoothMode; } };
@ -65,6 +64,8 @@ struct SwapFrontBackAccessor : public RefAccessorSaveSettings<bool> {
#ifdef FEATURE_CAN
struct SendFrontCanCmdAccessor : public RefAccessorSaveSettings<bool> { bool &getRef() const override { return settings.controllerHardware.sendFrontCanCmd; } };
struct SendBackCanCmdAccessor : public RefAccessorSaveSettings<bool> { bool &getRef() const override { return settings.controllerHardware.sendBackCanCmd; } };
struct CanTransmitTimeoutAccessor : public RefAccessorSaveSettings<int16_t> { int16_t &getRef() const override { return settings.controllerHardware.canTransmitTimeout; } };
struct CanReceiveTimeoutAccessor : public RefAccessorSaveSettings<int16_t> { int16_t &getRef() const override { return settings.controllerHardware.canReceiveTimeout; } };
#endif
struct SampleCountAccessor : public RefAccessorSaveSettings<int16_t> { int16_t &getRef() const override { return settings.boardcomputerHardware.sampleCount; } };
@ -89,6 +90,9 @@ struct ModeUpdateRateAccessor : public RefAccessorSaveSettings<int16_t> { int16_
struct StatsUpdateRateAccessor : public RefAccessorSaveSettings<int16_t> { int16_t &getRef() const override { return settings.boardcomputerHardware.timersSettings.statsUpdateRate; } };
struct DisplayUpdateRateAccessor : public RefAccessorSaveSettings<int16_t> { int16_t &getRef() const override { return settings.boardcomputerHardware.timersSettings.displayUpdateRate; } };
struct DisplayRedrawRateAccessor : public RefAccessorSaveSettings<int16_t> { int16_t &getRef() const override { return settings.boardcomputerHardware.timersSettings.displayRedrawRate; } };
#ifdef FEATURE_CAN
struct CanReceiveRateAccessor : public RefAccessorSaveSettings<int16_t> { int16_t &getRef() const override { return settings.boardcomputerHardware.timersSettings.canReceiveRate; } };
#endif
struct DefaultModeModelModeAccessor : public RefAccessorSaveSettings<UnifiedModelMode> { UnifiedModelMode &getRef() const override { return settings.defaultMode.modelMode; } };
struct DefaultModeSquareGasAccessor : public RefAccessorSaveSettings<bool> { bool &getRef() const override { return settings.defaultMode.squareGas; } };

View File

@ -1,5 +1,9 @@
#pragma once
// esp-idf includes
#include <esp_log.h>
// local includes
#include "actioninterface.h"
#include "globals.h"
#include "presets.h"
@ -14,25 +18,31 @@ public:
if (!settingsPersister.erase())
{
//Serial.println("EraseNvsAction::triggered() erase failed");
return;
ESP_LOGE("BOBBY", "erase() failed");
//return;
}
settings = presets::defaultSettings;
if (!profile)
return;
if (!settingsPersister.openProfile(*profile))
if (!settingsPersister.openCommon())
{
//Serial.println("EraseNvsAction::triggered() openProfile failed");
return;
ESP_LOGE("BOBBY", "openCommon() failed");
//return;
}
if (profile)
{
if (!settingsPersister.openProfile(*profile))
{
ESP_LOGE("BOBBY", "openProfile(%hhu) failed", *profile);
//return;
}
}
if (!settingsPersister.load(settings))
{
//Serial.println("EraseNvsAction::triggered() load failed");
return;
ESP_LOGE("BOBBY", "load() failed");
//return;
}
}
};

View File

@ -10,6 +10,7 @@
#include <Arduino.h>
#include <espchrono.h>
#include <tickchrono.h>
#include "bobbycar-can.h"
@ -36,7 +37,7 @@ CanButtonsState lastButtonsState;
void initCan()
{
//Serial.println("initCan()");
ESP_LOGI(TAG, "called");
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(GPIO_NUM_21, GPIO_NUM_22, TWAI_MODE_NORMAL);
twai_timing_config_t t_config TWAI_TIMING_CONFIG_250KBITS();
@ -50,29 +51,29 @@ void initCan()
if (const auto result = twai_driver_install(&g_config, &t_config, &f_config); result == ESP_OK)
{
//Serial.printf("CAN info twai_driver_install() succeeded\r\n");
ESP_LOGI(TAG, "twai_driver_install() succeeded");
}
else
{
//Serial.printf("CAN err twai_driver_install() failed with %s\r\n", esp_err_to_name(result));
ESP_LOGE(TAG, "twai_driver_install() failed with %s", esp_err_to_name(result));
return;
}
if (const auto result = twai_start(); result == ESP_OK)
{
//Serial.printf("CAN info twai_start() succeeded\r\n");
ESP_LOGI(TAG, "twai_start() succeeded");
}
else
{
//Serial.printf("CAN err twai_start() failed with %s\r\n", esp_err_to_name(result));
ESP_LOGE(TAG, "twai_start() failed with %s", esp_err_to_name(result));
if (const auto result = twai_driver_uninstall(); result == ESP_OK)
{
//Serial.printf("CAN info twai_driver_uninstall() succeeded\r\n");
ESP_LOGI(TAG, "twai_driver_uninstall() succeeded");
}
else
{
//Serial.printf("CAN err twai_driver_uninstall() failed with %s\r\n", esp_err_to_name(result));
ESP_LOGE(TAG, "twai_driver_uninstall() failed with %s", esp_err_to_name(result));
}
return;
@ -220,11 +221,12 @@ bool parseBoardcomputerCanMessage(const twai_message_t &message)
bool tryParseCanInput()
{
twai_message_t message;
if (const auto result = twai_receive(&message, pdMS_TO_TICKS(10)); result != ESP_OK)
const auto timeout = std::chrono::ceil<espcpputils::ticks>(espchrono::milliseconds32{settings.controllerHardware.canReceiveTimeout}).count();
if (const auto result = twai_receive(&message, timeout); result != ESP_OK)
{
if (result != ESP_ERR_TIMEOUT)
{
ESP_LOGE(TAG, "CAN err twai_receive() failed with %s", esp_err_to_name(result));
ESP_LOGE(TAG, "twai_receive() failed with %s", esp_err_to_name(result));
}
if (espchrono::millis_clock::now() - controllers.front.lastCanFeedback > 100ms)
@ -269,7 +271,7 @@ bool tryParseCanInput()
if (parseBoardcomputerCanMessage(message))
return true;
//Serial.printf("WARNING Unknown CAN info received .identifier = %u\r\n", message.identifier);
ESP_LOGW(TAG, "Unknown CAN info received .identifier = %u", message.identifier);
return true;
}
@ -291,7 +293,8 @@ void sendCanCommands()
std::fill(std::begin(message.data), std::end(message.data), 0);
std::memcpy(message.data, &value, sizeof(value));
const auto result = twai_transmit(&message, pdMS_TO_TICKS(200));
const auto timeout = std::chrono::ceil<espcpputils::ticks>(espchrono::milliseconds32{settings.controllerHardware.canTransmitTimeout}).count();
const auto result = twai_transmit(&message, timeout);
if (result != ESP_OK && result != ESP_ERR_TIMEOUT)
{
ESP_LOGE(TAG, "ERROR: twai_transmit() failed with %s", esp_err_to_name(result));

View File

@ -1,5 +1,7 @@
#pragma once
#include <fmt/core.h>
#include "display.h"
#include "textinterface.h"
#include "actioninterface.h"
@ -122,6 +124,18 @@ void ChangeValueDisplay<Tvalue>::redraw()
m_valueLabel.redraw(std::to_string(m_value));
}
template<>
void ChangeValueDisplay<float>::redraw()
{
tft.setTextFont(4);
tft.setTextColor(TFT_YELLOW);
m_titleLabel.redraw(text());
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.setTextFont(7);
m_valueLabel.redraw(fmt::format("{:02f}", m_value));
}
template<typename Tvalue>
void ChangeValueDisplay<Tvalue>::rotate(int offset)
{

View File

@ -1,5 +1,7 @@
#pragma once
#include <esp_log.h>
#include "changevaluedisplay.h"
#include "menudisplay.h"
#include "utils.h"
@ -45,7 +47,7 @@ void ChangeValueDisplay<bobbycar::protocol::ControlMode>::start()
case ControlMode::Speed: setSelectedIndex(2); break;
case ControlMode::Torque: setSelectedIndex(3); break;
default:
//Serial.printf("Unknown ControlMode: %i\r\n", int(value));
ESP_LOGW("BOBBY", "Unknown ControlMode: %i", int(value));
setSelectedIndex(4);
}
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <esp_log.h>
#include "changevaluedisplay.h"
#include "menudisplay.h"
#include "utils.h"
@ -43,7 +45,7 @@ void ChangeValueDisplay<bobbycar::protocol::ControlType>::start()
case ControlType::Sinusoidal: setSelectedIndex(1); break;
case ControlType::FieldOrientedControl: setSelectedIndex(2); break;
default:
//Serial.printf("Unknown ControlType: %i\r\n", int(value));
ESP_LOGW("BOBBY", "Unknown ControlType: %i", int(value));
setSelectedIndex(3);
}
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <esp_log.h>
#include "changevaluedisplay.h"
#include "menudisplay.h"
#include "utils.h"
@ -44,7 +46,7 @@ void ChangeValueDisplay<LarsmModeMode>::start()
case LarsmModeMode::Mode3: setSelectedIndex(2); break;
case LarsmModeMode::Mode4: setSelectedIndex(3); break;
default:
//Serial.printf("Unknown LarsmModeMode: %i\r\n", int(value));
ESP_LOGW("BOBBY", "Unknown LarsmModeMode: %i", int(value));
setSelectedIndex(4);
}
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <esp_log.h>
#include "changevaluedisplay.h"
#include "menudisplay.h"
#include "utils.h"
@ -46,7 +48,7 @@ void ChangeValueDisplay<UnifiedModelMode>::start()
case UnifiedModelMode::FocSpeed: setSelectedIndex(3); break;
case UnifiedModelMode::FocTorque: setSelectedIndex(4); break;
default:
//Serial.printf("Unknown UnifiedModelMode: %i\r\n", int(value));
ESP_LOGW("BOBBY", "Unknown UnifiedModelMode: %i", int(value));
setSelectedIndex(5);
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <esp_wifi_types.h>
#include <esp_log.h>
#include "changevaluedisplay.h"
#include "menudisplay.h"
@ -45,7 +46,7 @@ void ChangeValueDisplay<wifi_mode_t>::start()
case WIFI_MODE_AP: setSelectedIndex(2); break;
case WIFI_MODE_APSTA: setSelectedIndex(3); break;
default:
//Serial.printf("Unknown wifi_mode_t: %i\r\n", int(value));
ESP_LOGW("BOBBY", "Unknown wifi_mode_t: %i", int(value));
setSelectedIndex(4);
}
}

View File

@ -46,6 +46,22 @@ using NumMagnetPolesChangeScreen = makeComponent<
BackActionInterface<SwitchScreenAction<ControllerHardwareSettingsMenu>>,
SwitchScreenAction<ControllerHardwareSettingsMenu>
>;
#ifdef FEATURE_CAN
using CanTransmitTimeoutChangeScreen = makeComponent<
ChangeValueDisplay<int16_t>,
StaticText<TEXT_CANTRANSMITTIMEOUT>,
CanTransmitTimeoutAccessor,
BackActionInterface<SwitchScreenAction<ControllerHardwareSettingsMenu>>,
SwitchScreenAction<ControllerHardwareSettingsMenu>
>;
using CanReceiveTimeoutChangeScreen = makeComponent<
ChangeValueDisplay<int16_t>,
StaticText<TEXT_CANRECEIVETIMEOUT>,
CanReceiveTimeoutAccessor,
BackActionInterface<SwitchScreenAction<ControllerHardwareSettingsMenu>>,
SwitchScreenAction<ControllerHardwareSettingsMenu>
>;
#endif
class ControllerHardwareSettingsMenu :
public MenuDisplay,
@ -62,8 +78,10 @@ public:
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_NUMMAGNETPOLES>, SwitchScreenAction<NumMagnetPolesChangeScreen>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_SWAPFRONTBACK>, ToggleBoolAction, CheckboxIcon, SwapFrontBackAccessor>>();
#ifdef FEATURE_CAN
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_FRONTSENDCAN>, ToggleBoolAction, CheckboxIcon, SendFrontCanCmdAccessor>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACKSENDCAN>, ToggleBoolAction, CheckboxIcon, SendBackCanCmdAccessor>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_FRONTSENDCAN>, ToggleBoolAction, CheckboxIcon, SendFrontCanCmdAccessor>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACKSENDCAN>, ToggleBoolAction, CheckboxIcon, SendBackCanCmdAccessor>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_CANTRANSMITTIMEOUT>, SwitchScreenAction<CanTransmitTimeoutChangeScreen>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_CANRECEIVETIMEOUT>, SwitchScreenAction<CanReceiveTimeoutChangeScreen>>>();
#endif
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<SettingsMenu>, StaticMenuItemIcon<&icons::back>>>();
}

View File

@ -57,6 +57,16 @@ using DisplayRedrawRateChangeDisplay = makeComponent<
SwitchScreenAction<TimersMenu>
>;
#ifdef FEATURE_CAN
using CanReceiveRateChangeDisplay = makeComponent<
ChangeValueDisplay<int16_t>,
StaticText<TEXT_CANRECEIVERATE>,
CanReceiveRateAccessor,
BackActionInterface<SwitchScreenAction<TimersMenu>>,
SwitchScreenAction<TimersMenu>
>;
#endif
class TimersMenu :
public MenuDisplay,
public StaticText<TEXT_TIMERS>,
@ -70,6 +80,9 @@ public:
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_STATSUPDATERATE>, SwitchScreenAction<StatsUpdateRateChangeDisplay>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_DISPLAYUPDATERATE>, SwitchScreenAction<DisplayUpdateRateChangeDisplay>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_DISPLAYREDRAWRATE>, SwitchScreenAction<DisplayRedrawRateChangeDisplay>>>();
#ifdef FEATURE_CAN
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_CANRECEIVERATE>, SwitchScreenAction<CanReceiveRateChangeDisplay>>>();
#endif
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<BoardcomputerHardwareSettingsMenu>, StaticMenuItemIcon<&icons::back>>>();
}
};

View File

@ -1,6 +1,15 @@
#pragma once
// system includes
#include <optional>
// esp-idf includes
#include <esp_log.h>
// 3rdparty lib includes
#include <espchrono.h>
#include <espwifistack.h>
#include <fmt/core.h>
// local includes
#include "menudisplay.h"
@ -10,12 +19,15 @@
#include "actions/dummyaction.h"
#include "icons/back.h"
#include "texts.h"
#include "wifi_bobbycar.h"
// forward declares
namespace {
class WifiSettingsMenu;
} // namespace
using namespace std::chrono_literals;
namespace {
class WifiScanMenu : public MenuDisplay, public BackActionInterface<SwitchScreenAction<WifiSettingsMenu>>
{
@ -31,7 +43,7 @@ public:
void stop() override;
private:
espchrono::millis_clock::time_point m_lastScanComplete;
std::optional<espchrono::millis_clock::time_point> m_lastScanComplete;
std::vector<std::unique_ptr<makeComponent<MenuItem, ChangeableText, DummyAction>>> m_reusableItems;
};
@ -43,13 +55,13 @@ WifiScanMenu::WifiScanMenu()
std::string WifiScanMenu::text() const
{
auto text = std::to_string(menuItemCount()-1) + " found";
//switch (WiFi.scanComplete())
//{
//case WIFI_SCAN_RUNNING: text += " (scanning)"; break;
//case WIFI_SCAN_FAILED: text += " (error)"; break;
//}
text += " (not implemented)";
const auto scanStatus = wifi_stack::get_scan_status();
auto text = wifi_stack::toString(scanStatus);
if (scanStatus != wifi_stack::WiFiScanStatus::Scanning)
if (const auto &result = wifi_stack::get_scan_result())
text += fmt::format(" ({} found)", result->entries.size());
return text;
}
@ -59,63 +71,73 @@ void WifiScanMenu::start()
m_lastScanComplete = {};
//WiFi.scanNetworks(true);
if (wifi_stack::get_scan_status() != wifi_stack::WiFiScanStatus::Scanning)
if (const auto result = wifi_scan(); result != ESP_OK)
ESP_LOGE("BOBBY", "wifi_scan() failed with %s", esp_err_to_name(result));
}
void WifiScanMenu::update()
{
//const auto n = WiFi.scanComplete();
//if (n >= 0)
//{
// const auto now = espchrono::millis_clock::now();
// if (!m_lastScanComplete)
// {
// auto backButton = takeLastMenuItem();
//
// for (std::size_t i = 0; i < n; i++)
// {
// const auto ssid = to_string(WiFi.SSID(i));
// if (menuItemCount() <= i)
// {
// if (m_reusableItems.empty())
// {
// auto &item = constructMenuItem<makeComponent<MenuItem, ChangeableText, DummyAction>>();
// item.setTitle(ssid);
// }
// else
// {
// std::unique_ptr<makeComponent<MenuItem, ChangeableText, DummyAction>> ptr = std::move(m_reusableItems.back());
// m_reusableItems.pop_back();
// ptr->setTitle(ssid);
// emplaceMenuItem(std::move(ptr));
// }
// }
// else
// {
// auto &item = *(makeComponent<MenuItem, ChangeableText, DummyAction>*)(&getMenuItem(i));
// item.setTitle(ssid);
// }
// }
//
// while (menuItemCount() > n)
// m_reusableItems.emplace_back((makeComponent<MenuItem, ChangeableText, DummyAction>*)takeLastMenuItem().release());
//
// emplaceMenuItem(std::move(backButton));
//
// m_lastScanComplete = now;
// }
// else if (now - m_lastScanComplete >= 2000)
// {
// m_lastScanComplete = 0;
// WiFi.scanNetworks(true);
// }
//}
if (wifi_stack::get_scan_status() == wifi_stack::WiFiScanStatus::Scanning)
{
// TODO
}
else
{
const auto now = espchrono::millis_clock::now();
if (!m_lastScanComplete)
{
const auto &result = wifi_stack::get_scan_result();
auto backButton = takeLastMenuItem();
for (std::size_t i = 0; i < (result ? result->entries.size() : 0); i++)
{
std::string ssid{reinterpret_cast<const char*>(result->entries[i].ssid)};
if (menuItemCount() <= i)
{
if (m_reusableItems.empty())
{
auto &item = constructMenuItem<makeComponent<MenuItem, ChangeableText, DummyAction>>();
item.setTitle(std::move(ssid));
}
else
{
std::unique_ptr<makeComponent<MenuItem, ChangeableText, DummyAction>> ptr = std::move(m_reusableItems.back());
m_reusableItems.pop_back();
ptr->setTitle(std::move(ssid));
emplaceMenuItem(std::move(ptr));
}
}
else
{
auto &item = *(makeComponent<MenuItem, ChangeableText, DummyAction>*)(&getMenuItem(i));
item.setTitle(std::move(ssid));
}
}
while (menuItemCount() > (result ? result->entries.size() : 0))
m_reusableItems.emplace_back((makeComponent<MenuItem, ChangeableText, DummyAction>*)takeLastMenuItem().release());
emplaceMenuItem(std::move(backButton));
m_lastScanComplete = now;
}
else if (espchrono::ago(*m_lastScanComplete) >= 10s)
{
m_lastScanComplete = {};
if (const auto result = wifi_scan(); result != ESP_OK)
ESP_LOGE("BOBBY", "wifi_scan() failed with %s", esp_err_to_name(result));
}
}
Base::update();
}
void WifiScanMenu::stop()
{
//WiFi.scanDelete();
wifi_stack::delete_scan_result();
}
} // namespace

View File

@ -24,14 +24,6 @@ class SettingsMenu;
namespace {
class WifiSettingsMenu;
using AutoWifiModeChangeDisplay = makeComponent<
ChangeValueDisplay<wifi_mode_t>,
StaticText<TEXT_AUTOWIFIMODE>,
AutoWifiModeAccessor,
BackActionInterface<SwitchScreenAction<WifiSettingsMenu>>,
SwitchScreenAction<WifiSettingsMenu>
>;
class WifiSettingsMenu :
public MenuDisplay,
public StaticText<TEXT_WIFISETTINGS>,
@ -40,8 +32,7 @@ class WifiSettingsMenu :
public:
WifiSettingsMenu()
{
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_AUTOWIFIMODE>, SwitchScreenAction<AutoWifiModeChangeDisplay>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_AUTOENABLEAP>, ToggleBoolAction, CheckboxIcon, AutoEnableApAccessor>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_WIFIENABLED>, ToggleBoolAction, CheckboxIcon, WifiEnabledAccessor>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_GENERICWIFISETTINGS>, SwitchScreenAction<GenericWifiSettingsMenu>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_STATIONWIFISETTINGS>, SwitchScreenAction<StationWifiSettingsMenu>>>();
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_WIFISCAN>, SwitchScreenAction<WifiScanMenu>, StaticMenuItemIcon<&icons::scan>>>();

View File

@ -4,8 +4,7 @@
namespace {
namespace icons {
/*
const Icon<240, 130> logo{{
constexpr const Icon<240, 130> logo{{
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // 0x0010 (16) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // 0x0020 (32) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // 0x0030 (48) pixels
@ -1957,6 +1956,5 @@ const Icon<240, 130> logo{{
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // 0x79D0 (31184) pixels
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // 0x79E0 (31200) pixels
}};
*/
}
}

View File

@ -180,11 +180,17 @@ extern "C" void app_main()
if (settingsPersister.init())
{
if (settingsPersister.openProfile(0))
{
loadSettings();
}
if (!settingsPersister.openCommon())
ESP_LOGE("BOBBY", "openCommon() failed");
if (!settingsPersister.openProfile(0))
ESP_LOGE("BOBBY", "openProfile(0) failed");
loadSettings();
}
else
ESP_LOGE("BOBBY", "init() failed");
printMemoryStats("loadSettings()");
bootLabel.redraw("deviceName");
@ -372,8 +378,9 @@ extern "C" void app_main()
}
#ifdef FEATURE_CAN
if (!lastCanParse || now - *lastCanParse >= 50ms)
if (!lastCanParse || now - *lastCanParse >= 1000ms/settings.boardcomputerHardware.timersSettings.canReceiveRate)
{
//can::tryParseCanInput();
can::parseCanInput();
lastCanParse = now;

View File

@ -36,6 +36,8 @@ constexpr Settings::ControllerHardware defaultControllerHardware {
#ifdef FEATURE_CAN
.sendFrontCanCmd = true,
.sendBackCanCmd = true,
.canTransmitTimeout = 200,
.canReceiveTimeout = 0,
#endif
};
@ -56,12 +58,13 @@ constexpr Settings::ControllerHardware mosfetsOffControllerHardware {
#ifdef FEATURE_CAN
.sendFrontCanCmd = true,
.sendBackCanCmd = true,
.canTransmitTimeout = 200,
.canReceiveTimeout = 0,
#endif
};
constexpr Settings::WifiSettings defaultWifiSettings {
.autoWifiMode = WIFI_MODE_APSTA,
.autoEnableAp = true
.wifiEnabled = true
};
#ifdef FEATURE_BLUETOOTH
@ -87,6 +90,8 @@ constexpr Settings::ControllerHardware spinnerControllerHardware {
#ifdef FEATURE_CAN
.sendFrontCanCmd = true,
.sendBackCanCmd = true,
.canTransmitTimeout = 200,
.canReceiveTimeout = 0,
#endif
};
@ -95,7 +100,10 @@ constexpr Settings::BoardcomputerHardware::TimersSettings defaultTimersSettings
.modeUpdateRate = 50,
.statsUpdateRate = 50,
.displayUpdateRate = 50,
.displayRedrawRate = 50
.displayRedrawRate = 50,
#ifdef FEATURE_CAN
.canReceiveRate = 100,
#endif
};
constexpr Settings::BoardcomputerHardware defaultBoardcomputerHardware {

View File

@ -50,7 +50,7 @@ void initScreen()
tft.fillScreen(TFT_WHITE);
tft.setTextColor(TFT_BLACK, TFT_WHITE);
tft.setTextFont(4);
//tft.pushImage(0, 40, icons::logo.WIDTH, icons::logo.HEIGHT, icons::logo.buffer);
tft.pushImage(0, 40, icons::logo.WIDTH, icons::logo.HEIGHT, icons::logo.buffer);
tft.drawString("Bobbycar-OS", 32, 200);
tft.drawString("booting...", 32, 225);
bootLabel.start();

View File

@ -35,8 +35,7 @@ struct Settings
} limits;
struct WifiSettings {
wifi_mode_t autoWifiMode;
bool autoEnableAp;
bool wifiEnabled;
} wifiSettings;
#ifdef FEATURE_BLUETOOTH
@ -57,6 +56,8 @@ struct Settings
#ifdef FEATURE_CAN
bool sendFrontCanCmd;
bool sendBackCanCmd;
int16_t canTransmitTimeout; // in ms
int16_t canReceiveTimeout; // in ms
#endif
} controllerHardware;
@ -77,6 +78,9 @@ struct Settings
int16_t statsUpdateRate;
int16_t displayUpdateRate;
int16_t displayRedrawRate;
#ifdef FEATURE_CAN
int16_t canReceiveRate;
#endif
} timersSettings;
} boardcomputerHardware;
@ -107,44 +111,24 @@ struct Settings
template<typename T>
void executeForEverySetting(T &&callable);
void executeForEveryCommonSetting(T &&callable);
template<typename T>
void executeForEveryProfileSetting(T &&callable);
};
template<typename T>
void Settings::executeForEverySetting(T &&callable)
void Settings::executeForEveryCommonSetting(T &&callable)
{
#ifdef FEATURE_BMS
callable("autoConnectBms", autoConnectBms);
#endif
callable("reverseBeep", reverseBeep);
callable("revBeepFreq0", reverseBeepFreq0);
callable("revBeepFreq1", reverseBeepFreq1);
callable("revBeepDur0", reverseBeepDuration0);
callable("revBeepDur1", reverseBeepDuration1);
callable("iMotMax", limits.iMotMax);
callable("iDcMax", limits.iDcMax);
callable("nMotMax", limits.nMotMax);
callable("fieldWeakMax", limits.fieldWeakMax);
callable("phaseAdvMax", limits.phaseAdvMax);
#ifdef FEATURE_BLUETOOTH
callable("autoBluetoothMo", bluetoothSettings.autoBluetoothMode);
#endif
callable("autoWifiMode", wifiSettings.autoWifiMode);
callable("autoEnableAp", wifiSettings.autoEnableAp);
callable("enableFrontLeft", controllerHardware.enableFrontLeft);
callable("enableFrontRigh", controllerHardware.enableFrontRight);
callable("enableBackLeft", controllerHardware.enableBackLeft);
callable("enableBackRight", controllerHardware.enableBackRight);
callable("invertFrontLeft", controllerHardware.invertFrontLeft);
callable("invertFrontRigh", controllerHardware.invertFrontRight);
callable("invertBackLeft", controllerHardware.invertBackLeft);
callable("invertBackRight", controllerHardware.invertBackRight);
callable("wifiEnabled", wifiSettings.wifiEnabled);
callable("wheelDiameter", controllerHardware.wheelDiameter);
callable("numMagnetPoles", controllerHardware.numMagnetPoles);
@ -152,6 +136,8 @@ void Settings::executeForEverySetting(T &&callable)
#ifdef FEATURE_CAN
callable("sendFrontCanCmd", controllerHardware.sendFrontCanCmd);
callable("sendBackCanCmd", controllerHardware.sendBackCanCmd);
callable("canTransmitTime", controllerHardware.canTransmitTimeout);
callable("canReceiveTimeo", controllerHardware.canReceiveTimeout);
#endif
callable("sampleCount", boardcomputerHardware.sampleCount);
@ -177,6 +163,35 @@ void Settings::executeForEverySetting(T &&callable)
callable("statsUpdateRate", boardcomputerHardware.timersSettings.statsUpdateRate);
callable("displayUpdateRa", boardcomputerHardware.timersSettings.displayUpdateRate);
callable("displayRedrawRa", boardcomputerHardware.timersSettings.displayRedrawRate);
#ifdef FEATURE_CAN
callable("canReceiveRate", boardcomputerHardware.timersSettings.canReceiveRate);
#endif
}
template<typename T>
void Settings::executeForEveryProfileSetting(T &&callable)
{
callable("reverseBeep", reverseBeep);
callable("revBeepFreq0", reverseBeepFreq0);
callable("revBeepFreq1", reverseBeepFreq1);
callable("revBeepDur0", reverseBeepDuration0);
callable("revBeepDur1", reverseBeepDuration1);
callable("iMotMax", limits.iMotMax);
callable("iDcMax", limits.iDcMax);
callable("nMotMax", limits.nMotMax);
callable("fieldWeakMax", limits.fieldWeakMax);
callable("phaseAdvMax", limits.phaseAdvMax);
callable("enableFrontLeft", controllerHardware.enableFrontLeft);
callable("enableFrontRigh", controllerHardware.enableFrontRight);
callable("enableBackLeft", controllerHardware.enableBackLeft);
callable("enableBackRight", controllerHardware.enableBackRight);
callable("invertFrontLeft", controllerHardware.invertFrontLeft);
callable("invertFrontRigh", controllerHardware.invertFrontRight);
callable("invertBackLeft", controllerHardware.invertBackLeft);
callable("invertBackRight", controllerHardware.invertBackRight);
callable("default.modelMo", defaultMode.modelMode);
callable("default.enableS", defaultMode.enableSmoothing);

View File

@ -5,6 +5,10 @@
#include <nvs_flash.h>
#include <nvs.h>
#include <esp_log.h>
#include <fmt/core.h>
#include <cpputils.h>
#include "settings.h"
#ifdef FEATURE_BLUETOOTH
@ -18,6 +22,8 @@ class SettingsPersister
public:
bool init();
bool erase();
bool openCommon();
void closeCommon();
bool openProfile(uint8_t index);
void closeProfile();
bool load(Settings &settings);
@ -26,6 +32,9 @@ public:
std::optional<uint8_t> currentlyOpenProfileIndex() const;
private:
// for common settings
nvs_handle m_handle{};
struct CurrentlyOpenProfile {
nvs_handle handle;
uint8_t profileIndex;
@ -35,17 +44,15 @@ private:
bool SettingsPersister::init()
{
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
if (esp_err_t result = nvs_flash_init();
cpputils::is_in(result, ESP_ERR_NVS_NO_FREE_PAGES, ESP_ERR_NVS_NEW_VERSION_FOUND))
{
//Serial.printf("nvs_flash_init() returned: %s, trying to erase\r\n", esp_err_to_name(err));
ESP_LOGE("BOBBY", "nvs_flash_init() failed with %s, trying to erase...", esp_err_to_name(result));
return erase();
}
if (err != ESP_OK)
else if (result != ESP_OK)
{
//Serial.printf("nvs_flash_init() returned: %s\r\n", esp_err_to_name(err));
ESP_LOGE("BOBBY", "nvs_flash_init() failed with %s", esp_err_to_name(result));
return false;
}
@ -54,32 +61,61 @@ bool SettingsPersister::init()
bool SettingsPersister::erase()
{
esp_err_t err = nvs_flash_erase();
if (err != ESP_OK)
closeProfile();
closeCommon();
bool result{true};
if (esp_err_t result = nvs_flash_erase(); result != ESP_OK)
{
//Serial.printf("nvs_flash_erase() returned: %s, aborting\r\n", esp_err_to_name(err));
ESP_LOGE("BOBBY", "nvs_flash_erase() failed with %s", esp_err_to_name(result));
result = false;
}
if (esp_err_t result = nvs_flash_init(); result != ESP_OK)
{
ESP_LOGE("BOBBY", "nvs_flash_init() failed with %s", esp_err_to_name(result));
result = false;
}
return result;
}
bool SettingsPersister::openCommon()
{
closeCommon();
nvs_handle handle;
if (esp_err_t result = nvs_open("bobbycar", NVS_READWRITE, &handle); result != ESP_OK)
{
ESP_LOGE("BOBBY", "nvs_open() COMMON %s failed with %s", "bobbycar", esp_err_to_name(result));
return false;
}
err = nvs_flash_init();
if (err != ESP_OK)
{
//Serial.printf("nvs_flash_init() returned: %s\r\n", esp_err_to_name(err));
return false;
}
m_handle = handle;
return true;
}
void SettingsPersister::closeCommon()
{
if (!m_handle)
return;
nvs_close(m_handle);
m_handle = {};
}
bool SettingsPersister::openProfile(uint8_t index)
{
closeProfile();
nvs_handle handle;
esp_err_t err = nvs_open(("bobbycar"+std::to_string(index)).c_str(), NVS_READWRITE, &handle);
if (err != ESP_OK)
const auto name = fmt::format("bobbycar{}", index);
if (esp_err_t result = nvs_open(name.c_str(), NVS_READWRITE, &handle); result != ESP_OK)
{
//Serial.printf("nvs_open() returned: %s\r\n", esp_err_to_name(err));
ESP_LOGE("BOBBY", "nvs_open() PROFILE %s failed with %s", name.c_str(), esp_err_to_name(result));
return false;
}
@ -166,23 +202,41 @@ template<> struct nvsGetterHelper<wifi_mode_t> { static esp_err_t nvs_get(nvs_ha
bool SettingsPersister::load(Settings &settings)
{
if (!m_profile)
{
//Serial.println("SettingsPersister::load() no profile open currently!");
return false;
}
bool result{true};
settings.executeForEverySetting([&](const char *key, auto &value)
if (m_handle)
{
esp_err_t err = nvsGetterHelper<std::remove_reference_t<decltype(value)>>::nvs_get(m_profile->handle, key, &value);
if (err != ESP_OK)
settings.executeForEveryCommonSetting([&](const char *key, auto &value)
{
//Serial.printf("nvs_get_i32() for %s returned: %s\r\n", key, esp_err_to_name(err));
result = false;
}
});
if (esp_err_t result = nvsGetterHelper<std::remove_reference_t<decltype(value)>>::nvs_get(m_handle, key, &value); result != ESP_OK)
{
ESP_LOGE("BOBBY", "nvs_get() COMMON %s failed with %s", key, esp_err_to_name(result));
result = false;
}
});
}
else
{
ESP_LOGW("BOBBY", "common nvs handle not valid!");
result = false;
}
if (m_profile)
{
settings.executeForEveryProfileSetting([&](const char *key, auto &value)
{
if (esp_err_t result = nvsGetterHelper<std::remove_reference_t<decltype(value)>>::nvs_get(m_profile->handle, key, &value); result != ESP_OK)
{
ESP_LOGE("BOBBY", "nvs_get() PROFILE %s failed with %s", key, esp_err_to_name(result));
result = false;
}
});
}
else
{
ESP_LOGW("BOBBY", "no profile open currently!");
result = false;
}
return result;
}
@ -224,23 +278,41 @@ template<> struct nvsSetterHelper<wifi_mode_t> { static esp_err_t nvs_set(nvs_ha
bool SettingsPersister::save(Settings &settings)
{
if (!m_profile)
{
//Serial.println("SettingsPersister::save() no profile open currently!");
return false;
}
bool result{true};
settings.executeForEverySetting([&](const char *key, auto value)
if (m_handle)
{
esp_err_t err = nvsSetterHelper<decltype(value)>::nvs_set(m_profile->handle, key, value);
if (err != ESP_OK)
settings.executeForEveryCommonSetting([&](const char *key, auto value)
{
//Serial.printf("nvs_get_i32() for %s returned: %s\r\n", key, esp_err_to_name(err));
result = false;
}
});
if (esp_err_t result = nvsSetterHelper<decltype(value)>::nvs_set(m_handle, key, value); result != ESP_OK)
{
ESP_LOGE("BOBBY", "nvs_set() PROFILE %s failed with %s", key, esp_err_to_name(result));
result = false;
}
});
}
else
{
ESP_LOGW("BOBBY", "common nvs handle not valid!");
result = false;
}
if (m_profile)
{
settings.executeForEveryProfileSetting([&](const char *key, auto value)
{
if (esp_err_t result = nvsSetterHelper<decltype(value)>::nvs_set(m_profile->handle, key, value); result != ESP_OK)
{
ESP_LOGE("BOBBY", "nvs_set() PROFILE %s failed with %s", key, esp_err_to_name(result));
result = false;
}
});
}
else
{
ESP_LOGW("BOBBY", "no profile open currently!");
result = false;
}
return result;
}

View File

@ -1,5 +1,8 @@
#pragma once
// esp-idf includes
#include <esp_log.h>
// local includes
#include "globals.h"
#include "presets.h"
@ -9,16 +12,16 @@ void switchProfile(uint8_t index)
{
settings = presets::defaultSettings;
if (settingsPersister.openProfile(index))
if (!settingsPersister.openProfile(index))
{
if (!settingsPersister.load(settings))
{
//Serial.println("switchProfile() load failed");
}
ESP_LOGE("BOBBY", "openProfile() failed");
return;
}
else
if (!settingsPersister.load(settings))
{
//Serial.println("switchProfile() openProfile failed");
ESP_LOGE("BOBBY", "load() failed");
return;
}
}
}

View File

@ -99,13 +99,14 @@ constexpr char TEXT_SWAPFRONTBACK[] = "Swap front/back";
#ifdef FEATURE_CAN
constexpr char TEXT_FRONTSENDCAN[] = "Front send CAN";
constexpr char TEXT_BACKSENDCAN[] = "Back send CAN";
constexpr char TEXT_CANTRANSMITTIMEOUT[] = "CanTransmitTimeout";
constexpr char TEXT_CANRECEIVETIMEOUT[] = "CanReceiveTimeout";
#endif
//constexpr char TEXT_BACK[] = "Back";
//StationWifiSettingsMenu
constexpr char TEXT_STATIONWIFISETTINGS[] = "Station WiFi settings";
constexpr char TEXT_AUTOWIFIMODE[] = "Auto wifi mode";
constexpr char TEXT_AUTOENABLEAP[] = "Auto enable AP";
constexpr char TEXT_WIFIENABLED[] = "WiFi enabled";
constexpr char TEXT_WIFIRECONNECT[] = "reconnect()";
constexpr char TEXT_WIFIDISCONNECT[] = "disconnect()";
constexpr char TEXT_WIFICHANGEAUTOCONNECT[] = "Change auto connect";
@ -310,6 +311,9 @@ constexpr char TEXT_MODEUPDATERATE[] = "Mode update rate";
constexpr char TEXT_STATSUPDATERATE[] = "Stats update rate";
constexpr char TEXT_DISPLAYUPDATERATE[] = "Display update rate";
constexpr char TEXT_DISPLAYREDRAWRATE[] = "Display redraw rate";
#ifdef FEATURE_CAN
constexpr char TEXT_CANRECEIVERATE[] = "CAN receive rate";
#endif
//constexpr char TEXT_BACK[] = "Back";
//ChangeValueDisplay<BluetoothMode>

View File

@ -297,7 +297,7 @@ esp_err_t webserver_triggerItem_handler(httpd_req_t *req)
if (!menuDisplay)
CALL_AND_EXIT(httpd_resp_send_err, req, HTTPD_400_BAD_REQUEST, "currentDisplay is not a menu display");
if (index < 0 || index >= menuDisplay->menuItemCount())
if (/*index < 0 ||*/ index >= menuDisplay->menuItemCount())
CALL_AND_EXIT(httpd_resp_send_err, req, HTTPD_400_BAD_REQUEST, fmt::format("{} out of range", indexParamName).c_str());
menuDisplay->getMenuItem(index).triggered();

View File

@ -1,5 +1,8 @@
#pragma once
// esp-idf includes
#include <esp_log.h>
// 3rdparty lib includes
#include <espwifistack.h>
@ -10,7 +13,7 @@ namespace {
wifi_stack::config wifi_create_config()
{
static wifi_stack::config config {
.wifiEnabled = true,
.wifiEnabled = settings.wifiSettings.wifiEnabled,
.hostname = deviceName,
.sta = {
.wifis = std::array<wifi_stack::wifi_entry, 10> {
@ -49,44 +52,21 @@ wifi_stack::config wifi_create_config()
void wifi_begin()
{
wifi_stack::init(wifi_create_config());
//bootLabel.redraw("setHostname");
//if (!WiFi.setHostname(deviceName))
//{
//Serial.println("Could not setHostname");
//}
//printMemoryStats("setHostname()");
//bootLabel.redraw("softAPsetHostname");
//if (!WiFi.softAPsetHostname(deviceName))
//{
//Serial.println("Could not softAPsetHostname");
//}
//printMemoryStats("softAPsetHostname()");
//bootLabel.redraw("WiFi mode");
//if (!WiFi.mode(settings.wifiSettings.autoWifiMode))
//{
//Serial.println("Could not set mode to WIFI_AP_STA");
//}
//printMemoryStats("WiFi.mode()");
//if (settings.wifiSettings.autoEnableAp)
//{
//bootLabel.redraw("WiFi softAp");
//WifiSoftApAction{}.triggered();
//printMemoryStats("WifiSoftApAction()");
//}
//bootLabel.redraw("WiFi begin");
//if (!WiFi.begin("realraum", "r3alraum"))
//{
//Serial.println("Could not begin WiFi");
//}
//printMemoryStats("WiFi.begin()");
}
void wifi_update()
{
wifi_stack::update(wifi_create_config());
}
esp_err_t wifi_scan()
{
if (const auto result = wifi_stack::begin_scan(wifi_create_config()); result != ESP_OK)
{
ESP_LOGE("BOBBY", "begin_scan() failed with %s", esp_err_to_name(result));
return result;
}
return ESP_OK;
}
} // namespace