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

traintastic / traintastic / 26121453997

19 May 2026 07:52PM UTC coverage: 25.063% (-0.6%) from 25.624%
26121453997

Pull #221

github

web-flow
Merge 598936246 into 15e38bcf7
Pull Request #221: Xpressnet new messages

49 of 1129 new or added lines in 16 files covered. (4.34%)

782 existing lines in 21 files now uncovered.

8483 of 33847 relevant lines covered (25.06%)

172.88 hits per line

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

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

23
#include "simulationiohandler.hpp"
24
#include "../kernel.hpp"
25
#include "../messages.hpp"
26

27
namespace XpressNet {
28

29
static std::shared_ptr<std::byte[]> copy(const Message& message)
×
30
{
31
  auto* bytes = new std::byte[message.size()];
×
32
  std::memcpy(bytes, &message, message.size());
×
33
  return std::shared_ptr<std::byte[]>{bytes};
×
34
}
35

36
SimulationIOHandler::SimulationIOHandler(Kernel& kernel)
×
37
  : IOHandler(kernel)
×
38
{
39
}
×
40

41
void SimulationIOHandler::start()
×
42
{
43
  m_kernel.started();
×
44
}
×
45

46
bool SimulationIOHandler::send(const Message& message)
×
47
{
48
  switch(message.header)
×
49
  {
NEW
50
    case STOP_REQUEST:
×
51
    {
52
      if(message == ResumeOperationsRequest())
×
53
        reply(NormalOperationResumed(), 3);
×
54
      else if(message == StopOperationsRequest())
×
55
        reply(TrackPowerOff(), 3);
×
56
      break;
×
57
    }
NEW
58
    case SET_STOP_LOCO:
×
59
    {
60
      if(message == StopAllLocomotivesRequest())
×
61
        reply(EmergencyStop(), 3);
×
62
      break;
×
63
    }
NEW
64
    case GET_LOCO_INFO:
×
65
    {
NEW
66
      const auto& locomotiveInstruction = static_cast<const LocomotiveInstruction&>(message);
×
NEW
67
      switch(locomotiveInstruction.identification)
×
68
      {
NEW
69
        case 0:
×
70
        {
NEW
71
          Locomotive& loco = m_locomotives[locomotiveInstruction.address()];
×
NEW
72
          reply(loco.info);
×
NEW
73
          break;
×
74
        }
NEW
75
        case idQueryFuncGroup4and5:
×
76
        {
NEW
77
          Locomotive& loco = m_locomotives[locomotiveInstruction.address()];
×
NEW
78
          reply(loco.func13);
×
NEW
79
          break;
×
80
        }
NEW
81
        case idQueryFuncGroup6above:
×
82
        {
NEW
83
          Locomotive& loco = m_locomotives[locomotiveInstruction.address()];
×
NEW
84
          reply(loco.func29);
×
NEW
85
          break;
×
86
        }
87
      }
NEW
88
      break;
×
89
    }
NEW
90
    case SET_LOCO:
×
91
    {
NEW
92
      const auto& locomotiveInstruction = static_cast<const LocomotiveInstruction&>(message);
×
NEW
93
      switch(locomotiveInstruction.identification)
×
94
      {
NEW
95
        case idSetSpeed14:
×
96
        case idSetSpeed27:
97
        case idSetSpeed28:
98
        case idSetSpeed128:
99
        {
NEW
100
          speedAndDirectionInstruction(static_cast<const SpeedAndDirectionInstruction&>(locomotiveInstruction));
×
NEW
101
          break;
×
102
        }
NEW
103
        case idSetFuncGroup4_Roco:
×
104
        {
NEW
105
          const auto& funcInstruction = static_cast<const RocoMultiMAUS::FunctionInstructionF13F20&>(message);
×
106

NEW
107
          Locomotive& loco = m_locomotives[funcInstruction.address()];
×
NEW
108
          loco.info.setBusy(false);
×
NEW
109
          loco.info.updateChecksum();
×
110

NEW
111
          for(int i = 13; i <= 20; i++)
×
NEW
112
            loco.func13.setFunction(i, funcInstruction.getFunction(i));
×
NEW
113
          loco.func13.updateChecksum();
×
NEW
114
          break;
×
115
        }
NEW
116
        default:
×
117
        {
NEW
118
          const auto& funcInstruction = static_cast<const FunctionInstructionGroup&>(message);
×
NEW
119
          const uint8_t group = funcInstruction.getGroup();
×
NEW
120
          if(group == 0)
×
NEW
121
            break;
×
122

NEW
123
          Locomotive& loco = m_locomotives[funcInstruction.address()];
×
NEW
124
          loco.info.setBusy(false);
×
125

NEW
126
          if(group <= 3)
×
127
          {
NEW
128
            uint8_t i = FunctionInstructionGroup::getMinFunctionIndex(group);
×
NEW
129
            const uint8_t maxFuncIndex = FunctionInstructionGroup::getMaxFunctionIndex(group);
×
NEW
130
            for(; i <= maxFuncIndex; i++)
×
NEW
131
              loco.info.setFunction(i, funcInstruction.getFunction(i));
×
132
          }
NEW
133
          else if(group == 4 || group == 5)
×
134
          {
NEW
135
            uint8_t i = FunctionInstructionGroup::getMinFunctionIndex(group);
×
NEW
136
            const uint8_t maxFuncIndex = FunctionInstructionGroup::getMaxFunctionIndex(group);
×
NEW
137
            for(; i <= maxFuncIndex; i++)
×
NEW
138
              loco.func13.setFunction(i, funcInstruction.getFunction(i));
×
NEW
139
            loco.func13.updateChecksum();
×
NEW
140
          }
×
141
          else
142
          {
NEW
143
            uint8_t i = FunctionInstructionGroup::getMinFunctionIndex(group);
×
NEW
144
            const uint8_t maxFuncIndex = FunctionInstructionGroup::getMaxFunctionIndex(group);
×
NEW
145
            for(; i <= maxFuncIndex; i++)
×
NEW
146
              loco.func29.setFunction(i, funcInstruction.getFunction(i));
×
NEW
147
            loco.func29.updateChecksum();
×
148
          }
149

NEW
150
          loco.info.updateChecksum();
×
NEW
151
          break;
×
152
        }
153
      }
NEW
154
      break;
×
155
    }
156
  }
157

158
  return true;
×
159
}
160

161
void SimulationIOHandler::reply(const Message& message)
×
162
{
163
  // post the reply, so it has some delay
164
  //! \todo better delay simulation? at least xpressnet message transfer time?
165
  boost::asio::post(m_kernel.ioContext(), 
×
166
    [this, data=copy(message)]()
×
167
    {
168
      m_kernel.receive(*reinterpret_cast<const Message*>(data.get()));
×
169
    });
×
170
}
×
171

172
void SimulationIOHandler::reply(const Message& message, const size_t count)
×
173
{
174
  for(size_t i = 0; i < count; i++)
×
175
    reply(message);
×
176
}
×
177

NEW
178
void SimulationIOHandler::speedAndDirectionInstruction(const SpeedAndDirectionInstruction& message)
×
179
{
NEW
180
  Locomotive& loco = m_locomotives[message.address()];
×
NEW
181
  loco.info.setBusy(false);
×
NEW
182
  loco.info.setDirection(message.direction());
×
NEW
183
  loco.info.setSpeedSteps(message.speedSteps());
×
NEW
184
  if(message.isEmergencyStop())
×
NEW
185
    loco.info.setEmergencyStop();
×
186
  else
NEW
187
    loco.info.setSpeedStep(message.speedStep());
×
188

NEW
189
  if(message.speedSteps() == 14)
×
190
  {
NEW
191
    const auto& setSpeed14 = static_cast<const SpeedAndDirectionInstruction14&>(message);
×
NEW
192
    loco.info.setFunction(0, setSpeed14.getFl());
×
193
  }
NEW
194
  loco.info.updateChecksum();
×
NEW
195
}
×
196

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