ecos: added simulation of s88 objects
using data of last successful connection
Dieser Commit ist enthalten in:
Ursprung
c68142278b
Commit
7afe5ea943
@ -31,6 +31,7 @@
|
||||
#include "../../utils/displayname.hpp"
|
||||
#include "../../utils/inrange.hpp"
|
||||
#include "../../world/world.hpp"
|
||||
#include "../../world/worldloader.hpp"
|
||||
|
||||
constexpr auto decoderListColumns = DecoderListColumn::Id | DecoderListColumn::Name | DecoderListColumn::Address;
|
||||
constexpr auto inputListColumns = InputListColumn::Id | InputListColumn::Name | InputListColumn::Channel | InputListColumn::Address;
|
||||
@ -179,7 +180,7 @@ bool ECoSInterface::setOnline(bool& value, bool simulation)
|
||||
try
|
||||
{
|
||||
if(simulation)
|
||||
m_kernel = ECoS::Kernel::create<ECoS::SimulationIOHandler>(ecos->config());
|
||||
m_kernel = ECoS::Kernel::create<ECoS::SimulationIOHandler>(ecos->config(), m_simulation);
|
||||
else
|
||||
m_kernel = ECoS::Kernel::create<ECoS::TCPIOHandler>(ecos->config(), hostname.value());
|
||||
|
||||
@ -234,7 +235,7 @@ bool ECoSInterface::setOnline(bool& value, bool simulation)
|
||||
|
||||
m_ecosPropertyChanged.disconnect();
|
||||
|
||||
m_kernel->stop();
|
||||
m_kernel->stop(simulation ? nullptr : &m_simulation);
|
||||
m_kernel.reset();
|
||||
|
||||
status.setValueInternal(InterfaceStatus::Offline);
|
||||
@ -278,6 +279,53 @@ void ECoSInterface::destroying()
|
||||
Interface::destroying();
|
||||
}
|
||||
|
||||
void ECoSInterface::load(WorldLoader& loader, const nlohmann::json& data)
|
||||
{
|
||||
Interface::load(loader, data);
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
json state = loader.getState(getObjectId());
|
||||
// load simulation data:
|
||||
if(json simulation = state.value("simulation", json::object()); !simulation.empty())
|
||||
{
|
||||
using ECoS::Simulation;
|
||||
|
||||
if(json s88 = simulation.value("s88", json::array()); !s88.empty())
|
||||
{
|
||||
for(const json& object : s88)
|
||||
{
|
||||
const uint16_t objectId = object.value("id", 0U);
|
||||
const uint8_t ports = object.value("ports", 0U);
|
||||
if(objectId != 0 && (ports == 8 || ports == 16))
|
||||
m_simulation.s88.emplace_back(Simulation::S88{{objectId}, ports});
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ECoSInterface::save(WorldSaver& saver, nlohmann::json& data, nlohmann::json& state) const
|
||||
{
|
||||
Interface::save(saver, data, state);
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
// save data for simulation:
|
||||
json simulation = json::object();
|
||||
if(!m_simulation.s88.empty())
|
||||
{
|
||||
json objects = json::array();
|
||||
for(const auto& s88 : m_simulation.s88)
|
||||
objects.emplace_back(json::object({{"id", s88.id}, {"ports", s88.ports}}));
|
||||
simulation["s88"] = objects;
|
||||
}
|
||||
|
||||
if(!simulation.empty())
|
||||
state["simulation"] = simulation;
|
||||
}
|
||||
|
||||
void ECoSInterface::worldEvent(WorldState state, WorldEvent event)
|
||||
{
|
||||
Interface::worldEvent(state, event);
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include "interface.hpp"
|
||||
#include "../protocol/ecos/kernel.hpp"
|
||||
#include "../protocol/ecos/settings.hpp"
|
||||
#include "../protocol/ecos/simulation.hpp"
|
||||
#include "../decoder/decodercontroller.hpp"
|
||||
#include "../decoder/list/decoderlist.hpp"
|
||||
#include "../input/inputcontroller.hpp"
|
||||
@ -50,9 +51,12 @@ class ECoSInterface final
|
||||
private:
|
||||
std::unique_ptr<ECoS::Kernel> m_kernel;
|
||||
boost::signals2::connection m_ecosPropertyChanged;
|
||||
ECoS::Simulation m_simulation;
|
||||
|
||||
void addToWorld() final;
|
||||
void destroying() final;
|
||||
void load(WorldLoader& loader, const nlohmann::json& data) final;
|
||||
void save(WorldSaver& saver, nlohmann::json& data, nlohmann::json& state) const final;
|
||||
void worldEvent(WorldState state, WorldEvent event) final;
|
||||
|
||||
void idChanged(const std::string& newId) final;
|
||||
|
||||
@ -24,11 +24,13 @@
|
||||
#include "../kernel.hpp"
|
||||
#include "../messages.hpp"
|
||||
#include "../../../../utils/rtrim.hpp"
|
||||
#include "../../../../utils/contains.hpp"
|
||||
|
||||
namespace ECoS {
|
||||
|
||||
SimulationIOHandler::SimulationIOHandler(Kernel& kernel)
|
||||
SimulationIOHandler::SimulationIOHandler(Kernel& kernel, const Simulation& simulation)
|
||||
: IOHandler(kernel)
|
||||
, m_simulation{simulation}
|
||||
{
|
||||
}
|
||||
|
||||
@ -87,9 +89,37 @@ bool SimulationIOHandler::send(std::string_view message)
|
||||
{
|
||||
if(request.command == Command::queryObjects)
|
||||
{
|
||||
return replyOk(message); // empty list for now
|
||||
const bool ports = contains(request.options, Option::ports);
|
||||
|
||||
std::string response{replyHeader(message)};
|
||||
for(const auto& s88 : m_simulation.s88)
|
||||
{
|
||||
response.append(std::to_string(s88.id));
|
||||
if(ports)
|
||||
response.append(" ports[").append(std::to_string(s88.ports)).append("]");
|
||||
response.append("\r\n");
|
||||
}
|
||||
response.append("<END 0 (OK)>\r\n");
|
||||
|
||||
return reply(response);
|
||||
}
|
||||
}
|
||||
else if(auto it = std::find_if(m_simulation.s88.begin(), m_simulation.s88.end(),
|
||||
[id=request.objectId](const auto& v)
|
||||
{
|
||||
return v.id == id;
|
||||
}); it != m_simulation.s88.end())
|
||||
{
|
||||
const bool state = contains(request.options, Option::state);
|
||||
|
||||
std::string response{replyHeader(message)};
|
||||
response.append(std::to_string(request.objectId));
|
||||
if(state)
|
||||
response.append(" state[0x0]");
|
||||
response.append("<END 0 (OK)>\r\n");
|
||||
|
||||
return reply(response);
|
||||
}
|
||||
|
||||
return reply(std::string("<REPLY ").append(message).append(">\r\n<END 999 (Traintastic: no simulation support)>\r\n"));
|
||||
}
|
||||
@ -108,7 +138,12 @@ bool SimulationIOHandler::reply(std::string_view message)
|
||||
|
||||
bool SimulationIOHandler::replyOk(std::string_view request)
|
||||
{
|
||||
return reply(std::string("<REPLY ").append(rtrim(request, {'\r', '\n'})).append(">\r\n<END 0 (OK)>\r\n"));
|
||||
return reply(replyHeader(request).append("<END 0 (OK)>\r\n"));
|
||||
}
|
||||
|
||||
std::string SimulationIOHandler::replyHeader(std::string_view request)
|
||||
{
|
||||
return std::string("<REPLY ").append(rtrim(request, {'\r', '\n'})).append(">\r\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -26,17 +26,22 @@
|
||||
#include "iohandler.hpp"
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include "../simulation.hpp"
|
||||
|
||||
namespace ECoS {
|
||||
|
||||
class SimulationIOHandler final : public IOHandler
|
||||
{
|
||||
private:
|
||||
const Simulation m_simulation;
|
||||
|
||||
bool reply(std::string_view message);
|
||||
bool replyOk(std::string_view request);
|
||||
|
||||
static std::string replyHeader(std::string_view request);
|
||||
|
||||
public:
|
||||
SimulationIOHandler(Kernel& kernel);
|
||||
SimulationIOHandler(Kernel& kernel, const Simulation& simulation);
|
||||
|
||||
void start() final {}
|
||||
void stop() final {}
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include "kernel.hpp"
|
||||
#include <algorithm>
|
||||
#include "messages.hpp"
|
||||
#include "simulation.hpp"
|
||||
#include "object/ecos.hpp"
|
||||
#include "object/locomotivemanager.hpp"
|
||||
#include "object/locomotive.hpp"
|
||||
@ -161,7 +162,7 @@ void Kernel::start()
|
||||
#endif
|
||||
}
|
||||
|
||||
void Kernel::stop()
|
||||
void Kernel::stop(Simulation* simulation)
|
||||
{
|
||||
m_ioContext.post(
|
||||
[this]()
|
||||
@ -173,6 +174,25 @@ void Kernel::stop()
|
||||
|
||||
m_thread.join();
|
||||
|
||||
if(simulation) // get simulation data
|
||||
{
|
||||
simulation->clear();
|
||||
|
||||
// S88:
|
||||
{
|
||||
uint16_t id = ObjectId::s88;
|
||||
auto it = m_objects.find(id);
|
||||
while(it != m_objects.end())
|
||||
{
|
||||
if(const auto* feedback = dynamic_cast<Feedback*>(it->second.get()))
|
||||
simulation->s88.emplace_back(Simulation::S88{{feedback->id()}, feedback->ports()});
|
||||
else
|
||||
break;
|
||||
it = m_objects.find(++id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_objects.clear();
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
@ -44,6 +44,7 @@ class ECoS;
|
||||
class Locomotive;
|
||||
class SwitchManager;
|
||||
class Feedback;
|
||||
struct Simulation;
|
||||
|
||||
class Kernel
|
||||
{
|
||||
@ -255,8 +256,9 @@ class Kernel
|
||||
|
||||
/**
|
||||
* @brief Stop the kernel and IO handler
|
||||
* @param[out] simulation Get simulation data (optional)
|
||||
*/
|
||||
void stop();
|
||||
void stop(Simulation* simulation);
|
||||
|
||||
/**
|
||||
* @brief ...
|
||||
|
||||
@ -45,6 +45,8 @@ class Feedback final : public Object
|
||||
|
||||
Feedback(Kernel& kernel, uint16_t id);
|
||||
Feedback(Kernel& kernel, const Line& data);
|
||||
|
||||
uint8_t ports() const { return static_cast<uint8_t>(m_state.size()); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
53
server/src/hardware/protocol/ecos/simulation.hpp
Normale Datei
53
server/src/hardware/protocol/ecos/simulation.hpp
Normale Datei
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* server/src/hardware/protocol/ecos/simulation.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_SIMULATION_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_ECOS_SIMULATION_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ECoS {
|
||||
|
||||
struct Simulation
|
||||
{
|
||||
struct Object
|
||||
{
|
||||
uint16_t id;
|
||||
};
|
||||
|
||||
struct S88 : Object
|
||||
{
|
||||
uint8_t ports;
|
||||
};
|
||||
|
||||
std::vector<S88> s88;
|
||||
|
||||
void clear()
|
||||
{
|
||||
s88.clear();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
34
server/src/utils/contains.hpp
Normale Datei
34
server/src/utils/contains.hpp
Normale Datei
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* server/src/utils/contains.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_UTILS_CONTAINS_HPP
|
||||
#define TRAINTASTIC_SERVER_UTILS_CONTAINS_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
template<class T>
|
||||
inline bool contains(const std::vector<T>& vector, T value)
|
||||
{
|
||||
return std::find(vector.begin(), vector.end(), value) != vector.end();
|
||||
}
|
||||
|
||||
#endif
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren