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

traintastic / traintastic / 24288605255

11 Apr 2026 06:17PM UTC coverage: 25.599% (-2.4%) from 27.99%
24288605255

push

github

web-flow
Merge pull request #222 from traintastic/cbus

Added CBUS/VLCB hardware support

169 of 3369 new or added lines in 99 files covered. (5.02%)

5 existing lines in 4 files now uncovered.

8300 of 32423 relevant lines covered (25.6%)

178.31 hits per line

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

40.66
/server/src/hardware/booster/drivers/cbusboosterdriver.cpp
1
/**
2
 * This file is part of Traintastic,
3
 * see <https://github.com/traintastic/traintastic>.
4
 *
5
 * Copyright (C) 2026 Reinder Feenstra
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
 */
21

22
#include "cbusboosterdriver.hpp"
23
#include "../../interface/cbusinterface.hpp"
24
#include "../../protocol/cbus/cbusconst.hpp"
25
#include "../../protocol/cbus/messages/cbusaccessorymessages.hpp"
26
#include "../../../core/attributes.hpp"
27
#include "../../../core/objectproperty.tpp"
28
#include "../../../utils/displayname.hpp"
29
#include "../../../world/getworld.hpp"
30
#include "../../../world/world.hpp"
31

32
namespace {
33

34
constexpr float currentScale = 0.001f; //!< 1mA steps
35
constexpr float voltageScale = 0.1f; //!< 100mV steps
36

37
}
38

39
CBUSBoosterDriver::CBUSBoosterDriver(Booster& booster)
4✔
40
  : BoosterDriver(booster)
41
  , interface{this, "interface", nullptr, PropertyFlags::ReadWrite | PropertyFlags::Store | PropertyFlags::NoScript,
8✔
42
      [this](const std::shared_ptr<CBUSInterface>& value)
4✔
43
      {
NEW
44
        interfaceOnlineChanged(value->online);
×
NEW
45
      },
×
46
      [this](const std::shared_ptr<CBUSInterface>& value)
8✔
47
      {
NEW
48
        if(interface)
×
49
        {
NEW
50
          m_interfacePropertyChanged.disconnect();
×
NEW
51
          disableEvents();
×
52
        }
NEW
53
        if(value)
×
54
        {
NEW
55
          m_interfacePropertyChanged = value->propertyChanged.connect(std::bind_front(&CBUSBoosterDriver::interfacePropertyChanged, this));
×
56
        }
NEW
57
        return true;
×
58
      }}
59
  , node{this, "node", CBUS::NodeNumber::CANCMD, PropertyFlags::ReadWrite | PropertyFlags::Store | PropertyFlags::NoScript,
8✔
60
      [this](uint16_t /*value*/)
4✔
61
      {
NEW
62
        invalidateAll();
×
NEW
63
      }}
×
64
  , currentEvent{this, "current_event", 1, PropertyFlags::ReadWrite | PropertyFlags::Store | PropertyFlags::NoScript,
8✔
65
      [this](uint16_t /*value*/)
4✔
66
      {
NEW
67
        reportCurrent(); // invalidate
×
NEW
68
      }}
×
69
  , voltageEvent{this, "voltage_event", 2, PropertyFlags::ReadWrite | PropertyFlags::Store | PropertyFlags::NoScript,
8✔
70
      [this](uint16_t /*value*/)
4✔
71
      {
NEW
72
        reportVoltage(); // invalidate
×
73
      }}
8✔
74
{
75
  Attributes::addDisplayName(interface, DisplayName::Hardware::interface);
4✔
76
  Attributes::addEnabled(interface, false);
4✔
77
  Attributes::addObjectList(interface, getWorld(*this).cbusInterfaces);
4✔
78
  m_interfaceItems.add(interface);
4✔
79

80
  Attributes::addEnabled(node, false);
4✔
81
  m_interfaceItems.add(node);
4✔
82

83
  Attributes::addEnabled(currentEvent, false);
4✔
84
  m_interfaceItems.add(currentEvent);
4✔
85

86
  Attributes::addEnabled(voltageEvent, false);
4✔
87
  m_interfaceItems.add(voltageEvent);
4✔
88

89
  updateEnabled();
4✔
90
}
4✔
91

