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

traintastic / traintastic / 21078534351

16 Jan 2026 07:36PM UTC coverage: 27.192% (-0.03%) from 27.22%
21078534351

push

github

reinder
[manual] expanded supported hardware appendix with list of supported boosters

7918 of 29119 relevant lines covered (27.19%)

192.82 hits per line

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

49.45
/server/src/hardware/decoder/decodercontroller.cpp
1
/**
2
 * This file is part of Traintastic,
3
 * see <https://github.com/traintastic/traintastic>.
4
 *
5
 * Copyright (C) 2021-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 "decodercontroller.hpp"
23
#include "decoder.hpp"
24
#include "decoderchangeflags.hpp"
25
#include "list/decoderlist.hpp"
26
#include "list/decoderlisttablemodel.hpp"
27
#include "../protocol/dcc/dcc.hpp"
28
#include "../../core/attributes.hpp"
29
#include "../../core/objectproperty.tpp"
30
#include "../../core/controllerlist.hpp"
31
#include "../../utils/displayname.hpp"
32
#include "../../utils/almostzero.hpp"
33
#include "../../world/world.hpp"
34

35
DecoderController::DecoderController(IdObject& interface, DecoderListColumn columns)
55✔
36
  : decoders{&interface, "decoders", nullptr, PropertyFlags::ReadOnly | PropertyFlags::NoStore | PropertyFlags::SubObject}
55✔
37
{
38
  decoders.setValueInternal(std::make_shared<DecoderList>(interface, decoders.name(), columns));
55✔
39

40
  Attributes::addDisplayName(decoders, DisplayName::Hardware::decoders);
55✔
41
}
55✔
42

43
std::pair<uint16_t, uint16_t> DecoderController::decoderAddressMinMax(DecoderProtocol protocol) const
25✔
44
{
45
  switch(protocol)
25✔
46
  {
47
    case DecoderProtocol::DCCShort:
25✔
48
      return {DCC::addressMin, DCC::addressShortMax};
25✔
49

50
    case DecoderProtocol::DCCLong:
×
51
      return {DCC::addressMin, DCC::addressLongMax};
×
52

53
    case DecoderProtocol::Motorola:
×
54
      return {1, 255};
×
55

56
    case DecoderProtocol::Selectrix:
×
57
      return {1, 112};
×
58

59
    case DecoderProtocol::MFX: // no address -> MFX UID is used
×
60
    case DecoderProtocol::Analog:
61
    case DecoderProtocol::None:
62
      return noAddressMinMax;
×
63
  }
64
  assert(false);
×
65
  return noAddressMinMax;
66
}
67

68
std::span<const uint8_t> DecoderController::decoderSpeedSteps(DecoderProtocol protocol) const
20✔
69
{
70
  static constexpr std::array<uint8_t, 3> dccSpeedSteps{{14, 28, 128}};
71
  static constexpr std::array<uint8_t, 3> motorolaSpeedSteps{{14, 27, 28}};
72
  static constexpr std::array<uint8_t, 1> selectrixSpeedSteps{{32}};
73
  static constexpr std::array<uint8_t, 1> mfxSpeedSteps{{126}};
74

75
  switch(protocol)
20✔
76
  {
77
    case DecoderProtocol::DCCShort:
20✔
78
    case DecoderProtocol::DCCLong:
79
      return dccSpeedSteps;
20✔
80

81
    case DecoderProtocol::Motorola:
×
82
      return motorolaSpeedSteps;
×
83

84
    case DecoderProtocol::Selectrix:
×
85
      return selectrixSpeedSteps;
×
86

87
    case DecoderProtocol::MFX:
×
88
      return mfxSpeedSteps;
×
89

90
    case DecoderProtocol::None:
×
91
      return {};
×
92

93
    case DecoderProtocol::Analog:
×
94
      break; // must be handle by interface
×
95
  }
96
  assert(false);
×
97
  return {};
98
}
99

100
bool DecoderController::addDecoder(Decoder& decoder)
30✔
101
{
102
  if(findDecoder(decoder) != m_decoders.end())
30✔
103
    return false;
×
104

105
  m_decoders.emplace_back(decoder.shared_ptr<Decoder>());
30✔
106
  decoders->addObject(decoder.shared_ptr<Decoder>());
30✔
107
  return true;
30✔
108
}
109

110
bool DecoderController::removeDecoder(Decoder& decoder)
30✔
111
{
112
  auto it = findDecoder(decoder);
30✔
113
  if(it != m_decoders.end())
30✔
114
  {
115
    m_decoders.erase(it);
30✔
116
    decoders->removeObject(decoder.shared_ptr<Decoder>());
30✔
117
    return true;
30✔
118
  }
119
  return false;
×
120
}
121

122
const std::shared_ptr<Decoder>& DecoderController::getDecoder(DecoderProtocol protocol, uint16_t address)
×
123
{
124
  auto it = findDecoder(protocol, address);
×
125
  if(it != m_decoders.end())
×
126
    return *it;
×
127

128
  return Decoder::null;
×
129
}
130

131
void DecoderController::addToWorld()
55✔
132
{
133
  auto& object = interface();
55✔
134
  object.world().decoderControllers->add(std::dynamic_pointer_cast<DecoderController>(object.shared_from_this()));
55✔
135
}
55✔
136

137
void DecoderController::destroying()
55✔
138
{
139
  auto& object = interface();
55✔
140
  while(!decoders->empty())
67✔
141
  {
142
    const auto& decoder = decoders->front();
12✔
143
    assert(decoder->interface.value() == std::dynamic_pointer_cast<DecoderController>(object.shared_from_this()));
12✔
144
    decoder->interface = nullptr; // removes object form the list
12✔
145
  }
146

147
  object.world().decoderControllers->remove(std::dynamic_pointer_cast<DecoderController>(object.shared_from_this()));
55✔
148
}
55✔
149

150
DecoderController::DecoderVector::iterator DecoderController::findDecoder(const Decoder& decoder)
60✔
151
{
152
  return std::find_if(m_decoders.begin(), m_decoders.end(),
60✔
153
    [ptr=&decoder](const auto& it)
30✔
154
    {
155
      return ptr == it.get();
30✔
156
    });
60✔
157
}
158

159
DecoderController::DecoderVector::iterator DecoderController::findDecoder(DecoderProtocol protocol, uint16_t address)
×
160
{
161
  if(protocol == DecoderProtocol::MFX)
×
162
    return m_decoders.end();
×
163

164
  return std::find_if(m_decoders.begin(), m_decoders.end(),
×
165
    [protocol, address](const auto& it)
×
166
    {
167
      return it->protocol == protocol && it->address == address;
×
168
    });
×
169
}
170

171
DecoderController::DecoderVector::iterator DecoderController::findDecoderMFX(uint32_t mfxUID)
×
172
{
173
  if(mfxUID == 0)
×
174
    return m_decoders.end();
×
175

176
  return std::find_if(m_decoders.begin(), m_decoders.end(),
×
177
    [mfxUID](const auto& it)
×
178
    {
179
      return it->protocol == DecoderProtocol::MFX && it->mfxUID == mfxUID;
×
180
    });
×
181
}
182

183
void DecoderController::restoreDecoderSpeed()
×
184
{
185
  for(const auto& decoder : m_decoders)
×
186
    if(!decoder->emergencyStop && !almostZero(decoder->throttle.value()))
×
187
      decoderChanged(*decoder, DecoderChangeFlags::Throttle, 0);
×
188
}
×
189

190
IdObject& DecoderController::interface()
110✔
191
{
192
  auto* object = dynamic_cast<IdObject*>(this);
110✔
193
  assert(object);
110✔
194
  return *object;
110✔
195
}
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