239 Zeilen
6.2 KiB
C++
239 Zeilen
6.2 KiB
C++
/**
|
|
* 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);
|
|
}
|