92
void CBUSBoosterDriver::destroying()
2✔
93
{
94
  disableEvents();
2✔
95
  m_interfacePropertyChanged.disconnect();
2✔
96
  BoosterDriver::destroying();
2✔
97
}
2✔
98

NEW
99
void CBUSBoosterDriver::loaded()
×
100
{
NEW
101
  BoosterDriver::loaded();
×
102

NEW
103
  if(interface)
×
104
  {
NEW
105
    m_interfacePropertyChanged = interface->propertyChanged.connect(std::bind_front(&CBUSBoosterDriver::interfacePropertyChanged, this));
×
106
  }
NEW
107
}
×
108

NEW
109
void CBUSBoosterDriver::worldEvent(WorldState state, WorldEvent event)
×
110
{
NEW
111
  BoosterDriver::worldEvent(state, event);
×
NEW
112
  switch(event)
×
113
  {
NEW
114
    case WorldEvent::EditDisabled:
×
115
    case WorldEvent::EditEnabled:
NEW
116
      updateEnabled();
×
NEW
117
      break;
×
118

NEW
119
    default:
×
NEW
120
      break;
×
121
  }
NEW
122
}
×
123

NEW
124
void CBUSBoosterDriver::interfaceOnlineChanged(bool online)
×
125
{
NEW
126
  if(online)
×
127
  {
NEW
128
    enableEvents();
×
129
  }
130
  else
131
  {
NEW
132
    disableEvents();
×
NEW
133
    invalidateAll();
×
134
  }
NEW
135
  updateEnabled();
×
NEW
136
}
×
137

NEW
138
void CBUSBoosterDriver::interfacePropertyChanged(BaseProperty& property)
×
139
{
NEW
140
  if(property.name() == "online")
×
141
  {
NEW
142
    interfaceOnlineChanged(static_cast<Property<bool>&>(property).value());
×
143
  }
NEW
144
}
×
145

146
void CBUSBoosterDriver::updateEnabled()
4✔
147
{
148
  const bool editable = contains(getWorld(*this).state, WorldState::Edit);
4✔
149
  const bool online = interface && interface->online;
4✔
150

151
  Attributes::setEnabled(interface, editable && !online);
4✔
152
  Attributes::setEnabled({node, currentEvent, voltageEvent}, editable);
4✔
153
}
4✔
154

NEW
155
void CBUSBoosterDriver::enableEvents()
×
156
{
NEW
157
  assert(interface);
×
NEW
158
  assert(interface->online);
×
NEW
159
  m_onReceiveHandle = interface->registerOnReceive(CBUS::OpCode::ACON2, std::bind_front(&CBUSBoosterDriver::receive, this));
×
NEW
160
}
×
161

162
void CBUSBoosterDriver::disableEvents()
2✔
163
{
164
  if(interface)
2✔
165
  {
166
    // unregister callback for received messages:
NEW
167
    interface->unregisterOnReceive(m_onReceiveHandle);
×
NEW
168
    m_onReceiveHandle = 0;
×
169
  }
170
}
2✔
171

NEW
172
void CBUSBoosterDriver::receive(uint8_t /*canId*/, const CBUS::Message& message)
×
173
{
174
  using namespace CBUS;
175

NEW
176
  assert(message.opCode == OpCode::ACON2); // enforced by filter
×
NEW
177
  const auto& acon2 = static_cast<const Accessory2On&>(message);
×
178

NEW
179
  if(acon2.nodeNumber() != node)
×
180
  {
NEW
181
    return;
×
182
  }
183

NEW
184
  if(acon2.eventNumber() == currentEvent)
×
185
  {
NEW
186
    reportCurrent(acon2.data() * currentScale);
×
187
  }
NEW
188
  else if(acon2.eventNumber() == voltageEvent)
×
189
  {
NEW
190
    reportVoltage(acon2.data() * voltageScale);
×
191
  }
192
}
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