• 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

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)
288✔
18
{
19
    factory.RegisterProtocol(
288✔
20
        new TUint32SlaveIdProtocol("ivtm", TRegisterTypes({{0, "default", "value", Float, true}})),
864✔
21
        new TBasicDeviceFactory<TIVTMDevice>("#/definitions/simple_device", "#/definitions/common_channel"));
576✔
22
}
288✔
23

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

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

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

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

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

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

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

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

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

57
static const int MAX_LEN = 100;
58

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

135
    uint8_t* p = response; //&response[(address % 2) * 4];
6✔
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])};
12✔
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