A2B: Add A2B message initial support

add-device-sharing
Yasser Yassine 2022-10-11 11:20:04 -04:00
parent 3b9a31ef51
commit 3b80746fb8
7 changed files with 269 additions and 0 deletions

View File

@ -175,6 +175,7 @@ set(SRC_FILES
communication/message/ethphymessage.cpp
communication/packet/flexraypacket.cpp
communication/packet/canpacket.cpp
communication/packet/a2bpacket.cpp
communication/packet/ethernetpacket.cpp
communication/packet/versionpacket.cpp
communication/packet/iso9141packet.cpp

View File

@ -7,10 +7,12 @@
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
#include "icsneo/communication/message/wiviresponsemessage.h"
#include "icsneo/communication/message/a2bmessage.h"
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
#include "icsneo/communication/command.h"
#include "icsneo/device/device.h"
#include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/packet/a2bpacket.h"
#include "icsneo/communication/packet/ethernetpacket.h"
#include "icsneo/communication/packet/flexraypacket.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;
}
}
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

View File

@ -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;
}

View File

@ -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

View File

@ -147,6 +147,7 @@ public:
SWCAN = 8,
ISO9141 = 9,
I2C = 10,
A2B = 11,
Any = 0xFE, // Never actually set as type, but used as flag for filtering
Other = 0xFF
};
@ -234,6 +235,8 @@ public:
return "Single Wire CAN";
case Type::I2C:
return "I²C";
case Type::A2B:
return "A2B";
case Type::Invalid:
default:
return "Invalid Type";
@ -318,6 +321,9 @@ public:
case NetID::I2C3:
case NetID::I2C4:
return Type::I2C;
case NetID::A2B1:
case NetID::A2B2:
return Type::A2B;
default:
return Type::Other;
}

View File

@ -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

View File

@ -16,6 +16,7 @@
#include "icsneo/communication/message/iso9141message.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
#include "icsneo/communication/message/ethphymessage.h"
#include "icsneo/communication/message/a2bmessage.h"
namespace icsneo {