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 = this->m_osFile.open(this->m_name.toChar(), Os::File::OPEN_WRITE);
122  if (status == Os::File::OP_OK) {
123  this->m_fileCounter++;
124  // Reset bytes written
125  this->m_bytesWritten = 0;
126  // Initialize incremental hash
127  this->m_hash.init();
128  // Set mode
129  this->m_mode = File::Mode::OPEN;
130  } else {
131  Fw::LogStringArg string(this->m_name.toChar());
132  this->m_bufferLogger.log_WARNING_HI_BL_LogFileOpenError(status, string);
133  }
134 }
135 
136 bool BufferLogger::File ::writeBuffer(const U8* const data, const FwSizeType size) {
137  bool status = this->writeSize(size);
138  if (status) {
139  status = this->writeBytes(data, size);
140  }
141  return status;
142 }
143 
144 bool BufferLogger::File ::writeSize(const FwSizeType size) {
145  FW_ASSERT(this->m_sizeOfSize <= sizeof(FwSizeType));
146  // Reject sizes that do not fit in sizeOfSize bytes; writing the low bytes would corrupt the log
147  if ((this->m_sizeOfSize < sizeof(FwSizeType)) && ((size >> (8 * this->m_sizeOfSize)) != 0)) {
148  Fw::LogStringArg string(this->m_name.toChar());
149  this->m_bufferLogger.log_WARNING_HI_BL_LogFileWriteError(Os::File::INVALID_ARGUMENT, 0, static_cast<U32>(size),
150  string);
151  return false;
152  }
153  U8 sizeBuffer[sizeof(FwSizeType)];
154  FwSizeType sizeRegister = size;
155  for (U8 i = 0; i < this->m_sizeOfSize; ++i) {
156  sizeBuffer[this->m_sizeOfSize - i - 1] = sizeRegister & 0xFF;
157  sizeRegister >>= 8;
158  }
159  const bool status = this->writeBytes(sizeBuffer, this->m_sizeOfSize);
160  return status;
161 }
162 
163 bool BufferLogger::File ::writeBytes(const void* const data, const FwSizeType length) {
164  FwSizeType size = length;
165  const Os::File::Status fileStatus = this->m_osFile.write(reinterpret_cast<const U8*>(data), size);
166  bool status;
167  if (fileStatus == Os::File::OP_OK && static_cast<FwSizeType>(size) == length) {
168  this->m_bytesWritten += length;
169  this->m_hash.update(data, length);
170  status = true;
171  } else {
172  Fw::LogStringArg string(this->m_name.toChar());
173 
174  this->m_bufferLogger.log_WARNING_HI_BL_LogFileWriteError(fileStatus, static_cast<U32>(size),
175  static_cast<U32>(length), string);
176  status = false;
177  }
178  return status;
179 }
180 
181 void BufferLogger::File ::writeHashFile() {
182  // Finalize the incrementally computed hash
183  Utils::HashBuffer hashBuffer;
184  this->m_hash.finalize(hashBuffer);
185 
186  // Write hash file via ValidatedFile
187  Os::ValidatedFile validatedFile(this->m_name.toChar());
188  const Os::ValidateFile::Status status = validatedFile.createHashFile(hashBuffer);
189  if (status != Os::ValidateFile::VALIDATION_OK) {
190  Fw::LogStringArg logStringArg(validatedFile.getHashFileName().toChar());
191  this->m_bufferLogger.log_WARNING_HI_BL_LogFileValidationError(logStringArg, status);
192  }
193 }
194 
195 bool BufferLogger::File ::flush() {
196  // Unbuffered file I/O requires no flush; flush the Os::File here if using buffered I/O
197  return true;
198 }
199 
200 void BufferLogger::File ::close() {
201  if (this->m_mode == File::Mode::OPEN) {
202  // Close file
203  this->m_osFile.close();
204  // Write out the hash file to disk
205  this->writeHashFile();
206  // Update mode
207  this->m_mode = File::Mode::CLOSED;
208  }
209 }
210 
211 } // namespace Svc
PlatformSizeType FwSizeType
#define PRI_FwSizeType
Open file for writing.
Definition: File.hpp:35
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