• 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

89.71
/src/devices/ivtm_device.cpp
1
#include <cstdio>
2
#include <cstring>
3
#include <errno.h>
4
#include <fcntl.h>
5
#include <stdio.h>
6
#include <string.h>
7
#include <string>
8
#include <sys/ioctl.h>
9
#include <sys/select.h>
10
#include <sys/stat.h>
11
#include <sys/types.h>
12
#include <termios.h>
13
#include <unistd.h>
14

15
#include "ivtm_device.h"
16

17
void TIVTMDevice::Register(TSerialDeviceFactory& factory)
143✔
18
{
19
    factory.RegisterProtocol(
143✔
20
        new TUint32SlaveIdProtocol("ivtm", TRegisterTypes({{0, "default", "value", Float, true}})),
429✔
21
        new TBasicDeviceFactory<TIVTMDevice>("#/definitions/simple_device", "#/definitions/common_channel"));
286✔
22
}
143✔
23

24
TIVTMDevice::TIVTMDevice(PDeviceConfig config, PProtocol protocol)
1✔
25
    : TSerialDevice(config, protocol),
26
      TUInt32SlaveId(config->SlaveId)
1✔
27
{}
1✔
28

29
void TIVTMDevice::WriteCommand(TPort& port, uint16_t addr, uint16_t data_addr, uint8_t data_len)
3✔
30
{
31
    port.CheckPortOpen();
3✔
32
    uint8_t buf[16];
33
    buf[0] = '$';
3✔
34

35
    snprintf((char*)&buf[1], 3, "%02X", addr >> 8);
3✔
36
    snprintf((char*)&buf[3], 3, "%02X", addr & 0xFF);
3✔
37

38
    buf[5] = 'R';
3✔
39
    buf[6] = 'R';
3✔
40

41
    snprintf((char*)&buf[7], 3, "%02X", data_addr >> 8);
3✔
42
    snprintf((char*)&buf[9], 3, "%02X", data_addr & 0xFF);
3✔
43

44
    snprintf((char*)&buf[11], 3, "%02X", data_len);
3✔
45

46
    uint8_t crc8 = 0;
3✔
47
    for (size_t i = 0; i < 13; ++i) {
42✔
48
        crc8 += buf[i];
39✔
49
    }
50

51
    snprintf((char*)&buf[13], 3, "%02X", crc8);
3✔
52
    buf[15] = 0x0d;
3✔
53

54
    port.WriteBytes(buf, 16);
3✔
55
}
3✔
56

57
static const int MAX_LEN = 100;
58

59
bool TIVTMDevice::DecodeASCIIBytes(uint8_t* buf, uint8_t* result, uint8_t len_bytes)
6✔
60
{
61
    for (size_t i = 0; i < len_bytes; ++i) {
24✔
62
        result[i] = DecodeASCIIByte(buf + i * 2);
18✔
63
    }
64
    return true;
6✔
65
}
66

67
uint8_t TIVTMDevice::DecodeASCIIByte(uint8_t* buf)
21✔
68
{
69
    std::string s(buf, buf + 2);
21✔
70
    return stoul(s, nullptr, 16);
42✔
71
}
72

73
uint16_t TIVTMDevice::DecodeASCIIWord(uint8_t* buf)
3✔
74
{
75
    uint8_t decoded_buf[2];
76
    DecodeASCIIBytes(buf, decoded_buf, 2);
3✔
77

78
    return (decoded_buf[0] << 8) | decoded_buf[1];
3✔
79
}
80

81
void TIVTMDevice::ReadResponse(TPort& port, uint16_t addr, uint8_t* payload, uint16_t len)
3✔
82
{
83
    uint8_t buf[MAX_LEN];
84

85
    auto nread = port.ReadFrame(buf,
3✔
86
                                MAX_LEN,
NEW
87
                                GetResponseTimeout(port),
×
88
                                GetFrameTimeout(port),
3✔
89
                                [](uint8_t* buf, int size) { return size > 0 && buf[size - 1] == '\r'; })
60✔
90
                     .Count;
3✔
91
    if (nread < 10)
3✔
92
        throw TSerialDeviceTransientErrorException("frame too short");
×
93

94
    if ((buf[0] != '!') || (buf[5] != 'R') || (buf[6] != 'R')) {
3✔
95
        throw TSerialDeviceTransientErrorException("invalid response header");
×
96
    }
97

98
    if (buf[nread - 1] != 0x0D) {
3✔
99
        throw TSerialDeviceTransientErrorException("invalid response footer");
×
100
    }
101

102
    if (DecodeASCIIWord(&buf[1]) != addr) {
3✔
103
        throw TSerialDeviceTransientErrorException("invalid slave addr in response");
×
104
    }
105

106
    uint8_t crc8 = 0;
3✔
107
    for (size_t i = 0; i < (size_t)nread - 3; ++i) {
48✔
108
        crc8 += buf[i];
45✔
109
    }
110

111
    uint8_t actualCrc = DecodeASCIIByte(&buf[nread - 3]);
3✔
112

113
    if (crc8 != actualCrc)
3✔
114
        throw TSerialDeviceTransientErrorException("invalid crc");
×
115

116
    int actualPayloadSize = nread - 10; // in ASCII symbols
3✔
117
    if (len * 2 != actualPayloadSize) {
3✔
118
        throw TSerialDeviceTransientErrorException("unexpected frame size");
×
119
    } else {
120
        len = actualPayloadSize / 2;
3✔
121
    }
122

123
    DecodeASCIIBytes(buf + 7, payload, len);
3✔
124
}
3✔
125

126
TRegisterValue TIVTMDevice::ReadRegisterImpl(TPort& port, const TRegisterConfig& reg)
3✔
127
{
128
    port.SkipNoise();
3✔
129

130
    auto addr = GetUint32RegisterAddress(reg.GetAddress());
3✔
131
    WriteCommand(port, SlaveId, addr, reg.GetByteWidth());
3✔
132
    uint8_t response[4];
133
    ReadResponse(port, SlaveId, response, reg.GetByteWidth());
3✔
134

135
    uint8_t* p = response; //&response[(address % 2) * 4];
3✔
136

137
    // the response is little-endian. We inverse the byte order here to make it big-endian.
138

139
    return TRegisterValue{static_cast<uint64_t>((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0])};
6✔
140
}
141

142
#if 0
143
int main(int, char**)
144
{
145
    try {
146
        TIVTMDevice bus("/dev/ttyNSC1");
147
        bus.Open();
148
        int v = bus.ReadRegister(0x01, 0x0a);
149
        std::cout << "value of mod 0x01 reg 0x0a: " << v << std::endl;
150
        for (int i = 0; i < 8; ++i) {
151
            bus.WriteRegister(0x01, 0x02 + i, 0x00); // manual control of the channel (low threshold = 0)
152
            int address = 0x1a + i;
153
            std::cout << "value of relay " << i << ": " << (int)bus.ReadRegister(0x01, address) << std::endl;
154
            bus.WriteRegister(0x01, address, 0xff);
155
            std::cout << "value of relay " << i << " (on): " << (int)bus.ReadRegister(0x01, address) << std::endl;
156
            sleep(1);
157
            bus.WriteRegister(0x01, address, 0x00);
158
            std::cout << "value of relay " << i << " (off): " << (int)bus.ReadRegister(0x01, address) << std::endl;
159
        }
160
    } catch (const TIVTMDeviceException& e) {
161
        std::cerr << "uniel bus error: " << e.what() << std::endl;
162
    }
163
    return 0;
164
}
165
#endif
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