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

traintastic / traintastic / 23667775307

27 Mar 2026 09:13PM UTC coverage: 28.009% (-0.002%) from 28.011%
23667775307

push

github

reinder
[boost] fix timer cancel() error_code overload is removed in 1.87, see #220

0 of 5 new or added lines in 1 file covered. (0.0%)

220 existing lines in 10 files now uncovered.

8182 of 29212 relevant lines covered (28.01%)

194.75 hits per line

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

0.0
/server/src/hardware/protocol/traintasticdiy/kernel.hpp
1
/**
2
 * server/src/hardware/protocol/traintasticdiy/kernel.hpp
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
#ifndef TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_TRAINTASTICDIY_KERNEL_HPP
24
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_TRAINTASTICDIY_KERNEL_HPP
25

26
#include "../kernelbase.hpp"
27
#include <unordered_map>
28
#include <set>
29
#include <boost/asio/post.hpp>
30
#include <boost/asio/steady_timer.hpp>
31
#include <boost/signals2/signal.hpp>
32
#include <traintastic/enum/tristate.hpp>
33
#include "config.hpp"
34
#include "featureflags.hpp"
35
#include "inputstate.hpp"
36
#include "outputstate.hpp"
37
#include "iohandler/iohandler.hpp"
38

39
class World;
40
enum class SimulateInputAction;
41
class InputController;
42
class OutputController;
43
class Decoder;
44
enum class DecoderChangeFlags;
45

46
namespace TraintasticDIY {
47

48
struct Message;
49

50
class Kernel : public ::KernelBase
51
{
52
  private:
53
    struct DecoderSubscription
54
    {
55
      boost::signals2::connection connection;
56
      size_t count; //!< number of throttles subscribed to the decoder
57
    };
58

59
    World& m_world;
60
    std::unique_ptr<IOHandler> m_ioHandler;
61
    const bool m_simulation;
62
    std::string m_logId;
63
    boost::asio::steady_timer m_startupDelayTimer;
64
    boost::asio::steady_timer m_heartbeatTimeout;
65

66
    bool m_featureFlagsSet;
67
    FeatureFlags1 m_featureFlags1;
68
    FeatureFlags2 m_featureFlags2;
69
    FeatureFlags3 m_featureFlags3;
70
    FeatureFlags4 m_featureFlags4;
71

72
    InputController* m_inputController;
73
    std::unordered_map<uint16_t, InputState> m_inputValues;
74

75
    OutputController* m_outputController;
76
    std::unordered_map<uint16_t, OutputState>  m_outputValues;
77

78
    std::unordered_map<uint16_t, std::set<std::pair<uint16_t, bool>>> m_throttleSubscriptions;
79
    std::map<std::pair<uint16_t, bool>, DecoderSubscription> m_decoderSubscriptions;
80

81
    Config m_config;
82

83
    Kernel(std::string logId, World& world, const Config& config, bool simulation);
84

85
    void setIOHandler(std::unique_ptr<IOHandler> handler);
86

87
    template<class T>
UNCOV
88
    void postSend(const T& message)
×
89
    {
90
      boost::asio::post(m_ioContext, 
×
UNCOV
91
        [this, message]()
×
92
        {
UNCOV
93
          send(message);
×
94
        });
UNCOV
95
    }
×
96

97
    void send(const Message& message);
98

99
    inline bool hasFeatureInput() const { return contains(m_featureFlags1, FeatureFlags1::Input); }
×
100
    inline bool hasFeatureOutput() const { return contains(m_featureFlags1, FeatureFlags1::Output); }
×
UNCOV
101
    inline bool hasFeatureThrottle() const { return contains(m_featureFlags1, FeatureFlags1::Throttle); }
×
102

103
    void startupDelayExpired(const boost::system::error_code& ec);
104

105
    void restartHeartbeatTimeout();
106
    void heartbeatTimeoutExpired(const boost::system::error_code& ec);
107

108
    std::shared_ptr<Decoder> getDecoder(uint16_t address, bool longAddress) const;
109

110
    void throttleSubscribe(uint16_t throttleId, std::pair<uint16_t, bool> key);
111
    void throttleUnsubscribe(uint16_t throttleId, std::pair<uint16_t, bool> key);
112
    void throttleDecoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber);
113

114
  public:
115
    static constexpr uint16_t ioAddressMin = 1;
116
    static constexpr uint16_t ioAddressMax = std::numeric_limits<uint16_t>::max();
117

118
    Kernel(const Kernel&) = delete;
119
    Kernel& operator =(const Kernel&) = delete;
120

121
#ifndef NDEBUG
UNCOV
122
    bool isKernelThread() const
×
123
    {
UNCOV
124
      return std::this_thread::get_id() == m_thread.get_id();
×
125
    }
126
#endif
127

128
    /**
129
     * \brief Create kernel and IO handler
130
     *
131
     * \param[in] config TraintasticDIY configuration
132
     * \param[in] args IO handler arguments
133
     * \return The kernel instance
134
     */
