DCC++: added accessory output support
Dieser Commit ist enthalten in:
Ursprung
86f9956622
Commit
22099e80f9
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* This file is part of the traintastic source code.
|
* 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
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -40,9 +40,11 @@ DCCPlusPlusInterface::DCCPlusPlusInterface(const std::weak_ptr<World>& world, st
|
|||||||
, flowControl{this, "flow_control", SerialFlowControl::None, PropertyFlags::ReadWrite | PropertyFlags::Store}
|
, flowControl{this, "flow_control", SerialFlowControl::None, PropertyFlags::ReadWrite | PropertyFlags::Store}
|
||||||
, dccplusplus{this, "dccplusplus", nullptr, PropertyFlags::ReadOnly | PropertyFlags::Store | PropertyFlags::SubObject}
|
, dccplusplus{this, "dccplusplus", nullptr, PropertyFlags::ReadOnly | PropertyFlags::Store | PropertyFlags::SubObject}
|
||||||
, decoders{this, "decoders", nullptr, PropertyFlags::ReadOnly | PropertyFlags::NoStore | PropertyFlags::SubObject}
|
, decoders{this, "decoders", nullptr, PropertyFlags::ReadOnly | PropertyFlags::NoStore | PropertyFlags::SubObject}
|
||||||
|
, outputs{this, "outputs", nullptr, PropertyFlags::ReadOnly | PropertyFlags::NoStore | PropertyFlags::SubObject}
|
||||||
{
|
{
|
||||||
dccplusplus.setValueInternal(std::make_shared<DCCPlusPlus::Settings>(*this, dccplusplus.name()));
|
dccplusplus.setValueInternal(std::make_shared<DCCPlusPlus::Settings>(*this, dccplusplus.name()));
|
||||||
decoders.setValueInternal(std::make_shared<DecoderList>(*this, decoders.name()));
|
decoders.setValueInternal(std::make_shared<DecoderList>(*this, decoders.name()));
|
||||||
|
outputs.setValueInternal(std::make_shared<OutputList>(*this, outputs.name()));
|
||||||
|
|
||||||
Attributes::addDisplayName(device, DisplayName::Serial::device);
|
Attributes::addDisplayName(device, DisplayName::Serial::device);
|
||||||
Attributes::addEnabled(device, !online);
|
Attributes::addEnabled(device, !online);
|
||||||
@ -64,6 +66,9 @@ DCCPlusPlusInterface::DCCPlusPlusInterface(const std::weak_ptr<World>& world, st
|
|||||||
|
|
||||||
Attributes::addDisplayName(decoders, DisplayName::Hardware::decoders);
|
Attributes::addDisplayName(decoders, DisplayName::Hardware::decoders);
|
||||||
m_interfaceItems.insertBefore(decoders, notes);
|
m_interfaceItems.insertBefore(decoders, notes);
|
||||||
|
|
||||||
|
Attributes::addDisplayName(outputs, DisplayName::Hardware::outputs);
|
||||||
|
m_interfaceItems.insertBefore(outputs, notes);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DCCPlusPlusInterface::addDecoder(Decoder& decoder)
|
bool DCCPlusPlusInterface::addDecoder(Decoder& decoder)
|
||||||
@ -88,6 +93,30 @@ void DCCPlusPlusInterface::decoderChanged(const Decoder& decoder, DecoderChangeF
|
|||||||
m_kernel->decoderChanged(decoder, changes, functionNumber);
|
m_kernel->decoderChanged(decoder, changes, functionNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DCCPlusPlusInterface::addOutput(Output& output)
|
||||||
|
{
|
||||||
|
const bool success = OutputController::addOutput(output);
|
||||||
|
if(success)
|
||||||
|
outputs->addObject(output.shared_ptr<Output>());
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DCCPlusPlusInterface::removeOutput(Output& output)
|
||||||
|
{
|
||||||
|
const bool success = OutputController::removeOutput(output);
|
||||||
|
if(success)
|
||||||
|
outputs->removeObject(output.shared_ptr<Output>());
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DCCPlusPlusInterface::setOutputValue(uint32_t address, bool value)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
m_kernel &&
|
||||||
|
inRange(address, outputAddressMinMax()) &&
|
||||||
|
m_kernel->setOutput(static_cast<uint16_t>(address), value);
|
||||||
|
}
|
||||||
|
|
||||||
bool DCCPlusPlusInterface::setOnline(bool& value)
|
bool DCCPlusPlusInterface::setOnline(bool& value)
|
||||||
{
|
{
|
||||||
if(!m_kernel && value)
|
if(!m_kernel && value)
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* This file is part of the traintastic source code.
|
* 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
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -28,6 +28,8 @@
|
|||||||
#include "../protocol/dccplusplus/settings.hpp"
|
#include "../protocol/dccplusplus/settings.hpp"
|
||||||
#include "../decoder/decodercontroller.hpp"
|
#include "../decoder/decodercontroller.hpp"
|
||||||
#include "../decoder/decoderlist.hpp"
|
#include "../decoder/decoderlist.hpp"
|
||||||
|
#include "../output/outputcontroller.hpp"
|
||||||
|
#include "../output/list/outputlist.hpp"
|
||||||
#include "../../core/objectproperty.hpp"
|
#include "../../core/objectproperty.hpp"
|
||||||
#include "../../enum/serialflowcontrol.hpp"
|
#include "../../enum/serialflowcontrol.hpp"
|
||||||
|
|
||||||
@ -37,6 +39,7 @@
|
|||||||
class DCCPlusPlusInterface final
|
class DCCPlusPlusInterface final
|
||||||
: public Interface
|
: public Interface
|
||||||
, public DecoderController
|
, public DecoderController
|
||||||
|
, public OutputController
|
||||||
{
|
{
|
||||||
CLASS_ID("interface.dccplusplus")
|
CLASS_ID("interface.dccplusplus")
|
||||||
CREATE(DCCPlusPlusInterface)
|
CREATE(DCCPlusPlusInterface)
|
||||||
@ -65,6 +68,7 @@ class DCCPlusPlusInterface final
|
|||||||
Property<SerialFlowControl> flowControl;
|
Property<SerialFlowControl> flowControl;
|
||||||
ObjectProperty<DCCPlusPlus::Settings> dccplusplus;
|
ObjectProperty<DCCPlusPlus::Settings> dccplusplus;
|
||||||
ObjectProperty<DecoderList> decoders;
|
ObjectProperty<DecoderList> decoders;
|
||||||
|
ObjectProperty<OutputList> outputs;
|
||||||
|
|
||||||
DCCPlusPlusInterface(const std::weak_ptr<World>& world, std::string_view _id);
|
DCCPlusPlusInterface(const std::weak_ptr<World>& world, std::string_view _id);
|
||||||
|
|
||||||
@ -72,6 +76,12 @@ class DCCPlusPlusInterface final
|
|||||||
[[nodiscard]] bool addDecoder(Decoder& decoder) final;
|
[[nodiscard]] bool addDecoder(Decoder& decoder) final;
|
||||||
[[nodiscard]] bool removeDecoder(Decoder& decoder) final;
|
[[nodiscard]] bool removeDecoder(Decoder& decoder) final;
|
||||||
void decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber) final;
|
void decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber) final;
|
||||||
|
|
||||||
|
// OutputController:
|
||||||
|
std::pair<uint32_t, uint32_t> outputAddressMinMax() const final { return {DCCPlusPlus::Kernel::outputAddressMin, DCCPlusPlus::Kernel::outputAddressMax}; }
|
||||||
|
[[nodiscard]] bool addOutput(Output& output) final;
|
||||||
|
[[nodiscard]] bool removeOutput(Output& output) final;
|
||||||
|
[[nodiscard]] bool setOutputValue(uint32_t address, bool value) final;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* This file is part of the traintastic source code.
|
* 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
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -62,6 +62,7 @@ void Kernel::start()
|
|||||||
// reset all state values
|
// reset all state values
|
||||||
m_powerOn = TriState::Undefined;
|
m_powerOn = TriState::Undefined;
|
||||||
m_emergencyStop = TriState::Undefined;
|
m_emergencyStop = TriState::Undefined;
|
||||||
|
m_outputValues.fill(TriState::Undefined);
|
||||||
|
|
||||||
m_thread = std::thread(
|
m_thread = std::thread(
|
||||||
[this]()
|
[this]()
|
||||||
@ -214,6 +215,24 @@ void Kernel::decoderChanged(const Decoder& decoder, DecoderChangeFlags changes,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Kernel::setOutput(uint16_t address, bool value)
|
||||||
|
{
|
||||||
|
assert(inRange(address, outputAddressMin, outputAddressMax));
|
||||||
|
|
||||||
|
m_ioContext.post(
|
||||||
|
[this, address, value]()
|
||||||
|
{
|
||||||
|
const auto index = address - outputAddressMin;
|
||||||
|
if(m_outputValues[index] != toTriState(value))
|
||||||
|
{
|
||||||
|
m_outputValues[index] = toTriState(value);
|
||||||
|
send(Ex::setAccessory(address - outputAddressMin, value));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Kernel::setIOHandler(std::unique_ptr<IOHandler> handler)
|
void Kernel::setIOHandler(std::unique_ptr<IOHandler> handler)
|
||||||
{
|
{
|
||||||
assert(handler);
|
assert(handler);
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* This file is part of the traintastic source code.
|
* 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
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -34,6 +34,7 @@
|
|||||||
class Decoder;
|
class Decoder;
|
||||||
enum class DecoderChangeFlags;
|
enum class DecoderChangeFlags;
|
||||||
class DecoderController;
|
class DecoderController;
|
||||||
|
class OutputController;
|
||||||
|
|
||||||
namespace DCCPlusPlus {
|
namespace DCCPlusPlus {
|
||||||
|
|
||||||
@ -41,6 +42,10 @@ struct Message;
|
|||||||
|
|
||||||
class Kernel
|
class Kernel
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
static constexpr uint16_t outputAddressMin = 1;
|
||||||
|
static constexpr uint16_t outputAddressMax = 2044;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
boost::asio::io_context m_ioContext;
|
boost::asio::io_context m_ioContext;
|
||||||
std::unique_ptr<IOHandler> m_ioHandler;
|
std::unique_ptr<IOHandler> m_ioHandler;
|
||||||
@ -55,6 +60,9 @@ class Kernel
|
|||||||
|
|
||||||
DecoderController* m_decoderController;
|
DecoderController* m_decoderController;
|
||||||
|
|
||||||
|
OutputController* m_outputController;
|
||||||
|
std::array<TriState, outputAddressMax - outputAddressMin + 1> m_outputValues;
|
||||||
|
|
||||||
Config m_config;
|
Config m_config;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
bool m_started;
|
bool m_started;
|
||||||
@ -176,6 +184,18 @@ class Kernel
|
|||||||
m_decoderController = decoderController;
|
m_decoderController = decoderController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the output controller
|
||||||
|
*
|
||||||
|
* @param[in] outputController The output controller
|
||||||
|
* @note This function may not be called when the kernel is running.
|
||||||
|
*/
|
||||||
|
inline void setOutputController(OutputController* outputController)
|
||||||
|
{
|
||||||
|
assert(!m_started);
|
||||||
|
m_outputController = outputController;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start the kernel and IO handler
|
* @brief Start the kernel and IO handler
|
||||||
*/
|
*/
|
||||||
@ -225,6 +245,14 @@ class Kernel
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber);
|
void decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param[in] address Output address, #outputAddressMin..#outputAddressMax
|
||||||
|
* @param[in] value Output value: \c true is on, \c false is off.
|
||||||
|
* @return \c true if send successful, \c false otherwise.
|
||||||
|
*/
|
||||||
|
bool setOutput(uint16_t address, bool value);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* This file is part of the traintastic source code.
|
* 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
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -181,7 +181,7 @@ namespace Ex {
|
|||||||
|
|
||||||
inline std::string setAccessory(uint16_t linearAddress, bool activate)
|
inline std::string setAccessory(uint16_t linearAddress, bool activate)
|
||||||
{
|
{
|
||||||
assert(linearAddress <= 2047);
|
assert(linearAddress >= 1 && linearAddress <= 2044);
|
||||||
|
|
||||||
return std::string("<a ")
|
return std::string("<a ")
|
||||||
.append(std::to_string(linearAddress))
|
.append(std::to_string(linearAddress))
|
||||||
|
|||||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren