-
Notifications
You must be signed in to change notification settings - Fork 1
/
mbus_response.ino
executable file
·108 lines (95 loc) · 3.68 KB
/
mbus_response.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*
* mbus communication functions for emonMbus
* Based on OpenEnergyMonitor code by Trystan Lea, Glyn Hudson, and others
* https://github.com/openenergymonitor/HeatpumpMonitor
* Copyright 2018 Bryan McLellan <[email protected]>
* License: GPLv3 https://www.gnu.org/licenses/gpl.txt
*/
bool mbus_get_response(byte *pdata, unsigned char len_pdata) {
byte bid = 0; // current byte of response frame
byte bid_end = 255; // last byte of frame calculated from length byte sent
byte bid_checksum = 255; // checksum byte of frame (next to last)
byte len = 0;
byte checksum = 0;
bool long_frame_found = false;
bool complete_frame = false;
bool frame_error = false;
unsigned long timer_start = millis();
while (!frame_error && !complete_frame && (millis()-timer_start) < MBUS_TIMEOUT)
{
while (customSerial->available()) {
byte received_byte = (byte) customSerial->read();
// Try to skip noise
if (bid == 0 && received_byte != 0xE5 && received_byte != 0x68) {
if (DEBUG) Serial.print(F(">"));
continue;
}
if (bid > len_pdata) {
Serial.print("mbus: error: frame length exceeded variable size of ");
Serial.println(len_pdata);
return MBUS_BAD_FRAME;
}
pdata[bid] = received_byte;
// Single Character (ACK)
if (bid == 0 && received_byte == 0xE5) {
if (DEBUG) Serial.println(F("mbus: single character (ack)"));
return MBUS_GOOD_FRAME;
}
// Long frame start
if (bid == 0 && received_byte == 0x68) {
if (DEBUG) Serial.println(F("mbus: start long frame"));
long_frame_found = true;
}
if (long_frame_found) {
// 2nd byte is the frame length
if (bid == 1) {
len = received_byte;
bid_end = len+4+2-1;
bid_checksum = bid_end-1;
}
if (bid == 2 && received_byte != len) { // 3rd byte is also length, check that its the same as 2nd byte
if (DEBUG) Serial.println(F("mbus: frame length byte mismatch"));
frame_error = true;
}
if (bid == 3 && received_byte != 0x68) { ; // 4th byte is the start byte again
if (DEBUG) Serial.println(F("mbus: missing second start byte in long frame"));
frame_error = true;
}
if (bid > 3 && bid < bid_checksum) checksum += received_byte; // Increment checksum during data portion of frame
if (bid == bid_checksum && received_byte != checksum) { // Validate checksum
if (DEBUG) Serial.println(F("mbus: frame failed checksum"));
frame_error = true;
}
if (bid == bid_end && received_byte == 0x16) { // Parse frame if still valid
complete_frame = true;
}
}
bid++;
}
}
if (complete_frame && !frame_error) {
return MBUS_GOOD_FRAME;
} else {
return MBUS_BAD_FRAME;
}
}
// Spire 280T-S returns decimal values as hex, right to left for multi-byte values
// start_byte is first data byte / most significant data byte
long get_spire_value(byte *pdata, unsigned int start_byte, unsigned char num_bytes) {
String val;
for (int i = start_byte - 1 + num_bytes; i >= start_byte; i--) {
// Serial.println(String(pdata[i], HEX));
char hex[4];
sprintf(hex, "%.2X", pdata[i]); // ensure leading zeros are included
val = val + hex;
}
return val.toInt();
}
// Prints a whole response as a string for debugging
void print_bytes(byte *bytes, unsigned char len_bytes) {
for (int i = 0; i < len_bytes; i++) {
Serial.print(String(bytes[i], HEX));
Serial.print(F(" "));
}
Serial.println();
}