135
    template<class IOHandlerType, class... Args>
UNCOV
136
    static std::unique_ptr<Kernel> create(std::string logId_, World& world, const Config& config, Args... args)
×
137
    {
138
      static_assert(std::is_base_of_v<IOHandler, IOHandlerType>);
139
      std::unique_ptr<Kernel> kernel{new Kernel(std::move(logId_), world, config, isSimulation<IOHandlerType>())};
×
140
      kernel->setIOHandler(std::make_unique<IOHandlerType>(*kernel, std::forward<Args>(args)...));
×
141
      return kernel;
×
UNCOV
142
    }
×
143

144
    /**
145
     * \brief Access the IO handler
146
     *
147
     * \return The IO handler
148
     * \note The IO handler runs in the kernel's IO context, not all functions can be called safely!
149
     */
150
    template<class T>
151
    T& ioHandler()
152
    {
153
      assert(dynamic_cast<T*>(m_ioHandler.get()));
154
      return static_cast<T&>(*m_ioHandler);
155
    }
156

157
    /**
158
     * \brief Set TraintasticDIY configuration
159
     *
160
     * \param[in] config The TraintasticDIY configuration
161
     */
162
    void setConfig(const Config& config);
163

164
    /**
165
     * \brief Set the input controller
166
     *
167
     * \param[in] inputController The input controller
168
     * \note This function may not be called when the kernel is running.
169
     */
UNCOV
170
    inline void setInputController(InputController* inputController)
×
171
    {
172
      assert(!m_started);
×
173
      m_inputController = inputController;
×
UNCOV
174
    }
×
175

176
    /**
177
     * \brief Set the output controller
178
     *
179
     * \param[in] outputController The output controller
180
     * \note This function may not be called when the kernel is running.
181
     */
UNCOV
182
    inline void setOutputController(OutputController* outputController)
×
183
    {
184
      assert(!m_started);
×
185
      m_outputController = outputController;
×
UNCOV
186
    }
×
187

188
    /**
189
     * \brief Start the kernel and IO handler
190
     */
191
    void start();
192

193
    /**
194
     * \brief Stop the kernel and IO handler
195
     */
196
    void stop();
197

198
    /**
199
     * \brief Notify kernel the IO handler is started.
200
     * \note This function must run in the kernel's IO context
201
     */
202
    void started() final;
203

204
    /**
205
     * \brief ...
206
     *
207
     * This must be called by the IO handler whenever a TraintasticDIY message is received.
208
     *
209
     * \param[in] message The received TraintasticDIY message
210
     * \note This function must run in the kernel's IO context
211
     */
212
    void receive(const Message& message);
213

214
    /**
215
     *
216
     * \param[in] address Output address, #ioAddressMin..#ioAddressMax
217
     * \param[in] value Output value: \c true is on, \c false is off.
218
     * \return \c true if send successful, \c false otherwise.
219
     */
220
    bool setOutput(uint16_t address, bool value);
221

222
    /**
223
     * \brief Simulate input change
224
     * \param[in] address Input address, #ioAddressMin..#ioAddressMax
225
     * \param[in] action Simulation action to perform
226
     */
227
    void simulateInputChange(uint16_t address, SimulateInputAction action);
228
};
229

230
}
231

232
#endif
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