Initial bms work; protocol is todo
This commit is contained in:
@@ -470,12 +470,12 @@ CONFIG_BT_CONTROLLER_ENABLED=y
|
||||
#
|
||||
CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y
|
||||
# CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_DEFAULT is not set
|
||||
# CONFIG_BT_NIMBLE_LOG_LEVEL_NONE is not set
|
||||
CONFIG_BT_NIMBLE_LOG_LEVEL_NONE=y
|
||||
# CONFIG_BT_NIMBLE_LOG_LEVEL_ERROR is not set
|
||||
# CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING is not set
|
||||
# CONFIG_BT_NIMBLE_LOG_LEVEL_INFO is not set
|
||||
CONFIG_BT_NIMBLE_LOG_LEVEL_DEBUG=y
|
||||
CONFIG_BT_NIMBLE_LOG_LEVEL=0
|
||||
# CONFIG_BT_NIMBLE_LOG_LEVEL_DEBUG is not set
|
||||
CONFIG_BT_NIMBLE_LOG_LEVEL=4
|
||||
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=3
|
||||
CONFIG_BT_NIMBLE_MAX_BONDS=3
|
||||
CONFIG_BT_NIMBLE_MAX_CCCDS=8
|
||||
@@ -1814,12 +1814,12 @@ CONFIG_TFT_LOAD_FONT7=y
|
||||
#
|
||||
# ESP-NimBLE-CPP configuration
|
||||
#
|
||||
# CONFIG_NIMBLE_CPP_LOG_LEVEL_NONE is not set
|
||||
CONFIG_NIMBLE_CPP_LOG_LEVEL_NONE=y
|
||||
# CONFIG_NIMBLE_CPP_LOG_LEVEL_ERROR is not set
|
||||
# CONFIG_NIMBLE_CPP_LOG_LEVEL_WARNING is not set
|
||||
CONFIG_NIMBLE_CPP_LOG_LEVEL_INFO=y
|
||||
# CONFIG_NIMBLE_CPP_LOG_LEVEL_INFO is not set
|
||||
# CONFIG_NIMBLE_CPP_LOG_LEVEL_DEBUG is not set
|
||||
CONFIG_NIMBLE_CPP_LOG_LEVEL=3
|
||||
CONFIG_NIMBLE_CPP_LOG_LEVEL=0
|
||||
# CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT is not set
|
||||
# CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT is not set
|
||||
# CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT is not set
|
||||
|
@@ -1,11 +1,14 @@
|
||||
set(BOBBY_HEADERS
|
||||
accessorhelpers.h
|
||||
antbms.h
|
||||
accessors/globalaccessors.h
|
||||
accessors/settingsaccessors.h
|
||||
accessors/wifiaccessors.h
|
||||
accessors/wifiapconfigaccessors.h
|
||||
accessors/wifistaconfigaccessors.h
|
||||
actions/assertaction.h
|
||||
actions/bmsclearscanaction.h
|
||||
actions/bmsscanaction.h
|
||||
actions/dividebyzeroaction.h
|
||||
actions/erasenvsaction.h
|
||||
actions/ledstripanimationactions.h
|
||||
@@ -127,6 +130,7 @@ set(BOBBY_HEADERS
|
||||
screens/batteryinfodisplay.h
|
||||
screens/batterymenu.h
|
||||
screens/blesettingsmenu.h
|
||||
screens/bmsscanmenu.h
|
||||
screens/boardcomputerhardwaresettingsmenu.h
|
||||
screens/buzzermenu.h
|
||||
screens/calibratevoltagedisplay.h
|
||||
@@ -254,8 +258,11 @@ set(BOBBY_HEADERS
|
||||
)
|
||||
|
||||
set(BOBBY_SOURCES
|
||||
antbms.cpp
|
||||
accessors/wifistaconfigaccessors.cpp
|
||||
actions/assertaction.cpp
|
||||
actions/bmsclearscanaction.cpp
|
||||
actions/bmsscanaction.cpp
|
||||
actions/dividebyzeroaction.cpp
|
||||
actions/ledstripanimationactions.cpp
|
||||
actions/ledstripblinkactions.cpp
|
||||
@@ -356,6 +363,7 @@ set(BOBBY_SOURCES
|
||||
screens/batteryinfodisplay.cpp
|
||||
screens/batterymenu.cpp
|
||||
screens/blesettingsmenu.cpp
|
||||
screens/bmsscanmenu.cpp
|
||||
screens/boardcomputerhardwaresettingsmenu.cpp
|
||||
screens/buzzermenu.cpp
|
||||
screens/calibratevoltagedisplay.cpp
|
||||
|
@@ -274,3 +274,5 @@ struct FlipScreenAccessor : public NewSettingsAccessor<bool> { ConfigWrapper<boo
|
||||
// Other
|
||||
struct AnhaengerIdAccessor : public NewSettingsAccessor<uint16_t> { ConfigWrapper<uint16_t> &getConfig() const override { return configs.anhaenger_id; } };
|
||||
struct UsernameAccessor : public NewSettingsAccessor<std::string> { ConfigWrapper<std::string> &getConfig() const override { return configs.otaUsername; } };
|
||||
|
||||
struct BMSEnabledAccessor : public NewSettingsAccessor<bool> { ConfigWrapper<bool> &getConfig() const override { return configs.bmsEnabled; } };
|
||||
|
9
main/actions/bmsclearscanaction.cpp
Normal file
9
main/actions/bmsclearscanaction.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "bmsclearscanaction.h"
|
||||
|
||||
// local includes
|
||||
#include "bmsutils.h"
|
||||
|
||||
void BMSClearScanAction::triggered()
|
||||
{
|
||||
bmsutils::antBms.clearScanResults();
|
||||
}
|
10
main/actions/bmsclearscanaction.h
Normal file
10
main/actions/bmsclearscanaction.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <actioninterface.h>
|
||||
|
||||
class BMSClearScanAction : public virtual espgui::ActionInterface
|
||||
{
|
||||
public:
|
||||
void triggered() override;
|
||||
};
|
9
main/actions/bmsscanaction.cpp
Normal file
9
main/actions/bmsscanaction.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "bmsscanaction.h"
|
||||
|
||||
// local includes
|
||||
#include "bmsutils.h"
|
||||
|
||||
void BMSScanAction::triggered()
|
||||
{
|
||||
bmsutils::antBms.startScan();
|
||||
}
|
10
main/actions/bmsscanaction.h
Normal file
10
main/actions/bmsscanaction.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <actioninterface.h>
|
||||
|
||||
class BMSScanAction : public virtual espgui::ActionInterface
|
||||
{
|
||||
public:
|
||||
void triggered() override;
|
||||
};
|
350
main/antbms.cpp
Normal file
350
main/antbms.cpp
Normal file
@@ -0,0 +1,350 @@
|
||||
#include "antbms.h"
|
||||
|
||||
// local includes
|
||||
#include "bmsutils.h"
|
||||
#include "newsettings.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
void ANTBms::init()
|
||||
{
|
||||
// init code
|
||||
m_initialized = true;
|
||||
|
||||
// scan
|
||||
startScan();
|
||||
}
|
||||
|
||||
void ANTBms::update()
|
||||
{
|
||||
if (!m_initialized)
|
||||
return;
|
||||
|
||||
handleConnect();
|
||||
|
||||
if (m_client && (*m_client)->isConnected())
|
||||
{
|
||||
requestData();
|
||||
}
|
||||
}
|
||||
|
||||
void ANTBms::deinit()
|
||||
{
|
||||
// deinit code
|
||||
m_initialized = false;
|
||||
|
||||
if (m_client)
|
||||
{
|
||||
(*m_client)->disconnect();
|
||||
m_client.reset();
|
||||
}
|
||||
|
||||
if (m_scanResults)
|
||||
{
|
||||
m_scanResults.reset();
|
||||
}
|
||||
|
||||
if (m_service)
|
||||
{
|
||||
m_service.reset();
|
||||
}
|
||||
|
||||
if (m_rxCharacteristic)
|
||||
{
|
||||
m_rxCharacteristic.reset();
|
||||
}
|
||||
|
||||
if (m_txCharacteristic)
|
||||
{
|
||||
m_txCharacteristic.reset();
|
||||
}
|
||||
|
||||
m_scanStarted = false;
|
||||
m_initialized = false;
|
||||
}
|
||||
|
||||
bool ANTBms::isInitialized() const
|
||||
{
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
void ANTBms::startScan()
|
||||
{
|
||||
if (!m_initialized)
|
||||
return;
|
||||
|
||||
ESP_LOGI(TAG, "starting scan");
|
||||
|
||||
NimBLEScan* pScan = NimBLEDevice::getScan();
|
||||
pScan->setActiveScan(true);
|
||||
pScan->setInterval(100);
|
||||
pScan->setWindow(99);
|
||||
pScan->setScanCallbacks(new ScanResultsCallback(this), false);
|
||||
pScan->start(5000);
|
||||
|
||||
ESP_LOGI(TAG, "scan started");
|
||||
|
||||
m_scanStarted = true;
|
||||
}
|
||||
|
||||
void ANTBms::clearScanResults()
|
||||
{
|
||||
m_scanResults.reset();
|
||||
}
|
||||
|
||||
bool ANTBms::getScanStatus() const
|
||||
{
|
||||
return m_scanStarted;
|
||||
}
|
||||
|
||||
const std::optional<scanResults_t> &ANTBms::getScanResults()
|
||||
{
|
||||
return m_scanResults;
|
||||
}
|
||||
|
||||
void ANTBms::handleConnect()
|
||||
{
|
||||
if (!m_initialized)
|
||||
return;
|
||||
|
||||
ESP_LOGD(TAG, "!m_initialized passed");
|
||||
|
||||
if (m_connected)
|
||||
return;
|
||||
|
||||
ESP_LOGD(TAG, "m_connected passed");
|
||||
|
||||
if (!m_scanResults)
|
||||
return;
|
||||
|
||||
ESP_LOGD(TAG, "!m_scanResults passed");
|
||||
|
||||
if (m_scanResults && m_scanResults->entries.empty())
|
||||
return;
|
||||
|
||||
ESP_LOGD(TAG, "m_scanResults->entries.empty() passed");
|
||||
|
||||
if (m_client && (*m_client)->isConnected())
|
||||
return;
|
||||
|
||||
ESP_LOGD(TAG, "!m_client.has_value() passed");
|
||||
|
||||
if (configs.bmsAddress.value().empty())
|
||||
return;
|
||||
|
||||
ESP_LOGD(TAG, "configs.bmsAddress.value().empty() passed");
|
||||
|
||||
ESP_LOGI(TAG, "connecting to bms");
|
||||
|
||||
if (NimBLEDevice::getClientListSize())
|
||||
{
|
||||
m_client = NimBLEDevice::getClientByPeerAddress(configs.bmsAddress.value());
|
||||
|
||||
if (m_client)
|
||||
{
|
||||
if (!(*m_client)->connect(configs.bmsAddress.value()))
|
||||
{
|
||||
ESP_LOGE(TAG, "Reconnect failed");
|
||||
m_client.reset();
|
||||
m_service.reset();
|
||||
m_rxCharacteristic.reset();
|
||||
m_txCharacteristic.reset();
|
||||
|
||||
m_connected = false;
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Reconnected to client");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_client = NimBLEDevice::getDisconnectedClient();
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_client)
|
||||
{
|
||||
if (NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS)
|
||||
{
|
||||
ESP_LOGE(TAG, "Max clients reached - no more connections available!");
|
||||
return;
|
||||
}
|
||||
|
||||
m_client = NimBLEDevice::createClient();
|
||||
|
||||
const auto pClient = *m_client;
|
||||
|
||||
pClient->setClientCallbacks(new ClientCallbacks(this), false);
|
||||
pClient->setConnectTimeout(10);
|
||||
pClient->setConnectionParams(12, 12, 0, 51);
|
||||
|
||||
if (!pClient->connect(configs.bmsAddress.value()))
|
||||
{
|
||||
NimBLEDevice::deleteClient(pClient);
|
||||
m_client.reset();
|
||||
m_service.reset();
|
||||
m_rxCharacteristic.reset();
|
||||
m_txCharacteristic.reset();
|
||||
|
||||
m_connected = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(*m_client)->isConnected())
|
||||
{
|
||||
if (!(*m_client)->connect(configs.bmsAddress.value()))
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to connect");
|
||||
m_client.reset();
|
||||
m_service.reset();
|
||||
m_rxCharacteristic.reset();
|
||||
m_txCharacteristic.reset();
|
||||
|
||||
m_connected = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Connected!");
|
||||
m_connected = true;
|
||||
|
||||
m_service = (*m_client)->getService(serviceUUID);
|
||||
|
||||
if (!m_service)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to find our service UUID: %s", serviceUUID.toString().c_str());
|
||||
m_client.reset();
|
||||
m_service.reset();
|
||||
m_rxCharacteristic.reset();
|
||||
m_txCharacteristic.reset();
|
||||
|
||||
m_connected = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_service && (*m_service))
|
||||
{
|
||||
ESP_LOGI(TAG, "Getting characteristic");
|
||||
m_rxCharacteristic = (*m_service)->getCharacteristic(charRXUUID);
|
||||
m_txCharacteristic = (*m_service)->getCharacteristic(charTXUUID);
|
||||
|
||||
if ((m_rxCharacteristic && (*m_rxCharacteristic)) && (m_txCharacteristic && (*m_txCharacteristic)))
|
||||
{
|
||||
const auto pChr = *m_rxCharacteristic;
|
||||
|
||||
if (pChr->canNotify())
|
||||
{
|
||||
ESP_LOGI(TAG, "Subscribing to notifications");
|
||||
if (!pChr->subscribe(true, bmsutils::_notifyCB))
|
||||
{
|
||||
(*m_client)->disconnect();
|
||||
ESP_LOGE(TAG, "Failed to subscribe for notifications");
|
||||
m_client.reset();
|
||||
m_service.reset();
|
||||
m_rxCharacteristic.reset();
|
||||
|
||||
m_connected = false;
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Subscribed for notifications");
|
||||
|
||||
m_connected = true;
|
||||
|
||||
// 7ea1010000be1855aa55
|
||||
uint8_t data[10] = {0x7e, 0xa1, 0x01, 0x00, 0x00, 0xbe, 0x18, 0x55, 0xaa, 0x55};
|
||||
sendCommand(data, sizeof(data));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "Characteristic can't notify, disconnecting");
|
||||
(*m_client)->disconnect();
|
||||
m_client.reset();
|
||||
m_service.reset();
|
||||
m_rxCharacteristic.reset();
|
||||
|
||||
m_connected = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to find our characteristic UUID: %s", charRXUUID.toString().c_str());
|
||||
m_client.reset();
|
||||
m_service.reset();
|
||||
m_rxCharacteristic.reset();
|
||||
|
||||
m_connected = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ANTBms::notifyCB(NimBLERemoteCharacteristic *pRemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify)
|
||||
{
|
||||
ESP_LOGI(TAG, "Received %s: %s (%.*s)", isNotify ? "notification" : "indication", bmsutils::bytesToHex(pData, length).c_str(), length, pData);
|
||||
}
|
||||
|
||||
void ANTBms::requestData()
|
||||
{
|
||||
if (!m_initialized)
|
||||
return;
|
||||
|
||||
if (!m_connected)
|
||||
return;
|
||||
|
||||
if (espchrono::ago(m_lastRequestTime) > 2000ms || m_newPacketReceived)
|
||||
{
|
||||
m_lastRequestTime = espchrono::millis_clock::now();
|
||||
|
||||
if (m_toggle)
|
||||
{
|
||||
bmsGetInfo3();
|
||||
m_newPacketReceived = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bmsGetInfo4();
|
||||
m_newPacketReceived = false;
|
||||
}
|
||||
m_toggle = !m_toggle;
|
||||
}
|
||||
}
|
||||
|
||||
void ANTBms::sendCommand(uint8_t *pData, size_t length)
|
||||
{
|
||||
if (!m_initialized)
|
||||
return;
|
||||
|
||||
if (!m_connected)
|
||||
return;
|
||||
|
||||
if (!m_txCharacteristic)
|
||||
return;
|
||||
|
||||
if (!(*m_txCharacteristic))
|
||||
return;
|
||||
|
||||
if (!(*m_txCharacteristic)->canWrite())
|
||||
return;
|
||||
|
||||
ESP_LOGI(TAG, "Sending command: %s", bmsutils::bytesToHex(pData, length).c_str());
|
||||
|
||||
(*m_txCharacteristic)->writeValue(pData, length, true);
|
||||
}
|
||||
|
||||
void ANTBms::bmsGetInfo3()
|
||||
{
|
||||
// DD A5 03 00 FF FD 77
|
||||
uint8_t data[7] = {0xdd, 0xa5, 0x3, 0x0, 0xff, 0xfd, 0x77};
|
||||
|
||||
sendCommand(data, sizeof(data));
|
||||
}
|
||||
|
||||
void ANTBms::bmsGetInfo4()
|
||||
{
|
||||
// DD A5 04 00 FF FC 77
|
||||
uint8_t data[7] = {0xdd, 0xa5, 0x4, 0x0, 0xff, 0xfc, 0x77};
|
||||
|
||||
sendCommand(data, sizeof(data));
|
||||
}
|
126
main/antbms.h
Normal file
126
main/antbms.h
Normal file
@@ -0,0 +1,126 @@
|
||||
#pragma once
|
||||
|
||||
// TODO: jetbrains://idea/navigate/reference?project=bms_base_source_from_JADX&path=com/mayi/bms/bluetooth/BmsBluetoothManager.java
|
||||
|
||||
// system includes
|
||||
#include <optional>
|
||||
|
||||
// esp-idf includes
|
||||
#include <esp_log.h>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <NimBLEDevice.h>
|
||||
#include <espchrono.h>
|
||||
|
||||
typedef struct {
|
||||
NimBLEAddress address;
|
||||
std::string name;
|
||||
} scanResult_t;
|
||||
|
||||
typedef struct {
|
||||
std::vector<scanResult_t> entries;
|
||||
} scanResults_t;
|
||||
|
||||
const NimBLEUUID serviceUUID{"0000ffe0-0000-1000-8000-00805f9b34fb"};
|
||||
const NimBLEUUID charRXUUID {"0000ffe1-0000-1000-8000-00805f9b34fb"};
|
||||
//const NimBLEUUID charTXUUID {"0000ffe1-0000-1000-8000-00805f9b34fb"}; // same as RX
|
||||
const NimBLEUUID charTXUUID {"0000ffe2-0000-1000-8000-00805f9b34fb"}; // different
|
||||
|
||||
class ANTBms
|
||||
{
|
||||
public:
|
||||
static constexpr const char * const TAG = "ANTBMS";
|
||||
|
||||
// basic functions
|
||||
void init();
|
||||
void update();
|
||||
void deinit();
|
||||
|
||||
[[nodiscard]] bool isInitialized() const;
|
||||
|
||||
// scans
|
||||
void startScan();
|
||||
|
||||
[[nodiscard]] bool getScanStatus() const;
|
||||
|
||||
const std::optional<scanResults_t> &getScanResults();
|
||||
void clearScanResults();
|
||||
|
||||
void handleConnect();
|
||||
|
||||
void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify);
|
||||
|
||||
void requestData();
|
||||
void sendCommand(uint8_t *pData, size_t length);
|
||||
private:
|
||||
|
||||
class ScanResultsCallback : public NimBLEScanCallbacks
|
||||
{
|
||||
public:
|
||||
explicit ScanResultsCallback(ANTBms* antBms) : m_antBms{antBms} {}
|
||||
|
||||
void onScanEnd(NimBLEScanResults scanResults) override
|
||||
{
|
||||
m_antBms->m_scanResults.reset();
|
||||
|
||||
ESP_LOGI(TAG, "BLE Scan complete");
|
||||
|
||||
scanResults_t results;
|
||||
|
||||
for (auto &result : scanResults)
|
||||
{
|
||||
if (result->isAdvertisingService(serviceUUID))
|
||||
{
|
||||
scanResult_t scanResult;
|
||||
scanResult.address = result->getAddress();
|
||||
scanResult.name = result->getName();
|
||||
results.entries.push_back(scanResult);
|
||||
}
|
||||
}
|
||||
|
||||
m_antBms->m_scanResults = results;
|
||||
|
||||
m_antBms->m_scanStarted = false;
|
||||
}
|
||||
private:
|
||||
ANTBms* m_antBms;
|
||||
};
|
||||
|
||||
class ClientCallbacks : public NimBLEClientCallbacks
|
||||
{
|
||||
public:
|
||||
explicit ClientCallbacks(ANTBms* antBms) : m_antBms{antBms} {}
|
||||
void onConnect(NimBLEClient* pClient) override
|
||||
{
|
||||
m_antBms->m_connected = true;
|
||||
ESP_LOGD(TAG, "Connected to server");
|
||||
}
|
||||
|
||||
void onDisconnect(NimBLEClient* pClient, int reason) override
|
||||
{
|
||||
m_antBms->m_connected = false;
|
||||
ESP_LOGI(TAG, "Disconnected from server (%d)", reason);
|
||||
}
|
||||
private:
|
||||
ANTBms* m_antBms;
|
||||
};
|
||||
|
||||
bool m_initialized{false};
|
||||
bool m_scanStarted{false};
|
||||
bool m_connected{false};
|
||||
|
||||
bool m_newPacketReceived{false};
|
||||
bool m_toggle{false};
|
||||
|
||||
std::optional<NimBLEClient*> m_client;
|
||||
std::optional<NimBLERemoteService*> m_service;
|
||||
std::optional<NimBLERemoteCharacteristic*> m_rxCharacteristic;
|
||||
std::optional<NimBLERemoteCharacteristic*> m_txCharacteristic;
|
||||
|
||||
std::optional<scanResults_t> m_scanResults;
|
||||
|
||||
espchrono::millis_clock::time_point m_lastRequestTime;
|
||||
|
||||
void bmsGetInfo3();
|
||||
void bmsGetInfo4();
|
||||
};
|
@@ -55,7 +55,12 @@ void createBle()
|
||||
{
|
||||
ESP_LOGI("BOBBY", "called");
|
||||
|
||||
NimBLEDevice::init(configs.bluetoothName.value());
|
||||
if (!NimBLEDevice::getInitialized())
|
||||
{
|
||||
ESP_LOGI("BOBBY", "Initializing BLE");
|
||||
NimBLEDevice::init(configs.bluetoothName.value());
|
||||
NimBLEDevice::setPower(ESP_PWR_LVL_P9);
|
||||
}
|
||||
|
||||
const auto serviceUuid{"0335e46c-f355-4ce6-8076-017de08cee98"};
|
||||
|
||||
@@ -94,7 +99,10 @@ void destroyBle()
|
||||
{
|
||||
ESP_LOGI("BOBBY", "called");
|
||||
|
||||
NimBLEDevice::deinit(true);
|
||||
if (NimBLEDevice::getInitialized())
|
||||
{
|
||||
NimBLEDevice::deinit(true);
|
||||
}
|
||||
|
||||
pServer = {};
|
||||
pService = {};
|
||||
|
@@ -1,4 +1,56 @@
|
||||
#include "bmsutils.h"
|
||||
|
||||
namespace bms {
|
||||
} // namespace bms
|
||||
// system includes
|
||||
#include <iomanip>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <NimBLEDevice.h>
|
||||
|
||||
// local includes
|
||||
#include "newsettings.h"
|
||||
|
||||
namespace bmsutils {
|
||||
|
||||
ANTBms antBms;
|
||||
|
||||
void init() {}
|
||||
|
||||
void update()
|
||||
{
|
||||
const auto initialized = antBms.isInitialized();
|
||||
|
||||
if (configs.bmsEnabled.value() && !initialized && NimBLEDevice::getInitialized())
|
||||
{
|
||||
ESP_LOGI("bmsutils", "initializing bms");
|
||||
antBms.init();
|
||||
}
|
||||
else if (!configs.bmsEnabled.value() && initialized)
|
||||
{
|
||||
ESP_LOGI("bmsutils", "deinitializing bms");
|
||||
antBms.deinit();
|
||||
}
|
||||
|
||||
if (initialized && NimBLEDevice::getInitialized())
|
||||
{
|
||||
antBms.update();
|
||||
}
|
||||
}
|
||||
|
||||
void _notifyCB(NimBLERemoteCharacteristic *pRemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify)
|
||||
{
|
||||
ESP_LOGI("bmsutils", "notifyCB: %s", bmsutils::bytesToHex(pData, length).c_str());
|
||||
antBms.notifyCB(pRemoteCharacteristic, pData, length, isNotify);
|
||||
}
|
||||
|
||||
std::string bytesToHex(uint8_t *pData, size_t length)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
for (size_t i = 0; i < length; i++)
|
||||
{
|
||||
ss << std::hex << std::setfill('0') << std::setw(2) << (int)pData[i];
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
} // namespace bmsutils
|
||||
|
@@ -1,4 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
namespace bms {
|
||||
} // namespace bms
|
||||
// local includes
|
||||
#include "antbms.h"
|
||||
|
||||
namespace bmsutils {
|
||||
extern ANTBms antBms;
|
||||
|
||||
void init();
|
||||
|
||||
void update();
|
||||
|
||||
void _notifyCB(NimBLERemoteCharacteristic *pRemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify);
|
||||
|
||||
std::string bytesToHex(uint8_t *pData, size_t length);
|
||||
} // namespace bmsutils
|
||||
|
@@ -487,7 +487,10 @@ public:
|
||||
ConfigWrapperLegacy<bool> bleFenceEnabled {false, DoReset, {}, "bleFenceEnabled" };
|
||||
} bleSettings;
|
||||
|
||||
ConfigWrapperLegacy<bool> setupDone {false, DoReset, {}, "setupDone" };
|
||||
ConfigWrapperLegacy<bool> setupDone {false, DoReset, {}, "setupDone" };
|
||||
|
||||
ConfigWrapperLegacy<bool> bmsEnabled {false, DoReset, {}, "bmsEnabled" };
|
||||
ConfigWrapperLegacy<std::string> bmsAddress {std::string{}, DoReset, {}, "bmsAddress" };
|
||||
|
||||
#define NEW_SETTINGS(x) \
|
||||
x(baseMacAddressOverride) \
|
||||
@@ -809,10 +812,12 @@ public:
|
||||
x(feature.webserver.isEnabled) \
|
||||
x(feature.webserver_disable_lock.isEnabled) \
|
||||
x(bleSettings.bleEnabled) \
|
||||
x(emulateFeedback)
|
||||
x(emulateFeedback) \
|
||||
x(setupDone) \
|
||||
x(bmsEnabled)
|
||||
|
||||
#define FEATURES(x) \
|
||||
x(feature.ble) \
|
||||
x(feature.ble) \
|
||||
x(feature.cloud) \
|
||||
x(feature.dnsannounce)\
|
||||
x(feature.esp_now) \
|
||||
@@ -831,7 +836,7 @@ public:
|
||||
#define HELPER(x) callback(x);
|
||||
NEW_SETTINGS(HELPER)
|
||||
#undef HELPER
|
||||
callback(bleSettings.bleFenceEnabled);
|
||||
callback(bmsAddress);
|
||||
}
|
||||
|
||||
auto getAllConfigParams()
|
||||
@@ -840,7 +845,7 @@ public:
|
||||
#define HELPER(x) std::ref<ConfigWrapperInterface>(x),
|
||||
NEW_SETTINGS(HELPER)
|
||||
#undef HELPER
|
||||
std::ref<ConfigWrapperInterface>(bleSettings.bleFenceEnabled)
|
||||
std::ref<ConfigWrapperInterface>(bmsAddress)
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -10,10 +10,10 @@
|
||||
|
||||
// local includes
|
||||
#include "accessors/settingsaccessors.h"
|
||||
#include "bmsscanmenu.h"
|
||||
#include "guihelpers/bobbychangevaluedisplay.h"
|
||||
#include "guihelpers/bobbycheckbox.h"
|
||||
#include "icons/back.h"
|
||||
#include "screens/settingsmenu.h"
|
||||
#include "texthelpers/bletexthelpers.h"
|
||||
|
||||
namespace bobby {
|
||||
@@ -21,6 +21,8 @@ namespace bobby {
|
||||
namespace {
|
||||
constexpr char TEXT_BLESETTINGS[] = "BLE settings";
|
||||
constexpr char TEXT_ENABLED[] = "Enabled";
|
||||
constexpr char TEXT_BMS_ENABLED[] = "BMS enabled";
|
||||
constexpr char TEXT_BMS_SCANS[] = "BMS scans";
|
||||
constexpr char TEXT_FENCE_ENABLED[] = "Fence enabled";
|
||||
constexpr char TEXT_NAME[] = "Name";
|
||||
constexpr char TEXT_NAME_FORMATTED[] = "Name: &s";
|
||||
@@ -39,6 +41,10 @@ BleSettingsMenu::BleSettingsMenu()
|
||||
{
|
||||
using namespace espgui;
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_ENABLED>, BobbyCheckbox, BleEnabledAccessor>>();
|
||||
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BMS_ENABLED>, BobbyCheckbox, BMSEnabledAccessor>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BMS_SCANS>, PushScreenAction<BMSScanMenu>>>();
|
||||
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_FENCE_ENABLED>, BobbyCheckbox, BleFenceEnabledAccessor>>();
|
||||
constructMenuItem<makeComponent<MenuItem, BleServerPeerDevicesText, DisabledColor, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, BleCharacSubscribedText, DisabledColor, DummyAction>>();
|
||||
|
140
main/screens/bmsscanmenu.cpp
Normal file
140
main/screens/bmsscanmenu.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
#include "bmsscanmenu.h"
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <actions/popscreenaction.h>
|
||||
#include <fmt/format.h>
|
||||
#include <menuitem.h>
|
||||
#include <richtextrenderer.h>
|
||||
#include <screenmanager.h>
|
||||
|
||||
// local includes
|
||||
#include "actions/bmsclearscanaction.h"
|
||||
#include "actions/bmsscanaction.h"
|
||||
#include "bmsutils.h"
|
||||
#include "guihelpers/bobbypopupdisplay.h"
|
||||
#include "icons/back.h"
|
||||
#include "newsettings.h"
|
||||
|
||||
namespace bobby {
|
||||
|
||||
using namespace espgui;
|
||||
|
||||
namespace {
|
||||
constexpr char TEXT_STARTSCAN[] = "Start scan";
|
||||
constexpr char TEXT_CLEARRESULTS[] = "Clear results";
|
||||
constexpr char TEXT_BACK[] = "Back";
|
||||
|
||||
class BMSScanMenuItem : public MenuItem
|
||||
{
|
||||
public:
|
||||
BMSScanMenuItem(const scanResult_t &info) : m_info{info} {}
|
||||
|
||||
void setInfo(const scanResult_t &info) { m_info = info; }
|
||||
|
||||
void triggered() override;
|
||||
std::string text() const override;
|
||||
|
||||
private:
|
||||
scanResult_t m_info;
|
||||
};
|
||||
|
||||
constexpr const size_t extraItemsAtBeginning = 2; // Scan and clear
|
||||
} // namespace
|
||||
|
||||
BMSScanMenu::BMSScanMenu()
|
||||
{
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_STARTSCAN>, BMSScanAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_CLEARRESULTS>, BMSClearScanAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, PopScreenAction, StaticMenuItemIcon<&bobbyicons::back>>>();
|
||||
}
|
||||
|
||||
std::string BMSScanMenu::text() const
|
||||
{
|
||||
const bool scanStatus = bmsutils::antBms.getScanStatus();
|
||||
const auto &results = bmsutils::antBms.getScanResults();
|
||||
|
||||
auto text = fmt::format("Scan {}{}",
|
||||
[&](){
|
||||
if (scanStatus) return "&4";
|
||||
else return "&2";
|
||||
}(),
|
||||
[&](){
|
||||
if (scanStatus) return "Scanning";
|
||||
else return "Finished";
|
||||
}());
|
||||
|
||||
if (!scanStatus && results)
|
||||
text += fmt::format("&c ({} found)", results->entries.size());
|
||||
else if (!scanStatus && !results)
|
||||
text += fmt::format("&c (0 found)");
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
void BMSScanMenu::back()
|
||||
{
|
||||
popScreen();
|
||||
}
|
||||
|
||||
void BMSScanMenu::start()
|
||||
{
|
||||
Base::start();
|
||||
|
||||
m_wasScanning = true;
|
||||
}
|
||||
|
||||
void BMSScanMenu::update()
|
||||
{
|
||||
const auto scanStatus = bmsutils::antBms.getScanStatus();
|
||||
|
||||
if (scanStatus && !m_wasScanning)
|
||||
{
|
||||
m_wasScanning = true;
|
||||
}
|
||||
else if (!scanStatus && m_wasScanning)
|
||||
{
|
||||
m_wasScanning = false;
|
||||
|
||||
auto backButton = takeLastMenuItem();
|
||||
|
||||
const auto &result = bmsutils::antBms.getScanResults();
|
||||
|
||||
for (std::size_t i = 0; i < (result ? result->entries.size() : 0); i++)
|
||||
{
|
||||
if (menuItemCount() - extraItemsAtBeginning <= i)
|
||||
constructMenuItem<BMSScanMenuItem>(result->entries[i]);
|
||||
else
|
||||
((BMSScanMenuItem*)(&getMenuItem(i + extraItemsAtBeginning)))->setInfo(result->entries[i]);
|
||||
}
|
||||
|
||||
while (menuItemCount() - extraItemsAtBeginning > (result ? result->entries.size() : 0))
|
||||
takeLastMenuItem();
|
||||
|
||||
emplaceMenuItem(std::move(backButton));
|
||||
}
|
||||
|
||||
Base::update();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void BMSScanMenuItem::triggered()
|
||||
{
|
||||
configs.write_config(configs.bmsAddress, m_info.address);
|
||||
popScreen();
|
||||
}
|
||||
|
||||
std::string BMSScanMenuItem::text() const
|
||||
{
|
||||
return fmt::format("{}{}",
|
||||
[&](){
|
||||
if (m_info.name.find("ANT-BLE") != std::string::npos || m_info.address == configs.bmsAddress.value())
|
||||
return "&2";
|
||||
return "";
|
||||
}(),
|
||||
m_info.name.empty() ? m_info.address.toString() : m_info.name
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace bobby
|
25
main/screens/bmsscanmenu.h
Normal file
25
main/screens/bmsscanmenu.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
// local includes
|
||||
#include "guihelpers/bobbymenudisplay.h"
|
||||
|
||||
namespace bobby {
|
||||
|
||||
class BMSScanMenu : public BobbyMenuDisplay
|
||||
{
|
||||
using Base = BobbyMenuDisplay;
|
||||
public:
|
||||
BMSScanMenu();
|
||||
|
||||
std::string text() const override;
|
||||
|
||||
void start() override;
|
||||
void update() override;
|
||||
|
||||
void back() override;
|
||||
|
||||
private:
|
||||
bool m_wasScanning{false};
|
||||
};
|
||||
|
||||
} // namespace bobby
|
@@ -19,6 +19,6 @@ public:
|
||||
void update() override;
|
||||
|
||||
private:
|
||||
bool m_wasScanning;
|
||||
bool m_wasScanning{false};
|
||||
};
|
||||
} // namespace bobby
|
||||
|
@@ -38,6 +38,7 @@
|
||||
#include "screens.h"
|
||||
#include "utils.h"
|
||||
#include "feedbackemulator.h"
|
||||
#include "bmsutils.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
@@ -68,6 +69,7 @@ BobbySchedulerTask schedulerTasksArr[] {
|
||||
#endif
|
||||
BobbySchedulerTask { "ota", initOta, handleOta, 75ms, false },
|
||||
BobbySchedulerTask { "ble", initBle, handleBle, 100ms, false },
|
||||
BobbySchedulerTask { "bms", bmsutils::init, bmsutils::update, 100ms, false },
|
||||
BobbySchedulerTask { "webserver", initWebserver, handleWebserver, 100ms, false },
|
||||
BobbySchedulerTask { "ledstrip", initLedStrip, updateLedStrip, 24ms, false },
|
||||
BobbySchedulerTask { "espnow", espnow::initESPNow, espnow::handle, 150ms, false },
|
||||
|
Reference in New Issue
Block a user