F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
DpCatalog.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title DpCatalog.cpp
3 // \author tcanham
4 // \brief cpp file for DpCatalog component implementation class
5 // ======================================================================
6 
7 #include "FpConfig.hpp"
8 #include "Fw/Dp/DpContainer.hpp"
10 
11 #include "Os/FileSystem.hpp"
12 #include "Os/File.hpp"
13 #include <new> // placement new
14 
15 namespace Svc {
16 
17  // ----------------------------------------------------------------------
18  // Component construction and destruction
19  // ----------------------------------------------------------------------
20 
22  DpCatalog(const char* const compName) :
23  DpCatalogComponentBase(compName),
24  m_initialized(false),
25  m_dpList(nullptr),
26  m_sortedDpList(nullptr),
27  m_numDpRecords(0),
28  m_numDpSlots(0),
29  m_numDirectories(0),
30  m_memSize(0),
31  m_memPtr(nullptr),
32  m_allocatorId(0),
33  m_allocator(nullptr),
34  m_xmitInProgress(false),
35  m_currXmitRecord(nullptr),
36  m_xmitCmdWait(false),
37  m_xmitBytes(0),
38  m_xmitOpCode(0),
39  m_xmitCmdSeq(0)
40  {
41 
42  }
43 
46  {}
47 
50  FwSizeType numDirs,
51  NATIVE_UINT_TYPE memId,
52  Fw::MemAllocator& allocator
53  ) {
54 
55  // Do some assertion checks
56  FW_ASSERT(numDirs <= DP_MAX_DIRECTORIES, static_cast<FwAssertArgType>(numDirs));
57 
58  // request memory for catalog
59  this->m_memSize = DP_MAX_FILES * (sizeof(DpStateEntry) + sizeof(DpSortedList));
60  bool notUsed; // we don't need to recover the catalog.
61  // request memory
62  this->m_memPtr = allocator.allocate(memId, this->m_memSize, notUsed);
63  // adjust to actual size if less allocated and only initialize
64  // if there is enough room for at least one record and memory
65  // was allocated
66  if (
67  (this->m_memSize >= (sizeof(DpSortedList) + sizeof(DpStateEntry))) and
68  (this->m_memPtr != nullptr)
69  ) {
70  // set the number of available record slots
71  this->m_numDpSlots = this->m_memSize / (sizeof(DpSortedList) + sizeof(DpStateEntry));
72  // initialize data structures
73  // state entry pointers will be at the beginning of the memory
74  this->m_dpList = static_cast<DpStateEntry*>(this->m_memPtr);
75  // sorted list will be after state structures
76  this->m_sortedDpList = reinterpret_cast<DpSortedList*>(&this->m_dpList[this->m_numDpSlots]);
77  for (FwSizeType slot = 0; slot < this->m_numDpSlots; slot++) {
78  // overlay new instance of the DpState entry on the memory
79  (void) new(&this->m_dpList[slot]) DpStateEntry();
80  this->m_dpList[slot].entry = false;
81  this->m_dpList[slot].dir = -1;
82  // initialize sorted list entry to empty
83  this->m_sortedDpList[slot].recPtr = nullptr;
84  this->m_sortedDpList[slot].sent = false;
85  }
86  }
87  else {
88  // if we don't have enough memory, set the number of records
89  // to zero for later detection
90  this->m_numDpSlots = 0;
91  }
92 
93  // assign directory names
94  for (FwSizeType dir = 0; dir < numDirs; dir++) {
95  this->m_directories[dir] = directories[dir];
96  }
97  this->m_numDirectories = numDirs;
98 
99  // store allocator
100  this->m_allocator = &allocator;
101  this->m_allocatorId = memId;
102  this->m_initialized = true;
103  }
104 
105  Fw::CmdResponse DpCatalog::doCatalogBuild() {
106 
107  // check initialization
108  if (not this->checkInit()) {
110  }
111 
112  // make sure a downlink is not in progress
113  if (this->m_xmitInProgress) {
116  }
117 
118  // keep cumulative number of files
119  FwSizeType totalFiles = 0;
120 
121  // file class instance for processing files
122  Os::File dpFile;
123  // Working buffer for DP headers
124  U8 dpBuff[Fw::DpContainer::MIN_PACKET_SIZE]; // FIXME: replace magic number
125  Fw::Buffer hdrBuff(dpBuff, sizeof(dpBuff)); // buffer for container header decoding
126  Fw::DpContainer container; // container object for extracting header fields
127 
128  // get file listings from file system
129  for (FwSizeType dir = 0; dir < this->m_numDirectories; dir++) {
130  // read in each directory and keep track of total
131  this->log_ACTIVITY_LO_ProcessingDirectory(this->m_directories[dir]);
132  U32 filesRead = 0;
133  U32 pendingFiles = 0;
134  U64 pendingDpBytes = 0;
135 
136  Os::FileSystem::Status fsStat =
138  this->m_directories[dir].toChar(),
139  static_cast<U32>(this->m_numDpSlots - totalFiles),
140  this->m_fileList,
141  filesRead
142  );
143  if (fsStat != Os::FileSystem::OP_OK) {
145  this->m_directories[dir],
146  fsStat
147  );
149  }
150 
151  // Assert number of files isn't more than asked
152  FW_ASSERT(
153  filesRead <= this->m_numDpSlots - totalFiles,
154  static_cast<FwAssertArgType>(filesRead),
155  static_cast<FwAssertArgType>(this->m_numDpSlots - totalFiles));
156 
157  // extract metadata for each file
158  for (FwNativeUIntType file = 0; file < filesRead; file++) {
159  Fw::String fullFile;
160  fullFile.format("%s/%s",
161  this->m_directories[dir].toChar(),
162  this->m_fileList[file].toChar()
163  );
164  this->log_ACTIVITY_LO_ProcessingFile(fullFile);
165 
166  // get file size
167  FwSignedSizeType fileSize = 0;
168  Os::FileSystem::Status sizeStat =
169  Os::FileSystem::getFileSize(fullFile.toChar(),fileSize);
170  if (sizeStat != Os::FileSystem::OP_OK) {
171  this->log_WARNING_HI_FileSizeError(fullFile, sizeStat);
172  continue;
173  }
174 
175  Os::File::Status stat = dpFile.open(fullFile.toChar(), Os::File::OPEN_READ);
176  if (stat != Os::File::OP_OK) {
177  this->log_WARNING_HI_FileOpenError(fullFile, stat);
178  continue;
179  }
180 
181  // Read DP header
183 
184  stat = dpFile.read(dpBuff, size);
185  if (stat != Os::File::OP_OK) {
186  this->log_WARNING_HI_FileReadError(fullFile, stat);
187  dpFile.close();
188  continue; // maybe next file is fine
189  }
190 
191  // if full header isn't read, something's wrong with the file, so skip
192  if (size != Fw::DpContainer::Header::SIZE) {
194  dpFile.close();
195  continue; // maybe next file is fine
196  }
197 
198  // if all is well, don't need the file any more
199  dpFile.close();
200 
201  // give buffer to container instance
202  container.setBuffer(hdrBuff);
203 
204  // reset header deserialization in the container
205  Fw::SerializeStatus desStat = container.deserializeHeader();
206  if (desStat != Fw::FW_SERIALIZE_OK) {
207  this->log_WARNING_HI_FileHdrDesError(fullFile, desStat);
208  }
209 
210  // add entry to catalog.
211  DpStateEntry entry;
212  entry.dir = static_cast<FwIndexType>(dir);
213  entry.record.setid(container.getId());
214  entry.record.setpriority(container.getPriority());
215  entry.record.setstate(container.getState());
216  entry.record.settSec(container.getTimeTag().getSeconds());
217  entry.record.settSub(container.getTimeTag().getUSeconds());
218  entry.record.setsize(static_cast<U64>(fileSize));
219  entry.entry = true;
220 
221  // assign the entry to the stored list
222  this->m_dpList[this->m_numDpRecords] = entry;
223 
224  // insert entry into sorted list. if can't insert, quit
225  if (not this->insertEntry(this->m_dpList[this->m_numDpRecords])) {
226  this->log_WARNING_HI_DpInsertError(entry.record);
227  break;
228  }
229 
230  if (entry.record.getstate() == Fw::DpState::UNTRANSMITTED) {
231  pendingFiles++;
232  pendingDpBytes += entry.record.getsize();
233  }
234 
235  // make sure we haven't exceeded the limit
236  if (this->m_numDpRecords > this->m_numDpSlots) {
237  this->log_WARNING_HI_DpCatalogFull(entry.record);
238  break;
239  }
240 
241  } // end for each file in a directory
242 
243  totalFiles += filesRead;
244 
246  this->m_directories[dir],
247  static_cast<U32>(totalFiles),
248  pendingFiles,
249  pendingDpBytes
250  );
251 
252  // check to see if catalog is full
253  // that means generated products exceed the catalog size
254  if (totalFiles == this->m_numDpSlots) {
255  this->log_WARNING_HI_CatalogFull(this->m_directories[dir]);
256  break;
257  }
258  } // end for each directory
259 
261 
262  return Fw::CmdResponse::OK;
263  }
264 
265  bool DpCatalog::insertEntry(DpStateEntry& entry) {
266 
267  // Prototype version: Just add the record to the end of the list
268  this->m_sortedDpList[this->m_numDpRecords].recPtr = &entry;
269  this->m_sortedDpList[this->m_numDpRecords].sent = false;
270  this->m_numDpRecords++;
271 
272  return true;
273 
274  }
275 
276  void DpCatalog::deleteEntry(DpStateEntry& entry) {
277 
278  }
279 
280  void DpCatalog::sendNextEntry() {
281 
282  // Make sure that pointer is valid
283  FW_ASSERT(this->m_sortedDpList);
284 
285  // Demo code: Walk through list and send first file
286  for (FwSizeType record = 0; record < this->m_numDpRecords; record++) {
287  if (not this->m_sortedDpList[record].sent) {
288  // make sure the entry is used
289  if (this->m_sortedDpList[record].recPtr != nullptr) {
290  // store pointer to record for fileDone callback
291  this->m_currXmitRecord = &this->m_sortedDpList[record];
292  // build file name
293  this->m_currXmitFileName.format(DP_FILENAME_FORMAT,
294  this->m_directories[this->m_sortedDpList[record].recPtr->dir].toChar(),
295  this->m_sortedDpList[record].recPtr->record.getid(),
296  this->m_sortedDpList[record].recPtr->record.gettSec(),
297  this->m_sortedDpList[record].recPtr->record.gettSub()
298  );
300  this->m_currXmitFileName,
301  static_cast<U32>(this->m_sortedDpList[record].recPtr->record.getsize()),
302  this->m_sortedDpList[record].recPtr->record.getpriority()
303  );
304  this->fileOut_out(0, this->m_currXmitFileName, this->m_currXmitFileName, 0, 0);
305  this->m_xmitBytes += this->m_sortedDpList[record].recPtr->record.getsize();
306  // quit looking when we find an entry
307  return;
308  }
309  // clean up record
310  this->m_sortedDpList[record].sent = true;
311  }
312  }
313 
314  // if none were found, finish transmission
315  this->log_ACTIVITY_HI_CatalogXmitCompleted(this->m_xmitBytes);
316  this->m_xmitInProgress = false;
317  this->m_xmitBytes = 0;
318  this->m_currXmitRecord = nullptr;
319 
320  if (this->m_xmitCmdWait) {
321  this->m_xmitCmdWait = false;
322  this->cmdResponse_out(this->m_xmitOpCode, this->m_xmitCmdSeq, Fw::CmdResponse::OK);
323  }
324 
325  }
326 
327  bool DpCatalog::checkInit() {
328  if (not this->m_initialized) {
330  return false;
331  }
332  else if (0 == this->m_numDpSlots) {
334  return false;
335  }
336 
337  return true;
338  }
339 
341  // only try to deallocate if both pointers are non-zero
342  // it's a way to more gracefully shut down if there are missing
343  // pointers
344  if ((this->m_allocator != nullptr) and (this->m_memPtr != nullptr)) {
345  this->m_allocator->deallocate(this->m_allocatorId, this->m_memPtr);
346  }
347 
348  }
349 
350 
351  // ----------------------------------------------------------------------
352  // Handler implementations for user-defined typed input ports
353  // ----------------------------------------------------------------------
354 
355  void DpCatalog ::
356  fileDone_handler(
357  NATIVE_INT_TYPE portNum,
358  const Svc::SendFileResponse& resp
359  )
360  {
361  if (this->m_currXmitRecord) {
362  this->m_currXmitRecord->sent = true;
363  this->log_ACTIVITY_LO_ProductComplete(this->m_currXmitFileName);
364  }
365 
366  this->sendNextEntry();
367  }
368 
369  void DpCatalog ::
370  pingIn_handler(
371  NATIVE_INT_TYPE portNum,
372  U32 key
373  )
374  {
375  // return code for health ping
376  this->pingOut_out(0, key);
377  }
378 
379  // ----------------------------------------------------------------------
380  // Handler implementations for commands
381  // ----------------------------------------------------------------------
382 
383  void DpCatalog ::
384  BUILD_CATALOG_cmdHandler(
385  FwOpcodeType opCode,
386  U32 cmdSeq
387  )
388  {
389  // invoke helper
390  this->cmdResponse_out(opCode, cmdSeq, this->doCatalogBuild());
391  }
392 
393  void DpCatalog ::
394  START_XMIT_CATALOG_cmdHandler(
395  FwOpcodeType opCode,
396  U32 cmdSeq,
397  Fw::Wait wait
398  )
399  {
400 
401  Fw::CmdResponse resp = this->doCatalogXmit();
402 
403  if (Fw::Wait::NO_WAIT == wait) {
404  this->cmdResponse_out(opCode, cmdSeq, resp);
405  this->m_xmitCmdWait = false;
406  this->m_xmitOpCode = 0;
407  this->m_xmitCmdSeq = 0;
408  }
409  else {
410  this->m_xmitCmdWait = true;
411  this->m_xmitOpCode = opCode;
412  this->m_xmitCmdSeq = cmdSeq;
413  }
414 
415  }
416 
417  Fw::CmdResponse DpCatalog::doCatalogXmit() {
418 
419  this->m_xmitBytes = 0;
420  this->sendNextEntry();
421  return Fw::CmdResponse::OK;
422 
423  }
424 
425 
426  void DpCatalog ::
427  STOP_XMIT_CATALOG_cmdHandler(
428  FwOpcodeType opCode,
429  U32 cmdSeq
430  )
431  {
432  // TODO
433  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
434  }
435 
436  void DpCatalog ::
437  CLEAR_CATALOG_cmdHandler(
438  FwOpcodeType opCode,
439  U32 cmdSeq
440  )
441  {
442  // TODO
443  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
444  }
445 
446 
447 }
#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
constexpr const char * DP_FILENAME_FORMAT
Definition: DpCfg.hpp:20
PlatformAssertArgType FwAssertArgType
Definition: FpConfig.h:34
PlatformUIntType FwNativeUIntType
Definition: FpConfig.h:42
PlatformSignedSizeType FwSignedSizeType
Definition: FpConfig.h:25
U32 FwOpcodeType
Definition: FpConfig.h:78
PlatformSizeType FwSizeType
Definition: FpConfig.h:30
PlatformIndexType FwIndexType
Definition: FpConfig.h:20
C++-compatible configuration header for fprime configuration.
Enum representing a command response.
@ EXECUTION_ERROR
Command had execution error.
@ OK
Command successfully executed.
A data product Container.
Definition: DpContainer.hpp:21
Fw::Time getTimeTag() const
FwDpIdType getId() const
Definition: DpContainer.hpp:91
static constexpr FwSizeType MIN_PACKET_SIZE
Definition: DpContainer.hpp:58
FwDpPriorityType getPriority() const
Fw::DpState getState() const
Get the product state.
Fw::SerializeStatus deserializeHeader()
Definition: DpContainer.cpp:38
void setBuffer(const Buffer &buffer)
Set the packet buffer.
@ UNTRANSMITTED
The untransmitted state.
virtual void deallocate(const NATIVE_UINT_TYPE identifier, void *ptr)=0
Deallocate memory.
virtual void * allocate(const NATIVE_UINT_TYPE identifier, NATIVE_UINT_TYPE &size, bool &recoverable)=0
Allocate memory.
void format(const CHAR *formatString,...)
write formatted string to buffer
Definition: StringBase.cpp:56
const char * toChar() const
Definition: String.hpp:50
U32 getUSeconds() const
Definition: Time.cpp:139
U32 getSeconds() const
Definition: Time.cpp:135
Wait or don't wait for something.
Definition: WaitEnumAc.hpp:19
Status read(U8 *buffer, FwSignedSizeType &size)
read data from this file into supplied buffer bounded by size
Definition: File.cpp:142
void close() override
close the file, if not opened then do nothing
Definition: File.cpp:69
Os::FileInterface::Status open(const char *path, Mode mode)
open file with supplied path and mode
Definition: File.cpp:45
@ BAD_SIZE
Invalid size parameter.
Definition: File.hpp:34
@ OP_OK
Operation was successful.
Definition: File.hpp:30
@ OPEN_READ
Open file for reading.
Definition: File.hpp:21
Auto-generated base for DpCatalog component.
Svc::SendFileResponse fileOut_out(FwIndexType portNum, const Fw::StringBase &sourceFileName, const Fw::StringBase &destFileName, U32 offset, U32 length)
Invoke output port fileOut.
void cmdResponse_out(FwOpcodeType opCode, U32 cmdSeq, Fw::CmdResponse response)
Emit command response.
void log_WARNING_HI_FileOpenError(const Fw::StringBase &loc, I32 stat)
void log_ACTIVITY_HI_ProcessingDirectoryComplete(const Fw::StringBase &loc, U32 total, U32 pending, U64 pending_bytes)
void log_ACTIVITY_LO_SendingProduct(const Fw::StringBase &file, U32 bytes, U32 prio)
void log_WARNING_HI_DirectoryOpenError(const Fw::StringBase &loc, I32 stat)
void log_ACTIVITY_LO_ProcessingFile(const Fw::StringBase &file)
void log_ACTIVITY_LO_ProcessingDirectory(const Fw::StringBase &directory)
void log_WARNING_HI_DpInsertError(Svc::DpRecord dp)
void log_WARNING_HI_FileReadError(const Fw::StringBase &file, I32 stat)
void pingOut_out(FwIndexType portNum, U32 key)
Invoke output port pingOut.
void log_WARNING_HI_FileSizeError(const Fw::StringBase &file, I32 stat)
void log_WARNING_HI_CatalogFull(const Fw::StringBase &dir)
void log_WARNING_HI_DpCatalogFull(Svc::DpRecord dp)
void log_WARNING_HI_FileHdrDesError(const Fw::StringBase &file, I32 stat)
void log_ACTIVITY_HI_CatalogXmitCompleted(U64 bytes)
void log_ACTIVITY_LO_ProductComplete(const Fw::StringBase &file)
void configure(Fw::FileNameString directories[DP_MAX_DIRECTORIES], FwSizeType numDirs, NATIVE_UINT_TYPE memId, Fw::MemAllocator &allocator)
Configure the DpCatalog.
Definition: DpCatalog.cpp:48
DpCatalog(const char *const compName)
DpCatalog constructor.
Definition: DpCatalog.cpp:22
~DpCatalog()
DpCatalog destructor.
Definition: DpCatalog.cpp:45
SerializeStatus
forward declaration for string
@ FW_SERIALIZE_OK
Serialization/Deserialization operation was successful.
Status getFileSize(const char *path, FwSizeType &size)
Definition: FileSystem.cpp:38
@ OP_OK
Operation was successful.
Definition: FileSystem.hpp:15
Status readDirectory(const char *path, const U32 maxNum, Fw::String fileArray[], U32 &numFiles)
read the contents of a directory. Size of fileArray should be maxNum. Cleaner implementation found in...
Definition: FileSystem.cpp:16
static const FwSizeType DP_MAX_FILES
static const FwSizeType DP_MAX_DIRECTORIES
#define U64(C)
Definition: sha.h:176
static constexpr FwSizeType SIZE
The header size.
Definition: DpContainer.hpp:48