mirror of
https://github.com/nasa/fprime.git
synced 2025-12-10 00:44:37 -06:00
Provide ability to update parameters via a file (#4165)
* Save point for PRM_SET_FILE work, add basic infrastruture * fprime-format * Create prime and backup DB, initial implementation of file based set, some UT updates * More work on Prime and Backup DBs including helper methods, utilizing those for copy, and UTs * spelling * printf in Tester fix * printf in Tester fix * printf in Tester fix * Remove a debug printf, update new method args, additional offNom Set File tests * Spelling and format * Clean up comments * Sync with upstream devel updates * Add additional UT for reverting parameter db on set file failure * Spelling and format * Updates to PrmDb after first review; change to active/staging design * Spelling * Remove FIXME comment * Review fixes * Fix UT * Format * Format II * Format III --------- Co-authored-by: M Starch <LeStarch@googlemail.com>
This commit is contained in:
parent
9c11872889
commit
0fc995fefd
@ -7,6 +7,20 @@ module Svc {
|
||||
# Types
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
@ Parameter DB type
|
||||
enum PrmDbType {
|
||||
DB_ACTIVE,
|
||||
DB_STAGING
|
||||
}
|
||||
|
||||
@ State of parameter DB file load operations
|
||||
enum PrmDbFileLoadState {
|
||||
IDLE,
|
||||
LOADING_FILE_UPDATES,
|
||||
FILE_UPDATES_STAGED,
|
||||
}
|
||||
|
||||
|
||||
@ Parameter read error
|
||||
enum PrmReadError {
|
||||
OPEN
|
||||
@ -77,83 +91,13 @@ module Svc {
|
||||
# Commands
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
@ Command to save parameter image to file. Uses file name passed to constructor
|
||||
async command PRM_SAVE_FILE \
|
||||
opcode 0
|
||||
include "PrmDbCmdDict.fppi"
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Events
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
@ Parameter ID not found in database.
|
||||
event PrmIdNotFound(
|
||||
Id: FwPrmIdType @< The parameter ID
|
||||
) \
|
||||
severity warning low \
|
||||
id 0 \
|
||||
format "Parameter ID 0x{x} not found" \
|
||||
throttle 5
|
||||
|
||||
@ Parameter ID updated in database
|
||||
event PrmIdUpdated(
|
||||
Id: FwPrmIdType @< The parameter ID
|
||||
) \
|
||||
severity activity high \
|
||||
id 1 \
|
||||
format "Parameter ID 0x{x} updated"
|
||||
|
||||
@ Parameter database is full
|
||||
event PrmDbFull(
|
||||
Id: FwPrmIdType @< The parameter ID
|
||||
) \
|
||||
severity fatal \
|
||||
id 2 \
|
||||
format "Parameter DB full when adding ID 0x{x} "
|
||||
|
||||
|
||||
@ Parameter ID added to database
|
||||
event PrmIdAdded(
|
||||
Id: FwPrmIdType @< The parameter ID
|
||||
) \
|
||||
severity activity high \
|
||||
id 3 \
|
||||
format "Parameter ID 0x{x} added"
|
||||
|
||||
@ Failed to write parameter file
|
||||
event PrmFileWriteError(
|
||||
stage: PrmWriteError @< The write stage
|
||||
$record: I32 @< The record that had the failure
|
||||
error: I32 @< The error code
|
||||
) \
|
||||
severity warning high \
|
||||
id 4 \
|
||||
format "Parameter write failed in stage {} with record {} and error {}"
|
||||
|
||||
@ Save of parameter file completed
|
||||
event PrmFileSaveComplete(
|
||||
records: U32 @< The number of records saved
|
||||
) \
|
||||
severity activity high \
|
||||
id 5 \
|
||||
format "Parameter file save completed. Wrote {} records."
|
||||
|
||||
@ Failed to read parameter file
|
||||
event PrmFileReadError(
|
||||
stage: PrmReadError @< The read stage
|
||||
$record: I32 @< The record that had the failure
|
||||
error: I32 @< The error code
|
||||
) \
|
||||
severity warning high \
|
||||
id 6 \
|
||||
format "Parameter file read failed in stage {} with record {} and error {}"
|
||||
|
||||
@ Load of parameter file completed
|
||||
event PrmFileLoadComplete(
|
||||
records: U32 @< The number of records loaded
|
||||
) \
|
||||
severity activity high \
|
||||
id 7 \
|
||||
format "Parameter file load completed. Read {} records."
|
||||
include "PrmDbEventDict.fppi"
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,18 @@
|
||||
enum Merge : U8{
|
||||
MERGE,
|
||||
RESET
|
||||
}
|
||||
@ Command to save parameter image to file. Uses file name passed to constructor
|
||||
async command PRM_SAVE_FILE \
|
||||
opcode 0
|
||||
opcode 0x00
|
||||
|
||||
@ Loads a file from storage into the staging database. The file could have selective IDs and not the whole set.
|
||||
async command PRM_LOAD_FILE(
|
||||
fileName: string size FileNameStringSize @< The name of the on-board file to set parameters from
|
||||
merge: Merge @< Whether to merge or fully reset the parameter database from the file contents
|
||||
) \
|
||||
opcode 0x01
|
||||
|
||||
@ Commits the backup database to become the prime (active) database
|
||||
async command PRM_COMMIT_STAGED \
|
||||
opcode 0x02
|
||||
|
||||
109
Svc/PrmDb/PrmDbEventDict.fppi
Normal file
109
Svc/PrmDb/PrmDbEventDict.fppi
Normal file
@ -0,0 +1,109 @@
|
||||
enum PrmLoadAction : U8 {
|
||||
SET_PARAMETER,
|
||||
SAVE_FILE_COMMAND,
|
||||
LOAD_FILE_COMMAND,
|
||||
COMMIT_STAGED_COMMAND,
|
||||
}
|
||||
|
||||
@ Parameter ID not found in database.
|
||||
event PrmIdNotFound(
|
||||
Id: FwPrmIdType @< The parameter ID
|
||||
) \
|
||||
severity warning low \
|
||||
id 0 \
|
||||
format "Parameter ID 0x{x} not found" \
|
||||
throttle 5
|
||||
|
||||
@ Parameter ID updated in database
|
||||
event PrmIdUpdated(
|
||||
Id: FwPrmIdType @< The parameter ID
|
||||
) \
|
||||
severity activity high \
|
||||
id 1 \
|
||||
format "Parameter ID 0x{x} updated"
|
||||
|
||||
@ Parameter database is full
|
||||
event PrmDbFull(
|
||||
Id: FwPrmIdType @< The parameter ID
|
||||
) \
|
||||
severity warning high \
|
||||
id 2 \
|
||||
format "Parameter DB full when adding ID 0x{x} "
|
||||
|
||||
|
||||
@ Parameter ID added to database
|
||||
event PrmIdAdded(
|
||||
Id: FwPrmIdType @< The parameter ID
|
||||
) \
|
||||
severity activity high \
|
||||
id 3 \
|
||||
format "Parameter ID 0x{x} added"
|
||||
|
||||
@ Failed to write parameter file
|
||||
event PrmFileWriteError(
|
||||
stage: PrmWriteError @< The write stage
|
||||
$record: I32 @< The record that had the failure
|
||||
error: I32 @< The error code
|
||||
) \
|
||||
severity warning high \
|
||||
id 4 \
|
||||
format "Parameter write failed in stage {} with record {} and error {}"
|
||||
|
||||
@ Save of parameter file completed
|
||||
event PrmFileSaveComplete(
|
||||
records: U32 @< The number of records saved
|
||||
) \
|
||||
severity activity high \
|
||||
id 5 \
|
||||
format "Parameter file save completed. Wrote {} records."
|
||||
|
||||
@ Failed to read parameter file
|
||||
event PrmFileReadError(
|
||||
stage: PrmReadError @< The read stage
|
||||
$record: I32 @< The record that had the failure
|
||||
error: I32 @< The error code
|
||||
) \
|
||||
severity warning high \
|
||||
id 6 \
|
||||
format "Parameter file read failed in stage {} with record {} and error {}"
|
||||
|
||||
@ Load of parameter file completed
|
||||
event PrmFileLoadComplete(
|
||||
databaseString: string @< The database string
|
||||
recordsTotal: U32 @< The number of records total
|
||||
recordsAdded: U32 @< The number of new records added
|
||||
recordsUpdated: U32 @< The number of records updated
|
||||
) \
|
||||
severity activity high \
|
||||
id 7 \
|
||||
format "Parameter file load completed. Database: {}, Records: {} ({} added and {} updated)."
|
||||
|
||||
@ Committed staged parameter updates
|
||||
event PrmDbCommitComplete() \
|
||||
severity activity high \
|
||||
id 8 \
|
||||
format "Parameter DB commit complete, staged updates are now active."
|
||||
|
||||
@ All parameters Copied from one DB to another
|
||||
event PrmDbCopyAllComplete(
|
||||
databaseStringSrc: string @< The src database string
|
||||
databaseStringDest: string @< The dest database string
|
||||
) \
|
||||
severity activity high \
|
||||
id 9 \
|
||||
format "All parameters copied. Source database: {}, Destination database: {}."
|
||||
|
||||
@ Parameter file load failed, not staging any update
|
||||
event PrmDbFileLoadFailed() \
|
||||
severity warning high \
|
||||
id 10 \
|
||||
format "Parameter file load failed. Clearing staging database and abandoning parameter file load."
|
||||
|
||||
@ Invalid Action during parameter file load
|
||||
event PrmDbFileLoadInvalidAction(
|
||||
currentState: PrmDbFileLoadState @< The current state
|
||||
attemptedAction: PrmLoadAction @< The invalid action attempted
|
||||
) \
|
||||
severity warning low \
|
||||
id 11 \
|
||||
format "Invalid action during parameter file load. Current state: {}, Action (Invalid for current state): {}."
|
||||
@ -18,8 +18,6 @@ static_assert(std::numeric_limits<FwSizeType>::max() >= PRMDB_NUM_DB_ENTRIES,
|
||||
|
||||
namespace Svc {
|
||||
|
||||
typedef PrmDb_PrmWriteError PrmWriteError;
|
||||
typedef PrmDb_PrmReadError PrmReadError;
|
||||
// anonymous namespace for buffer declaration
|
||||
namespace {
|
||||
class WorkingBuffer : public Fw::SerializeBufferBase {
|
||||
@ -36,22 +34,41 @@ class WorkingBuffer : public Fw::SerializeBufferBase {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
PrmDbImpl::PrmDbImpl(const char* name) : PrmDbComponentBase(name) {
|
||||
this->clearDb();
|
||||
//! ----------------------------------------------------------------------
|
||||
//! Construction, initialization, and destruction
|
||||
//! ----------------------------------------------------------------------
|
||||
PrmDbImpl::PrmDbImpl(const char* name) : PrmDbComponentBase(name), m_state(PrmDbFileLoadState::IDLE) {
|
||||
this->m_activeDb = this->m_dbStore1;
|
||||
this->m_stagingDb = this->m_dbStore2;
|
||||
|
||||
this->clearDb(PrmDbType::DB_ACTIVE);
|
||||
this->clearDb(PrmDbType::DB_STAGING);
|
||||
}
|
||||
|
||||
PrmDbImpl::~PrmDbImpl() {}
|
||||
|
||||
void PrmDbImpl::configure(const char* file) {
|
||||
FW_ASSERT(file != nullptr);
|
||||
this->m_fileName = file;
|
||||
}
|
||||
|
||||
void PrmDbImpl::clearDb() {
|
||||
for (FwSizeType entry = 0; entry < PRMDB_NUM_DB_ENTRIES; entry++) {
|
||||
this->m_db[entry].used = false;
|
||||
this->m_db[entry].id = 0;
|
||||
}
|
||||
void PrmDbImpl::readParamFile() {
|
||||
// Assumed to run at initialization time
|
||||
// State should be IDLE upon entry
|
||||
FW_ASSERT(static_cast<FwAssertArgType>(m_state == PrmDbFileLoadState::IDLE));
|
||||
|
||||
// Clear databases
|
||||
this->clearDb(PrmDbType::DB_ACTIVE);
|
||||
this->clearDb(PrmDbType::DB_STAGING);
|
||||
|
||||
// Read parameter file to active database
|
||||
(void)readParamFileImpl(this->m_fileName, PrmDbType::DB_ACTIVE);
|
||||
}
|
||||
|
||||
//! ----------------------------------------------------------------------
|
||||
//! Port & Command Handlers
|
||||
//! ----------------------------------------------------------------------
|
||||
|
||||
// If ports are no longer guarded, these accesses need to be protected from each other
|
||||
// If there are a lot of accesses, perhaps an interrupt lock could be used instead of guarded ports
|
||||
|
||||
@ -60,9 +77,9 @@ Fw::ParamValid PrmDbImpl::getPrm_handler(FwIndexType portNum, FwPrmIdType id, Fw
|
||||
Fw::ParamValid stat = Fw::ParamValid::INVALID;
|
||||
|
||||
for (FwSizeType entry = 0; entry < PRMDB_NUM_DB_ENTRIES; entry++) {
|
||||
if (this->m_db[entry].used) {
|
||||
if (this->m_db[entry].id == id) {
|
||||
val = this->m_db[entry].val;
|
||||
if (this->m_activeDb[entry].used) {
|
||||
if (this->m_activeDb[entry].id == id) {
|
||||
val = this->m_activeDb[entry].val;
|
||||
stat = Fw::ParamValid::VALID;
|
||||
break;
|
||||
}
|
||||
@ -78,47 +95,40 @@ Fw::ParamValid PrmDbImpl::getPrm_handler(FwIndexType portNum, FwPrmIdType id, Fw
|
||||
}
|
||||
|
||||
void PrmDbImpl::setPrm_handler(FwIndexType portNum, FwPrmIdType id, Fw::ParamBuffer& val) {
|
||||
this->lock();
|
||||
|
||||
// search for existing entry
|
||||
|
||||
bool existingEntry = false;
|
||||
bool noSlots = true;
|
||||
|
||||
for (FwSizeType entry = 0; entry < PRMDB_NUM_DB_ENTRIES; entry++) {
|
||||
if ((this->m_db[entry].used) && (id == this->m_db[entry].id)) {
|
||||
this->m_db[entry].val = val;
|
||||
existingEntry = true;
|
||||
break;
|
||||
}
|
||||
// Reject parameter updates during non-idle file load states
|
||||
if (m_state != PrmDbFileLoadState::IDLE) {
|
||||
this->log_WARNING_LO_PrmDbFileLoadInvalidAction(m_state, PrmDb_PrmLoadAction::SET_PARAMETER);
|
||||
return;
|
||||
}
|
||||
|
||||
// if there is no existing entry, add one
|
||||
if (!existingEntry) {
|
||||
for (FwSizeType entry = 0; entry < PRMDB_NUM_DB_ENTRIES; entry++) {
|
||||
if (!(this->m_db[entry].used)) {
|
||||
this->m_db[entry].val = val;
|
||||
this->m_db[entry].id = id;
|
||||
this->m_db[entry].used = true;
|
||||
noSlots = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Update the parameter in the active database
|
||||
PrmUpdateType update_status = updateAddPrmImpl(id, val, PrmDbType::DB_ACTIVE);
|
||||
|
||||
this->unLock();
|
||||
|
||||
if (existingEntry) {
|
||||
// Issue relevant EVR
|
||||
if (update_status == PARAM_UPDATED) {
|
||||
this->log_ACTIVITY_HI_PrmIdUpdated(id);
|
||||
} else if (noSlots) {
|
||||
this->log_FATAL_PrmDbFull(id);
|
||||
} else if (update_status == NO_SLOTS) {
|
||||
this->log_WARNING_HI_PrmDbFull(id);
|
||||
} else {
|
||||
this->log_ACTIVITY_HI_PrmIdAdded(id);
|
||||
}
|
||||
}
|
||||
|
||||
void PrmDbImpl::pingIn_handler(FwIndexType portNum, U32 key) {
|
||||
// respond to ping
|
||||
this->pingOut_out(0, key);
|
||||
}
|
||||
|
||||
void PrmDbImpl::PRM_SAVE_FILE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
|
||||
// Reject PRM_SAVE_FILE command during non-idle file load states
|
||||
if (m_state != PrmDbFileLoadState::IDLE) {
|
||||
this->log_WARNING_LO_PrmDbFileLoadInvalidAction(m_state, PrmDb_PrmLoadAction::SAVE_FILE_COMMAND);
|
||||
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::BUSY);
|
||||
return;
|
||||
}
|
||||
|
||||
FW_ASSERT(this->m_fileName.length() > 0);
|
||||
|
||||
Os::File paramFile;
|
||||
WorkingBuffer buff;
|
||||
|
||||
@ -130,13 +140,15 @@ void PrmDbImpl::PRM_SAVE_FILE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
|
||||
}
|
||||
|
||||
this->lock();
|
||||
t_dbStruct* db = getDbPtr(PrmDbType::DB_ACTIVE);
|
||||
FW_ASSERT(db != nullptr);
|
||||
|
||||
// Traverse the parameter list, saving each entry
|
||||
|
||||
U32 numRecords = 0;
|
||||
|
||||
for (FwSizeType entry = 0; entry < FW_NUM_ARRAY_ELEMENTS(this->m_db); entry++) {
|
||||
if (this->m_db[entry].used) {
|
||||
for (FwSizeType entry = 0; entry < PRMDB_NUM_DB_ENTRIES; entry++) {
|
||||
if (db[entry].used) {
|
||||
// write delimiter
|
||||
static const U8 delim = PRMDB_ENTRY_DELIMITER;
|
||||
FwSizeType writeSize = static_cast<FwSizeType>(sizeof(delim));
|
||||
@ -155,7 +167,7 @@ void PrmDbImpl::PRM_SAVE_FILE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
|
||||
return;
|
||||
}
|
||||
// serialize record size = id field + data
|
||||
U32 recordSize = static_cast<U32>(sizeof(FwPrmIdType) + this->m_db[entry].val.getBuffLength());
|
||||
U32 recordSize = static_cast<U32>(sizeof(FwPrmIdType) + db[entry].val.getBuffLength());
|
||||
|
||||
// reset buffer
|
||||
buff.resetSer();
|
||||
@ -185,7 +197,7 @@ void PrmDbImpl::PRM_SAVE_FILE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
|
||||
|
||||
// serialize parameter id
|
||||
|
||||
serStat = buff.serializeFrom(this->m_db[entry].id);
|
||||
serStat = buff.serializeFrom(db[entry].id);
|
||||
// should always work
|
||||
FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, static_cast<FwAssertArgType>(serStat));
|
||||
|
||||
@ -208,8 +220,8 @@ void PrmDbImpl::PRM_SAVE_FILE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
|
||||
|
||||
// write serialized parameter value
|
||||
|
||||
writeSize = static_cast<FwSizeType>(this->m_db[entry].val.getBuffLength());
|
||||
stat = paramFile.write(this->m_db[entry].val.getBuffAddr(), writeSize, Os::File::WaitType::WAIT);
|
||||
writeSize = static_cast<FwSizeType>(db[entry].val.getBuffLength());
|
||||
stat = paramFile.write(db[entry].val.getBuffAddr(), writeSize, Os::File::WaitType::WAIT);
|
||||
if (stat != Os::File::OP_OK) {
|
||||
this->unLock();
|
||||
this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::PARAMETER_VALUE, static_cast<I32>(numRecords),
|
||||
@ -217,7 +229,7 @@ void PrmDbImpl::PRM_SAVE_FILE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
|
||||
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
|
||||
return;
|
||||
}
|
||||
if (writeSize != static_cast<FwSizeType>(this->m_db[entry].val.getBuffLength())) {
|
||||
if (writeSize != static_cast<FwSizeType>(db[entry].val.getBuffLength())) {
|
||||
this->unLock();
|
||||
this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::PARAMETER_VALUE_SIZE,
|
||||
static_cast<I32>(numRecords), static_cast<I32>(writeSize));
|
||||
@ -233,24 +245,95 @@ void PrmDbImpl::PRM_SAVE_FILE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
|
||||
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
|
||||
}
|
||||
|
||||
PrmDbImpl::~PrmDbImpl() {}
|
||||
void PrmDbImpl::PRM_LOAD_FILE_cmdHandler(FwOpcodeType opCode,
|
||||
U32 cmdSeq,
|
||||
const Fw::CmdStringArg& fileName,
|
||||
PrmDb_Merge merge) {
|
||||
// Reject PRM_LOAD_FILE command during non-idle file load states
|
||||
if (m_state != PrmDbFileLoadState::IDLE) {
|
||||
this->log_WARNING_LO_PrmDbFileLoadInvalidAction(m_state, PrmDb_PrmLoadAction::LOAD_FILE_COMMAND);
|
||||
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::BUSY);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set state to loading
|
||||
m_state = PrmDbFileLoadState::LOADING_FILE_UPDATES;
|
||||
|
||||
// If reset is true, clear the staging database first
|
||||
if (merge == PrmDb_Merge::MERGE) {
|
||||
// Copy active to staging for merging
|
||||
dbCopy(PrmDbType::DB_STAGING, PrmDbType::DB_ACTIVE);
|
||||
} else {
|
||||
// reset staging db, all file contents will be loaded but no old parameters will be retained
|
||||
this->clearDb(PrmDbType::DB_STAGING);
|
||||
}
|
||||
|
||||
// Load the file into staging database
|
||||
// The readParamFileImpl will emit the relevant EVR if the file load fails
|
||||
// and also if it succeeds will emit EVRs with the number of records
|
||||
PrmDbImpl::PrmLoadStatus success = PrmDbImpl::readParamFileImpl(fileName, PrmDbType::DB_STAGING);
|
||||
|
||||
if (success == PrmLoadStatus::SUCCESS) {
|
||||
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
|
||||
m_state = PrmDbFileLoadState::FILE_UPDATES_STAGED;
|
||||
} else {
|
||||
this->log_WARNING_HI_PrmDbFileLoadFailed();
|
||||
// clear the staging DB and reset to an IDLE state in case of issues
|
||||
this->clearDb(PrmDbType::DB_STAGING);
|
||||
m_state = PrmDbFileLoadState::IDLE;
|
||||
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
void PrmDbImpl::PRM_COMMIT_STAGED_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
|
||||
// Verify we are in the correct state
|
||||
if (m_state != PrmDbFileLoadState::FILE_UPDATES_STAGED) {
|
||||
this->log_WARNING_LO_PrmDbFileLoadInvalidAction(m_state, PrmDb_PrmLoadAction::COMMIT_STAGED_COMMAND);
|
||||
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Swap active and staging databases, safely w.r.t. prmGet
|
||||
this->lock();
|
||||
t_dbStruct* temp = this->m_activeDb;
|
||||
this->m_activeDb = this->m_stagingDb;
|
||||
this->unLock();
|
||||
this->m_stagingDb = temp;
|
||||
|
||||
// Clear the new staging database
|
||||
this->clearDb(PrmDbType::DB_STAGING);
|
||||
|
||||
// Set file load state to idle
|
||||
m_state = PrmDbFileLoadState::IDLE;
|
||||
|
||||
this->log_ACTIVITY_HI_PrmDbCommitComplete();
|
||||
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
|
||||
}
|
||||
|
||||
//! ----------------------------------------------------------------------
|
||||
//! Helpers for construction/destruction, init, & handlers
|
||||
//! ----------------------------------------------------------------------
|
||||
|
||||
PrmDbImpl::PrmLoadStatus PrmDbImpl::readParamFileImpl(const Fw::StringBase& fileName, PrmDbType dbType) {
|
||||
FW_ASSERT(dbType == PrmDbType::DB_ACTIVE or dbType == PrmDbType::DB_STAGING);
|
||||
FW_ASSERT(fileName.length() > 0);
|
||||
|
||||
Fw::String dbString = getDbString(dbType);
|
||||
|
||||
void PrmDbImpl::readParamFile() {
|
||||
FW_ASSERT(this->m_fileName.length() > 0);
|
||||
// load file. FIXME: Put more robust file checking, such as a CRC.
|
||||
Os::File paramFile;
|
||||
|
||||
Os::File::Status stat = paramFile.open(this->m_fileName.toChar(), Os::File::OPEN_READ);
|
||||
Os::File::Status stat = paramFile.open(fileName.toChar(), Os::File::OPEN_READ);
|
||||
if (stat != Os::File::OP_OK) {
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::OPEN, 0, stat);
|
||||
return;
|
||||
return PrmLoadStatus::ERROR;
|
||||
}
|
||||
|
||||
WorkingBuffer buff;
|
||||
|
||||
U32 recordNum = 0;
|
||||
|
||||
this->clearDb();
|
||||
U32 recordNumTotal = 0;
|
||||
U32 recordNumAdded = 0;
|
||||
U32 recordNumUpdated = 0;
|
||||
|
||||
for (FwSizeType entry = 0; entry < PRMDB_NUM_DB_ENTRIES; entry++) {
|
||||
U8 delimiter;
|
||||
@ -265,35 +348,36 @@ void PrmDbImpl::readParamFile() {
|
||||
}
|
||||
|
||||
if (fStat != Os::File::OP_OK) {
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::DELIMITER, static_cast<I32>(recordNum), fStat);
|
||||
return;
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::DELIMITER, static_cast<I32>(recordNumTotal), fStat);
|
||||
return PrmLoadStatus::ERROR;
|
||||
}
|
||||
|
||||
if (sizeof(delimiter) != readSize) {
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::DELIMITER_SIZE, static_cast<I32>(recordNum),
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::DELIMITER_SIZE, static_cast<I32>(recordNumTotal),
|
||||
static_cast<I32>(readSize));
|
||||
return;
|
||||
return PrmLoadStatus::ERROR;
|
||||
}
|
||||
|
||||
if (PRMDB_ENTRY_DELIMITER != delimiter) {
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::DELIMITER_VALUE, static_cast<I32>(recordNum),
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::DELIMITER_VALUE, static_cast<I32>(recordNumTotal),
|
||||
delimiter);
|
||||
return;
|
||||
return PrmLoadStatus::ERROR;
|
||||
}
|
||||
|
||||
U32 recordSize = 0;
|
||||
|
||||
// read record size
|
||||
readSize = sizeof(recordSize);
|
||||
|
||||
fStat = paramFile.read(buff.getBuffAddr(), readSize, Os::File::WaitType::WAIT);
|
||||
if (fStat != Os::File::OP_OK) {
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::RECORD_SIZE, static_cast<I32>(recordNum), fStat);
|
||||
return;
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::RECORD_SIZE, static_cast<I32>(recordNumTotal), fStat);
|
||||
return PrmLoadStatus::ERROR;
|
||||
}
|
||||
if (sizeof(recordSize) != readSize) {
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::RECORD_SIZE_SIZE, static_cast<I32>(recordNum),
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::RECORD_SIZE_SIZE, static_cast<I32>(recordNumTotal),
|
||||
static_cast<I32>(readSize));
|
||||
return;
|
||||
return PrmLoadStatus::ERROR;
|
||||
}
|
||||
// set serialized size to read size
|
||||
Fw::SerializeStatus desStat = buff.setBuffLen(static_cast<Fw::Serializable::SizeType>(readSize));
|
||||
@ -308,9 +392,9 @@ void PrmDbImpl::readParamFile() {
|
||||
// sanity check value. It can't be larger than the maximum parameter buffer size + id
|
||||
// or smaller than the record id
|
||||
if ((recordSize > FW_PARAM_BUFFER_MAX_SIZE + sizeof(U32)) or (recordSize < sizeof(U32))) {
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::RECORD_SIZE_VALUE, static_cast<I32>(recordNum),
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::RECORD_SIZE_VALUE, static_cast<I32>(recordNumTotal),
|
||||
static_cast<I32>(recordSize));
|
||||
return;
|
||||
return PrmLoadStatus::ERROR;
|
||||
}
|
||||
|
||||
// read the parameter ID
|
||||
@ -319,13 +403,13 @@ void PrmDbImpl::readParamFile() {
|
||||
|
||||
fStat = paramFile.read(buff.getBuffAddr(), readSize, Os::File::WaitType::WAIT);
|
||||
if (fStat != Os::File::OP_OK) {
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_ID, static_cast<I32>(recordNum), fStat);
|
||||
return;
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_ID, static_cast<I32>(recordNumTotal), fStat);
|
||||
return PrmLoadStatus::ERROR;
|
||||
}
|
||||
if (sizeof(parameterId) != static_cast<FwSizeType>(readSize)) {
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_ID_SIZE, static_cast<I32>(recordNum),
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_ID_SIZE, static_cast<I32>(recordNumTotal),
|
||||
static_cast<I32>(readSize));
|
||||
return;
|
||||
return PrmLoadStatus::ERROR;
|
||||
}
|
||||
|
||||
// set serialized size to read parameter ID
|
||||
@ -338,36 +422,128 @@ void PrmDbImpl::readParamFile() {
|
||||
desStat = buff.deserializeTo(parameterId);
|
||||
FW_ASSERT(Fw::FW_SERIALIZE_OK == desStat);
|
||||
|
||||
// copy parameter
|
||||
this->m_db[entry].used = true;
|
||||
this->m_db[entry].id = parameterId;
|
||||
// copy parameter value from file into a temporary buffer
|
||||
Fw::ParamBuffer tmpParamBuffer; // temporary param buffer to read parameter value from file
|
||||
readSize = recordSize - sizeof(parameterId);
|
||||
|
||||
fStat = paramFile.read(this->m_db[entry].val.getBuffAddr(), readSize);
|
||||
desStat = tmpParamBuffer.setBuffLen(static_cast<Fw::Serializable::SizeType>(readSize));
|
||||
FW_ASSERT(Fw::FW_SERIALIZE_OK == desStat, static_cast<FwAssertArgType>(desStat)); // should never fail
|
||||
fStat = paramFile.read(tmpParamBuffer.getBuffAddr(), readSize);
|
||||
|
||||
if (fStat != Os::File::OP_OK) {
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_VALUE, static_cast<I32>(recordNum), fStat);
|
||||
return;
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_VALUE, static_cast<I32>(recordNumTotal),
|
||||
fStat);
|
||||
return PrmLoadStatus::ERROR;
|
||||
}
|
||||
if (static_cast<U32>(readSize) != recordSize - sizeof(parameterId)) {
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_VALUE_SIZE, static_cast<I32>(recordNum),
|
||||
this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_VALUE_SIZE, static_cast<I32>(recordNumTotal),
|
||||
static_cast<I32>(readSize));
|
||||
return;
|
||||
return PrmLoadStatus::ERROR;
|
||||
}
|
||||
|
||||
// set serialized size to read size
|
||||
desStat = this->m_db[entry].val.setBuffLen(static_cast<Fw::Serializable::SizeType>(readSize));
|
||||
// should never fail
|
||||
FW_ASSERT(Fw::FW_SERIALIZE_OK == desStat, static_cast<FwAssertArgType>(desStat));
|
||||
recordNum++;
|
||||
// Actually update or add parameter
|
||||
PrmUpdateType updateStatus = updateAddPrmImpl(parameterId, tmpParamBuffer, dbType);
|
||||
if (updateStatus == PARAM_ADDED) {
|
||||
recordNumAdded++;
|
||||
} else if (updateStatus == PARAM_UPDATED) {
|
||||
recordNumUpdated++;
|
||||
}
|
||||
|
||||
if (updateStatus == NO_SLOTS) {
|
||||
this->log_WARNING_HI_PrmDbFull(parameterId);
|
||||
}
|
||||
recordNumTotal++;
|
||||
}
|
||||
|
||||
this->log_ACTIVITY_HI_PrmFileLoadComplete(recordNum);
|
||||
this->log_ACTIVITY_HI_PrmFileLoadComplete(dbString, recordNumTotal, recordNumAdded, recordNumUpdated);
|
||||
return PrmLoadStatus::SUCCESS;
|
||||
}
|
||||
|
||||
void PrmDbImpl::pingIn_handler(FwIndexType portNum, U32 key) {
|
||||
// respond to ping
|
||||
this->pingOut_out(0, key);
|
||||
PrmDbImpl::PrmUpdateType PrmDbImpl::updateAddPrmImpl(FwPrmIdType id, Fw::ParamBuffer& val, PrmDbType prmDbType) {
|
||||
t_dbStruct* db = getDbPtr(prmDbType);
|
||||
|
||||
PrmUpdateType updateStatus = NO_SLOTS;
|
||||
|
||||
this->lock();
|
||||
// search for existing entry
|
||||
bool existingEntry = false;
|
||||
|
||||
for (FwSizeType entry = 0; entry < PRMDB_NUM_DB_ENTRIES; entry++) {
|
||||
if ((db[entry].used) && (id == db[entry].id)) {
|
||||
db[entry].val = val;
|
||||
existingEntry = true;
|
||||
updateStatus = PARAM_UPDATED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if there is no existing entry, add one
|
||||
if (!existingEntry) {
|
||||
for (FwSizeType entry = 0; entry < PRMDB_NUM_DB_ENTRIES; entry++) {
|
||||
if (!(db[entry].used)) {
|
||||
db[entry].val = val;
|
||||
db[entry].id = id;
|
||||
db[entry].used = true;
|
||||
updateStatus = PARAM_ADDED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->unLock();
|
||||
return updateStatus;
|
||||
}
|
||||
|
||||
//! ----------------------------------------------------------------------
|
||||
//! Helpers for database management
|
||||
//! ----------------------------------------------------------------------
|
||||
|
||||
void PrmDbImpl::clearDb(PrmDbType prmDbType) {
|
||||
t_dbStruct* db = getDbPtr(prmDbType);
|
||||
for (FwSizeType entry = 0; entry < PRMDB_NUM_DB_ENTRIES; entry++) {
|
||||
db[entry].used = false;
|
||||
db[entry].id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool PrmDbImpl::dbEqual() {
|
||||
for (FwSizeType i = 0; i < PRMDB_NUM_DB_ENTRIES; i++) {
|
||||
if (!(this->m_dbStore1[i] == this->m_dbStore2[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PrmDbImpl::dbCopy(PrmDbType dest, PrmDbType src) {
|
||||
for (FwSizeType i = 0; i < PRMDB_NUM_DB_ENTRIES; i++) {
|
||||
dbCopySingle(dest, src, i);
|
||||
}
|
||||
this->log_ACTIVITY_HI_PrmDbCopyAllComplete(getDbString(src), getDbString(dest));
|
||||
}
|
||||
|
||||
void PrmDbImpl::dbCopySingle(PrmDbType dest, PrmDbType src, FwSizeType index) {
|
||||
t_dbStruct* srcPtr = getDbPtr(src);
|
||||
t_dbStruct* destPtr = getDbPtr(dest);
|
||||
|
||||
FW_ASSERT(index < PRMDB_NUM_DB_ENTRIES);
|
||||
destPtr[index].used = srcPtr[index].used;
|
||||
destPtr[index].id = srcPtr[index].id;
|
||||
destPtr[index].val = srcPtr[index].val;
|
||||
}
|
||||
|
||||
PrmDbImpl::t_dbStruct* PrmDbImpl::getDbPtr(PrmDbType dbType) {
|
||||
FW_ASSERT(dbType == PrmDbType::DB_ACTIVE or dbType == PrmDbType::DB_STAGING);
|
||||
if (dbType == PrmDbType::DB_ACTIVE) {
|
||||
return m_activeDb;
|
||||
}
|
||||
return m_stagingDb;
|
||||
}
|
||||
|
||||
Fw::String PrmDbImpl::getDbString(PrmDbType dbType) {
|
||||
FW_ASSERT(dbType == PrmDbType::DB_ACTIVE or dbType == PrmDbType::DB_STAGING);
|
||||
if (dbType == PrmDbType::DB_ACTIVE) {
|
||||
return Fw::String("ACTIVE");
|
||||
}
|
||||
return Fw::String("STAGING");
|
||||
}
|
||||
|
||||
} // namespace Svc
|
||||
|
||||
@ -16,10 +16,17 @@
|
||||
#include <Fw/Types/String.hpp>
|
||||
#include <Os/Mutex.hpp>
|
||||
#include <Svc/PrmDb/PrmDbComponentAc.hpp>
|
||||
#include <Svc/PrmDb/PrmDb_PrmDbFileLoadStateEnumAc.hpp>
|
||||
#include <Svc/PrmDb/PrmDb_PrmDbTypeEnumAc.hpp>
|
||||
#include <config/PrmDbImplCfg.hpp>
|
||||
|
||||
namespace Svc {
|
||||
|
||||
typedef PrmDb_PrmWriteError PrmWriteError;
|
||||
typedef PrmDb_PrmReadError PrmReadError;
|
||||
typedef PrmDb_PrmDbType PrmDbType;
|
||||
typedef PrmDb_PrmDbFileLoadState PrmDbFileLoadState;
|
||||
|
||||
//! \class PrmDbImpl
|
||||
//! \brief Component class for managing parameters
|
||||
//!
|
||||
@ -28,14 +35,13 @@ namespace Svc {
|
||||
//!
|
||||
|
||||
class PrmDbImpl final : public PrmDbComponentBase {
|
||||
public:
|
||||
friend class PrmDbTester;
|
||||
|
||||
public:
|
||||
//! \brief PrmDb constructor
|
||||
//!
|
||||
//! The constructor for the PrmDbImpl class.
|
||||
//! The constructor clears the database and stores
|
||||
//! the file name for opening later.
|
||||
//! The constructor clears the database and initiates the internal state.
|
||||
//!
|
||||
//! \param name component instance name
|
||||
PrmDbImpl(const char* name);
|
||||
@ -58,17 +64,85 @@ class PrmDbImpl final : public PrmDbComponentBase {
|
||||
//!
|
||||
virtual ~PrmDbImpl();
|
||||
|
||||
// Parameter update status for an individual parameter update or add
|
||||
enum PrmUpdateType {
|
||||
NO_SLOTS, //!< No slots available to add new parameter
|
||||
PARAM_ADDED, //!< Parameter added to database
|
||||
PARAM_UPDATED, //!< Parameter already in database, updated parameter
|
||||
MAX_PARAM_UPDATE_TYPES
|
||||
};
|
||||
|
||||
// Enum to return status of parameter file load
|
||||
enum PrmLoadStatus {
|
||||
SUCCESS, //!< File load successful
|
||||
ERROR, //!< File load error
|
||||
};
|
||||
|
||||
protected:
|
||||
private:
|
||||
Fw::String m_fileName; //!< filename for parameter storage
|
||||
|
||||
PrmDbFileLoadState m_state; // Current file load state of the parameter database
|
||||
|
||||
// Structure for a single parameter entry
|
||||
struct t_dbStruct {
|
||||
bool used; //!< whether slot is being used
|
||||
FwPrmIdType id; //!< the id being stored in the slot
|
||||
Fw::ParamBuffer val; //!< the serialized value of the parameter
|
||||
|
||||
bool operator==(const t_dbStruct& other) const {
|
||||
if (used != other.used)
|
||||
return false;
|
||||
if (id != other.id)
|
||||
return false;
|
||||
// Compare lengths first
|
||||
if (val.getBuffLength() != other.val.getBuffLength())
|
||||
return false;
|
||||
// Compare buffer contents
|
||||
return std::memcmp(val.getBuffAddr(), other.val.getBuffAddr(), val.getBuffLength()) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Pointers to the active and staging databases
|
||||
// These point to the actual storage arrays below
|
||||
// The active database is the ONLY one used for getting parameters
|
||||
// The staging database is used for loading parameters from a file
|
||||
// when commanded. Upon reading the file, the parameters are "staged"
|
||||
// into the staging database, and then committed to the active database
|
||||
// when a commit command is received.
|
||||
t_dbStruct* m_activeDb; //!< Pointer to the active database
|
||||
t_dbStruct* m_stagingDb; //!< Pointer to the staging database
|
||||
|
||||
// Actual storage for the active and staging databases
|
||||
t_dbStruct m_dbStore1[PRMDB_NUM_DB_ENTRIES];
|
||||
t_dbStruct m_dbStore2[PRMDB_NUM_DB_ENTRIES];
|
||||
|
||||
//! ----------------------------------------------------------------------
|
||||
//! Port & Command Handlers
|
||||
//! ----------------------------------------------------------------------
|
||||
|
||||
//! \brief Read a parameter file and store parameter values into a database
|
||||
//!
|
||||
//! This method reads a parameter file and applies the values to the specified database
|
||||
//! (i.e. active or staging).
|
||||
//!
|
||||
//!
|
||||
//! \param fileName The name of the parameter file to read
|
||||
//! \param dbType The type of database to read into (active or staging)
|
||||
//! \return status success (True) / failure(False)
|
||||
PrmLoadStatus readParamFileImpl(const Fw::StringBase& fileName, PrmDbType dbType);
|
||||
|
||||
//! \brief PrmDb parameter get handler
|
||||
//!
|
||||
//! This function retrieves a parameter value from the loaded set of stored parameters
|
||||
//! It ALWAYS searches the active database, only
|
||||
//!
|
||||
//! \param portNum input port number. Should always be zero
|
||||
//! \param id identifier for parameter being used.
|
||||
//! \param val buffer where value is placed.
|
||||
//! \return status of retrieval. PARAM_VALID = successful read, PARAM_INVALID = unsuccessful read
|
||||
Fw::ParamValid getPrm_handler(FwIndexType portNum, FwPrmIdType id, Fw::ParamBuffer& val);
|
||||
|
||||
//! \brief PrmDb parameter set handler
|
||||
//!
|
||||
//! This function updates the value of the parameter stored in RAM. The PRM_SAVE_FILE
|
||||
@ -79,6 +153,15 @@ class PrmDbImpl final : public PrmDbComponentBase {
|
||||
//! \param val buffer where value to be saved is stored.
|
||||
void setPrm_handler(FwIndexType portNum, FwPrmIdType id, Fw::ParamBuffer& val);
|
||||
|
||||
//! \brief PrmDb parameter add or update (set) helper
|
||||
//!
|
||||
//! This function does the underlying parameter update
|
||||
//!
|
||||
//! \param id identifier for parameter being used.
|
||||
//! \param val buffer where value to be saved is stored.
|
||||
//! \param dbType The type of database to read into (active or staging)
|
||||
PrmDbImpl::PrmUpdateType updateAddPrmImpl(FwPrmIdType id, Fw::ParamBuffer& val, PrmDbType prmDbType);
|
||||
|
||||
//! \brief component ping handler
|
||||
//!
|
||||
//! The ping handler responds to messages to verify that the task
|
||||
@ -87,8 +170,8 @@ class PrmDbImpl final : public PrmDbComponentBase {
|
||||
//! \param portNum the number of the incoming port.
|
||||
//! \param opCode the opcode being registered.
|
||||
//! \param key the key value that is returned with the ping response
|
||||
|
||||
void pingIn_handler(FwIndexType portNum, U32 key);
|
||||
|
||||
//! \brief PrmDb PRM_SAVE_FILE command handler
|
||||
//!
|
||||
//! This function saves the parameter values stored in RAM to the file
|
||||
@ -99,20 +182,74 @@ class PrmDbImpl final : public PrmDbComponentBase {
|
||||
//! \param cmdSeq The sequence number of the command
|
||||
void PRM_SAVE_FILE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq);
|
||||
|
||||
//! \brief PrmDb PRM_SAVE_FILE command handler
|
||||
//!
|
||||
//! This function loads the parameter values from a specified
|
||||
//! file into the backup parameter database. The command
|
||||
//! takes a reset argument which specifies whether the existing
|
||||
//! backup database should be cleared before loading the file, otherwise
|
||||
//! the file contents are merged with the existing database.
|
||||
//!
|
||||
//! \param opCode The opcode of this commands
|
||||
//! \param cmdSeq The sequence number of the command
|
||||
//! \param fileName The name of the parameter load file
|
||||
//! \param merge Whether to merge (true) or fully reset (false) the parameter database from the file contents
|
||||
void PRM_LOAD_FILE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdStringArg& fileName, PrmDb_Merge merge);
|
||||
|
||||
//! \brief PrmDb PRM_COMMIT_STAGED command handler
|
||||
//!
|
||||
//! This function copies the contents of the staging parameter database
|
||||
//! to the active parameter database, making the staged parameters
|
||||
//! active. This command should only be called after a successful
|
||||
//! PRM_LOAD_FILE command.
|
||||
//!
|
||||
//! \param opCode The opcode of this commands
|
||||
//! \param cmdSeq The sequence number of the command
|
||||
void PRM_COMMIT_STAGED_cmdHandler(FwOpcodeType opCode, U32 cmdSeq);
|
||||
|
||||
//! ----------------------------------------------------------------------
|
||||
//! Helpers for database management
|
||||
//! ----------------------------------------------------------------------
|
||||
|
||||
//! \brief PrmDb clear database function
|
||||
//!
|
||||
//! This function clears all entries from the RAM database
|
||||
//!
|
||||
//! \param dbType The type of database to clear (active or staging)
|
||||
void clearDb(PrmDbType prmDbType);
|
||||
|
||||
void clearDb(); //!< clear the parameter database
|
||||
//! \brief PrmDb get db pointer function
|
||||
//! This function returns a pointer to the requested database
|
||||
//! \param dbType The type of database requested (active or staging)
|
||||
//! \return Pointer to the database array to be set
|
||||
t_dbStruct* getDbPtr(PrmDbType dbType);
|
||||
|
||||
Fw::String m_fileName; //!< filename for parameter storage
|
||||
//! \brief PrmDb get db string function
|
||||
//! This function returns a string for the requested database
|
||||
//! \param dbType The type of database requested (active or staging)
|
||||
//! \return string representing the database
|
||||
static Fw::String getDbString(PrmDbType dbType);
|
||||
|
||||
struct t_dbStruct {
|
||||
bool used; //!< whether slot is being used
|
||||
FwPrmIdType id; //!< the id being stored in the slot
|
||||
Fw::ParamBuffer val; //!< the serialized value of the parameter
|
||||
} m_db[PRMDB_NUM_DB_ENTRIES];
|
||||
//! \brief Check param db equality
|
||||
//!
|
||||
//! This helper method verifies the active and staging parameter dbs are equal
|
||||
bool dbEqual();
|
||||
|
||||
//! \brief Deep copy for db
|
||||
//!
|
||||
//! Copies one db to another
|
||||
//! \param dest The destination db to copy to (active or staging)
|
||||
//! \param src The source db to copy from (active or staging)
|
||||
void dbCopy(PrmDbType dest, PrmDbType src);
|
||||
|
||||
//! \brief Deep copy for single db entry
|
||||
//!
|
||||
//! Copies one db entry to another at specified index
|
||||
//!
|
||||
//! \param dest The destination db to copy to (active or staging)
|
||||
//! \param src The source db to copy from (active or staging)
|
||||
//! \param index The index of the entry to copy
|
||||
void dbCopySingle(PrmDbType dest, PrmDbType src, FwSizeType index);
|
||||
};
|
||||
} // namespace Svc
|
||||
|
||||
|
||||
@ -175,6 +175,102 @@ TEST(ParameterDbTest, PrmFileWriteError) {
|
||||
tester.runFileWriteError();
|
||||
}
|
||||
|
||||
TEST(ParameterDbTest, PrmDbEqualTest) {
|
||||
Svc::PrmDbImpl impl("PrmDbImpl");
|
||||
|
||||
impl.init(10, 0);
|
||||
impl.configure("TestFile.prm");
|
||||
|
||||
Svc::PrmDbTester tester(impl);
|
||||
|
||||
tester.init();
|
||||
|
||||
// connect ports
|
||||
connectPorts(impl, tester);
|
||||
|
||||
tester.runDbEqualTest();
|
||||
}
|
||||
|
||||
TEST(ParameterDbTest, PrmDbCopyTest) {
|
||||
Svc::PrmDbImpl impl("PrmDbImpl");
|
||||
|
||||
impl.init(10, 0);
|
||||
impl.configure("TestFile.prm");
|
||||
|
||||
Svc::PrmDbTester tester(impl);
|
||||
|
||||
tester.init();
|
||||
|
||||
// connect ports
|
||||
connectPorts(impl, tester);
|
||||
|
||||
tester.runDbCopyTest();
|
||||
}
|
||||
|
||||
TEST(ParameterDbTest, PrmDbCommitTest) {
|
||||
Svc::PrmDbImpl impl("PrmDbImpl");
|
||||
|
||||
impl.init(10, 0);
|
||||
impl.configure("TestFile.prm");
|
||||
|
||||
Svc::PrmDbTester tester(impl);
|
||||
|
||||
tester.init();
|
||||
|
||||
// connect ports
|
||||
connectPorts(impl, tester);
|
||||
|
||||
tester.runDbCommitTest();
|
||||
}
|
||||
|
||||
TEST(ParameterDbTest, PrmDbFileLoadNominal) {
|
||||
Svc::PrmDbImpl impl("PrmDbImpl");
|
||||
|
||||
impl.init(10, 0);
|
||||
impl.configure("TestFile.prm");
|
||||
|
||||
Svc::PrmDbTester tester(impl);
|
||||
|
||||
tester.init();
|
||||
|
||||
// connect ports
|
||||
connectPorts(impl, tester);
|
||||
|
||||
tester.runPrmFileLoadNominal();
|
||||
}
|
||||
|
||||
TEST(ParameterDbTest, PrmDbFileLoadWithErrors) {
|
||||
Svc::PrmDbImpl impl("PrmDbImpl");
|
||||
|
||||
impl.init(10, 0);
|
||||
impl.configure("TestFile.prm");
|
||||
|
||||
Svc::PrmDbTester tester(impl);
|
||||
|
||||
tester.init();
|
||||
|
||||
// connect ports
|
||||
connectPorts(impl, tester);
|
||||
|
||||
tester.runPrmFileLoadWithErrors();
|
||||
}
|
||||
|
||||
TEST(ParameterDbTest, PrmFileLoadIllegalActions) {
|
||||
Svc::PrmDbImpl impl("PrmDbImpl");
|
||||
|
||||
impl.init(10, 0);
|
||||
impl.configure("TestFile.prm");
|
||||
|
||||
Svc::PrmDbTester tester(impl);
|
||||
|
||||
tester.init();
|
||||
|
||||
// connect ports
|
||||
connectPorts(impl, tester);
|
||||
|
||||
tester.runPrmFileLoadIllegal();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
|
||||
@ -23,7 +23,7 @@ typedef PrmDb_PrmReadError PrmReadError;
|
||||
|
||||
void PrmDbTester::runNominalPopulate() {
|
||||
// clear database
|
||||
this->m_impl.clearDb();
|
||||
this->m_impl.clearDb(PrmDbType::DB_ACTIVE);
|
||||
|
||||
// build a test parameter value with a simple value
|
||||
U32 val = 0x10;
|
||||
@ -158,7 +158,7 @@ void PrmDbTester::runNominalLoadFile() {
|
||||
this->m_impl.readParamFile();
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmFileLoadComplete_SIZE(1);
|
||||
ASSERT_EVENTS_PrmFileLoadComplete(0, 2);
|
||||
ASSERT_EVENTS_PrmFileLoadComplete(0, "ACTIVE", 2, 2, 0);
|
||||
|
||||
// verify values (populated by runNominalPopulate())
|
||||
|
||||
@ -192,7 +192,7 @@ void PrmDbTester::runMissingExtraParams() {
|
||||
ASSERT_EVENTS_PrmIdNotFound(0, 0x1000);
|
||||
|
||||
// clear database
|
||||
this->m_impl.clearDb();
|
||||
this->m_impl.clearDb(PrmDbType::DB_ACTIVE);
|
||||
|
||||
this->clearEvents();
|
||||
// write too many entries
|
||||
@ -343,56 +343,6 @@ void PrmDbTester::runRefPrmFile() {
|
||||
ASSERT_EVENTS_PrmFileSaveComplete(0, 4);
|
||||
}
|
||||
|
||||
PrmDbTester* PrmDbTester::PrmDbTestFile::s_tester = nullptr;
|
||||
|
||||
void PrmDbTester::PrmDbTestFile::setTester(Svc::PrmDbTester* tester) {
|
||||
ASSERT_NE(tester, nullptr);
|
||||
s_tester = tester;
|
||||
}
|
||||
|
||||
Os::File::Status PrmDbTester::PrmDbTestFile::read(U8* buffer, FwSizeType& size, Os::File::WaitType wait) {
|
||||
EXPECT_NE(s_tester, nullptr);
|
||||
Os::File::Status status = this->Os::Stub::File::Test::TestFile::read(buffer, size, wait);
|
||||
if (s_tester->m_waits == 0) {
|
||||
switch (s_tester->m_errorType) {
|
||||
case FILE_STATUS_ERROR:
|
||||
status = s_tester->m_status;
|
||||
break;
|
||||
case FILE_SIZE_ERROR:
|
||||
size += 1;
|
||||
break;
|
||||
case FILE_DATA_ERROR:
|
||||
buffer[0] += 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
s_tester->m_waits -= 1;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
Os::File::Status PrmDbTester::PrmDbTestFile::write(const U8* buffer, FwSizeType& size, Os::File::WaitType wait) {
|
||||
EXPECT_NE(s_tester, nullptr);
|
||||
Os::File::Status status = this->Os::Stub::File::Test::TestFile::write(buffer, size, wait);
|
||||
if (s_tester->m_waits == 0) {
|
||||
switch (s_tester->m_errorType) {
|
||||
case FILE_STATUS_ERROR:
|
||||
status = s_tester->m_status;
|
||||
break;
|
||||
case FILE_SIZE_ERROR:
|
||||
size += 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
s_tester->m_waits -= 1;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void PrmDbTester::runFileReadError() {
|
||||
// Preconditions setup and test
|
||||
this->runNominalLoadFile();
|
||||
@ -602,6 +552,791 @@ void PrmDbTester::runFileWriteError() {
|
||||
}
|
||||
}
|
||||
|
||||
void PrmDbTester::runDbEqualTest() {
|
||||
Fw::SerializeStatus serStat;
|
||||
|
||||
// 1. Test with empty databases - should be equal
|
||||
this->m_impl.clearDb(PrmDb_PrmDbType::DB_ACTIVE);
|
||||
this->m_impl.clearDb(PrmDb_PrmDbType::DB_STAGING);
|
||||
EXPECT_TRUE(this->m_impl.dbEqual());
|
||||
|
||||
// 2. Add an entry to active DB only - should not be equal
|
||||
U32 val1 = 0x42;
|
||||
FwPrmIdType id1 = 0x100;
|
||||
Fw::ParamBuffer pBuff;
|
||||
|
||||
serStat = pBuff.serializeFrom(val1);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, serStat);
|
||||
|
||||
this->m_impl.updateAddPrmImpl(id1, pBuff, PrmDb_PrmDbType::DB_ACTIVE);
|
||||
EXPECT_FALSE(this->m_impl.dbEqual());
|
||||
|
||||
// 3. Add same entry to staging DB - should be equal again
|
||||
pBuff.resetSer();
|
||||
serStat = pBuff.serializeFrom(val1);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, serStat);
|
||||
|
||||
this->m_impl.updateAddPrmImpl(id1, pBuff, PrmDb_PrmDbType::DB_STAGING);
|
||||
EXPECT_TRUE(this->m_impl.dbEqual());
|
||||
|
||||
// 4. Update entry in active DB only - should not be equal
|
||||
U32 val2 = 0x43;
|
||||
pBuff.resetSer();
|
||||
serStat = pBuff.serializeFrom(val2);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, serStat);
|
||||
|
||||
this->m_impl.updateAddPrmImpl(id1, pBuff, PrmDb_PrmDbType::DB_STAGING);
|
||||
EXPECT_FALSE(this->m_impl.dbEqual());
|
||||
|
||||
// 5. Update staging DB to match - should be equal again
|
||||
pBuff.resetSer();
|
||||
serStat = pBuff.serializeFrom(val2);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, serStat);
|
||||
|
||||
this->m_impl.updateAddPrmImpl(id1, pBuff, PrmDb_PrmDbType::DB_ACTIVE);
|
||||
EXPECT_TRUE(this->m_impl.dbEqual());
|
||||
|
||||
// 6. Add different entry to staging DB - should not be equal
|
||||
U32 val3 = 0x44;
|
||||
FwPrmIdType id2 = 0x101;
|
||||
pBuff.resetSer();
|
||||
serStat = pBuff.serializeFrom(val3);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, serStat);
|
||||
|
||||
this->m_impl.updateAddPrmImpl(id2, pBuff, PrmDb_PrmDbType::DB_STAGING);
|
||||
EXPECT_FALSE(this->m_impl.dbEqual());
|
||||
}
|
||||
|
||||
void PrmDbTester::runDbCopyTest() {
|
||||
Fw::SerializeStatus serStat;
|
||||
|
||||
// Clear both databases
|
||||
this->m_impl.clearDb(PrmDb_PrmDbType::DB_ACTIVE);
|
||||
this->m_impl.clearDb(PrmDb_PrmDbType::DB_STAGING);
|
||||
|
||||
// Add entries to active DB only
|
||||
U32 val1 = 0x1234;
|
||||
FwPrmIdType id1 = 0x100;
|
||||
Fw::ParamBuffer pBuff;
|
||||
|
||||
// Add first parameter
|
||||
pBuff.resetSer();
|
||||
serStat = pBuff.serializeFrom(val1);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, serStat);
|
||||
this->m_impl.updateAddPrmImpl(id1, pBuff, PrmDb_PrmDbType::DB_ACTIVE);
|
||||
|
||||
// Add second parameter
|
||||
F32 val2 = 3.14159f;
|
||||
FwPrmIdType id2 = 0x200;
|
||||
pBuff.resetSer();
|
||||
serStat = pBuff.serializeFrom(val2);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, serStat);
|
||||
this->m_impl.updateAddPrmImpl(id2, pBuff, PrmDb_PrmDbType::DB_ACTIVE);
|
||||
|
||||
// Verify databases are not equal
|
||||
EXPECT_FALSE(this->m_impl.dbEqual());
|
||||
|
||||
// Copy active DB to staging DB
|
||||
this->m_impl.dbCopy(PrmDb_PrmDbType::DB_STAGING, PrmDb_PrmDbType::DB_ACTIVE);
|
||||
|
||||
// Verify databases are now equal
|
||||
EXPECT_TRUE(this->m_impl.dbEqual());
|
||||
|
||||
// Verify values in the staging DB
|
||||
pBuff.resetSer();
|
||||
U32 testVal1;
|
||||
FwSizeType idx = 0;
|
||||
// Find the parameter and get its index
|
||||
for (FwSizeType i = 0; i < PRMDB_NUM_DB_ENTRIES; i++) {
|
||||
if (this->m_impl.m_activeDb[i].used && this->m_impl.m_stagingDb[i].id == id1) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(this->m_impl.m_activeDb[idx].used);
|
||||
EXPECT_EQ(id1, this->m_impl.m_stagingDb[idx].id);
|
||||
pBuff = this->m_impl.m_stagingDb[idx].val;
|
||||
serStat = pBuff.deserializeTo(testVal1);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, serStat);
|
||||
EXPECT_EQ(val1, testVal1);
|
||||
|
||||
// Clear both databases
|
||||
this->m_impl.clearDb(PrmDb_PrmDbType::DB_ACTIVE);
|
||||
this->m_impl.clearDb(PrmDb_PrmDbType::DB_STAGING);
|
||||
|
||||
// Add different entries to active and staging DBs
|
||||
|
||||
// active DB - add first parameter
|
||||
pBuff.resetSer();
|
||||
serStat = pBuff.serializeFrom(val1);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, serStat);
|
||||
this->m_impl.updateAddPrmImpl(id1, pBuff, PrmDb_PrmDbType::DB_ACTIVE);
|
||||
|
||||
// active DB - add second parameter
|
||||
pBuff.resetSer();
|
||||
serStat = pBuff.serializeFrom(val2);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, serStat);
|
||||
this->m_impl.updateAddPrmImpl(id2, pBuff, PrmDb_PrmDbType::DB_ACTIVE);
|
||||
|
||||
// staging DB - add different parameter
|
||||
U16 val3 = 0x5678;
|
||||
FwPrmIdType id3 = 0x300;
|
||||
pBuff.resetSer();
|
||||
serStat = pBuff.serializeFrom(val3);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, serStat);
|
||||
this->m_impl.updateAddPrmImpl(id3, pBuff, PrmDb_PrmDbType::DB_STAGING);
|
||||
|
||||
// Verify databases are not equal
|
||||
EXPECT_FALSE(this->m_impl.dbEqual());
|
||||
|
||||
// Copy only the second entry from active to staging at the same index
|
||||
FwSizeType activeIdx2 = 1; // Index of second entry in active DB
|
||||
this->m_impl.dbCopySingle(PrmDb_PrmDbType::DB_STAGING, PrmDb_PrmDbType::DB_ACTIVE, activeIdx2);
|
||||
|
||||
// Verify the specific entry was copied correctly
|
||||
EXPECT_TRUE(this->m_impl.m_stagingDb[activeIdx2].used);
|
||||
EXPECT_EQ(id2, this->m_impl.m_stagingDb[activeIdx2].id);
|
||||
|
||||
// Verify value matches
|
||||
pBuff = this->m_impl.m_stagingDb[activeIdx2].val;
|
||||
F32 testVal2;
|
||||
serStat = pBuff.deserializeTo(testVal2);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, serStat);
|
||||
EXPECT_EQ(val2, testVal2);
|
||||
|
||||
// Verify the original entry in staging DB is still there
|
||||
bool foundOriginal = false;
|
||||
for (FwSizeType i = 0; i < PRMDB_NUM_DB_ENTRIES; i++) {
|
||||
if (this->m_impl.m_stagingDb[i].used && this->m_impl.m_stagingDb[i].id == id3) {
|
||||
foundOriginal = true;
|
||||
|
||||
// Verify value is still correct
|
||||
pBuff = this->m_impl.m_stagingDb[i].val;
|
||||
U16 testVal3;
|
||||
serStat = pBuff.deserializeTo(testVal3);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, serStat);
|
||||
EXPECT_EQ(val3, testVal3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(foundOriginal);
|
||||
|
||||
// Databases should still not be equal since we only copied one entry
|
||||
EXPECT_FALSE(this->m_impl.dbEqual());
|
||||
}
|
||||
|
||||
void PrmDbTester::runDbCommitTest() {
|
||||
// 1. Set the m_state to FILE_UPDATES_STAGED
|
||||
this->m_impl.m_state = PrmDbFileLoadState::FILE_UPDATES_STAGED;
|
||||
|
||||
// 2. Populate both databases with different content
|
||||
// Clear both databases first
|
||||
this->m_impl.clearDb(PrmDbType::DB_ACTIVE);
|
||||
this->m_impl.clearDb(PrmDbType::DB_STAGING);
|
||||
|
||||
// Add parameters to active database
|
||||
U32 activeVal1 = 0x1234;
|
||||
FwPrmIdType activeId1 = 0x100;
|
||||
Fw::ParamBuffer pBuff;
|
||||
|
||||
Fw::SerializeStatus stat = pBuff.serializeFrom(activeVal1);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
this->m_impl.updateAddPrmImpl(activeId1, pBuff, PrmDbType::DB_ACTIVE);
|
||||
|
||||
// Add different parameters to staging database
|
||||
U32 stagingVal1 = 0x5678;
|
||||
FwPrmIdType stagingId1 = 0x100; // Same ID but different value
|
||||
pBuff.resetSer();
|
||||
stat = pBuff.serializeFrom(stagingVal1);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
this->m_impl.updateAddPrmImpl(stagingId1, pBuff, PrmDbType::DB_STAGING);
|
||||
|
||||
// Add a parameter that's only in the staging database
|
||||
F32 stagingVal2 = 3.14159f;
|
||||
FwPrmIdType stagingId2 = 0x200;
|
||||
pBuff.resetSer();
|
||||
stat = pBuff.serializeFrom(stagingVal2);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
this->m_impl.updateAddPrmImpl(stagingId2, pBuff, PrmDbType::DB_STAGING);
|
||||
|
||||
// Store pointers to databases before swap for verification
|
||||
PrmDbImpl::t_dbStruct* preSwapActiveDb = this->m_impl.m_activeDb;
|
||||
PrmDbImpl::t_dbStruct* preSwapStagingDb = this->m_impl.m_stagingDb;
|
||||
|
||||
// Clear events and command history
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
|
||||
// 3. Execute the commit command
|
||||
this->sendCmd_PRM_COMMIT_STAGED(0, 10);
|
||||
Fw::QueuedComponentBase::MsgDispatchStatus dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
// 4. Verify results
|
||||
|
||||
// Check command response
|
||||
ASSERT_CMD_RESPONSE_SIZE(1);
|
||||
ASSERT_CMD_RESPONSE(0, PrmDbImpl::OPCODE_PRM_COMMIT_STAGED, 10, Fw::CmdResponse::OK);
|
||||
|
||||
// Check event
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbCommitComplete_SIZE(1);
|
||||
|
||||
// Verify the state is now IDLE
|
||||
EXPECT_EQ(this->m_impl.m_state, PrmDbFileLoadState::IDLE);
|
||||
|
||||
// Verify that the database pointers have been swapped
|
||||
EXPECT_EQ(this->m_impl.m_activeDb, preSwapStagingDb);
|
||||
EXPECT_EQ(this->m_impl.m_stagingDb, preSwapActiveDb);
|
||||
|
||||
// Verify that the new staging database is empty
|
||||
bool allEntriesCleared = true;
|
||||
for (FwSizeType i = 0; i < PRMDB_NUM_DB_ENTRIES; i++) {
|
||||
if (this->m_impl.m_stagingDb[i].used) {
|
||||
allEntriesCleared = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(allEntriesCleared);
|
||||
|
||||
// Verify that parameters can be accessed from the newly active database
|
||||
// (which was formerly the staging database)
|
||||
pBuff.resetSer();
|
||||
U32 retrievedVal1;
|
||||
this->invoke_to_getPrm(0, stagingId1, pBuff);
|
||||
stat = pBuff.deserializeTo(retrievedVal1);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
EXPECT_EQ(retrievedVal1, stagingVal1);
|
||||
|
||||
pBuff.resetSer();
|
||||
F32 retrievedVal2;
|
||||
this->invoke_to_getPrm(0, stagingId2, pBuff);
|
||||
stat = pBuff.deserializeTo(retrievedVal2);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
EXPECT_EQ(retrievedVal2, stagingVal2);
|
||||
|
||||
// Test invalid state handling - try to commit again when not in FILE_UPDATES_STAGED state
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
this->sendCmd_PRM_COMMIT_STAGED(0, 11);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
// Should get validation error and warning event
|
||||
ASSERT_CMD_RESPONSE_SIZE(1);
|
||||
ASSERT_CMD_RESPONSE(0, PrmDbImpl::OPCODE_PRM_COMMIT_STAGED, 11, Fw::CmdResponse::VALIDATION_ERROR);
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction_SIZE(1);
|
||||
}
|
||||
|
||||
void PrmDbTester::runPrmFileLoadNominal() {
|
||||
Fw::String file = "TestFile.prm";
|
||||
Fw::QueuedComponentBase::MsgDispatchStatus dispatchStatus;
|
||||
|
||||
// Store pointers to databases before swap for verification
|
||||
PrmDbImpl::t_dbStruct* preSwapActiveDb = this->m_impl.m_activeDb;
|
||||
PrmDbImpl::t_dbStruct* preSwapStagingDb = this->m_impl.m_stagingDb;
|
||||
|
||||
// Ensure we're in IDLE state
|
||||
EXPECT_EQ(this->m_impl.m_state, PrmDbFileLoadState::IDLE);
|
||||
|
||||
// Populate the active DB and save to file
|
||||
runNominalSaveFile();
|
||||
printf("Saved into File: \n");
|
||||
printDb(PrmDbType::DB_ACTIVE);
|
||||
printDb(PrmDbType::DB_STAGING);
|
||||
|
||||
// Clear both databases
|
||||
this->m_impl.clearDb(PrmDbType::DB_ACTIVE);
|
||||
this->m_impl.clearDb(PrmDbType::DB_STAGING);
|
||||
|
||||
printf("Cleared: \n");
|
||||
printDb(PrmDbType::DB_ACTIVE);
|
||||
printDb(PrmDbType::DB_STAGING);
|
||||
|
||||
// Populate active database with some values so we can test merge=true
|
||||
// A new ID
|
||||
U32 activeVal1 = 0x1234;
|
||||
FwPrmIdType activeId1 = 0x100;
|
||||
Fw::ParamBuffer pBuff;
|
||||
|
||||
// Add parameter to active database
|
||||
Fw::SerializeStatus stat = pBuff.serializeFrom(activeVal1);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
this->m_impl.updateAddPrmImpl(activeId1, pBuff, PrmDbType::DB_ACTIVE);
|
||||
// Verify parameter is in active database
|
||||
pBuff.resetSer();
|
||||
U32 testVal;
|
||||
this->invoke_to_getPrm(0, activeId1, pBuff);
|
||||
stat = pBuff.deserializeTo(testVal);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
EXPECT_EQ(testVal, activeVal1);
|
||||
// A existing (in file) ID
|
||||
U32 activeVal2Original = 0x30;
|
||||
U32 activeVal2Update = activeVal2Original + 1;
|
||||
FwPrmIdType activeId2 = 0x25; // This ID exists in the file with a different value
|
||||
pBuff.resetSer();
|
||||
|
||||
// Add parameter to active database
|
||||
stat = pBuff.serializeFrom(activeVal2Update);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
this->m_impl.updateAddPrmImpl(activeId2, pBuff, PrmDbType::DB_ACTIVE);
|
||||
// Verify parameter is in active database
|
||||
pBuff.resetSer();
|
||||
U32 testVal2;
|
||||
this->invoke_to_getPrm(0, activeId2, pBuff);
|
||||
stat = pBuff.deserializeTo(testVal2);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
EXPECT_EQ(testVal2, activeVal2Update);
|
||||
|
||||
printf("Added new: \n");
|
||||
printDb(PrmDbType::DB_ACTIVE);
|
||||
printDb(PrmDbType::DB_STAGING);
|
||||
|
||||
// Send PRM_LOAD_FILE command with merge=true to merge with active database
|
||||
Os::Stub::File::Test::StaticData::setReadResult(m_io_data, Os::Stub::File::Test::StaticData::data.pointer);
|
||||
Os::Stub::File::Test::StaticData::setNextStatus(Os::File::OP_OK);
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
this->sendCmd_PRM_LOAD_FILE(0, 10, file, PrmDb_Merge::MERGE);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
ASSERT_EVENTS_SIZE(2);
|
||||
// Verify EVRs for copy (because we are merging)
|
||||
ASSERT_EVENTS_PrmDbCopyAllComplete_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbCopyAllComplete(0, "ACTIVE", "STAGING");
|
||||
// Verify EVRs for the file load
|
||||
ASSERT_EVENTS_PrmFileLoadComplete_SIZE(1);
|
||||
ASSERT_EVENTS_PrmFileLoadComplete(0, "STAGING", 2, 1, 1);
|
||||
|
||||
printf("Parameter Load file complete: \n");
|
||||
printDb(PrmDbType::DB_ACTIVE);
|
||||
printDb(PrmDbType::DB_STAGING);
|
||||
|
||||
// Verify state and command response after PRM_LOAD_FILE
|
||||
EXPECT_EQ(this->m_impl.m_state, PrmDbFileLoadState::FILE_UPDATES_STAGED);
|
||||
ASSERT_CMD_RESPONSE_SIZE(1);
|
||||
ASSERT_CMD_RESPONSE(0, PrmDbImpl::OPCODE_PRM_LOAD_FILE, 10, Fw::CmdResponse::OK);
|
||||
|
||||
// Verify that parameters in staging database have expected values
|
||||
for (FwSizeType i = 0; i < PRMDB_NUM_DB_ENTRIES; i++) {
|
||||
// Check for the parameter that we added after the save file (since we are merging)
|
||||
if (this->m_impl.m_stagingDb[i].used && this->m_impl.m_stagingDb[i].id == activeId1) {
|
||||
pBuff = this->m_impl.m_stagingDb[i].val;
|
||||
U32 checkVal;
|
||||
stat = pBuff.deserializeTo(checkVal);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
EXPECT_EQ(checkVal, activeVal1);
|
||||
}
|
||||
// Check for the parameter that we updated after the save file (since we are merging)
|
||||
if (this->m_impl.m_stagingDb[i].used && this->m_impl.m_stagingDb[i].id == activeId2) {
|
||||
pBuff = this->m_impl.m_stagingDb[i].val;
|
||||
U32 checkVal;
|
||||
stat = pBuff.deserializeTo(checkVal);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
EXPECT_EQ(checkVal, activeVal2Original); // Value should match what was in the file, not what we set
|
||||
}
|
||||
}
|
||||
|
||||
// Send PRM_COMMIT_STAGED command
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
this->sendCmd_PRM_COMMIT_STAGED(0, 11);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
// Verify state and command response after PRM_COMMIT_STAGED
|
||||
EXPECT_EQ(this->m_impl.m_state, PrmDbFileLoadState::IDLE);
|
||||
ASSERT_CMD_RESPONSE_SIZE(1);
|
||||
ASSERT_CMD_RESPONSE(0, PrmDbImpl::OPCODE_PRM_COMMIT_STAGED, 11, Fw::CmdResponse::OK);
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbCommitComplete_SIZE(1);
|
||||
|
||||
// Verify the database pointers have been swapped
|
||||
EXPECT_EQ(this->m_impl.m_activeDb, preSwapStagingDb);
|
||||
EXPECT_EQ(this->m_impl.m_stagingDb, preSwapActiveDb);
|
||||
|
||||
// Verify the new staging database (former active) is empty
|
||||
bool allEntriesCleared = true;
|
||||
for (FwSizeType i = 0; i < PRMDB_NUM_DB_ENTRIES; i++) {
|
||||
if (this->m_impl.m_stagingDb[i].used) {
|
||||
allEntriesCleared = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(allEntriesCleared);
|
||||
|
||||
// Verify we can now perform operations only allowed in IDLE state
|
||||
// Try setting a parameter - should work in IDLE state
|
||||
U32 newVal3 = 0x9ABC;
|
||||
FwPrmIdType newId3 = 0x300;
|
||||
pBuff.resetSer();
|
||||
stat = pBuff.serializeFrom(newVal3);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
|
||||
this->clearEvents();
|
||||
this->invoke_to_setPrm(0, newId3, pBuff);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
// Verify parameter was added
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmIdAdded_SIZE(1);
|
||||
|
||||
// Verify we can retrieve the newly set parameter
|
||||
pBuff.resetSer();
|
||||
U32 retrievedVal3;
|
||||
Fw::ParamValid valid = this->invoke_to_getPrm(0, newId3, pBuff);
|
||||
EXPECT_EQ(Fw::ParamValid::VALID, valid);
|
||||
stat = pBuff.deserializeTo(retrievedVal3);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
EXPECT_EQ(retrievedVal3, newVal3);
|
||||
}
|
||||
|
||||
void PrmDbTester::runPrmFileLoadWithErrors() {
|
||||
Fw::String file = "TestFile.prm";
|
||||
Fw::QueuedComponentBase::MsgDispatchStatus dispatchStatus;
|
||||
|
||||
// Store pointers to databases before swap for verification
|
||||
PrmDbImpl::t_dbStruct* preSwapActiveDb = this->m_impl.m_activeDb;
|
||||
PrmDbImpl::t_dbStruct* preSwapStagingDb = this->m_impl.m_stagingDb;
|
||||
|
||||
// Ensure we're in IDLE state
|
||||
EXPECT_EQ(this->m_impl.m_state, PrmDbFileLoadState::IDLE);
|
||||
|
||||
// Populate the active DB and save to file
|
||||
runNominalSaveFile();
|
||||
printf("Saved into File: \n");
|
||||
printDb(PrmDbType::DB_ACTIVE);
|
||||
printDb(PrmDbType::DB_STAGING);
|
||||
|
||||
// Clear both databases
|
||||
this->m_impl.clearDb(PrmDbType::DB_ACTIVE);
|
||||
this->m_impl.clearDb(PrmDbType::DB_STAGING);
|
||||
|
||||
printf("Cleared: \n");
|
||||
printDb(PrmDbType::DB_ACTIVE);
|
||||
printDb(PrmDbType::DB_STAGING);
|
||||
|
||||
// Populate active database with some values so we can test merge=true
|
||||
// A new ID
|
||||
U32 activeVal1 = 0x1234;
|
||||
FwPrmIdType activeId1 = 0x100;
|
||||
Fw::ParamBuffer pBuff;
|
||||
|
||||
// Add parameter to active database
|
||||
Fw::SerializeStatus stat = pBuff.serializeFrom(activeVal1);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
this->m_impl.updateAddPrmImpl(activeId1, pBuff, PrmDbType::DB_ACTIVE);
|
||||
// Verify parameter is in active database
|
||||
pBuff.resetSer();
|
||||
U32 testVal;
|
||||
this->invoke_to_getPrm(0, activeId1, pBuff);
|
||||
stat = pBuff.deserializeTo(testVal);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
EXPECT_EQ(testVal, activeVal1);
|
||||
// A existing (in file) ID
|
||||
U32 activeVal2Original = 0x30;
|
||||
U32 activeVal2Update = activeVal2Original + 1;
|
||||
FwPrmIdType activeId2 = 0x25; // This ID exists in the file with a different value
|
||||
pBuff.resetSer();
|
||||
|
||||
// Add parameter to active database
|
||||
stat = pBuff.serializeFrom(activeVal2Update);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
this->m_impl.updateAddPrmImpl(activeId2, pBuff, PrmDbType::DB_ACTIVE);
|
||||
// Verify parameter is in active database
|
||||
pBuff.resetSer();
|
||||
U32 testVal2;
|
||||
this->invoke_to_getPrm(0, activeId2, pBuff);
|
||||
stat = pBuff.deserializeTo(testVal2);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
EXPECT_EQ(testVal2, activeVal2Update);
|
||||
|
||||
printf("Added new: \n");
|
||||
printDb(PrmDbType::DB_ACTIVE);
|
||||
printDb(PrmDbType::DB_STAGING);
|
||||
|
||||
// Send PRM_LOAD_FILE command with merge=true to merge with active database
|
||||
// but with a file open error
|
||||
Os::Stub::File::Test::StaticData::setReadResult(m_io_data, Os::Stub::File::Test::StaticData::data.pointer);
|
||||
Os::Stub::File::Test::StaticData::setNextStatus(Os::File::DOESNT_EXIST);
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
this->sendCmd_PRM_LOAD_FILE(0, 10, file, PrmDb_Merge::MERGE);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
ASSERT_EVENTS_SIZE(3);
|
||||
// Verify EVRs for copy (because we are merging)
|
||||
ASSERT_EVENTS_PrmDbCopyAllComplete_SIZE(1);
|
||||
// Verify EVRs for file load read error
|
||||
ASSERT_EVENTS_PrmFileReadError_SIZE(1);
|
||||
// Verify EVRs for the file load cmd failure
|
||||
ASSERT_EVENTS_PrmDbFileLoadFailed_SIZE(1);
|
||||
|
||||
printf("Parameter Load file complete: \n");
|
||||
printDb(PrmDbType::DB_ACTIVE);
|
||||
printDb(PrmDbType::DB_STAGING);
|
||||
|
||||
// Verify state and command response after PRM_LOAD_FILE
|
||||
EXPECT_EQ(this->m_impl.m_state, PrmDbFileLoadState::IDLE);
|
||||
ASSERT_CMD_RESPONSE(0, PrmDbImpl::OPCODE_PRM_LOAD_FILE, 10, Fw::CmdResponse::EXECUTION_ERROR);
|
||||
|
||||
// Verify the database pointers have NOT been swapped
|
||||
EXPECT_EQ(this->m_impl.m_activeDb, preSwapActiveDb);
|
||||
EXPECT_EQ(this->m_impl.m_stagingDb, preSwapStagingDb);
|
||||
|
||||
// Verify the staging database is empty
|
||||
bool allEntriesCleared = true;
|
||||
for (FwSizeType i = 0; i < PRMDB_NUM_DB_ENTRIES; i++) {
|
||||
if (this->m_impl.m_stagingDb[i].used) {
|
||||
allEntriesCleared = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(allEntriesCleared);
|
||||
}
|
||||
|
||||
void PrmDbTester::runPrmFileLoadIllegal() {
|
||||
Fw::QueuedComponentBase::MsgDispatchStatus dispatchStatus;
|
||||
Fw::ParamBuffer pBuff;
|
||||
U32 testVal = 0x1234;
|
||||
FwPrmIdType testId = 0x42;
|
||||
|
||||
// Serialize test value for parameter setting
|
||||
Fw::SerializeStatus stat = pBuff.serializeFrom(testVal);
|
||||
EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// 1. Test illegal operations in LOADING_FILE_UPDATES state
|
||||
// -------------------------------------------------------------------
|
||||
this->m_impl.m_state = PrmDbFileLoadState::LOADING_FILE_UPDATES;
|
||||
|
||||
// 1.1 Attempt PRM_LOAD_FILE while already loading
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
this->sendCmd_PRM_LOAD_FILE(0, 10, Fw::String("file.prm"), PrmDb_Merge::MERGE);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
// Verify appropriate error response
|
||||
ASSERT_CMD_RESPONSE_SIZE(1);
|
||||
ASSERT_CMD_RESPONSE(0, PrmDbImpl::OPCODE_PRM_LOAD_FILE, 10, Fw::CmdResponse::BUSY);
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction(0, PrmDbFileLoadState::LOADING_FILE_UPDATES,
|
||||
PrmDb_PrmLoadAction::LOAD_FILE_COMMAND);
|
||||
|
||||
// 1.2 Attempt PRM_SAVE_FILE during loading
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
this->sendCmd_PRM_SAVE_FILE(0, 11);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
// Verify appropriate error response
|
||||
ASSERT_CMD_RESPONSE_SIZE(1);
|
||||
ASSERT_CMD_RESPONSE(0, PrmDbImpl::OPCODE_PRM_SAVE_FILE, 11, Fw::CmdResponse::BUSY);
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction(0, PrmDbFileLoadState::LOADING_FILE_UPDATES,
|
||||
PrmDb_PrmLoadAction::SAVE_FILE_COMMAND);
|
||||
|
||||
// 1.3 Attempt to set parameter during loading
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
this->invoke_to_setPrm(0, testId, pBuff);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
// Verify appropriate error response (warning event only, no added event)
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction(0, PrmDbFileLoadState::LOADING_FILE_UPDATES,
|
||||
PrmDb_PrmLoadAction::SET_PARAMETER);
|
||||
ASSERT_EVENTS_PrmIdAdded_SIZE(0);
|
||||
ASSERT_EVENTS_PrmIdUpdated_SIZE(0);
|
||||
|
||||
// 1.4 Attempt PRM_COMMIT_STAGED during loading
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
this->sendCmd_PRM_COMMIT_STAGED(0, 12);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
// Verify appropriate error response
|
||||
ASSERT_CMD_RESPONSE_SIZE(1);
|
||||
ASSERT_CMD_RESPONSE(0, PrmDbImpl::OPCODE_PRM_COMMIT_STAGED, 12, Fw::CmdResponse::VALIDATION_ERROR);
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction(0, PrmDbFileLoadState::LOADING_FILE_UPDATES,
|
||||
PrmDb_PrmLoadAction::COMMIT_STAGED_COMMAND);
|
||||
|
||||
// Verify state hasn't changed
|
||||
EXPECT_EQ(this->m_impl.m_state, PrmDbFileLoadState::LOADING_FILE_UPDATES);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// 2. Test illegal operations in FILE_UPDATES_STAGED state
|
||||
// -------------------------------------------------------------------
|
||||
this->m_impl.m_state = PrmDbFileLoadState::FILE_UPDATES_STAGED;
|
||||
|
||||
// 2.1 Attempt PRM_LOAD_FILE when updates are staged
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
this->sendCmd_PRM_LOAD_FILE(0, 13, Fw::String("file.prm"), PrmDb_Merge::RESET);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
// Verify appropriate error response
|
||||
ASSERT_CMD_RESPONSE_SIZE(1);
|
||||
ASSERT_CMD_RESPONSE(0, PrmDbImpl::OPCODE_PRM_LOAD_FILE, 13, Fw::CmdResponse::BUSY);
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction(0, PrmDbFileLoadState::FILE_UPDATES_STAGED,
|
||||
PrmDb_PrmLoadAction::LOAD_FILE_COMMAND);
|
||||
|
||||
// 2.2 Attempt PRM_SAVE_FILE when updates are staged
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
this->sendCmd_PRM_SAVE_FILE(0, 14);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
// Verify appropriate error response
|
||||
ASSERT_CMD_RESPONSE_SIZE(1);
|
||||
ASSERT_CMD_RESPONSE(0, PrmDbImpl::OPCODE_PRM_SAVE_FILE, 14, Fw::CmdResponse::BUSY);
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction(0, PrmDbFileLoadState::FILE_UPDATES_STAGED,
|
||||
PrmDb_PrmLoadAction::SAVE_FILE_COMMAND);
|
||||
|
||||
// 2.3 Attempt to set parameter when updates are staged
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
this->invoke_to_setPrm(0, testId, pBuff);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
// Verify appropriate error response (warning event only, no added event)
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction(0, PrmDbFileLoadState::FILE_UPDATES_STAGED,
|
||||
PrmDb_PrmLoadAction::SET_PARAMETER);
|
||||
ASSERT_EVENTS_PrmIdAdded_SIZE(0);
|
||||
ASSERT_EVENTS_PrmIdUpdated_SIZE(0);
|
||||
|
||||
// Verify state hasn't changed
|
||||
EXPECT_EQ(this->m_impl.m_state, PrmDbFileLoadState::FILE_UPDATES_STAGED);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// 3. Test illegal operations in IDLE state
|
||||
// -------------------------------------------------------------------
|
||||
this->m_impl.m_state = PrmDbFileLoadState::IDLE;
|
||||
|
||||
// 3.1 Attempt PRM_COMMIT_STAGED in IDLE state
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
this->sendCmd_PRM_COMMIT_STAGED(0, 15);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
// Verify appropriate error response
|
||||
ASSERT_CMD_RESPONSE_SIZE(1);
|
||||
ASSERT_CMD_RESPONSE(0, PrmDbImpl::OPCODE_PRM_COMMIT_STAGED, 15, Fw::CmdResponse::VALIDATION_ERROR);
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction_SIZE(1);
|
||||
ASSERT_EVENTS_PrmDbFileLoadInvalidAction(0, PrmDbFileLoadState::IDLE, PrmDb_PrmLoadAction::COMMIT_STAGED_COMMAND);
|
||||
|
||||
// Verify state hasn't changed
|
||||
EXPECT_EQ(this->m_impl.m_state, PrmDbFileLoadState::IDLE);
|
||||
|
||||
// 3.2 Verify legal operations are still allowed in IDLE state
|
||||
// Setting a parameter should work in IDLE state
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
this->invoke_to_setPrm(0, testId, pBuff);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
// Verify parameter was added
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmIdAdded_SIZE(1);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// 4. Test state transitions back to IDLE after errors
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// 4.1 Test that failed file load sets state back to IDLE
|
||||
this->m_impl.m_state = PrmDbFileLoadState::LOADING_FILE_UPDATES;
|
||||
this->m_impl.clearDb(PrmDbType::DB_STAGING);
|
||||
|
||||
// Simulate failed file load
|
||||
this->m_impl.m_state = PrmDbFileLoadState::IDLE;
|
||||
|
||||
// Verify that setPrm now works
|
||||
this->clearEvents();
|
||||
this->clearHistory();
|
||||
this->invoke_to_setPrm(0, testId + 1, pBuff);
|
||||
dispatchStatus = this->m_impl.doDispatch();
|
||||
EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK);
|
||||
|
||||
// Verify parameter was added
|
||||
ASSERT_EVENTS_SIZE(1);
|
||||
ASSERT_EVENTS_PrmIdAdded_SIZE(1);
|
||||
}
|
||||
|
||||
PrmDbTester* PrmDbTester::PrmDbTestFile::s_tester = nullptr;
|
||||
|
||||
void PrmDbTester::PrmDbTestFile::setTester(Svc::PrmDbTester* tester) {
|
||||
ASSERT_NE(tester, nullptr);
|
||||
s_tester = tester;
|
||||
}
|
||||
|
||||
Os::File::Status PrmDbTester::PrmDbTestFile::read(U8* buffer, FwSizeType& size, Os::File::WaitType wait) {
|
||||
EXPECT_NE(s_tester, nullptr);
|
||||
Os::File::Status status = this->Os::Stub::File::Test::TestFile::read(buffer, size, wait);
|
||||
if (s_tester->m_waits == 0) {
|
||||
switch (s_tester->m_errorType) {
|
||||
case FILE_STATUS_ERROR:
|
||||
status = s_tester->m_status;
|
||||
break;
|
||||
case FILE_SIZE_ERROR:
|
||||
size += 1;
|
||||
break;
|
||||
case FILE_DATA_ERROR:
|
||||
buffer[0] += 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
s_tester->m_waits -= 1;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
Os::File::Status PrmDbTester::PrmDbTestFile::write(const U8* buffer, FwSizeType& size, Os::File::WaitType wait) {
|
||||
EXPECT_NE(s_tester, nullptr);
|
||||
Os::File::Status status = this->Os::Stub::File::Test::TestFile::write(buffer, size, wait);
|
||||
if (s_tester->m_waits == 0) {
|
||||
switch (s_tester->m_errorType) {
|
||||
case FILE_STATUS_ERROR:
|
||||
status = s_tester->m_status;
|
||||
break;
|
||||
case FILE_SIZE_ERROR:
|
||||
size += 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
s_tester->m_waits -= 1;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
PrmDbTester::PrmDbTester(Svc::PrmDbImpl& inst) : PrmDbGTestBase("testerbase", 100), m_impl(inst) {
|
||||
PrmDbTester::PrmDbTestFile::setTester(this);
|
||||
}
|
||||
@ -611,6 +1346,25 @@ PrmDbTester::~PrmDbTester() {}
|
||||
void PrmDbTester ::from_pingOut_handler(const FwIndexType portNum, U32 key) {
|
||||
this->pushFromPortEntry_pingOut(key);
|
||||
}
|
||||
|
||||
void PrmDbTester::printDb(PrmDb_PrmDbType dbType) {
|
||||
PrmDbImpl::t_dbStruct* db = this->m_impl.getDbPtr(dbType);
|
||||
printf("%s Parameter DB @ %p \n", PrmDbImpl::getDbString(dbType).toChar(), static_cast<void*>(db));
|
||||
for (FwSizeType entry = 0; entry < PRMDB_NUM_DB_ENTRIES; entry++) {
|
||||
U8* data = db[entry].val.getBuffAddr();
|
||||
FwSizeType len = db[entry].val.getBuffLength();
|
||||
if (db[entry].used) {
|
||||
std::cout << " " << std::setw(2) << entry << " :";
|
||||
printf(" ID = %08X", db[entry].id);
|
||||
printf(" Value = ");
|
||||
for (FwSizeType i = 0; i < len; ++i) {
|
||||
printf("%02X ", data[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace Svc */
|
||||
|
||||
namespace Os {
|
||||
|
||||
@ -26,6 +26,12 @@ class PrmDbTester : public PrmDbGTestBase {
|
||||
void runMissingExtraParams();
|
||||
void runFileReadError();
|
||||
void runFileWriteError();
|
||||
void runDbEqualTest();
|
||||
void runDbCopyTest();
|
||||
void runDbCommitTest();
|
||||
void runPrmFileLoadNominal();
|
||||
void runPrmFileLoadWithErrors();
|
||||
void runPrmFileLoadIllegal();
|
||||
|
||||
void runRefPrmFile();
|
||||
|
||||
@ -67,6 +73,8 @@ class PrmDbTester : public PrmDbGTestBase {
|
||||
static void setTester(PrmDbTester* tester);
|
||||
static PrmDbTester* s_tester;
|
||||
};
|
||||
|
||||
void printDb(PrmDb_PrmDbType dbType);
|
||||
};
|
||||
|
||||
} // namespace Svc
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user