mirror of
https://github.com/nasa/fprime.git
synced 2025-12-10 00:44:37 -06:00
* Created new SerialBufferBase as a parent of SerializeBufferBase. Renaming interface functions to be less confusing. * Deprecating copyRawOffset. No direct use-cases in F' core. * Make SerialBufferBase a true pure virtual interface. * Changing Serializable to work with SerialBufferBase parent interface. * Changing copyRaw and copyRawOffset to work with SerialBufferBase * Updating documentation for SerialBufferBase usage * Adding some documentation. Adding missing ASSERT in copyRaw. Fixing some bugs that new ASSERT uncovered. * Renaming SerializeBufferBase to LinearBufferBase. Add a using declaration to maintain backwards compatability. Properly mark LinearBufferBase functions as override. * Filling in the rest of the docstrings for the classes in Serializable * Removing redundant virtual keyword on override function * Applying clang formatting * Incorporating PR comments * Fix compile issues * Bump version to alpha * Format * v --------- Co-authored-by: M Starch <LeStarch@googlemail.com>
346 lines
12 KiB
C++
346 lines
12 KiB
C++
// \title AMPCSSequence.cpp
|
|
// \author Rob Bocchino
|
|
// \brief AMPCSSequence implementation
|
|
//
|
|
// \copyright
|
|
// Copyright (C) 2009-2018 California Institute of Technology.
|
|
// ALL RIGHTS RESERVED. United States Government Sponsorship
|
|
// acknowledged.
|
|
//
|
|
// ======================================================================
|
|
|
|
#include "Svc/CmdSequencer/formats/AMPCSSequence.hpp"
|
|
#include "Fw/Com/ComPacket.hpp"
|
|
#include "Fw/Types/Assert.hpp"
|
|
#include "Os/FileSystem.hpp"
|
|
extern "C" {
|
|
#include "Utils/Hash/libcrc/lib_crc.h"
|
|
}
|
|
|
|
namespace Svc {
|
|
|
|
AMPCSSequence ::AMPCSSequence(CmdSequencerComponentImpl& component) : CmdSequencerComponentImpl::Sequence(component) {}
|
|
|
|
bool AMPCSSequence ::loadFile(const Fw::StringBase& fileName) {
|
|
// Make sure there is a buffer allocated
|
|
FW_ASSERT(this->m_buffer.getBuffAddr());
|
|
|
|
Fw::CmdStringArg crcFileName(fileName);
|
|
crcFileName += ".CRC32";
|
|
|
|
this->m_header.m_timeBase = TimeBase::TB_DONT_CARE;
|
|
this->m_header.m_timeContext = FW_CONTEXT_DONT_CARE;
|
|
|
|
const bool status = this->readCRCFile(crcFileName) and this->getFileSize(fileName) and
|
|
this->readSequenceFile(fileName) and this->validateCRC() and
|
|
this->m_header.validateTime(this->m_component) and this->validateRecords();
|
|
|
|
return status;
|
|
}
|
|
|
|
bool AMPCSSequence ::readCRCFile(Fw::CmdStringArg& crcFileName) {
|
|
bool result;
|
|
|
|
this->setFileName(crcFileName);
|
|
|
|
Os::File::Status status = this->m_crcFile.open(crcFileName.toChar(), Os::File::OPEN_READ);
|
|
|
|
if (status == Os::File::OP_OK) {
|
|
result = this->readCRC() and this->deserializeCRC();
|
|
} else if (status == Os::File::DOESNT_EXIST) {
|
|
this->m_events.fileNotFound();
|
|
result = false;
|
|
} else {
|
|
this->m_events.fileReadError();
|
|
result = false;
|
|
}
|
|
|
|
this->m_crcFile.close();
|
|
return result;
|
|
}
|
|
|
|
bool AMPCSSequence ::getFileSize(const Fw::StringBase& seqFileName) {
|
|
bool status = true;
|
|
FwSizeType fileSize;
|
|
this->setFileName(seqFileName);
|
|
const Os::FileSystem::Status fileStatus = Os::FileSystem::getFileSize(this->m_fileName.toChar(), fileSize);
|
|
if (fileStatus == Os::FileSystem::OP_OK and fileSize >= static_cast<FwSizeType>(sizeof(this->m_sequenceHeader))) {
|
|
this->m_header.m_fileSize =
|
|
static_cast<U32>(fileSize - static_cast<FwSizeType>(sizeof(this->m_sequenceHeader)));
|
|
} else {
|
|
this->m_events.fileInvalid(CmdSequencer_FileReadStage::READ_HEADER_SIZE, fileStatus);
|
|
status = false;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
bool AMPCSSequence ::readSequenceFile(const Fw::StringBase& seqFileName) {
|
|
bool result;
|
|
|
|
this->setFileName(seqFileName);
|
|
Os::File::Status status = this->m_sequenceFile.open(this->m_fileName.toChar(), Os::File::OPEN_READ);
|
|
|
|
if (status == Os::File::OP_OK) {
|
|
result = this->readOpenSequenceFile();
|
|
} else if (status == Os::File::DOESNT_EXIST) {
|
|
this->m_events.fileNotFound();
|
|
result = false;
|
|
} else {
|
|
this->m_events.fileReadError();
|
|
result = false;
|
|
}
|
|
|
|
this->m_sequenceFile.close();
|
|
return result;
|
|
}
|
|
|
|
bool AMPCSSequence ::validateCRC() {
|
|
bool result = true;
|
|
if (this->m_crc.m_stored != this->m_crc.m_computed) {
|
|
this->m_events.fileCRCFailure(this->m_crc.m_stored, this->m_crc.m_computed);
|
|
result = false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool AMPCSSequence ::validateRecords() {
|
|
Fw::SerializeBufferBase& buffer = this->m_buffer;
|
|
Sequence::Record record;
|
|
|
|
// Deserialize all records and count the records
|
|
const U32 loopBound = static_cast<U32>(buffer.getDeserializeSizeLeft());
|
|
U32 numRecords = 0;
|
|
for (; numRecords < loopBound; ++numRecords) {
|
|
if (not this->hasMoreRecords()) {
|
|
break;
|
|
}
|
|
Fw::SerializeStatus status = this->deserializeRecord(record);
|
|
if (status != Fw::FW_SERIALIZE_OK) {
|
|
this->m_events.recordInvalid(numRecords, status);
|
|
return false;
|
|
}
|
|
}
|
|
// Set the number of records
|
|
this->m_header.m_numRecords = numRecords;
|
|
// Reset deserialization
|
|
this->reset();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool AMPCSSequence ::hasMoreRecords() const {
|
|
return this->m_buffer.getDeserializeSizeLeft() > 0;
|
|
}
|
|
|
|
void AMPCSSequence ::nextRecord(Sequence::Record& record) {
|
|
Fw::SerializeStatus status = this->deserializeRecord(record);
|
|
FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
|
|
}
|
|
|
|
void AMPCSSequence ::reset() {
|
|
this->m_buffer.resetDeser();
|
|
}
|
|
|
|
void AMPCSSequence ::clear() {
|
|
this->m_buffer.resetSer();
|
|
}
|
|
|
|
bool AMPCSSequence ::readCRC() {
|
|
Os::File& file = this->m_crcFile;
|
|
Fw::SerializeBufferBase& buffer = this->m_buffer;
|
|
bool status = true;
|
|
Fw::SerializeStatus ser_status;
|
|
|
|
FwSizeType readLen = static_cast<FwSizeType>(sizeof(U32));
|
|
ser_status = buffer.setBuffLen(static_cast<Fw::Serializable::SizeType>(readLen));
|
|
FW_ASSERT(ser_status == Fw::FW_SERIALIZE_OK, ser_status);
|
|
|
|
U8* const addr = buffer.getBuffAddr();
|
|
Os::File::Status fileStatus = file.read(addr, readLen);
|
|
|
|
if (fileStatus != Os::File::OP_OK) {
|
|
this->m_events.fileInvalid(CmdSequencer_FileReadStage::READ_SEQ_CRC, fileStatus);
|
|
status = false;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
bool AMPCSSequence ::deserializeCRC() {
|
|
bool status = true;
|
|
Fw::SerializeStatus serializeStatus = this->m_buffer.deserializeTo(this->m_crc.m_stored);
|
|
if (serializeStatus != Fw::FW_SERIALIZE_OK) {
|
|
this->m_events.fileInvalid(CmdSequencer_FileReadStage::READ_SEQ_CRC, serializeStatus);
|
|
status = false;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
bool AMPCSSequence ::readOpenSequenceFile() {
|
|
this->m_buffer.resetSer();
|
|
this->m_crc.init();
|
|
bool status = this->readSequenceHeader();
|
|
if (status) {
|
|
this->m_crc.update(this->m_sequenceHeader, sizeof(this->m_sequenceHeader));
|
|
status = this->readRecords();
|
|
}
|
|
if (status) {
|
|
U8* const buffAddr = this->m_buffer.getBuffAddr();
|
|
const FwSizeType buffLen = this->m_buffer.getSize();
|
|
FW_ASSERT(buffLen == this->m_header.m_fileSize, static_cast<FwAssertArgType>(buffLen),
|
|
static_cast<FwAssertArgType>(this->m_header.m_fileSize));
|
|
this->m_crc.update(buffAddr, buffLen);
|
|
this->m_crc.finalize();
|
|
}
|
|
return status;
|
|
}
|
|
|
|
bool AMPCSSequence ::readSequenceHeader() {
|
|
Os::File& file = this->m_sequenceFile;
|
|
|
|
bool status = true;
|
|
|
|
FwSizeType readLen = sizeof this->m_sequenceHeader;
|
|
const Os::File::Status fileStatus = file.read(this->m_sequenceHeader, readLen);
|
|
|
|
if (fileStatus != Os::File::OP_OK) {
|
|
this->m_events.fileInvalid(CmdSequencer_FileReadStage::READ_HEADER, fileStatus);
|
|
status = false;
|
|
}
|
|
|
|
if (status and readLen != sizeof this->m_sequenceHeader) {
|
|
this->m_events.fileInvalid(CmdSequencer_FileReadStage::READ_HEADER_SIZE, static_cast<I32>(readLen));
|
|
status = false;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
bool AMPCSSequence ::readRecords() {
|
|
Os::File& file = this->m_sequenceFile;
|
|
const FwSizeType size = this->m_header.m_fileSize;
|
|
Fw::SerializeBufferBase& buffer = this->m_buffer;
|
|
U8* const addr = buffer.getBuffAddr();
|
|
|
|
// Check file size
|
|
if (size > this->m_buffer.getCapacity()) {
|
|
this->m_events.fileSizeError(static_cast<U32>(size));
|
|
return false;
|
|
}
|
|
|
|
FwSizeType readLen = size;
|
|
const Os::File::Status fileStatus = file.read(addr, readLen);
|
|
// Check read status
|
|
if (fileStatus != Os::File::OP_OK) {
|
|
this->m_events.fileInvalid(CmdSequencer_FileReadStage::READ_SEQ_DATA, fileStatus);
|
|
return false;
|
|
}
|
|
// Check read size
|
|
const FwSizeType readLenUint = static_cast<FwSizeType>(readLen);
|
|
if (readLenUint != size) {
|
|
this->m_events.fileInvalid(CmdSequencer_FileReadStage::READ_SEQ_DATA_SIZE, static_cast<I32>(readLen));
|
|
return false;
|
|
}
|
|
// set buffer size
|
|
const Fw::SerializeStatus serializeStatus = buffer.setBuffLen(size);
|
|
FW_ASSERT(serializeStatus == Fw::FW_SERIALIZE_OK, serializeStatus);
|
|
return true;
|
|
}
|
|
|
|
Fw::SerializeStatus AMPCSSequence ::deserializeRecord(Sequence::Record& record) {
|
|
Record::CmdLength::t cmdLength;
|
|
|
|
Fw::SerializeStatus status = this->deserializeTimeFlag(record.m_descriptor);
|
|
|
|
if (status == Fw::FW_SERIALIZE_OK) {
|
|
status = this->deserializeTime(record.m_timeTag);
|
|
}
|
|
if (status == Fw::FW_SERIALIZE_OK) {
|
|
status = this->deserializeCmdLength(cmdLength);
|
|
}
|
|
if (status == Fw::FW_SERIALIZE_OK) {
|
|
status = this->translateCommand(record.m_command, cmdLength);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
Fw::SerializeStatus AMPCSSequence ::deserializeTimeFlag(Sequence::Record::Descriptor& descriptor) {
|
|
Fw::SerializeBufferBase& buffer = this->m_buffer;
|
|
Record::TimeFlag::Serial::t timeFlagSerial;
|
|
Fw::SerializeStatus status = buffer.deserializeTo(timeFlagSerial);
|
|
if (status == Fw::FW_SERIALIZE_OK) {
|
|
switch (timeFlagSerial) {
|
|
case Record::TimeFlag::ABSOLUTE:
|
|
descriptor = Sequence::Record::ABSOLUTE;
|
|
break;
|
|
case Record::TimeFlag::RELATIVE:
|
|
descriptor = Sequence::Record::RELATIVE;
|
|
break;
|
|
default:
|
|
status = Fw::FW_DESERIALIZE_FORMAT_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
Fw::SerializeStatus AMPCSSequence ::deserializeTime(Fw::Time& timeTag) {
|
|
Record::Time::t time;
|
|
Fw::SerializeBufferBase& buffer = this->m_buffer;
|
|
Fw::SerializeStatus status = buffer.deserializeTo(time);
|
|
if (status == Fw::FW_SERIALIZE_OK) {
|
|
timeTag.set(time, 0);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
Fw::SerializeStatus AMPCSSequence ::deserializeCmdLength(Record::CmdLength::t& cmdLength) {
|
|
Fw::SerializeBufferBase& buffer = this->m_buffer;
|
|
Fw::SerializeStatus status = buffer.deserializeTo(cmdLength);
|
|
if (status == Fw::FW_SERIALIZE_OK and cmdLength > buffer.getDeserializeSizeLeft()) {
|
|
// Not enough data left
|
|
status = Fw::FW_DESERIALIZE_SIZE_MISMATCH;
|
|
}
|
|
if (status == Fw::FW_SERIALIZE_OK and
|
|
sizeof(FwPacketDescriptorType) + sizeof(U16) + cmdLength > Fw::ComBuffer::SERIALIZED_SIZE) {
|
|
// Record size is too big for com buffer
|
|
status = Fw::FW_DESERIALIZE_SIZE_MISMATCH;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
Fw::SerializeStatus AMPCSSequence ::translateCommand(Fw::ComBuffer& comBuffer, const Record::CmdLength::t cmdLength) {
|
|
Fw::SerializeBufferBase& buffer = this->m_buffer;
|
|
comBuffer.resetSer();
|
|
// Serialize the command packet descriptor
|
|
const FwPacketDescriptorType cmdDescriptor = Fw::ComPacketType::FW_PACKET_COMMAND;
|
|
Fw::SerializeStatus status = comBuffer.serializeFrom(cmdDescriptor);
|
|
FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
|
|
// Zero-extend the two-byte AMPCS opcode by (sizeof(FwOpcodeType) - 2) bytes
|
|
FW_ASSERT(sizeof(FwOpcodeType) >= 2);
|
|
U32 sizeOfZeros = 0;
|
|
const FwIndexType bytesToExtend = sizeof(FwOpcodeType) - 2;
|
|
const U8 zeros = 0;
|
|
for (FwIndexType i = 0; i < bytesToExtend; i++) {
|
|
status = comBuffer.serializeFrom(zeros);
|
|
FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
|
|
sizeOfZeros += static_cast<U32>(sizeof(zeros));
|
|
}
|
|
// Set the buffer length
|
|
const U32 fixedBuffLen = static_cast<U32>(comBuffer.getSize());
|
|
FW_ASSERT(fixedBuffLen == sizeof(cmdDescriptor) + sizeOfZeros, static_cast<FwAssertArgType>(fixedBuffLen));
|
|
const U32 totalBuffLen = fixedBuffLen + cmdLength;
|
|
status = comBuffer.setBuffLen(totalBuffLen);
|
|
FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
|
|
// Copy the opcode and argument bytes
|
|
FwSizeType size = cmdLength;
|
|
U8* const addr = comBuffer.getBuffAddr();
|
|
FW_ASSERT(addr != nullptr);
|
|
// true means "don't serialize the length"
|
|
status = buffer.deserializeTo(&addr[fixedBuffLen], size, Fw::Serialization::OMIT_LENGTH);
|
|
return status;
|
|
}
|
|
|
|
} // namespace Svc
|