36 m_vcs[vcInd].vcStructIndex = vcInd;
50 FW_ASSERT(fixedFrameSize > minSize, static_cast<FwAssertArgType>(fixedFrameSize),
51 static_cast<FwAssertArgType>(minSize));
54 FW_ASSERT((spacecraftId & 0xFC00) == 0, static_cast<FwAssertArgType>(spacecraftId));
57 FW_ASSERT((vcId & 0xC0) == 0, static_cast<FwAssertArgType>(vcId));
67 m_fixedFrameSize = fixedFrameSize;
68 m_fecfEnabled = frameErrorControlField;
69 m_spacecraftId = spacecraftId;
75 m_vcs[0].virtualChannelId = vcId;
76 m_vcs[0].pvnMask = pvnMask;
80 m_vcs[vcInd].framesProcessed = 0;
81 m_vcs[vcInd].packetsExtracted = 0;
82 m_vcs[vcInd].vcFrameCount = 0;
85 this->abandonSpanningPacket(m_vcs[vcInd]);
96 FW_ASSERT(m_fixedFrameSize > 0, static_cast<FwAssertArgType>(m_fixedFrameSize));
98 if (data.
getSize() < m_fixedFrameSize) {
108 const bool fecfValid = this->validateFecf(data);
119 AosDeframerVc* vc = this->parseAndValidateHeader(data, packetContext);
127 if (!vc->spanningPacket.buffer.isValid()) {
128 vc->spanningPacket.context = packetContext;
132 this->extractPackets(*vc, data);
150 void AosDeframer::notifyErrorIfConnected(Ccsds::FrameError error) {
156 void AosDeframer::abandonSpanningPacket(AosDeframerVc& vc) {
157 if (vc.spanningPacket.buffer.isValid()) {
159 vc.spanningPacket.bytesReceived,
160 vc.spanningPacket.buffer.getSize());
164 vc.spanningPacket.bytesReceived = 0;
168 AosDeframer::AosDeframerVc* AosDeframer::getVcStruct(
const U8 vcId) {
170 if (m_vcs[vcInd].virtualChannelId == vcId) {
171 return &m_vcs[vcInd];
189 if (tfvn != static_cast<U8>(
Tfvn::AOS)) {
198 const U16 spacecraftId =
204 if (spacecraftId != m_spacecraftId) {
212 AosDeframerVc* vc = this->getVcStruct(vcId);
227 U32 frameCountMask = 0x00FF
'FFFF; 229 // Extract VC Frame Count Cycle if in use (Section 4.1.2.5.3) 230 if ((header.get_frameCountAndSignaling() & AOSHeaderSubfields::cycleCountFlagMask) != 0) { 231 const U8 rxVcFrameCountCycle = header.get_frameCountAndSignaling() & AOSHeaderSubfields::vcFrameCountCycleMask; 232 // Extend the 24-bit frame count with the 4-bit cycle count 233 rxVcFrameCount |= static_cast<U32>(rxVcFrameCountCycle) << 24; 234 // Add the 4 additional bits to our modulo 235 frameCountMask |= 0x0F00'0000;
239 if (vc->framesProcessed > 0U) {
240 const U32 expectedVcFrameCount = vc->vcFrameCount + 1U;
241 if (rxVcFrameCount != (expectedVcFrameCount & frameCountMask)) {
242 this->log_WARNING_HI_VcFrameCountGap(vcId, rxVcFrameCount, expectedVcFrameCount);
245 this->abandonSpanningPacket(*vc);
250 vc->vcFrameCount = rxVcFrameCount;
251 this->tlmWrite_LatestVcFrameCount(vc->vcFrameCount);
259 bool AosDeframer::validateFecf(
Fw::Buffer& data) {
263 const FwSizeType crcDataLen = m_fixedFrameSize - AOSTrailer::SERIALIZED_SIZE;
271 status = deserializer.deserializeTo(trailer);
274 U16 transmittedCrc = trailer.get_fecf();
275 if (transmittedCrc != computedCrc) {
276 this->log_WARNING_HI_InvalidFecf(transmittedCrc, computedCrc);
278 this->tlmWrite_CrcErrorCount(++m_crcErrorCount);
287 FW_ASSERT(size > 0, static_cast<FwAssertArgType>(size));
293 if (!vc.spanningPacket.buffer.isValid()) {
295 const FwSizeType headerCap = AosDeframerVc::SpanningPacketState::HEADER_BUF_SIZE;
297 const FwSizeType toHeader =
FW_MIN(size, headerCap - vc.spanningPacket.bytesReceived);
299 FW_ASSERT(vc.spanningPacket.bytesReceived < headerCap,
300 static_cast<FwAssertArgType>(vc.spanningPacket.bytesReceived),
301 static_cast<FwAssertArgType>(headerCap));
302 FW_ASSERT(toHeader <= headerCap, static_cast<FwAssertArgType>(toHeader),
303 static_cast<FwAssertArgType>(headerCap));
304 FW_ASSERT(vc.spanningPacket.bytesReceived + toHeader <= headerCap,
305 static_cast<FwAssertArgType>(vc.spanningPacket.bytesReceived),
306 static_cast<FwAssertArgType>(toHeader), static_cast<FwAssertArgType>(headerCap));
307 (void)::memcpy(vc.spanningPacket.headerBuf + vc.spanningPacket.bytesReceived, data, toHeader);
308 vc.spanningPacket.bytesReceived += toHeader;
313 seekForward += toHeader;
318 const FwSizeType packetSize = sizePacket(vc, vc.spanningPacket.headerBuf, vc.spanningPacket.bytesReceived);
319 if (packetSize == 0) {
325 if (packetSize < vc.spanningPacket.bytesReceived) {
326 const FwSizeType surplus = vc.spanningPacket.bytesReceived - packetSize;
328 FW_ASSERT(surplus <= toHeader, static_cast<FwAssertArgType>(surplus),
329 static_cast<FwAssertArgType>(toHeader));
330 vc.spanningPacket.bytesReceived = packetSize;
333 seekForward -= surplus;
338 vc.spanningPacket.buffer = this->allocate_out(0, packetSize);
339 if ((not vc.spanningPacket.buffer.isValid()) || (vc.spanningPacket.buffer.getSize() < packetSize)) {
340 this->log_WARNING_HI_SpanningPacketAllocFailed(vc.virtualChannelId, vc.spanningPacket.context.get_pvn(),
343 const FwSizeType remainingBody = packetSize - vc.spanningPacket.bytesReceived;
344 this->abandonSpanningPacket(vc);
347 const FwSizeType remainingLength = seekForward + remainingBody;
348 if (remainingBody > size) {
351 return remainingLength;
356 FW_ASSERT(vc.spanningPacket.bytesReceived <= AosDeframerVc::SpanningPacketState::HEADER_BUF_SIZE,
357 static_cast<FwAssertArgType>(vc.spanningPacket.bytesReceived),
358 AosDeframerVc::SpanningPacketState::HEADER_BUF_SIZE);
362 FW_ASSERT(vc.spanningPacket.bytesReceived <= vc.spanningPacket.buffer.getSize(),
364 static_cast<FwAssertArgType>(vc.spanningPacket.buffer.getSize()));
365 (void)::memcpy(vc.spanningPacket.buffer.getData(), vc.spanningPacket.headerBuf,
366 vc.spanningPacket.bytesReceived);
370 const FwSizeType spaceLeft = vc.spanningPacket.buffer.getSize() - vc.spanningPacket.bytesReceived;
374 FW_ASSERT(vc.spanningPacket.bytesReceived + toBody <= vc.spanningPacket.buffer.getSize(),
375 static_cast<FwAssertArgType>(vc.spanningPacket.bytesReceived), static_cast<FwAssertArgType>(toBody),
377 (void)::memcpy(vc.spanningPacket.buffer.getData() + vc.spanningPacket.bytesReceived, data, toBody);
378 vc.spanningPacket.bytesReceived += toBody;
379 seekForward += toBody;
383 if (vc.spanningPacket.buffer.getSize() > 0 &&
384 vc.spanningPacket.bytesReceived >= vc.spanningPacket.buffer.getSize()) {
385 this->dataOut_out(0, vc.spanningPacket.buffer, vc.spanningPacket.context);
386 this->tlmWrite_PacketsExtracted(++vc.packetsExtracted);
391 this->abandonSpanningPacket(vc);
397 void AosDeframer::extractPackets(AosDeframerVc& vc,
Fw::Buffer& data) {
399 M_PDUHeader mpduHeader;
403 status = deserializer.deserializeTo(mpduHeader);
406 U16 firstHeaderPointer = mpduHeader.get_firstHeaderPointer();
409 const FwSizeType dataZoneStart = AOSHeader::SERIALIZED_SIZE + M_PDUHeader::SERIALIZED_SIZE;
410 const FwSizeType dataZoneEnd = m_fixedFrameSize - (m_fecfEnabled ? AOSTrailer::SERIALIZED_SIZE : 0);
411 const FwSizeType dataZoneSize = dataZoneEnd - dataZoneStart;
412 U8* dataZone = data.
getData() + dataZoneStart;
417 this->log_ACTIVITY_LO_IdleFrame(vc.virtualChannelId);
423 if (vc.spanningPacket.bytesReceived > 0) {
424 (void)this->appendToSpanningPacket(vc, dataZone, dataZoneSize);
431 if (firstHeaderPointer >= dataZoneSize) {
432 this->log_WARNING_HI_InvalidFhp(vc.virtualChannelId, firstHeaderPointer, dataZoneSize);
435 this->abandonSpanningPacket(vc);
440 if (firstHeaderPointer > 0 && vc.spanningPacket.bytesReceived > 0) {
441 (void)this->appendToSpanningPacket(vc, dataZone, static_cast<FwSizeType>(firstHeaderPointer));
443 this->abandonSpanningPacket(vc);
447 FwSizeType currentOffset = firstHeaderPointer;
454 for (
FwIndexType iter = 0; iter < maxIters && currentOffset < dataZoneSize; iter++) {
456 this->abandonSpanningPacket(vc);
458 U8* packetStart = dataZone + currentOffset;
459 FwSizeType remainingBytes = dataZoneSize - currentOffset;
461 FwSizeType packetSize = this->appendToSpanningPacket(vc, packetStart, remainingBytes);
463 if (packetSize == 0) {
468 currentOffset += packetSize;
474 FW_ASSERT(remainingBytes > 0, static_cast<FwAssertArgType>(remainingBytes));
477 U8 pvn = getPacketVersion(packetStart[0]);
482 if (~vc.pvnMask & (1 << pvn)) {
483 this->log_WARNING_HI_DisabledPvn(vc.virtualChannelId, pvn);
488 vc.spanningPacket.context.set_pvn(pvnEnum);
493 return sizeSppPacket(packetStart, remainingBytes);
496 return sizeEppPacket(packetStart, remainingBytes);
507 SpacePacketHeader header;
521 constexpr
FwSizeType MAX_LENGTH = std::numeric_limits<FwSizeType>::max() - SpacePacketHeader::SERIALIZED_SIZE;
522 static_assert(MAX_LENGTH >= std::numeric_limits<U16>::max() + 1,
523 "FwSizeType must be wide enough to hold the maximum SPP packet size without overflow");
524 FwSizeType totalPacketSize = SpacePacketHeader::SERIALIZED_SIZE + header.get_packetDataLength() + 1;
537 return totalPacketSize;
544 FW_ASSERT(payloadSize > 0, static_cast<FwAssertArgType>(payloadSize));
547 U8 firstByte = payloadStart[0];
553 if (protocolId == static_cast<U8>(EppProtocolId::Idle)) {
560 U8 lengthOffset = 1U;
563 if (lengthOfLength >= EppLengthOfLength::Two) {
564 lengthOffset =
static_cast<U8>(lengthOffset + 1U);
568 if (lengthOfLength == EppLengthOfLength::Four) {
569 lengthOffset =
static_cast<U8>(lengthOffset + 2U);
575 const U8 headerLength =
static_cast<U8>(lengthOffset + lengthOfLength);
578 if (payloadSize < headerLength) {
583 U32 packetDataLength = 0;
584 for (
U8 i = 0; i < lengthOfLength; i++) {
585 packetDataLength = (packetDataLength << 8) | payloadStart[lengthOffset + i];
590 if (packetDataLength > (std::numeric_limits<FwSizeType>::max() -
static_cast<FwSizeType>(headerLength))) {
600 totalPacketSize =
static_cast<FwSizeType>(headerLength) + static_cast<FwSizeType>(packetDataLength);
602 return totalPacketSize;
605 U8 AosDeframer::getPacketVersion(
U8 firstByte) {
Serialization/Deserialization operation was successful.
static U16 compute(const U8 *buffer, U32 length)
compute CRC16 for a buffer
void log_WARNING_HI_SpanningPacketAbandoned(U8 vcId, const ComCfg::Pvn &pvn, FwSizeType bytesReceived, FwSizeType bytesExpected) const
CCSDS 732.0-B-5: Transfer Frame Version Number mismatch (4.1.2.2.2)
Fully Featured CCSDS Space Packet Protocol.
Advanced Orbiting Systems SDL.
PlatformSizeType FwSizeType
CCSDS 732.0-B-5: Frame length insufficient.
CCSDS 732.0-B-5: Frame Error Control Field CRC mismatch (4.1.6)
Anything equal or higher value is invalid and should not be used.
SerializeStatus deserializeTo(U8 &val, Endianness mode=Endianness::BIG) override
Deserialize an 8-bit unsigned integer value.
~AosDeframer()
Destroy AosDeframer object.
void configure(U32 fixedFrameSize, bool frameErrorControlField, U16 spacecraftId=ComCfg::SpacecraftId, U8 vcId=0, U8 pvnMask=PvnBitfield::SPP_MASK|PvnBitfield::EPP_MASK)
Configure the AosDeframer with mission-specific parameters.
bool isConnected_errorNotify_OutputPort(FwIndexType portNum) const
Auto-generated base for AosDeframer component.
CCSDS 732.0-B-5: Virtual Channel ID mismatch (4.1.2.3)
void log_WARNING_LO_InvalidSpacecraftId(U16 transmitted, U16 configured) const
SerializeStatus
forward declaration for string
ExternalSerializeBufferWithMemberCopy getDeserializer()
bool isConnected_allocate_OutputPort(FwIndexType portNum) const
void tlmWrite_FramesProcessed(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
void log_WARNING_HI_InvalidFrameLength(FwSizeType actual, U32 expected) const
SerializeStatus moveDeserToOffset(FwSizeType offset) override
Move deserialization pointer to specified offset.
#define FW_MIN(a, b)
MIN macro (deprecated in C++, use std::min)
void deallocate_out(FwIndexType portNum, Fw::Buffer &fwBuffer) const
Invoke output port deallocate.
CCSDS 732.0-B-5: Spacecraft ID mismatch (4.1.2.2)
Packet Version Numbers are 3 bits with only 2 currently valid values.
bool isConnected_deallocate_OutputPort(FwIndexType portNum) const
void set_vcId(U8 vcId)
Set member vcId.
uint8_t U8
8-bit unsigned integer
void errorNotify_out(FwIndexType portNum, const Svc::Ccsds::FrameError &errorCode) const
Invoke output port errorNotify.
FwSizeType getSize() const
AosDeframer(const char *const compName)
Construct AosDeframer object.
Bare-bones CCSDS Encapsulation Packet Protocol.
PlatformIndexType FwIndexType
The size of the serial representation.
void log_ACTIVITY_LO_InvalidVcId(U8 transmitted, U8 configured) const
Type used to pass context info between components during framing/deframing.
RateGroupDivider component implementation.
Per Space Packet Standard, all 1s (11bits) is reserved for Idle Packets.
void dataReturnOut_out(FwIndexType portNum, Fw::Buffer &data, const ComCfg::FrameContext &context) const
Invoke output port dataReturnOut.
PlatformAssertArgType FwAssertArgType
The type of arguments to assert functions.
void log_WARNING_HI_InvalidTfvn(U8 transmitted, U8 expected) const
CCSDS 732.0-B-5: AOS VC frame count discontinuity detected.