loconet: updated OPC_MULTI_SENSE_LONG
based on documentation from the developer of the message format.
Dieser Commit ist enthalten in:
Ursprung
a457088f29
Commit
8ff6a98dc8
@ -764,17 +764,17 @@ void Kernel::receive(const Message& message)
|
||||
case OPC_MULTI_SENSE_LONG:
|
||||
{
|
||||
const MultiSenseLong& multiSense = static_cast<const MultiSenseLong&>(message);
|
||||
if(multiSense.isTransponder())
|
||||
if(multiSense.code() == MultiSenseLong::Code::ReleaseTransponder || multiSense.code() == MultiSenseLong::Code::DetectTransponder)
|
||||
{
|
||||
EventLoop::call(
|
||||
[this, multiSenseTransponder=static_cast<const MultiSenseLongTransponder&>(multiSense)]()
|
||||
[this, multiSense]()
|
||||
{
|
||||
m_identificationController->identificationEvent(
|
||||
IdentificationController::defaultIdentificationChannel,
|
||||
1 + multiSenseTransponder.sensorAddress(),
|
||||
multiSenseTransponder.isPresent() ? IdentificationEventType::Present : IdentificationEventType::Absent,
|
||||
multiSenseTransponder.transponderAddress(),
|
||||
multiSenseTransponder.transponderDirection(),
|
||||
1 + multiSense.sensorAddress(),
|
||||
multiSense.code() == MultiSenseLong::Code::DetectTransponder ? IdentificationEventType::Present : IdentificationEventType::Absent,
|
||||
multiSense.transponderAddress(),
|
||||
multiSense.transponderDirection(),
|
||||
0);
|
||||
});
|
||||
}
|
||||
|
||||
136
server/src/hardware/protocol/loconet/message/multisenselong.hpp
Normale Datei
136
server/src/hardware/protocol/loconet/message/multisenselong.hpp
Normale Datei
@ -0,0 +1,136 @@
|
||||
/**
|
||||
* server/src/hardware/protocol/loconet/message/multisenselong.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_LOCONET_MESSAGE_MULTISENSELONG_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_LOCONET_MESSAGE_MULTISENSELONG_HPP
|
||||
|
||||
#include "message.hpp"
|
||||
#include <traintastic/enum/direction.hpp>
|
||||
#include "../../railcom/appdynid.hpp"
|
||||
|
||||
namespace LocoNet {
|
||||
|
||||
struct MultiSenseLong : Message
|
||||
{
|
||||
enum class Code
|
||||
{
|
||||
ReleaseTransponder = 0x00,
|
||||
DetectTransponder = 0x20,
|
||||
RailComAppDyn = 0x40,
|
||||
Reserved = 0x60,
|
||||
};
|
||||
|
||||
uint8_t len;
|
||||
uint8_t data1;
|
||||
uint8_t data2;
|
||||
uint8_t data3;
|
||||
uint8_t data4;
|
||||
uint8_t data5;
|
||||
uint8_t data6;
|
||||
uint8_t checksum;
|
||||
|
||||
MultiSenseLong() :
|
||||
Message(OPC_MULTI_SENSE_LONG),
|
||||
len{9}
|
||||
{
|
||||
}
|
||||
|
||||
Code code() const
|
||||
{
|
||||
return static_cast<Code>(data1 & 0x60);
|
||||
}
|
||||
|
||||
uint16_t sensorAddress() const
|
||||
{
|
||||
return (static_cast<uint16_t>(data1 & 0x1F) << 7) | (data2 & 0x7F);
|
||||
}
|
||||
|
||||
uint16_t transponderAddress() const
|
||||
{
|
||||
if(isTransponderAddressLong())
|
||||
return (static_cast<uint16_t>(data3 & 0x7F) << 7) | (data4 & 0x7F);
|
||||
else
|
||||
return (data4 & 0x7F);
|
||||
}
|
||||
|
||||
bool isTransponderAddressLong() const
|
||||
{
|
||||
return data3 != 0xFD;
|
||||
}
|
||||
|
||||
Direction transponderDirection() const
|
||||
{
|
||||
return (data5 & 0x40) ? Direction::Forward : Direction::Reverse;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(MultiSenseLong) == 9);
|
||||
|
||||
struct MultiSenseLongRailComAppDyn : MultiSenseLong
|
||||
{
|
||||
RailCom::AppDynId appDynId() const
|
||||
{
|
||||
return static_cast<RailCom::AppDynId>((data5 >> 1) & 0x1F);
|
||||
}
|
||||
|
||||
uint8_t value() const
|
||||
{
|
||||
return ((data5 & 0x01) << 7) | data6;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(MultiSenseLongRailComAppDyn) == 9);
|
||||
|
||||
struct MultiSenseLongRailComAppDynActualSpeed : MultiSenseLongRailComAppDyn
|
||||
{
|
||||
uint16_t actualSpeed() const
|
||||
{
|
||||
if(appDynId() == RailCom::AppDynId::ActualSpeed)
|
||||
{
|
||||
return value();
|
||||
}
|
||||
assert(appDynId() == RailCom::AppDynId::ActualSpeedHigh);
|
||||
return 0x100 + value();
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(MultiSenseLongRailComAppDynActualSpeed) == 9);
|
||||
|
||||
}
|
||||
|
||||
constexpr std::string_view toString(LocoNet::MultiSenseLong::Code value)
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
case LocoNet::MultiSenseLong::Code::ReleaseTransponder:
|
||||
return "Release";
|
||||
|
||||
case LocoNet::MultiSenseLong::Code::DetectTransponder:
|
||||
return "Detect";
|
||||
|
||||
case LocoNet::MultiSenseLong::Code::RailComAppDyn:
|
||||
return "RailComAppDyn";
|
||||
|
||||
case LocoNet::MultiSenseLong::Code::Reserved:
|
||||
return "Reserved";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019-2022 Reinder Feenstra
|
||||
* Copyright (C) 2019-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
|
||||
@ -357,13 +357,26 @@ std::string toString(const Message& message)
|
||||
case OPC_MULTI_SENSE_LONG:
|
||||
{
|
||||
const MultiSenseLong& multiSense = static_cast<const MultiSenseLong&>(message);
|
||||
if(multiSense.isTransponder())
|
||||
s.append(::toString(multiSense.code()));
|
||||
s.append(" sensorAddress=").append(std::to_string(multiSense.sensorAddress()));
|
||||
s.append(" transponderAddress=").append(std::to_string(multiSense.transponderAddress()));
|
||||
s.append(" transponderDirection=").append(multiSense.transponderDirection() == Direction::Forward ? "fwd" : "rev");
|
||||
if(multiSense.code() == MultiSenseLong::Code::RailComAppDyn)
|
||||
{
|
||||
const MultiSenseLongTransponder& multiSenseTransponder = static_cast<const MultiSenseLongTransponder&>(multiSense);
|
||||
s.append(multiSenseTransponder.isPresent() ? " present" : " absent");
|
||||
s.append(" sensorAddress=").append(std::to_string(multiSenseTransponder.sensorAddress()));
|
||||
s.append(" transponderAddress=").append(std::to_string(multiSenseTransponder.transponderAddress()));
|
||||
s.append(" transponderDirection=").append(multiSenseTransponder.transponderDirection() == Direction::Forward ? "fwd" : "rev");
|
||||
const auto& multiSenseRailComAppDyn = static_cast<const MultiSenseLongRailComAppDyn&>(multiSense);
|
||||
s.append(" app_dyn=").append(std::to_string(static_cast<uint8_t>(multiSenseRailComAppDyn.appDynId())));
|
||||
if(auto sv = ::toString(multiSenseRailComAppDyn.appDynId()); !sv.empty())
|
||||
{
|
||||
s.append(" ()").append(sv).append(")");
|
||||
}
|
||||
if(RailCom::isAppDynActualSpeed(multiSenseRailComAppDyn.appDynId()))
|
||||
{
|
||||
s.append(" actual_speed=").append(std::to_string(static_cast<const MultiSenseLongRailComAppDynActualSpeed&>(multiSenseRailComAppDyn).actualSpeed()));
|
||||
}
|
||||
else
|
||||
{
|
||||
s.append(" value=").append(std::to_string(multiSenseRailComAppDyn.value()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
#include "message/locof9f12imm.hpp"
|
||||
#include "message/locof13f20imm.hpp"
|
||||
#include "message/locof21f28imm.hpp"
|
||||
#include "message/multisenselong.hpp"
|
||||
#include "message/uhlenbrock.hpp"
|
||||
|
||||
namespace LocoNet {
|
||||
@ -110,6 +111,7 @@ constexpr uint8_t SW2_DIR = 0x20;
|
||||
constexpr uint8_t MULTI_SENSE_TYPE_MASK = 0xE0;
|
||||
constexpr uint8_t MULTI_SENSE_TYPE_TRANSPONDER_GONE = 0x00;
|
||||
constexpr uint8_t MULTI_SENSE_TYPE_TRANSPONDER_PRESENT = 0x20;
|
||||
constexpr uint8_t MULTI_SENSE_LONG_TYPE_RAILCOM_APP_DYN = 0x40;
|
||||
constexpr uint8_t MULTI_SENSE_TRANSPONDER_ADDRESS_SHORT = 0xFD;
|
||||
|
||||
struct SlotMessage : Message
|
||||
@ -1059,64 +1061,6 @@ struct MultiSenseTransponder : MultiSense
|
||||
};
|
||||
static_assert(sizeof(MultiSenseTransponder) == 6);
|
||||
|
||||
struct MultiSenseLong : Message
|
||||
{
|
||||
uint8_t len;
|
||||
uint8_t data1;
|
||||
uint8_t data2;
|
||||
uint8_t data3;
|
||||
uint8_t data4;
|
||||
uint8_t data5;
|
||||
uint8_t data6;
|
||||
uint8_t checksum;
|
||||
|
||||
MultiSenseLong() :
|
||||
Message(OPC_MULTI_SENSE_LONG),
|
||||
len{9}
|
||||
{
|
||||
}
|
||||
|
||||
bool isTransponder() const
|
||||
{
|
||||
return
|
||||
((data1 & MULTI_SENSE_TYPE_MASK) == MULTI_SENSE_TYPE_TRANSPONDER_GONE) ||
|
||||
((data1 & MULTI_SENSE_TYPE_MASK) == MULTI_SENSE_TYPE_TRANSPONDER_PRESENT);
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(MultiSenseLong) == 9);
|
||||
|
||||
struct MultiSenseLongTransponder : MultiSenseLong
|
||||
{
|
||||
bool isPresent() const
|
||||
{
|
||||
return (data1 & MULTI_SENSE_TYPE_MASK) == MULTI_SENSE_TYPE_TRANSPONDER_PRESENT;
|
||||
}
|
||||
|
||||
uint16_t sensorAddress() const
|
||||
{
|
||||
return (static_cast<uint16_t>(data1 & 0x1F) << 7) | (data2 & 0x7F);
|
||||
}
|
||||
|
||||
uint16_t transponderAddress() const
|
||||
{
|
||||
if(isTransponderAddressLong())
|
||||
return (static_cast<uint16_t>(data3 & 0x7F) << 7) | (data4 & 0x7F);
|
||||
else
|
||||
return (data4 & 0x7F);
|
||||
}
|
||||
|
||||
bool isTransponderAddressLong() const
|
||||
{
|
||||
return data3 != MULTI_SENSE_TRANSPONDER_ADDRESS_SHORT;
|
||||
}
|
||||
|
||||
Direction transponderDirection() const
|
||||
{
|
||||
return (data5 & 0x40) ? Direction::Forward : Direction::Reverse;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(MultiSenseLongTransponder) == 9);
|
||||
|
||||
struct SlotReadDataBase : Message
|
||||
{
|
||||
uint8_t len;
|
||||
|
||||
119
server/src/hardware/protocol/railcom/appdynid.hpp
Normale Datei
119
server/src/hardware/protocol/railcom/appdynid.hpp
Normale Datei
@ -0,0 +1,119 @@
|
||||
/**
|
||||
* server/src/hardware/protocol/railcom/appdynid.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_RAILCOM_APPDYNID_HPP
|
||||
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_RAILCOM_APPDYNID_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include "../../../utils/inrange.hpp"
|
||||
|
||||
namespace RailCom {
|
||||
|
||||
enum class AppDynId : uint8_t
|
||||
{
|
||||
ActualSpeed = 0,
|
||||
ActualSpeedHigh = 1,
|
||||
QualityOfService = 7,
|
||||
Container1 = 8,
|
||||
Container2 = 9,
|
||||
Container3 = 10,
|
||||
Container4 = 11,
|
||||
Container5 = 12,
|
||||
Container6 = 13,
|
||||
Container7 = 14,
|
||||
Container8 = 15,
|
||||
Container9 = 16,
|
||||
Container10 = 17,
|
||||
Container11 = 18,
|
||||
Container12 = 19,
|
||||
};
|
||||
|
||||
constexpr bool isAppDynActualSpeed(AppDynId value)
|
||||
{
|
||||
return
|
||||
(value == RailCom::AppDynId::ActualSpeed) ||
|
||||
(value == RailCom::AppDynId::ActualSpeedHigh);
|
||||
}
|
||||
|
||||
constexpr bool isAppDynContainer(AppDynId value)
|
||||
{
|
||||
return inRange(
|
||||
static_cast<uint8_t>(value),
|
||||
static_cast<uint8_t>(RailCom::AppDynId::Container1),
|
||||
static_cast<uint8_t>(RailCom::AppDynId::Container12));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
constexpr std::string_view toString(RailCom::AppDynId value)
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
case RailCom::AppDynId::ActualSpeed:
|
||||
return "ActualSpeed";
|
||||
|
||||
case RailCom::AppDynId::ActualSpeedHigh:
|
||||
return "ActualSpeedHigh";
|
||||
|
||||
case RailCom::AppDynId::QualityOfService:
|
||||
return "QualityOfService";
|
||||
|
||||
case RailCom::AppDynId::Container1:
|
||||
return "Container1";
|
||||
|
||||
case RailCom::AppDynId::Container2:
|
||||
return "Container2";
|
||||
|
||||
case RailCom::AppDynId::Container3:
|
||||
return "Container3";
|
||||
|
||||
case RailCom::AppDynId::Container4:
|
||||
return "Container4";
|
||||
|
||||
case RailCom::AppDynId::Container5:
|
||||
return "Container5";
|
||||
|
||||
case RailCom::AppDynId::Container6:
|
||||
return "Container6";
|
||||
|
||||
case RailCom::AppDynId::Container7:
|
||||
return "Container7";
|
||||
|
||||
case RailCom::AppDynId::Container8:
|
||||
return "Container8";
|
||||
|
||||
case RailCom::AppDynId::Container9:
|
||||
return "Container9";
|
||||
|
||||
case RailCom::AppDynId::Container10:
|
||||
return "Container10";
|
||||
|
||||
case RailCom::AppDynId::Container11:
|
||||
return "Container11";
|
||||
|
||||
case RailCom::AppDynId::Container12:
|
||||
return "Container12";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
#endif
|
||||
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren