F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
BufferLoggerFile.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title BufferLoggerFile.cpp
3 // \author bocchino, dinkel, mereweth
4 // \brief Implementation for Svc::BufferLogger::BufferLoggerFile
5 //
6 // \copyright
7 // Copyright (C) 2015-2017 California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 //
11 // ======================================================================
12 
13 #include "Os/ValidatedFile.hpp"
15 #include "Utils/Hash/Hash.hpp"
16 
17 namespace Svc {
18 
19 // ----------------------------------------------------------------------
20 // Constructors and destructors
21 // ----------------------------------------------------------------------
22 
23 BufferLogger::File ::File(BufferLogger& bufferLogger)
24  : m_bufferLogger(bufferLogger),
25  m_prefix(""),
26  m_suffix(""),
27  m_baseName(""),
28  m_fileCounter(0),
29  m_maxSize(0),
30  m_sizeOfSize(0),
31  m_mode(Mode::CLOSED),
32  m_bytesWritten(0) {}
33 
34 BufferLogger::File ::~File() {
35  this->close();
36 }
37 
38 // ----------------------------------------------------------------------
39 // Public functions
40 // ----------------------------------------------------------------------
41 
42 void BufferLogger::File ::init(const char* const logFilePrefix,
43  const char* const logFileSuffix,
44  const FwSizeType maxFileSize,
45  const U8 sizeOfSize) {
46  // NOTE(mereweth) - only call this before opening the file
47  FW_ASSERT(this->m_mode == File::Mode::CLOSED);
48 
49  this->m_prefix = logFilePrefix;
50  this->m_suffix = logFileSuffix;
51  this->m_maxSize = maxFileSize;
52  this->m_sizeOfSize = sizeOfSize;
53 
54  FW_ASSERT(sizeOfSize <= sizeof(FwSizeType), static_cast<FwAssertArgType>(sizeOfSize));
55  FW_ASSERT(m_maxSize > sizeOfSize, static_cast<FwAssertArgType>(m_maxSize));
56 }
57 
58 void BufferLogger::File ::setBaseName(const Fw::ConstStringBase& baseName) {
59  if (this->m_mode == File::Mode::OPEN) {
60  this->closeAndEmitEvent();
61  }
62  this->m_baseName = baseName;
63  this->m_fileCounter = 0;
64  this->open();
65 }
66 
67 void BufferLogger::File ::logBuffer(const U8* const data, const FwSizeType size) {
68  FW_ASSERT(data != nullptr);
69  // Close the file if it will be too big
70  if (this->m_mode == File::Mode::OPEN) {
71  const FwSizeType projectedByteCount = this->m_bytesWritten + this->m_sizeOfSize + size;
72  if (projectedByteCount > this->m_maxSize) {
73  this->closeAndEmitEvent();
74  }
75  }
76  // Open a file if necessary
77  if (this->m_mode == File::Mode::CLOSED) {
78  this->open();
79  }
80  // Write to the file if it is open
81  if (this->m_mode == File::Mode::OPEN) {
82  (void)this->writeBuffer(data, size);
83  }
84 }
85 
86 void BufferLogger::File ::closeAndEmitEvent() {
87  if (this->m_mode == File::Mode::OPEN) {
88  this->close();
89  Fw::LogStringArg logStringArg(this->m_name.toChar());
90  this->m_bufferLogger.log_DIAGNOSTIC_BL_LogFileClosed(logStringArg);
91  }
92 }
93 
94 // ----------------------------------------------------------------------
95 // Private functions
96 // ----------------------------------------------------------------------
97 
98 void BufferLogger::File ::open() {
99  FW_ASSERT(this->m_mode == File::Mode::CLOSED);
100 
101  // NOTE(mereweth) - check that file path has been set and that initLog has been called
102  if ((this->m_baseName.toChar()[0] == '\0') || (this->m_sizeOfSize > sizeof(FwSizeType)) ||
103  (this->m_maxSize <= this->m_sizeOfSize)) {
104  this->m_bufferLogger.log_WARNING_HI_BL_NoLogFileOpenInitError();
105  return;
106  }
107 
108  Fw::FormatStatus formatStatus;
109  if (this->m_fileCounter == 0) {
110  formatStatus =
111  this->m_name.format("%s%s%s", this->m_prefix.toChar(), this->m_baseName.toChar(), this->m_suffix.toChar());
112  } else {
113  formatStatus = this->m_name.format("%s%s%" PRI_FwSizeType "%s", this->m_prefix.toChar(),
114  this->m_baseName.toChar(), this->m_fileCounter, this->m_suffix.toChar());
115  }
116  if (formatStatus != Fw::FormatStatus::SUCCESS) {
117  this->m_bufferLogger.log_WARNING_HI_BL_LogFileNameError(static_cast<Fw::StringFormatStatus::T>(formatStatus));
118  return;
119  }
120 
121  const Os::File::Status status =
122  this->m_osFile.open(this->m_name.toChar(), Os::File::OPEN_CREATE, Os::File::OVERWRITE);
123  if (status == Os::File::OP_OK) {
124  this->m_fileCounter++;
125  // Reset bytes written
126  this->m_bytesWritten = 0;
127  // Initialize incremental hash
128  this->m_hash.init();
129  // Set mode
130  this->m_mode = File::Mode::OPEN;
131  } else {
132  Fw::LogStringArg string(this->m_name.toChar());
133  this->m_bufferLogger.log_WARNING_HI_BL_LogFileOpenError(status, string);
134  }
135 }
136 
137 bool BufferLogger::File ::writeBuffer(const U8* const data, const FwSizeType size) {
138  bool status = this->writeSize(size);
139  if (status) {
140  status = this->writeBytes(data, size);
141  }
142  return status;
143 }
144 
145 bool BufferLogger::File ::writeSize(const FwSizeType size) {
146  FW_ASSERT(this->m_sizeOfSize <= sizeof(FwSizeType));
147  // Reject sizes that do not fit in sizeOfSize bytes; writing the low bytes would corrupt the log
148  if ((this->m_sizeOfSize < sizeof(FwSizeType)) && ((size >> (8 * this->m_sizeOfSize)) != 0)) {
149  Fw::LogStringArg string(this->m_name.toChar());
150  this->m_bufferLogger.log_WARNING_HI_BL_LogFileWriteError(Os::File::INVALID_ARGUMENT, 0, static_cast<U32>(size),
151  string);
152  return false;
153  }
154  U8 sizeBuffer[sizeof(FwSizeType)];
155  FwSizeType sizeRegister = size;
156  for (U8 i = 0; i < this->m_sizeOfSize; ++i) {
157  sizeBuffer[this->m_sizeOfSize - i - 1] = sizeRegister & 0xFF;
158  sizeRegister >>= 8;
159  }
160  const bool status = this->writeBytes(sizeBuffer, this->m_sizeOfSize);
161  return status;
162 }
163 
164 bool BufferLogger::File ::writeBytes(const void* const data, const FwSizeType length) {
165  FwSizeType size = length;
166  const Os::File::Status fileStatus = this->m_osFile.write(reinterpret_cast<const U8*>(data), size);
167  bool status;
168  if (fileStatus == Os::File::OP_OK && static_cast<FwSizeType>(size) == length) {
169  this->m_bytesWritten += length;
170  this->m_hash.update(data, length);
171  status = true;
172  } else {
173  Fw::LogStringArg string(this->m_name.toChar());
174 
175  this->m_bufferLogger.log_WARNING_HI_BL_LogFileWriteError(fileStatus, static_cast<U32>(size),
176  static_cast<U32>(length), string);
177  status = false;
178  }
179  return status;
180 }
181 
182 void BufferLogger::File ::writeHashFile() {
183  // Finalize the incrementally computed hash
184  Utils::HashBuffer hashBuffer;
185  this->m_hash.finalize(hashBuffer);
186 
187  // Write hash file via ValidatedFile
188  Os::ValidatedFile validatedFile(this->m_name.toChar());
189  const Os::ValidateFile::Status status = validatedFile.createHashFile(hashBuffer);
190  if (status != Os::ValidateFile::VALIDATION_OK) {
191  Fw::LogStringArg logStringArg(validatedFile.getHashFileName().toChar());
192  this->m_bufferLogger.log_WARNING_HI_BL_LogFileValidationError(logStringArg, status);
193  }
194 }
195 
196 bool BufferLogger::File ::flush() {
197  // Unbuffered file I/O requires no flush; flush the Os::File here if using buffered I/O
198  return true;
199 }
200 
201 void BufferLogger::File ::close() {
202  if (this->m_mode == File::Mode::OPEN) {
203  // Close file
204  this->m_osFile.close();
205  // Write out the hash file to disk
206  this->writeHashFile();
207  // Update mode
208  this->m_mode = File::Mode::CLOSED;
209  }
210 }
211 
212 } // namespace Svc
PlatformSizeType FwSizeType
#define PRI_FwSizeType
Overwrite file when it exists and creation was requested.
Definition: File.hpp:60
A validated file.
The validation of the file passed.
Os::ValidateFile::Status createHashFile()
Invalid argument passed in.
Definition: File.hpp:51
void init()
Initialize the OS Abstraction Layer (OSAL)
Definition: Os.cpp:15
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:54
Operation was successful.
Definition: File.hpp:42
A read-only abstract superclass for StringBase.
A container class for holding a hash buffer.
Definition: HashBuffer.hpp:26
RateGroupDivider component implementation.
#define FW_ASSERT(...)
Definition: Assert.hpp:14
FormatStatus
status of string format calls
Definition: format.hpp:18
Open file for writing and truncates file if it exists, ie same flags as creat()
Definition: File.hpp:34