Work on decoding using structs

This commit is contained in:
2025-12-18 22:27:15 +11:00
parent 2ccac7b0c8
commit 139c6f961d
3 changed files with 87 additions and 35 deletions

4
TODO
View File

@@ -2,3 +2,7 @@
* Consider support for upper/lower case MAC address and optionaly ":" * Consider support for upper/lower case MAC address and optionaly ":"
* Scanning - list devices publishing, should be able to get list even without knowing MAC / Encryption key * Scanning - list devices publishing, should be able to get list even without knowing MAC / Encryption key
* Struct vs Manual
* Sh3dNg version and examples uses structs to get data - seems to work
* Example generated uses manually managing a string
* Reconsider what is best and use

View File

@@ -213,6 +213,8 @@ void VictronBLE::processDevice(BLEAdvertisedDevice advertisedDevice) {
return; return;
} }
// XXX Use struct like code in Sh3dNg
// Check if it's Victron (manufacturer ID 0x02E1) // Check if it's Victron (manufacturer ID 0x02E1)
uint16_t mfgId = (uint8_t)mfgData[1] << 8 | (uint8_t)mfgData[0]; uint16_t mfgId = (uint8_t)mfgData[1] << 8 | (uint8_t)mfgData[0];
if (mfgId != VICTRON_MANUFACTURER_ID) { if (mfgId != VICTRON_MANUFACTURER_ID) {
@@ -236,9 +238,11 @@ bool VictronBLE::parseAdvertisement(const uint8_t* manufacturerData, size_t len,
const String& macAddress) { const String& macAddress) {
auto it = devices.find(macAddress); auto it = devices.find(macAddress);
if (it == devices.end()) { if (it == devices.end()) {
debugPrint("parseAdvertisement: Device not found");
return false; return false;
} }
// XXX Work out second?
DeviceInfo* deviceInfo = it->second; DeviceInfo* deviceInfo = it->second;
if (len < 6) { if (len < 6) {
@@ -246,18 +250,29 @@ bool VictronBLE::parseAdvertisement(const uint8_t* manufacturerData, size_t len,
return false; return false;
} }
// XXX map to struct - NOTE: Check size first (exact? or bigger?)
victronManufacturerData * vicData=(victronManufacturerData *)manufacturerData;
debugPrint("VendorID" + String(vicData->vendorID));
debugPrint("Record Type" + String(vicData->victronRecordType));
// Structure: [MfgID(2)] [DeviceType(1)] [IV(2)] [EncryptedData(n)] // Structure: [MfgID(2)] [DeviceType(1)] [IV(2)] [EncryptedData(n)]
uint8_t deviceType = manufacturerData[2]; // XXX This is actually 4 - Struct would help - it was 2
uint8_t deviceType = manufacturerData[4];
// Extract IV (initialization vector) - bytes 3-4, little-endian // Extract IV (initialization vector) - bytes 3-4, little-endian
// XXX These look wrong
uint8_t iv[16] = {0}; uint8_t iv[16] = {0};
iv[0] = manufacturerData[3]; iv[0] = manufacturerData[3];
iv[1] = manufacturerData[4]; iv[1] = manufacturerData[4];
// Rest of IV is zero-padded // Rest of IV is zero-padded
// Encrypted data starts at byte 5 // Encrypted data starts at byte 5
const uint8_t* encryptedData = manufacturerData + 5; // const uint8_t* encryptedData = manufacturerData + 5;
size_t encryptedLen = len - 5; // size_t encryptedLen = len - 5;
// XXX Experiment
const uint8_t* encryptedData = vicData->victronEncryptedData;
size_t encryptedLen = sizeof(vicData->victronEncryptedData);
if (debugEnabled) { if (debugEnabled) {
debugPrintHex("Encrypted data", encryptedData, encryptedLen); debugPrintHex("Encrypted data", encryptedData, encryptedLen);

View File

@@ -53,6 +53,39 @@ enum SolarChargerState {
CHARGER_EXTERNAL_CONTROL = 252 CHARGER_EXTERNAL_CONTROL = 252
}; };
// XXX HARD Core structs
// Used for decoding
// But then data is put into specific device structs
// Which means a lot of overlap - reconsider...
// NOTE: c struct vs classes
// Must use the "packed" attribute to make sure the compiler doesn't add any padding to deal with
// word alignment.
typedef struct {
uint8_t deviceState;
uint8_t errorCode;
int16_t batteryVoltage;
int16_t batteryCurrent;
uint16_t todayYield;
uint16_t inputPower;
uint8_t outputCurrentLo; // Low 8 bits of output current (in 0.1 Amp increments)
uint8_t outputCurrentHi; // High 1 bit of ourput current (must mask off unused bits)
uint8_t unused[4];
} __attribute__((packed)) victronPanelData; // XXX Specific type -
typedef struct {
uint16_t vendorID; // vendor ID
uint8_t beaconType; // Should be 0x10 (Product Advertisement) for the packets we want
uint8_t unknownData1[3]; // Unknown data
uint8_t victronRecordType; // Should be 0x01 (Solar Charger) for the packets we want
uint16_t nonceDataCounter; // Nonce
uint8_t encryptKeyMatch; // Should match pre-shared encryption key byte 0
uint8_t victronEncryptedData[21]; // (31 bytes max per BLE spec - size of previous elements)
uint8_t nullPad; // extra byte because toCharArray() adds a \0 byte.
} __attribute__((packed)) victronManufacturerData;
// XXX End of new bit above
// Base structure for all device data // Base structure for all device data
struct VictronDeviceData { struct VictronDeviceData {
String deviceName; String deviceName;