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

traintastic / traintastic / 23088148108

14 Mar 2026 12:40PM UTC coverage: 26.661% (-0.2%) from 26.84%
23088148108

push

github

reinder
[cbus] added input support for short/long events

0 of 133 new or added lines in 4 files covered. (0.0%)

587 existing lines in 20 files now uncovered.

8246 of 30929 relevant lines covered (26.66%)

185.83 hits per line

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

49.62
/server/src/hardware/interface/traintasticdiyinterface.cpp
1
/**
2
 * This file is part of Traintastic,
3
 * see <https://github.com/traintastic/traintastic>.
4
 *
5
 * Copyright (C) 2022-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 "traintasticdiyinterface.hpp"
23
#include "../input/list/inputlist.hpp"
24
#include "../output/list/outputlist.hpp"
25
#include "../protocol/traintasticdiy/kernel.hpp"
26
#include "../protocol/traintasticdiy/settings.hpp"
27
#include "../protocol/traintasticdiy/messages.hpp"
28
#include "../protocol/traintasticdiy/iohandler/serialiohandler.hpp"
29
#include "../protocol/traintasticdiy/iohandler/simulationiohandler.hpp"
30
#include "../protocol/traintasticdiy/iohandler/tcpiohandler.hpp"
31
#include "../../core/attributes.hpp"
32
#include "../../core/eventloop.hpp"
33
#include "../../core/objectproperty.tpp"
34
#include "../../log/log.hpp"
35
#include "../../log/logmessageexception.hpp"
36
#include "../../utils/displayname.hpp"
37
#include "../../utils/inrange.hpp"
38
#include "../../utils/makearray.hpp"
39
#include "../../world/world.hpp"
40

41
constexpr auto inputListColumns = InputListColumn::Address;
42
constexpr auto outputListColumns = OutputListColumn::Address;
43

44
CREATE_IMPL(TraintasticDIYInterface)
3✔
45

46
TraintasticDIYInterface::TraintasticDIYInterface(World& world, std::string_view _id)
3✔
47
  : Interface(world, _id)
48
  , InputController(static_cast<IdObject&>(*this))
49
  , OutputController(static_cast<IdObject&>(*this))
50
  , type{this, "type", TraintasticDIYInterfaceType::Serial, PropertyFlags::ReadWrite | PropertyFlags::Store,
6✔
51
      [this](TraintasticDIYInterfaceType /*value*/)
3✔
52
      {
53
        updateVisible();
×
54
      }}
×
55
  , device{this, "device", "", PropertyFlags::ReadWrite | PropertyFlags::Store}
6✔
56
  , baudrate{this, "baudrate", 19200, PropertyFlags::ReadWrite | PropertyFlags::Store}
3✔
57
  , flowControl{this, "flow_control", SerialFlowControl::None, PropertyFlags::ReadWrite | PropertyFlags::Store}
3✔
58
  , hostname{this, "hostname", "192.168.1.203", PropertyFlags::ReadWrite | PropertyFlags::Store}
6✔
59
  , port{this, "port", 5550, PropertyFlags::ReadWrite | PropertyFlags::Store}
3✔
60
  , traintasticDIY{this, "traintastic_diy", nullptr, PropertyFlags::ReadOnly | PropertyFlags::Store | PropertyFlags::SubObject}
6✔
61
{
62
  name = "Traintastic DIY";
3✔
63
  traintasticDIY.setValueInternal(std::make_shared<TraintasticDIY::Settings>(*this, traintasticDIY.name()));
3✔
64

65
  Attributes::addDisplayName(type, DisplayName::Interface::type);
3✔
66
  Attributes::addEnabled(type, !online);
3✔
67
  Attributes::addValues(type, traintasticDIYInterfaceTypeValues);
3✔
68
  m_interfaceItems.insertBefore(type, notes);
3✔
69

70
  Attributes::addEnabled(device, !online);
3✔
71
  Attributes::addVisible(device, false);
3✔
72
  m_interfaceItems.insertBefore(device, notes);
3✔
73

74
  Attributes::addDisplayName(baudrate, DisplayName::Serial::baudrate);
3✔
75
  Attributes::addEnabled(baudrate, !online);
3✔
76
  Attributes::addVisible(baudrate, false);
3✔
77
  m_interfaceItems.insertBefore(baudrate, notes);
3✔
78

79
  Attributes::addDisplayName(flowControl, DisplayName::Serial::flowControl);
3✔
80
  Attributes::addEnabled(flowControl, !online);
3✔
81
  Attributes::addValues(flowControl, SerialFlowControlValues);
3✔
82
  Attributes::addVisible(flowControl, false);
3✔
83
  m_interfaceItems.insertBefore(flowControl, notes);
3✔
84

85
  Attributes::addDisplayName(hostname, DisplayName::IP::hostname);
3✔
86
  Attributes::addEnabled(hostname, !online);
3✔
87
  Attributes::addVisible(hostname, false);
3✔
88
  m_interfaceItems.insertBefore(hostname, notes);
3✔
89

90
  Attributes::addDisplayName(port, DisplayName::IP::port);
3✔
91
  Attributes::addEnabled(port, !online);
3✔
92
  Attributes::addVisible(port, false);
3✔
93
  m_interfaceItems.insertBefore(port, notes);
3✔
94

95
  m_interfaceItems.insertBefore(traintasticDIY, notes);
3✔
96

97
  m_interfaceItems.insertBefore(inputs, notes);
3✔
98

99
  m_interfaceItems.insertBefore(outputs, notes);
3✔
100

101
  updateVisible();
3✔
102
}
3✔
103

104
TraintasticDIYInterface::~TraintasticDIYInterface() = default;
3✔
105

106
std::span<const InputChannel> TraintasticDIYInterface::inputChannels() const
3✔
107
{
108
  static const auto values = makeArray(InputChannel::Input);
109
  return values;
3✔
110
}
111

112
std::pair<uint32_t, uint32_t> TraintasticDIYInterface::inputAddressMinMax(InputChannel /*channel*/) const
×
113
{
114
  return {TraintasticDIY::Kernel::ioAddressMin, TraintasticDIY::Kernel::ioAddressMax};
×
115
}
116

117
void TraintasticDIYInterface::inputSimulateChange(InputChannel channel, const InputLocation& location, SimulateInputAction action)
×
118
{
119
  assert(std::holds_alternative<InputAddress>(location));
×
120
  const auto address = std::get<InputAddress>(location).address;
×
121
  if(m_kernel && inRange(address, inputAddressMinMax(channel)))
×
UNCOV
122
    m_kernel->simulateInputChange(address, action);
×
UNCOV
123
}
×
124

125
std::span<const OutputChannel> TraintasticDIYInterface::outputChannels() const
6✔
126
{
127
  static const auto values = makeArray(OutputChannel::Output);
128
  return values;
6✔
129
}
130

131
std::pair<uint32_t, uint32_t> TraintasticDIYInterface::outputAddressMinMax(OutputChannel /*channel*/) const
×
132
{
UNCOV
133
  return {TraintasticDIY::Kernel::ioAddressMin, TraintasticDIY::Kernel::ioAddressMax};
×
134
}
135

136
bool TraintasticDIYInterface::setOutputValue(OutputChannel channel, const OutputLocation& location, OutputValue value)
×
137
{
138
  assert(isOutputChannel(channel));
×
UNCOV
139
  assert(std::get<TriState>(value) == TriState::True || std::get<TriState>(value) == TriState::False);
×
140
  const auto address = std::get<OutputAddress>(location).address;
×
141
  return
142
      m_kernel &&
×
UNCOV
143
      inRange(address, outputAddressMinMax(channel)) &&
×
UNCOV
144
      m_kernel->setOutput(static_cast<uint16_t>(address), std::get<TriState>(value) == TriState::True);
×
145
}
146

