Ursprung
31e5be6405
Commit
6095969cd0
@ -116,6 +116,8 @@ file(GLOB SOURCES
|
||||
"src/hardware/protocol/marklincan/*.cpp"
|
||||
"src/hardware/protocol/marklincan/iohandler/*.hpp"
|
||||
"src/hardware/protocol/marklincan/iohandler/*.cpp"
|
||||
"src/hardware/protocol/marklincan/message/*.hpp"
|
||||
"src/hardware/protocol/marklincan/message/*.cpp"
|
||||
"src/hardware/protocol/traintasticdiy/*.hpp"
|
||||
"src/hardware/protocol/traintasticdiy/*.cpp"
|
||||
"src/hardware/protocol/traintasticdiy/iohandler/*.hpp"
|
||||
|
||||
@ -29,6 +29,7 @@ struct Config
|
||||
{
|
||||
uint32_t defaultSwitchTime; //!< Default switch time in ms
|
||||
bool debugLogRXTX;
|
||||
bool debugConfigStream;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
115
server/src/hardware/protocol/marklincan/configdatastreamcollector.cpp
Normale Datei
115
server/src/hardware/protocol/marklincan/configdatastreamcollector.cpp
Normale Datei
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* server/src/hardware/protocol/marklincan/configdatastreamcollector.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2023 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 "configdatastreamcollector.hpp"
|
||||
|
||||
namespace MarklinCAN {
|
||||
|
||||
//! CRC algorithm as documented by Marklin in the CS2 CAN documentation
|
||||
static uint16_t crc16(uint16_t crc, uint8_t value)
|
||||
{
|
||||
constexpr uint16_t poly = 0x1021;
|
||||
|
||||
// Create the CRC "dividend" for polynomial arithmetic (binary arithmetic with no carries)
|
||||
crc = crc ^ (static_cast<uint16_t>(value) << 8);
|
||||
|
||||
// "Divide" the poly into the dividend using CRC XOR subtraction CRC_acc holds the
|
||||
// "remainder" of each divide. Only complete this division for 8 bits since input is 1 byte
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
// Check if the MSB is set (if MSB is 1, then the POLY can "divide" into the "dividend")
|
||||
if((crc & 0x8000) == 0x8000)
|
||||
{
|
||||
// if so, shift the CRC value, and XOR "subtract" the poly
|
||||
crc = crc << 1;
|
||||
crc ^= poly;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if not, just shift the CRC value
|
||||
crc = crc << 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the final remainder (CRC value)
|
||||
return crc;
|
||||
}
|
||||
|
||||
static uint16_t crc16(const std::vector<std::byte>& data)
|
||||
{
|
||||
uint16_t crc = 0xFFFF;
|
||||
|
||||
for(auto value : data)
|
||||
{
|
||||
crc = crc16(crc, static_cast<uint8_t>(value));
|
||||
}
|
||||
|
||||
if(data.size() % 8 != 0)
|
||||
{
|
||||
// unused nul bytes must be included in CRC:
|
||||
const size_t n = 8 - (data.size() % 8);
|
||||
for(size_t i = 0; i < n; i++)
|
||||
crc = crc16(crc, 0x00);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
ConfigDataStreamCollector::ConfigDataStreamCollector(std::string name_)
|
||||
: name{std::move(name_)}
|
||||
{
|
||||
}
|
||||
|
||||
ConfigDataStreamCollector::Status ConfigDataStreamCollector::process(const ConfigDataStream& message)
|
||||
{
|
||||
if(message.isData() && m_crc != 0x0000)
|
||||
{
|
||||
if(m_offset >= m_data.size()) /*[[unlikely]]*/
|
||||
return ErrorToMuchData;
|
||||
|
||||
if(m_offset + 8 >= m_data.size()) // last message
|
||||
{
|
||||
std::memcpy(m_data.data() + m_offset, message.data, m_data.size() - m_offset);
|
||||
m_offset = m_data.size();
|
||||
|
||||
if(crc16(m_data) != m_crc)
|
||||
return ErrorInvalidCRC;
|
||||
|
||||
return Complete;
|
||||
}
|
||||
|
||||
std::memcpy(m_data.data() + m_offset, message.data, 8);
|
||||
m_offset += 8;
|
||||
return Collecting;
|
||||
}
|
||||
else if(message.isStart() && m_crc == 0x0000)
|
||||
{
|
||||
m_data.resize(message.length());
|
||||
m_crc = message.crc();
|
||||
return Collecting;
|
||||
}
|
||||
|
||||
return ErrorInvalidMessage;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* server/src/hardware/protocol/marklincan/configdatastreamcollector.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2023 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_MARKLINCAN_CONFIGDATASTREAMCOLLECTOR_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_MARKLINCAN_CONFIGDATASTREAMCOLLECTOR_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include "message/configdata.hpp"
|
||||
|
||||
namespace MarklinCAN {
|
||||
|
||||
class ConfigDataStreamCollector
|
||||
{
|
||||
private:
|
||||
uint16_t m_crc = 0;
|
||||
std::vector<std::byte> m_data;
|
||||
size_t m_offset = 0;
|
||||
|
||||
public:
|
||||
enum Status
|
||||
{
|
||||
Collecting,
|
||||
Complete,
|
||||
ErrorInvalidMessage,
|
||||
ErrorToMuchData,
|
||||
ErrorInvalidCRC,
|
||||
};
|
||||
|
||||
const std::string name;
|
||||
|
||||
ConfigDataStreamCollector(std::string name_);
|
||||
|
||||
const std::byte* data() const
|
||||
{
|
||||
return m_data.data();
|
||||
}
|
||||
|
||||
size_t dataSize() const
|
||||
{
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
const std::vector<std::byte>& bytes() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
Status process(const ConfigDataStream& message);
|
||||
|
||||
std::vector<std::byte>&& releaseData()
|
||||
{
|
||||
return std::move(m_data);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -22,6 +22,8 @@
|
||||
|
||||
#include "kernel.hpp"
|
||||
#include "messages.hpp"
|
||||
#include "message/configdata.hpp"
|
||||
#include "locomotivelist.hpp"
|
||||
#include "uid.hpp"
|
||||
#include "../dcc/dcc.hpp"
|
||||
#include "../../decoder/decoder.hpp"
|
||||
@ -31,8 +33,11 @@
|
||||
#include "../../output/outputcontroller.hpp"
|
||||
#include "../../../core/eventloop.hpp"
|
||||
#include "../../../log/log.hpp"
|
||||
#include "../../../traintastic/traintastic.hpp"
|
||||
#include "../../../utils/inrange.hpp"
|
||||
#include "../../../utils/setthreadname.hpp"
|
||||
#include "../../../utils/writefile.hpp"
|
||||
#include "../../../utils/zlib.hpp"
|
||||
|
||||
namespace MarklinCAN {
|
||||
|
||||
@ -57,6 +62,7 @@ static std::tuple<bool, DecoderProtocol, uint16_t> uidToProtocolAddress(uint32_t
|
||||
Kernel::Kernel(const Config& config, bool simulation)
|
||||
: m_ioContext{1}
|
||||
, m_simulation{simulation}
|
||||
, m_debugDir{Traintastic::instance->debugDir()}
|
||||
, m_config{config}
|
||||
#ifndef NDEBUG
|
||||
, m_started{false}
|
||||
@ -94,6 +100,13 @@ void Kernel::setOnError(std::function<void()> callback)
|
||||
m_onError = std::move(callback);
|
||||
}
|
||||
|
||||
void Kernel::setOnLocomotiveListChanged(std::function<void(const std::shared_ptr<LocomotiveList>&)> callback)
|
||||
{
|
||||
assert(isEventLoopThread());
|
||||
assert(!m_started);
|
||||
m_onLocomotiveListChanged = std::move(callback);
|
||||
}
|
||||
|
||||
void Kernel::setDecoderController(DecoderController* decoderController)
|
||||
{
|
||||
assert(isEventLoopThread());
|
||||
@ -142,6 +155,8 @@ void Kernel::start()
|
||||
|
||||
send(AccessorySwitchTime(m_config.defaultSwitchTime / 10));
|
||||
|
||||
send(ConfigData("loks"));
|
||||
|
||||
if(m_onStarted)
|
||||
EventLoop::call(
|
||||
[this]()
|
||||
@ -396,10 +411,33 @@ void Kernel::receive(const Message& message)
|
||||
case Command::BootloaderCAN:
|
||||
case Command::BootloaderTrack:
|
||||
case Command::StatusDataConfig:
|
||||
case Command::ConfigData:
|
||||
case Command::ConfigDataStream:
|
||||
// not (yet) implemented
|
||||
break;
|
||||
|
||||
case Command::ConfigData:
|
||||
if(message.isResponse() && message.dlc == 8)
|
||||
{
|
||||
m_configDataStreamCollector = std::make_unique<ConfigDataStreamCollector>(std::string{static_cast<const ConfigData&>(message).name()});
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::ConfigDataStream:
|
||||
if(m_configDataStreamCollector) /*[[likely]]*/
|
||||
{
|
||||
const auto status = m_configDataStreamCollector->process(static_cast<const ConfigDataStream&>(message));
|
||||
if(status != ConfigDataStreamCollector::Collecting)
|
||||
{
|
||||
if(status == ConfigDataStreamCollector::Complete)
|
||||
{
|
||||
receiveConfigData(std::move(m_configDataStreamCollector));
|
||||
}
|
||||
else // error
|
||||
{
|
||||
m_configDataStreamCollector.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -573,4 +611,35 @@ void Kernel::postSend(const Message& message)
|
||||
});
|
||||
}
|
||||
|
||||
void Kernel::receiveConfigData(std::unique_ptr<ConfigDataStreamCollector> configData)
|
||||
{
|
||||
const auto basename = m_debugDir / m_logId / "configstream" / configData->name;
|
||||
if(m_config.debugConfigStream)
|
||||
{
|
||||
writeFile(std::filesystem::path(basename).concat(".bin"), configData->bytes());
|
||||
}
|
||||
|
||||
if(configData->name == "loks")
|
||||
{
|
||||
const size_t uncompressedSize = be_to_host(*reinterpret_cast<const uint32_t*>(configData->data()));
|
||||
std::string locList;
|
||||
if(ZLib::Uncompress::toString(configData->data() + sizeof(uint32_t), configData->dataSize() - sizeof(uint32_t), uncompressedSize, locList))
|
||||
{
|
||||
if(m_config.debugConfigStream)
|
||||
{
|
||||
writeFile(std::filesystem::path(basename).concat(".txt"), locList);
|
||||
}
|
||||
|
||||
if(m_onLocomotiveListChanged)
|
||||
{
|
||||
EventLoop::call(
|
||||
[this, list=std::make_shared<LocomotiveList>(locList)]()
|
||||
{
|
||||
m_onLocomotiveListChanged(list);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -26,10 +26,12 @@
|
||||
#include <memory>
|
||||
#include <array>
|
||||
#include <thread>
|
||||
#include <filesystem>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <traintastic/enum/tristate.hpp>
|
||||
#include "config.hpp"
|
||||
#include "iohandler/iohandler.hpp"
|
||||
#include "configdatastreamcollector.hpp"
|
||||
|
||||
class Decoder;
|
||||
enum class DecoderChangeFlags;
|
||||
@ -40,6 +42,7 @@ class OutputController;
|
||||
namespace MarklinCAN {
|
||||
|
||||
struct Message;
|
||||
class LocomotiveList;
|
||||
|
||||
class Kernel
|
||||
{
|
||||
@ -81,6 +84,7 @@ class Kernel
|
||||
std::string m_logId;
|
||||
std::function<void()> m_onStarted;
|
||||
std::function<void()> m_onError;
|
||||
std::function<void(const std::shared_ptr<LocomotiveList>&)> m_onLocomotiveListChanged;
|
||||
|
||||
DecoderController* m_decoderController = nullptr;
|
||||
|
||||
@ -92,6 +96,10 @@ class Kernel
|
||||
std::array<TriState, outputDCCAddressMax - outputDCCAddressMin + 1> m_outputValuesDCC;
|
||||
std::array<TriState, outputSX1AddressMax - outputSX1AddressMin + 1> m_outputValuesSX1;
|
||||
|
||||
std::unique_ptr<ConfigDataStreamCollector> m_configDataStreamCollector;
|
||||
|
||||
const std::filesystem::path m_debugDir;
|
||||
|
||||
Config m_config;
|
||||
#ifndef NDEBUG
|
||||
bool m_started;
|
||||
@ -104,6 +112,8 @@ class Kernel
|
||||
void send(const Message& message);
|
||||
void postSend(const Message& message);
|
||||
|
||||
void receiveConfigData(std::unique_ptr<ConfigDataStreamCollector> configData);
|
||||
|
||||
public:
|
||||
Kernel(const Kernel&) = delete;
|
||||
Kernel& operator =(const Kernel&) = delete;
|
||||
@ -192,6 +202,11 @@ class Kernel
|
||||
*/
|
||||
void setOnError(std::function<void()> callback);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void setOnLocomotiveListChanged(std::function<void(const std::shared_ptr<LocomotiveList>&)> callback);
|
||||
|
||||
/**
|
||||
* \brief Set the decoder controller
|
||||
* \param[in] decoderController The decoder controller
|
||||
|
||||
146
server/src/hardware/protocol/marklincan/locomotivelist.cpp
Normale Datei
146
server/src/hardware/protocol/marklincan/locomotivelist.cpp
Normale Datei
@ -0,0 +1,146 @@
|
||||
/**
|
||||
* server/src/hardware/protocol/marklincan/locomotivelist.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2023 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 "locomotivelist.hpp"
|
||||
#include <traintastic/enum/decoderprotocol.hpp>
|
||||
#include "../dcc/dcc.hpp"
|
||||
#include "../../../utils/fromchars.hpp"
|
||||
#include "../../../utils/startswith.hpp"
|
||||
|
||||
namespace MarklinCAN {
|
||||
|
||||
static bool readLine(std::string_view& src, std::string_view& line)
|
||||
{
|
||||
const size_t n = src.find('\n');
|
||||
if(n == std::string_view::npos)
|
||||
return false;
|
||||
|
||||
line = src.substr(0, n);
|
||||
src = src.substr(n + 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LocomotiveList::LocomotiveList(std::string_view list)
|
||||
{
|
||||
std::string_view line;
|
||||
|
||||
if(!readLine(list, line) || line != "[lokomotive]")
|
||||
return;
|
||||
|
||||
while(readLine(list, line))
|
||||
{
|
||||
if(line == "lokomotive")
|
||||
{
|
||||
Locomotive locomotive;
|
||||
|
||||
while(readLine(list, line))
|
||||
{
|
||||
if(startsWith(line, " ."))
|
||||
{
|
||||
line = line.substr(2);
|
||||
if(startsWith(line, "name="))
|
||||
{
|
||||
locomotive.name = line.substr(5);
|
||||
}
|
||||
else if(startsWith(line, "adresse=0x"))
|
||||
{
|
||||
fromChars(line.substr(10), locomotive.address, 16);
|
||||
}
|
||||
else if(startsWith(line, "typ="))
|
||||
{
|
||||
std::string_view typ = line.substr(4);
|
||||
if(typ == "mfx")
|
||||
{
|
||||
locomotive.protocol = DecoderProtocol::MFX;
|
||||
}
|
||||
else if(typ == "dcc")
|
||||
{
|
||||
locomotive.protocol = DecoderProtocol::DCCShort; // or DCCLong (handled later)
|
||||
}
|
||||
else if(typ == "mm2_dil8" || typ == "mm2_prg")
|
||||
{
|
||||
locomotive.protocol = DecoderProtocol::Motorola;
|
||||
}
|
||||
}
|
||||
else if(startsWith(line, "sid=0x"))
|
||||
{
|
||||
fromChars(line.substr(6), locomotive.sid, 16);
|
||||
}
|
||||
else if(startsWith(line, "mfxuid=0x"))
|
||||
{
|
||||
fromChars(line.substr(9), locomotive.mfxUID, 16);
|
||||
}
|
||||
else if(line == "funktionen")
|
||||
{
|
||||
Function function;
|
||||
function.nr = 0xFF;
|
||||
|
||||
while(readLine(list, line))
|
||||
{
|
||||
if(startsWith(line, " .."))
|
||||
{
|
||||
line = line.substr(3);
|
||||
if(startsWith(line, "nr="))
|
||||
{
|
||||
fromChars(line.substr(3), function.nr);
|
||||
}
|
||||
else if(startsWith(line, "typ="))
|
||||
{
|
||||
uint8_t typ;
|
||||
if(fromChars(line.substr(4), typ).ec == std::errc())
|
||||
{
|
||||
(void)typ; //! \todo convert value to type/function (if constant)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
list = {line.data(), line.size() + 1 + list.size()}; // restore list for next readLine
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(function.nr != 0xFF)
|
||||
{
|
||||
locomotive.functions.push_back(function);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
list = {line.data(), line.size() + 1 + list.size()}; // restore list for next readLine
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(locomotive.protocol == DecoderProtocol::DCCShort && DCC::isLongAddress(locomotive.address))
|
||||
{
|
||||
locomotive.protocol = DecoderProtocol::DCCLong;
|
||||
}
|
||||
|
||||
m_locomotives.emplace_back(std::move(locomotive));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
64
server/src/hardware/protocol/marklincan/locomotivelist.hpp
Normale Datei
64
server/src/hardware/protocol/marklincan/locomotivelist.hpp
Normale Datei
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* server/src/hardware/protocol/marklincan/locomotivelist.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2023 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_MARKLINCAN_LOCOMOTIVELIST_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_MARKLINCAN_LOCOMOTIVELIST_HPP
|
||||
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <traintastic/enum/decoderprotocol.hpp>
|
||||
#include <traintastic/enum/decoderfunctiontype.hpp>
|
||||
#include <traintastic/enum/decoderfunctionfunction.hpp>
|
||||
|
||||
namespace MarklinCAN {
|
||||
|
||||
class LocomotiveList
|
||||
{
|
||||
public:
|
||||
struct Function
|
||||
{
|
||||
uint8_t nr;
|
||||
DecoderFunctionType type = DecoderFunctionType::OnOff;
|
||||
DecoderFunctionFunction function = DecoderFunctionFunction::Generic;
|
||||
};
|
||||
|
||||
struct Locomotive
|
||||
{
|
||||
std::string name;
|
||||
uint16_t address = 0;
|
||||
DecoderProtocol protocol = DecoderProtocol::None;
|
||||
uint16_t sid = 0;
|
||||
uint32_t mfxUID = 0;
|
||||
std::vector<Function> functions;
|
||||
};
|
||||
|
||||
private:
|
||||
std::vector<Locomotive> m_locomotives;
|
||||
|
||||
public:
|
||||
LocomotiveList(std::string_view list = {});
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
74
server/src/hardware/protocol/marklincan/message/configdata.hpp
Normale Datei
74
server/src/hardware/protocol/marklincan/message/configdata.hpp
Normale Datei
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* server/src/hardware/protocol/marklincan/message/configdata.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2023 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_MARKLINCAN_MESSAGE_CONFIGDATA_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_MARKLINCAN_MESSAGE_CONFIGDATA_HPP
|
||||
|
||||
#include "../messages.hpp"
|
||||
|
||||
namespace MarklinCAN {
|
||||
|
||||
struct ConfigData : Message
|
||||
{
|
||||
ConfigData(std::string_view name_)
|
||||
: Message(Command::ConfigData, false)
|
||||
{
|
||||
assert(name_.size() <= 8);
|
||||
dlc = 8;
|
||||
std::memcpy(data, name_.data(), std::min<size_t>(name_.size(), 8));
|
||||
}
|
||||
|
||||
std::string_view name() const
|
||||
{
|
||||
const char* str = reinterpret_cast<const char*>(data);
|
||||
return {str, strnlen(str, dlc)};
|
||||
}
|
||||
};
|
||||
|
||||
struct ConfigDataStream : Message
|
||||
{
|
||||
bool isStart() const
|
||||
{
|
||||
return dlc == 6 || dlc == 7;
|
||||
}
|
||||
|
||||
uint32_t length() const
|
||||
{
|
||||
assert(isStart());
|
||||
return be_to_host(*reinterpret_cast<const uint32_t*>(data));
|
||||
}
|
||||
|
||||
uint16_t crc() const
|
||||
{
|
||||
assert(isStart());
|
||||
return be_to_host(*reinterpret_cast<const uint16_t*>(data + sizeof(uint32_t)));
|
||||
}
|
||||
|
||||
bool isData() const
|
||||
{
|
||||
return dlc == 8;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -30,6 +30,7 @@ Settings::Settings(Object& _parent, std::string_view parentPropertyName)
|
||||
: SubObject(_parent, parentPropertyName)
|
||||
, defaultSwitchTime{this, "default_switch_time", 0, PropertyFlags::ReadWrite | PropertyFlags::Store}
|
||||
, debugLogRXTX{this, "debug_log_rx_tx", false, PropertyFlags::ReadWrite | PropertyFlags::Store}
|
||||
, debugConfigStream{this, "debug_config_stream", false, PropertyFlags::ReadWrite | PropertyFlags::Store}
|
||||
{
|
||||
Attributes::addMinMax<uint32_t>(defaultSwitchTime, 0, 163'000);
|
||||
//Attributes::addStep(defaultSwitchTime, 10);
|
||||
@ -37,6 +38,8 @@ Settings::Settings(Object& _parent, std::string_view parentPropertyName)
|
||||
|
||||
Attributes::addDisplayName(debugLogRXTX, DisplayName::Hardware::debugLogRXTX);
|
||||
m_interfaceItems.add(debugLogRXTX);
|
||||
|
||||
m_interfaceItems.add(debugConfigStream);
|
||||
}
|
||||
|
||||
Config Settings::config() const
|
||||
@ -45,6 +48,7 @@ Config Settings::config() const
|
||||
|
||||
config.defaultSwitchTime = defaultSwitchTime;
|
||||
config.debugLogRXTX = debugLogRXTX;
|
||||
config.debugConfigStream = debugConfigStream;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ class Settings final : public SubObject
|
||||
|
||||
Property<uint32_t> defaultSwitchTime;
|
||||
Property<bool> debugLogRXTX;
|
||||
Property<bool> debugConfigStream;
|
||||
|
||||
Settings(Object& _parent, std::string_view parentPropertyName);
|
||||
|
||||
|
||||
47
server/src/utils/writefile.cpp
Normale Datei
47
server/src/utils/writefile.cpp
Normale Datei
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* server/src/utils/writefile.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2023 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 "writefile.hpp"
|
||||
#include <fstream>
|
||||
|
||||
bool writeFile(const std::filesystem::path& filename, const void* data, size_t dataSize)
|
||||
{
|
||||
// try create directory if it doesn't exist
|
||||
const auto path = filename.parent_path();
|
||||
if(!std::filesystem::is_directory(path))
|
||||
{
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(path, ec);
|
||||
if(ec)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ofstream file;
|
||||
file.open(filename, std::ios::binary | std::ios::out | std::ios::trunc);
|
||||
if(!file.is_open())
|
||||
return false;
|
||||
|
||||
file.write(reinterpret_cast<const char*>(data), dataSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
43
server/src/utils/writefile.hpp
Normale Datei
43
server/src/utils/writefile.hpp
Normale Datei
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* server/src/utils/writefile.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2023 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_WRITEFILE_HPP
|
||||
#define TRAINTASTIC_SERVER_UTILS_WRITEFILE_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
|
||||
bool writeFile(const std::filesystem::path& filename, const void* data, size_t dataSize);
|
||||
|
||||
inline bool writeFile(const std::filesystem::path& filename, std::string_view data)
|
||||
{
|
||||
return writeFile(filename, data.data(), data.size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool writeFile(const std::filesystem::path& filename, const std::vector<T>& data)
|
||||
{
|
||||
return writeFile(filename, data.data(), data.size() * sizeof(T));
|
||||
}
|
||||
|
||||
#endif
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren