[cbus] added interface/kernel/iohandlers (untested due to leak of hardware)
Dieser Commit ist enthalten in:
Ursprung
2bfbbb267f
Commit
ff784fcf49
@ -105,6 +105,7 @@ file(GLOB SOURCES
|
||||
"src/hardware/input/monitor/*.cpp"
|
||||
"src/hardware/interface/*.hpp"
|
||||
"src/hardware/interface/*.cpp"
|
||||
"src/hardware/interface/cbus/*.cpp"
|
||||
"src/hardware/interface/marklincan/*.hpp"
|
||||
"src/hardware/interface/marklincan/*.cpp"
|
||||
"src/hardware/output/*.hpp"
|
||||
@ -119,6 +120,8 @@ file(GLOB SOURCES
|
||||
"src/hardware/programming/lncv/*.cpp"
|
||||
"src/hardware/protocol/*.hpp"
|
||||
"src/hardware/protocol/*.cpp"
|
||||
"src/hardware/protocol/cbus/*.cpp"
|
||||
"src/hardware/protocol/cbus/iohandler/*.cpp"
|
||||
"src/hardware/protocol/dccex/*.hpp"
|
||||
"src/hardware/protocol/dccex/*.cpp"
|
||||
"src/hardware/protocol/dccex/iohandler/*.hpp"
|
||||
|
||||
40
server/src/hardware/interface/cbus/cbussettings.cpp
Normale Datei
40
server/src/hardware/interface/cbus/cbussettings.cpp
Normale Datei
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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 "cbussettings.hpp"
|
||||
#include "../../../core/attributes.hpp"
|
||||
#include "../../../utils/displayname.hpp"
|
||||
|
||||
CBUSSettings::CBUSSettings(Object& _parent, std::string_view parentPropertyName)
|
||||
: SubObject(_parent, parentPropertyName)
|
||||
, debugLogRXTX{this, "debug_log_rx_tx", false, PropertyFlags::ReadWrite | PropertyFlags::Store}
|
||||
{
|
||||
Attributes::addDisplayName(debugLogRXTX, DisplayName::Hardware::debugLogRXTX);
|
||||
//Attributes::addGroup(debugLogRXTX, Group::debug);
|
||||
m_interfaceItems.add(debugLogRXTX);
|
||||
}
|
||||
|
||||
CBUS::Config CBUSSettings::config() const
|
||||
{
|
||||
return CBUS::Config{
|
||||
.debugLogRXTX = debugLogRXTX,
|
||||
};
|
||||
}
|
||||
41
server/src/hardware/interface/cbus/cbussettings.hpp
Normale Datei
41
server/src/hardware/interface/cbus/cbussettings.hpp
Normale Datei
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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_INTERFACE_CBUS_CBUSSETTINGS_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_INTERFACE_CBUS_CBUSSETTINGS_HPP
|
||||
|
||||
#include "../../../core/subobject.hpp"
|
||||
#include "../../../core/property.hpp"
|
||||
#include "../../../hardware/protocol/cbus/cbusconfig.hpp"
|
||||
|
||||
class CBUSSettings final : public SubObject
|
||||
{
|
||||
CLASS_ID("cbus_settings")
|
||||
|
||||
public:
|
||||
Property<bool> debugLogRXTX;
|
||||
|
||||
CBUSSettings(Object& _parent, std::string_view parentPropertyName);
|
||||
|
||||
CBUS::Config config() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
238
server/src/hardware/interface/cbusinterface.cpp
Normale Datei
238
server/src/hardware/interface/cbusinterface.cpp
Normale Datei
@ -0,0 +1,238 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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 "cbusinterface.hpp"
|
||||
#include "cbus/cbussettings.hpp"
|
||||
#include "../protocol/cbus/cbuskernel.hpp"
|
||||
#include "../protocol/cbus/iohandler/cbuscanusbiohandler.hpp"
|
||||
#include "../protocol/cbus/iohandler/cbuscanetheriohandler.hpp"
|
||||
/*
|
||||
#include "../protocol/cbus/simulator/cbussimulator.hpp"
|
||||
*/
|
||||
#include "../../core/attributes.hpp"
|
||||
#include "../../core/eventloop.hpp"
|
||||
#include "../../core/method.tpp"
|
||||
#include "../../core/objectproperty.tpp"
|
||||
#include "../../log/log.hpp"
|
||||
#include "../../log/logmessageexception.hpp"
|
||||
#include "../../utils/displayname.hpp"
|
||||
#include "../../world/world.hpp"
|
||||
|
||||
CREATE_IMPL(CBUSInterface)
|
||||
|
||||
CBUSInterface::CBUSInterface(World& world, std::string_view _id)
|
||||
: Interface(world, _id)
|
||||
, type{this, "type", CBUSInterfaceType::CANUSB, PropertyFlags::ReadWrite | PropertyFlags::Store,
|
||||
[this](CBUSInterfaceType /*value*/)
|
||||
{
|
||||
updateVisible();
|
||||
}}
|
||||
, device{this, "device", "", PropertyFlags::ReadWrite | PropertyFlags::Store}
|
||||
, hostname{this, "hostname", "", PropertyFlags::ReadWrite | PropertyFlags::Store}
|
||||
, port{this, "port", 0, PropertyFlags::ReadWrite | PropertyFlags::Store}
|
||||
, cbus{this, "cbus", nullptr, PropertyFlags::ReadOnly | PropertyFlags::Store | PropertyFlags::SubObject}
|
||||
{
|
||||
name = "CBUS/VLCB";
|
||||
cbus.setValueInternal(std::make_shared<CBUSSettings>(*this, cbus.name()));
|
||||
|
||||
Attributes::addDisplayName(type, DisplayName::Interface::type);
|
||||
Attributes::addEnabled(type, !online);
|
||||
Attributes::addValues(type, CBUSInterfaceTypeValues);
|
||||
m_interfaceItems.insertBefore(type, notes);
|
||||
|
||||
Attributes::addEnabled(device, !online);
|
||||
Attributes::addVisible(device, false);
|
||||
m_interfaceItems.insertBefore(device, notes);
|
||||
|
||||
Attributes::addDisplayName(hostname, DisplayName::IP::hostname);
|
||||
Attributes::addEnabled(hostname, !online);
|
||||
Attributes::addVisible(hostname, false);
|
||||
m_interfaceItems.insertBefore(hostname, notes);
|
||||
|
||||
Attributes::addDisplayName(port, DisplayName::IP::port);
|
||||
Attributes::addEnabled(port, !online);
|
||||
Attributes::addVisible(port, false);
|
||||
m_interfaceItems.insertBefore(port, notes);
|
||||
|
||||
m_interfaceItems.insertBefore(cbus, notes);
|
||||
|
||||
m_cbusPropertyChanged = cbus->propertyChanged.connect(
|
||||
[this](BaseProperty& /*property*/)
|
||||
{
|
||||
if(m_kernel)
|
||||
{
|
||||
m_kernel->setConfig(cbus->config());
|
||||
}
|
||||
});
|
||||
|
||||
updateVisible();
|
||||
}
|
||||
|
||||
CBUSInterface::~CBUSInterface() = default;
|
||||
|
||||
void CBUSInterface::addToWorld()
|
||||
{
|
||||
Interface::addToWorld();
|
||||
}
|
||||
|
||||
void CBUSInterface::loaded()
|
||||
{
|
||||
Interface::loaded();
|
||||
|
||||
updateVisible();
|
||||
}
|
||||
|
||||
void CBUSInterface::destroying()
|
||||
{
|
||||
m_cbusPropertyChanged.disconnect();
|
||||
Interface::destroying();
|
||||
}
|
||||
|
||||
void CBUSInterface::worldEvent(WorldState state, WorldEvent event)
|
||||
{
|
||||
Interface::worldEvent(state, event);
|
||||
|
||||
switch(event)
|
||||
{
|
||||
case WorldEvent::PowerOff:
|
||||
if(m_kernel)
|
||||
{
|
||||
m_kernel->trackOff();
|
||||
}
|
||||
break;
|
||||
|
||||
case WorldEvent::PowerOn:
|
||||
if(m_kernel)
|
||||
{
|
||||
m_kernel->trackOn();
|
||||
}
|
||||
break;
|
||||
|
||||
case WorldEvent::Stop:
|
||||
if(m_kernel)
|
||||
{
|
||||
m_kernel->requestEmergencyStop();
|
||||
}
|
||||
break;
|
||||
|
||||
case WorldEvent::Run:
|
||||
if(m_kernel)
|
||||
{
|
||||
// TODO: send all known speed values
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool CBUSInterface::setOnline(bool& value, bool simulation)
|
||||
{
|
||||
if(!m_kernel && value)
|
||||
{
|
||||
try
|
||||
{
|
||||
(void)simulation; // silence warning until simulation is added
|
||||
/* TODO: simulation support
|
||||
if(simulation)
|
||||
{
|
||||
m_simulator = std::make_unique<CBUS::Simulator>();
|
||||
m_kernel = CBUS::Kernel::create<CBUS::SimulationIOHandler>(id.value(), cbus->config(), std::ref(*m_simulator));
|
||||
}
|
||||
else
|
||||
*/
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case CBUSInterfaceType::CANUSB:
|
||||
m_kernel = CBUS::Kernel::create<CBUS::CANUSBIOHandler>(id.value(), cbus->config(), device.value());
|
||||
break;
|
||||
|
||||
case CBUSInterfaceType::CANEther:
|
||||
m_kernel = CBUS::Kernel::create<CBUS::CANEtherIOHandler>(id.value(), cbus->config(), hostname.value(), port.value());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setState(InterfaceState::Initializing);
|
||||
|
||||
m_kernel->setOnStarted(
|
||||
[this]()
|
||||
{
|
||||
setState(InterfaceState::Online);
|
||||
});
|
||||
m_kernel->setOnError(
|
||||
[this]()
|
||||
{
|
||||
setState(InterfaceState::Error);
|
||||
online = false; // communication no longer possible
|
||||
});
|
||||
m_kernel->onTrackOff =
|
||||
[this]()
|
||||
{
|
||||
m_world.powerOff();
|
||||
};
|
||||
m_kernel->onTrackOn =
|
||||
[this]()
|
||||
{
|
||||
m_world.powerOn();
|
||||
};
|
||||
m_kernel->onEmergencyStop =
|
||||
[this]()
|
||||
{
|
||||
m_world.stop();
|
||||
};
|
||||
|
||||
m_kernel->start();
|
||||
}
|
||||
catch(const LogMessageException& e)
|
||||
{
|
||||
setState(InterfaceState::Offline);
|
||||
Log::log(*this, e.message(), e.args());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(m_kernel && !value)
|
||||
{
|
||||
m_kernel->stop();
|
||||
EventLoop::deleteLater(m_kernel.release());
|
||||
/*
|
||||
EventLoop::deleteLater(m_simulator.release());
|
||||
*/
|
||||
|
||||
if(status->state != InterfaceState::Error)
|
||||
{
|
||||
setState(InterfaceState::Offline);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBUSInterface::updateVisible()
|
||||
{
|
||||
const bool isSerial = (type == CBUSInterfaceType::CANUSB);
|
||||
Attributes::setVisible(device, isSerial);
|
||||
|
||||
const bool isNetwork = (type == CBUSInterfaceType::CANEther);
|
||||
Attributes::setVisible(hostname, isNetwork);
|
||||
Attributes::setVisible(port, isNetwork);
|
||||
}
|
||||
72
server/src/hardware/interface/cbusinterface.hpp
Normale Datei
72
server/src/hardware/interface/cbusinterface.hpp
Normale Datei
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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_INTERFACE_CBUSINTERFACE_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_INTERFACE_CBUSINTERFACE_HPP
|
||||
|
||||
#include "interface.hpp"
|
||||
#include "../../core/serialdeviceproperty.hpp"
|
||||
#include <traintastic/enum/cbusinterfacetype.hpp>
|
||||
|
||||
class CBUSSettings;
|
||||
|
||||
namespace CBUS {
|
||||
class Kernel;
|
||||
class Simulator {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CBUS hardware interface
|
||||
*/
|
||||
class CBUSInterface final
|
||||
: public Interface
|
||||
{
|
||||
CLASS_ID("interface.cbus")
|
||||
DEFAULT_ID("cbus")
|
||||
CREATE_DEF(CBUSInterface)
|
||||
|
||||
public:
|
||||
Property<CBUSInterfaceType> type;
|
||||
SerialDeviceProperty device;
|
||||
Property<std::string> hostname;
|
||||
Property<uint16_t> port;
|
||||
ObjectProperty<CBUSSettings> cbus;
|
||||
|
||||
CBUSInterface(World& world, std::string_view _id);
|
||||
~CBUSInterface() final;
|
||||
|
||||
protected:
|
||||
void addToWorld() final;
|
||||
void loaded() final;
|
||||
void destroying() final;
|
||||
void worldEvent(WorldState state, WorldEvent event) final;
|
||||
|
||||
bool setOnline(bool& value, bool simulation) final;
|
||||
|
||||
private:
|
||||
std::unique_ptr<CBUS::Kernel> m_kernel;
|
||||
std::unique_ptr<CBUS::Simulator> m_simulator;
|
||||
boost::signals2::connection m_cbusPropertyChanged;
|
||||
|
||||
void updateVisible();
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,9 +1,8 @@
|
||||
/**
|
||||
* server/src/hardware/interface/interfaces.cpp
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2021-2025 Reinder Feenstra
|
||||
* Copyright (C) 2021-2026 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -25,6 +24,7 @@
|
||||
#include "../../world/world.hpp"
|
||||
#include "../../utils/makearray.hpp"
|
||||
|
||||
#include "cbusinterface.hpp"
|
||||
#include "dccexinterface.hpp"
|
||||
#include "ecosinterface.hpp"
|
||||
#include "hsi88.hpp"
|
||||
@ -39,6 +39,7 @@
|
||||
std::span<const std::string_view> Interfaces::classList()
|
||||
{
|
||||
static constexpr auto classes = makeArray(
|
||||
CBUSInterface::classId,
|
||||
DCCEXInterface::classId,
|
||||
ECoSInterface::classId,
|
||||
HSI88Interface::classId,
|
||||
@ -55,6 +56,7 @@ std::span<const std::string_view> Interfaces::classList()
|
||||
|
||||
std::shared_ptr<Interface> Interfaces::create(World& world, std::string_view classId, std::string_view id)
|
||||
{
|
||||
IF_CLASSID_CREATE(CBUSInterface)
|
||||
IF_CLASSID_CREATE(DCCEXInterface)
|
||||
IF_CLASSID_CREATE(ECoSInterface)
|
||||
IF_CLASSID_CREATE(HSI88Interface)
|
||||
|
||||
168
server/src/hardware/protocol/cbus/cbusgetminorpriority.hpp
Normale Datei
168
server/src/hardware/protocol/cbus/cbusgetminorpriority.hpp
Normale Datei
@ -0,0 +1,168 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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_CBUS_CBUSGETMINORPRIORITY_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_CBUS_CBUSGETMINORPRIORITY_HPP
|
||||
|
||||
#include "cbusopcode.hpp"
|
||||
#include "cbuspriority.hpp"
|
||||
|
||||
namespace CBUS {
|
||||
|
||||
constexpr MinorPriority getMinorPriority(OpCode opCode)
|
||||
{
|
||||
switch(opCode)
|
||||
{
|
||||
using enum OpCode;
|
||||
|
||||
case HLT:
|
||||
case ARST:
|
||||
case RESTP:
|
||||
return MinorPriority::High;
|
||||
|
||||
case BON:
|
||||
case TOF:
|
||||
case TON:
|
||||
case ESTOP:
|
||||
case RTOF:
|
||||
case RTON:
|
||||
return MinorPriority::AboveNormal;
|
||||
|
||||
case ACK:
|
||||
case NAK:
|
||||
case RSTAT:
|
||||
case RQMN:
|
||||
case KLOC:
|
||||
case QLOC:
|
||||
case DKEEP:
|
||||
case DBG1:
|
||||
case RLOC:
|
||||
case QCON:
|
||||
case ALOC:
|
||||
case STMOD:
|
||||
case PCON:
|
||||
case KCON:
|
||||
case DSPD:
|
||||
case DFLG:
|
||||
case DFNON:
|
||||
case DFNOF:
|
||||
case DFUN:
|
||||
case GLOC:
|
||||
case ERR:
|
||||
case RDCC3:
|
||||
case WCVO:
|
||||
case WCVB:
|
||||
case QCVS:
|
||||
case PCVS:
|
||||
case RDCC4:
|
||||
case WCVS:
|
||||
case RDCC5:
|
||||
case WCVOA:
|
||||
case CABDAT:
|
||||
case FCLK:
|
||||
case RDCC6:
|
||||
case PLOC:
|
||||
case STAT:
|
||||
return MinorPriority::Normal;
|
||||
|
||||
case QNN:
|
||||
case RQNP:
|
||||
case EXTC:
|
||||
case SNN:
|
||||
case SSTAT:
|
||||
case NNRSM:
|
||||
case RQNN:
|
||||
case NNREL:
|
||||
case NNACK:
|
||||
case NNLRN:
|
||||
case NNULN:
|
||||
case NNCLR:
|
||||
case NNEVN:
|
||||
case NERD:
|
||||
case RQEVN:
|
||||
case WRACK:
|
||||
case RQDAT:
|
||||
case RQDDS:
|
||||
case BOOTM:
|
||||
case ENUM:
|
||||
case NNRST:
|
||||
case EXTC1:
|
||||
case CMDERR:
|
||||
case EVNLF:
|
||||
case NVRD:
|
||||
case NENRD:
|
||||
case RQNPN:
|
||||
case NUMEV:
|
||||
case CANID:
|
||||
case EXTC2:
|
||||
case ACON:
|
||||
case ACOF:
|
||||
case AREQ:
|
||||
case ARON:
|
||||
case AROF:
|
||||
case EVULN:
|
||||
case NVSET:
|
||||
case NVANS:
|
||||
case ASON:
|
||||
case ASOF:
|
||||
case ASRQ:
|
||||
case PARAN:
|
||||
case REVAL:
|
||||
case ARSON:
|
||||
case ARSOF:
|
||||
case EXTC3:
|
||||
case ACON1:
|
||||
case ACOF1:
|
||||
case REQEV:
|
||||
case ARON1:
|
||||
case AROF1:
|
||||
case NEVAL:
|
||||
case PNN:
|
||||
case ASON1:
|
||||
case ASOF1:
|
||||
case ARSON1:
|
||||
case ARSOF1:
|
||||
case EXTC4:
|
||||
case NAME:
|
||||
case PARAMS:
|
||||
case ACON3:
|
||||
case ACOF3:
|
||||
case ENRSP:
|
||||
case ARON3:
|
||||
case AROF3:
|
||||
case EVLRNI:
|
||||
case ACDAT:
|
||||
case ARDAT:
|
||||
case ASON3:
|
||||
case ASOF3:
|
||||
case DDES:
|
||||
case DDRS:
|
||||
case ARSON3:
|
||||
case ARSOF3:
|
||||
case EXTC6:
|
||||
return MinorPriority::Low;
|
||||
}
|
||||
return MinorPriority::Low;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
221
server/src/hardware/protocol/cbus/cbuskernel.cpp
Normale Datei
221
server/src/hardware/protocol/cbus/cbuskernel.cpp
Normale Datei
@ -0,0 +1,221 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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 "cbuskernel.hpp"
|
||||
#include "cbusmessages.hpp"
|
||||
#include "cbustostring.hpp"
|
||||
/*
|
||||
#include "simulator/cbussimulator.hpp"
|
||||
*/
|
||||
#include "../../../core/eventloop.hpp"
|
||||
#include "../../../log/log.hpp"
|
||||
#include "../../../log/logmessageexception.hpp"
|
||||
#include "../../../utils/setthreadname.hpp"
|
||||
|
||||
namespace CBUS {
|
||||
|
||||
Kernel::Kernel(std::string logId_, const Config& config, bool simulation)
|
||||
: KernelBase(std::move(logId_))
|
||||
, m_simulation{simulation}
|
||||
, m_config{config}
|
||||
{
|
||||
assert(isEventLoopThread());
|
||||
}
|
||||
|
||||
void Kernel::setConfig(const Config& config)
|
||||
{
|
||||
assert(isEventLoopThread());
|
||||
|
||||
m_ioContext.post(
|
||||
[this, newConfig=config]()
|
||||
{
|
||||
m_config = newConfig;
|
||||
});
|
||||
}
|
||||
|
||||
void Kernel::start()
|
||||
{
|
||||
assert(isEventLoopThread());
|
||||
assert(m_ioHandler);
|
||||
|
||||
m_thread = std::thread(
|
||||
[this]()
|
||||
{
|
||||
setThreadName("cbus");
|
||||
auto work = std::make_shared<boost::asio::io_context::work>(m_ioContext);
|
||||
m_ioContext.run();
|
||||
});
|
||||
|
||||
m_ioContext.post(
|
||||
[this]()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_ioHandler->start();
|
||||
}
|
||||
catch(const LogMessageException& e)
|
||||
{
|
||||
EventLoop::call(
|
||||
[this, e]()
|
||||
{
|
||||
Log::log(logId, e.message(), e.args());
|
||||
error();
|
||||
});
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Kernel::stop()
|
||||
{
|
||||
assert(isEventLoopThread());
|
||||
|
||||
m_ioContext.post(
|
||||
[this]()
|
||||
{
|
||||
m_ioHandler->stop();
|
||||
});
|
||||
|
||||
m_ioContext.stop();
|
||||
|
||||
m_thread.join();
|
||||
}
|
||||
|
||||
void Kernel::started()
|
||||
{
|
||||
assert(isKernelThread());
|
||||
|
||||
send(RequestCommandStationStatus());
|
||||
send(QueryNodeNumber());
|
||||
|
||||
::KernelBase::started();
|
||||
}
|
||||
|
||||
void Kernel::receive(uint8_t /*canId*/, const Message& message)
|
||||
{
|
||||
assert(isKernelThread());
|
||||
|
||||
if(m_config.debugLogRXTX)
|
||||
{
|
||||
EventLoop::call(
|
||||
[this, msg=toString(message)]()
|
||||
{
|
||||
Log::log(logId, LogMessage::D2002_RX_X, msg);
|
||||
});
|
||||
}
|
||||
|
||||
switch(message.opCode)
|
||||
{
|
||||
case OpCode::TOF:
|
||||
m_trackOn = false;
|
||||
if(onTrackOff) [[likely]]
|
||||
{
|
||||
EventLoop::call(onTrackOff);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpCode::TON:
|
||||
m_trackOn = true;
|
||||
if(onTrackOn) [[likely]]
|
||||
{
|
||||
EventLoop::call(onTrackOn);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpCode::ESTOP:
|
||||
if(onEmergencyStop) [[likely]]
|
||||
{
|
||||
EventLoop::call(onEmergencyStop);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Kernel::trackOff()
|
||||
{
|
||||
assert(isEventLoopThread());
|
||||
|
||||
m_ioContext.post(
|
||||
[this]()
|
||||
{
|
||||
if(m_trackOn)
|
||||
{
|
||||
send(RequestTrackOff());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Kernel::trackOn()
|
||||
{
|
||||
assert(isEventLoopThread());
|
||||
|
||||
m_ioContext.post(
|
||||
[this]()
|
||||
{
|
||||
if(!m_trackOn)
|
||||
{
|
||||
send(RequestTrackOn());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Kernel::requestEmergencyStop()
|
||||
{
|
||||
assert(isEventLoopThread());
|
||||
|
||||
m_ioContext.post(
|
||||
[this]()
|
||||
{
|
||||
send(RequestEmergencyStop());
|
||||
});
|
||||
}
|
||||
|
||||
void Kernel::setIOHandler(std::unique_ptr<IOHandler> handler)
|
||||
{
|
||||
assert(isEventLoopThread());
|
||||
assert(handler);
|
||||
assert(!m_ioHandler);
|
||||
m_ioHandler = std::move(handler);
|
||||
}
|
||||
|
||||
void Kernel::send(const Message& message)
|
||||
{
|
||||
assert(isKernelThread());
|
||||
|
||||
if(m_config.debugLogRXTX)
|
||||
{
|
||||
EventLoop::call(
|
||||
[this, msg=toString(message)]()
|
||||
{
|
||||
Log::log(logId, LogMessage::D2001_TX_X, msg);
|
||||
});
|
||||
}
|
||||
|
||||
if(auto ec = m_ioHandler->send(message); ec)
|
||||
{
|
||||
(void)ec; // FIXME: handle error
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
110
server/src/hardware/protocol/cbus/cbuskernel.hpp
Normale Datei
110
server/src/hardware/protocol/cbus/cbuskernel.hpp
Normale Datei
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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_CBUS_CBUSKERNEL_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_CBUS_CBUSKERNEL_HPP
|
||||
|
||||
#include "../kernelbase.hpp"
|
||||
#include <span>
|
||||
#include <traintastic/enum/direction.hpp>
|
||||
#include "cbusconfig.hpp"
|
||||
#include "iohandler/cbusiohandler.hpp"
|
||||
|
||||
namespace CBUS {
|
||||
|
||||
class Kernel : public ::KernelBase
|
||||
{
|
||||
public:
|
||||
std::function<void()> onTrackOff;
|
||||
std::function<void()> onTrackOn;
|
||||
std::function<void()> onEmergencyStop;
|
||||
|
||||
/**
|
||||
* @brief Create kernel and IO handler
|
||||
*
|
||||
* @param[in] config CBUS configuration
|
||||
* @param[in] args IO handler arguments
|
||||
* @return The kernel instance
|
||||
*/
|
||||
template<class IOHandlerType, class... Args>
|
||||
static std::unique_ptr<Kernel> create(std::string logId_, const Config& config, Args... args)
|
||||
{
|
||||
static_assert(std::is_base_of_v<IOHandler, IOHandlerType>);
|
||||
std::unique_ptr<Kernel> kernel{new Kernel(std::move(logId_), config, isSimulation<IOHandlerType>())};
|
||||
kernel->setIOHandler(std::make_unique<IOHandlerType>(*kernel, std::forward<Args>(args)...));
|
||||
return kernel;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool isKernelThread() const
|
||||
{
|
||||
return std::this_thread::get_id() == m_thread.get_id();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set CBUS configuration
|
||||
*
|
||||
* @param[in] config The CBUS configuration
|
||||
*/
|
||||
void setConfig(const Config& config);
|
||||
|
||||
/**
|
||||
* @brief Start the kernel and IO handler
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* @brief Stop the kernel and IO handler
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* \brief Notify kernel the IO handler is started.
|
||||
* \note This function must run in the kernel's IO context
|
||||
*/
|
||||
void started() final;
|
||||
|
||||
void receive(uint8_t canId, const Message& message);
|
||||
|
||||
void trackOff();
|
||||
void trackOn();
|
||||
void requestEmergencyStop();
|
||||
|
||||
private:
|
||||
std::unique_ptr<IOHandler> m_ioHandler;
|
||||
const bool m_simulation;
|
||||
Config m_config;
|
||||
bool m_trackOn = false;
|
||||
|
||||
Kernel(std::string logId_, const Config& config, bool simulation);
|
||||
|
||||
Kernel(const Kernel&) = delete;
|
||||
Kernel& operator =(const Kernel&) = delete;
|
||||
|
||||
void setIOHandler(std::unique_ptr<IOHandler> handler);
|
||||
|
||||
void send(const Message& message);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -167,6 +167,11 @@ enum class OpCode : uint8_t
|
||||
EXTC6 = 0xFF, //!< Extended op-code with 6 data bytes
|
||||
};
|
||||
|
||||
constexpr uint8_t dataSize(OpCode opc)
|
||||
{
|
||||
return static_cast<uint8_t>(opc) >> 5; // highest 3 bits determine data length
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
46
server/src/hardware/protocol/cbus/cbuspriority.hpp
Normale Datei
46
server/src/hardware/protocol/cbus/cbuspriority.hpp
Normale Datei
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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_CBUS_CBUSPRIORITY_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_CBUS_CBUSPRIORITY_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace CBUS {
|
||||
|
||||
enum class MajorPriority : uint8_t
|
||||
{
|
||||
Highest = 0b00,
|
||||
Next = 0b01,
|
||||
Lowest = 0b10,
|
||||
};
|
||||
|
||||
enum class MinorPriority : uint8_t
|
||||
{
|
||||
High = 0b00,
|
||||
AboveNormal = 0b01,
|
||||
Normal = 0b10,
|
||||
Low = 0b11,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
381
server/src/hardware/protocol/cbus/cbustostring.cpp
Normale Datei
381
server/src/hardware/protocol/cbus/cbustostring.cpp
Normale Datei
@ -0,0 +1,381 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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 "cbustostring.hpp"
|
||||
#include <format>
|
||||
#include "cbusmessages.hpp"
|
||||
#include "../../../utils/tohex.hpp"
|
||||
|
||||
namespace CBUS {
|
||||
|
||||
std::string toString(const Message& message)
|
||||
{
|
||||
std::string s(toString(message.opCode));
|
||||
|
||||
switch (message.opCode)
|
||||
{
|
||||
using enum OpCode;
|
||||
|
||||
// 00-1F – 0 data byte packets:
|
||||
case ACK:
|
||||
case NAK:
|
||||
case HLT:
|
||||
case BON:
|
||||
case TOF:
|
||||
case TON:
|
||||
case ESTOP:
|
||||
case ARST:
|
||||
case RTOF:
|
||||
case RTON:
|
||||
case RESTP:
|
||||
case RSTAT:
|
||||
case QNN:
|
||||
case RQNP:
|
||||
case RQMN:
|
||||
break; // no data
|
||||
|
||||
// 20–3F - 1 data byte packets:
|
||||
case KLOC:
|
||||
case QLOC:
|
||||
case DKEEP:
|
||||
{
|
||||
const auto& m = static_cast<const EngineMessage&>(message);
|
||||
s.append(std::format(" session={}", m.session));
|
||||
break;
|
||||
}
|
||||
case DBG1:
|
||||
break;
|
||||
|
||||
case EXTC:
|
||||
break;
|
||||
|
||||
// 40–5F - 2 data byte packets:
|
||||
case RLOC:
|
||||
break;
|
||||
|
||||
case QCON:
|
||||
break;
|
||||
|
||||
case SNN:
|
||||
break;
|
||||
|
||||
case ALOC:
|
||||
break;
|
||||
|
||||
case STMOD:
|
||||
break;
|
||||
|
||||
case PCON:
|
||||
break;
|
||||
|
||||
case KCON:
|
||||
break;
|
||||
|
||||
case DSPD:
|
||||
break;
|
||||
|
||||
case DFLG:
|
||||
break;
|
||||
|
||||
case DFNON:
|
||||
break;
|
||||
|
||||
case DFNOF:
|
||||
break;
|
||||
|
||||
case SSTAT:
|
||||
break;
|
||||
|
||||
case NNRSM:
|
||||
break;
|
||||
|
||||
case RQNN:
|
||||
break;
|
||||
|
||||
case NNREL:
|
||||
break;
|
||||
|
||||
case NNACK:
|
||||
break;
|
||||
|
||||
case NNLRN:
|
||||
break;
|
||||
|
||||
case NNULN:
|
||||
break;
|
||||
|
||||
case NNCLR:
|
||||
break;
|
||||
|
||||
case NNEVN:
|
||||
break;
|
||||
|
||||
case NERD:
|
||||
break;
|
||||
|
||||
case RQEVN:
|
||||
break;
|
||||
|
||||
case WRACK:
|
||||
break;
|
||||
|
||||
case RQDAT:
|
||||
break;
|
||||
|
||||
case RQDDS:
|
||||
break;
|
||||
|
||||
case BOOTM:
|
||||
break;
|
||||
|
||||
case ENUM:
|
||||
break;
|
||||
|
||||
case NNRST:
|
||||
break;
|
||||
|
||||
case EXTC1:
|
||||
break;
|
||||
|
||||
// 60-7F - 3 data byte packets:
|
||||
case DFUN:
|
||||
break;
|
||||
|
||||
case GLOC:
|
||||
break;
|
||||
|
||||
case ERR:
|
||||
break;
|
||||
|
||||
case CMDERR:
|
||||
break;
|
||||
|
||||
case EVNLF:
|
||||
break;
|
||||
|
||||
case NVRD:
|
||||
break;
|
||||
|
||||
case NENRD:
|
||||
break;
|
||||
|
||||
case RQNPN:
|
||||
break;
|
||||
|
||||
case NUMEV:
|
||||
break;
|
||||
|
||||
case CANID:
|
||||
break;
|
||||
|
||||
case EXTC2:
|
||||
break;
|
||||
|
||||
// 80-9F - 4 data byte packets:
|
||||
case RDCC3:
|
||||
break;
|
||||
|
||||
case WCVO:
|
||||
break;
|
||||
|
||||
case WCVB:
|
||||
break;
|
||||
|
||||
case QCVS:
|
||||
break;
|
||||
|
||||
case PCVS:
|
||||
break;
|
||||
|
||||
case ACON:
|
||||
break;
|
||||
|
||||
case ACOF:
|
||||
break;
|
||||
|
||||
case AREQ:
|
||||
break;
|
||||
|
||||
case ARON:
|
||||
break;
|
||||
|
||||
case AROF:
|
||||
break;
|
||||
|
||||
case EVULN:
|
||||
break;
|
||||
|
||||
case NVSET:
|
||||
break;
|
||||
|
||||
case NVANS:
|
||||
break;
|
||||
|
||||
case ASON:
|
||||
break;
|
||||
|
||||
case ASOF:
|
||||
break;
|
||||
|
||||
case ASRQ:
|
||||
break;
|
||||
|
||||
case PARAN:
|
||||
break;
|
||||
|
||||
case REVAL:
|
||||
break;
|
||||
|
||||
case ARSON:
|
||||
break;
|
||||
|
||||
case ARSOF:
|
||||
break;
|
||||
|
||||
case EXTC3:
|
||||
break;
|
||||
|
||||
// A0-BF - 5 data byte packets:
|
||||
case RDCC4:
|
||||
break;
|
||||
|
||||
case WCVS:
|
||||
break;
|
||||
|
||||
case ACON1:
|
||||
break;
|
||||
|
||||
case ACOF1:
|
||||
break;
|
||||
|
||||
case REQEV:
|
||||
break;
|
||||
|
||||
case ARON1:
|
||||
break;
|
||||
|
||||
case AROF1:
|
||||
break;
|
||||
|
||||
case NEVAL:
|
||||
break;
|
||||
|
||||
case PNN:
|
||||
break;
|
||||
|
||||
case ASON1:
|
||||
break;
|
||||
|
||||
case ASOF1:
|
||||
break;
|
||||
|
||||
case ARSON1:
|
||||
break;
|
||||
|
||||
case ARSOF1:
|
||||
break;
|
||||
|
||||
case EXTC4:
|
||||
break;
|
||||
|
||||
// C0-DF - 6 data byte packets:
|
||||
case RDCC5:
|
||||
break;
|
||||
|
||||
case WCVOA:
|
||||
break;
|
||||
|
||||
case CABDAT:
|
||||
break;
|
||||
|
||||
case FCLK:
|
||||
break;
|
||||
|
||||
// E0-FF - 7 data byte packets:
|
||||
case RDCC6:
|
||||
break;
|
||||
|
||||
case PLOC:
|
||||
break;
|
||||
|
||||
case NAME:
|
||||
break;
|
||||
|
||||
case STAT:
|
||||
break;
|
||||
|
||||
case PARAMS:
|
||||
break;
|
||||
|
||||
case ACON3:
|
||||
break;
|
||||
|
||||
case ACOF3:
|
||||
break;
|
||||
|
||||
case ENRSP:
|
||||
break;
|
||||
|
||||
case ARON3:
|
||||
break;
|
||||
|
||||
case AROF3:
|
||||
break;
|
||||
|
||||
case EVLRNI:
|
||||
break;
|
||||
|
||||
case ACDAT:
|
||||
break;
|
||||
|
||||
case ARDAT:
|
||||
break;
|
||||
|
||||
case ASON3:
|
||||
break;
|
||||
|
||||
case ASOF3:
|
||||
break;
|
||||
|
||||
case DDES:
|
||||
break;
|
||||
|
||||
case DDRS:
|
||||
break;
|
||||
|
||||
case ARSON3:
|
||||
break;
|
||||
|
||||
case ARSOF3:
|
||||
break;
|
||||
|
||||
case EXTC6:
|
||||
break;
|
||||
}
|
||||
|
||||
s.append(" [");
|
||||
s.append(toHex(&message, message.size()));
|
||||
s.append("]");
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
@ -27,13 +27,15 @@
|
||||
|
||||
namespace CBUS {
|
||||
|
||||
struct Message;
|
||||
|
||||
constexpr std::string_view toString(OpCode opCode)
|
||||
{
|
||||
switch(opCode)
|
||||
{
|
||||
using enum OpCode;
|
||||
|
||||
// 00-1F – 0 data bytes packets:
|
||||
// 00-1F – 0 data byte packets:
|
||||
case ACK: return "ACK";
|
||||
case NAK: return "NAK";
|
||||
case HLT: return "HLT";
|
||||
@ -171,6 +173,8 @@ constexpr std::string_view toString(OpCode opCode)
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string toString(const Message& message);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
165
server/src/hardware/protocol/cbus/iohandler/cbusasciiiohandler.cpp
Normale Datei
165
server/src/hardware/protocol/cbus/iohandler/cbusasciiiohandler.cpp
Normale Datei
@ -0,0 +1,165 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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 "cbusasciiiohandler.hpp"
|
||||
#include "../cbusgetminorpriority.hpp"
|
||||
#include "../cbuskernel.hpp"
|
||||
#include "../messages/cbusmessage.hpp"
|
||||
#include "../../../../core/eventloop.hpp"
|
||||
#include "../../../../log/log.hpp"
|
||||
#include "../../../../utils/tohex.hpp"
|
||||
#include "../../../../utils/fromchars.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
std::string buildFrame(CBUS::MajorPriority majorPriority, CBUS::MinorPriority minorPriority, uint8_t canId, const CBUS::Message& message)
|
||||
{
|
||||
const uint16_t sid =
|
||||
(static_cast<uint16_t>(majorPriority) << 14) |
|
||||
(static_cast<uint16_t>(minorPriority) << 12) |
|
||||
(static_cast<uint16_t>(canId) << 5);
|
||||
|
||||
std::string frame(":S");
|
||||
frame.append(toHex(sid));
|
||||
frame.append("N");
|
||||
frame.append(toHex(&message, message.size()));
|
||||
frame.append(";");
|
||||
return frame;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace CBUS {
|
||||
|
||||
ASCIIIOHandler::ASCIIIOHandler(Kernel& kernel, uint8_t canId)
|
||||
: IOHandler(kernel, canId)
|
||||
{
|
||||
}
|
||||
|
||||
std::error_code ASCIIIOHandler::send(const Message& message)
|
||||
{
|
||||
const bool wasEmpty = m_writeQueue.empty();
|
||||
|
||||
// FIXME: handle priority queueing
|
||||
// FIXME: what to do with MajorPriority?
|
||||
m_writeQueue.emplace(buildFrame(MajorPriority::Lowest, getMinorPriority(message.opCode), m_canId, message));
|
||||
|
||||
if(wasEmpty)
|
||||
{
|
||||
write();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void ASCIIIOHandler::logDropIfNonZeroAndReset(size_t& drop)
|
||||
{
|
||||
if(drop != 0)
|
||||
{
|
||||
EventLoop::call(
|
||||
[this, drop]()
|
||||
{
|
||||
Log::log(m_kernel.logId, LogMessage::W2001_RECEIVED_MALFORMED_DATA_DROPPED_X_BYTES, drop);
|
||||
});
|
||||
drop = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ASCIIIOHandler::processRead(std::size_t bytesTransferred)
|
||||
{
|
||||
constexpr size_t maxFrameSize = 24; // :SXXXXNXXXXXXXXXXXXXXXX;
|
||||
|
||||
std::string_view buffer{m_readBuffer.data(), m_readBufferOffset + bytesTransferred};
|
||||
|
||||
size_t drop = 0;
|
||||
|
||||
while(!buffer.empty())
|
||||
{
|
||||
logDropIfNonZeroAndReset(drop);
|
||||
|
||||
if(auto pos = buffer.find(':'); pos != 0)
|
||||
{
|
||||
if(pos == std::string_view::npos)
|
||||
{
|
||||
// no start marker drop all bytes:
|
||||
drop += buffer.size();
|
||||
buffer = {};
|
||||
break;
|
||||
}
|
||||
|
||||
// drop bytes before start marker:
|
||||
drop += pos;
|
||||
buffer.remove_prefix(pos);
|
||||
}
|
||||
|
||||
auto end = buffer.find(';');
|
||||
if(end == std::string_view::npos)
|
||||
{
|
||||
// no end marker yet, wait for more data
|
||||
break;
|
||||
}
|
||||
|
||||
std::string_view frame{buffer.data(), end + 1};
|
||||
|
||||
buffer.remove_prefix(frame.size()); // consume frame
|
||||
|
||||
if(frame.size() > maxFrameSize)
|
||||
{
|
||||
drop += frame.size();
|
||||
}
|
||||
else if(frame[1] == 'S' && frame[6] == 'N') // CBUS only uses standard non RTR CAN frames
|
||||
{
|
||||
uint16_t sid;
|
||||
if(fromChars(frame.substr(2, sizeof(sid) * 2), sid, 16).ec != std::errc())
|
||||
{
|
||||
continue; // error reading, ignore frame
|
||||
}
|
||||
|
||||
const auto dataLength = (frame.size() - 7) / 2;
|
||||
std::array<uint8_t, 8> data;
|
||||
std::errc ec = std::errc();
|
||||
for(size_t i = 0; i < dataLength; ++i)
|
||||
{
|
||||
ec = fromChars(frame.substr(7 + i * 2, 2), data[i], 16).ec;
|
||||
if(ec != std::errc())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(ec != std::errc())
|
||||
{
|
||||
continue; // error reading, ignore frame
|
||||
}
|
||||
|
||||
m_kernel.receive((sid >> 5) & 0x7F, *reinterpret_cast<const Message*>(data.data()));
|
||||
}
|
||||
}
|
||||
|
||||
logDropIfNonZeroAndReset(drop);
|
||||
|
||||
if(buffer.size() != 0)
|
||||
{
|
||||
memmove(m_readBuffer.data(), buffer.data(), buffer.size());
|
||||
}
|
||||
m_readBufferOffset = buffer.size();
|
||||
}
|
||||
|
||||
}
|
||||
53
server/src/hardware/protocol/cbus/iohandler/cbusasciiiohandler.hpp
Normale Datei
53
server/src/hardware/protocol/cbus/iohandler/cbusasciiiohandler.hpp
Normale Datei
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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_CBUS_IOHANDLER_CBUSASCIIIOHANDLER_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_CBUS_IOHANDLER_CBUSASCIIIOHANDLER_HPP
|
||||
|
||||
#include "cbusiohandler.hpp"
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
|
||||
namespace CBUS {
|
||||
|
||||
class ASCIIIOHandler : public IOHandler
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] std::error_code send(const Message& message) override;
|
||||
|
||||
protected:
|
||||
std::array<char, 1024> m_readBuffer;
|
||||
size_t m_readBufferOffset;
|
||||
std::queue<std::string> m_writeQueue;
|
||||
|
||||
ASCIIIOHandler(Kernel& kernel, uint8_t canId);
|
||||
|
||||
void logDropIfNonZeroAndReset(size_t& drop);
|
||||
void processRead(std::size_t bytesTransferred);
|
||||
|
||||
virtual void read() = 0;
|
||||
virtual void write() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
135
server/src/hardware/protocol/cbus/iohandler/cbuscanetheriohandler.cpp
Normale Datei
135
server/src/hardware/protocol/cbus/iohandler/cbuscanetheriohandler.cpp
Normale Datei
@ -0,0 +1,135 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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 "cbuscanetheriohandler.hpp"
|
||||
#include <boost/asio/write.hpp>
|
||||
#include "../cbuskernel.hpp"
|
||||
#include "../../../../core/eventloop.hpp"
|
||||
#include "../../../../log/log.hpp"
|
||||
#include "../../../../log/logmessageexception.hpp"
|
||||
|
||||
namespace CBUS {
|
||||
|
||||
CANEtherIOHandler::CANEtherIOHandler(Kernel& kernel, std::string hostname, uint16_t port)
|
||||
: ASCIIIOHandler(kernel, canId)
|
||||
, m_hostname{std::move(hostname)}
|
||||
, m_port{port}
|
||||
, m_socket{m_kernel.ioContext()}
|
||||
{
|
||||
}
|
||||
|
||||
void CANEtherIOHandler::start()
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
m_endpoint.port(m_port);
|
||||
m_endpoint.address(boost::asio::ip::make_address(m_hostname, ec));
|
||||
if(ec)
|
||||
{
|
||||
throw LogMessageException(LogMessage::E2003_MAKE_ADDRESS_FAILED_X, ec);
|
||||
}
|
||||
|
||||
m_socket.async_connect(m_endpoint,
|
||||
[this](const boost::system::error_code& err)
|
||||
{
|
||||
if(!err)
|
||||
{
|
||||
m_socket.set_option(boost::asio::socket_base::linger(true, 0));
|
||||
m_socket.set_option(boost::asio::ip::tcp::no_delay(true));
|
||||
|
||||
m_connected = true;
|
||||
|
||||
read();
|
||||
write();
|
||||
|
||||
m_kernel.started();
|
||||
}
|
||||
else if(err != boost::asio::error::operation_aborted)
|
||||
{
|
||||
EventLoop::call(
|
||||
[this, err]()
|
||||
{
|
||||
Log::log(m_kernel.logId, LogMessage::E2005_SOCKET_CONNECT_FAILED_X, err);
|
||||
m_kernel.error();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CANEtherIOHandler::stop()
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
m_socket.cancel(ec);
|
||||
m_socket.close(ec);
|
||||
// ignore errors
|
||||
m_connected = false;
|
||||
}
|
||||
|
||||
void CANEtherIOHandler::read()
|
||||
{
|
||||
m_socket.async_read_some(boost::asio::buffer(m_readBuffer.data() + m_readBufferOffset, m_readBuffer.size() - m_readBufferOffset),
|
||||
[this](const boost::system::error_code& ec, std::size_t bytesTransferred)
|
||||
{
|
||||
if(!ec)
|
||||
{
|
||||
processRead(bytesTransferred);
|
||||
read();
|
||||
}
|
||||
else if(ec != boost::asio::error::operation_aborted)
|
||||
{
|
||||
EventLoop::call(
|
||||
[this, ec]()
|
||||
{
|
||||
Log::log(m_kernel.logId, LogMessage::E1007_SOCKET_READ_FAILED_X, ec);
|
||||
m_kernel.error();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CANEtherIOHandler::write()
|
||||
{
|
||||
assert(!m_writeQueue.empty());
|
||||
const auto& message = m_writeQueue.front();
|
||||
boost::asio::async_write(m_socket, boost::asio::buffer(message.data(), message.size()),
|
||||
[this](const boost::system::error_code& ec, std::size_t /*bytesTransferred*/)
|
||||
{
|
||||
if(!ec)
|
||||
{
|
||||
m_writeQueue.pop();
|
||||
if(!m_writeQueue.empty())
|
||||
{
|
||||
write();
|
||||
}
|
||||
}
|
||||
else if(ec != boost::asio::error::operation_aborted)
|
||||
{
|
||||
EventLoop::call(
|
||||
[this, ec]()
|
||||
{
|
||||
Log::log(m_kernel.logId, LogMessage::E1006_SOCKET_WRITE_FAILED_X, ec);
|
||||
m_kernel.error();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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_CBUS_IOHANDLER_CBUSCANETHERIOHANDLER_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_CBUS_IOHANDLER_CBUSCANETHERIOHANDLER_HPP
|
||||
|
||||
#include "cbusasciiiohandler.hpp"
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
||||
namespace CBUS {
|
||||
|
||||
class CANEtherIOHandler final : public ASCIIIOHandler
|
||||
{
|
||||
public:
|
||||
CANEtherIOHandler(Kernel& kernel, std::string hostname, uint16_t port);
|
||||
|
||||
void start() final;
|
||||
void stop() final;
|
||||
|
||||
protected:
|
||||
void read() final;
|
||||
void write() final;
|
||||
|
||||
private:
|
||||
static constexpr uint8_t canId = 0x7D; //!< CANEther fixed CAN_ID
|
||||
|
||||
const std::string m_hostname;
|
||||
const uint16_t m_port;
|
||||
boost::asio::ip::tcp::socket m_socket;
|
||||
boost::asio::ip::tcp::endpoint m_endpoint;
|
||||
bool m_connected = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
109
server/src/hardware/protocol/cbus/iohandler/cbuscanusbiohandler.cpp
Normale Datei
109
server/src/hardware/protocol/cbus/iohandler/cbuscanusbiohandler.cpp
Normale Datei
@ -0,0 +1,109 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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 "cbuscanusbiohandler.hpp"
|
||||
#include <boost/asio/write.hpp>
|
||||
#include "../cbuskernel.hpp"
|
||||
#include "../../../../core/eventloop.hpp"
|
||||
#include "../../../../log/log.hpp"
|
||||
#include "../../../../utils/serialport.hpp"
|
||||
|
||||
namespace CBUS {
|
||||
|
||||
CANUSBIOHandler::CANUSBIOHandler(Kernel& kernel, const std::string& device)
|
||||
: ASCIIIOHandler(kernel, canId)
|
||||
, m_serialPort{m_kernel.ioContext()}
|
||||
{
|
||||
// FIXME: check serial settings, just a guess, if more settings are needed add them to the interface
|
||||
SerialPort::open(m_serialPort, device, 115'200, 8, SerialParity::None, SerialStopBits::One, SerialFlowControl::None);
|
||||
}
|
||||
|
||||
CANUSBIOHandler::~CANUSBIOHandler()
|
||||
{
|
||||
if(m_serialPort.is_open())
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
m_serialPort.close(ec);
|
||||
// ignore the error
|
||||
}
|
||||
}
|
||||
|
||||
void CANUSBIOHandler::start()
|
||||
{
|
||||
read();
|
||||
m_kernel.started();
|
||||
}
|
||||
|
||||
void CANUSBIOHandler::stop()
|
||||
{
|
||||
m_serialPort.close();
|
||||
}
|
||||
|
||||
void CANUSBIOHandler::read()
|
||||
{
|
||||
m_serialPort.async_read_some(boost::asio::buffer(m_readBuffer.data() + m_readBufferOffset, m_readBuffer.size() - m_readBufferOffset),
|
||||
[this](const boost::system::error_code& ec, std::size_t bytesTransferred)
|
||||
{
|
||||
if(!ec)
|
||||
{
|
||||
processRead(bytesTransferred);
|
||||
read();
|
||||
}
|
||||
else if(ec != boost::asio::error::operation_aborted)
|
||||
{
|
||||
EventLoop::call(
|
||||
[this, ec]()
|
||||
{
|
||||
Log::log(m_kernel.logId, LogMessage::E2002_SERIAL_READ_FAILED_X, ec);
|
||||
m_kernel.error();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CANUSBIOHandler::write()
|
||||
{
|
||||
assert(!m_writeQueue.empty());
|
||||
const auto& message = m_writeQueue.front();
|
||||
boost::asio::async_write(m_serialPort, boost::asio::buffer(message.data(), message.size()),
|
||||
[this](const boost::system::error_code& ec, std::size_t /*bytesTransferred*/)
|
||||
{
|
||||
if(!ec)
|
||||
{
|
||||
m_writeQueue.pop();
|
||||
if(!m_writeQueue.empty())
|
||||
{
|
||||
write();
|
||||
}
|
||||
}
|
||||
else if(ec != boost::asio::error::operation_aborted)
|
||||
{
|
||||
EventLoop::call(
|
||||
[this, ec]()
|
||||
{
|
||||
Log::log(m_kernel.logId, LogMessage::E2001_SERIAL_WRITE_FAILED_X, ec);
|
||||
m_kernel.error();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
51
server/src/hardware/protocol/cbus/iohandler/cbuscanusbiohandler.hpp
Normale Datei
51
server/src/hardware/protocol/cbus/iohandler/cbuscanusbiohandler.hpp
Normale Datei
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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_CBUS_IOHANDLER_CBUSCANUSBIOHANDLER_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_CBUS_IOHANDLER_CBUSCANUSBIOHANDLER_HPP
|
||||
|
||||
#include "cbusasciiiohandler.hpp"
|
||||
#include <boost/asio/serial_port.hpp>
|
||||
|
||||
namespace CBUS {
|
||||
|
||||
class CANUSBIOHandler final : public ASCIIIOHandler
|
||||
{
|
||||
public:
|
||||
CANUSBIOHandler(Kernel& kernel, const std::string& device);
|
||||
~CANUSBIOHandler() final;
|
||||
|
||||
void start() final;
|
||||
void stop() final;
|
||||
|
||||
protected:
|
||||
void read() final;
|
||||
void write() final;
|
||||
|
||||
private:
|
||||
static constexpr uint8_t canId = 0x7C; //!< CANUSB fixed CAN_ID
|
||||
|
||||
boost::asio::serial_port m_serialPort;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
32
server/src/hardware/protocol/cbus/iohandler/cbusiohandler.cpp
Normale Datei
32
server/src/hardware/protocol/cbus/iohandler/cbusiohandler.cpp
Normale Datei
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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 "cbusiohandler.hpp"
|
||||
|
||||
namespace CBUS {
|
||||
|
||||
IOHandler::IOHandler(Kernel& kernel, uint8_t canId)
|
||||
: m_kernel{kernel}
|
||||
, m_canId{canId}
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
61
server/src/hardware/protocol/cbus/iohandler/cbusiohandler.hpp
Normale Datei
61
server/src/hardware/protocol/cbus/iohandler/cbusiohandler.hpp
Normale Datei
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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_CBUS_IOHANDLER_CBUSIOHANDLER_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_CBUS_IOHANDLER_CBUSIOHANDLER_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <system_error>
|
||||
|
||||
namespace CBUS {
|
||||
|
||||
class Kernel;
|
||||
struct Message;
|
||||
|
||||
class IOHandler
|
||||
{
|
||||
public:
|
||||
IOHandler(const IOHandler&) = delete;
|
||||
IOHandler& operator =(const IOHandler&) = delete;
|
||||
|
||||
virtual ~IOHandler() = default;
|
||||
|
||||
virtual void start() = 0;
|
||||
virtual void stop() = 0;
|
||||
|
||||
[[nodiscard]] virtual std::error_code send(const Message& message) = 0;
|
||||
|
||||
protected:
|
||||
Kernel& m_kernel;
|
||||
const uint8_t m_canId;
|
||||
|
||||
IOHandler(Kernel& kernel, uint8_t canId);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
constexpr bool isSimulation()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -30,6 +30,11 @@ struct Message
|
||||
{
|
||||
OpCode opCode;
|
||||
|
||||
constexpr uint8_t size() const
|
||||
{
|
||||
return sizeof(OpCode) + dataSize(opCode);
|
||||
}
|
||||
|
||||
protected:
|
||||
Message(OpCode opc)
|
||||
: opCode{opc}
|
||||
|
||||
46
shared/src/traintastic/enum/cbusinterfacetype.hpp
Normale Datei
46
shared/src/traintastic/enum/cbusinterfacetype.hpp
Normale Datei
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* This file is part of Traintastic,
|
||||
* see <https://github.com/traintastic/traintastic>.
|
||||
*
|
||||
* Copyright (C) 2026 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_SHARED_TRAINTASTIC_ENUM_CBUSINTERFACETYPE_HPP
|
||||
#define TRAINTASTIC_SHARED_TRAINTASTIC_ENUM_CBUSINTERFACETYPE_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include "enum.hpp"
|
||||
|
||||
enum class CBUSInterfaceType : uint8_t
|
||||
{
|
||||
CANUSB = 0,
|
||||
CANEther = 1,
|
||||
};
|
||||
|
||||
TRAINTASTIC_ENUM(CBUSInterfaceType, "cbus_interface_type", 2,
|
||||
{
|
||||
{CBUSInterfaceType::CANUSB, "canusb"},
|
||||
{CBUSInterfaceType::CANEther, "canether"},
|
||||
});
|
||||
|
||||
inline constexpr std::array<CBUSInterfaceType, 2> CBUSInterfaceTypeValues{{
|
||||
CBUSInterfaceType::CANUSB,
|
||||
CBUSInterfaceType::CANEther,
|
||||
}};
|
||||
|
||||
#endif
|
||||
@ -1,4 +1,8 @@
|
||||
[
|
||||
{
|
||||
"term": "class_id:interface.cbus",
|
||||
"definition": "CBUS/VLCB"
|
||||
},
|
||||
{
|
||||
"term": "class_id:interface.dccex",
|
||||
"definition": "DCC-EX"
|
||||
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren