diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fa56a2..aad5af1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/communication/decoder.cpp b/communication/decoder.cpp index 91f2d6f..138a0e9 100644 --- a/communication/decoder.cpp +++ b/communication/decoder.cpp @@ -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& result, const std::shared_ptrdata); + + 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(result.get()); + msg.network = packet->network; + return true; + } } // For the moment other types of messages will automatically be decoded as raw messages diff --git a/communication/packet/a2bpacket.cpp b/communication/packet/a2bpacket.cpp new file mode 100644 index 0000000..916724c --- /dev/null +++ b/communication/packet/a2bpacket.cpp @@ -0,0 +1,63 @@ +#include "icsneo/communication/packet/a2bpacket.h" +#include "icsneo/communication/message/a2bmessage.h" +#include + +using namespace icsneo; + +std::shared_ptr HardwareA2BPacket::DecodeToMessage(const std::vector &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(bytestream.size()) - static_cast(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 msg = std::make_shared(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(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; +} diff --git a/include/icsneo/communication/message/a2bmessage.h b/include/icsneo/communication/message/a2bmessage.h new file mode 100644 index 0000000..5082990 --- /dev/null +++ b/include/icsneo/communication/message/a2bmessage.h @@ -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 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 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 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(downstream.size()); + } + + uint8_t getBitDepth() const + { + return mBitDepth; + } + + uint8_t getBytesPerSample() const + { + return mBytesPerSample; + } + + bool isMonitor() const + { + return mMonitor; + } + +private: + std::vector downstream; + std::vector upstream; + size_t totalSamples = 0; + + uint8_t mBitDepth; + uint8_t mBytesPerSample; + bool mMonitor; +}; + +} + +#endif // __cplusplus + +#endif \ No newline at end of file diff --git a/include/icsneo/communication/network.h b/include/icsneo/communication/network.h index b6eb1a8..a3c7f81 100644 --- a/include/icsneo/communication/network.h +++ b/include/icsneo/communication/network.h @@ -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; } diff --git a/include/icsneo/communication/packet/a2bpacket.h b/include/icsneo/communication/packet/a2bpacket.h new file mode 100644 index 0000000..da90bb3 --- /dev/null +++ b/include/icsneo/communication/packet/a2bpacket.h @@ -0,0 +1,44 @@ +#ifndef __A2BPACKET_H__ +#define __A2BPACKET_H__ + +#ifdef __cplusplus + +#include "icsneo/api/eventmanager.h" +#include +#include +#include +#include "icsneo/communication/message/message.h" + + + +namespace icsneo { + +typedef uint16_t icscm_bitfield; + +struct HardwareA2BPacket { + + static std::shared_ptr DecodeToMessage(const std::vector& 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 \ No newline at end of file diff --git a/include/icsneo/icsneocpp.h b/include/icsneo/icsneocpp.h index ed5636f..1f33c26 100644 --- a/include/icsneo/icsneocpp.h +++ b/include/icsneo/icsneocpp.h @@ -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 {