F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
AMPCSSequence.cpp
Go to the documentation of this file.
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 "Fw/Com/ComPacket.hpp"
13 #include "Fw/Types/Assert.hpp"
14 #include "Os/FileSystem.hpp"
16 extern "C" {
18 }
19 
20 namespace Svc {
21 
24  CmdSequencerComponentImpl::Sequence(component)
25  {
26 
27  }
28 
30  loadFile(const Fw::CmdStringArg& fileName)
31  {
32  // Make sure there is a buffer allocated
34 
35  Fw::CmdStringArg crcFileName = fileName;
36  crcFileName += ".CRC32";
37 
40 
41  const bool status = this->readCRCFile(crcFileName)
42  and this->getFileSize(fileName)
43  and this->readSequenceFile(fileName)
44  and this->validateCRC()
45  and this->m_header.validateTime(this->m_component)
46  and this->validateRecords();
47 
48  return status;
49  }
50 
51  bool AMPCSSequence ::
52  readCRCFile(Fw::CmdStringArg& crcFileName)
53  {
54 
55  bool result;
56 
57  this->setFileName(crcFileName);
58 
59  Os::File::Status status = this->m_crcFile.open(
60  crcFileName.toChar(),
62  );
63 
64  if (status == Os::File::OP_OK) {
65  result = this->readCRC() and this->deserializeCRC();
66  } else if (status == Os::File::DOESNT_EXIST) {
67  this->m_events.fileNotFound();
68  result = false;
69  } else {
70  this->m_events.fileReadError();
71  result = false;
72  }
73 
74  this->m_crcFile.close();
75  return result;
76 
77  }
78 
79  bool AMPCSSequence ::
80  getFileSize(const Fw::CmdStringArg& seqFileName)
81  {
82  bool status = true;
83  FwSizeType fileSize;
84  this->setFileName(seqFileName);
85  const Os::FileSystem::Status fileStatus =
87  // fileSize will be used to set a U32 member below, thus we check overflow first
88  bool overflow = static_cast<FwSizeType>(static_cast<U32>(fileSize)) != fileSize;
89  if (
90  fileStatus == Os::FileSystem::OP_OK and
91  fileSize >= sizeof(this->m_sequenceHeader) and
92  !overflow
93  ) {
94  this->m_header.m_fileSize = static_cast<U32>(fileSize - sizeof(this->m_sequenceHeader));
95  }
96  else {
97  this->m_events.fileInvalid(
99  overflow ? Os::FileSystem::OTHER_ERROR : fileStatus
100  );
101  status = false;
102  }
103  return status;
104  }
105 
106  bool AMPCSSequence ::
107  readSequenceFile(const Fw::CmdStringArg& seqFileName)
108  {
109 
110  bool result;
111 
112  this->setFileName(seqFileName);
113  Os::File::Status status = this->m_sequenceFile.open(
114  this->m_fileName.toChar(),
116  );
117 
118  if (status == Os::File::OP_OK) {
119  result = this->readOpenSequenceFile();
120  } else if (status == Os::File::DOESNT_EXIST) {
121  this->m_events.fileNotFound();
122  result = false;
123  } else {
124  this->m_events.fileReadError();
125  result = false;
126  }
127 
128  this->m_sequenceFile.close();
129  return result;
130 
131  }
132 
133  bool AMPCSSequence ::
134  validateCRC()
135  {
136  bool result = true;
137  if (this->m_crc.m_stored != this->m_crc.m_computed) {
138  this->m_events.fileCRCFailure(
139  this->m_crc.m_stored,
140  this->m_crc.m_computed
141  );
142  result = false;
143  }
144  return result;
145  }
146 
147  bool AMPCSSequence ::
148  validateRecords()
149  {
150  Fw::SerializeBufferBase& buffer = this->m_buffer;
151  Sequence::Record record;
152 
153  // Deserialize all records and count the records
154  const NATIVE_UINT_TYPE loopBound = buffer.getBuffLeft();
155  U32 numRecords = 0;
156  for ( ; numRecords < loopBound; ++numRecords) {
157  if (not this->hasMoreRecords()) {
158  break;
159  }
160  Fw::SerializeStatus status = this->deserializeRecord(record);
161  if (status != Fw::FW_SERIALIZE_OK) {
162  this->m_events.recordInvalid(numRecords, status);
163  return false;
164  }
165  }
166  // Set the number of records
167  this->m_header.m_numRecords = numRecords;
168  // Reset deserialization
169  this->reset();
170 
171  return true;
172  }
173 
175  hasMoreRecords() const
176  {
177  return this->m_buffer.getBuffLeft() > 0;
178  }
179 
181  nextRecord(Sequence::Record& record)
182  {
183  Fw::SerializeStatus status = this->deserializeRecord(record);
184  FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
185  }
186 
188  reset()
189  {
190  this->m_buffer.resetDeser();
191  }
192 
194  clear()
195  {
196  this->m_buffer.resetSer();
197  }
198 
199  bool AMPCSSequence ::
200  readCRC()
201  {
202 
203  Os::File& file = this->m_crcFile;
204  Fw::SerializeBufferBase& buffer = this->m_buffer;
205  bool status = true;
206  Fw::SerializeStatus ser_status;
207 
208  NATIVE_INT_TYPE readLen = sizeof(U32);
209  FW_ASSERT(readLen >= 0, readLen);
210 
211  ser_status = buffer.setBuffLen(readLen);
212  FW_ASSERT(ser_status == Fw::FW_SERIALIZE_OK, ser_status);
213 
214  U8 *const addr = buffer.getBuffAddr();
215  Os::File::Status fileStatus = file.read(addr, readLen);
216 
217  if (fileStatus != Os::File::OP_OK) {
218  this->m_events.fileInvalid(
220  file.getLastError()
221  );
222  status = false;
223  }
224 
225  return status;
226 
227  }
228 
229  bool AMPCSSequence ::
230  deserializeCRC()
231  {
232  bool status = true;
233  Fw::SerializeStatus serializeStatus =
234  this->m_buffer.deserialize(this->m_crc.m_stored);
235  if (serializeStatus != Fw::FW_SERIALIZE_OK) {
236  this->m_events.fileInvalid(
238  serializeStatus
239  );
240  status = false;
241  }
242  return status;
243  }
244 
245  bool AMPCSSequence ::
246  readOpenSequenceFile()
247  {
248  this->m_buffer.resetSer();
249  this->m_crc.init();
250  bool status = this->readSequenceHeader();
251  if (status) {
252  this->m_crc.update(
253  this->m_sequenceHeader,
254  sizeof(this->m_sequenceHeader)
255  );
256  status = this->readRecords();
257  }
258  if (status) {
259  U8 *const buffAddr = this->m_buffer.getBuffAddr();
260  const NATIVE_UINT_TYPE buffLen = this->m_buffer.getBuffLength();
261  FW_ASSERT(
262  buffLen == this->m_header.m_fileSize,
263  buffLen,
264  this->m_header.m_fileSize
265  );
266  this->m_crc.update(buffAddr, buffLen);
267  this->m_crc.finalize();
268  }
269  return status;
270  }
271 
272  bool AMPCSSequence ::
273  readSequenceHeader()
274  {
275 
276  Os::File& file = this->m_sequenceFile;
277 
278  bool status = true;
279 
280  NATIVE_INT_TYPE readLen = sizeof this->m_sequenceHeader;
281  const Os::File::Status fileStatus = file.read(
282  this->m_sequenceHeader,
283  readLen
284  );
285 
286  if (fileStatus != Os::File::OP_OK) {
287  this->m_events.fileInvalid(
289  file.getLastError()
290  );
291  status = false;
292  }
293 
294  if (status and readLen != sizeof this->m_sequenceHeader) {
295  this->m_events.fileInvalid(
297  readLen
298  );
299  status = false;
300  }
301 
302  return status;
303 
304  }
305 
306 
307  bool AMPCSSequence ::
308  readRecords()
309  {
310  Os::File& file = this->m_sequenceFile;
311  const NATIVE_UINT_TYPE size = this->m_header.m_fileSize;
312  Fw::SerializeBufferBase& buffer = this->m_buffer;
313  U8 *const addr = buffer.getBuffAddr();
314 
315  // Check file size
316  if (size > this->m_buffer.getBuffCapacity()) {
317  this->m_events.fileSizeError(size);
318  return false;
319  }
320 
321  NATIVE_INT_TYPE readLen = size;
322  const Os::File::Status fileStatus = file.read(addr, readLen);
323  // Check read status
324  if (fileStatus != Os::File::OP_OK) {
325  this->m_events.fileInvalid(
327  file.getLastError()
328  );
329  return false;
330  }
331  // Check read size
332  const NATIVE_UINT_TYPE readLenUint = readLen;
333  if (readLenUint != size) {
334  this->m_events.fileInvalid(
336  readLen
337  );
338  return false;
339  }
340  // set buffer size
341  const Fw::SerializeStatus serializeStatus = buffer.setBuffLen(size);
342  FW_ASSERT(serializeStatus == Fw::FW_SERIALIZE_OK, serializeStatus);
343  return true;
344  }
345 
346  Fw::SerializeStatus AMPCSSequence ::
347  deserializeRecord(Sequence::Record& record)
348  {
349 
350  Record::CmdLength::t cmdLength;
351 
352  Fw::SerializeStatus status =
353  this->deserializeTimeFlag(record.m_descriptor);
354 
355  if (status == Fw::FW_SERIALIZE_OK) {
356  status = this->deserializeTime(record.m_timeTag);
357  }
358  if (status == Fw::FW_SERIALIZE_OK) {
359  status = this->deserializeCmdLength(cmdLength);
360  }
361  if (status == Fw::FW_SERIALIZE_OK) {
362  status = this->translateCommand(record.m_command, cmdLength);
363  }
364 
365  return status;
366 
367  }
368 
369  Fw::SerializeStatus AMPCSSequence ::
370  deserializeTimeFlag(Sequence::Record::Descriptor& descriptor)
371  {
372  Fw::SerializeBufferBase& buffer = this->m_buffer;
373  Record::TimeFlag::Serial::t timeFlagSerial;
374  Fw::SerializeStatus status = buffer.deserialize(timeFlagSerial);
375  if (status == Fw::FW_SERIALIZE_OK) {
376  switch (timeFlagSerial) {
378  descriptor = Sequence::Record::ABSOLUTE;
379  break;
381  descriptor = Sequence::Record::RELATIVE;
382  break;
383  default:
385  break;
386  }
387  }
388  return status;
389  }
390 
391  Fw::SerializeStatus AMPCSSequence ::
392  deserializeTime(Fw::Time& timeTag)
393  {
394  Record::Time::t time;
395  Fw::SerializeBufferBase& buffer = this->m_buffer;
396  Fw::SerializeStatus status = buffer.deserialize(time);
397  if (status == Fw::FW_SERIALIZE_OK) {
398  timeTag.set(time, 0);
399  }
400  return status;
401  }
402 
403  Fw::SerializeStatus AMPCSSequence ::
404  deserializeCmdLength(Record::CmdLength::t& cmdLength)
405  {
406  Fw::SerializeBufferBase& buffer = this->m_buffer;
407  Fw::SerializeStatus status = buffer.deserialize(cmdLength);
408  if (status == Fw::FW_SERIALIZE_OK and cmdLength > buffer.getBuffLeft()) {
409  // Not enough data left
411  }
412  if (
413  status == Fw::FW_SERIALIZE_OK and
414  sizeof(FwPacketDescriptorType) + sizeof(U16) + cmdLength > Fw::ComBuffer::SERIALIZED_SIZE
415  ) {
416  // Record size is too big for com buffer
418  }
419  return status;
420  }
421 
422  Fw::SerializeStatus AMPCSSequence ::
423  translateCommand(
424  Fw::ComBuffer& comBuffer,
425  const Record::CmdLength::t cmdLength
426  )
427  {
428  Fw::SerializeBufferBase& buffer = this->m_buffer;
429  comBuffer.resetSer();
430  // Serialize the command packet descriptor
432  Fw::SerializeStatus status = comBuffer.serialize(cmdDescriptor);
433  FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
434  // Zero-extend the two-byte AMPCS opcode by two bytes
435  const U16 zeros = 0;
436  status = comBuffer.serialize(zeros);
437  FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
438  // Set the buffer length
439  const U32 fixedBuffLen = comBuffer.getBuffLength();
440  FW_ASSERT(
441  fixedBuffLen == sizeof(cmdDescriptor) + sizeof(zeros),
442  fixedBuffLen
443  );
444  const U32 totalBuffLen = fixedBuffLen + cmdLength;
445  status = comBuffer.setBuffLen(totalBuffLen);
446  FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
447  // Copy the opcode and argument bytes
448  NATIVE_UINT_TYPE size = cmdLength;
449  U8 *const addr = comBuffer.getBuffAddr();
450  FW_ASSERT(addr != nullptr);
451  // true means "don't serialize the length"
452  status = buffer.deserialize(&addr[fixedBuffLen], size, true);
453  return status;
454  }
455 
456 }
457 
#define FW_ASSERT(...)
Definition: Assert.hpp:14
PlatformIntType NATIVE_INT_TYPE
Definition: BasicTypes.h:51
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:26
PlatformUIntType NATIVE_UINT_TYPE
Definition: BasicTypes.h:52
@ TB_DONT_CARE
Don't care value for sequences. If FwTimeBaseStoreType is changed, value should be changed.
Definition: FpConfig.h:42
#define FW_CONTEXT_DONT_CARE
Don't care value for time contexts in sequences.
Definition: FpConfig.h:45
U32 FwPacketDescriptorType
Definition: FpConfig.h:53
PlatformSizeType FwSizeType
Definition: FpConfig.h:18
const char * toChar() const
Definition: CmdString.cpp:48
U8 * getBuffAddr()
gets buffer address for data filling
Definition: ComBuffer.cpp:40
NATIVE_UINT_TYPE getBuffCapacity() const
returns capacity, not current size, of buffer
U8 * getBuffAddr()
gets buffer address for data filling
NATIVE_UINT_TYPE getBuffLeft() const
returns how much deserialization buffer is left
virtual U8 * getBuffAddr()=0
gets buffer address for data filling
void resetDeser()
reset deserialization to beginning
SerializeStatus setBuffLen(NATIVE_UINT_TYPE length)
sets buffer length manually after filling with data
void resetSer()
reset to beginning of buffer to reuse for serialization
SerializeStatus deserialize(U8 &val)
deserialize 8-bit unsigned int
SerializeStatus serialize(U8 val)
serialize 8-bit unsigned int
NATIVE_UINT_TYPE getBuffLength() const
returns current buffer size
Definition: Time.hpp:9
void set(U32 seconds, U32 useconds)
Definition: Time.cpp:25
void close()
close file
Definition: File.cpp:36
Status
Definition: File.hpp:23
@ DOESNT_EXIST
File doesn't exist (for read)
Definition: File.hpp:25
@ OP_OK
Operation was successful.
Definition: File.hpp:24
@ OPEN_READ
Open file for reading.
Definition: File.hpp:15
NATIVE_INT_TYPE getLastError()
read back last error code (typically errno)
Definition: File.cpp:38
Status open(const char *fileName, Mode mode)
open file. Writing creates file if it doesn't exist
Definition: File.cpp:12
Status read(void *buffer, NATIVE_INT_TYPE &size, bool waitForFull=true)
waitForFull = true to wait for all bytes to be read
Definition: File.cpp:28
bool hasMoreRecords() const
AMPCSSequence(CmdSequencerComponentImpl &component)
Construct an AMPCSSequence.
bool loadFile(const Fw::CmdStringArg &fileName)
void nextRecord(Sequence::Record &record)
void fileSizeError(const U32 size)
File size error.
Definition: Events.cpp:68
void fileCRCFailure(const U32 storedCRC, const U32 computedCRC)
File CRC failure.
Definition: Events.cpp:24
void recordInvalid(const U32 recordNumber, const I32 error)
Record invalid.
Definition: Events.cpp:80
void fileInvalid(const CmdSequencer_FileReadStage::t stage, const I32 error)
File invalid.
Definition: Events.cpp:37
bool validateTime(CmdSequencerComponentImpl &component)
Definition: Sequence.cpp:42
FwTimeContextStoreType m_timeContext
The context of the sequence.
U32 m_numRecords
The number of records in the sequence.
TimeBase m_timeBase
The time base of the sequence.
Fw::ExternalSerializeBuffer m_buffer
Serialize buffer to hold the binary sequence data.
CmdSequencerComponentImpl & m_component
The enclosing component.
void setFileName(const Fw::CmdStringArg &fileName)
Set the file name. Also sets the log file name.
Definition: Sequence.cpp:111
Fw::CmdStringArg m_fileName
The sequence file name.
SerializeStatus
forward declaration for string
@ FW_DESERIALIZE_FORMAT_ERROR
Deserialization data had incorrect values (unexpected data types)
@ FW_SERIALIZE_OK
Serialization/Deserialization operation was successful.
@ FW_DESERIALIZE_SIZE_MISMATCH
Data was left in the buffer, but not enough to deserialize.
Status getFileSize(const char *path, FwSizeType &size)
append file origin to destination file. If boolean true, creates a brand new file if the destination ...
Definition: FileSystem.cpp:38
@ OP_OK
Operation was successful.
Definition: FileSystem.hpp:15
@ OTHER_ERROR
other OS-specific error
Definition: FileSystem.hpp:25
Definition: File.cpp:6
U16 t
The type of the command length field.
U32 t
The type of the time field.
void update(const BYTE *buffer, NATIVE_UINT_TYPE bufferSize)
Update computed CRC.