// ---------------------------------------------------------------------- // // ComLogger.cpp // // ---------------------------------------------------------------------- #include #include #include #include #include #include namespace Svc { // ---------------------------------------------------------------------- // Construction, initialization, and destruction // ---------------------------------------------------------------------- ComLogger :: ComLogger(const char* compName, const char* incomingFilePrefix, U32 maxFileSize, bool storeBufferLength) : ComLoggerComponentBase(compName), maxFileSize(maxFileSize), fileMode(CLOSED), byteCount(0), writeErrorOccurred(false), openErrorOccurred(false), storeBufferLength(storeBufferLength) { if( this->storeBufferLength ) { FW_ASSERT(maxFileSize > sizeof(U16), maxFileSize); // must be a positive integer greater than buffer length size } else { FW_ASSERT(maxFileSize > sizeof(0), maxFileSize); // must be a positive integer } FW_ASSERT(strnlen(incomingFilePrefix, sizeof(this->filePrefix)) < sizeof(this->filePrefix), strnlen(incomingFilePrefix, sizeof(this->filePrefix)), sizeof(this->filePrefix)); // ensure that file prefix is not too big // Set the file prefix: Fw::StringUtils::string_copy(this->filePrefix, incomingFilePrefix, sizeof(this->filePrefix)); } void ComLogger :: init( NATIVE_INT_TYPE queueDepth, //!< The queue depth NATIVE_INT_TYPE instance //!< The instance number ) { ComLoggerComponentBase::init(queueDepth, instance); } ComLogger :: ~ComLogger() { // Close file: // this->closeFile(); // NOTE: the above did not work because we don't want to issue an event // in the destructor. This can cause "virtual method called" segmentation // faults. // So I am copying part of that function here. if( OPEN == this->fileMode ) { // Close file: this->file.close(); // Write out the hash file to disk: this->writeHashFile(); // Update mode: this->fileMode = CLOSED; // Send event: //Fw::LogStringArg logStringArg((char*) fileName); //this->log_DIAGNOSTIC_FileClosed(logStringArg); } } // ---------------------------------------------------------------------- // Handler implementations // ---------------------------------------------------------------------- void ComLogger :: comIn_handler( NATIVE_INT_TYPE portNum, Fw::ComBuffer &data, U32 context ) { FW_ASSERT(portNum == 0); // Get length of buffer: U32 size32 = data.getBuffLength(); // ComLogger only writes 16-bit sizes to save space // on disk: FW_ASSERT(size32 < 65536, size32); U16 size = size32 & 0xFFFF; // Close the file if it will be too big: if( OPEN == this->fileMode ) { U32 projectedByteCount = this->byteCount + size; if( this->storeBufferLength ) { projectedByteCount += sizeof(size); } if( projectedByteCount > this->maxFileSize ) { this->closeFile(); } } // Open the file if it there is not one open: if( CLOSED == this->fileMode ){ this->openFile(); } // Write to the file if it is open: if( OPEN == this->fileMode ) { this->writeComBufferToFile(data, size); } } void ComLogger :: CloseFile_cmdHandler( FwOpcodeType opCode, U32 cmdSeq ) { this->closeFile(); this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); } void ComLogger :: pingIn_handler( const NATIVE_INT_TYPE portNum, U32 key ) { // return key this->pingOut_out(0,key); } void ComLogger :: openFile( ) { FW_ASSERT( CLOSED == this->fileMode ); U32 bytesCopied; // Create filename: Fw::Time timestamp = getTime(); memset(this->fileName, 0, sizeof(this->fileName)); bytesCopied = snprintf(this->fileName, sizeof(this->fileName), "%s_%d_%d_%06d.com", this->filePrefix, static_cast(timestamp.getTimeBase()), timestamp.getSeconds(), timestamp.getUSeconds()); // "A return value of size or more means that the output was truncated" // See here: http://linux.die.net/man/3/snprintf FW_ASSERT( bytesCopied < sizeof(this->fileName) ); // Create sha filename: bytesCopied = snprintf(this->hashFileName, sizeof(this->hashFileName), "%s_%d_%d_%06d.com%s", this->filePrefix, static_cast(timestamp.getTimeBase()), timestamp.getSeconds(), timestamp.getUSeconds(), Utils::Hash::getFileExtensionString()); FW_ASSERT( bytesCopied < sizeof(this->hashFileName) ); Os::File::Status ret = file.open(this->fileName, Os::File::OPEN_WRITE); if( Os::File::OP_OK != ret ) { if( !this->openErrorOccurred ) { // throttle this event, otherwise a positive // feedback event loop can occur! Fw::LogStringArg logStringArg(this->fileName); this->log_WARNING_HI_FileOpenError(ret, logStringArg); } this->openErrorOccurred = true; } else { // Reset event throttle: this->openErrorOccurred = false; // Reset byte count: this->byteCount = 0; // Set mode: this->fileMode = OPEN; } } void ComLogger :: closeFile( ) { if( OPEN == this->fileMode ) { // Close file: this->file.close(); // Write out the hash file to disk: this->writeHashFile(); // Update mode: this->fileMode = CLOSED; // Send event: Fw::LogStringArg logStringArg(this->fileName); this->log_DIAGNOSTIC_FileClosed(logStringArg); } } void ComLogger :: writeComBufferToFile( Fw::ComBuffer &data, U16 size ) { if( this->storeBufferLength ) { U8 buffer[sizeof(size)]; Fw::SerialBuffer serialLength(&buffer[0], sizeof(size)); serialLength.serialize(size); if(this->writeToFile(serialLength.getBuffAddr(), static_cast(serialLength.getBuffLength()))) { this->byteCount += serialLength.getBuffLength(); } else { return; } } // Write buffer to file: if(this->writeToFile(data.getBuffAddr(), size)) { this->byteCount += size; } } bool ComLogger :: writeToFile( void* data, U16 length ) { NATIVE_INT_TYPE size = length; Os::File::Status ret = file.write(data, size); if( Os::File::OP_OK != ret || size != static_cast(length) ) { if( !this->writeErrorOccurred ) { // throttle this event, otherwise a positive // feedback event loop can occur! Fw::LogStringArg logStringArg(this->fileName); this->log_WARNING_HI_FileWriteError(ret, size, length, logStringArg); } this->writeErrorOccurred = true; return false; } this->writeErrorOccurred = false; return true; } void ComLogger :: writeHashFile( ) { Os::ValidateFile::Status validateStatus; validateStatus = Os::ValidateFile::createValidation(this->fileName, this->hashFileName); if( Os::ValidateFile::VALIDATION_OK != validateStatus ) { Fw::LogStringArg logStringArg1(this->fileName); Fw::LogStringArg logStringArg2(this->hashFileName); this->log_WARNING_LO_FileValidationError(logStringArg1, logStringArg2, validateStatus); } } };