-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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 and Router #2900
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check-spelling found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
Will fix #2073 |
@thomas-bc @LeStarch I made a fork and kinda ran with it in my repo I found what I think is an issue with the frame detection here Currently I'm workin to fix my TM framer impl but let me know if I'm stepping on anyones toes or going in a bad direction |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for putting together these changes, @thomas-bc. I like the splitting out of the Router from the Deframer, but I'm not so sure I like splitting out the FrameAccumulator from the Deframer; this will actually make it less likely that I can use these stock components in my design. More details in individual comments.
remaining -= serSize; | ||
} | ||
// Either all the bytes from the data buffer must be processed, or the ring must be full | ||
FW_ASSERT(remaining == 0 || this->m_inRing.get_free_size() == 0, static_cast<FwAssertArgType>(remaining)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean that data will be silently dropped under some circumstances? Can we have a way to make it not silent (either a FATAL or some other kind of response)?
// No frame was detected or an unknown status was received | ||
else { | ||
// Discard a single byte of data and start again | ||
m_inRing.rotate(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we know how much data is invalid and should be discarded? Stepping through one byte at a time is likely to be needlessly slow. Yes, some frame detectors won't know how many bytes to discard, but some will.
output port frameAllocate: Fw.BufferGet | ||
|
||
@ Port for sending an extracted frame out | ||
output port frameOut: Fw.DataWithContext |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we send DataWithContext if there's always no context?
|
||
protected: | ||
TokenType m_value; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if this is my place to comment, since I won't be using the StartLengthCrcDetector, but I do want to say that I think all the templates in this file are needlessly convoluted. I don't see what benefit all of this abstraction adds. If you want to make it easy to implement a custom Start-Length-CRC detector, I'd just provide example code and tell people to copy it. It shouldn't be very complicated.
} | ||
// TODO: add asserts? | ||
data.setData(data.getData() + FrameConfig::HEADER_SIZE); | ||
data.setSize(data.getSize() - FrameConfig::HEADER_SIZE - FrameConfig::CHECKSUM_SIZE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect that this isn't going to be something you'll change, but I do want to note that modifying the buffer passed in as a reference seems dangerous. What if the caller didn't expect its buffer pointer and size to change? Yes, the caller should probably realize this could happen and not rely on it (especially since it should expect the data in the buffer to change anyway), but it still makes me nervous.
{ | ||
(void) memset(m_pollBuffer, 0, sizeof m_pollBuffer); | ||
} | ||
Deframer ::Deframer(const char* const compName) : DeframerComponentBase(compName) {} |
Check notice
Code scanning / CodeQL
Use of basic integral type Note
DeframingProtocol::DEFRAMING_STATUS_SUCCESS; | ||
// The ring buffer capacity | ||
const NATIVE_UINT_TYPE ringCapacity = m_inRing.get_capacity(); | ||
void Deframer ::framedIn_handler(FwIndexType portNum, Fw::Buffer& data, Fw::Buffer& context) { |
Check notice
Code scanning / CodeQL
Use of basic integral type Note
// Component construction and destruction | ||
// ---------------------------------------------------------------------- | ||
|
||
FrameAccumulator ::FrameAccumulator(const char* const compName) : FrameAccumulatorComponentBase(compName), |
Check notice
Code scanning / CodeQL
Use of basic integral type Note
} | ||
} | ||
|
||
void FrameAccumulator ::configure(const FrameDetector& detector, NATIVE_UINT_TYPE allocationId, |
Check notice
Code scanning / CodeQL
Use of basic integral type Note
|
||
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
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
// Component construction and destruction | ||
// ---------------------------------------------------------------------- | ||
|
||
Router ::Router(const char* const compName) : RouterComponentBase(compName) {} |
Check notice
Code scanning / CodeQL
Use of basic integral type Note
// 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
} | ||
|
||
// Whether to deallocate the packet buffer | ||
bool deallocate = true; |
Check notice
Code scanning / CodeQL
Use of basic integral type Note
} | ||
} | ||
|
||
void Router ::cmdResponseIn_handler(NATIVE_INT_TYPE portNum, |
Check notice
Code scanning / CodeQL
Use of basic integral type Note
|
||
this->deframedOut_out(0, data, context); |
Check warning
Code scanning / CodeQL
Unchecked function argument Warning
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); | ||
U8* data = reinterpret_cast<U8*>(allocator.allocate(allocationId, store_size_int, recoverable)); |
Check warning
Code scanning / CodeQL
Unchecked function argument Warning
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); | ||
U8* data = reinterpret_cast<U8*>(allocator.allocate(allocationId, store_size_int, recoverable)); |
Check warning
Code scanning / CodeQL
Unchecked function argument Warning
FW_ASSERT(store_size_int >= store_size); | ||
m_inRing.setup(data, store_size_int); | ||
|
||
this->m_detector = &detector; |
Check warning
Code scanning / CodeQL
Unchecked function argument Warning
// 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->processBuffer(buffer); | ||
} | ||
// Deallocate the buffer | ||
this->dataDeallocate_out(0, buffer); |
Check warning
Code scanning / CodeQL
Unchecked function argument Warning
} | ||
|
||
void FrameAccumulator ::processBuffer(Fw::Buffer& buffer) { | ||
const U32 bufferSize = buffer.getSize(); |
Check warning
Code scanning / CodeQL
Unchecked function argument Warning
// Copy out data and rotate | ||
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
rotate
// No frame was detected or an unknown status was received | ||
else { | ||
// Discard a single byte of data and start again | ||
m_inRing.rotate(1); |
Check warning
Code scanning / CodeQL
Unchecked return value Warning
rotate
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->deframedOut_out(0, data, context); |
Check warning
Code scanning / CodeQL
Unchecked function argument
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); | ||
U8* data = reinterpret_cast<U8*>(allocator.allocate(allocationId, store_size_int, recoverable)); |
Check warning
Code scanning / CodeQL
Unchecked function argument
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); | ||
U8* data = reinterpret_cast<U8*>(allocator.allocate(allocationId, store_size_int, recoverable)); |
Check notice
Code scanning / CodeQL
Conditional compilation Note
FW_ASSERT(store_size_int >= store_size); | ||
m_inRing.setup(data, store_size_int); | ||
|
||
this->m_detector = &detector; |
Check warning
Code scanning / CodeQL
Unchecked function argument
// 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
this->processBuffer(buffer); | ||
} | ||
// Deallocate the buffer | ||
this->dataDeallocate_out(0, buffer); |
Check warning
Code scanning / CodeQL
Unchecked function argument
} | ||
|
||
void FrameAccumulator ::processBuffer(Fw::Buffer& buffer) { | ||
const U32 bufferSize = buffer.getSize(); |
Check warning
Code scanning / CodeQL
Unchecked function argument
// Copy out data and rotate | ||
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
// No frame was detected or an unknown status was received | ||
else { | ||
// Discard a single byte of data and start again | ||
m_inRing.rotate(1); |
Check warning
Code scanning / CodeQL
Unchecked return value
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
{ | ||
(void) memset(m_pollBuffer, 0, sizeof m_pollBuffer); | ||
} | ||
Deframer ::Deframer(const char* const compName) : DeframerComponentBase(compName) {} |
Check notice
Code scanning / CodeQL
More than one statement per line Note
// ---------------------------------------------------------------------- | ||
|
||
FrameAccumulator ::FrameAccumulator(const char* const compName) : FrameAccumulatorComponentBase(compName), | ||
m_detector(nullptr), m_memoryAllocator(nullptr), m_memory(nullptr), m_allocatorId(0) {} |
Check notice
Code scanning / CodeQL
More than one statement per line Note
} | ||
} | ||
|
||
void FrameAccumulator ::configure(const FrameDetector& detector, NATIVE_UINT_TYPE allocationId, |
Check notice
Code scanning / CodeQL
Long function without assertion Note
this->dataDeallocate_out(0, buffer); | ||
} | ||
|
||
void FrameAccumulator ::processBuffer(Fw::Buffer& buffer) { |
Check notice
Code scanning / CodeQL
Long function without assertion Note
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
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
// Component construction and destruction | ||
// ---------------------------------------------------------------------- | ||
|
||
Router ::Router(const char* const compName) : RouterComponentBase(compName) {} |
Check notice
Code scanning / CodeQL
More than one statement per line Note
|
||
Router ::Router(const char* const compName) : RouterComponentBase(compName) {} | ||
|
||
Router ::~Router() {} |
Check notice
Code scanning / CodeQL
More than one statement per line Note
// 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
// 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
{ | ||
(void) memset(m_pollBuffer, 0, sizeof m_pollBuffer); | ||
} | ||
Deframer ::Deframer(const char* const compName) : DeframerComponentBase(compName) {} |
Check notice
Code scanning / CodeQL
More than one statement per line
// ---------------------------------------------------------------------- | ||
|
||
FrameAccumulator ::FrameAccumulator(const char* const compName) : FrameAccumulatorComponentBase(compName), | ||
m_detector(nullptr), m_memoryAllocator(nullptr), m_memory(nullptr), m_allocatorId(0) {} |
Check notice
Code scanning / CodeQL
More than one statement per line
} | ||
} | ||
|
||
void FrameAccumulator ::configure(const FrameDetector& detector, NATIVE_UINT_TYPE allocationId, |
Check notice
Code scanning / CodeQL
Long function without assertion
this->dataDeallocate_out(0, buffer); | ||
} | ||
|
||
void FrameAccumulator ::processBuffer(Fw::Buffer& buffer) { |
Check notice
Code scanning / CodeQL
Long function without 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
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
// Component construction and destruction | ||
// ---------------------------------------------------------------------- | ||
|
||
Router ::Router(const char* const compName) : RouterComponentBase(compName) {} |
Check notice
Code scanning / CodeQL
More than one statement per line
|
||
Router ::Router(const char* const compName) : RouterComponentBase(compName) {} | ||
|
||
Router ::~Router() {} |
Check notice
Code scanning / CodeQL
Use of basic integral type Note
// 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
// 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
{ | ||
(void) memset(m_pollBuffer, 0, sizeof m_pollBuffer); | ||
} | ||
Deframer ::Deframer(const char* const compName) : DeframerComponentBase(compName) {} |
Check notice
Code scanning / CodeQL
Use of basic integral type
DeframingProtocol::DEFRAMING_STATUS_SUCCESS; | ||
// The ring buffer capacity | ||
const NATIVE_UINT_TYPE ringCapacity = m_inRing.get_capacity(); | ||
void Deframer ::framedIn_handler(FwIndexType portNum, Fw::Buffer& data, Fw::Buffer& context) { |
Check notice
Code scanning / CodeQL
Use of basic integral type
// Component construction and destruction | ||
// ---------------------------------------------------------------------- | ||
|
||
FrameAccumulator ::FrameAccumulator(const char* const compName) : FrameAccumulatorComponentBase(compName), |
Check notice
Code scanning / CodeQL
Use of basic integral type
} | ||
} | ||
|
||
void FrameAccumulator ::configure(const FrameDetector& detector, NATIVE_UINT_TYPE allocationId, |
Check notice
Code scanning / CodeQL
Use of basic integral type
|
||
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
U8* m_memory; | ||
|
||
//! Identification used with the memory allocator | ||
NATIVE_UINT_TYPE m_allocatorId; |
Check notice
Code scanning / CodeQL
Use of basic integral type
} | ||
|
||
// Whether to deallocate the packet buffer | ||
bool deallocate = true; |
Check notice
Code scanning / CodeQL
Use of basic integral type
} | ||
} | ||
|
||
void Router ::cmdResponseIn_handler(NATIVE_INT_TYPE portNum, |
Check notice
Code scanning / CodeQL
Use of basic integral type
After further review, we're going to try to move away from the templated FrameDetectors and instead leverage FPP to specify the header format, and leverage the struct's serializing functions to do the grunt work. Closing for now so as not to spam CI and yall with notifications - will reopen when we're closer to done |
Change Description
Split up Deframer into 3 components:
UplinkRouter
?)Using this new structure, adding in 2 new deframers for CCSDS SpacePacket and TM protocols.
Rationale
Better reusability and chaining of deframers, preliminary work for CCSDS integrations
TODO
!!! UPDATE
fprime-util new --deployment
To discuss