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

wirenboard / wb-mqtt-serial / 666

08 Jul 2025 11:10AM UTC coverage: 73.854% (+0.1%) from 73.706%
666

push

github

web-flow
Port handling refactoring (#960)

Pass port by reference when needed instead of storing it in every device

6444 of 9057 branches covered (71.15%)

526 of 700 new or added lines in 56 files covered. (75.14%)

6 existing lines in 5 files now uncovered.

12341 of 16710 relevant lines covered (73.85%)

305.53 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)
18✔
4
    : TSerialDevice(config, protocol),
5
      TUInt32SlaveId(config->SlaveId, true)
18✔
6
{
7
    if (HasBroadcastSlaveId) {
18✔
8
        SlaveId = 0;
×
9
    }
10
}
18✔
11

12
void TEMDevice::WriteCommand(TPort& port, uint8_t cmd, uint8_t* payload, int len)
163✔
13
{
14
    uint8_t buf[MAX_LEN], *p = buf;
163✔
15
    if (len + 3 + SlaveIdWidth > MAX_LEN)
163✔
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) {
335✔
20
        *p++ = (SlaveId & (0xFF << (8 * i))) >> (8 * i);
172✔
21
    }
22

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

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

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

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

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

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

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

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

76
void TEMDevice::Talk(TPort& port,
141✔
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);
141✔
86
    WriteCommand(port, cmd, payload, payload_len);
141✔
87
    try {
88
        while (!ReadResponse(port, expected_byte1, resp_payload, resp_payload_len, frame_complete)) {
145✔
89
            EnsureSlaveConnected(port, true);
2✔
90
            WriteCommand(port, cmd, payload, payload_len);
2✔
91
        }
92
    } catch (const TSerialDeviceTransientErrorException& e) {
4✔
93
        port.SkipNoise();
2✔
94
        throw;
2✔
95
    }
96
}
139✔
97

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

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

108
    ConnectedSlaves.insert(SlaveId);
20✔
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