44// \brief cpp file for PayloadHandler component implementation class
55// ======================================================================
66#include " Os/File.hpp"
7+ #include " Fw/Types/Assert.hpp"
8+ #include " Fw/Types/BasicTypes.hpp"
79#include " FprimeZephyrReference/Components/PayloadHandler/PayloadHandler.hpp"
10+ #include < cstring>
811
912namespace Components {
1013
1114// ----------------------------------------------------------------------
1215// Component construction and destruction
1316// ----------------------------------------------------------------------
1417
15- PayloadHandler ::PayloadHandler (const char * const compName) : PayloadHandlerComponentBase(compName) {}
16- PayloadHandler ::~PayloadHandler () {}
18+ PayloadHandler ::PayloadHandler (const char * const compName)
19+ : PayloadHandlerComponentBase(compName),
20+ m_protocolBufferSize(0 ),
21+ m_imageBufferUsed(0 ) {
22+ // Initialize protocol buffer to zero
23+ memset (m_protocolBuffer, 0 , PROTOCOL_BUFFER_SIZE);
24+ }
25+
26+ PayloadHandler ::~PayloadHandler () {
27+ // Clean up any allocated image buffer
28+ deallocateImageBuffer ();
29+ }
1730
1831
1932// ----------------------------------------------------------------------
@@ -25,7 +38,63 @@ void PayloadHandler ::in_port_handler(FwIndexType portNum, Fw::Buffer& buffer, c
2538
2639 this ->log_ACTIVITY_LO_UartReceived ();
2740
28-
41+ // Check if we received data successfully
42+ if (status != Drv::ByteStreamStatus::OP_OK) {
43+ // TODO - log error event?
44+ return ;
45+ }
46+
47+ // Check if buffer is valid
48+ if (!buffer.isValid ()) {
49+ return ;
50+ }
51+
52+ // Get the data from the incoming buffer
53+ const U8* data = buffer.getData ();
54+ const U32 dataSize = static_cast <U32>(buffer.getSize ());
55+
56+ // Unclear if this works as intended if data flow is interrupted
57+
58+ if (m_receiving && m_imageBuffer.isValid ()) {
59+ // Currently receiving image data - accumulate into large buffer
60+ // Check for end marker before accumulating
61+ I32 endMarkerPos = findImageEndMarker (data, dataSize);
62+
63+ if (endMarkerPos >= 0 ) {
64+ // Found end marker - accumulate data up to marker
65+ U32 finalDataSize = static_cast <U32>(endMarkerPos);
66+ if (finalDataSize > 0 ) {
67+ if (!accumulateImageData (data, finalDataSize)) {
68+ // Overflow
69+ this ->log_WARNING_HI_ImageDataOverflow ();
70+ deallocateImageBuffer ();
71+ m_receiving = false ;
72+ return ;
73+ }
74+ }
75+
76+ // Image is complete
77+ processCompleteImage ();
78+ } else {
79+ // No end marker yet - accumulate all data
80+ if (!accumulateImageData (data, dataSize)) {
81+ // Image buffer overflow
82+ this ->log_WARNING_HI_ImageDataOverflow ();
83+ deallocateImageBuffer ();
84+ m_receiving = false ;
85+ }
86+ }
87+ } else {
88+ // Not receiving image - accumulate protocol data
89+ if (!accumulateProtocolData (data, dataSize)) {
90+ // Protocol buffer overflow - clear and retry
91+ clearProtocolBuffer ();
92+ accumulateProtocolData (data, dataSize);
93+ }
94+
95+ // Process protocol buffer to detect image headers/commands
96+ processProtocolBuffer ();
97+ }
2998}
3099
31100// ----------------------------------------------------------------------
@@ -60,4 +129,230 @@ void PayloadHandler ::SEND_COMMAND_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, c
60129 this ->cmdResponse_out (opCode, cmdSeq, Fw::CmdResponse::OK);
61130}
62131
132+ // ----------------------------------------------------------------------
133+ // Helper method implementations
134+ // ----------------------------------------------------------------------
135+
136+ bool PayloadHandler ::accumulateProtocolData (const U8* data, U32 size) {
137+ // Check if we have space for the new data
138+ if (m_protocolBufferSize + size > PROTOCOL_BUFFER_SIZE) {
139+ return false ;
140+ }
141+
142+ // Copy data into protocol buffer
143+ memcpy (&m_protocolBuffer[m_protocolBufferSize], data, size);
144+ m_protocolBufferSize += size;
145+
146+ return true ;
147+ }
148+
149+ void PayloadHandler ::processProtocolBuffer () {
150+ // Process newline-terminated commands/headers
151+ // Looking for "<IMG_START>" to begin image reception
152+
153+ while (m_protocolBufferSize > 0 ) {
154+ // Look for newline character
155+ bool foundNewline = false ;
156+ U32 lineEndIndex = 0 ;
157+
158+ for (U32 i = 0 ; i < m_protocolBufferSize; ++i) {
159+ if (m_protocolBuffer[i] == ' \n ' || m_protocolBuffer[i] == ' \r ' ) {
160+ foundNewline = true ;
161+ lineEndIndex = i;
162+ break ;
163+ }
164+ }
165+
166+ if (foundNewline) {
167+ U32 lineLength = lineEndIndex;
168+
169+ // Skip carriage return if present (handle \r\n)
170+ // needed?
171+ if (lineEndIndex + 1 < m_protocolBufferSize &&
172+ m_protocolBuffer[lineEndIndex] == ' \r ' &&
173+ m_protocolBuffer[lineEndIndex + 1 ] == ' \n ' ) {
174+ lineEndIndex++;
175+ }
176+
177+ // Check if this is the image start command
178+ if (isImageStartCommand (m_protocolBuffer, lineLength)) {
179+ // Allocate buffer for image data
180+ if (allocateImageBuffer ()) {
181+ m_receiving = true ;
182+ m_bytes_received = 0 ;
183+
184+ // Generate filename
185+ char filename[64 ];
186+ snprintf (filename, sizeof (filename), " /mnt/data/img_%03d.jpg" , m_data_file_count++);
187+ m_currentFilename = filename;
188+
189+ this ->log_ACTIVITY_LO_ImageHeaderReceived ();
190+
191+ // Remove the IMG_START line from buffer
192+ U32 remainingSize = m_protocolBufferSize - (lineEndIndex + 1 );
193+ if (remainingSize > 0 ) {
194+ memmove (m_protocolBuffer,
195+ &m_protocolBuffer[lineEndIndex + 1 ],
196+ remainingSize);
197+ }
198+ m_protocolBufferSize = remainingSize;
199+
200+ // Any remaining data in protocol buffer is image data, so we transfer it to the image buffer immediately
201+ if (m_protocolBufferSize > 0 ) {
202+ if (!accumulateImageData (m_protocolBuffer, m_protocolBufferSize)) {
203+ this ->log_WARNING_HI_ImageDataOverflow ();
204+ deallocateImageBuffer ();
205+ m_receiving = false ;
206+ }
207+ clearProtocolBuffer (); // Clear now that data is moved
208+ }
209+
210+ // Exit loop - we're now in image receiving mode
211+ break ;
212+ } else {
213+ // Buffer allocation failed
214+ this ->log_WARNING_HI_BufferAllocationFailed (IMAGE_BUFFER_SIZE);
215+ }
216+ } else {
217+ // Log other commands/data for debugging
218+ for (U32 i = 0 ; i < lineLength && i < 16 ; ++i) {
219+ this ->log_ACTIVITY_LO_ByteReceived (m_protocolBuffer[i]);
220+ }
221+
222+ // Remove processed line from buffer
223+ U32 remainingSize = m_protocolBufferSize - (lineEndIndex + 1 );
224+ if (remainingSize > 0 ) {
225+ memmove (m_protocolBuffer,
226+ &m_protocolBuffer[lineEndIndex + 1 ],
227+ remainingSize);
228+ }
229+ m_protocolBufferSize = remainingSize;
230+ }
231+ } else {
232+ break ;
233+ }
234+ }
235+ }
236+
237+ void PayloadHandler ::clearProtocolBuffer () {
238+ m_protocolBufferSize = 0 ;
239+ memset (m_protocolBuffer, 0 , PROTOCOL_BUFFER_SIZE);
240+ }
241+
242+ bool PayloadHandler ::allocateImageBuffer () {
243+ // Request buffer from BufferManager
244+ m_imageBuffer = this ->allocate_out (0 , IMAGE_BUFFER_SIZE);
245+
246+ // Check if allocation succeeded
247+ if (!m_imageBuffer.isValid () || m_imageBuffer.getSize () < IMAGE_BUFFER_SIZE) {
248+ this ->log_WARNING_HI_BufferAllocationFailed (IMAGE_BUFFER_SIZE);
249+ deallocateImageBuffer ();
250+ return false ;
251+ }
252+
253+ m_imageBufferUsed = 0 ;
254+ return true ;
255+ }
256+
257+ void PayloadHandler ::deallocateImageBuffer () {
258+ if (m_imageBuffer.isValid ()) {
259+ this ->deallocate_out (0 , m_imageBuffer);
260+ m_imageBuffer = Fw::Buffer (); // Reset to invalid buffer
261+ }
262+ m_imageBufferUsed = 0 ;
263+ }
264+
265+ bool PayloadHandler ::accumulateImageData (const U8* data, U32 size) {
266+ FW_ASSERT (m_imageBuffer.isValid ());
267+
268+ // Check if we have space
269+ if (m_imageBufferUsed + size > m_imageBuffer.getSize ()) {
270+ return false ;
271+ }
272+
273+ // Copy data into image buffer
274+ memcpy (&m_imageBuffer.getData ()[m_imageBufferUsed], data, size);
275+ m_imageBufferUsed += size;
276+ m_bytes_received += size;
277+
278+ return true ;
279+ }
280+
281+ void PayloadHandler ::processCompleteImage () {
282+ FW_ASSERT (m_imageBuffer.isValid ());
283+
284+ // Write image to file
285+ Os::File::Status status = m_file.open (m_currentFilename.c_str (), Os::File::OPEN_WRITE);
286+
287+ if (status == Os::File::OP_OK) {
288+ // Os::File::write expects FwSizeType& for size parameter
289+ FwSizeType sizeToWrite = static_cast <FwSizeType>(m_imageBufferUsed);
290+ status = m_file.write (m_imageBuffer.getData (), sizeToWrite, Os::File::WaitType::NO_WAIT);
291+ m_file.close ();
292+
293+ if (status == Os::File::OP_OK) {
294+ // Success! sizeToWrite now contains actual bytes written
295+ Fw::LogStringArg pathArg (m_currentFilename.c_str ());
296+ this ->log_ACTIVITY_HI_DataReceived (m_imageBufferUsed, pathArg);
297+ } else {
298+ // TODO - log write error
299+ }
300+ } else {
301+ // TODO - log open error
302+ }
303+
304+ // Clean up
305+ deallocateImageBuffer ();
306+ m_receiving = false ;
307+ m_bytes_received = 0 ;
308+ }
309+
310+ I32 PayloadHandler ::findImageEndMarker (const U8* data, U32 size) {
311+ // Looking for "\n<IMG_END>" or "<IMG_END>"
312+ const char * marker = " <IMG_END>" ;
313+ const U32 markerLen = 9 ; // strlen("<IMG_END>")
314+
315+ if (size < markerLen) {
316+ return -1 ;
317+ }
318+
319+ // Search for the marker
320+ for (U32 i = 0 ; i <= size - markerLen; ++i) {
321+ bool found = true ;
322+ for (U32 j = 0 ; j < markerLen; ++j) {
323+ if (data[i + j] != static_cast <U8>(marker[j])) {
324+ found = false ;
325+ break ;
326+ }
327+ }
328+ if (found) {
329+ // Found marker at position i
330+ // If preceded by newline, back up to before newline
331+ if (i > 0 && data[i - 1 ] == ' \n ' ) {
332+ return static_cast <I32>(i - 1 );
333+ }
334+ return static_cast <I32>(i);
335+ }
336+ }
337+
338+ return -1 ; // Not found
339+ }
340+
341+ bool PayloadHandler ::isImageStartCommand (const U8* line, U32 length) {
342+ const char * command = " <IMG_START>" ;
343+ const U32 cmdLen = 11 ; // strlen("<IMG_START>")
344+
345+ if (length != cmdLen) {
346+ return false ;
347+ }
348+
349+ for (U32 i = 0 ; i < cmdLen; ++i) {
350+ if (line[i] != static_cast <U8>(command[i])) {
351+ return false ;
352+ }
353+ }
354+
355+ return true ;
356+ }
357+
63358} // namespace Components
0 commit comments