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  FwSizeType filesRead = 0;
133  U32 pendingFiles = 0;
134  U64 pendingDpBytes = 0;
135 
136  Os::Directory dpDir;
137  Os::Directory::Status status = dpDir.open(this->m_directories[dir].toChar(), Os::Directory::OpenMode::READ);
138  if (status != Os::Directory::OP_OK) {
140  this->m_directories[dir],
141  status
142  );
144  }
145  status = dpDir.readDirectory(this->m_fileList, (this->m_numDpSlots - totalFiles), filesRead);
146 
147  if (status != Os::Directory::OP_OK) {
149  this->m_directories[dir],
150  status
151  );
153  }
154 
155  // Assert number of files isn't more than asked
156  FW_ASSERT(
157  filesRead <= this->m_numDpSlots - totalFiles,
158  static_cast<FwAssertArgType>(filesRead),
159  static_cast<FwAssertArgType>(this->m_numDpSlots - totalFiles));
160 
161  // extract metadata for each file
162  for (FwNativeUIntType file = 0; file < filesRead; file++) {
163  Fw::String fullFile;
164  fullFile.format("%s/%s",
165  this->m_directories[dir].toChar(),
166  this->m_fileList[file].toChar()
167  );
168  this->log_ACTIVITY_LO_ProcessingFile(fullFile);
169 
170  // get file size
171  FwSignedSizeType fileSize = 0;
172  Os::FileSystem::Status sizeStat =
173  Os::FileSystem::getFileSize(fullFile.toChar(),fileSize);
174  if (sizeStat != Os::FileSystem::OP_OK) {
175  this->log_WARNING_HI_FileSizeError(fullFile, sizeStat);
176  continue;
177  }
178 
179  Os::File::Status stat = dpFile.open(fullFile.toChar(), Os::File::OPEN_READ);
180  if (stat != Os::File::OP_OK) {
181  this->log_WARNING_HI_FileOpenError(fullFile, stat);
182  continue;
183  }
184 
185  // Read DP header
187 
188  stat = dpFile.read(dpBuff, size);
189  if (stat != Os::File::OP_OK) {
190  this->log_WARNING_HI_FileReadError(fullFile, stat);
191  dpFile.close();
192  continue; // maybe next file is fine
193  }
194 
195  // if full header isn't read, something's wrong with the file, so skip
196  if (size != Fw::DpContainer::Header::SIZE) {
198  dpFile.close();
199  continue; // maybe next file is fine
200  }
201 
202  // if all is well, don't need the file any more
203  dpFile.close();
204 
205  // give buffer to container instance
206  container.setBuffer(hdrBuff);
207 
208  // reset header deserialization in the container
209  Fw::SerializeStatus desStat = container.deserializeHeader();
210  if (desStat != Fw::FW_SERIALIZE_OK) {
211  this->log_WARNING_HI_FileHdrDesError(fullFile, desStat);
212  }
213 
214  // add entry to catalog.
215  DpStateEntry entry;
216  entry.dir = static_cast<FwIndexType>(dir);
217  entry.record.setid(container.getId());
218  entry.record.setpriority(container.getPriority());
219  entry.record.setstate(container.getState());
220  entry.record.settSec(container.getTimeTag().getSeconds());
221  entry.record.settSub(container.getTimeTag().getUSeconds());
222  entry.record.setsize(static_cast<U64>(fileSize));
223  entry.entry = true;
224 
225  // assign the entry to the stored list
226  this->m_dpList[this->m_numDpRecords] = entry;
227 
228  // insert entry into sorted list. if can't insert, quit
229  if (not this->insertEntry(this->m_dpList[this->m_numDpRecords])) {
230  this->log_WARNING_HI_DpInsertError(entry.record);
231  break;
232  }
233 
234  if (entry.record.getstate() == Fw::DpState::UNTRANSMITTED) {
235  pendingFiles++;
236  pendingDpBytes += entry.record.getsize();
237  }
238 
239  // make sure we haven't exceeded the limit
240  if (this->m_numDpRecords > this->m_numDpSlots) {
241  this->log_WARNING_HI_DpCatalogFull(entry.record);
242  break;
243  }
244 
245  } // end for each file in a directory
246 
247  totalFiles += filesRead;
248 
250  this->m_directories[dir],
251  static_cast<U32>(totalFiles),
252  pendingFiles,
253  pendingDpBytes
254  );
255 
256  // check to see if catalog is full
257  // that means generated products exceed the catalog size
258  if (totalFiles == this->m_numDpSlots) {
259  this->log_WARNING_HI_CatalogFull(this->m_directories[dir]);
260  break;
261  }
262  } // end for each directory
263 
265 
266  return Fw::CmdResponse::OK;
267  }
268 
269  bool DpCatalog::insertEntry(DpStateEntry& entry) {
270 
271  // Prototype version: Just add the record to the end of the list
272  this->m_sortedDpList[this->m_numDpRecords].recPtr = &entry;
273  this->m_sortedDpList[this->m_numDpRecords].sent = false;
274  this->m_numDpRecords++;
275 
276  return true;
277 
278  }
279 
280  void DpCatalog::deleteEntry(DpStateEntry& entry) {
281 
282  }
283 
284  void DpCatalog::sendNextEntry() {
285 
286  // Make sure that pointer is valid
287  FW_ASSERT(this->m_sortedDpList);
288 
289  // Demo code: Walk through list and send first file
290  for (FwSizeType record = 0; record < this->m_numDpRecords; record++) {
291  if (not this->m_sortedDpList[record].sent) {
292  // make sure the entry is used
293  if (this->m_sortedDpList[record].recPtr != nullptr) {
294  // store pointer to record for fileDone callback
295  this->m_currXmitRecord = &this->m_sortedDpList[record];
296  // build file name
297  this->m_currXmitFileName.format(DP_FILENAME_FORMAT,
298  this->m_directories[this->m_sortedDpList[record].recPtr->dir].toChar(),
299  this->m_sortedDpList[record].recPtr->record.getid(),
300  this->m_sortedDpList[record].recPtr->record.gettSec(),
301  this->m_sortedDpList[record].recPtr->record.gettSub()
302  );
304  this->m_currXmitFileName,
305  static_cast<U32>(this->m_sortedDpList[record].recPtr->record.getsize()),
306  this->m_sortedDpList[record].recPtr->record.getpriority()
307  );
308  this->fileOut_out(0, this->m_currXmitFileName, this->m_currXmitFileName, 0, 0);
309  this->m_xmitBytes += this->m_sortedDpList[record].recPtr->record.getsize();
310  // quit looking when we find an entry
311  return;
312  }
313  // clean up record
314  this->m_sortedDpList[record].sent = true;
315  }
316  }
317 
318  // if none were found, finish transmission
319  this->log_ACTIVITY_HI_CatalogXmitCompleted(this->m_xmitBytes);
320  this->m_xmitInProgress = false;
321  this->m_xmitBytes = 0;
322  this->m_currXmitRecord = nullptr;
323 
324  if (this->m_xmitCmdWait) {
325  this->m_xmitCmdWait = false;
326  this->cmdResponse_out(this->m_xmitOpCode, this->m_xmitCmdSeq, Fw::CmdResponse::OK);
327  }
328 
329  }
330 
331  bool DpCatalog::checkInit() {
332  if (not this->m_initialized) {
334  return false;
335  }
336  else if (0 == this->m_numDpSlots) {
338  return false;
339  }
340 
341  return true;
342  }
343 
345  // only try to deallocate if both pointers are non-zero
346  // it's a way to more gracefully shut down if there are missing
347  // pointers
348  if ((this->m_allocator != nullptr) and (this->m_memPtr != nullptr)) {
349  this->m_allocator->deallocate(this->m_allocatorId, this->m_memPtr);
350  }
351 
352  }
353 
354 
355  // ----------------------------------------------------------------------
356  // Handler implementations for user-defined typed input ports
357  // ----------------------------------------------------------------------
358 
359  void DpCatalog ::
360  fileDone_handler(
361  NATIVE_INT_TYPE portNum,
362  const Svc::SendFileResponse& resp
363  )
364  {
365  if (this->m_currXmitRecord) {
366  this->m_currXmitRecord->sent = true;
367  this->log_ACTIVITY_LO_ProductComplete(this->m_currXmitFileName);
368  }
369 
370  this->sendNextEntry();
371  }
372 
373  void DpCatalog ::
374  pingIn_handler(
375  NATIVE_INT_TYPE portNum,
376  U32 key
377  )
378  {
379  // return code for health ping
380  this->pingOut_out(0, key);
381  }
382 
383  // ----------------------------------------------------------------------
384  // Handler implementations for commands
385  // ----------------------------------------------------------------------
386 
387  void DpCatalog ::
388  BUILD_CATALOG_cmdHandler(
389  FwOpcodeType opCode,
390  U32 cmdSeq
391  )
392  {
393  // invoke helper
394  this->cmdResponse_out(opCode, cmdSeq, this->doCatalogBuild());
395  }
396 
397  void DpCatalog ::
398  START_XMIT_CATALOG_cmdHandler(
399  FwOpcodeType opCode,
400  U32 cmdSeq,
401  Fw::Wait wait
402  )
403  {
404 
405  Fw::CmdResponse resp = this->doCatalogXmit();
406 
407  if (Fw::Wait::NO_WAIT == wait) {
408  this->cmdResponse_out(opCode, cmdSeq, resp);
409  this->m_xmitCmdWait = false;
410  this->m_xmitOpCode = 0;
411  this->m_xmitCmdSeq = 0;
412  }
413  else {
414  this->m_xmitCmdWait = true;
415  this->m_xmitOpCode = opCode;
416  this->m_xmitCmdSeq = cmdSeq;
417  }
418 
419  }
420 
421  Fw::CmdResponse DpCatalog::doCatalogXmit() {
422 
423  this->m_xmitBytes = 0;
424  this->sendNextEntry();
425  return Fw::CmdResponse::OK;
426 
427  }
428 
429 
430  void DpCatalog ::
431  STOP_XMIT_CATALOG_cmdHandler(
432  FwOpcodeType opCode,
433  U32 cmdSeq
434  )
435  {
436  // TODO
437  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
438  }
439 
440  void DpCatalog ::
441  CLEAR_CATALOG_cmdHandler(
442  FwOpcodeType opCode,
443  U32 cmdSeq
444  )
445  {
446  // TODO
447  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
448  }
449 
450 
451 }
#define FW_ASSERT(...)
Definition: Assert.hpp:14
PlatformIntType NATIVE_INT_TYPE
Definition: BasicTypes.h:55
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:30
PlatformUIntType NATIVE_UINT_TYPE
Definition: BasicTypes.h:56
constexpr const char * DP_FILENAME_FORMAT
Definition: DpCfg.hpp:20
PlatformAssertArgType FwAssertArgType
Definition: FpConfig.h:39
PlatformUIntType FwNativeUIntType
Definition: FpConfig.h:47
PlatformSignedSizeType FwSignedSizeType
Definition: FpConfig.h:30
U32 FwOpcodeType
Definition: FpConfig.h:91
PlatformSizeType FwSizeType
Definition: FpConfig.h:35
PlatformIndexType FwIndexType
Definition: FpConfig.h:25
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
Directory class.
Definition: Directory.hpp:117
Status open(const char *path, OpenMode mode) override
Open or create a directory.
Definition: Directory.cpp:30
Status readDirectory(Fw::String filenameArray[], const FwSizeType arraySize, FwSizeType &filenameCount)
Read the contents of the directory and store filenames in filenameArray of size arraySize.
Definition: Directory.cpp:113
@ OP_OK
Operation was successful.
Definition: Directory.hpp:20
Status read(U8 *buffer, FwSignedSizeType &size)
read data from this file into supplied buffer bounded by size
Definition: File.cpp:143
void close() override
close the file, if not opened then do nothing
Definition: File.cpp:70
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
static Status getFileSize(const char *path, FwSignedSizeType &size)
Get the size of the file (in bytes) at the specified path.
Definition: FileSystem.cpp:227
@ OP_OK
Operation was successful.
Definition: FileSystem.hpp:25
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.
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