Work on decoding using structs
This commit is contained in:
4
TODO
4
TODO
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user