• 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

0.0
/server/src/hardware/protocol/cbus/simulator/cbussimulator.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 "cbussimulator.hpp"
23
#include <algorithm>
24
#include "../cbuscanmessageutils.hpp"
25
#include "../messages/cbusaccessorymessages.hpp"
26
#include "../messages/cbusaccessoryshortmessages.hpp"
27

28
namespace {
29

30
static constexpr uint8_t simCanId = 84;
31
static constexpr uint16_t simNodeNumber = 0x84B7;
32

33
}
34

35
namespace CBUS
36
{
37

NEW
38
Simulator::Simulator()
×
39
{
NEW
40
}
×
41

NEW
42
bool Simulator::addModule(std::unique_ptr<Module::CANModule> module)
×
43
{
NEW
44
  if(!module || std::find_if(m_modules.begin(), m_modules.end(),
×
NEW
45
    [nodeNumber=module->nodeNumber, canId=module->canId](const auto& m)
×
46
    {
NEW
47
      return (m->nodeNumber == nodeNumber) || (m->canId == canId);
×
NEW
48
    }) != m_modules.end())
×
49
  {
NEW
50
    return false;
×
51
  }
NEW
52
  m_modules.emplace_back(std::move(module));
×
NEW
53
  return true;
×
54
}
55

NEW
56
void Simulator::receive(const CAN::Message& canMessage)
×
57
{
NEW
58
  for(const auto& module : m_modules)
×
59
  {
NEW
60
    module->receive(canMessage);
×
61
  }
NEW
62
}
×
63

NEW
64
void Simulator::shortEvent(uint16_t eventNumber, SimulateInputAction action)
×
65
{
66
  bool value;
NEW
67
  switch(action)
×
68
  {
NEW
69
    case SimulateInputAction::SetTrue:
×
NEW
70
      value = true;
×
NEW
71
      break;
×
72

NEW
73
    case SimulateInputAction::SetFalse:
×
NEW
74
      value = false;
×
NEW
75
      break;
×
76

NEW
77
    case SimulateInputAction::Toggle:
×
NEW
78
      if(auto it = m_shortEvents.find(eventNumber); it != m_shortEvents.end())
×
79
      {
NEW
80
        value = !it->second;
×
81
      }
82
      else
83
      {
NEW
84
        value = true;
×
85
      }
NEW
86
      break;
×
87

NEW
88
    default: [[unlikely]]
×
NEW
89
      return;
×
90
  }
91

NEW
92
  if(value)
×
93
  {
NEW
94
    send(toCANMessage(AccessoryShortOn(simNodeNumber, eventNumber), simCanId));
×
95
  }
96
  else
97
  {
NEW
98
    send(toCANMessage(AccessoryShortOff(simNodeNumber, eventNumber), simCanId));
×
99
  }
100
}
101

NEW
102
void Simulator::longEvent(uint16_t nodeNumber, uint16_t eventNumber, SimulateInputAction action)
×
103
{
NEW
104
  uint8_t canId = simCanId;
×
NEW
105
  if(auto it = std::find_if(m_modules.begin(), m_modules.end(),
×
NEW
106
    [nodeNumber](const auto& module)
×
107
    {
NEW
108
      return module->nodeNumber == nodeNumber;
×
NEW
109
    }); it != m_modules.end())
×
110
  {
NEW
111
    canId = (**it).canId;
×
112
  }
113

114
  bool value;
NEW
115
  switch(action)
×
116
  {
NEW
117
    case SimulateInputAction::SetTrue:
×
NEW
118
      value = true;
×
NEW
119
      break;
×
120

NEW
121
    case SimulateInputAction::SetFalse:
×
NEW
122
      value = false;
×
NEW
123
      break;
×
124

NEW
125
    case SimulateInputAction::Toggle:
×
NEW
126
      if(auto it = m_longEvents.find({nodeNumber, eventNumber}); it != m_longEvents.end())
×
127
      {
NEW
128
        value = !it->second;
×
129
      }
130
      else
131
      {
NEW
132
        value = true;
×
133
      }
NEW
134
      break;
×
135

NEW
136
    default: [[unlikely]]
×
NEW
137
      return;
×
138
  }
139

NEW
140
  if(value)
×
141
  {
NEW
142
    send(toCANMessage(AccessoryOn(nodeNumber, eventNumber), canId));
×
143
  }
144
  else
145
  {
NEW
146
    send(toCANMessage(AccessoryOff(nodeNumber, eventNumber), canId));
×
147
  }
148
}
149

NEW
150
void Simulator::send(const CAN::Message& canMessage)
×
151
{
NEW
152
  const auto& message = asMessage(canMessage);
×
NEW
153
  switch(message.opCode)
×
154
  {
155
    using enum OpCode;
156

NEW
157
    case ASON:
×
158
    {
NEW
159
      const auto& ason = static_cast<const AccessoryShortOn&>(message);
×
NEW
160
      m_shortEvents[ason.deviceNumber()] = true;
×
NEW
161
      break;
×
162
    }
NEW
163
    case ASOF:
×
164
    {
NEW
165
      const auto& asof = static_cast<const AccessoryShortOff&>(message);
×
NEW
166
      m_shortEvents[asof.deviceNumber()] = false;
×
NEW
167
      break;
×
168
    }
NEW
169
    case ACON:
×
170
    {
NEW
171
      const auto& acon = static_cast<const AccessoryOn&>(message);
×
NEW
172
      m_longEvents[{acon.nodeNumber(), acon.eventNumber()}] = true;
×
NEW
173
      break;
×
174
    }
NEW
175
    case ACOF:
×
176
    {
NEW
177
      const auto& acof = static_cast<const AccessoryOff&>(message);
×
NEW
178
      m_longEvents[{acof.nodeNumber(), acof.eventNumber()}] = false;
×
NEW
179
      break;
×
180
    }
NEW
181
    default:
×
NEW
182
      break;
×
183
  }
NEW
184
  onSend(canMessage);
×
NEW
185
}
×
186

187
}
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