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

wirenboard / wb-mqtt-gpio / 93

31 Jul 2026 10:43AM UTC coverage: 44.281% (+4.5%) from 39.772%
93

push

github

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

493 of 1086 branches covered (45.4%)

875 of 1976 relevant lines covered (44.28%)

3.96 hits per line

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

65.43
/src/gpio_counter.cpp
1
#include "gpio_counter.h"
2
#include "config.h"
3
#include "exceptions.h"
4
#include "log.h"
5
#include "utils.h"
6

7
#include <wblib/utils.h>
8

9
#include <cassert>
10
#include <cmath>
11

12
#define LOG(logger) ::logger.Log() << "[gpio counter] "
13

14
using namespace std;
15

16
const auto WATT_METER = "watt_meter";
17
const auto WATER_METER = "water_meter";
18
const auto ID_POSTFIX_TOTAL = "_total";
19
const auto ID_POSTFIX_CURRENT = "_current";
20
const auto CURRENT_TIME_INTERVAL = 1;
21
const auto NULL_TIME_INTERVAL = 100;
22
const auto COUNTER_UPDATE_INTERVAL_US = 200000;
23

24
TGpioCounter::TGpioCounter(const TGpioLineConfig& config)
17✔
25
    : Multiplier(config.Multiplier),
17✔
26
      InitialTotal(0),
17✔
27
      Total(0),
17✔
28
      Current(0),
17✔
29
      DecimalPlacesTotal(config.DecimalPlacesTotal),
17✔
30
      DecimalPlacesCurrent(config.DecimalPlacesCurrent),
17✔
31
      Counts(0),
17✔
32
      InterruptEdge(config.InterruptEdge),
17✔
33
      PreviousInterval(TTimeIntervalUs::zero())
17✔
34
{
35
    if (config.Type == WATT_METER) {
17✔
36
        TotalType = "power_consumption";
×
37
        CurrentType = "power";
×
38
        ConvertingMultiplier = 1000; // convert kW to W (1/h)
×
39
    } else if (config.Type == WATER_METER) {
17✔
40
        TotalType = "water_consumption";
17✔
41
        CurrentType = "water_flow";
17✔
42
        ConvertingMultiplier = 1.0; // 1/h
17✔
43
    } else {
44
        LOG(Error) << "Unknown gpio type";
×
45
        wb_throw(TGpioDriverException, "unknown GPIO type: '" + config.Type + "'");
×
46
    }
47

48
    LOG(Debug) << "New counter of type '" << config.Type << "' for " << config.Name
17✔
49
               << " edge: " << GpioEdgeToString(config.InterruptEdge);
17✔
50
}
17✔
51

52
TGpioCounter::~TGpioCounter()
17✔
53
{}
17✔
54

55
void TGpioCounter::HandleInterrupt(EGpioEdge edge, const TTimeIntervalUs& interval)
7✔
56
{
57
    assert(edge == InterruptEdge);
7✔
58

59
    PreviousInterval = interval;
7✔
60

61
    if (interval == TTimeIntervalUs::zero()) {
7✔
62
        Current.Set(-1);
×
63
    } else {
64
        UpdateCurrent(interval);
7✔
65
    }
66

67
    std::unique_lock<std::mutex> lk(AccessMutex);
7✔
68
    ++Counts;
7✔
69
    UpdateTotal();
7✔
70
}
7✔
71

72
void TGpioCounter::Update(const TTimeIntervalUs& interval)
2✔
73
{
74
    if (interval > NULL_TIME_INTERVAL * PreviousInterval) {
2✔
75
        Current.Set(0);
×
76
    } else if (interval > CURRENT_TIME_INTERVAL * PreviousInterval) {
2✔
77
        // more info at https://wirenboard.com/wiki/Frequency_registers
78
        auto divider = std::pow(2, (interval.count() / COUNTER_UPDATE_INTERVAL_US));
2✔
79
        Current.Set(Current.Get() / divider);
2✔
80
    }
81
}
2✔
82

83
float TGpioCounter::GetCurrent() const
7✔
84
{
85
    return Current.Get();
7✔
86
}
87

88
float TGpioCounter::GetTotal() const
13✔
89
{
90
    std::unique_lock<std::mutex> lk(AccessMutex);
13✔
91
    return Total.Get();
26✔
92
}
13✔
93

94
uint64_t TGpioCounter::GetCounts() const
×
95
{
96
    std::unique_lock<std::mutex> lk(AccessMutex);
×
97
    return Counts;
×
98
}
×
99

100
vector<TGpioCounter::TMetadataPair> TGpioCounter::GetIdsAndTypes(const string& baseId) const
×
101
{
102
    return {{baseId + ID_POSTFIX_TOTAL, TotalType}, {baseId + ID_POSTFIX_CURRENT, CurrentType}};
×
103
}
×
104

105
vector<TGpioCounter::TValuePair> TGpioCounter::GetIdsAndValues(const string& baseId) const
×
106
{
107
    vector<TGpioCounter::TValuePair> idsAndValues;
×
108

109
    idsAndValues.push_back({baseId + ID_POSTFIX_TOTAL, GetRoundedTotal()});
×
110
    idsAndValues.push_back({baseId + ID_POSTFIX_CURRENT, Utils::SetDecimalPlaces(Current.Get(), DecimalPlacesCurrent)});
×
111

112
    return idsAndValues;
×
113
}
×
114

115
std::string TGpioCounter::GetRoundedTotal() const
×
116
{
117
    return Utils::SetDecimalPlaces(GetTotal(), DecimalPlacesTotal);
×
118
}
119

120
void TGpioCounter::SetInterruptEdge(EGpioEdge edge)
4✔
121
{
122
    InterruptEdge = edge;
4✔
123
}
4✔
124

125
EGpioEdge TGpioCounter::GetInterruptEdge() const
76✔
126
{
127
    return InterruptEdge;
76✔
128
}
129

130
void TGpioCounter::SetInitialValues(float total)
×
131
{
132
    std::unique_lock<std::mutex> lk(AccessMutex);
×
133
    InitialTotal = total;
×
134
    Counts = 0;
×
135
    Total.Set(total);
×
136
}
×
137

138
void TGpioCounter::UpdateCurrent(const TTimeIntervalUs& interval)
7✔
139
{
140
    Current.Set(3600.0 * 1000000 * ConvertingMultiplier /
14✔
141
                (interval.count() * Multiplier)); // convert microseconds to seconds, hours to seconds
7✔
142
}
7✔
143

144
void TGpioCounter::UpdateTotal()
7✔
145
{
146
    Total.Set((float)Counts / Multiplier + InitialTotal);
7✔
147
}
7✔
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