fprime/Svc/FrameAccumulator/FrameAccumulator.cpp
Vince Woo a2141d98fb
Deprecate Fw::Buffer::getSerializeRepr in favor of 'getSerializer' and 'getDeserializer' (#3431)
* Deprecating Fw::Buffer::getSerializeRepr in favour of Fw::Buffer::getSerializer and Fw::Buffer::getDeserializer (#2714)

* Addressing PR comments.

* Add workflow for running fpp-to-json on Ref (#3430)

* Add workflow for running fpp-to-json on Ref

* Update working dirs

* Add FPP v3.0.0a4

* fpp v3.0.0a5

* Use setup action

* Rename workflow for better display

---------

Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>

* Return cmd repsonse and UT check (#3438)

Co-authored-by: Zimri Leisher <zimri.leisher@fireflyspace.com>

* Update Ref to use FPP telemetry packets (#3440)

* Revise Ref app

Convert Ref packets to FPP

* Remove header include for XML packets

* Remove trailing spaces

* Delete RefPackets.xml

* Update Ref packets

* Update fpp version

* Update fpp version

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>

* Refactored type organization (#3422)

* Refactored type organization

* Creating better configuration/types header hierarchy

* Replace FpConfig type aliases with FPP generated aliases

* Add the aliases to the FPP model

* Config + Type Aliases builds

* Renamed Fw/Types.h,hpp to Fw/FPrimeBasicTypes.h,hpp

* Updating to FPP-a7

* Adding newline

* sp

* Fixing minor nit from review

* Spurious ;

---------

Co-authored-by: Andrei Tumbar <andrei.tumbar@jpl.nasa.gov>

* Deprecating Fw::Buffer::getSerializeRepr in favour of Fw::Buffer::getSerializer and Fw::Buffer::getDeserializer (#2714)

* Incorporating PR suggested fixes

* Adding the setting of m_serLoc and m_deserLoc to the copy constructor. Moving those members from private to protected.

* Adding m_serLoc and m_deserLoc copying to = operator function. Fixing FPP tests to explicitly move deserialize location to offset.

* File typo (#3464)

* typo. SeekType does not have a CURRENT value but it does have a RELATIVE value

* applied formatter

* Incorporating PR comments

* Incorporating PR comments

---------

Co-authored-by: Justine West <35715959+jwest115@users.noreply.github.com>
Co-authored-by: Thomas Boyer-Chammard <49786685+thomas-bc@users.noreply.github.com>
Co-authored-by: Zimri Leisher <zimri.leisher@gmail.com>
Co-authored-by: Zimri Leisher <zimri.leisher@fireflyspace.com>
Co-authored-by: Rob Bocchino <bocchino@jpl.nasa.gov>
Co-authored-by: M Starch <LeStarch@googlemail.com>
Co-authored-by: Andrei Tumbar <andrei.tumbar@jpl.nasa.gov>
Co-authored-by: kevin-f-ortega <kevin.f.ortega@gmail.com>
2025-04-15 14:42:44 -07:00

169 lines
7.8 KiB
C++

// ======================================================================
// \title FrameAccumulator.cpp
// \author mstarch
// \brief cpp file for FrameAccumulator component implementation class
// ======================================================================
#include "Svc/FrameAccumulator/FrameAccumulator.hpp"
#include <new> // required for placement new in configure() member function
#include "Fw/FPrimeBasicTypes.hpp"
#include "Fw/Types/Assert.hpp"
namespace Svc {
// ----------------------------------------------------------------------
// Component construction and destruction
// ----------------------------------------------------------------------
FrameAccumulator ::FrameAccumulator(const char* const compName)
: FrameAccumulatorComponentBase(compName),
m_detector(nullptr),
m_memoryAllocator(nullptr),
m_memory(nullptr),
m_allocatorId(0) {}
FrameAccumulator ::~FrameAccumulator() {}
void FrameAccumulator ::configure(const FrameDetector& detector,
FwEnumStoreType allocationId,
Fw::MemAllocator& allocator,
FwSizeType store_size) {
bool recoverable = false;
void* data_void = allocator.allocate(allocationId, store_size, recoverable);
U8* data = new (data_void) U8[store_size];
FW_ASSERT(data != nullptr);
m_inRing.setup(data, store_size);
this->m_detector = &detector;
this->m_allocatorId = allocationId;
this->m_memoryAllocator = &allocator;
this->m_memory = data;
}
void FrameAccumulator ::cleanup() {
// If configuration happened, we must deallocate
if (this->m_memoryAllocator != nullptr) {
this->m_memoryAllocator->deallocate(this->m_allocatorId, this->m_memory);
this->m_memory = nullptr;
}
}
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
void FrameAccumulator ::dataIn_handler(FwIndexType portNum, Fw::Buffer& buffer, const Drv::RecvStatus& status) {
// Check whether there is data to process
if (status.e == Drv::RecvStatus::RECV_OK) {
// There is: process the data
this->processBuffer(buffer);
}
// Deallocate the buffer
this->bufferDeallocate_out(0, buffer);
}
void FrameAccumulator ::processBuffer(Fw::Buffer& buffer) {
const FwSizeType bufferSize = buffer.getSize();
U8* const bufferData = buffer.getData();
// Current offset into buffer
FwSizeType offset = 0;
// Remaining data in buffer
FwSizeType remaining = bufferSize;
for (FwSizeType i = 0; i < bufferSize; ++i) {
// If there is no data left or no space, exit the loop
if (remaining == 0 || this->m_inRing.get_free_size() == 0) {
break;
}
// Compute the size of data to serialize
const FwSizeType ringFreeSize = this->m_inRing.get_free_size();
const FwSizeType serSize = (ringFreeSize <= remaining) ? ringFreeSize : remaining;
// Serialize data into the ring buffer
const Fw::SerializeStatus status = this->m_inRing.serialize(&bufferData[offset], serSize);
// If data does not fit, there is a coding error
FW_ASSERT(status == Fw::FW_SERIALIZE_OK, static_cast<FwAssertArgType>(status),
static_cast<FwAssertArgType>(offset), static_cast<FwAssertArgType>(serSize));
// Process the data
this->processRing();
// Update buffer offset and remaining
offset += serSize;
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));
}
void FrameAccumulator ::processRing() {
FW_ASSERT(this->m_detector != nullptr);
// The number of remaining bytes in the ring buffer
FwSizeType remaining = 0;
// The protocol status
FrameDetector::Status status = FrameDetector::Status::FRAME_DETECTED;
// The ring buffer capacity
const FwSizeType ringCapacity = this->m_inRing.get_capacity();
// Process the ring buffer looking for at least the header
for (FwSizeType i = 0; i < ringCapacity; i++) {
// Get the number of bytes remaining in the ring buffer
remaining = this->m_inRing.get_allocated_size();
// If there are none, we are done
if (remaining == 0) {
break;
}
// size_out is a return variable we initialize to zero, but it should be overwritten
FwSizeType size_out = 0;
// Attempt to detect the frame without changing the circular buffer
status = this->m_detector->detect(this->m_inRing, size_out);
// Detect must not consume data in the ring buffer
FW_ASSERT(m_inRing.get_allocated_size() == remaining,
static_cast<FwAssertArgType>(m_inRing.get_allocated_size()), static_cast<FwAssertArgType>(remaining));
// On successful detection, consume data from the ring buffer and place it into an allocated frame
if (status == FrameDetector::FRAME_DETECTED) {
// size_out must be set to the size of the buffer and must fit within the existing data
FW_ASSERT(size_out != 0);
FW_ASSERT(size_out <= remaining, static_cast<FwAssertArgType>(size_out),
static_cast<FwAssertArgType>(remaining));
// check for overflow before casting down to U32
FW_ASSERT(size_out <= std::numeric_limits<U32>::max());
Fw::Buffer buffer = this->bufferAllocate_out(0, static_cast<U32>(size_out));
if (buffer.isValid()) {
// Copy data out of ring buffer into the allocated buffer
Fw::SerializeStatus serialize_status = this->m_inRing.peek(buffer.getData(), size_out);
FW_ASSERT(serialize_status == Fw::SerializeStatus::FW_SERIALIZE_OK);
// Consume (rotate) the data from the ring buffer
serialize_status = this->m_inRing.rotate(size_out);
FW_ASSERT(serialize_status == Fw::SerializeStatus::FW_SERIALIZE_OK);
FW_ASSERT(m_inRing.get_allocated_size() == remaining - size_out,
static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
static_cast<FwAssertArgType>(remaining), static_cast<FwAssertArgType>(size_out));
Fw::Buffer nullContext;
this->frameOut_out(0, buffer, nullContext);
} else {
// No buffer is available, we need to exit and try again later
this->log_WARNING_HI_NoBufferAvailable();
break;
}
}
// More data needed
else if (status == FrameDetector::MORE_DATA_NEEDED) {
// size_out can never be larger than the capacity of the ring. Otherwise all uplink will fail.
FW_ASSERT(size_out < m_inRing.get_capacity(), static_cast<FwAssertArgType>(size_out));
// Detection should report "more is needed" and set size_out to something larger than available data
FW_ASSERT(size_out > remaining, static_cast<FwAssertArgType>(size_out),
static_cast<FwAssertArgType>(remaining));
// Break out of loop: suspend detection until we receive another buffer
break;
}
// No frame was detected or an unknown status was received
else {
// Discard a single byte of data and start again
(void)this->m_inRing.rotate(1);
FW_ASSERT(m_inRing.get_allocated_size() == remaining - 1,
static_cast<FwAssertArgType>(m_inRing.get_allocated_size()),
static_cast<FwAssertArgType>(remaining));
}
}
}
} // namespace Svc