ecos: implemented switch by address commands
Dieser Commit ist enthalten in:
Ursprung
4bf74802f1
Commit
ee5de7705b
@ -33,7 +33,7 @@
|
||||
|
||||
constexpr auto decoderListColumns = DecoderListColumn::Id | DecoderListColumn::Name | DecoderListColumn::Address;
|
||||
constexpr auto inputListColumns = InputListColumn::Id | InputListColumn::Name | InputListColumn::Channel | InputListColumn::Address;
|
||||
constexpr auto outputListColumns = OutputListColumn::Id | OutputListColumn::Name | OutputListColumn::Address;
|
||||
constexpr auto outputListColumns = OutputListColumn::Id | OutputListColumn::Name | OutputListColumn::Channel | OutputListColumn::Address;
|
||||
|
||||
ECoSInterface::ECoSInterface(World& world, std::string_view _id)
|
||||
: Interface(world, _id)
|
||||
@ -130,6 +130,23 @@ bool ECoSInterface::removeInput(Input& input)
|
||||
return success;
|
||||
}
|
||||
|
||||
std::pair<uint32_t, uint32_t> ECoSInterface::outputAddressMinMax(uint32_t channel) const
|
||||
{
|
||||
using namespace ECoS;
|
||||
|
||||
switch(channel)
|
||||
{
|
||||
case Kernel::OutputChannel::dcc:
|
||||
return {Kernel::outputDCCAddressMin, Kernel::outputDCCAddressMax};
|
||||
|
||||
case Kernel::OutputChannel::motorola:
|
||||
return {Kernel::outputMotorolaAddressMin, Kernel::outputMotorolaAddressMax};
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
bool ECoSInterface::addOutput(Output& output)
|
||||
{
|
||||
const bool success = OutputController::addOutput(output);
|
||||
@ -151,7 +168,7 @@ bool ECoSInterface::setOutputValue(uint32_t channel, uint32_t address, bool valu
|
||||
return
|
||||
m_kernel &&
|
||||
inRange(address, outputAddressMinMax(channel)) &&
|
||||
m_kernel->setOutput(static_cast<uint16_t>(address), value);
|
||||
m_kernel->setOutput(channel, static_cast<uint16_t>(address), value);
|
||||
}
|
||||
|
||||
bool ECoSInterface::setOnline(bool& value, bool simulation)
|
||||
|
||||
@ -86,7 +86,9 @@ class ECoSInterface final
|
||||
[[nodiscard]] bool removeInput(Input& input) final;
|
||||
|
||||
// OutputController:
|
||||
std::pair<uint32_t, uint32_t> outputAddressMinMax(uint32_t /*channel*/) const final { return {1, 1}; }
|
||||
const std::vector<uint32_t>* outputChannels() const final { return &ECoS::Kernel::outputChannels; }
|
||||
const std::vector<std::string_view>* outputChannelNames() const final { return &ECoS::Kernel::outputChannelNames; }
|
||||
std::pair<uint32_t, uint32_t> outputAddressMinMax(uint32_t channel) const final;
|
||||
[[nodiscard]] bool addOutput(Output& output) final;
|
||||
[[nodiscard]] bool removeOutput(Output& output) final;
|
||||
[[nodiscard]] bool setOutputValue(uint32_t channel, uint32_t address, bool value) final;
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
#include "../../decoder/decoder.hpp"
|
||||
#include "../../decoder/decoderchangeflags.hpp"
|
||||
#include "../../input/inputcontroller.hpp"
|
||||
#include "../../output/outputcontroller.hpp"
|
||||
#include "../../../utils/setthreadname.hpp"
|
||||
#include "../../../utils/startswith.hpp"
|
||||
#include "../../../utils/rtrim.hpp"
|
||||
@ -244,6 +245,13 @@ Locomotive* Kernel::getLocomotive(DecoderProtocol protocol, uint16_t address, ui
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SwitchManager& Kernel::switchManager()
|
||||
{
|
||||
ASSERT_IS_KERNEL_THREAD;
|
||||
|
||||
return static_cast<SwitchManager&>(*m_objects[ObjectId::switchManager]);
|
||||
}
|
||||
|
||||
void Kernel::emergencyStop()
|
||||
{
|
||||
m_ioContext.post([this]() { ecos().stop(); });
|
||||
@ -304,14 +312,67 @@ void Kernel::decoderChanged(const Decoder& decoder, DecoderChangeFlags changes,
|
||||
}
|
||||
}
|
||||
|
||||
bool Kernel::setOutput(uint16_t address, bool value)
|
||||
bool Kernel::setOutput(uint32_t channel, uint16_t address, bool value)
|
||||
{
|
||||
(void)(address);
|
||||
(void)(value);
|
||||
if(value)
|
||||
{
|
||||
switch(channel)
|
||||
{
|
||||
case OutputChannel::dcc:
|
||||
m_ioContext.post(
|
||||
[this, address]()
|
||||
{
|
||||
switchManager().setSwitch(SwitchProtocol::DCC, address);
|
||||
});
|
||||
return true;
|
||||
|
||||
case OutputChannel::motorola:
|
||||
m_ioContext.post(
|
||||
[this, address]()
|
||||
{
|
||||
switchManager().setSwitch(SwitchProtocol::Motorola, address);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Kernel::switchManagerSwitched(SwitchProtocol protocol, uint16_t address)
|
||||
{
|
||||
ASSERT_IS_KERNEL_THREAD;
|
||||
|
||||
if(!m_outputController)
|
||||
return;
|
||||
|
||||
switch(protocol)
|
||||
{
|
||||
case SwitchProtocol::DCC:
|
||||
EventLoop::call(
|
||||
[this, address]()
|
||||
{
|
||||
m_outputController->updateOutputValue(OutputChannel::dcc, address, TriState::True);
|
||||
m_outputController->updateOutputValue(OutputChannel::dcc, (address & 1) ? (address + 1) : (address - 1), TriState::False);
|
||||
});
|
||||
break;
|
||||
|
||||
case SwitchProtocol::Motorola:
|
||||
EventLoop::call(
|
||||
[this, address]()
|
||||
{
|
||||
m_outputController->updateOutputValue(OutputChannel::motorola, address, TriState::True);
|
||||
m_outputController->updateOutputValue(OutputChannel::motorola, (address & 1) ? (address + 1) : (address - 1), TriState::False);
|
||||
});
|
||||
break;
|
||||
|
||||
case SwitchProtocol::Unknown:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Kernel::feedbackStateChanged(Feedback& object, uint8_t port, TriState value)
|
||||
{
|
||||
if(!m_inputController)
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
#include "config.hpp"
|
||||
#include "iohandler/iohandler.hpp"
|
||||
#include "object/object.hpp"
|
||||
#include "object/switchprotocol.hpp"
|
||||
|
||||
class Decoder;
|
||||
enum class DecoderChangeFlags;
|
||||
@ -41,6 +42,7 @@ namespace ECoS {
|
||||
|
||||
class ECoS;
|
||||
class Locomotive;
|
||||
class SwitchManager;
|
||||
class Feedback;
|
||||
|
||||
class Kernel
|
||||
@ -70,6 +72,27 @@ class Kernel
|
||||
"$ecos_channel:ecos_detector$",
|
||||
};
|
||||
|
||||
static constexpr uint16_t outputDCCAddressMin = 1;
|
||||
static constexpr uint16_t outputDCCAddressMax = 1000; //!< \todo what is the maximum
|
||||
static constexpr uint16_t outputMotorolaAddressMin = 1;
|
||||
static constexpr uint16_t outputMotorolaAddressMax = 1000; //!< \todo what is the maximum
|
||||
|
||||
struct OutputChannel
|
||||
{
|
||||
static constexpr uint32_t dcc = 1;
|
||||
static constexpr uint32_t motorola = 2;
|
||||
};
|
||||
|
||||
inline static const std::vector<uint32_t> outputChannels = {
|
||||
OutputChannel::dcc,
|
||||
OutputChannel::motorola,
|
||||
};
|
||||
|
||||
inline static const std::vector<std::string_view> outputChannelNames = {
|
||||
"$hardware:dcc$",
|
||||
"$hardware:motorola$",
|
||||
};
|
||||
|
||||
private:
|
||||
class Objects : public std::unordered_map<uint16_t, std::unique_ptr<Object>>
|
||||
{
|
||||
@ -111,6 +134,8 @@ class Kernel
|
||||
|
||||
Locomotive* getLocomotive(DecoderProtocol protocol, uint16_t address, uint8_t speedSteps);
|
||||
|
||||
SwitchManager& switchManager();
|
||||
|
||||
public:// REMOVE!! just for testing
|
||||
void postSend(const std::string& message)
|
||||
{
|
||||
@ -263,11 +288,14 @@ class Kernel
|
||||
|
||||
/**
|
||||
* @brief ...
|
||||
* @param[in] channel Channel
|
||||
* @param[in] address Output address
|
||||
* @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);
|
||||
bool setOutput(uint32_t channel, uint16_t address, bool value);
|
||||
|
||||
void switchManagerSwitched(SwitchProtocol protocol, uint16_t address);
|
||||
|
||||
void feedbackStateChanged(Feedback& object, uint8_t port, TriState value);
|
||||
};
|
||||
|
||||
@ -77,6 +77,7 @@ struct Option
|
||||
static constexpr std::string_view state = "state";
|
||||
static constexpr std::string_view status = "status";
|
||||
static constexpr std::string_view stop = "stop";
|
||||
static constexpr std::string_view switch_ = "switch";
|
||||
static constexpr std::string_view view = "view";
|
||||
};
|
||||
|
||||
@ -135,7 +136,12 @@ inline std::string set(uint16_t objectId, std::string_view option, T value)
|
||||
std::string s(Command::set);
|
||||
s.append("(").append(std::to_string(objectId));
|
||||
s.append(", ").append(option);
|
||||
s.append("[").append(std::to_string(value)).append("]");
|
||||
s.append("[");
|
||||
if constexpr(std::is_same_v<T, std::string>)
|
||||
s.append(value);
|
||||
else
|
||||
s.append(std::to_string(value));
|
||||
s.append("]");
|
||||
s.append(")\n");
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -27,18 +27,7 @@
|
||||
|
||||
namespace ECoS {
|
||||
|
||||
const std::initializer_list<std::string_view> Switch::options = {Option::addr, Option::protocol, Option::state, Option::mode, Option::duration};
|
||||
|
||||
static bool fromString(std::string_view text, Switch::Protocol& protocol)
|
||||
{
|
||||
if(text == "MM")
|
||||
protocol = Switch::Protocol::MM;
|
||||
else if(text == "DCC")
|
||||
protocol = Switch::Protocol::DCC;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
const std::initializer_list<std::string_view> Switch::options = {Option::addr, Option::protocol};
|
||||
|
||||
static bool fromString(std::string_view text, Switch::Mode& mode)
|
||||
{
|
||||
@ -55,6 +44,7 @@ Switch::Switch(Kernel& kernel, uint16_t id)
|
||||
: Object(kernel, id)
|
||||
{
|
||||
requestView();
|
||||
send(get(m_id, {Option::state, Option::mode, Option::duration}));
|
||||
}
|
||||
|
||||
Switch::Switch(Kernel& kernel, const Line& data)
|
||||
@ -65,12 +55,6 @@ Switch::Switch(Kernel& kernel, const Line& data)
|
||||
fromChars(addr->second, m_address);
|
||||
if(auto protocol = values.find(Option::protocol); protocol != values.end())
|
||||
fromString(protocol->second, m_protocol);
|
||||
if(auto state = values.find(Option::state); state != values.end())
|
||||
{}
|
||||
if(auto mode = values.find(Option::mode); mode != values.end())
|
||||
fromString(mode->second, m_mode);
|
||||
if(auto duration = values.find(Option::duration); duration != values.end())
|
||||
fromChars(duration->second, m_duration);
|
||||
}
|
||||
|
||||
bool Switch::receiveReply(const Reply& reply)
|
||||
@ -91,4 +75,20 @@ bool Switch::receiveEvent(const Event& event)
|
||||
return Object::receiveEvent(event);
|
||||
}
|
||||
|
||||
void Switch::update(std::string_view option, std::string_view value)
|
||||
{
|
||||
if(option == Option::state)
|
||||
{
|
||||
(void)value; //! \todo implement
|
||||
}
|
||||
else if(option == Option::mode)
|
||||
{
|
||||
fromString(value, m_mode);
|
||||
}
|
||||
else if(option == Option::duration)
|
||||
{
|
||||
(void)value; //! \todo implement
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -24,6 +24,7 @@
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_ECOS_OBJECT_SWITCH_HPP
|
||||
|
||||
#include "object.hpp"
|
||||
#include "switchprotocol.hpp"
|
||||
#include "../messages.hpp"
|
||||
|
||||
namespace ECoS {
|
||||
@ -34,13 +35,6 @@ struct Line;
|
||||
class Switch final : public Object
|
||||
{
|
||||
public:
|
||||
enum class Protocol
|
||||
{
|
||||
Unknown = 0,
|
||||
DCC = 1,
|
||||
MM = 2,
|
||||
};
|
||||
|
||||
enum class Mode
|
||||
{
|
||||
Unknown = 0,
|
||||
@ -50,10 +44,13 @@ class Switch final : public Object
|
||||
|
||||
private:
|
||||
uint16_t m_address = 0;
|
||||
Protocol m_protocol = Protocol::Unknown;
|
||||
SwitchProtocol m_protocol = SwitchProtocol::Unknown;
|
||||
Mode m_mode = Mode::Unknown;
|
||||
uint16_t m_duration = 0;
|
||||
|
||||
protected:
|
||||
void update(std::string_view option, std::string_view value) final;
|
||||
|
||||
public:
|
||||
static const std::initializer_list<std::string_view> options;
|
||||
|
||||
@ -64,7 +61,7 @@ class Switch final : public Object
|
||||
bool receiveEvent(const Event& event) final;
|
||||
|
||||
uint16_t address() const { return m_address; }
|
||||
Protocol protocol() const { return m_protocol; }
|
||||
SwitchProtocol protocol() const { return m_protocol; }
|
||||
Mode mode() const { return m_mode; }
|
||||
uint16_t duration() const { return m_duration; }
|
||||
};
|
||||
|
||||
@ -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
|
||||
@ -23,7 +23,10 @@
|
||||
#include "switchmanager.hpp"
|
||||
#include <cassert>
|
||||
#include "switch.hpp"
|
||||
#include "../kernel.hpp"
|
||||
#include "../messages.hpp"
|
||||
#include "../../../../utils/fromchars.hpp"
|
||||
#include "../../../../utils/startswith.hpp"
|
||||
|
||||
namespace ECoS {
|
||||
|
||||
@ -34,6 +37,12 @@ SwitchManager::SwitchManager(Kernel& kernel)
|
||||
send(queryObjects(m_id, Switch::options));
|
||||
}
|
||||
|
||||
void SwitchManager::setSwitch(SwitchProtocol protocol, uint16_t address)
|
||||
{
|
||||
if(protocol == SwitchProtocol::DCC || protocol == SwitchProtocol::Motorola)
|
||||
send(set(m_id, Option::switch_, std::string((protocol == SwitchProtocol::Motorola) ? "MOT" : "DCC").append(std::to_string(1 + ((address - 1) >> 1))).append(((address - 1) & 1) ? "g" : "r")));
|
||||
}
|
||||
|
||||
bool SwitchManager::receiveReply(const Reply& reply)
|
||||
{
|
||||
assert(reply.objectId == m_id);
|
||||
@ -60,4 +69,29 @@ bool SwitchManager::receiveEvent(const Event& event)
|
||||
return Object::receiveEvent(event);
|
||||
}
|
||||
|
||||
void SwitchManager::update(std::string_view option, std::string_view value)
|
||||
{
|
||||
if(option == Option::switch_)
|
||||
{
|
||||
auto protocol = SwitchProtocol::Unknown;
|
||||
for(auto p : {SwitchProtocol::DCC, SwitchProtocol::Motorola})
|
||||
if(startsWith(value, toString(p)))
|
||||
{
|
||||
protocol = p;
|
||||
value = value.substr(toString(p).size());
|
||||
break;
|
||||
}
|
||||
|
||||
if(protocol != SwitchProtocol::Unknown)
|
||||
{
|
||||
uint16_t address;
|
||||
if(auto r = fromChars(value, address); r.ec == std::errc() && r.ptr < value.data() + value.size())
|
||||
{
|
||||
address = (address << 1) - ((*r.ptr == 'r') ? 1 : 0);
|
||||
m_kernel.switchManagerSwitched(protocol, address);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -24,6 +24,7 @@
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_ECOS_OBJECT_SWITCHMANAGER_HPP
|
||||
|
||||
#include "object.hpp"
|
||||
#include "switchprotocol.hpp"
|
||||
|
||||
namespace ECoS {
|
||||
|
||||
@ -31,9 +32,14 @@ class Kernel;
|
||||
|
||||
class SwitchManager final : public Object
|
||||
{
|
||||
protected:
|
||||
void update(std::string_view option, std::string_view value) final;
|
||||
|
||||
public:
|
||||
SwitchManager(Kernel& kernel);
|
||||
|
||||
void setSwitch(SwitchProtocol protocol, uint16_t address);
|
||||
|
||||
bool receiveReply(const Reply& reply) final;
|
||||
bool receiveEvent(const Event& event) final;
|
||||
};
|
||||
|
||||
67
server/src/hardware/protocol/ecos/object/switchprotocol.hpp
Normale Datei
67
server/src/hardware/protocol/ecos/object/switchprotocol.hpp
Normale Datei
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* server/src/hardware/protocol/ecos/object/switchprotocol.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 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
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_ECOS_OBJECT_SWITCHPROTOCOL_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_ECOS_OBJECT_SWITCHPROTOCOL_HPP
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace ECoS
|
||||
{
|
||||
|
||||
enum class SwitchProtocol
|
||||
{
|
||||
Unknown = 0,
|
||||
DCC = 1,
|
||||
Motorola = 2,
|
||||
};
|
||||
|
||||
constexpr std::string_view toString(SwitchProtocol value)
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
case SwitchProtocol::DCC:
|
||||
return "DCC";
|
||||
|
||||
case SwitchProtocol::Motorola:
|
||||
return "MM";
|
||||
|
||||
case SwitchProtocol::Unknown:
|
||||
break;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
constexpr bool fromString(std::string_view text, SwitchProtocol& protocol)
|
||||
{
|
||||
if(text == "MM")
|
||||
protocol = SwitchProtocol::Motorola;
|
||||
else if(text == "DCC")
|
||||
protocol = SwitchProtocol::DCC;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -134,6 +134,7 @@ ecos_channel:ecos_detector=ECoS Detector
|
||||
hardware:address=Address
|
||||
hardware:channel=Channel
|
||||
hardware:command_station=Command station
|
||||
hardware:dcc=DCC
|
||||
hardware:dccplusplus=DCC++
|
||||
hardware:debug_log_input=Log input changes
|
||||
hardware:debug_log_output=Log output changes
|
||||
@ -144,6 +145,7 @@ hardware:input_monitor=Input monitor
|
||||
hardware:inputs=Inputs
|
||||
hardware:interface=Interface
|
||||
hardware:loconet=LocoNet
|
||||
hardware:motorola=Motorola
|
||||
hardware:output_keyboard=Output keyboard
|
||||
hardware:outputs=Outputs
|
||||
hardware:s88=S88
|
||||
@ -159,6 +161,8 @@ input_map_item.block:type=Type
|
||||
|
||||
interface.dccplusplus:dcc_plus_plus=DCC++(EX)
|
||||
|
||||
interface.ecos:ecos=ECoS
|
||||
|
||||
interface.loconet:interface=Interface
|
||||
|
||||
interface.xpressnet:interface=Interface
|
||||
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren