From 6139fa366c0e0a2ad37a4a268f59bec6e5951963 Mon Sep 17 00:00:00 2001 From: Reinder Feenstra Date: Mon, 20 Dec 2021 00:23:31 +0100 Subject: [PATCH] ecos: added mirror objects for ECoS internal objects --- server/CMakeLists.txt | 2 + server/src/hardware/protocol/ecos/kernel.cpp | 108 +++++------------- server/src/hardware/protocol/ecos/kernel.hpp | 25 +++- .../src/hardware/protocol/ecos/messages.cpp | 28 +++++ .../src/hardware/protocol/ecos/messages.hpp | 15 ++- .../hardware/protocol/ecos/object/ecos.cpp | 96 ++++++++++++++++ .../hardware/protocol/ecos/object/ecos.hpp | 50 ++++++++ .../protocol/ecos/object/feedback.cpp | 50 ++++++++ .../protocol/ecos/object/feedback.hpp | 46 ++++++++ .../protocol/ecos/object/feedbackmanager.cpp | 65 +++++++++++ .../protocol/ecos/object/feedbackmanager.hpp | 43 +++++++ .../protocol/ecos/object/locomotive.cpp | 51 +++++++++ .../protocol/ecos/object/locomotive.hpp | 65 +++++++++++ .../ecos/object/locomotivemanager.cpp | 63 ++++++++++ .../ecos/object/locomotivemanager.hpp | 43 +++++++ .../hardware/protocol/ecos/object/object.cpp | 71 ++++++++++++ .../hardware/protocol/ecos/object/object.hpp | 66 +++++++++++ .../hardware/protocol/ecos/object/switch.cpp | 51 +++++++++ .../hardware/protocol/ecos/object/switch.hpp | 59 ++++++++++ .../protocol/ecos/object/switchmanager.cpp | 64 +++++++++++ .../protocol/ecos/object/switchmanager.hpp | 43 +++++++ server/src/utils/rtrim.hpp | 18 ++- 22 files changed, 1035 insertions(+), 87 deletions(-) create mode 100644 server/src/hardware/protocol/ecos/object/ecos.cpp create mode 100644 server/src/hardware/protocol/ecos/object/ecos.hpp create mode 100644 server/src/hardware/protocol/ecos/object/feedback.cpp create mode 100644 server/src/hardware/protocol/ecos/object/feedback.hpp create mode 100644 server/src/hardware/protocol/ecos/object/feedbackmanager.cpp create mode 100644 server/src/hardware/protocol/ecos/object/feedbackmanager.hpp create mode 100644 server/src/hardware/protocol/ecos/object/locomotive.cpp create mode 100644 server/src/hardware/protocol/ecos/object/locomotive.hpp create mode 100644 server/src/hardware/protocol/ecos/object/locomotivemanager.cpp create mode 100644 server/src/hardware/protocol/ecos/object/locomotivemanager.hpp create mode 100644 server/src/hardware/protocol/ecos/object/object.cpp create mode 100644 server/src/hardware/protocol/ecos/object/object.hpp create mode 100644 server/src/hardware/protocol/ecos/object/switch.cpp create mode 100644 server/src/hardware/protocol/ecos/object/switch.hpp create mode 100644 server/src/hardware/protocol/ecos/object/switchmanager.cpp create mode 100644 server/src/hardware/protocol/ecos/object/switchmanager.hpp diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index de3faff6..01c520fc 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -105,6 +105,8 @@ file(GLOB SOURCES "src/hardware/protocol/ecos/*.cpp" "src/hardware/protocol/ecos/iohandler/*.hpp" "src/hardware/protocol/ecos/iohandler/*.cpp" + "src/hardware/protocol/ecos/object/*.hpp" + "src/hardware/protocol/ecos/object/*.cpp" "src/hardware/protocol/loconet/*.hpp" "src/hardware/protocol/loconet/*.cpp" "src/hardware/protocol/loconet/iohandler/*.hpp" diff --git a/server/src/hardware/protocol/ecos/kernel.cpp b/server/src/hardware/protocol/ecos/kernel.cpp index 9cd5d7e2..c9f80744 100644 --- a/server/src/hardware/protocol/ecos/kernel.cpp +++ b/server/src/hardware/protocol/ecos/kernel.cpp @@ -23,6 +23,10 @@ #include "kernel.hpp" #include #include "messages.hpp" +#include "object/ecos.hpp" +#include "object/locomotivemanager.hpp" +#include "object/switchmanager.hpp" +#include "object/feedbackmanager.hpp" #include "../../decoder/decoder.hpp" #include "../../decoder/decoderchangeflags.hpp" #include "../../../utils/setthreadname.hpp" @@ -94,9 +98,7 @@ void Kernel::start() { assert(m_ioHandler); assert(!m_started); - - // reset all state values - m_emergencyStop = TriState::Undefined; + assert(m_objects.empty()); m_thread = std::thread( [this]() @@ -111,20 +113,10 @@ void Kernel::start() { m_ioHandler->start(); - for(auto id : {ObjectId::ecos, ObjectId::locManager, ObjectId::switchManager, ObjectId::feedbackManager}) - send(request(id, {Option::view})); - - send(get(ObjectId::ecos, {Option::info})); - - // query some lists - send(queryObjects(ObjectId::locManager, {Option::addr, Option::protocol})); - send(queryObjects(ObjectId::switchManager, {Option::addr})); - send(queryObjects(ObjectId::feedbackManager)); - - // query an object - send(request(1000, {Option::view})); - send(get(1000, {Option::addr})); - send(get(1000, {Option::name})); + m_objects.add(std::make_unique(*this)); + m_objects.add(std::make_unique(*this)); + m_objects.add(std::make_unique(*this)); + m_objects.add(std::make_unique(*this)); if(m_onStarted) EventLoop::call( @@ -151,6 +143,8 @@ void Kernel::stop() m_thread.join(); + m_objects.clear(); + #ifndef NDEBUG m_started = false; #endif @@ -160,90 +154,48 @@ void Kernel::receive(std::string_view message) { if(m_config.debugLogRXTX) { - std::string msg{message}; - std::replace(msg.begin(), msg.end(), '\n', ';'); + std::string msg{rtrim(message, {'\r', '\n'})}; + std::replace_if(msg.begin(), msg.end(), [](char c){ return c == '\r' || c == '\n'; }, ';'); EventLoop::call([this, msg](){ Log::log(m_logId, LogMessage::D2002_RX_X, msg); }); } - Reply reply; - Event event; - - if(parseReply(message, reply)) + if(Reply reply; parseReply(message, reply)) { - receiveReply(reply); + auto it = m_objects.find(reply.objectId); + if(it != m_objects.end()) + it->second->receiveReply(reply); } - else if(parseEvent(message, event)) + else if(Event event; parseEvent(message, event)) { - receiveEvent(event); + auto it = m_objects.find(event.objectId); + if(it != m_objects.end()) + it->second->receiveEvent(event); } else {}// EventLoop::call([this]() { Log::log(m_logId, LogMessage::E2018_ParseError); }); } -void Kernel::receiveReply(const Reply& reply) +ECoS& Kernel::ecos() { - if(reply.objectId == ObjectId::ecos) - { - if(reply.command == Command::set) - { - if(reply.options.size() == 1) - { - if(reply.options[0] == Option::stop) - { - if(m_emergencyStop != TriState::True) - { - m_emergencyStop = TriState::True; - if(m_onEmergencyStop) - EventLoop::call([this]() { m_onEmergencyStop(); }); - } - } - else if(reply.options[0] == Option::go) - { - if(m_emergencyStop != TriState::False) - { - m_emergencyStop = TriState::False; - if(m_onGo) - EventLoop::call([this]() { m_onGo(); }); - } - } - } - } - else if(reply.command == Command::get) - { - if(reply.options.size() == 1) - { - if(reply.options[0] == Option::info) - { - //! @todo - } - } - } - } + return static_cast(*m_objects[ObjectId::ecos]); } -void Kernel::receiveEvent(const Event& event) +void Kernel::ecosGoChanged(TriState value) { - (void)event; + if(value == TriState::False && m_onEmergencyStop) + EventLoop::call([this]() { m_onEmergencyStop(); }); + else if(value == TriState::True && m_onGo) + EventLoop::call([this]() { m_onGo(); }); } void Kernel::emergencyStop() { - m_ioContext.post( - [this]() - { - if(m_emergencyStop != TriState::True) - send(set(ObjectId::ecos, {Option::stop})); - }); + m_ioContext.post([this]() { ecos().stop(); }); } void Kernel::go() { - m_ioContext.post( - [this]() - { - if(m_emergencyStop != TriState::False) - send(set(ObjectId::ecos, {Option::go})); - }); + m_ioContext.post([this]() { ecos().go(); }); } void Kernel::decoderChanged(const Decoder& decoder, DecoderChangeFlags changes, uint32_t functionNumber) diff --git a/server/src/hardware/protocol/ecos/kernel.hpp b/server/src/hardware/protocol/ecos/kernel.hpp index 0127d242..14f6ece7 100644 --- a/server/src/hardware/protocol/ecos/kernel.hpp +++ b/server/src/hardware/protocol/ecos/kernel.hpp @@ -28,6 +28,7 @@ #include #include "config.hpp" #include "iohandler/iohandler.hpp" +#include "object/object.hpp" class Decoder; enum class DecoderChangeFlags; @@ -37,19 +38,33 @@ class OutputController; namespace ECoS { -struct Reply; -struct Event; +class ECoS; class Kernel { + friend class Object; + friend class ECoS; + private: + class Objects : public std::unordered_map> + { + public: + template + inline void add(std::unique_ptr object) + { + const auto id = object->id(); + emplace(id, std::move(object)); + } + }; + boost::asio::io_context m_ioContext; std::unique_ptr m_ioHandler; std::thread m_thread; std::string m_logId; std::function m_onStarted; - TriState m_emergencyStop; + Objects m_objects; + std::function m_onGo; std::function m_onEmergencyStop; @@ -66,8 +81,8 @@ class Kernel void setIOHandler(std::unique_ptr handler); - void receiveReply(const Reply& reply); - void receiveEvent(const Event& event); + ECoS& ecos(); + void ecosGoChanged(TriState value); public:// REMOVE!! just for testing void postSend(const std::string& message) diff --git a/server/src/hardware/protocol/ecos/messages.cpp b/server/src/hardware/protocol/ecos/messages.cpp index e7e25833..929e1115 100644 --- a/server/src/hardware/protocol/ecos/messages.cpp +++ b/server/src/hardware/protocol/ecos/messages.cpp @@ -1,3 +1,25 @@ +/** + * server/src/hardware/protocol/ecos/messages.cpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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. + */ + #include "messages.hpp" #include #include @@ -102,4 +124,10 @@ bool parseEvent(std::string_view message, Event& event) return false; } +bool parseId(std::string_view line, uint16_t& id) +{ + auto r = std::from_chars(line.data(), line.data() + line.size() - 1, id); + return r.ec == std::errc(); +} + } diff --git a/server/src/hardware/protocol/ecos/messages.hpp b/server/src/hardware/protocol/ecos/messages.hpp index 75c7192b..9a13c563 100644 --- a/server/src/hardware/protocol/ecos/messages.hpp +++ b/server/src/hardware/protocol/ecos/messages.hpp @@ -43,7 +43,7 @@ struct ObjectId { static constexpr uint16_t ecos = 1; static constexpr uint16_t programmingTrack = 5; - static constexpr uint16_t locManager = 10; + static constexpr uint16_t locomotiveManager = 10; static constexpr uint16_t switchManager = 11; static constexpr uint16_t shuttleTrainControl = 12; static constexpr uint16_t deviceManager = 20; @@ -51,15 +51,22 @@ struct ObjectId static constexpr uint16_t feedbackManager = 26; static constexpr uint16_t booster = 27; static constexpr uint16_t controlDesk = 31; + static constexpr uint16_t s88 = 100; + static constexpr uint16_t ecosDetector = 200; }; struct Option { static constexpr std::string_view addr = "addr"; + static constexpr std::string_view dir = "dir"; static constexpr std::string_view go = "go"; static constexpr std::string_view info = "info"; + static constexpr std::string_view mode = "mode"; static constexpr std::string_view name = "name"; + static constexpr std::string_view ports = "ports"; static constexpr std::string_view protocol = "protocol"; + static constexpr std::string_view speedStep = "speedstep"; + 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 view = "view"; @@ -73,7 +80,7 @@ enum class Status : uint32_t struct Reply { std::string_view command; - uint32_t objectId; + uint16_t objectId; std::vector options; std::vector lines; Status status; @@ -82,7 +89,7 @@ struct Reply struct Event { - uint32_t objectId; + uint16_t objectId; }; inline std::string buildCommand(std::string_view command, uint16_t objectId, std::initializer_list options) @@ -133,6 +140,8 @@ inline std::string release(uint16_t objectId, std::initializer_list +#include "../kernel.hpp" +#include "../messages.hpp" + +namespace ECoS { + +ECoS::ECoS(Kernel& kernel) + : Object(kernel, ObjectId::ecos) +{ + requestView(); + send(get(m_id, {Option::info})); +} + +bool ECoS::receiveReply(const Reply& reply) +{ + assert(reply.objectId == m_id); + + if(reply.command == Command::set) + { + if(reply.options.size() == 1) + { + if(reply.options[0] == Option::stop) + { + if(m_go != TriState::False) + { + m_go = TriState::False; + m_kernel.ecosGoChanged(m_go); + } + } + else if(reply.options[0] == Option::go) + { + if(m_go != TriState::True) + { + m_go = TriState::True; + m_kernel.ecosGoChanged(m_go); + } + } + } + } + else if(reply.command == Command::get) + { + if(reply.options.size() == 1) + { + if(reply.options[0] == Option::info) + { + //! @todo + } + } + } + + return Object::receiveReply(reply); +} + +bool ECoS::receiveEvent(const Event& event) +{ + assert(event.objectId == m_id); + + return Object::receiveEvent(event); +} + +void ECoS::go() +{ + if(m_go != TriState::True) + send(set(m_id, {Option::go})); +} + +void ECoS::stop() +{ + if(m_go != TriState::False) + send(set(m_id, {Option::stop})); +} + +} diff --git a/server/src/hardware/protocol/ecos/object/ecos.hpp b/server/src/hardware/protocol/ecos/object/ecos.hpp new file mode 100644 index 00000000..90815576 --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/ecos.hpp @@ -0,0 +1,50 @@ +/** + * server/src/hardware/protocol/ecos/object/ecos.hpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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_ECOS_HPP +#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_ECOS_OBJECT_ECOS_HPP + +#include "object.hpp" +#include + +namespace ECoS { + +class Kernel; + +class ECoS final : public Object +{ + private: + TriState m_go = TriState::Undefined; + + public: + ECoS(Kernel& kernel); + + bool receiveReply(const Reply& reply) final; + bool receiveEvent(const Event& event) final; + + void go(); + void stop(); +}; + +} + +#endif diff --git a/server/src/hardware/protocol/ecos/object/feedback.cpp b/server/src/hardware/protocol/ecos/object/feedback.cpp new file mode 100644 index 00000000..2414eba0 --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/feedback.cpp @@ -0,0 +1,50 @@ +/** + * server/src/hardware/protocol/ecos/object/feedback.cpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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. + */ + +#include "feedback.hpp" +#include +#include "../messages.hpp" + +namespace ECoS { + +const std::initializer_list Feedback::options = {Option::addr, Option::protocol, Option::state, Option::ports}; + +Feedback::Feedback(Kernel& kernel, uint16_t id) + : Object(kernel, id) +{ +} + +bool Feedback::receiveReply(const Reply& reply) +{ + assert(reply.objectId == m_id); + + return Object::receiveReply(reply); +} + +bool Feedback::receiveEvent(const Event& event) +{ + assert(event.objectId == m_id); + + return Object::receiveEvent(event); +} + +} diff --git a/server/src/hardware/protocol/ecos/object/feedback.hpp b/server/src/hardware/protocol/ecos/object/feedback.hpp new file mode 100644 index 00000000..fa3fa17b --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/feedback.hpp @@ -0,0 +1,46 @@ +/** + * server/src/hardware/protocol/ecos/object/feedback.hpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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_FEEDBACK_HPP +#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_ECOS_OBJECT_FEEDBACK_HPP + +#include "object.hpp" +#include "../messages.hpp" + +namespace ECoS { + +class Kernel; + +class Feedback final : public Object +{ + public: + static const std::initializer_list options; + + Feedback(Kernel& kernel, uint16_t id); + + bool receiveReply(const Reply& reply) final; + bool receiveEvent(const Event& event) final; +}; + +} + +#endif \ No newline at end of file diff --git a/server/src/hardware/protocol/ecos/object/feedbackmanager.cpp b/server/src/hardware/protocol/ecos/object/feedbackmanager.cpp new file mode 100644 index 00000000..9cbc338f --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/feedbackmanager.cpp @@ -0,0 +1,65 @@ +/** + * server/src/hardware/protocol/ecos/object/feedbackmanager.cpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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. + */ + +#include "feedbackmanager.hpp" +#include +#include "feedback.hpp" +#include "../messages.hpp" + +namespace ECoS { + +FeedbackManager::FeedbackManager(Kernel& kernel) + : Object(kernel, ObjectId::feedbackManager) +{ + requestView(); + send(queryObjects(m_id, Feedback::options)); + send(request(ObjectId::s88, {Option::view})); + send(request(ObjectId::ecosDetector, {Option::view})); +} + +bool FeedbackManager::receiveReply(const Reply& reply) +{ + assert(reply.objectId == m_id); + + if(reply.command == Command::queryObjects) + { + for(std::string_view line : reply.lines) + { + if(uint16_t id; parseId(line, id) && !objectExists(id)) + { + addObject(std::make_unique(m_kernel, id)); + } + } + return true; + } + + return Object::receiveReply(reply); +} + +bool FeedbackManager::receiveEvent(const Event& event) +{ + assert(event.objectId == m_id); + + return Object::receiveEvent(event); +} + +} diff --git a/server/src/hardware/protocol/ecos/object/feedbackmanager.hpp b/server/src/hardware/protocol/ecos/object/feedbackmanager.hpp new file mode 100644 index 00000000..2277d8cf --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/feedbackmanager.hpp @@ -0,0 +1,43 @@ +/** + * server/src/hardware/protocol/ecos/object/feedbackmanager.hpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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_FEEDBACKMANAGER_HPP +#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_ECOS_OBJECT_FEEDBACKMANAGER_HPP + +#include "object.hpp" + +namespace ECoS { + +class Kernel; + +class FeedbackManager final : public Object +{ + public: + FeedbackManager(Kernel& kernel); + + bool receiveReply(const Reply& reply) final; + bool receiveEvent(const Event& event) final; +}; + +} + +#endif \ No newline at end of file diff --git a/server/src/hardware/protocol/ecos/object/locomotive.cpp b/server/src/hardware/protocol/ecos/object/locomotive.cpp new file mode 100644 index 00000000..34056144 --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/locomotive.cpp @@ -0,0 +1,51 @@ +/** + * server/src/hardware/protocol/ecos/object/locomotive.cpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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. + */ + +#include "locomotive.hpp" +#include +#include "../messages.hpp" + +namespace ECoS { + +const std::initializer_list Locomotive::options = {Option::addr, Option::protocol, Option::state, Option::speedStep}; + +Locomotive::Locomotive(Kernel& kernel, uint16_t id) + : Object(kernel, id) +{ + requestView(); +} + +bool Locomotive::receiveReply(const Reply& reply) +{ + assert(reply.objectId == m_id); + + return Object::receiveReply(reply); +} + +bool Locomotive::receiveEvent(const Event& event) +{ + assert(event.objectId == m_id); + + return Object::receiveEvent(event); +} + +} diff --git a/server/src/hardware/protocol/ecos/object/locomotive.hpp b/server/src/hardware/protocol/ecos/object/locomotive.hpp new file mode 100644 index 00000000..07c06b7d --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/locomotive.hpp @@ -0,0 +1,65 @@ +/** + * server/src/hardware/protocol/ecos/object/locomotive.hpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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_LOCOMOTIVE_HPP +#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_ECOS_OBJECT_LOCOMOTIVE_HPP + +#include "object.hpp" +#include "../messages.hpp" + +namespace ECoS { + +class Kernel; + +class Locomotive final : public Object +{ + public: + enum class Protocol + { + Unknown = 0, + MM14 = 1, + MM27 = 2, + MM28 = 3, + DCC14 = 4, + DCC28 = 5, + DCC128 = 6, + SX32 = 7, + MMFKT = 8, + }; + + private: + Protocol m_protocol = Protocol::Unknown; + + public: + static const std::initializer_list options; + + Locomotive(Kernel& kernel, uint16_t id); + + bool receiveReply(const Reply& reply) final; + bool receiveEvent(const Event& event) final; + + Protocol protocol() const { return m_protocol; } +}; + +} + +#endif \ No newline at end of file diff --git a/server/src/hardware/protocol/ecos/object/locomotivemanager.cpp b/server/src/hardware/protocol/ecos/object/locomotivemanager.cpp new file mode 100644 index 00000000..c34154c4 --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/locomotivemanager.cpp @@ -0,0 +1,63 @@ +/** + * server/src/hardware/protocol/ecos/object/locomotivemanager.cpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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. + */ + +#include "locomotivemanager.hpp" +#include +#include "locomotive.hpp" +#include "../messages.hpp" + +namespace ECoS { + +LocomotiveManager::LocomotiveManager(Kernel& kernel) + : Object(kernel, ObjectId::locomotiveManager) +{ + requestView(); + send(queryObjects(m_id, Locomotive::options)); +} + +bool LocomotiveManager::receiveReply(const Reply& reply) +{ + assert(reply.objectId == m_id); + + if(reply.command == Command::queryObjects) + { + for(std::string_view line : reply.lines) + { + if(uint16_t id; parseId(line, id) && !objectExists(id)) + { + addObject(std::make_unique(m_kernel, id)); + } + } + return true; + } + + return Object::receiveReply(reply); +} + +bool LocomotiveManager::receiveEvent(const Event& event) +{ + assert(event.objectId == m_id); + + return Object::receiveEvent(event); +} + +} diff --git a/server/src/hardware/protocol/ecos/object/locomotivemanager.hpp b/server/src/hardware/protocol/ecos/object/locomotivemanager.hpp new file mode 100644 index 00000000..d96837e0 --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/locomotivemanager.hpp @@ -0,0 +1,43 @@ +/** + * server/src/hardware/protocol/ecos/object/locomotivemanager.hpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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_LOCOMOTIVEMANAGER_HPP +#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_ECOS_OBJECT_LOCOMOTIVEMANAGER_HPP + +#include "object.hpp" + +namespace ECoS { + +class Kernel; + +class LocomotiveManager final : public Object +{ + public: + LocomotiveManager(Kernel& kernel); + + bool receiveReply(const Reply& reply) final; + bool receiveEvent(const Event& event) final; +}; + +} + +#endif \ No newline at end of file diff --git a/server/src/hardware/protocol/ecos/object/object.cpp b/server/src/hardware/protocol/ecos/object/object.cpp new file mode 100644 index 00000000..a6ca23a2 --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/object.cpp @@ -0,0 +1,71 @@ +/** + * server/src/hardware/protocol/ecos/object/object.cpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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. + */ + +#include "object.hpp" +#include +#include "../messages.hpp" +#include "../kernel.hpp" + +namespace ECoS { + +Object::Object(Kernel& kernel, uint16_t id) + : m_kernel{kernel} + , m_id{id} +{ +} + +bool Object::receiveReply(const Reply& reply) +{ + assert(reply.objectId == m_id); + + return false; +} + +bool Object::receiveEvent(const Event& event) +{ + assert(event.objectId == m_id); + + return false; +} + +void Object::requestView() +{ + if(!m_isViewActive) + send(request(m_id, {Option::view})); +} + +void Object::send(std::string_view message) +{ + m_kernel.send(message); +} + +bool Object::objectExists(uint16_t objectId) const +{ + return m_kernel.m_objects.find(objectId) != m_kernel.m_objects.end(); +} + +void Object::addObject(std::unique_ptr object) +{ + m_kernel.m_objects.add(std::move(object)); +} + +} diff --git a/server/src/hardware/protocol/ecos/object/object.hpp b/server/src/hardware/protocol/ecos/object/object.hpp new file mode 100644 index 00000000..7b25529e --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/object.hpp @@ -0,0 +1,66 @@ +/** + * server/src/hardware/protocol/ecos/object/object.hpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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_OBJECT_HPP +#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_ECOS_OBJECT_OBJECT_HPP + +#include +#include +#include + +namespace ECoS { + +class Kernel; +struct Reply; +struct Event; + +class Object +{ + protected: + Kernel& m_kernel; + const uint16_t m_id; + bool m_isViewActive = false; + + void send(std::string_view message); + + bool objectExists(uint16_t objectId) const; + void addObject(std::unique_ptr object); + + public: + Object(const Object&) = delete; + Object& operator =(const Object&) = delete; + + Object(Kernel& kernel, uint16_t id); + virtual ~Object() = default; + + virtual bool receiveReply(const Reply& reply); + virtual bool receiveEvent(const Event& event); + + inline uint16_t id() const { return m_id; } + inline bool isViewActive() const { return m_isViewActive; } + + void requestView(); +}; + +} + +#endif diff --git a/server/src/hardware/protocol/ecos/object/switch.cpp b/server/src/hardware/protocol/ecos/object/switch.cpp new file mode 100644 index 00000000..2b3f138b --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/switch.cpp @@ -0,0 +1,51 @@ +/** + * server/src/hardware/protocol/ecos/object/switch.cpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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. + */ + +#include "switch.hpp" +#include +#include "../messages.hpp" + +namespace ECoS { + +const std::initializer_list Switch::options = {Option::addr, Option::protocol, Option::state, Option::mode}; + +Switch::Switch(Kernel& kernel, uint16_t id) + : Object(kernel, id) +{ + requestView(); +} + +bool Switch::receiveReply(const Reply& reply) +{ + assert(reply.objectId == m_id); + + return Object::receiveReply(reply); +} + +bool Switch::receiveEvent(const Event& event) +{ + assert(event.objectId == m_id); + + return Object::receiveEvent(event); +} + +} diff --git a/server/src/hardware/protocol/ecos/object/switch.hpp b/server/src/hardware/protocol/ecos/object/switch.hpp new file mode 100644 index 00000000..0d6e7209 --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/switch.hpp @@ -0,0 +1,59 @@ +/** + * server/src/hardware/protocol/ecos/object/switch.hpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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_SWITCH_HPP +#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_ECOS_OBJECT_SWITCH_HPP + +#include "object.hpp" +#include "../messages.hpp" + +namespace ECoS { + +class Kernel; + +class Switch final : public Object +{ + public: + enum class Protocol + { + Unknown = 0, + DCC = 1, + MM = 2, + }; + + private: + Protocol m_protocol = Protocol::Unknown; + + public: + static const std::initializer_list options; + + Switch(Kernel& kernel, uint16_t id); + + bool receiveReply(const Reply& reply) final; + bool receiveEvent(const Event& event) final; + + Protocol protocol() const { return m_protocol; } +}; + +} + +#endif \ No newline at end of file diff --git a/server/src/hardware/protocol/ecos/object/switchmanager.cpp b/server/src/hardware/protocol/ecos/object/switchmanager.cpp new file mode 100644 index 00000000..55550fc0 --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/switchmanager.cpp @@ -0,0 +1,64 @@ +/** + * server/src/hardware/protocol/ecos/object/switchmanager.cpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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. + */ + +#include "switchmanager.hpp" +#include +#include "switch.hpp" +#include "../messages.hpp" + +namespace ECoS { + +SwitchManager::SwitchManager(Kernel& kernel) + : Object(kernel, ObjectId::switchManager) +{ + requestView(); + send(queryObjects(m_id, Switch::options)); +} + +bool SwitchManager::receiveReply(const Reply& reply) +{ + assert(reply.objectId == m_id); + + if(reply.command == Command::queryObjects) + { + for(std::string_view line : reply.lines) + { + if(uint16_t id; parseId(line, id) && !objectExists(id)) + { + addObject(std::make_unique(m_kernel, id)); + } + } + return true; + } + + return Object::receiveReply(reply); +} + +bool SwitchManager::receiveEvent(const Event& event) +{ + assert(event.objectId == m_id); + + + return Object::receiveEvent(event); +} + +} diff --git a/server/src/hardware/protocol/ecos/object/switchmanager.hpp b/server/src/hardware/protocol/ecos/object/switchmanager.hpp new file mode 100644 index 00000000..b231ef93 --- /dev/null +++ b/server/src/hardware/protocol/ecos/object/switchmanager.hpp @@ -0,0 +1,43 @@ +/** + * server/src/hardware/protocol/ecos/object/switchmanager.hpp + * + * This file is part of the traintastic source code. + * + * Copyright (C) 2021 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_SWITCHMANAGER_HPP +#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_ECOS_OBJECT_SWITCHMANAGER_HPP + +#include "object.hpp" + +namespace ECoS { + +class Kernel; + +class SwitchManager final : public Object +{ + public: + SwitchManager(Kernel& kernel); + + bool receiveReply(const Reply& reply) final; + bool receiveEvent(const Event& event) final; +}; + +} + +#endif diff --git a/server/src/utils/rtrim.hpp b/server/src/utils/rtrim.hpp index 08990edf..5b4cea1b 100644 --- a/server/src/utils/rtrim.hpp +++ b/server/src/utils/rtrim.hpp @@ -24,6 +24,7 @@ #define TRAINTASTIC_SERVER_UTILS_RTRIM_HPP #include +#include constexpr std::string_view rtrim(std::string_view s, char c) { @@ -31,7 +32,22 @@ constexpr std::string_view rtrim(std::string_view s, char c) return {}; size_t size = s.size() - 1; - while(s.data()[--size] == c) + while(s.data()[size] == c) + { + if(size == 0) + return {}; + size--; + } + return {s.data(), size + 1}; +} + +constexpr std::string_view rtrim(std::string_view s, std::initializer_list c) +{ + if(s.empty()) + return {}; + + size_t size = s.size() - 1; + while(std::any_of(c.begin(), c.end(), [c1=s.data()[size]](char c2) { return c1 == c2; })) { if(size == 0) return {};