Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split Deframer into FrameAccumulator Deframer and Router #3250

Open
wants to merge 53 commits into
base: devel
Choose a base branch
from

Conversation

thomas-bc
Copy link
Collaborator

Related Issue(s) #2763
Has Unit Tests (y/n)
Documentation Included (y/n)

Change Description

(GitHub doesn't let me re-open #2900 for some reason..., so re-opening here)

Implements #2763

Split up Deframer into 3 components:

  • FrameAccumulator
  • FprimeDeframer
  • Router

Rationale

Better reusability and chaining of deframers, preliminary work for CCSDS integrations

TODO

!!! UPDATE fprime-util new --deployment

To discuss

@thomas-bc thomas-bc added the Update Instructions Needed Need to add instructions in the release notes for updates. label Feb 20, 2025
// Component construction and destruction
// ----------------------------------------------------------------------

FprimeDeframer ::FprimeDeframer(const char* const compName) : FprimeDeframerComponentBase(compName) {}

Check notice

Code scanning / CodeQL

Use of basic integral type Note

compName uses the basic integral type char rather than a typedef with size and signedness.
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------

void FprimeDeframer ::framedIn_handler(FwIndexType portNum, Fw::Buffer& data, Fw::Buffer& context) {

Check notice

Code scanning / CodeQL

Use of basic integral type Note

portNum uses the basic integral type int rather than a typedef with size and signedness.
namespace Svc {
namespace FrameDetectors {

FrameDetector::Status FprimeFrameDetector::detect(const Types::CircularBuffer& data, FwSizeType& size_out) const {

Check notice

Code scanning / CodeQL

Use of basic integral type Note

size_out uses the basic integral type unsigned long rather than a typedef with size and signedness.
// Component construction and destruction
// ----------------------------------------------------------------------

Router ::Router(const char* const compName) : RouterComponentBase(compName) {}

Check notice

Code scanning / CodeQL

Use of basic integral type Note

compName uses the basic integral type char rather than a typedef with size and signedness.
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------

void Router ::dataIn_handler(NATIVE_INT_TYPE portNum, Fw::Buffer& packetBuffer, Fw::Buffer& contextBuffer) {

Check notice

Code scanning / CodeQL

Use of basic integral type Note

portNum uses the basic integral type int rather than a typedef with size and signedness.
}

// Whether to deallocate the packet buffer
bool deallocate = true;

Check notice

Code scanning / CodeQL

Use of basic integral type Note

deallocate uses the basic integral type bool rather than a typedef with size and signedness.
}
}

void Router ::cmdResponseIn_handler(NATIVE_INT_TYPE portNum,

Check notice

Code scanning / CodeQL

Use of basic integral type Note

portNum uses the basic integral type int rather than a typedef with size and signedness.
Copy link

@github-advanced-security github-advanced-security bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

// Component construction and destruction
// ----------------------------------------------------------------------

FprimeDeframer ::FprimeDeframer(const char* const compName) : FprimeDeframerComponentBase(compName) {}

Check notice

Code scanning / CodeQL

More than one statement per line Note

This line contains 2 statements; only one is allowed.

FprimeDeframer ::FprimeDeframer(const char* const compName) : FprimeDeframerComponentBase(compName) {}

FprimeDeframer ::~FprimeDeframer() {}

Check notice

Code scanning / CodeQL

More than one statement per line Note

This line contains 2 statements; only one is allowed.
}
// Deallocate the buffer
this->bufferDeallocate_out(0, buffer);
}

Check notice

Code scanning / CodeQL

Long function without assertion Note

All functions of more than 10 lines should have at least one assertion.
namespace Svc {
namespace FrameDetectors {

FrameDetector::Status FprimeFrameDetector::detect(const Types::CircularBuffer& data, FwSizeType& size_out) const {

Check notice

Code scanning / CodeQL

Long function without assertion Note

All functions of more than 10 lines should have at least one assertion.
// Component construction and destruction
// ----------------------------------------------------------------------

Router ::Router(const char* const compName) : RouterComponentBase(compName) {}

Check notice

Code scanning / CodeQL

More than one statement per line Note

This line contains 2 statements; only one is allowed.

Router ::Router(const char* const compName) : RouterComponentBase(compName) {}

Router ::~Router() {}

Check notice

Code scanning / CodeQL

More than one statement per line Note

This line contains 2 statements; only one is allowed.
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------

void Router ::dataIn_handler(NATIVE_INT_TYPE portNum, Fw::Buffer& packetBuffer, Fw::Buffer& contextBuffer) {

Check notice

Code scanning / CodeQL

Function too long Note

dataIn_handler has too many lines (64, while 60 are allowed).
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------

void Router ::dataIn_handler(NATIVE_INT_TYPE portNum, Fw::Buffer& packetBuffer, Fw::Buffer& contextBuffer) {

Check notice

Code scanning / CodeQL

Long function without assertion Note

All functions of more than 10 lines should have at least one assertion.
data.setData(data.getData() + FprimeProtocol::FrameHeader::SERIALIZED_SIZE);
data.setSize(data.getSize() - FprimeProtocol::FrameHeader::SERIALIZED_SIZE - FprimeProtocol::FrameTrailer::SERIALIZED_SIZE);

this->deframedOut_out(0, data, context);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter context has not been checked.
bool recoverable = false;
FW_ASSERT(std::numeric_limits<NATIVE_INT_TYPE>::max() >= store_size, static_cast<FwAssertArgType>(store_size));
NATIVE_UINT_TYPE store_size_int = static_cast<NATIVE_UINT_TYPE>(store_size);
void* data_void = allocator.allocate(allocationId, store_size_int, recoverable);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter allocator has not been checked.
bool recoverable = false;
FW_ASSERT(std::numeric_limits<NATIVE_INT_TYPE>::max() >= store_size, static_cast<FwAssertArgType>(store_size));
NATIVE_UINT_TYPE store_size_int = static_cast<NATIVE_UINT_TYPE>(store_size);
void* data_void = allocator.allocate(allocationId, store_size_int, recoverable);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter allocationId has not been checked.
U8* data = new(data_void) U8[store_size_int];
FW_ASSERT(data != nullptr);
FW_ASSERT(store_size_int >= store_size);
m_inRing.setup(data, store_size_int);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter detector has not been checked.
// Check whether there is data to process
if (status.e == Drv::RecvStatus::RECV_OK) {
// There is: process the data
this->processBuffer(buffer);

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter buffer has not been checked.
FwPacketDescriptorType packetType = Fw::ComPacket::FW_PACKET_UNKNOWN;
Fw::SerializeStatus status = Fw::FW_SERIALIZE_OK;
{
Fw::SerializeBufferBase& serial = packetBuffer.getSerializeRepr();

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter packetBuffer has not been checked.
Utils::HashBuffer hashBuffer;

// Compute CRC over the transmitted data (header + body)
FwSizeType hash_field_size = header.getlength() + FprimeProtocol::FrameHeader::SERIALIZED_SIZE;

Check notice

Code scanning / CodeQL

Use of basic integral type Note

hash_field_size uses the basic integral type unsigned long rather than a typedef with size and signedness.
// Component construction and destruction
// ----------------------------------------------------------------------

FrameAccumulator ::FrameAccumulator(const char* const compName)

Check notice

Code scanning / CodeQL

Use of basic integral type Note

compName uses the basic integral type char rather than a typedef with size and signedness.
}

void FrameAccumulator ::configure(const FrameDetector& detector,
NATIVE_UINT_TYPE allocationId,

Check notice

Code scanning / CodeQL

Use of basic integral type Note

allocationId uses the basic integral type unsigned int rather than a typedef with size and signedness.
void FrameAccumulator ::configure(const FrameDetector& detector,
NATIVE_UINT_TYPE allocationId,
Fw::MemAllocator& allocator,
FwSizeType store_size) {

Check notice

Code scanning / CodeQL

Use of basic integral type Note

store_size uses the basic integral type unsigned long rather than a typedef with size and signedness.
break;
}
// Compute the size of data to serialize
const NATIVE_UINT_TYPE ringFreeSize = this->m_inRing.get_free_size();

Check notice

Code scanning / CodeQL

Use of basic integral type Note

ringFreeSize uses the basic integral type unsigned int rather than a typedef with size and signedness.
}
// Compute the size of data to serialize
const NATIVE_UINT_TYPE ringFreeSize = this->m_inRing.get_free_size();
const NATIVE_UINT_TYPE serSize =

Check notice

Code scanning / CodeQL

Use of basic integral type Note

serSize uses the basic integral type unsigned int rather than a typedef with size and signedness.
// The protocol status
FrameDetector::Status status = FrameDetector::Status::FRAME_DETECTED;
// The ring buffer capacity
const NATIVE_UINT_TYPE ringCapacity = this->m_inRing.get_capacity();

Check notice

Code scanning / CodeQL

Use of basic integral type Note

ringCapacity uses the basic integral type unsigned int rather than a typedef with size and signedness.
break;
}
// size_out is a return variable we initialize to zero, but it should be overwritten
FwSizeType size_out = 0;

Check notice

Code scanning / CodeQL

Use of basic integral type Note

size_out uses the basic integral type unsigned long rather than a typedef with size and signedness.
U8* m_memory;

//! Identification used with the memory allocator
NATIVE_UINT_TYPE m_allocatorId;

Check notice

Code scanning / CodeQL

Use of basic integral type Note

m_allocatorId uses the basic integral type unsigned int rather than a typedef with size and signedness.
Comment on lines +132 to +133
FW_ASSERT(this->m_inRing.peek(buffer.getData(), static_cast<NATIVE_UINT_TYPE>(size_out)) ==
Fw::SerializeStatus::FW_SERIALIZE_OK);

Check warning

Code scanning / CodeQL

Side effect in a Boolean expression Warning

This Boolean expression is not side-effect free.
FW_ASSERT(this->m_inRing.peek(buffer.getData(), static_cast<NATIVE_UINT_TYPE>(size_out)) ==
Fw::SerializeStatus::FW_SERIALIZE_OK);
buffer.setSize(static_cast<U32>(size_out));
m_inRing.rotate(static_cast<U32>(size_out));

Check warning

Code scanning / CodeQL

Unchecked return value Warning

The return value of non-void function
rotate
is not checked.
// If the deserialized length token can't fit in current allocated size -> MORE_DATA_NEEDED
if (data.get_allocated_size() < FprimeProtocol::FrameHeader::SERIALIZED_SIZE + header.getlength() +
FprimeProtocol::FrameTrailer::SERIALIZED_SIZE) {
size_out = header.getlength() + FprimeProtocol::FrameHeader::SERIALIZED_SIZE +

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter size_out has not been checked.
// Add Status::DATA_ERROR , and use it for deserialization errors as well?
return Status::NO_FRAME_DETECTED;
}
size_out = header.getlength() + FprimeProtocol::FrameHeader::SERIALIZED_SIZE +

Check warning

Code scanning / CodeQL

Unchecked function argument Warning

This use of parameter size_out has not been checked.
m_detector(nullptr),
m_memoryAllocator(nullptr),
m_memory(nullptr),
m_allocatorId(0) {}

Check notice

Code scanning / CodeQL

More than one statement per line Note

This line contains 2 statements; only one is allowed.
}
}

void FrameAccumulator ::configure(const FrameDetector& detector,

Check notice

Code scanning / CodeQL

Long function without assertion Note

All functions of more than 10 lines should have at least one assertion.
FW_ASSERT(remaining == 0 || this->m_inRing.get_free_size() == 0, static_cast<FwAssertArgType>(remaining));
}

void FrameAccumulator ::processRing() {

Check notice

Code scanning / CodeQL

Function too long Note

processRing has too many lines (68, while 60 are allowed).
FW_ASSERT(remaining == 0 || this->m_inRing.get_free_size() == 0, static_cast<FwAssertArgType>(remaining));
}

void FrameAccumulator ::processRing() {

Check notice

Code scanning / CodeQL

Long function without assertion Note

All functions of more than 10 lines should have at least one assertion.
thomas-bc added a commit to thomas-bc/fprime-tools that referenced this pull request Feb 27, 2025
@thomas-bc thomas-bc requested a review from LeStarch February 27, 2025 01:44
break;
}
// Take no action for other packet types
default:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to emit these on a third output port so that custom routing can be extended easily?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do like that. Send everything else unknown to a third output port and if connected. WARNING_HI if not connected.

Copy link
Collaborator

@LeStarch LeStarch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of minor changes, but this is looking to be in really good shape!

@@ -13,6 +13,7 @@ module Ref {
enum Ports_StaticMemory {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You aren't using this anymore. Delete it.

)

set(MOD_DEPS
Svc/FramingProtocol
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a dependency?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not be anymore - will remove. We should probably capture a follow-up ticket to look into whether we can do some cleanup in the FramingProtocol itself

@@ -119,6 +119,11 @@ typedef U32 FwDpIdType;
typedef U32 FwDpPriorityType;
#define PRI_FwDpPriorityType PRIu32

// Type for start word and length word used in fprime framing
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete this.

@@ -0,0 +1,8 @@
@ Receiving data (Fw::Buffer) to be routed with optional context to help with routing
guarded input port dataIn: Fw.DataWithContext
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the data is just routed. This could be sync as no modifications of internal data is done. Right?

if (status == Fw::FW_SERIALIZE_OK) {
// Send the com buffer
commandOut_out(0, com, 0);
// REVIEW NOTE: Deframer did not check if the output port was connected, should it?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was done because it was presumed to be an error if data paths weren't connected. Since this is critical for base functionality, leave a comment. Users could always add in a dev-null "cap" component to explicitly discard.

@@ -0,0 +1,17 @@
module Svc {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For completeness, should this be an interface too?

title: "F Prime Frame Format"
---
packet-beta
0-31: "Start word: 0xDEADBEEF [4 bytes]"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically aren't these intended to be configurable?

@@ -0,0 +1,166 @@
// ======================================================================
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might need to reimport this code, if and when my PR merges that changes types.

FW_ASSERT(size_out != 0);
FW_ASSERT(size_out <= remaining, static_cast<FwAssertArgType>(size_out),
static_cast<FwAssertArgType>(remaining));
Fw::Buffer buffer = this->bufferAllocate_out(0, static_cast<U32>(size_out));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to check for overflow from FwSizeType to U32

Fw::Buffer nullContext;
this->frameOut_out(0, buffer, nullContext);
} else {
// No buffer is available, we need to exit and try again later
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should produce an event in this case. Probably a WARNING_HI

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Update Instructions Needed Need to add instructions in the release notes for updates.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants