A2B: Add A2B message initial support
parent
3b9a31ef51
commit
3b80746fb8
|
|
@ -175,6 +175,7 @@ set(SRC_FILES
|
||||||
communication/message/ethphymessage.cpp
|
communication/message/ethphymessage.cpp
|
||||||
communication/packet/flexraypacket.cpp
|
communication/packet/flexraypacket.cpp
|
||||||
communication/packet/canpacket.cpp
|
communication/packet/canpacket.cpp
|
||||||
|
communication/packet/a2bpacket.cpp
|
||||||
communication/packet/ethernetpacket.cpp
|
communication/packet/ethernetpacket.cpp
|
||||||
communication/packet/versionpacket.cpp
|
communication/packet/versionpacket.cpp
|
||||||
communication/packet/iso9141packet.cpp
|
communication/packet/iso9141packet.cpp
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,12 @@
|
||||||
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
|
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
|
||||||
#include "icsneo/communication/message/extendedresponsemessage.h"
|
#include "icsneo/communication/message/extendedresponsemessage.h"
|
||||||
#include "icsneo/communication/message/wiviresponsemessage.h"
|
#include "icsneo/communication/message/wiviresponsemessage.h"
|
||||||
|
#include "icsneo/communication/message/a2bmessage.h"
|
||||||
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
|
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
|
||||||
#include "icsneo/communication/command.h"
|
#include "icsneo/communication/command.h"
|
||||||
#include "icsneo/device/device.h"
|
#include "icsneo/device/device.h"
|
||||||
#include "icsneo/communication/packet/canpacket.h"
|
#include "icsneo/communication/packet/canpacket.h"
|
||||||
|
#include "icsneo/communication/packet/a2bpacket.h"
|
||||||
#include "icsneo/communication/packet/ethernetpacket.h"
|
#include "icsneo/communication/packet/ethernetpacket.h"
|
||||||
#include "icsneo/communication/packet/flexraypacket.h"
|
#include "icsneo/communication/packet/flexraypacket.h"
|
||||||
#include "icsneo/communication/packet/iso9141packet.h"
|
#include "icsneo/communication/packet/iso9141packet.h"
|
||||||
|
|
@ -321,6 +323,18 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case Network::Type::A2B: {
|
||||||
|
result = HardwareA2BPacket::DecodeToMessage(packet->data);
|
||||||
|
|
||||||
|
if(!result) {
|
||||||
|
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
||||||
|
return false; // A nullptr was returned, the packet was not long enough to decode
|
||||||
|
}
|
||||||
|
|
||||||
|
A2BMessage& msg = *static_cast<A2BMessage*>(result.get());
|
||||||
|
msg.network = packet->network;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For the moment other types of messages will automatically be decoded as raw messages
|
// For the moment other types of messages will automatically be decoded as raw messages
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
#include "icsneo/communication/packet/a2bpacket.h"
|
||||||
|
#include "icsneo/communication/message/a2bmessage.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
using namespace icsneo;
|
||||||
|
|
||||||
|
std::shared_ptr<Message> HardwareA2BPacket::DecodeToMessage(const std::vector<uint8_t> &bytestream)
|
||||||
|
{
|
||||||
|
|
||||||
|
constexpr uint8_t coreMiniMessageHeaderSize = 28;
|
||||||
|
|
||||||
|
if(bytestream.size() < coreMiniMessageHeaderSize)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto getSampleFromBytes = [](uint8_t bytesPerSample, const uint8_t *bytes) {
|
||||||
|
A2BPCMSample result = 0;
|
||||||
|
|
||||||
|
for(auto i = 0; i < bytesPerSample; i++)
|
||||||
|
{
|
||||||
|
result |= bytes[i] << (i * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const HardwareA2BPacket *data = (const HardwareA2BPacket*)bytestream.data();
|
||||||
|
|
||||||
|
uint32_t totalPackedLength = static_cast<uint32_t>(bytestream.size()) - static_cast<uint32_t>(coreMiniMessageHeaderSize); // First 28 bytes are message header.
|
||||||
|
|
||||||
|
uint8_t bytesPerChannel = data->header.channelSize16 ? 2 : 4;
|
||||||
|
uint8_t numChannels = data->header.channelNum;
|
||||||
|
uint8_t bitDepth = data->header.channelSize16 ? A2BPCM_L16 : A2BPCM_L24;
|
||||||
|
bool monitor = data->header.monitor;
|
||||||
|
|
||||||
|
std::shared_ptr<A2BMessage> msg = std::make_shared<A2BMessage>(bitDepth, bytesPerChannel, numChannels, monitor);
|
||||||
|
|
||||||
|
const uint8_t *bytes = bytestream.data();
|
||||||
|
bytes+=coreMiniMessageHeaderSize;
|
||||||
|
|
||||||
|
uint8_t channel = 0;
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < totalPackedLength; i += 2 * static_cast<uint32_t>(bytesPerChannel), bytes += 2 * bytesPerChannel, channel = (channel + 1) % numChannels)
|
||||||
|
{
|
||||||
|
|
||||||
|
msg->addSample(
|
||||||
|
getSampleFromBytes(bytesPerChannel, bytes),
|
||||||
|
A2BMessage::A2BDirection::DownStream,
|
||||||
|
channel
|
||||||
|
);
|
||||||
|
|
||||||
|
msg->addSample(
|
||||||
|
getSampleFromBytes(bytesPerChannel, bytes + bytesPerChannel),
|
||||||
|
A2BMessage::A2BDirection::UpStream,
|
||||||
|
channel
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
#ifndef __A2BMESSAGE_H_
|
||||||
|
#define __A2BMESSAGE_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include "icsneo/communication/message/message.h"
|
||||||
|
|
||||||
|
#define A2BMESSAGE_UPSTREAM 1
|
||||||
|
#define A2BMESSAGE_DOWNSTREAM 0
|
||||||
|
|
||||||
|
#define A2BPCM_L16 16
|
||||||
|
#define A2BPCM_L24 24
|
||||||
|
|
||||||
|
#define A2BPCM_SAMPLERATE_44100 44100
|
||||||
|
#define A2BPCM_SAMPLERATE_48000 48000
|
||||||
|
|
||||||
|
namespace icsneo
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef uint32_t A2BPCMSample;
|
||||||
|
typedef std::vector<A2BPCMSample> ChannelBuffer;
|
||||||
|
|
||||||
|
class A2BMessage : public Frame
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class A2BDirection : uint8_t
|
||||||
|
{
|
||||||
|
DownStream = 0,
|
||||||
|
UpStream = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
A2BMessage() = delete;
|
||||||
|
|
||||||
|
A2BMessage(uint8_t bitDepth, uint8_t bytesPerSample, uint8_t numChannels, bool monitor) :
|
||||||
|
mBitDepth(bitDepth),
|
||||||
|
mBytesPerSample(bytesPerSample),
|
||||||
|
mMonitor(monitor)
|
||||||
|
{
|
||||||
|
downstream.resize(numChannels);
|
||||||
|
upstream.resize(numChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addSample(A2BPCMSample &&sample, A2BDirection dir, uint8_t channel)
|
||||||
|
{
|
||||||
|
if(dir == A2BDirection::DownStream)
|
||||||
|
{
|
||||||
|
downstream[channel].push_back(std::move(sample));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
upstream[channel].push_back(std::move(sample));
|
||||||
|
}
|
||||||
|
totalSamples++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const A2BPCMSample *getSamples(A2BDirection dir, uint8_t channel) const
|
||||||
|
{
|
||||||
|
if(channel >= getNumChannels())
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dir == A2BDirection::DownStream)
|
||||||
|
{
|
||||||
|
return downstream[channel].data();
|
||||||
|
}
|
||||||
|
return upstream[channel].data();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<A2BPCMSample> getSample(A2BDirection dir, uint8_t channel, uint32_t sampleIndex) const
|
||||||
|
{
|
||||||
|
const A2BPCMSample *samples = getSamples(dir, channel);
|
||||||
|
auto numSamplesInChannel = getNumSamplesInChannel(dir, channel);
|
||||||
|
|
||||||
|
if(
|
||||||
|
samples == nullptr ||
|
||||||
|
sampleIndex >= numSamplesInChannel.value_or(0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples[sampleIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::size_t> getNumSamplesInChannel(A2BDirection dir, uint8_t channel) const
|
||||||
|
{
|
||||||
|
if(channel >= getNumChannels())
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dir == A2BDirection::DownStream)
|
||||||
|
{
|
||||||
|
return downstream[channel].size();
|
||||||
|
}
|
||||||
|
|
||||||
|
return upstream[channel].size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getNumSamples() const
|
||||||
|
{
|
||||||
|
return totalSamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getNumChannels() const
|
||||||
|
{
|
||||||
|
return static_cast<uint8_t>(downstream.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getBitDepth() const
|
||||||
|
{
|
||||||
|
return mBitDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getBytesPerSample() const
|
||||||
|
{
|
||||||
|
return mBytesPerSample;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isMonitor() const
|
||||||
|
{
|
||||||
|
return mMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<ChannelBuffer> downstream;
|
||||||
|
std::vector<ChannelBuffer> upstream;
|
||||||
|
size_t totalSamples = 0;
|
||||||
|
|
||||||
|
uint8_t mBitDepth;
|
||||||
|
uint8_t mBytesPerSample;
|
||||||
|
bool mMonitor;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -147,6 +147,7 @@ public:
|
||||||
SWCAN = 8,
|
SWCAN = 8,
|
||||||
ISO9141 = 9,
|
ISO9141 = 9,
|
||||||
I2C = 10,
|
I2C = 10,
|
||||||
|
A2B = 11,
|
||||||
Any = 0xFE, // Never actually set as type, but used as flag for filtering
|
Any = 0xFE, // Never actually set as type, but used as flag for filtering
|
||||||
Other = 0xFF
|
Other = 0xFF
|
||||||
};
|
};
|
||||||
|
|
@ -234,6 +235,8 @@ public:
|
||||||
return "Single Wire CAN";
|
return "Single Wire CAN";
|
||||||
case Type::I2C:
|
case Type::I2C:
|
||||||
return "I²C";
|
return "I²C";
|
||||||
|
case Type::A2B:
|
||||||
|
return "A2B";
|
||||||
case Type::Invalid:
|
case Type::Invalid:
|
||||||
default:
|
default:
|
||||||
return "Invalid Type";
|
return "Invalid Type";
|
||||||
|
|
@ -318,6 +321,9 @@ public:
|
||||||
case NetID::I2C3:
|
case NetID::I2C3:
|
||||||
case NetID::I2C4:
|
case NetID::I2C4:
|
||||||
return Type::I2C;
|
return Type::I2C;
|
||||||
|
case NetID::A2B1:
|
||||||
|
case NetID::A2B2:
|
||||||
|
return Type::A2B;
|
||||||
default:
|
default:
|
||||||
return Type::Other;
|
return Type::Other;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef __A2BPACKET_H__
|
||||||
|
#define __A2BPACKET_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include "icsneo/api/eventmanager.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include "icsneo/communication/message/message.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace icsneo {
|
||||||
|
|
||||||
|
typedef uint16_t icscm_bitfield;
|
||||||
|
|
||||||
|
struct HardwareA2BPacket {
|
||||||
|
|
||||||
|
static std::shared_ptr<Message> DecodeToMessage(const std::vector<uint8_t>& bytestream);
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
// CxA2B
|
||||||
|
icscm_bitfield channelNum : 8;
|
||||||
|
icscm_bitfield channelSize16 : 1;
|
||||||
|
icscm_bitfield : 7;
|
||||||
|
|
||||||
|
// CxA2B2
|
||||||
|
icscm_bitfield monitor : 1;
|
||||||
|
icscm_bitfield txmsg : 1;
|
||||||
|
icscm_bitfield errIndicator : 1;
|
||||||
|
icscm_bitfield syncFrame : 1;
|
||||||
|
icscm_bitfield upstream : 1;
|
||||||
|
icscm_bitfield : 11;
|
||||||
|
icscm_bitfield rfu2;
|
||||||
|
} header;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
#include "icsneo/communication/message/iso9141message.h"
|
#include "icsneo/communication/message/iso9141message.h"
|
||||||
#include "icsneo/communication/message/canerrorcountmessage.h"
|
#include "icsneo/communication/message/canerrorcountmessage.h"
|
||||||
#include "icsneo/communication/message/ethphymessage.h"
|
#include "icsneo/communication/message/ethphymessage.h"
|
||||||
|
#include "icsneo/communication/message/a2bmessage.h"
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue