| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ====================================================================== | ||
| 2 | // \title SpacePacketDeframer.cpp | ||
| 3 | // \author thomas-bc | ||
| 4 | // \brief cpp file for SpacePacketDeframer component implementation class | ||
| 5 | // ====================================================================== | ||
| 6 | |||
| 7 | #include "Svc/Ccsds/SpacePacketDeframer/SpacePacketDeframer.hpp" | ||
| 8 | #include "Svc/Ccsds/Types/FppConstantsAc.hpp" | ||
| 9 | #include "Svc/Ccsds/Types/SpacePacketHeaderSerializableAc.hpp" | ||
| 10 | |||
| 11 | namespace Svc { | ||
| 12 | |||
| 13 | namespace Ccsds { | ||
| 14 | |||
| 15 | // ---------------------------------------------------------------------- | ||
| 16 | // Component construction and destruction | ||
| 17 | // ---------------------------------------------------------------------- | ||
| 18 | |||
| 19 | 1 | SpacePacketDeframer ::SpacePacketDeframer(const char* const compName) : SpacePacketDeframerComponentBase(compName) {} | |
| 20 | |||
| 21 | 2 | SpacePacketDeframer ::~SpacePacketDeframer() {} | |
| 22 | |||
| 23 | namespace { | ||
| 24 | |||
| 25 | 146 | bool isValidPacketVersionNumber(const SpacePacketHeader& header) { | |
| 26 | 146 | const U16 packetIdentification = header.get_packetIdentification(); | |
| 27 | 146 | const U16 pvn = (packetIdentification & SpacePacketSubfields::PvnMask) >> SpacePacketSubfields::PvnOffset; | |
| 28 | 146 | return pvn == static_cast<U16>(ComCfg::Pvn::SPACE_PACKET_PROTOCOL); | |
| 29 | } | ||
| 30 | |||
| 31 | } // namespace | ||
| 32 | |||
| 33 | // ---------------------------------------------------------------------- | ||
| 34 | // Handler implementations for typed input ports | ||
| 35 | // ---------------------------------------------------------------------- | ||
| 36 | |||
| 37 | 146 | void SpacePacketDeframer ::dataIn_handler(FwIndexType portNum, Fw::Buffer& data, const ComCfg::FrameContext& context) { | |
| 38 | // ################################ | ||
| 39 | // CCSDS SpacePacket Format: | ||
| 40 | // 6 octets - Primary Header | ||
| 41 | // 0-65536 octets - Data Field (with optional secondary header) | ||
| 42 | |||
| 43 | // CCSDS SpacePacket Primary Header: | ||
| 44 | // 3b - 000 - (PVN) Packet Version Number | ||
| 45 | // 1b - 0/1 - (PT) Packet Type | ||
| 46 | // 1b - 0/1 - (SHF) Secondary Header Flag | ||
| 47 | // 11b - n/a - (APID) Application Process ID | ||
| 48 | // 2b - 00/01/10/11 - Sequence Flag | ||
| 49 | // 14b - n/a - Sequence Count | ||
| 50 | // 16b - n/a - Packet Data Length | ||
| 51 | // ################################ | ||
| 52 | |||
| 53 | // Check size and drop packets that are too-small | ||
| 54 |
2/3✓ Branch 1 taken 146 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 146 times.
|
146 | if (data.getSize() <= SpacePacketHeader::SERIALIZED_SIZE) { |
| 55 | ✗ | this->log_WARNING_HI_InvalidPacket(); | |
| 56 | ✗ | if (this->isConnected_errorNotify_OutputPort(0)) { | |
| 57 | ✗ | this->errorNotify_out(0, Svc::Ccsds::FrameError::SP_INVALID_PACKET); | |
| 58 | } | ||
| 59 | ✗ | this->dataReturnOut_out(0, data, context); // Drop the packet | |
| 60 | ✗ | return; | |
| 61 | } | ||
| 62 | |||
| 63 |
1/1✓ Branch 1 taken 146 times.
|
146 | SpacePacketHeader header; |
| 64 |
2/2✓ Branch 1 taken 146 times.
✓ Branch 4 taken 146 times.
|
146 | Fw::SerializeStatus status = data.getDeserializer().deserializeTo(header); |
| 65 | // Deserialization can still fail if the buffer is malformed despite passing the size check | ||
| 66 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 146 times.
|
146 | if (status != Fw::FW_SERIALIZE_OK) { |
| 67 | ✗ | this->log_WARNING_HI_InvalidPacket(); | |
| 68 | ✗ | if (this->isConnected_errorNotify_OutputPort(0)) { | |
| 69 | ✗ | this->errorNotify_out(0, Svc::Ccsds::FrameError::SP_INVALID_PACKET); | |
| 70 | } | ||
| 71 | ✗ | this->dataReturnOut_out(0, data, context); // Drop the packet | |
| 72 | ✗ | return; | |
| 73 | } | ||
| 74 | |||
| 75 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 146 times.
|
146 | if (!isValidPacketVersionNumber(header)) { |
| 76 | ✗ | this->log_WARNING_HI_InvalidPacket(); | |
| 77 | ✗ | if (this->isConnected_errorNotify_OutputPort(0)) { | |
| 78 | ✗ | this->errorNotify_out(0, Svc::Ccsds::FrameError::SP_INVALID_PACKET); | |
| 79 | } | ||
| 80 | ✗ | this->dataReturnOut_out(0, data, context); // Drop the packet | |
| 81 | ✗ | return; | |
| 82 | } | ||
| 83 | |||
| 84 | // Widen to U32 before adding 1 to prevent U16 truncation to 0 when packetDataLength == 0xFFFF (max U16 value). | ||
| 85 | // This is a undefined behavior condition in C++. | ||
| 86 | 146 | const U32 pkt_length = static_cast<U32>(header.get_packetDataLength()) + 1U; | |
| 87 |
4/7✓ Branch 1 taken 146 times.
✓ Branch 3 taken 146 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 146 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 146 times.
|
292 | if ((pkt_length > data.getSize() - SpacePacketHeader::SERIALIZED_SIZE) || |
| 88 | 146 | (pkt_length > std::numeric_limits<FwSizeType>::max())) { | |
| 89 | ✗ | FwSizeType maxDataAvailable = data.getSize() - SpacePacketHeader::SERIALIZED_SIZE; | |
| 90 | ✗ | this->log_WARNING_HI_InvalidLength(pkt_length, maxDataAvailable); | |
| 91 | ✗ | if (this->isConnected_errorNotify_OutputPort(0)) { | |
| 92 | ✗ | this->errorNotify_out(0, Svc::Ccsds::FrameError::SP_INVALID_LENGTH); | |
| 93 | } | ||
| 94 | ✗ | this->dataReturnOut_out(0, data, context); // Drop the packet | |
| 95 | ✗ | return; | |
| 96 | } | ||
| 97 | |||
| 98 | 146 | U16 apidValue = header.get_packetIdentification() & SpacePacketSubfields::ApidMask; | |
| 99 |
2/3✓ Branch 1 taken 146 times.
✓ Branch 3 taken 146 times.
✗ Branch 4 not taken.
|
146 | ComCfg::Apid::T apid = ComCfg::Apid::isValid(apidValue) ? static_cast<ComCfg::Apid::T>(apidValue) |
| 100 | 146 | : ComCfg::Apid::INVALID_UNINITIALIZED; | |
| 101 |
1/1✓ Branch 1 taken 146 times.
|
146 | ComCfg::FrameContext contextCopy = context; |
| 102 |
1/1✓ Branch 1 taken 146 times.
|
146 | contextCopy.set_apid(apid); |
| 103 | |||
| 104 | // Extract secondary header flag | ||
| 105 | 146 | bool hasSecHdr = (header.get_packetIdentification() & SpacePacketSubfields::SecHdrMask) != 0; | |
| 106 |
1/1✓ Branch 1 taken 146 times.
|
146 | contextCopy.set_hasSecHdr(hasSecHdr); |
| 107 | |||
| 108 | // Extract sequence flags | ||
| 109 | 146 | U8 sequenceFlags = static_cast<U8>((header.get_packetSequenceControl() & SpacePacketSubfields::SeqFlagsMask) >> | |
| 110 | 146 | SpacePacketSubfields::SeqFlagsOffset); | |
| 111 |
1/1✓ Branch 1 taken 146 times.
|
146 | contextCopy.set_sequenceFlags(sequenceFlags); |
| 112 | |||
| 113 | // Validate with the ApidManager that the sequence count is correct | ||
| 114 | 146 | U16 receivedSequenceCount = header.get_packetSequenceControl() & SpacePacketSubfields::SeqCountMask; | |
| 115 |
2/2✓ Branch 1 taken 146 times.
✓ Branch 4 taken 146 times.
|
146 | (void)this->validateApidSeqCount_out(0, apid, receivedSequenceCount); |
| 116 |
1/1✓ Branch 1 taken 146 times.
|
146 | contextCopy.set_sequenceCount(receivedSequenceCount); |
| 117 | |||
| 118 | // Set data buffer to be of the encapsulated data: HEADER (6 bytes) | PACKET DATA | ||
| 119 |
1/1✓ Branch 1 taken 146 times.
|
146 | data.advance(SpacePacketHeader::SERIALIZED_SIZE); |
| 120 |
1/1✓ Branch 1 taken 146 times.
|
146 | data.setSize(pkt_length); |
| 121 | |||
| 122 |
1/1✓ Branch 1 taken 146 times.
|
146 | this->dataOut_out(0, data, contextCopy); |
| 123 | 146 | } | |
| 124 | |||
| 125 | 146 | void SpacePacketDeframer ::dataReturnIn_handler(FwIndexType portNum, | |
| 126 | Fw::Buffer& data, | ||
| 127 | const ComCfg::FrameContext& context) { | ||
| 128 | 146 | this->dataReturnOut_out(0, data, context); | |
| 129 | 146 | } | |
| 130 | |||
| 131 | } // namespace Ccsds | ||
| 132 | } // namespace Svc | ||
| 133 |