dcc++: implemented input simulation
Dieser Commit ist enthalten in:
Ursprung
24fbe33bf5
Commit
56307232dd
@ -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;
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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
|
||||
|
||||
@ -43,6 +43,12 @@ class SimulationIOHandler final : public IOHandler
|
||||
bool send(std::string_view message) final;
|
||||
};
|
||||
|
||||
template<>
|
||||
constexpr bool isSimulation<SimulationIOHandler>()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren