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
85 changes: 85 additions & 0 deletions src/MBusCom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,5 +227,90 @@ uint8_t MBusCom::read_rxbuffer(uint8_t *pdata, size_t len_pdata) {
return i;
}

// ============================================================================
// Slave functions
// ============================================================================

bool MBusCom::receiveShortFrame(uint8_t &cField, uint8_t &address) {
unsigned long start = millis();

// Wait for start byte (0x10) or ACK (0xE5)
while (millis() - start < 500) {
if (!_MbusSerial->available()) continue;

byte b = (byte)_MbusSerial->read();

// ACK received from master (unusual, ignore)
if (b == 0xE5) {
return false;
}

// Short frame start found
if (b != MBUS_FRAME_SHORT_START) continue;

// Read remaining 4 bytes: C, A, CHK, 0x16
byte buf[5];
buf[0] = b; // 0x10
unsigned long byteStart = millis();
uint8_t idx = 1;
while (idx < 5 && millis() - byteStart < 200) {
if (_MbusSerial->available()) {
buf[idx++] = (byte)_MbusSerial->read();
byteStart = millis();
}
}

if (idx != 5) return false;

// Validate stop byte
if (buf[4] != MBUS_FRAME_STOP) return false;

// Validate checksum: CHK = C + A
if (buf[3] != (buf[1] + buf[2])) return false;

cField = buf[1];
address = buf[2];
return true;
}
return false;
}

void MBusCom::sendAck() {
_MbusSerial->write(0xE5);
}

void MBusCom::sendResponse(uint8_t address, const uint8_t *data, uint16_t len) {
// Build long frame: 0x68 | L | L | 0x68 | C | A | CI | Data... | CHK | 0x16
// C-field response: 0x08 (RSP_UD, no error)
// Address is inverted (XOR 0xFF)

uint8_t cField = 0x08; // RSP_UD response from slave
uint8_t ciField = data[0]; // CI-field from data

// Frame: start(1) + len(1) + len(1) + start(1) + C(1) + A(1) + data(len) + chk(1) + stop(1)
// Total: 6 + len
uint16_t frameLen = len + 6;

// For frames > 200, length is encoded differently, but for typical
// M-Bus responses (< 200 bytes) single-byte length is fine.

uint8_t chk = 0;
chk += cField;
chk += address;
for (uint16_t i = 0; i < len; i++) {
chk += data[i];
}

_MbusSerial->write(MBUS_FRAME_LONG_START); // 0x68
_MbusSerial->write((uint8_t)(len + 1)); // L = data + C + A (not including CI separately, it's part of data)
_MbusSerial->write((uint8_t)(len + 1)); // L repeated
_MbusSerial->write(MBUS_FRAME_LONG_START); // 0x68
_MbusSerial->write(cField); // 0x08 RSP_UD
_MbusSerial->write(address); // slave address
_MbusSerial->write(data, len); // CI + data records
_MbusSerial->write(chk); // checksum
_MbusSerial->write(MBUS_FRAME_STOP); // 0x16
}



5 changes: 5 additions & 0 deletions src/MBusCom.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ class MBusCom {
bool available();
void application_reset(byte address);
uint8_t read_rxbuffer(uint8_t *pdata, size_t len_pdata);// for debug use

// Slave functions
bool receiveShortFrame(uint8_t &cField, uint8_t &address);
void sendAck();
void sendResponse(uint8_t address, const uint8_t *data, uint16_t len);

protected:

Expand Down