• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wirenboard / wb-mqtt-serial / 2

29 Dec 2025 12:28PM UTC coverage: 76.817% (+4.0%) from 72.836%
2

Pull #1045

github

54aa0c
pgasheev
up changelog
Pull Request #1045: Fix firmware version in WB-M1W2 template

6873 of 9161 branches covered (75.02%)

12966 of 16879 relevant lines covered (76.82%)

1651.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.94
/src/devices/em_device.cpp
1
#include "em_device.h"
2

3
TEMDevice::TEMDevice(PDeviceConfig config, PProtocol protocol)
36✔
4
    : TSerialDevice(config, protocol),
5
      TUInt32SlaveId(config->SlaveId, true)
36✔
6
{
7
    if (HasBroadcastSlaveId) {
36✔
8
        SlaveId = 0;
×
9
    }
10
}
36✔
11

12
void TEMDevice::WriteCommand(TPort& port, uint8_t cmd, uint8_t* payload, int len)
326✔
13
{
14
    uint8_t buf[MAX_LEN], *p = buf;
326✔
15
    if (len + 3 + SlaveIdWidth > MAX_LEN)
326✔
16
        throw TSerialDeviceException("outgoing command too long");
×
17

18
    // SlaveId is sent in reverse (little-endian) order
19
    for (int i = 0; i < SlaveIdWidth; ++i) {
670✔
20
        *p++ = (SlaveId & (0xFF << (8 * i))) >> (8 * i);
344✔
21
    }
22

23
    *p++ = cmd;
326✔
24
    while (len--)
1,064✔
25
        *p++ = *payload++;
738✔
26
    uint16_t crc = CRC16::CalculateCRC16(buf, p - buf);
326✔
27
    *p++ = crc >> 8;
326✔
28
    *p++ = crc & 0xff;
326✔
29
    port.WriteBytes(buf, p - buf);
652✔
30
}
326✔
31

32
bool TEMDevice::ReadResponse(TPort& port,
326✔
33
                             int expectedByte1,
34
                             uint8_t* payload,
35
                             int len,
36
                             TPort::TFrameCompletePred frame_complete)
37
{
38
    uint8_t buf[MAX_LEN], *p = buf;
326✔
39
    int nread = port.ReadFrame(buf, MAX_LEN, GetResponseTimeout(port), GetFrameTimeout(port), frame_complete).Count;
326✔
40
    if (nread < 3 + SlaveIdWidth)
326✔
41
        throw TSerialDeviceTransientErrorException("frame too short");
×
42

43
    uint16_t crc = CRC16::CalculateCRC16(buf, nread - 2), crc1 = buf[nread - 2], crc2 = buf[nread - 1],
326✔
44
             actualCrc = (crc1 << 8) + crc2;
326✔
45
    if (crc != actualCrc)
326✔
46
        throw TSerialDeviceTransientErrorException("invalid crc");
×
47

48
    for (int i = 0; i < SlaveIdWidth; ++i) {
670✔
49
        if (*p++ != (SlaveId & (0xFF << (8 * i))) >> (8 * i)) {
344✔
50
            throw TSerialDeviceTransientErrorException("invalid slave id");
×
51
        }
52
    }
53

54
    const char* msg;
55
    ErrorType err = CheckForException(buf, nread, &msg);
326✔
56
    if (err == NO_OPEN_SESSION)
326✔
57
        return false;
4✔
58
    if (err == PERMANENT_ERROR)
322✔
59
        throw TSerialDevicePermanentRegisterException(msg);
×
60
    if (err != NO_ERROR)
322✔
61
        throw TSerialDeviceTransientErrorException(msg);
4✔
62

63
    if (expectedByte1 >= 0 && *p++ != expectedByte1)
318✔
64
        throw TSerialDeviceTransientErrorException("invalid command code in the response");
×
65

66
    int actualPayloadSize = nread - (p - buf) - 2;
318✔
67
    if (len >= 0 && len != actualPayloadSize)
318✔
68
        throw TSerialDeviceTransientErrorException("unexpected frame size");
×
69
    else
70
        len = actualPayloadSize;
318✔
71

72
    std::memcpy(payload, p, len);
318✔
73
    return true;
644✔
74
}
75

76
void TEMDevice::Talk(TPort& port,
282✔
77
                     uint8_t cmd,
78
                     uint8_t* payload,
79
                     int payload_len,
80
                     int expected_byte1,
81
                     uint8_t* resp_payload,
82
                     int resp_payload_len,
83
                     TPort::TFrameCompletePred frame_complete)
84
{
85
    EnsureSlaveConnected(port);
282✔
86
    WriteCommand(port, cmd, payload, payload_len);
282✔
87
    try {
88
        while (!ReadResponse(port, expected_byte1, resp_payload, resp_payload_len, frame_complete)) {
290✔
89
            EnsureSlaveConnected(port, true);
4✔
90
            WriteCommand(port, cmd, payload, payload_len);
4✔
91
        }
92
    } catch (const TSerialDeviceTransientErrorException& e) {
8✔
93
        port.SkipNoise();
4✔
94
        throw;
4✔
95
    }
96
}
278✔
97

98
void TEMDevice::EnsureSlaveConnected(TPort& port, bool force)
286✔
99
{
100
    if (!force && ConnectedSlaves.find(SlaveId) != ConnectedSlaves.end())
286✔
101
        return;
246✔
102

103
    ConnectedSlaves.erase(SlaveId);
40✔
104
    port.SkipNoise();
40✔
105
    if (!ConnectionSetup(port))
40✔
106
        throw TSerialDeviceTransientErrorException("failed to establish meter connection");
×
107

108
    ConnectedSlaves.insert(SlaveId);
40✔
109
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc