Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
305 changes: 280 additions & 25 deletions src/MBUSPayload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ uint8_t MBUSPayload::addField(uint8_t code, float value) {
bool valid = (_getVIF(code, scalar) != 0xFF);

// Now move down
uint32_t scaled = round(value);
int32_t scaled = round(value);
while ((scaled % 10) == 0) {
scalar++;
scaled /= 10;
Expand Down Expand Up @@ -202,13 +202,125 @@ uint8_t MBUSPayload::decode(uint8_t *buffer, uint8_t size, JsonArray& root) {

// Decode DIF
uint8_t dif = buffer[index++];
bool bcd = ((dif & 0x08) == 0x08);
uint8_t len = (dif & 0x07);
if ((len < 1) || (4 < len)) {
_error = MBUS_ERROR::UNSUPPORTED_CODING;
return 0;
}
uint8_t difLeast4bit = (dif & 0x0F);
uint8_t difFunctionField = ((dif & 0x30) >> 4);
uint8_t len = 0;
uint8_t dataCodingType = 0;
/*
0 --> no Data
1 --> integer
2 --> bcd
3 --> real
4 --> variable lengs
5 --> special functions
6 --> TimePoint Date&Time Typ F
7 --> TimePoint Date Typ G

Length in Bit Code Meaning Code Meaning
0 0000 No data 1000 Selection for Readout
8 0001 8 Bit Integer 1001 2 digit BCD
16 0010 16 Bit Integer 1010 4 digit BCD
24 0011 24 Bit Integer 1011 6 digit BCD
32 0100 32 Bit Integer 1100 8 digit BCD
32 / N 0101 32 Bit Real 1101 variable length
48 0110 48 Bit Integer 1110 12 digit BCD
64 0111 64 Bit Integer 1111 Special Functions
*/

switch(difLeast4bit){
case 0x00: //No data
len = 0;
dataCodingType = 0;
break;
case 0x01: //0001 8 Bit Integer
len = 1;
dataCodingType = 1;
break;
case 0x02: //0010 16 Bit Integer
len = 2;
dataCodingType = 1;
break;
case 0x03: //0011 24 Bit Integer
len = 3;
dataCodingType = 1;
break;
case 0x04: //0100 32 Bit Integer
len = 4;
dataCodingType = 1;
break;
case 0x05: //0101 32 Bit Real
len = 4;
dataCodingType = 3;
break;
case 0x06: //0110 48 Bit Integer
len = 6;
dataCodingType = 1;
break;
case 0x07: //0111 64 Bit Integer
len = 8;
dataCodingType = 1;
break;
case 0x08: //not supported
len = 0;
dataCodingType = 0;
break;
case 0x09: //1001 2 digit BCD
len = 1;
dataCodingType = 2;
break;
case 0x0A: //1010 4 digit BCD
len = 2;
dataCodingType = 2;
break;
case 0x0B: //1011 6 digit BCD
len = 3;
dataCodingType = 2;
break;
case 0x0C: //1100 8 digit BCD
len = 4;
dataCodingType = 2;
break;
case 0x0D: //1101 variable length
len = 0;
dataCodingType = 4;
break;
case 0x0E: //1110 12 digit BCD
len = 6;
dataCodingType = 2;
break;
case 0x0F: //1111 Special Functions
len = 0;
dataCodingType = 5;
break;

}
char stringFunctionField[5];
switch(difFunctionField){
case 0:
strcpy(stringFunctionField, ""); //current
break;
case 1:
strcpy(stringFunctionField, "_max");
break;
case 2:
strcpy(stringFunctionField, "_min");
break;
case 3:
strcpy(stringFunctionField, "_err");
break;
}


// handle DIFE to prevent stumble if a DIFE is used
bool dife = ((dif & 0x80) == 0x80); //check if the first bit of DIF marked as "DIFE is following"
while(dife) {
index++;
dife = false;
dife = ((buffer[index-1] & 0x80) == 0x80); //check if after the DIFE another DIFE is following
}
// End of DIFE handling


// Get VIF(E)
uint32_t vif = 0;
do {
Expand All @@ -225,6 +337,13 @@ uint8_t MBUSPayload::decode(uint8_t *buffer, uint8_t size, JsonArray& root) {
_error = MBUS_ERROR::UNSUPPORTED_VIF;
return 0;
}

if((vif & 0x6D) == 0x6D){ // TimePoint Date&Time TypF
dataCodingType = 6;
}
else if((vif & 0x6C) == 0x6C){ // TimePoint Date TypG
dataCodingType = 7;
}

// Check buffer overflow
if (index + len > size) {
Expand All @@ -233,33 +352,150 @@ uint8_t MBUSPayload::decode(uint8_t *buffer, uint8_t size, JsonArray& root) {
}

// read value
uint32_t value = 0;
if (bcd) {
for (uint8_t i = 0; i<len; i++) {
uint8_t byte = buffer[index + len - i - 1];
value = (value * 100) + ((byte >> 4) * 10) + (byte & 0x0F);
}
} else {
for (uint8_t i = 0; i<len; i++) {
value = (value << 8) + buffer[index + len - i - 1];
}
int16_t value16 = 0; // int16_t to notice negative values at 2 byte data
int32_t value32 = 0; // int32_t to notice negative values at 4 byte data
int64_t value = 0;

float valueFloat = 0;


uint8_t date[len] ={0};
char datestring[12] = {0};
char datestring2[24] = {0};
int out_len = 0;

switch(dataCodingType){
case 0: //no Data

break;
case 1: //integer
if(len==2){
for (uint8_t i = 0; i<len; i++) {
value16 = (value16 << 8) + buffer[index + len - i - 1];
}
value = (int64_t)value16;
}
else if(len==4){
for (uint8_t i = 0; i<len; i++) {
value32 = (value32 << 8) + buffer[index + len - i - 1];
}
value = (int64_t)value32;
}
else{
for (uint8_t i = 0; i<len; i++) {
value = (value << 8) + buffer[index + len - i - 1];
}
}
break;
case 2: //bcd
if(len==2){
for (uint8_t i = 0; i<len; i++) {
uint8_t byte = buffer[index + len - i - 1];
value16 = (value16 * 100) + ((byte >> 4) * 10) + (byte & 0x0F);
}
value = (int64_t)value16;
}
else if(len==4){
for (uint8_t i = 0; i<len; i++) {
uint8_t byte = buffer[index + len - i - 1];
value32 = (value32 * 100) + ((byte >> 4) * 10) + (byte & 0x0F);
}
value = (int64_t)value32;
}
else{
for (uint8_t i = 0; i<len; i++) {
uint8_t byte = buffer[index + len - i - 1];
value = (value * 100) + ((byte >> 4) * 10) + (byte & 0x0F);
}
}
break;
case 3: //real
for (uint8_t i = 0; i<len; i++) {
value = (value << 8) + buffer[index + len - i - 1];
}
memcpy(&valueFloat, &value, sizeof(valueFloat));
break;
case 4: //variable lengs

break;
case 5: //special functions

break;
case 6: //TimePoint Date&Time Typ F

for (uint8_t i = 0; i<len; i++) {
date[i] = buffer[index + i];
}

if ((date[0] & 0x80) != 0) { // Time valid ?
//out_len = snprintf(output, output_size, "invalid");
break;
}
out_len = snprintf(datestring, 24, "%02d%02d%02d%02d%02d",
((date[2] & 0xE0) >> 5) | ((date[3] & 0xF0) >> 1), // year
date[3] & 0x0F, // mon
date[2] & 0x1F, // mday
date[1] & 0x1F, // hour
date[0] & 0x3F // sec
);

out_len = snprintf(datestring2, 24, "%02d-%02d-%02dT%02d:%02d:00",
((date[2] & 0xE0) >> 5) | ((date[3] & 0xF0) >> 1), // year
date[3] & 0x0F, // mon
date[2] & 0x1F, // mday
date[1] & 0x1F, // hour
date[0] & 0x3F // sec
);
value = atof( datestring);
break;
case 7: //TimePoint Date Typ G
for (uint8_t i = 0; i<len; i++) {
date[i] = buffer[index + i];
}

if ((date[1] & 0x0F) > 12) { // Time valid ?
//out_len = snprintf(output, output_size, "invalid");
break;
}
out_len = snprintf(datestring, 10, "%02d%02d%02d",
((date[0] & 0xE0) >> 5) | ((date[1] & 0xF0) >> 1), // year
date[1] & 0x0F, // mon
date[0] & 0x1F // mday
);
out_len = snprintf(datestring2, 10, "%02d-%02d-%02d",
((date[0] & 0xE0) >> 5) | ((date[1] & 0xF0) >> 1), // year
date[1] & 0x0F, // mon
date[0] & 0x1F // mday
);
value = atof( datestring);
break;
default:
break;
}

index += len;

// scaled value
int8_t scalar = vif_defs[def].scalar + vif - vif_defs[def].base;
double scaled = value;
for (int8_t i=0; i<scalar; i++) scaled *= 10;
for (int8_t i=scalar; i<0; i++) scaled /= 10;

double scaled = 0;
int8_t scalar = vif_defs[def].scalar + vif - vif_defs[def].base;
if(dataCodingType == 3){
scaled = valueFloat;
}
else{
scaled = value;
for (int8_t i=0; i<scalar; i++) scaled *= 10;
for (int8_t i=scalar; i<0; i++) scaled /= 10;
}
// Init object
JsonObject data = root.createNestedObject();
data["vif"] = vif;
data["code"] = vif_defs[def].code;
data["scalar"] = scalar;
data["value_raw"] = value;
data["value_scaled"] = scaled;
//data["units"] = String(getCodeUnits(vif_defs[def].code));
data["units"] = String(getCodeUnits(vif_defs[def].code));
data["name"] = String(getCodeName(vif_defs[def].code)+String(stringFunctionField));
// data["date"] = String(datestring2); formatted dates, optional

}

Expand Down Expand Up @@ -337,6 +573,12 @@ const char * MBUSPayload::getCodeUnits(uint8_t code) {
case MBUS_CODE::PRESSURE_BAR:
return "bar";

case MBUS_CODE::TIME_POINT_DATE:
return "Date_JJMMDD";

case MBUS_CODE::TIME_POINT_DATETIME:
return "Time_JJMMDDhhmm";

case MBUS_CODE::BAUDRATE_BPS:
return "bps";

Expand Down Expand Up @@ -365,6 +607,9 @@ const char * MBUSPayload::getCodeUnits(uint8_t code) {
case MBUS_CODE::TEMPERATURE_LIMIT_F:
return "F";

case MBUS_CODE::UNSUPPORTED_X:
return "X";

default:
break;

Expand Down Expand Up @@ -451,6 +696,10 @@ const char * MBUSPayload::getCodeName(uint8_t code) {
case MBUS_CODE::PRESSURE_BAR:
return "pressure";

case MBUS_CODE::TIME_POINT_DATE:
case MBUS_CODE::TIME_POINT_DATETIME:
return "time_point";

case MBUS_CODE::BAUDRATE_BPS:
return "baudrate";

Expand Down Expand Up @@ -487,6 +736,9 @@ const char * MBUSPayload::getCodeName(uint8_t code) {
case MBUS_CODE::FIRMWARE_VERSION:
return "firmware_version";

case MBUS_CODE::SOFTWARE_VERSION:
return "software_version"; //neu

case MBUS_CODE::CUSTOMER:
return "customer";

Expand Down Expand Up @@ -514,7 +766,9 @@ const char * MBUSPayload::getCodeName(uint8_t code) {
case MBUS_CODE::RESET_COUNTER:
case MBUS_CODE::CUMULATION_COUNTER:
return "counter";


case MBUS_CODE::UNSUPPORTED_X:
return "counter";
default:
break;

Expand All @@ -523,6 +777,7 @@ const char * MBUSPayload::getCodeName(uint8_t code) {
return "";

}

// ----------------------------------------------------------------------------

int8_t MBUSPayload::_findDefinition(uint32_t vif) {
Expand Down Expand Up @@ -551,4 +806,4 @@ uint32_t MBUSPayload::_getVIF(uint8_t code, int8_t scalar) {

return 0xFF; // this is not a valid VIF

}
}
Loading