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) {
107 if (m_fecfEnabled && !this->validateFecf(data)) {
119 if ((vc = this->parseAndValidateHeader(data, packetContext)) ==
nullptr) {
126 if (!vc->spanningPacket.buffer.isValid()) {
127 vc->spanningPacket.context = packetContext;
131 this->extractPackets(*vc, data);
149 void AosDeframer::notifyErrorIfConnected(Ccsds::FrameError error) {
155 void AosDeframer::abandonSpanningPacket(AosDeframerVc& vc) {
156 if (vc.spanningPacket.buffer.isValid()) {
158 vc.spanningPacket.bytesReceived,
159 vc.spanningPacket.buffer.getSize());
163 vc.spanningPacket.bytesReceived = 0;
167 AosDeframer::AosDeframerVc* AosDeframer::getVcStruct(
const U8 vcId) {
169 if (m_vcs[vcInd].virtualChannelId == vcId) {
170 return &m_vcs[vcInd];
188 if (tfvn != static_cast<U8>(
Tfvn::AOS)) {
197 const U16 spacecraftId =
203 if (spacecraftId != m_spacecraftId) {
211 AosDeframerVc* vc = this->getVcStruct(vcId);
226 U32 frameCountMask = 0x00FF
'FFFF; 228 // Extract VC Frame Count Cycle if in use (Section 4.1.2.5.3) 229 if ((header.get_frameCountAndSignaling() & AOSHeaderSubfields::cycleCountFlagMask) != 0) { 230 const U8 rxVcFrameCountCycle = header.get_frameCountAndSignaling() & AOSHeaderSubfields::vcFrameCountCycleMask; 231 // Extend the 24-bit frame count with the 4-bit cycle count 232 rxVcFrameCount |= static_cast<U32>(rxVcFrameCountCycle) << 24; 233 // Add the 4 additional bits to our modulo 234 frameCountMask |= 0x0F00'0000;
238 if (vc->framesProcessed > 0U) {
239 const U32 expectedVcFrameCount = vc->vcFrameCount + 1U;
240 if (rxVcFrameCount != (expectedVcFrameCount & frameCountMask)) {
241 this->log_WARNING_HI_VcFrameCountGap(vcId, rxVcFrameCount, expectedVcFrameCount);
244 this->abandonSpanningPacket(*vc);
249 vc->vcFrameCount = rxVcFrameCount;
250 this->tlmWrite_LatestVcFrameCount(vc->vcFrameCount);
258 bool AosDeframer::validateFecf(
Fw::Buffer& data) {
262 const FwSizeType crcDataLen = m_fixedFrameSize - AOSTrailer::SERIALIZED_SIZE;
272 U16 transmittedCrc = trailer.get_fecf();
273 if (transmittedCrc != computedCrc) {
274 this->log_WARNING_HI_InvalidFecf(transmittedCrc, computedCrc);
276 this->tlmWrite_CrcErrorCount(++m_crcErrorCount);
285 FW_ASSERT(size > 0, static_cast<FwAssertArgType>(size));
291 if (!vc.spanningPacket.buffer.isValid()) {
293 const FwSizeType headerCap = AosDeframerVc::SpanningPacketState::HEADER_BUF_SIZE;
295 const FwSizeType toHeader =
FW_MIN(size, headerCap - vc.spanningPacket.bytesReceived);
297 FW_ASSERT(vc.spanningPacket.bytesReceived < headerCap,
298 static_cast<FwAssertArgType>(vc.spanningPacket.bytesReceived),
299 static_cast<FwAssertArgType>(headerCap));
300 FW_ASSERT(toHeader <= headerCap, static_cast<FwAssertArgType>(toHeader),
301 static_cast<FwAssertArgType>(headerCap));
302 FW_ASSERT(vc.spanningPacket.bytesReceived + toHeader <= headerCap,
303 static_cast<FwAssertArgType>(vc.spanningPacket.bytesReceived),
304 static_cast<FwAssertArgType>(toHeader), static_cast<FwAssertArgType>(headerCap));
305 ::memcpy(vc.spanningPacket.headerBuf + vc.spanningPacket.bytesReceived, data, toHeader);
306 vc.spanningPacket.bytesReceived += toHeader;
311 seekForward += toHeader;
316 const FwSizeType packetSize = sizePacket(vc, vc.spanningPacket.headerBuf, vc.spanningPacket.bytesReceived);
317 if (packetSize == 0) {
323 vc.spanningPacket.buffer = this->allocate_out(0, packetSize);
324 if ((not vc.spanningPacket.buffer.isValid()) || (vc.spanningPacket.buffer.getSize() < packetSize)) {
325 this->log_WARNING_HI_SpanningPacketAllocFailed(vc.virtualChannelId, vc.spanningPacket.context.get_pvn(),
328 const FwSizeType remainingBody = packetSize - vc.spanningPacket.bytesReceived;
329 this->abandonSpanningPacket(vc);
332 const FwSizeType remainingLength = seekForward + remainingBody;
333 if (remainingLength > size) {
336 return remainingLength;
341 FW_ASSERT(vc.spanningPacket.bytesReceived <= AosDeframerVc::SpanningPacketState::HEADER_BUF_SIZE,
342 static_cast<FwAssertArgType>(vc.spanningPacket.bytesReceived),
343 AosDeframerVc::SpanningPacketState::HEADER_BUF_SIZE);
347 FW_ASSERT(vc.spanningPacket.bytesReceived <= vc.spanningPacket.buffer.getSize(),
349 static_cast<FwAssertArgType>(vc.spanningPacket.buffer.getSize()));
350 ::memcpy(vc.spanningPacket.buffer.getData(), vc.spanningPacket.headerBuf, vc.spanningPacket.bytesReceived);
354 const FwSizeType spaceLeft = vc.spanningPacket.buffer.getSize() - vc.spanningPacket.bytesReceived;
358 FW_ASSERT(vc.spanningPacket.bytesReceived + toBody <= vc.spanningPacket.buffer.getSize(),
359 static_cast<FwAssertArgType>(vc.spanningPacket.bytesReceived), static_cast<FwAssertArgType>(toBody),
361 ::memcpy(vc.spanningPacket.buffer.getData() + vc.spanningPacket.bytesReceived, data, toBody);
362 vc.spanningPacket.bytesReceived += toBody;
363 seekForward += toBody;
367 if (vc.spanningPacket.buffer.getSize() > 0 &&
368 vc.spanningPacket.bytesReceived >= vc.spanningPacket.buffer.getSize()) {
369 this->dataOut_out(0, vc.spanningPacket.buffer, vc.spanningPacket.context);
370 this->tlmWrite_PacketsExtracted(++vc.packetsExtracted);
375 this->abandonSpanningPacket(vc);
381 void AosDeframer::extractPackets(AosDeframerVc& vc,
Fw::Buffer& data) {
383 M_PDUHeader mpduHeader;
389 U16 firstHeaderPointer = mpduHeader.get_firstHeaderPointer();
392 const FwSizeType dataZoneStart = AOSHeader::SERIALIZED_SIZE + M_PDUHeader::SERIALIZED_SIZE;
393 const FwSizeType dataZoneEnd = m_fixedFrameSize - (m_fecfEnabled ? AOSTrailer::SERIALIZED_SIZE : 0);
394 const FwSizeType dataZoneSize = dataZoneEnd - dataZoneStart;
395 U8* dataZone = data.
getData() + dataZoneStart;
400 this->log_ACTIVITY_LO_IdleFrame(vc.virtualChannelId);
406 if (vc.spanningPacket.bytesReceived > 0) {
407 (void)this->appendToSpanningPacket(vc, dataZone, dataZoneSize);
414 if (firstHeaderPointer >= dataZoneSize) {
415 this->log_WARNING_HI_InvalidFhp(vc.virtualChannelId, firstHeaderPointer, dataZoneSize);
418 this->abandonSpanningPacket(vc);
423 if (firstHeaderPointer > 0 && vc.spanningPacket.bytesReceived > 0) {
424 (void)this->appendToSpanningPacket(vc, dataZone, static_cast<FwSizeType>(firstHeaderPointer));
426 this->abandonSpanningPacket(vc);
430 FwSizeType currentOffset = firstHeaderPointer;
437 for (
FwIndexType iter = 0; iter < maxIters && currentOffset < dataZoneSize; iter++) {
439 this->abandonSpanningPacket(vc);
441 U8* packetStart = dataZone + currentOffset;
442 FwSizeType remainingBytes = dataZoneSize - currentOffset;
444 FwSizeType packetSize = this->appendToSpanningPacket(vc, packetStart, remainingBytes);
446 if (packetSize == 0) {
451 currentOffset += packetSize;
456 FW_ASSERT(remainingBytes > 0, static_cast<FwAssertArgType>(remainingBytes));
459 U8 pvn = getPacketVersion(packetStart[0]);
464 if (~vc.pvnMask & (1 << pvn)) {
465 this->log_WARNING_HI_DisabledPvn(vc.virtualChannelId, pvn);
470 vc.spanningPacket.context.set_pvn(pvnEnum);
475 return sizeSppPacket(packetStart, remainingBytes);
478 return sizeEppPacket(packetStart, remainingBytes);
488 SpacePacketHeader header;
502 constexpr
FwSizeType MAX_LENGTH = std::numeric_limits<FwSizeType>::max() - SpacePacketHeader::SERIALIZED_SIZE;
503 static_assert(MAX_LENGTH >= std::numeric_limits<U16>::max() + 1,
504 "FwSizeType must be wide enough to hold the maximum SPP packet size without overflow");
505 FwSizeType totalPacketSize = SpacePacketHeader::SERIALIZED_SIZE + header.get_packetDataLength() + 1;
518 return totalPacketSize;
524 FW_ASSERT(payloadSize > 0, static_cast<FwAssertArgType>(payloadSize));
527 U8 firstByte = payloadStart[0];
533 if (protocolId == static_cast<U8>(EppProtocolId::Idle)) {
540 U8 lengthOffset = 1U;
543 if (lengthOfLength >= EppLengthOfLength::Two) {
544 lengthOffset =
static_cast<U8>(lengthOffset + 1U);
548 if (lengthOfLength == EppLengthOfLength::Four) {
549 lengthOffset =
static_cast<U8>(lengthOffset + 2U);
555 const U8 headerLength =
static_cast<U8>(lengthOffset + lengthOfLength);
558 if (payloadSize < headerLength) {
563 U32 packetDataLength = 0;
564 for (
U8 i = 0; i < lengthOfLength; i++) {
565 packetDataLength = (packetDataLength << 8) | payloadStart[lengthOffset + i];
570 if (packetDataLength > (std::numeric_limits<FwSizeType>::max() -
static_cast<FwSizeType>(headerLength))) {
580 totalPacketSize =
static_cast<FwSizeType>(headerLength) + static_cast<FwSizeType>(packetDataLength);
582 return totalPacketSize;
585 U8 AosDeframer::getPacketVersion(
U8 firstByte) {
Serialization/Deserialization operation was successful.
static U16 compute(const U8 *buffer, U32 length)
compute CRC16 for a buffer
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.
~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
#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.
void log_WARNING_HI_SpanningPacketAbandoned(U8 vcId, ComCfg::Pvn pvn, FwSizeType bytesReceived, FwSizeType bytesExpected) const
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
SerializeStatus moveDeserToOffset(FwSizeType offset) override
Move deserialization pointer to specified offset.
void log_ACTIVITY_LO_InvalidVcId(U8 transmitted, U8 configured) const
Type used to pass context info between components during framing/deframing.
RateGroupDivider component implementation.
SerializeStatus deserializeTo(U8 &val, Endianness mode=Endianness::BIG) override
Deserialize an 8-bit unsigned integer value.
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.
The size of the serial representation.
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.