diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 3762eff..e07280e 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,6 +1,7 @@ set(BOBBY_HEADERS accessorhelpers.h antbms.h + antbmsmanager.h accessors/globalaccessors.h accessors/settingsaccessors.h accessors/wifiaccessors.h @@ -259,6 +260,7 @@ set(BOBBY_HEADERS set(BOBBY_SOURCES antbms.cpp + antbmsmanager.cpp accessors/wifistaconfigaccessors.cpp actions/assertaction.cpp actions/bmsclearscanaction.cpp diff --git a/main/antbms.cpp b/main/antbms.cpp index ee33d70..4d81824 100644 --- a/main/antbms.cpp +++ b/main/antbms.cpp @@ -1,350 +1,108 @@ #include "antbms.h" -// local includes -#include "bmsutils.h" -#include "newsettings.h" +// esp-idf includes +#include -using namespace std::chrono_literals; +BmsInstruction::BmsInstruction(uint8_t b, uint8_t b2) : + functionCode{b}, + length{b2} +{} -void ANTBms::init() +void BmsInstruction::setData(uint8_t *_data, uint8_t _length) { - // init code - m_initialized = true; - - // scan - startScan(); + std::copy(_data, _data + _length, this->data); } -void ANTBms::update() +int BmsInstruction::getAddress() const { - if (!m_initialized) - return; + return address; +} - handleConnect(); +void BmsInstruction::setAddress(int _address) +{ + address = _address; +} - if (m_client && (*m_client)->isConnected()) +uint8_t *BmsInstruction::getInstruction() +{ + if (length == 0) { - requestData(); + return BmsBluetoothInst::buildReadBmsInst(functionCode, address, 0); } + return BmsBluetoothInst::buildReadBmsInstWithData(this->functionCode, this->address, this->length, this->data); } -void ANTBms::deinit() +std::string BmsInstruction::toString() const { - // deinit code - m_initialized = false; + return "BmsInstruction{functionCode=" + std::to_string(functionCode) + ", address=" + std::to_string(address) + ", inst = " + ", data = " + "}"; +} - if (m_client) +int CRC16::calcCrc16(const uint8_t *data, uint16_t len) +{ + // calculate crc16 + uint16_t crc = 0xFFFF; + + for (int pos = 0; pos < len; pos++) { - (*m_client)->disconnect(); - m_client.reset(); - } + crc ^= (uint16_t) data[pos]; // XOR byte into least sig. byte of crc - 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 &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; + for (int i = 8; i != 0; i--) + { // Loop over each bit + if ((crc & 0x0001) != 0) + { // If the LSB is set + crc >>= 1; // Shift right and XOR 0xA001 + crc ^= 0xA001; } - ESP_LOGI(TAG, "Reconnected to client"); - } - else - { - m_client = NimBLEDevice::getDisconnectedClient(); + else // Else LSB is not set + crc >>= 1; // Just shift right } } - 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; - } - } + return crc; } -void ANTBms::notifyCB(NimBLERemoteCharacteristic *pRemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify) +uint8_t *BmsBluetoothInst::buildReadBmsInst(uint8_t b, int i, uint8_t b2) { - ESP_LOGI(TAG, "Received %s: %s (%.*s)", isNotify ? "notification" : "indication", bmsutils::bytesToHex(pData, length).c_str(), length, pData); + auto *bArr = new uint8_t[64]; + bArr[0] = PROTOCOL_FRAME_HEAD; + bArr[1] = PROTOCOL_ADD; + bArr[2] = b; + bArr[3] = (uint8_t) (i & 255); + bArr[4] = (uint8_t) ((i >> 8) & 255); + bArr[5] = b2; + int crc16 = CRC16::calcCrc16(bArr + 1, 5); + ESP_LOGI(TAG, "crc: %d", crc16); + bArr[6] = (uint8_t) (crc16 >> 8); + bArr[7] = (uint8_t) (crc16 & 255); + bArr[8] = -86; + bArr[9] = 85; + return bArr; } -void ANTBms::requestData() +uint8_t *BmsBluetoothInst::buildReadBmsInstWithData(uint8_t b, int i, uint8_t b2, uint8_t *bArr) { - if (!m_initialized) - return; - - if (!m_connected) - return; - - if (espchrono::ago(m_lastRequestTime) > 2000ms || m_newPacketReceived) + auto *bArr2 = new uint8_t[64 + sizeof(bArr)]; + bArr2[0] = PROTOCOL_FRAME_HEAD; + bArr2[1] = PROTOCOL_ADD; + bArr2[2] = b; + bArr2[3] = (uint8_t) (i & 255); + bArr2[4] = (uint8_t) ((i >> 8) & 255); + bArr2[5] = b2; + int i2 = 5; + for (int _i = 0; _i < sizeof(bArr); _i++) { - m_lastRequestTime = espchrono::millis_clock::now(); - - if (m_toggle) - { - bmsGetInfo3(); - m_newPacketReceived = false; - } - else - { - bmsGetInfo4(); - m_newPacketReceived = false; - } - m_toggle = !m_toggle; + i2++; + bArr2[i2] = bArr[_i]; } -} - -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)); + int i3 = i2 + 1; + int crc16 = CRC16::calcCrc16(bArr2 + 1, (uint16_t) (sizeof(bArr) + 5)); + ESP_LOGI(TAG, "crc: %d", crc16); + bArr2[i3] = (uint8_t) (crc16 >> 8); + int i4 = i3 + 1; + bArr2[i4] = (uint8_t) (crc16 & 255); + int i5 = i4 + 1; + bArr2[i5] = -86; + int i6 = i5 + 1; + bArr2[i6] = 85; + return bArr2; } diff --git a/main/antbms.h b/main/antbms.h index e1274e7..0c244f8 100644 --- a/main/antbms.h +++ b/main/antbms.h @@ -1,126 +1,53 @@ #pragma once -// TODO: jetbrains://idea/navigate/reference?project=bms_base_source_from_JADX&path=com/mayi/bms/bluetooth/BmsBluetoothManager.java - // system includes -#include +#include +#include -// esp-idf includes -#include - -// 3rdparty lib includes -#include -#include - -typedef struct { - NimBLEAddress address; - std::string name; -} scanResult_t; - -typedef struct { - std::vector 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 +class CRC16 { 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 &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 m_client; - std::optional m_service; - std::optional m_rxCharacteristic; - std::optional m_txCharacteristic; - - std::optional m_scanResults; - - espchrono::millis_clock::time_point m_lastRequestTime; - - void bmsGetInfo3(); - void bmsGetInfo4(); + static int calcCrc16(const uint8_t *data, uint16_t len); +}; + +class BmsBluetoothInst +{ +public: + static constexpr const char * const TAG = "BMSBluetoothInst"; + + static uint8_t *buildReadBmsInst(uint8_t b, int i, uint8_t b2); + + static uint8_t *buildReadBmsInstWithData(uint8_t b, int i, uint8_t b2, uint8_t *bArr); + + static constexpr uint8_t PROTOCOL_ADD = 0xA1; + static constexpr uint8_t PROTOCOL_FRAME_HEAD = 0x7E; +}; + +class BmsInstruction +{ +private: + const uint8_t functionCode; + const uint8_t length; + + int address{0}; + + uint8_t data[32]{}; +public: + static constexpr const char * const TAG = "BMSInstruction"; + + BmsInstruction(uint8_t b, uint8_t b2); + + void setData(uint8_t *data, uint8_t length); + + [[nodiscard]] uint8_t getLength() const; + + [[nodiscard]] uint8_t getFunctionCode() const; + + [[nodiscard]] int getAddress() const; + + void setAddress(int address); + + uint8_t* getInstruction(); + + [[nodiscard]] std::string toString() const; }; diff --git a/main/antbmsmanager.cpp b/main/antbmsmanager.cpp new file mode 100644 index 0000000..03748d3 --- /dev/null +++ b/main/antbmsmanager.cpp @@ -0,0 +1,330 @@ +#include "antbmsmanager.h" + +// local includes +#include "antbms.h" +#include "bmsutils.h" +#include "newsettings.h" + +using namespace std::chrono_literals; + +void ANTBmsManager::init() +{ + // init code + m_initialized = true; + + // scan + startScan(); +} + +void ANTBmsManager::update() +{ + if (!m_initialized) + return; + + handleConnect(); + + if (m_client && (*m_client)->isConnected()) + { + requestData(); + } +} + +void ANTBmsManager::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 ANTBmsManager::isInitialized() const +{ + return m_initialized; +} + +void ANTBmsManager::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 ANTBmsManager::clearScanResults() +{ + m_scanResults.reset(); +} + +bool ANTBmsManager::getScanStatus() const +{ + return m_scanStarted; +} + +const std::optional &ANTBmsManager::getScanResults() +{ + return m_scanResults; +} + +void ANTBmsManager::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(); // this sometimes crashes with StoreProhibited + + 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; + 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 ANTBmsManager::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 ANTBmsManager::requestData() +{ + if (!m_initialized) + return; + + if (!m_connected) + return; + + if (espchrono::ago(m_lastRequestTime) > 2000ms || m_newPacketReceived) + { + m_lastRequestTime = espchrono::millis_clock::now(); + + readBmsState(); + } +} + +void ANTBmsManager::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 ANTBmsManager::readBmsState() +{ + BmsInstruction bmsInstruction = BmsInstruction(1, -66); + ESP_LOGI(TAG, "read real status, inst: %s", bmsInstruction.toString().c_str()); + const auto inst = bmsInstruction.getInstruction(); + sendCommand(inst, sizeof(inst)); +} + diff --git a/main/antbmsmanager.h b/main/antbmsmanager.h new file mode 100644 index 0000000..83c48b0 --- /dev/null +++ b/main/antbmsmanager.h @@ -0,0 +1,123 @@ +#pragma once + +// system includes +#include + +// esp-idf includes +#include + +// 3rdparty lib includes +#include +#include + +typedef struct { + NimBLEAddress address; + std::string name; +} scanResult_t; + +typedef struct { + std::vector 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 ANTBmsManager +{ +public: + static constexpr const char * const TAG = "ANTBMS-MANAGER"; + + // basic functions + void init(); + void update(); + void deinit(); + + [[nodiscard]] bool isInitialized() const; + + // scans + void startScan(); + + [[nodiscard]] bool getScanStatus() const; + + const std::optional &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); + + void readBmsState(); +private: + + class ScanResultsCallback : public NimBLEScanCallbacks + { + public: + explicit ScanResultsCallback(ANTBmsManager* 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: + ANTBmsManager* m_antBms; + }; + + class ClientCallbacks : public NimBLEClientCallbacks + { + public: + explicit ClientCallbacks(ANTBmsManager* 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: + ANTBmsManager* m_antBms; + }; + + bool m_initialized{false}; + bool m_scanStarted{false}; + bool m_connected{false}; + + bool m_newPacketReceived{false}; + bool m_toggle{false}; + + std::optional m_client; + std::optional m_service; + std::optional m_rxCharacteristic; + std::optional m_txCharacteristic; + + std::optional m_scanResults; + + espchrono::millis_clock::time_point m_lastRequestTime; +}; diff --git a/main/bmsutils.cpp b/main/bmsutils.cpp index f998140..1d7b038 100644 --- a/main/bmsutils.cpp +++ b/main/bmsutils.cpp @@ -11,7 +11,7 @@ namespace bmsutils { -ANTBms antBms; +ANTBmsManager antBms; void init() {} @@ -24,7 +24,7 @@ void update() ESP_LOGI("bmsutils", "initializing bms"); antBms.init(); } - else if (!configs.bmsEnabled.value() && initialized) + else if ((!configs.bmsEnabled.value() || !configs.bleSettings.bleEnabled.value()) && initialized) { ESP_LOGI("bmsutils", "deinitializing bms"); antBms.deinit(); diff --git a/main/bmsutils.h b/main/bmsutils.h index ae41fed..de3c702 100644 --- a/main/bmsutils.h +++ b/main/bmsutils.h @@ -1,10 +1,10 @@ #pragma once // local includes -#include "antbms.h" +#include "antbmsmanager.h" namespace bmsutils { -extern ANTBms antBms; +extern ANTBmsManager antBms; void init();