147
bool TraintasticDIYInterface::setOnline(bool& value, bool simulation)
×
148
{
UNCOV
149
  if(!m_kernel && value)
×
150
  {
151
    try
152
    {
153
      if(simulation)
×
154
      {
UNCOV
155
        m_kernel = TraintasticDIY::Kernel::create<TraintasticDIY::SimulationIOHandler>(id.value(), m_world, traintasticDIY->config());
×
156
      }
157
      else
158
      {
159
        switch(type)
×
160
        {
161
          case TraintasticDIYInterfaceType::Serial:
×
UNCOV
162
            m_kernel = TraintasticDIY::Kernel::create<TraintasticDIY::SerialIOHandler>(id.value(), m_world, traintasticDIY->config(), device.value(), baudrate.value(), flowControl.value());
×
163
            break;
×
164

165
          case TraintasticDIYInterfaceType::NetworkTCP:
×
UNCOV
166
            m_kernel = TraintasticDIY::Kernel::create<TraintasticDIY::TCPIOHandler>(id.value(), m_world, traintasticDIY->config(), hostname.value(), port.value());
×
UNCOV
167
            break;
×
168
        }
169
      }
170

171
      if(!m_kernel)
×
172
      {
UNCOV
173
        assert(false);
×
174
        return false;
175
      }
176

177
      setState(InterfaceState::Initializing);
×
178

UNCOV
179
      m_kernel->setOnStarted(
×
180
        [this]()
×
181
        {
182
          setState(InterfaceState::Online);
×
183
        });
×
UNCOV
184
      m_kernel->setOnError(
×
185
        [this]()
×
186
        {
187
          setState(InterfaceState::Error);
×
188
          online = false; // communication no longer possible
×
189
        });
×
190
      m_kernel->setInputController(this);
×
UNCOV
191
      m_kernel->setOutputController(this);
×
192
      m_kernel->start();
×
193

UNCOV
194
      m_traintasticDIYPropertyChanged = traintasticDIY->propertyChanged.connect(
×
195
        [this](BaseProperty& /*property*/)
×
196
        {
UNCOV
197
          m_kernel->setConfig(traintasticDIY->config());
×
198
        });
×
199

200
      Attributes::setEnabled({type, device, baudrate, flowControl, hostname, port}, false);
×
201
    }
202
    catch(const LogMessageException& e)
×
203
    {
204
      setState(InterfaceState::Offline);
×
205
      Log::log(*this, e.message(), e.args());
×
UNCOV
206
      return false;
×
207
    }
×
208
  }
209
  else if(m_kernel && !value)
×
210
  {
211
    Attributes::setEnabled({type, device, baudrate, flowControl, hostname, port}, true);
×
212

213
    m_traintasticDIYPropertyChanged.disconnect();
×
214

UNCOV
215
    m_kernel->stop();
×
216
    EventLoop::deleteLater(m_kernel.release());
×
217

218
    setState(InterfaceState::Offline);
×
219
  }
UNCOV
220
  return true;
×
221
}
222

223
void TraintasticDIYInterface::addToWorld()
3✔
224
{
225
  Interface::addToWorld();
3✔
226
  InputController::addToWorld(inputListColumns);
3✔
227
  OutputController::addToWorld(outputListColumns);
3✔
228
}
3✔
229

230
void TraintasticDIYInterface::loaded()
×
231
{
232
  Interface::loaded();
×
233

UNCOV
234
  updateVisible();
×
UNCOV
235
}
×
236

237
void TraintasticDIYInterface::destroying()
3✔
238
{
239
  OutputController::destroying();
3✔
240
  InputController::destroying();
3✔
241
  Interface::destroying();
3✔
242
}
3✔
243

244
void TraintasticDIYInterface::updateVisible()
3✔
245
{
246
  const bool isSerial = (type == TraintasticDIYInterfaceType::Serial);
3✔
247
  Attributes::setVisible(device, isSerial);
3✔
248
  Attributes::setVisible(baudrate, isSerial);
3✔
249
  Attributes::setVisible(flowControl, isSerial);
3✔
250

251
  const bool isNetwork = (type == TraintasticDIYInterfaceType::NetworkTCP);
3✔
252
  Attributes::setVisible(hostname, isNetwork);
3✔
253
  Attributes::setVisible(port, isNetwork);
3✔
254
}
3✔
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