#72 Decoder.protocol is now limited by DecoderController

Dieser Commit ist enthalten in:
Reinder Feenstra 2023-06-23 00:19:35 +02:00
Ursprung 5d01de9b32
Commit ab81ad73b3
14 geänderte Dateien mit 96 neuen und 6 gelöschten Zeilen

Datei anzeigen

@ -70,6 +70,11 @@ class SpanAttribute : public AbstractValuesAttribute
return to<std::string>(m_values[index]);
}
tcb::span<const T> values() const
{
return m_values;
}
void setValues(tcb::span<const T> values)
{
if(m_values.size() != values.size() || std::memcmp(m_values.data(), values.data(), m_values.size()) != 0)

Datei anzeigen

@ -3,7 +3,7 @@
*
* This file is part of the traintastic source code.
*
* Copyright (C) 2019-2022 Reinder Feenstra
* Copyright (C) 2019-2023 Reinder Feenstra
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -43,7 +43,20 @@ const std::shared_ptr<Decoder> Decoder::null;
Decoder::Decoder(World& world, std::string_view _id) :
IdObject(world, _id),
name{this, "name", "", PropertyFlags::ReadWrite | PropertyFlags::Store},
interface{this, "interface", nullptr, PropertyFlags::ReadWrite | PropertyFlags::Store, nullptr,
interface{this, "interface", nullptr, PropertyFlags::ReadWrite | PropertyFlags::Store,
[this](const std::shared_ptr<DecoderController>& value)
{
if(value)
{
assert(!value->decoderProtocols().empty());
Attributes::setValues(protocol, value->decoderProtocols());
checkProtocol();
Attributes::setVisible(protocol, true);
}
else
Attributes::setVisible(protocol, false);
updateEditable();
},
[this](const std::shared_ptr<DecoderController>& newValue)
{
if(!newValue || newValue->addDecoder(*this))
@ -60,6 +73,15 @@ Decoder::Decoder(World& world, std::string_view _id) :
if(value == DecoderProtocol::DCC && DCC::isLongAddress(address))
longAddress = true;
updateEditable();
},
[this](DecoderProtocol& value)
{
if(interface)
{
const auto protocols = interface->decoderProtocols();
return std::find(protocols.begin(), protocols.end(), value) != protocols.end();
}
return false;
}},
address{this, "address", 0, PropertyFlags::ReadWrite | PropertyFlags::Store,
[this](const uint16_t& value)
@ -121,7 +143,8 @@ Decoder::Decoder(World& world, std::string_view _id) :
m_interfaceItems.add(interface);
Attributes::addEnabled(protocol, false);
Attributes::addValues(protocol, decoderProtocolValues);
Attributes::addValues(protocol, tcb::span<const DecoderProtocol>{});
Attributes::addVisible(protocol, false);
m_interfaceItems.add(protocol);
Attributes::addDisplayName(address, DisplayName::Hardware::address);
@ -166,6 +189,10 @@ void Decoder::loaded()
IdObject::loaded();
if(interface)
{
Attributes::setValues(protocol, interface->decoderProtocols());
Attributes::setVisible(protocol, true);
checkProtocol(); //! \todo log something if protocol is changed??
if(!interface->addDecoder(*this))
{
if(auto object = std::dynamic_pointer_cast<Object>(interface.value()))
@ -329,6 +356,18 @@ void Decoder::worldEvent(WorldState state, WorldEvent event)
}
}
bool Decoder::checkProtocol()
{
const auto protocols = protocol.getSpanAttribute<DecoderProtocol>(AttributeName::Values).values();
assert(!protocols.empty());
if(auto it = std::find(protocols.begin(), protocols.end(), protocol); it == protocols.end())
{
protocol = protocols.front();
return true;
}
return false;
}
void Decoder::updateEditable()
{
updateEditable(contains(m_world.state.value(), WorldState::Edit));
@ -339,7 +378,7 @@ void Decoder::updateEditable(bool editable)
const bool stopped = editable && almostZero(throttle.value());
Attributes::setEnabled(name, editable);
Attributes::setEnabled(interface, stopped);
Attributes::setEnabled(protocol, stopped);
Attributes::setEnabled(protocol, stopped && protocol.getSpanAttribute<DecoderProtocol>(AttributeName::Values).length() > 1);
Attributes::setEnabled(address, stopped);
Attributes::setEnabled(longAddress, stopped && protocol == DecoderProtocol::DCC && !DCC::isLongAddress(address));
Attributes::setEnabled(speedSteps, stopped);

Datei anzeigen

@ -3,7 +3,7 @@
*
* This file is part of the traintastic source code.
*
* Copyright (C) 2019-2022 Reinder Feenstra
* Copyright (C) 2019-2023 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 Decoder : public IdObject
void loaded() final;
void destroying() override;
void worldEvent(WorldState state, WorldEvent event) final;
//! \brief Check and correct protocol
//! If the current value isn't in the list of valid protocols the protocol is set the the first valid one.
//! \return \c true if adjusted, \c false if unchanged
bool checkProtocol();
void updateEditable();
void updateEditable(bool editable);
void changed(DecoderChangeFlags changes, uint32_t functionNumber = 0);

Datei anzeigen

@ -3,7 +3,7 @@
*
* This file is part of the traintastic source code.
*
* Copyright (C) 2021-2022 Reinder Feenstra
* Copyright (C) 2021-2023 Reinder Feenstra
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -26,6 +26,7 @@
#include <cstdint>
#include <vector>
#include <memory>
#include <tcb/span.hpp>
#include "../../core/objectproperty.hpp"
#ifdef interface
@ -64,6 +65,10 @@ class DecoderController
public:
ObjectProperty<DecoderList> decoders;
//! \brief Get supported protocols
//! \return Supported protocols, may not be empty and must be constant for the instance!
virtual tcb::span<const DecoderProtocol> decoderProtocols() const = 0;
[[nodiscard]] bool addDecoder(Decoder& decoder);
[[nodiscard]] bool removeDecoder(Decoder& decoder);

Datei anzeigen

@ -77,6 +77,12 @@ DCCPlusPlusInterface::DCCPlusPlusInterface(World& world, std::string_view _id)
m_interfaceItems.insertBefore(outputs, notes);
}
tcb::span<const DecoderProtocol> DCCPlusPlusInterface::decoderProtocols() const
{
static constexpr std::array<DecoderProtocol, 1> protocols{DecoderProtocol::DCC};
return tcb::span<const DecoderProtocol>{protocols.data(), protocols.size()};
}
void DCCPlusPlusInterface::decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber)
{
if(m_kernel)

Datei anzeigen

@ -74,6 +74,7 @@ class DCCPlusPlusInterface final
DCCPlusPlusInterface(World& world, std::string_view _id);
// DecoderController:
tcb::span<const DecoderProtocol> decoderProtocols() const final;
void decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber) final;
// InputController:

Datei anzeigen

@ -69,6 +69,12 @@ ECoSInterface::ECoSInterface(World& world, std::string_view _id)
m_interfaceItems.insertBefore(outputs, notes);
}
tcb::span<const DecoderProtocol> ECoSInterface::decoderProtocols() const
{
static constexpr std::array<DecoderProtocol, 3> protocols{DecoderProtocol::DCC, DecoderProtocol::Motorola, DecoderProtocol::Selectrix};
return tcb::span<const DecoderProtocol>{protocols.data(), protocols.size()};
}
void ECoSInterface::decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber)
{
if(m_kernel)

Datei anzeigen

@ -73,6 +73,7 @@ class ECoSInterface final
ECoSInterface(World& world, std::string_view _id);
// DecoderController:
tcb::span<const DecoderProtocol> decoderProtocols() const final;
void decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber) final;
// InputController:

Datei anzeigen

@ -131,6 +131,12 @@ bool LocoNetInterface::immPacket(tcb::span<uint8_t> dccPacket, uint8_t repeat)
return false;
}
tcb::span<const DecoderProtocol> LocoNetInterface::decoderProtocols() const
{
static constexpr std::array<DecoderProtocol, 1> protocols{DecoderProtocol::DCC};
return tcb::span<const DecoderProtocol>{protocols.data(), protocols.size()};
}
void LocoNetInterface::decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber)
{
if(m_kernel)

Datei anzeigen

@ -94,6 +94,7 @@ class LocoNetInterface final
bool immPacket(tcb::span<uint8_t> dccPacket, uint8_t repeat);
// DecoderController:
tcb::span<const DecoderProtocol> decoderProtocols() const final;
void decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber) final;
// InputController:

Datei anzeigen

@ -156,6 +156,12 @@ XpressNetInterface::XpressNetInterface(World& world, std::string_view _id)
updateVisible();
}
tcb::span<const DecoderProtocol> XpressNetInterface::decoderProtocols() const
{
static constexpr std::array<DecoderProtocol, 1> protocols{DecoderProtocol::DCC};
return tcb::span<const DecoderProtocol>{protocols.data(), protocols.size()};
}
void XpressNetInterface::decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber)
{
if(m_kernel)

Datei anzeigen

@ -82,6 +82,7 @@ class XpressNetInterface final
XpressNetInterface(World& world, std::string_view _id);
// DecoderController:
tcb::span<const DecoderProtocol> decoderProtocols() const final;
void decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber) final;
// InputController:

Datei anzeigen

@ -87,6 +87,12 @@ Z21Interface::Z21Interface(World& world, std::string_view _id)
m_interfaceItems.insertBefore(firmwareVersion, notes);
}
tcb::span<const DecoderProtocol> Z21Interface::decoderProtocols() const
{
static constexpr std::array<DecoderProtocol, 2> protocols{DecoderProtocol::DCC, DecoderProtocol::Motorola};
return tcb::span<const DecoderProtocol>{protocols.data(), protocols.size()};
}
void Z21Interface::decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber)
{
if(m_kernel)

Datei anzeigen

@ -73,6 +73,7 @@ class Z21Interface final
Z21Interface(World& world, std::string_view _id);
// DecoderController:
tcb::span<const DecoderProtocol> decoderProtocols() const final;
void decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber) final;
// InputController: