| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ---------------------------------------------------------------------- | ||
| 2 | // | ||
| 3 | // ComLogger.cpp | ||
| 4 | // | ||
| 5 | // ---------------------------------------------------------------------- | ||
| 6 | |||
| 7 | #include <Fw/FPrimeBasicTypes.hpp> | ||
| 8 | #include <Fw/Types/SerialBuffer.hpp> | ||
| 9 | #include <Fw/Types/StringUtils.hpp> | ||
| 10 | #include <Os/ValidateFile.hpp> | ||
| 11 | #include <Svc/ComLogger/ComLogger.hpp> | ||
| 12 | #include <cstdio> | ||
| 13 | |||
| 14 | namespace Svc { | ||
| 15 | static_assert(std::numeric_limits<U16>::max() <= std::numeric_limits<FwSizeType>::max(), | ||
| 16 | "U16 must fit in the positive range of FwSizeType"); | ||
| 17 | // ---------------------------------------------------------------------- | ||
| 18 | // Construction, initialization, and destruction | ||
| 19 | // ---------------------------------------------------------------------- | ||
| 20 | |||
| 21 | ✗ | ComLogger ::ComLogger(const char* compName, const char* incomingFilePrefix, U32 maxFileSize, bool storeBufferLength) | |
| 22 | : ComLoggerComponentBase(compName), | ||
| 23 | ✗ | m_maxFileSize(maxFileSize), | |
| 24 | ✗ | m_fileMode(CLOSED), | |
| 25 | ✗ | m_byteCount(0), | |
| 26 | ✗ | m_writeErrorOccurred(false), | |
| 27 | ✗ | m_openErrorOccurred(false), | |
| 28 | ✗ | m_storeBufferLength(storeBufferLength), | |
| 29 | ✗ | m_initialized(true) { | |
| 30 | ✗ | this->init_log_file(incomingFilePrefix, maxFileSize, storeBufferLength); | |
| 31 | ✗ | } | |
| 32 | |||
| 33 | ✗ | ComLogger ::ComLogger(const char* compName) | |
| 34 | : ComLoggerComponentBase(compName), | ||
| 35 | ✗ | m_filePrefix(), | |
| 36 | ✗ | m_maxFileSize(0), | |
| 37 | ✗ | m_fileMode(CLOSED), | |
| 38 | ✗ | m_fileName(), | |
| 39 | ✗ | m_hashFileName(), | |
| 40 | ✗ | m_byteCount(0), | |
| 41 | ✗ | m_writeErrorOccurred(false), | |
| 42 | ✗ | m_openErrorOccurred(false), | |
| 43 | ✗ | m_storeBufferLength(), | |
| 44 | ✗ | m_initialized(false) {} | |
| 45 | |||
| 46 | ✗ | void ComLogger ::init_log_file(const char* incomingFilePrefix, U32 maxFileSize, bool storeBufferLength) { | |
| 47 | ✗ | FW_ASSERT(incomingFilePrefix != nullptr); | |
| 48 | ✗ | this->m_maxFileSize = maxFileSize; | |
| 49 | ✗ | this->m_storeBufferLength = storeBufferLength; | |
| 50 | ✗ | if (this->m_storeBufferLength) { | |
| 51 | ✗ | FW_ASSERT(maxFileSize > sizeof(U16), static_cast<FwAssertArgType>(maxFileSize)); | |
| 52 | } | ||
| 53 | // Assign the prefix checking if it is too big | ||
| 54 | ✗ | Fw::FormatStatus formatStatus = this->m_filePrefix.format("%s", incomingFilePrefix); | |
| 55 | ✗ | FW_ASSERT(formatStatus == Fw::FormatStatus::SUCCESS); | |
| 56 | ✗ | this->m_initialized = true; | |
| 57 | ✗ | } | |
| 58 | |||
| 59 | ✗ | ComLogger ::~ComLogger() { | |
| 60 | // Close file: | ||
| 61 | // this->closeFile(); | ||
| 62 | // NOTE: the above did not work because we don't want to issue an event | ||
| 63 | // in the destructor. This can cause "virtual method called" segmentation | ||
| 64 | // faults. | ||
| 65 | // So I am copying part of that function here. | ||
| 66 | ✗ | if (OPEN == this->m_fileMode) { | |
| 67 | // Close file: | ||
| 68 | ✗ | this->m_file.close(); | |
| 69 | |||
| 70 | // Write out the hash file to disk: | ||
| 71 | ✗ | this->writeHashFile(); | |
| 72 | |||
| 73 | // Update mode: | ||
| 74 | ✗ | this->m_fileMode = CLOSED; | |
| 75 | } | ||
| 76 | ✗ | } | |
| 77 | |||
| 78 | // ---------------------------------------------------------------------- | ||
| 79 | // Handler implementations | ||
| 80 | // ---------------------------------------------------------------------- | ||
| 81 | |||
| 82 | ✗ | void ComLogger ::comIn_handler(FwIndexType portNum, Fw::ComBuffer& data, U32 context) { | |
| 83 | ✗ | FW_ASSERT(portNum == 0); | |
| 84 | |||
| 85 | // Get length of buffer: | ||
| 86 | ✗ | FwSizeType sizeNative = data.getSize(); | |
| 87 | // ComLogger only writes 16-bit sizes to save space | ||
| 88 | // on disk: | ||
| 89 | ✗ | FW_ASSERT(sizeNative < 65536, static_cast<FwAssertArgType>(sizeNative)); | |
| 90 | ✗ | U16 size = sizeNative & 0xFFFF; | |
| 91 | |||
| 92 | // Close the file if it will be too big: | ||
| 93 | ✗ | if (OPEN == this->m_fileMode) { | |
| 94 | ✗ | U32 projectedByteCount = this->m_byteCount + size; | |
| 95 | ✗ | if (this->m_storeBufferLength) { | |
| 96 | ✗ | projectedByteCount += static_cast<U32>(sizeof(size)); | |
| 97 | } | ||
| 98 | ✗ | if (projectedByteCount > this->m_maxFileSize) { | |
| 99 | ✗ | this->closeFile(); | |
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | // Open the file if it there is not one open: | ||
| 104 | ✗ | if (CLOSED == this->m_fileMode) { | |
| 105 | ✗ | this->openFile(); | |
| 106 | } | ||
| 107 | |||
| 108 | // Write to the file if it is open: | ||
| 109 | ✗ | if (OPEN == this->m_fileMode) { | |
| 110 | ✗ | this->writeComBufferToFile(data, size); | |
| 111 | } | ||
| 112 | ✗ | } | |
| 113 | |||
| 114 | ✗ | void ComLogger ::CloseFile_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { | |
| 115 | ✗ | this->closeFile(); | |
| 116 | ✗ | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); | |
| 117 | ✗ | } | |
| 118 | |||
| 119 | ✗ | void ComLogger ::pingIn_handler(const FwIndexType portNum, U32 key) { | |
| 120 | // return key | ||
| 121 | ✗ | this->pingOut_out(0, key); | |
| 122 | ✗ | } | |
| 123 | |||
| 124 | ✗ | void ComLogger ::openFile() { | |
| 125 | ✗ | FW_ASSERT(CLOSED == this->m_fileMode); | |
| 126 | |||
| 127 | ✗ | if (!this->m_initialized) { | |
| 128 | ✗ | this->log_WARNING_LO_FileNotInitialized(); | |
| 129 | ✗ | return; | |
| 130 | } | ||
| 131 | |||
| 132 | // Create filename: | ||
| 133 | ✗ | Fw::Time timestamp = getTime(); | |
| 134 | ✗ | Fw::FormatStatus formatStatus = this->m_fileName.format( | |
| 135 | "%s_%" PRI_FwTimeBaseStoreType "_%" PRIu32 "_%06" PRIu32 ".com", this->m_filePrefix.toChar(), | ||
| 136 | ✗ | static_cast<FwTimeBaseStoreType>(timestamp.getTimeBase()), timestamp.getSeconds(), timestamp.getUSeconds()); | |
| 137 | ✗ | FW_ASSERT(formatStatus == Fw::FormatStatus::SUCCESS); | |
| 138 | formatStatus = | ||
| 139 | ✗ | this->m_hashFileName.format("%s%s", this->m_fileName.toChar(), Utils::Hash::getFileExtensionString()); | |
| 140 | ✗ | FW_ASSERT(formatStatus == Fw::FormatStatus::SUCCESS); | |
| 141 | |||
| 142 | ✗ | Os::File::Status ret = m_file.open(this->m_fileName.toChar(), Os::File::OPEN_WRITE); | |
| 143 | ✗ | if (Os::File::OP_OK != ret) { | |
| 144 | ✗ | if (!this->m_openErrorOccurred) { // throttle this event, otherwise a positive | |
| 145 | // feedback event loop can occur! | ||
| 146 | ✗ | this->log_WARNING_HI_FileOpenError(ret, this->m_fileName); | |
| 147 | } | ||
| 148 | ✗ | this->m_openErrorOccurred = true; | |
| 149 | } else { | ||
| 150 | // Reset event throttle: | ||
| 151 | ✗ | this->m_openErrorOccurred = false; | |
| 152 | |||
| 153 | // Reset byte count: | ||
| 154 | ✗ | this->m_byteCount = 0; | |
| 155 | |||
| 156 | // Set mode: | ||
| 157 | ✗ | this->m_fileMode = OPEN; | |
| 158 | } | ||
| 159 | ✗ | } | |
| 160 | |||
| 161 | ✗ | void ComLogger ::closeFile() { | |
| 162 | ✗ | if (OPEN == this->m_fileMode) { | |
| 163 | // Close file: | ||
| 164 | ✗ | this->m_file.close(); | |
| 165 | |||
| 166 | // Write out the hash file to disk: | ||
| 167 | ✗ | this->writeHashFile(); | |
| 168 | |||
| 169 | // Update mode: | ||
| 170 | ✗ | this->m_fileMode = CLOSED; | |
| 171 | |||
| 172 | // Send event: | ||
| 173 | ✗ | this->log_DIAGNOSTIC_FileClosed(this->m_fileName); | |
| 174 | } | ||
| 175 | ✗ | } | |
| 176 | |||
| 177 | ✗ | void ComLogger ::writeComBufferToFile(Fw::ComBuffer& data, U16 size) { | |
| 178 | ✗ | if (this->m_storeBufferLength) { | |
| 179 | U8 buffer[sizeof(size)]; | ||
| 180 | ✗ | Fw::SerialBuffer serialLength(&buffer[0], sizeof(size)); | |
| 181 | ✗ | Fw::SerializeStatus serStatus = serialLength.serializeFrom(size); | |
| 182 | ✗ | FW_ASSERT(serStatus == Fw::FW_SERIALIZE_OK, serStatus); | |
| 183 | const bool lengthWritten = | ||
| 184 | ✗ | this->writeToFile(serialLength.getBuffAddr(), static_cast<U16>(serialLength.getSize())); | |
| 185 | ✗ | if (lengthWritten) { | |
| 186 | ✗ | this->m_byteCount += static_cast<U32>(serialLength.getSize()); | |
| 187 | } else { | ||
| 188 | ✗ | return; | |
| 189 | } | ||
| 190 | ✗ | } | |
| 191 | |||
| 192 | // Write buffer to file: | ||
| 193 | ✗ | const bool dataWritten = this->writeToFile(data.getBuffAddr(), size); | |
| 194 | ✗ | if (dataWritten) { | |
| 195 | ✗ | this->m_byteCount += size; | |
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | ✗ | bool ComLogger ::writeToFile(void* data, U16 length) { | |
| 200 | ✗ | FwSizeType size = length; | |
| 201 | ✗ | Os::File::Status ret = m_file.write(reinterpret_cast<const U8*>(data), size); | |
| 202 | ✗ | if ((Os::File::OP_OK != ret) || (size != length)) { | |
| 203 | ✗ | if (!this->m_writeErrorOccurred) { // throttle this event, otherwise a positive | |
| 204 | // feedback event loop can occur! | ||
| 205 | ✗ | this->log_WARNING_HI_FileWriteError(ret, static_cast<U32>(size), length, this->m_fileName); | |
| 206 | } | ||
| 207 | ✗ | this->m_writeErrorOccurred = true; | |
| 208 | ✗ | return false; | |
| 209 | } | ||
| 210 | |||
| 211 | ✗ | this->m_writeErrorOccurred = false; | |
| 212 | ✗ | return true; | |
| 213 | } | ||
| 214 | |||
| 215 | ✗ | void ComLogger ::writeHashFile() { | |
| 216 | Os::ValidateFile::Status validateStatus; | ||
| 217 | ✗ | validateStatus = Os::ValidateFile::createValidation(this->m_fileName.toChar(), this->m_hashFileName.toChar()); | |
| 218 | ✗ | if (Os::ValidateFile::VALIDATION_OK != validateStatus) { | |
| 219 | ✗ | this->log_WARNING_LO_FileValidationError(this->m_hashFileName, this->m_fileName, validateStatus); | |
| 220 | } | ||
| 221 | ✗ | } | |
| 222 | } // namespace Svc | ||
| 223 |