diff --git a/src/MBusCom.cpp b/src/MBusCom.cpp index d863278..b7f03d6 100644 --- a/src/MBusCom.cpp +++ b/src/MBusCom.cpp @@ -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 +} + diff --git a/src/MBusCom.h b/src/MBusCom.h index 1bc284d..3034315 100644 --- a/src/MBusCom.h +++ b/src/MBusCom.h @@ -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: