DCC++: added accessory output support

Dieser Commit ist enthalten in:
Reinder Feenstra 2022-01-09 12:57:28 +01:00
Ursprung 86f9956622
Commit 22099e80f9
5 geänderte Dateien mit 92 neuen und 6 gelöschten Zeilen

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
@ -40,9 +40,11 @@ DCCPlusPlusInterface::DCCPlusPlusInterface(const std::weak_ptr<World>& world, st
, flowControl{this, "flow_control", SerialFlowControl::None, PropertyFlags::ReadWrite | PropertyFlags::Store}
, dccplusplus{this, "dccplusplus", nullptr, PropertyFlags::ReadOnly | PropertyFlags::Store | 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()));
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::addEnabled(device, !online);
@ -64,6 +66,9 @@ DCCPlusPlusInterface::DCCPlusPlusInterface(const std::weak_ptr<World>& world, st
Attributes::addDisplayName(decoders, DisplayName::Hardware::decoders);
m_interfaceItems.insertBefore(decoders, notes);
Attributes::addDisplayName(outputs, DisplayName::Hardware::outputs);
m_interfaceItems.insertBefore(outputs, notes);
}
bool DCCPlusPlusInterface::addDecoder(Decoder& decoder)
@ -88,6 +93,30 @@ void DCCPlusPlusInterface::decoderChanged(const Decoder& decoder, DecoderChangeF
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)
{
if(!m_kernel && value)

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
@ -28,6 +28,8 @@
#include "../protocol/dccplusplus/settings.hpp"
#include "../decoder/decodercontroller.hpp"
#include "../decoder/decoderlist.hpp"
#include "../output/outputcontroller.hpp"
#include "../output/list/outputlist.hpp"
#include "../../core/objectproperty.hpp"
#include "../../enum/serialflowcontrol.hpp"
@ -37,6 +39,7 @@
class DCCPlusPlusInterface final
: public Interface
, public DecoderController
, public OutputController
{
CLASS_ID("interface.dccplusplus")
CREATE(DCCPlusPlusInterface)
@ -65,6 +68,7 @@ class DCCPlusPlusInterface final
Property<SerialFlowControl> flowControl;
ObjectProperty<DCCPlusPlus::Settings> dccplusplus;
ObjectProperty<DecoderList> decoders;
ObjectProperty<OutputList> outputs;
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 removeDecoder(Decoder& decoder) 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

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
@ -62,6 +62,7 @@ void Kernel::start()
// reset all state values
m_powerOn = TriState::Undefined;
m_emergencyStop = TriState::Undefined;
m_outputValues.fill(TriState::Undefined);
m_thread = std::thread(
[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)
{
assert(handler);

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
@ -34,6 +34,7 @@
class Decoder;
enum class DecoderChangeFlags;
class DecoderController;
class OutputController;
namespace DCCPlusPlus {
@ -41,6 +42,10 @@ struct Message;
class Kernel
{
public:
static constexpr uint16_t outputAddressMin = 1;
static constexpr uint16_t outputAddressMax = 2044;
private:
boost::asio::io_context m_ioContext;
std::unique_ptr<IOHandler> m_ioHandler;
@ -55,6 +60,9 @@ class Kernel
DecoderController* m_decoderController;
OutputController* m_outputController;
std::array<TriState, outputAddressMax - outputAddressMin + 1> m_outputValues;
Config m_config;
#ifndef NDEBUG
bool m_started;
@ -176,6 +184,18 @@ class Kernel
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
*/
@ -225,6 +245,14 @@ class Kernel
*
*/
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);
};
}

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
@ -181,7 +181,7 @@ namespace Ex {
inline std::string setAccessory(uint16_t linearAddress, bool activate)
{
assert(linearAddress <= 2047);
assert(linearAddress >= 1 && linearAddress <= 2044);
return std::string("<a ")
.append(std::to_string(linearAddress))