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

wirenboard / wb-mqtt-adc / 56

31 Jul 2026 10:38AM UTC coverage: 56.281% (-1.1%) from 57.332%
56

push

github

web-flow
Use exported vars instead of MAKEFLAGS for coverage options (#51)

282 of 466 branches covered (60.52%)

457 of 812 relevant lines covered (56.28%)

4.55 hits per line

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

0.0
/src/adc_driver.cpp
1
#include "adc_driver.h"
2

3
#include <vector>
4

5
#include "sysfs_adc.h"
6

7
/*
8
"/devices/" DriverId "/meta/name"                                       = Config.DeviceName
9
"/devices/" DriverId "/controls/" Config.Channels[i].Id                 = measured voltage
10
"/devices/" DriverId "/controls/" Config.Channels[i].Id "/meta/order"   = i from Config.Channels[i]
11
"/devices/" DriverId "/controls/" Config.Channels[i].Id "/meta/type"    = string "voltage"
12
*/
13

14
//! default scale for file "in_voltageNUMBER_scale"
15
#define MXS_LRADC_DEFAULT_SCALE_FACTOR 0.451660156
16

17
namespace
18
{
19
    const char* DriverId = "wb-adc";
20

21
    struct TChannelDesc
22
    {
23
        std::string MqttId;
24
        bool Error;
25
        TChannelReader::Timestamp PublishedTimestamp;
26
        TChannelReader Reader;
27

28
        //! Flag indicating what we should create MQTT control for channel
29
        bool ShouldCreateControl = true;
30
    };
31

32
    WBMQTT::TControlArgs MakeControlArgs(const std::string& id, size_t order, const std::string& error)
×
33
    {
34
        return WBMQTT::TControlArgs{}.SetId(id).SetType("voltage").SetError(error).SetOrder(order).SetReadonly(true);
×
35
    }
36

37
    void CreateControl(WBMQTT::PDriverTx& tx,
×
38
                       WBMQTT::TLocalDevice& device,
39
                       size_t order,
40
                       const std::string& id,
41
                       const std::string& value,
42
                       const std::string& error)
43
    {
44
        device.CreateControl(tx, MakeControlArgs(id, order, error).SetRawValue(value)).Wait();
×
45
    }
×
46

47
    void AdcWorker(bool* active,
×
48
                   WBMQTT::PLocalDevice device,
49
                   WBMQTT::PDeviceDriver mqttDriver,
50
                   std::shared_ptr<std::vector<TChannelDesc>> channels,
51
                   size_t controlOrder,
52
                   WBMQTT::TLogger& infoLogger,
53
                   WBMQTT::TLogger& errorLogger)
54
    {
55
        bool shouldRemoveUnusedControls = true;
×
56
        infoLogger.Log() << "ADC worker thread is started";
×
57
        while (*active) {
×
58
            auto now = std::chrono::steady_clock::now();
×
59

60
            for (auto& channel: *channels) {
×
61
                try {
62
                    channel.Reader.Poll(now, channel.MqttId + " ");
×
63
                    channel.Error = false;
×
64
                } catch (const std::exception& er) {
×
65
                    channel.Error = true;
×
66
                    errorLogger.Log() << er.what();
×
67
                }
×
68
            }
69

70
            {
71
                auto tx = mqttDriver->BeginTx();
×
72
                for (auto& channel: *channels) {
×
73
                    if (channel.ShouldCreateControl) {
×
74
                        CreateControl(tx,
×
75
                                      *device,
×
76
                                      controlOrder,
77
                                      channel.MqttId,
×
78
                                      channel.Reader.GetValue(),
×
79
                                      channel.Error ? "r" : "");
×
80
                        infoLogger.Log() << "Channel " << channel.MqttId << " MQTT controls are created, poll interval "
×
81
                                         << channel.Reader.GetPollInterval().count() << " ms";
×
82
                        ++controlOrder;
×
83
                        channel.ShouldCreateControl = false;
×
84
                    } else if (channel.Reader.GetLastMeasureTimestamp() != channel.PublishedTimestamp) {
×
85
                        channel.PublishedTimestamp = channel.Reader.GetLastMeasureTimestamp();
×
86

87
                        // update channel value only if it is fresh
88
                        WBMQTT::PControl control = device->GetControl(channel.MqttId);
×
89
                        if (channel.Error) {
×
90
                            auto future = control->SetError(tx, "r");
×
91
                            future.Wait();
×
92
                        } else {
×
93
                            auto future = control->SetRawValue(tx, channel.Reader.GetValue());
×
94
                            future.Wait();
×
95
                        }
×
96
                    }
×
97
                }
98

99
                if (shouldRemoveUnusedControls) {
×
100
                    device->RemoveUnusedControls(tx);
×
101
                    shouldRemoveUnusedControls = false;
×
102
                }
103
            }
×
104

105
            // sleep until next scheduled poll
106
            auto nextPoll = TChannelReader::Timestamp::max();
×
107
            for (auto& channel: *channels) {
×
108
                nextPoll = std::min(nextPoll, channel.Reader.GetNextPollTimestamp());
×
109
            }
110

111
            // use new steady_clock value here for precision
112
            std::this_thread::sleep_until(nextPoll);
×
113
        }
114
        infoLogger.Log() << "ADC worker thread is stopped";
×
115
    }
×
116
} // namespace
117

118
TADCDriver::TADCDriver(const WBMQTT::PDeviceDriver& mqttDriver,
×
119
                       const TConfig& config,
120
                       WBMQTT::TLogger& errorLogger,
121
                       WBMQTT::TLogger& debugLogger,
122
                       WBMQTT::TLogger& infoLogger)
×
123
    : MqttDriver(mqttDriver),
×
124
      ErrorLogger(errorLogger),
×
125
      DebugLogger(debugLogger),
×
126
      InfoLogger(infoLogger)
×
127
{
128
    InfoLogger.Log() << "Creating driver MQTT controls";
×
129
    auto tx = MqttDriver->BeginTx();
×
130
    Device = tx->CreateDevice(WBMQTT::TLocalDeviceArgs{}
×
131
                                  .SetId(DriverId)
×
132
                                  .SetTitle(config.DeviceName)
×
133
                                  .SetIsVirtual(true)
×
134
                                  .SetDoLoadPrevious(false))
135
                 .GetValue();
×
136

137
    size_t controlOrder = 0;
×
138
    std::shared_ptr<std::vector<TChannelDesc>> readers(new std::vector<TChannelDesc>());
×
139
    for (const auto& channel: config.Channels) {
×
140
        std::string sysfsIIODir = FindSysfsIIODir(channel.MatchIIO);
×
141
        if (sysfsIIODir.empty()) {
×
142
            ErrorLogger.Log() << "Can't fild matching sysfs IIO: " + channel.MatchIIO;
×
143
            Device->CreateControl(tx, MakeControlArgs(channel.Id, controlOrder, "r")).Wait();
×
144
            ++controlOrder;
×
145
        } else {
146
            readers->push_back(TChannelDesc{
×
147
                channel.Id,
×
148
                false,
149
                TChannelReader::Timestamp::min(),
150
                {MXS_LRADC_DEFAULT_SCALE_FACTOR, channel.ReaderCfg, DebugLogger, InfoLogger, sysfsIIODir}});
×
151
        }
152
    }
×
153

154
    Active = true;
×
155
    Worker = WBMQTT::MakeThread(
×
156
        "ADC worker",
157
        {[=] { AdcWorker(&Active, Device, MqttDriver, readers, controlOrder, InfoLogger, ErrorLogger); }});
×
158
}
×
159

160
void TADCDriver::Stop()
×
161
{
162
    {
163
        std::lock_guard<std::mutex> lg(ActiveMutex);
×
164
        if (!Active) {
×
165
            ErrorLogger.Log() << "Attempt to stop already stopped TADCDriver";
×
166
            return;
×
167
        }
168
        Active = false;
×
169
    }
×
170

171
    InfoLogger.Log() << "Stopping...";
×
172

173
    if (Worker->joinable()) {
×
174
        Worker->join();
×
175
    }
176
    Worker.reset();
×
177

178
    try {
179
        MqttDriver->BeginTx()->RemoveDeviceById(DriverId).Sync();
×
180
    } catch (const std::exception& e) {
×
181
        ErrorLogger.Log() << "Exception during TADCDriver::Stop: " << e.what();
×
182
    } catch (...) {
×
183
        ErrorLogger.Log() << "Unknown exception during TADCDriver::Stop";
×
184
    }
×
185
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc