GCC Code Coverage Report


Directory: ./
File: Svc/CmdSequencer/formats/AMPCSSequence.cpp
Date: 2026-09-03 22:12:29
Exec Total Coverage
Lines: 0 209 0.0%
Functions: 0 21 0.0%
Branches: 0 126 0.0%

Line Branch Exec Source
1 // \title AMPCSSequence.cpp
2 // \author Rob Bocchino
3 // \brief AMPCSSequence implementation
4 //
5 // \copyright
6 // Copyright (C) 2009-2018 California Institute of Technology.
7 // ALL RIGHTS RESERVED. United States Government Sponsorship
8 // acknowledged.
9 //
10 // ======================================================================
11
12 #include "Svc/CmdSequencer/formats/AMPCSSequence.hpp"
13 #include <Utils/Hash/Hash.hpp>
14 #include "Fw/Com/ComPacket.hpp"
15 #include "Fw/Types/Assert.hpp"
16 #include "Os/FileSystem.hpp"
17
18 namespace Svc {
19
20 AMPCSSequence ::AMPCSSequence(CmdSequencerComponentImpl& component) : CmdSequencerComponentImpl::Sequence(component) {}
21
22 bool AMPCSSequence ::loadFile(const Fw::ConstStringBase& fileName) {
23 // Make sure there is a buffer allocated
24 FW_ASSERT(this->m_buffer.getBuffAddr() != nullptr);
25
26 Fw::CmdStringArg crcFileName(fileName);
27 crcFileName += ".CRC32";
28
29 this->m_header.m_timeBase = TimeBase::TB_DONT_CARE;
30 this->m_header.m_timeContext = FW_CONTEXT_DONT_CARE;
31
32 const bool status = this->readCRCFile(crcFileName) and this->getFileSize(fileName) and
33 this->readSequenceFile(fileName) and this->validateCRC() and
34 this->m_header.validateTime(this->m_component) and this->validateRecords();
35
36 return status;
37 }
38
39 bool AMPCSSequence ::readCRCFile(Fw::CmdStringArg& crcFileName) {
40 bool result;
41
42 this->setFileName(crcFileName);
43
44 Os::File::Status status = this->m_crcFile.open(crcFileName.toChar(), Os::File::OPEN_READ);
45
46 if (status == Os::File::OP_OK) {
47 result = this->readCRC() and this->deserializeCRC();
48 } else if (status == Os::File::DOESNT_EXIST) {
49 this->m_events.fileNotFound();
50 result = false;
51 } else {
52 this->m_events.fileReadError();
53 result = false;
54 }
55
56 this->m_crcFile.close();
57 return result;
58 }
59
60 bool AMPCSSequence ::getFileSize(const Fw::ConstStringBase& seqFileName) {
61 bool status = true;
62 FwSizeType fileSize;
63 this->setFileName(seqFileName);
64 const Os::FileSystem::Status fileStatus = Os::FileSystem::getFileSize(this->m_fileName.toChar(), fileSize);
65 if (fileStatus == Os::FileSystem::OP_OK and fileSize >= static_cast<FwSizeType>(sizeof(this->m_sequenceHeader))) {
66 this->m_header.m_fileSize =
67 static_cast<U32>(fileSize - static_cast<FwSizeType>(sizeof(this->m_sequenceHeader)));
68 } else {
69 this->m_events.fileInvalid(CmdSequencer_FileReadStage::READ_HEADER_SIZE, fileStatus);
70 status = false;
71 }
72 return status;
73 }
74
75 bool AMPCSSequence ::readSequenceFile(const Fw::ConstStringBase& seqFileName) {
76 bool result;
77
78 this->setFileName(seqFileName);
79 Os::File::Status status = this->m_sequenceFile.open(this->m_fileName.toChar(), Os::File::OPEN_READ);
80
81 if (status == Os::File::OP_OK) {
82 result = this->readOpenSequenceFile();
83 } else if (status == Os::File::DOESNT_EXIST) {
84 this->m_events.fileNotFound();
85 result = false;
86 } else {
87 this->m_events.fileReadError();
88 result = false;
89 }
90
91 this->m_sequenceFile.close();
92 return result;
93 }
94
95 bool AMPCSSequence ::validateCRC() {
96 bool result = true;
97 U32 computed = this->m_crc.finalize();
98 if (this->m_crc.m_stored != computed) {
99 this->m_events.fileCRCFailure(this->m_crc.m_stored, computed);
100 result = false;
101 }
102 return result;
103 }
104
105 bool AMPCSSequence ::validateRecords() {
106 Fw::LinearBufferBase& buffer = this->m_buffer;
107 Sequence::Record record;
108
109 // Deserialize all records and count the records
110 const U32 loopBound = static_cast<U32>(buffer.getDeserializeSizeLeft());
111 U32 numRecords = 0;
112 for (; numRecords < loopBound; ++numRecords) {
113 if (not this->hasMoreRecords()) {
114 break;
115 }
116 Fw::SerializeStatus status = this->deserializeRecord(record);
117 if (status != Fw::FW_SERIALIZE_OK) {
118 this->m_events.recordInvalid(numRecords, status);
119 return false;
120 }
121 }
122 // Set the number of records
123 this->m_header.m_numRecords = numRecords;
124 // Reset deserialization
125 this->reset();
126
127 return true;
128 }
129
130 bool AMPCSSequence ::hasMoreRecords() const {
131 return this->m_buffer.getDeserializeSizeLeft() > 0;
132 }
133
134 void AMPCSSequence ::nextRecord(Sequence::Record& record) {
135 Fw::SerializeStatus status = this->deserializeRecord(record);
136 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
137 }
138
139 void AMPCSSequence ::reset() {
140 this->m_buffer.resetDeser();
141 }
142
143 void AMPCSSequence ::clear() {
144 this->m_buffer.resetSer();
145 }
146
147 bool AMPCSSequence ::readCRC() {
148 Os::File& file = this->m_crcFile;
149 Fw::LinearBufferBase& buffer = this->m_buffer;
150 bool status = true;
151 Fw::SerializeStatus ser_status;
152
153 FwSizeType readLen = static_cast<FwSizeType>(sizeof(U32));
154 ser_status = buffer.setBuffLen(static_cast<Fw::Serializable::SizeType>(readLen));
155 FW_ASSERT(ser_status == Fw::FW_SERIALIZE_OK, ser_status);
156
157 U8* const addr = buffer.getBuffAddr();
158 Os::File::Status fileStatus = file.read(addr, readLen);
159
160 if (fileStatus != Os::File::OP_OK) {
161 this->m_events.fileInvalid(CmdSequencer_FileReadStage::READ_SEQ_CRC, fileStatus);
162 status = false;
163 }
164
165 return status;
166 }
167
168 bool AMPCSSequence ::deserializeCRC() {
169 bool status = true;
170 Fw::SerializeStatus serializeStatus = this->m_buffer.deserializeTo(this->m_crc.m_stored);
171 if (serializeStatus != Fw::FW_SERIALIZE_OK) {
172 this->m_events.fileInvalid(CmdSequencer_FileReadStage::READ_SEQ_CRC, serializeStatus);
173 status = false;
174 }
175 return status;
176 }
177
178 bool AMPCSSequence ::readOpenSequenceFile() {
179 this->m_buffer.resetSer();
180 this->m_crc.init();
181 bool status = this->readSequenceHeader();
182 if (status) {
183 this->m_crc.update(this->m_sequenceHeader, sizeof(this->m_sequenceHeader));
184 status = this->readRecords();
185 }
186 if (status) {
187 U8* const buffAddr = this->m_buffer.getBuffAddr();
188 const FwSizeType buffLen = this->m_buffer.getSize();
189 FW_ASSERT(buffLen == this->m_header.m_fileSize, static_cast<FwAssertArgType>(buffLen),
190 static_cast<FwAssertArgType>(this->m_header.m_fileSize));
191 this->m_crc.update(buffAddr, buffLen);
192 }
193 return status;
194 }
195
196 bool AMPCSSequence ::readSequenceHeader() {
197 Os::File& file = this->m_sequenceFile;
198
199 bool status = true;
200
201 FwSizeType readLen = sizeof this->m_sequenceHeader;
202 const Os::File::Status fileStatus = file.read(this->m_sequenceHeader, readLen);
203
204 if (fileStatus != Os::File::OP_OK) {
205 this->m_events.fileInvalid(CmdSequencer_FileReadStage::READ_HEADER, fileStatus);
206 status = false;
207 }
208
209 if (status and readLen != sizeof this->m_sequenceHeader) {
210 this->m_events.fileInvalid(CmdSequencer_FileReadStage::READ_HEADER_SIZE, static_cast<I32>(readLen));
211 status = false;
212 }
213
214 return status;
215 }
216
217 bool AMPCSSequence ::readRecords() {
218 Os::File& file = this->m_sequenceFile;
219 const FwSizeType size = this->m_header.m_fileSize;
220 Fw::LinearBufferBase& buffer = this->m_buffer;
221 U8* const addr = buffer.getBuffAddr();
222
223 // Check file size
224 if (size > this->m_buffer.getCapacity()) {
225 this->m_events.fileSizeError(static_cast<U32>(size));
226 return false;
227 }
228
229 FwSizeType readLen = size;
230 const Os::File::Status fileStatus = file.read(addr, readLen);
231 // Check read status
232 if (fileStatus != Os::File::OP_OK) {
233 this->m_events.fileInvalid(CmdSequencer_FileReadStage::READ_SEQ_DATA, fileStatus);
234 return false;
235 }
236 // Check read size
237 const FwSizeType readLenUint = static_cast<FwSizeType>(readLen);
238 if (readLenUint != size) {
239 this->m_events.fileInvalid(CmdSequencer_FileReadStage::READ_SEQ_DATA_SIZE, static_cast<I32>(readLen));
240 return false;
241 }
242 // set buffer size
243 const Fw::SerializeStatus serializeStatus = buffer.setBuffLen(size);
244 FW_ASSERT(serializeStatus == Fw::FW_SERIALIZE_OK, serializeStatus);
245 return true;
246 }
247
248 Fw::SerializeStatus AMPCSSequence ::deserializeRecord(Sequence::Record& record) {
249 Record::CmdLength::t cmdLength;
250
251 Fw::SerializeStatus status = this->deserializeTimeFlag(record.m_descriptor);
252
253 if (status == Fw::FW_SERIALIZE_OK) {
254 status = this->deserializeTime(record.m_timeTag);
255 }
256 if (status == Fw::FW_SERIALIZE_OK) {
257 status = this->deserializeCmdLength(cmdLength);
258 }
259 if (status == Fw::FW_SERIALIZE_OK) {
260 status = this->translateCommand(record.m_command, cmdLength);
261 }
262
263 return status;
264 }
265
266 Fw::SerializeStatus AMPCSSequence ::deserializeTimeFlag(Sequence::Record::Descriptor& descriptor) {
267 Fw::LinearBufferBase& buffer = this->m_buffer;
268 Record::TimeFlag::Serial::t timeFlagSerial;
269 Fw::SerializeStatus status = buffer.deserializeTo(timeFlagSerial);
270 if (status == Fw::FW_SERIALIZE_OK) {
271 switch (timeFlagSerial) {
272 case Record::TimeFlag::ABSOLUTE:
273 descriptor = Sequence::Record::ABSOLUTE;
274 break;
275 case Record::TimeFlag::RELATIVE:
276 descriptor = Sequence::Record::RELATIVE;
277 break;
278 default:
279 status = Fw::FW_DESERIALIZE_FORMAT_ERROR;
280 break;
281 }
282 }
283 return status;
284 }
285
286 Fw::SerializeStatus AMPCSSequence ::deserializeTime(Fw::Time& timeTag) {
287 Record::Time::t time;
288 Fw::LinearBufferBase& buffer = this->m_buffer;
289 Fw::SerializeStatus status = buffer.deserializeTo(time);
290 if (status == Fw::FW_SERIALIZE_OK) {
291 timeTag.set(time, 0);
292 }
293 return status;
294 }
295
296 Fw::SerializeStatus AMPCSSequence ::deserializeCmdLength(Record::CmdLength::t& cmdLength) {
297 Fw::LinearBufferBase& buffer = this->m_buffer;
298 Fw::SerializeStatus status = buffer.deserializeTo(cmdLength);
299 if (status == Fw::FW_SERIALIZE_OK and cmdLength > buffer.getDeserializeSizeLeft()) {
300 // Not enough data left
301 status = Fw::FW_DESERIALIZE_SIZE_MISMATCH;
302 }
303 // The translated record occupies the packet descriptor, the zero-extension bytes prepended to
304 // the two-byte AMPCS opcode, and the record body. It must fit the ComBuffer capacity:
305 // SERIALIZED_SIZE is the capacity plus the stored length, and comparing against it admits
306 // records that setBuffLen then rejects, asserting in translateCommand
307 const FwSizeType translatedSize =
308 sizeof(FwPacketDescriptorType) + (sizeof(FwOpcodeType) - 2) + static_cast<FwSizeType>(cmdLength);
309 if (status == Fw::FW_SERIALIZE_OK and translatedSize > FW_COM_BUFFER_MAX_SIZE) {
310 // Record size is too big for com buffer
311 status = Fw::FW_DESERIALIZE_SIZE_MISMATCH;
312 }
313 return status;
314 }
315
316 Fw::SerializeStatus AMPCSSequence ::translateCommand(Fw::ComBuffer& comBuffer, const Record::CmdLength::t cmdLength) {
317 Fw::LinearBufferBase& buffer = this->m_buffer;
318 comBuffer.resetSer();
319 // Serialize the command packet descriptor
320 const FwPacketDescriptorType cmdDescriptor = Fw::ComPacketType::FW_PACKET_COMMAND;
321 Fw::SerializeStatus status = comBuffer.serializeFrom(cmdDescriptor);
322 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
323 // Zero-extend the two-byte AMPCS opcode by (sizeof(FwOpcodeType) - 2) bytes
324 static_assert(sizeof(FwOpcodeType) >= 2, "FwOpcodeType must be at least two bytes wide");
325 U32 sizeOfZeros = 0;
326 const FwIndexType bytesToExtend = sizeof(FwOpcodeType) - 2;
327 const U8 zeros = 0;
328 for (FwIndexType i = 0; i < bytesToExtend; i++) {
329 status = comBuffer.serializeFrom(zeros);
330 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
331 sizeOfZeros += static_cast<U32>(sizeof(zeros));
332 }
333 // Set the buffer length
334 const U32 fixedBuffLen = static_cast<U32>(comBuffer.getSize());
335 FW_ASSERT(fixedBuffLen == sizeof(cmdDescriptor) + sizeOfZeros, static_cast<FwAssertArgType>(fixedBuffLen));
336 const U32 totalBuffLen = fixedBuffLen + cmdLength;
337 status = comBuffer.setBuffLen(totalBuffLen);
338 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
339 // Copy the opcode and argument bytes
340 FwSizeType size = cmdLength;
341 U8* const addr = comBuffer.getBuffAddr();
342 FW_ASSERT(addr != nullptr);
343 // true means "don't serialize the length"
344 status = buffer.deserializeTo(&addr[fixedBuffLen], size, Fw::Serialization::OMIT_LENGTH);
345 return status;
346 }
347
348 } // namespace Svc
349