dcc++: implemented input simulation

Dieser Commit ist enthalten in:
Reinder Feenstra 2022-04-30 18:51:54 +02:00
Ursprung 24fbe33bf5
Commit 56307232dd
7 geänderte Dateien mit 66 neuen und 9 gelöschten Zeilen

Datei anzeigen

@ -114,6 +114,12 @@ bool DCCPlusPlusInterface::removeInput(Input& input)
return success;
}
void DCCPlusPlusInterface::inputSimulateChange(uint32_t channel, uint32_t address)
{
if(m_kernel && inRange(address, inputAddressMinMax(channel)))
m_kernel->simulateInputChange(address);
}
std::pair<uint32_t, uint32_t> DCCPlusPlusInterface::outputAddressMinMax(uint32_t channel) const
{
using namespace DCCPlusPlus;

Datei anzeigen

@ -84,6 +84,7 @@ class DCCPlusPlusInterface final
std::pair<uint32_t, uint32_t> inputAddressMinMax(uint32_t /*channel*/) const final { return {DCCPlusPlus::Kernel::idMin, DCCPlusPlus::Kernel::idMax}; }
[[nodiscard]] bool addInput(Input& input) final;
[[nodiscard]] bool removeInput(Input& input) final;
void inputSimulateChange(uint32_t channel, uint32_t address) final;
// OutputController:
const std::vector<uint32_t>* outputChannels() const final { return &DCCPlusPlus::Kernel::outputChannels; }

Datei anzeigen

@ -3,7 +3,7 @@
*
* This file is part of the traintastic source code.
*
* Copyright (C) 2021 Reinder Feenstra
* Copyright (C) 2021-2022 Reinder Feenstra
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -52,6 +52,12 @@ class IOHandler
virtual bool send(std::string_view message) = 0;
};
template<class T>
constexpr bool isSimulation()
{
return false;
}
}
#endif

Datei anzeigen

@ -43,6 +43,12 @@ class SimulationIOHandler final : public IOHandler
bool send(std::string_view message) final;
};
template<>
constexpr bool isSimulation<SimulationIOHandler>()
{
return true;
}
}
#endif

Datei anzeigen

@ -36,8 +36,9 @@
namespace DCCPlusPlus {
Kernel::Kernel(const Config& config)
Kernel::Kernel(const Config& config, bool simulation)
: m_ioContext{1}
, m_simulation{simulation}
, m_startupDelayTimer{m_ioContext}
, m_decoderController{nullptr}
, m_inputController{nullptr}
@ -69,6 +70,7 @@ void Kernel::start()
// reset all state values
m_powerOn = TriState::Undefined;
m_emergencyStop = TriState::Undefined;
m_inputValues.clear();
m_thread = std::thread(
[this]()
@ -186,11 +188,18 @@ void Kernel::receive(std::string_view message)
uint32_t id;
if(auto r = fromChars(message.substr(3), id); r.ec == std::errc() && *r.ptr == '>' && id <= idMax)
{
EventLoop::call(
[this, id, value=toTriState(message[1] == 'Q')]()
{
m_inputController->updateInputValue(InputController::defaultInputChannel, id, value);
});
const bool value = message[1] == 'Q';
auto it = m_inputValues.find(id);
if(it == m_inputValues.end() || it->second != value)
{
m_inputValues[id] = value;
EventLoop::call(
[this, id, value]()
{
m_inputController->updateInputValue(InputController::defaultInputChannel, id, toTriState(value));
});
}
}
}
break;
@ -329,6 +338,17 @@ bool Kernel::setOutput(uint32_t channel, uint16_t address, bool value)
return false;
}
void Kernel::simulateInputChange(uint16_t address)
{
if(m_simulation)
m_ioContext.post(
[this, address]()
{
auto it = m_inputValues.find(address);
receive(Ex::sensorTransition(address, it != m_inputValues.end() ? !it->second : true));
});
}
void Kernel::setIOHandler(std::unique_ptr<IOHandler> handler)
{
assert(handler);

Datei anzeigen

@ -71,6 +71,7 @@ class Kernel
private:
boost::asio::io_context m_ioContext;
std::unique_ptr<IOHandler> m_ioHandler;
const bool m_simulation;
std::thread m_thread;
std::string m_logId;
boost::asio::steady_timer m_startupDelayTimer;
@ -83,6 +84,7 @@ class Kernel
DecoderController* m_decoderController;
InputController* m_inputController;
std::unordered_map<uint16_t, bool> m_inputValues;
OutputController* m_outputController;
@ -91,7 +93,7 @@ class Kernel
bool m_started;
#endif
Kernel(const Config& config);
Kernel(const Config& config, bool simulation);
void setIOHandler(std::unique_ptr<IOHandler> handler);
@ -130,7 +132,7 @@ class Kernel
static std::unique_ptr<Kernel> create(const Config& config, Args... args)
{
static_assert(std::is_base_of_v<IOHandler, IOHandlerType>);
std::unique_ptr<Kernel> kernel{new Kernel(config)};
std::unique_ptr<Kernel> kernel{new Kernel(config, isSimulation<IOHandlerType>())};
kernel->setIOHandler(std::make_unique<IOHandlerType>(*kernel, std::forward<Args>(args)...));
return kernel;
}
@ -289,6 +291,12 @@ class Kernel
* @return \c true if send successful, \c false otherwise.
*/
bool setOutput(uint32_t channel, uint16_t address, bool value);
/**
* \brief Simulate input change
* \param[in] address Input address, #idMin..#idMax
*/
void simulateInputChange(uint16_t address);
};
}

Datei anzeigen

@ -283,6 +283,16 @@ namespace Ex {
.append(">\n");
}
inline std::string sensorTransition(uint16_t id, bool active)
{
assert(id <= 32767);
if(active)
return std::string("<Q ").append(std::to_string(id)).append(">\n");
else
return std::string("<q ").append(std::to_string(id)).append(">\n");
}
inline std::string_view setSpeedSteps(uint8_t value)
{
switch(value)