[cbus] added Lua support for sending CBUS/VLCB message and DCC commands
Einige Prüfungen sind fehlgeschlagen
Build / client macos-15-arm64 (push) Has been cancelled
Build / client macos-15-intel (push) Has been cancelled
Build / client ubuntu_24.04 (push) Has been cancelled
Build / client ubuntu_24.04_arm64 (push) Has been cancelled
Build / client raspberrypios_arm64 (push) Has been cancelled
Build / client raspberrypios_arm7 (push) Has been cancelled
Build / client windows_x64_msvc (push) Has been cancelled
Build / server ubuntu_24.04 (debug+ccov) (push) Has been cancelled
Build / server macos-15-arm64 (push) Has been cancelled
Build / server macos-15-intel (push) Has been cancelled
Build / server raspberrypios_arm64 (push) Has been cancelled
Build / server raspberrypios_arm7 (push) Has been cancelled
Build / server ubuntu_24.04 (push) Has been cancelled
Build / server ubuntu_24.04_arm64 (push) Has been cancelled
Build / server windows_x64_clang (push) Has been cancelled
Build / language files (push) Has been cancelled
Build / manual (push) Has been cancelled
Build / Update contributers in README.md (push) Has been cancelled
Build / shared data raspberrypios_10 (push) Has been cancelled
Build / shared data ubuntu_24.04 (push) Has been cancelled
Build / package innosetup (push) Has been cancelled
Build / Deploy to website (push) Has been cancelled
Einige Prüfungen sind fehlgeschlagen
Build / client macos-15-arm64 (push) Has been cancelled
Build / client macos-15-intel (push) Has been cancelled
Build / client ubuntu_24.04 (push) Has been cancelled
Build / client ubuntu_24.04_arm64 (push) Has been cancelled
Build / client raspberrypios_arm64 (push) Has been cancelled
Build / client raspberrypios_arm7 (push) Has been cancelled
Build / client windows_x64_msvc (push) Has been cancelled
Build / server ubuntu_24.04 (debug+ccov) (push) Has been cancelled
Build / server macos-15-arm64 (push) Has been cancelled
Build / server macos-15-intel (push) Has been cancelled
Build / server raspberrypios_arm64 (push) Has been cancelled
Build / server raspberrypios_arm7 (push) Has been cancelled
Build / server ubuntu_24.04 (push) Has been cancelled
Build / server ubuntu_24.04_arm64 (push) Has been cancelled
Build / server windows_x64_clang (push) Has been cancelled
Build / language files (push) Has been cancelled
Build / manual (push) Has been cancelled
Build / Update contributers in README.md (push) Has been cancelled
Build / shared data raspberrypios_10 (push) Has been cancelled
Build / shared data ubuntu_24.04 (push) Has been cancelled
Build / package innosetup (push) Has been cancelled
Build / Deploy to website (push) Has been cancelled
Dieser Commit ist enthalten in:
Ursprung
81d452bad1
Commit
222c219fb7
@ -221,6 +221,7 @@ class TraintasticHelp:
|
|||||||
]},
|
]},
|
||||||
{'Product index': 'appendix/supported-hardware/product-index.md'}
|
{'Product index': 'appendix/supported-hardware/product-index.md'}
|
||||||
]},
|
]},
|
||||||
|
{'CBUS/VLCB reference': 'appendix/cbus-vlcb.md'},
|
||||||
{'LocoNet reference': 'appendix/loconet.md'},
|
{'LocoNet reference': 'appendix/loconet.md'},
|
||||||
{'XpressNet reference': 'appendix/xpressnet.md'},
|
{'XpressNet reference': 'appendix/xpressnet.md'},
|
||||||
{'Lua scripting reference': lua_ref},
|
{'Lua scripting reference': lua_ref},
|
||||||
|
|||||||
44
manual/docs/en/appendix/cbus-vlcb.md
Normale Datei
44
manual/docs/en/appendix/cbus-vlcb.md
Normale Datei
@ -0,0 +1,44 @@
|
|||||||
|
# CBUS/VLCB reference
|
||||||
|
|
||||||
|
CBUS is a Layout Control Bus developed by members of the Model Electronic Railway Group (MERG).
|
||||||
|
CBUS uses the Controller Area Network (CAN) for communication between the CBUS modules.
|
||||||
|
|
||||||
|
VLCB is an CBUS extension developed by MERG members to it adds additional commands and introduced a a stricter priority system for commands.
|
||||||
|
|
||||||
|
This appendix does **not** explain the CBUS/VLCB protocol.
|
||||||
|
Instead, it **how Traintastic implements and uses CBUS/VLCB** and which protocol messages are recognized.
|
||||||
|
It is intended for advanced users who are already familiar with the basics of the CBUS/VLCB protocol.
|
||||||
|
|
||||||
|
## Supported hardware
|
||||||
|
|
||||||
|
*TODO: under development*
|
||||||
|
|
||||||
|
## Message support
|
||||||
|
|
||||||
|
### General control
|
||||||
|
- Track on/off: `TOF`, `TON`, `RTOF`, `RTON` - Supported
|
||||||
|
- Emergency stop: `ESTOP`, `RESTP` - Supported
|
||||||
|
|
||||||
|
*TODO: under development, will be expanded when implemented*
|
||||||
|
|
||||||
|
## Debugging and monitoring
|
||||||
|
|
||||||
|
Traintastic provides a debug option for CBUS/VLCB that logs all bus traffic.
|
||||||
|
Messages are shown in **hexadecimal format**, and for many message types a human-readable textual description of the content is also provided.
|
||||||
|
|
||||||
|
This is useful for:
|
||||||
|
|
||||||
|
- Diagnosing compatibility issues with specific modules.
|
||||||
|
- Verifying that messages are transmitted and received as expected.
|
||||||
|
|
||||||
|
### Sending raw messages
|
||||||
|
|
||||||
|
Through [**Lua scripting**](../advanced/scripting-basics.md), it is also possible to:
|
||||||
|
|
||||||
|
- Send **raw CBUS/VLCB messages**, see [`send()`](lua/object/cbusinterface.md#send).
|
||||||
|
- Send **raw DCC track commands** (`RDCCn`), see [`send_dcc()`](lua/object/cbusinterface.md#send_dcc).
|
||||||
|
|
||||||
|
!!! warning "Use this with caution!"
|
||||||
|
- These messages bypass Traintastic’s normal handling.
|
||||||
|
- You need a solid understanding of CBUS/VLCB and DCC to avoid conflicts.
|
||||||
|
- Side effects may occur that Traintastic is not aware of or cannot manage.
|
||||||
@ -106,6 +106,9 @@
|
|||||||
"CLOCK": {
|
"CLOCK": {
|
||||||
"type": "constant"
|
"type": "constant"
|
||||||
},
|
},
|
||||||
|
"CBUS_INTERFACE": {
|
||||||
|
"type": "constant"
|
||||||
|
},
|
||||||
"DCCEX_INTERFACE": {
|
"DCCEX_INTERFACE": {
|
||||||
"type": "constant"
|
"type": "constant"
|
||||||
},
|
},
|
||||||
@ -228,4 +231,4 @@
|
|||||||
"type": "constant",
|
"type": "constant",
|
||||||
"since": "0.3"
|
"since": "0.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
manual/luadoc/object/cbusinterface.json
Normale Datei
23
manual/luadoc/object/cbusinterface.json
Normale Datei
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"send": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "message"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"return_values": 1
|
||||||
|
},
|
||||||
|
"send_dcc": {
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "dcc_packet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "repeat",
|
||||||
|
"optional": true,
|
||||||
|
"default": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"return_values": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3190,5 +3190,58 @@
|
|||||||
{
|
{
|
||||||
"term": "object.category.signals:title",
|
"term": "object.category.signals:title",
|
||||||
"definition": "Signals"
|
"definition": "Signals"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"term": "object.cbusinterface:title",
|
||||||
|
"definition": "CBUS/VLCB interface"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"term": "object.cbusinterface:description",
|
||||||
|
"definition": "Interface for communicating with a CBUS/VLCB network."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"term": "object.cbusinterface.send_dcc:description",
|
||||||
|
"definition": "Request the command station to send a DCC packet to the track (`RDCCn`)."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"term": "object.cbusinterface.send_dcc.parameter.dcc_packet:description",
|
||||||
|
"definition": "Table containing two to five DCC packet bytes to send excluding checksum byte."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"term": "object.cbusinterface.send_dcc.parameter.repeat:description",
|
||||||
|
"definition": "Number of times to repeat the packet on the track. (1...255)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"term": "object.cbusinterface.send_dcc:return_values",
|
||||||
|
"definition": "`true` if send, `false` otherwise."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"term": "object.cbusinterface.send_dcc.warning:title",
|
||||||
|
"definition": "Use this with caution!"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"term": "object.cbusinterface.send_dcc.warning:description",
|
||||||
|
"definition": "These messages bypass Traintastic’s normal handling. You need a solid understanding of DCC to avoid conflicts. Side effects may occur that Traintastic is not aware of or cannot manage."
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"term": "object.cbusinterface.send:description",
|
||||||
|
"definition": "Send CBUS/VLCB message."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"term": "object.cbusinterface.send.parameter.message:description",
|
||||||
|
"definition": "CBUS/VLCB message bytes. (1...8)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"term": "object.cbusinterface.send:return_values",
|
||||||
|
"definition": "`true` if send, `false` otherwise."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"term": "object.cbusinterface.send.warning:title",
|
||||||
|
"definition": "Use this with caution!"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"term": "object.cbusinterface.send.warning:description",
|
||||||
|
"definition": "These messages bypass Traintastic’s normal handling. You need a solid understanding of CBUS/VLCB to avoid conflicts. Side effects may occur that Traintastic is not aware of or cannot manage."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -36,6 +36,10 @@
|
|||||||
#include "../../utils/displayname.hpp"
|
#include "../../utils/displayname.hpp"
|
||||||
#include "../../world/world.hpp"
|
#include "../../world/world.hpp"
|
||||||
|
|
||||||
|
namespace CBUS {
|
||||||
|
class Simulator{};
|
||||||
|
}
|
||||||
|
|
||||||
CREATE_IMPL(CBUSInterface)
|
CREATE_IMPL(CBUSInterface)
|
||||||
|
|
||||||
CBUSInterface::CBUSInterface(World& world, std::string_view _id)
|
CBUSInterface::CBUSInterface(World& world, std::string_view _id)
|
||||||
@ -88,6 +92,24 @@ CBUSInterface::CBUSInterface(World& world, std::string_view _id)
|
|||||||
|
|
||||||
CBUSInterface::~CBUSInterface() = default;
|
CBUSInterface::~CBUSInterface() = default;
|
||||||
|
|
||||||
|
bool CBUSInterface::send(std::vector<uint8_t> message)
|
||||||
|
{
|
||||||
|
if(m_kernel)
|
||||||
|
{
|
||||||
|
return m_kernel->send(std::move(message));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CBUSInterface::sendDCC(std::vector<uint8_t> dccPacket, uint8_t repeat)
|
||||||
|
{
|
||||||
|
if(m_kernel)
|
||||||
|
{
|
||||||
|
return m_kernel->sendDCC(std::move(dccPacket), repeat);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void CBUSInterface::addToWorld()
|
void CBUSInterface::addToWorld()
|
||||||
{
|
{
|
||||||
Interface::addToWorld();
|
Interface::addToWorld();
|
||||||
|
|||||||
@ -30,7 +30,7 @@ class CBUSSettings;
|
|||||||
|
|
||||||
namespace CBUS {
|
namespace CBUS {
|
||||||
class Kernel;
|
class Kernel;
|
||||||
class Simulator {};
|
class Simulator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,6 +53,17 @@ public:
|
|||||||
CBUSInterface(World& world, std::string_view _id);
|
CBUSInterface(World& world, std::string_view _id);
|
||||||
~CBUSInterface() final;
|
~CBUSInterface() final;
|
||||||
|
|
||||||
|
//! \brief Send CBUS/VLCB message
|
||||||
|
//! \param[in] message CBUS/VLCB message bytes, 1..8 bytes.
|
||||||
|
//! \return \c true if send, \c false otherwise.
|
||||||
|
bool send(std::vector<uint8_t> message);
|
||||||
|
|
||||||
|
//! \brief Send DCC packet
|
||||||
|
//! \param[in] dccPacket DCC packet byte, exluding checksum. Length is limited to 6.
|
||||||
|
//! \param[in] repeat DCC packet repeat count 0..7
|
||||||
|
//! \return \c true if send, \c false otherwise.
|
||||||
|
bool sendDCC(std::vector<uint8_t> dccPacket, uint8_t repeat);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void addToWorld() final;
|
void addToWorld() final;
|
||||||
void loaded() final;
|
void loaded() final;
|
||||||
|
|||||||
@ -25,9 +25,11 @@
|
|||||||
/*
|
/*
|
||||||
#include "simulator/cbussimulator.hpp"
|
#include "simulator/cbussimulator.hpp"
|
||||||
*/
|
*/
|
||||||
|
#include "../dcc/dcc.hpp"
|
||||||
#include "../../../core/eventloop.hpp"
|
#include "../../../core/eventloop.hpp"
|
||||||
#include "../../../log/log.hpp"
|
#include "../../../log/log.hpp"
|
||||||
#include "../../../log/logmessageexception.hpp"
|
#include "../../../log/logmessageexception.hpp"
|
||||||
|
#include "../../../utils/inrange.hpp"
|
||||||
#include "../../../utils/setthreadname.hpp"
|
#include "../../../utils/setthreadname.hpp"
|
||||||
|
|
||||||
namespace CBUS {
|
namespace CBUS {
|
||||||
@ -191,6 +193,65 @@ void Kernel::requestEmergencyStop()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Kernel::send(std::vector<uint8_t> message)
|
||||||
|
{
|
||||||
|
assert(isEventLoopThread());
|
||||||
|
|
||||||
|
if(!inRange<size_t>(message.size(), 1, 8))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ioContext.post(
|
||||||
|
[this, msg=std::move(message)]()
|
||||||
|
{
|
||||||
|
send(*reinterpret_cast<const Message*>(msg.data()));
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Kernel::sendDCC(std::vector<uint8_t> dccPacket, uint8_t repeat)
|
||||||
|
{
|
||||||
|
assert(isEventLoopThread());
|
||||||
|
|
||||||
|
if(!inRange<size_t>(dccPacket.size(), 2, 5) || repeat == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dccPacket.emplace_back(DCC::calcChecksum(dccPacket));
|
||||||
|
|
||||||
|
m_ioContext.post(
|
||||||
|
[this, packet=std::move(dccPacket), repeat]()
|
||||||
|
{
|
||||||
|
switch(packet.size())
|
||||||
|
{
|
||||||
|
case 3:
|
||||||
|
send(RequestDCCPacket<3>(packet, repeat));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
send(RequestDCCPacket<4>(packet, repeat));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
send(RequestDCCPacket<5>(packet, repeat));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
send(RequestDCCPacket<6>(packet, repeat));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: [[unlikely]]
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Kernel::setIOHandler(std::unique_ptr<IOHandler> handler)
|
void Kernel::setIOHandler(std::unique_ptr<IOHandler> handler)
|
||||||
{
|
{
|
||||||
assert(isEventLoopThread());
|
assert(isEventLoopThread());
|
||||||
|
|||||||
@ -89,6 +89,9 @@ public:
|
|||||||
void trackOn();
|
void trackOn();
|
||||||
void requestEmergencyStop();
|
void requestEmergencyStop();
|
||||||
|
|
||||||
|
bool send(std::vector<uint8_t> message);
|
||||||
|
bool sendDCC(std::vector<uint8_t> dccPacket, uint8_t repeat);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<IOHandler> m_ioHandler;
|
std::unique_ptr<IOHandler> m_ioHandler;
|
||||||
const bool m_simulation;
|
const bool m_simulation;
|
||||||
|
|||||||
@ -24,5 +24,6 @@
|
|||||||
|
|
||||||
#include "messages/cbusenginemessages.hpp"
|
#include "messages/cbusenginemessages.hpp"
|
||||||
#include "messages/cbusgeneralmessages.hpp"
|
#include "messages/cbusgeneralmessages.hpp"
|
||||||
|
#include "messages/cbusrequestdccpacketmessage.hpp"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* 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_MESSAGES_CBUSREQUESTDCCPACKETMESSAGE_HPP
|
||||||
|
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_CBUS_MESSAGES_CBUSREQUESTDCCPACKETMESSAGE_HPP
|
||||||
|
|
||||||
|
#include "cbusmessage.hpp"
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
namespace CBUS {
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
requires(N >= 3 && N <= 6)
|
||||||
|
struct RequestDCCPacket : Message
|
||||||
|
{
|
||||||
|
uint8_t repeat;
|
||||||
|
uint8_t data[N];
|
||||||
|
|
||||||
|
RequestDCCPacket(std::span<const uint8_t> bytes, uint8_t repeat_)
|
||||||
|
: Message(RDCCn())
|
||||||
|
, repeat{repeat_}
|
||||||
|
{
|
||||||
|
assert(N == bytes.size());
|
||||||
|
std::memcpy(data, bytes.data(), N);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr OpCode RDCCn() noexcept
|
||||||
|
{
|
||||||
|
switch(N)
|
||||||
|
{
|
||||||
|
case 3: return OpCode::RDCC3;
|
||||||
|
case 4: return OpCode::RDCC4;
|
||||||
|
case 5: return OpCode::RDCC5;
|
||||||
|
case 6: return OpCode::RDCC6;
|
||||||
|
}
|
||||||
|
return static_cast<OpCode>(0); // unreachable, should never happen
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(sizeof(RequestDCCPacket<3>) == 5);
|
||||||
|
static_assert(sizeof(RequestDCCPacket<4>) == 6);
|
||||||
|
static_assert(sizeof(RequestDCCPacket<5>) == 7);
|
||||||
|
static_assert(sizeof(RequestDCCPacket<6>) == 8);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,9 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* server/src/hardware/protocol/dcc/dcc.hpp
|
* This file is part of Traintastic,
|
||||||
|
* see <https://github.com/traintastic/traintastic>.
|
||||||
*
|
*
|
||||||
* This file is part of the traintastic source code.
|
* Copyright (C) 2021-2026 Reinder Feenstra
|
||||||
*
|
|
||||||
* Copyright (C) 2021,2023-2024 Reinder Feenstra
|
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -24,6 +23,7 @@
|
|||||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_DCC_DCC_HPP
|
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_DCC_DCC_HPP
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
#include <traintastic/enum/decoderprotocol.hpp>
|
#include <traintastic/enum/decoderprotocol.hpp>
|
||||||
#include "../../../utils/inrange.hpp"
|
#include "../../../utils/inrange.hpp"
|
||||||
|
|
||||||
@ -45,6 +45,20 @@ constexpr DecoderProtocol getProtocol(uint16_t address)
|
|||||||
return isLongAddress(address) ? DecoderProtocol::DCCLong : DecoderProtocol::DCCShort;
|
return isLongAddress(address) ? DecoderProtocol::DCCLong : DecoderProtocol::DCCShort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr uint8_t calcChecksum(std::span<const uint8_t> message)
|
||||||
|
{
|
||||||
|
if(message.empty()) [[unlikely]]
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint8_t checksum = message[0];
|
||||||
|
for(size_t i = 1; i < message.size(); i++)
|
||||||
|
{
|
||||||
|
checksum ^= message[i];
|
||||||
|
}
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Accessory {
|
namespace Accessory {
|
||||||
|
|
||||||
constexpr uint16_t addressMin = 1;
|
constexpr uint16_t addressMin = 1;
|
||||||
|
|||||||
@ -62,6 +62,7 @@
|
|||||||
|
|
||||||
#include "../clock/clock.hpp"
|
#include "../clock/clock.hpp"
|
||||||
|
|
||||||
|
#include "../hardware/interface/cbusinterface.hpp"
|
||||||
#include "../hardware/interface/dccexinterface.hpp"
|
#include "../hardware/interface/dccexinterface.hpp"
|
||||||
#include "../hardware/interface/ecosinterface.hpp"
|
#include "../hardware/interface/ecosinterface.hpp"
|
||||||
#include "../hardware/interface/hsi88.hpp"
|
#include "../hardware/interface/hsi88.hpp"
|
||||||
@ -196,6 +197,7 @@ void Class::registerValues(lua_State* L)
|
|||||||
registerValue<Clock>(L, "CLOCK");
|
registerValue<Clock>(L, "CLOCK");
|
||||||
|
|
||||||
// hardware - interface:
|
// hardware - interface:
|
||||||
|
registerValue<CBUSInterface>(L, "CBUS_INTERFACE");
|
||||||
registerValue<DCCEXInterface>(L, "DCCEX_INTERFACE");
|
registerValue<DCCEXInterface>(L, "DCCEX_INTERFACE");
|
||||||
registerValue<ECoSInterface>(L, "ECOS_INTERFACE");
|
registerValue<ECoSInterface>(L, "ECOS_INTERFACE");
|
||||||
registerValue<HSI88Interface>(L, "HSI88_INTERFACE");
|
registerValue<HSI88Interface>(L, "HSI88_INTERFACE");
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* server/src/lua/object.cpp
|
* This file is part of Traintastic,
|
||||||
|
* see <https://github.com/traintastic/traintastic>.
|
||||||
*
|
*
|
||||||
* This file is part of the traintastic source code.
|
* Copyright (C) 2019-2026 Reinder Feenstra
|
||||||
*
|
|
||||||
* Copyright (C) 2019-2025 Reinder Feenstra
|
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -24,6 +23,7 @@
|
|||||||
#include "object/object.hpp"
|
#include "object/object.hpp"
|
||||||
#include "object/objectlist.hpp"
|
#include "object/objectlist.hpp"
|
||||||
#include "object/interface.hpp"
|
#include "object/interface.hpp"
|
||||||
|
#include "object/cbusinterface.hpp"
|
||||||
#include "object/loconetinterface.hpp"
|
#include "object/loconetinterface.hpp"
|
||||||
#include "object/scriptthrottle.hpp"
|
#include "object/scriptthrottle.hpp"
|
||||||
|
|
||||||
@ -36,6 +36,7 @@ void registerTypes(lua_State* L)
|
|||||||
Object::registerType(L);
|
Object::registerType(L);
|
||||||
ObjectList::registerType(L);
|
ObjectList::registerType(L);
|
||||||
Interface::registerType(L);
|
Interface::registerType(L);
|
||||||
|
CBUSInterface::registerType(L);
|
||||||
LocoNetInterface::registerType(L);
|
LocoNetInterface::registerType(L);
|
||||||
ScriptThrottle::registerType(L);
|
ScriptThrottle::registerType(L);
|
||||||
|
|
||||||
@ -65,7 +66,11 @@ void push(lua_State* L, const ObjectPtr& value)
|
|||||||
lua_pop(L, 1); // remove nil
|
lua_pop(L, 1); // remove nil
|
||||||
new(lua_newuserdata(L, sizeof(ObjectPtrWeak))) ObjectPtrWeak(value);
|
new(lua_newuserdata(L, sizeof(ObjectPtrWeak))) ObjectPtrWeak(value);
|
||||||
|
|
||||||
if(dynamic_cast<::LocoNetInterface*>(value.get()))
|
if(dynamic_cast<::CBUSInterface*>(value.get()))
|
||||||
|
{
|
||||||
|
luaL_setmetatable(L, CBUSInterface::metaTableName);
|
||||||
|
}
|
||||||
|
else if(dynamic_cast<::LocoNetInterface*>(value.get()))
|
||||||
luaL_setmetatable(L, LocoNetInterface::metaTableName);
|
luaL_setmetatable(L, LocoNetInterface::metaTableName);
|
||||||
else if(dynamic_cast<AbstractObjectList*>(value.get()))
|
else if(dynamic_cast<AbstractObjectList*>(value.get()))
|
||||||
luaL_setmetatable(L, ObjectList::metaTableName);
|
luaL_setmetatable(L, ObjectList::metaTableName);
|
||||||
|
|||||||
75
server/src/lua/object/cbusinterface.cpp
Normale Datei
75
server/src/lua/object/cbusinterface.cpp
Normale Datei
@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* 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 "interface.hpp"
|
||||||
|
#include "object.hpp"
|
||||||
|
#include "../check.hpp"
|
||||||
|
#include "../checkarguments.hpp"
|
||||||
|
#include "../checkvector.hpp"
|
||||||
|
#include "../push.hpp"
|
||||||
|
#include "../to.hpp"
|
||||||
|
#include "../metatable.hpp"
|
||||||
|
|
||||||
|
namespace Lua::Object {
|
||||||
|
|
||||||
|
void CBUSInterface::registerType(lua_State* L)
|
||||||
|
{
|
||||||
|
MetaTable::clone(L, Interface::metaTableName, metaTableName);
|
||||||
|
lua_pushcfunction(L, __index);
|
||||||
|
lua_setfield(L, -2, "__index");
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CBUSInterface::index(lua_State* L, ::CBUSInterface& object)
|
||||||
|
{
|
||||||
|
const auto key = to<std::string_view>(L, 2);
|
||||||
|
LUA_OBJECT_METHOD(send)
|
||||||
|
LUA_OBJECT_METHOD(send_dcc)
|
||||||
|
return Interface::index(L, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CBUSInterface::__index(lua_State* L)
|
||||||
|
{
|
||||||
|
return index(L, *check<::CBUSInterface>(L, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
int CBUSInterface::send(lua_State* L)
|
||||||
|
{
|
||||||
|
checkArguments(L, 1);
|
||||||
|
auto interface = check<::CBUSInterface>(L, lua_upvalueindex(1));
|
||||||
|
auto message = checkVector<uint8_t>(L, 1);
|
||||||
|
Lua::push(L, interface->send(std::move(message)));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CBUSInterface::send_dcc(lua_State* L)
|
||||||
|
{
|
||||||
|
const uint8_t defaultRepeat = 2;
|
||||||
|
const int argc = checkArguments(L, 1, 2);
|
||||||
|
auto interface = check<::CBUSInterface>(L, lua_upvalueindex(1));
|
||||||
|
auto dccPacket = checkVector<uint8_t>(L, 1);
|
||||||
|
auto repeat = (argc >= 2) ? check<uint8_t>(L, 2) : defaultRepeat;
|
||||||
|
Lua::push(L, interface->sendDCC(std::move(dccPacket), repeat));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
48
server/src/lua/object/cbusinterface.hpp
Normale Datei
48
server/src/lua/object/cbusinterface.hpp
Normale Datei
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* 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_LUA_OBJECT_CBUSINTERFACE_HPP
|
||||||
|
#define TRAINTASTIC_SERVER_LUA_OBJECT_CBUSINTERFACE_HPP
|
||||||
|
|
||||||
|
#include <lua.hpp>
|
||||||
|
#include "../../hardware/interface/cbusinterface.hpp"
|
||||||
|
|
||||||
|
namespace Lua::Object {
|
||||||
|
|
||||||
|
class CBUSInterface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static int __index(lua_State* L);
|
||||||
|
|
||||||
|
static int send(lua_State* L);
|
||||||
|
static int send_dcc(lua_State* L);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr char const* metaTableName = "object.interface.cbus";
|
||||||
|
|
||||||
|
static void registerType(lua_State* L);
|
||||||
|
|
||||||
|
static int index(lua_State* L, ::CBUSInterface& object);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren