diff --git a/Svc/PrmDb/PrmDbImpl.cpp b/Svc/PrmDb/PrmDbImpl.cpp index 0d8114383d..bfdab664b2 100644 --- a/Svc/PrmDb/PrmDbImpl.cpp +++ b/Svc/PrmDb/PrmDbImpl.cpp @@ -205,11 +205,12 @@ void PrmDbImpl::PRM_SAVE_FILE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { crc = this->computeCrc(crc, &delim, sizeof(delim)); // serialize record size = id field + data - U32 recordSize = static_cast(sizeof(FwPrmIdType) + entry.getValue().getSize()); + FwSizeType recordSize = static_cast(sizeof(FwPrmIdType) + entry.getValue().getSize()); // reset buffer buff.resetSer(); - serStat = buff.serializeFrom(recordSize); + // Persist this field as FwSizeStoreType (via serializeSize) for canonical on-disk encoding. + Fw::SerializeStatus serStat = buff.serializeSize(recordSize); // should always work FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, static_cast(serStat)); @@ -222,7 +223,7 @@ void PrmDbImpl::PRM_SAVE_FILE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) { this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); return; } - if (writeSize != sizeof(recordSize)) { + if (writeSize != static_cast(sizeof(FwSizeStoreType))) { this->unLock(); this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::RECORD_SIZE_SIZE, static_cast(numRecords), static_cast(writeSize)); @@ -493,17 +494,17 @@ PrmDbImpl::PrmLoadStatus PrmDbImpl::readParamFileImpl(const Fw::StringBase& file return PrmLoadStatus::ERROR; } - U32 recordSize = 0; + FwSizeType recordSize = 0; - // read record size - readSize = sizeof(recordSize); + // read canonical record size field + readSize = static_cast(sizeof(FwSizeStoreType)); 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(recordNumTotal), fStat); return PrmLoadStatus::ERROR; } - if (sizeof(recordSize) != readSize) { + if (static_cast(sizeof(FwSizeStoreType)) != readSize) { this->log_WARNING_HI_PrmFileReadError(PrmReadError::RECORD_SIZE_SIZE, static_cast(recordNumTotal), static_cast(readSize)); return PrmLoadStatus::ERROR; @@ -515,12 +516,13 @@ PrmDbImpl::PrmLoadStatus PrmDbImpl::readParamFileImpl(const Fw::StringBase& file // reset deserialization buff.resetDeser(); // deserialize, since record size is serialized in file - desStat = buff.deserializeTo(recordSize); + desStat = buff.deserializeSize(recordSize); FW_ASSERT(Fw::FW_SERIALIZE_OK == desStat); // 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))) { + if ((recordSize > FW_PARAM_BUFFER_MAX_SIZE + sizeof(FwPrmIdType)) or + (recordSize < static_cast(sizeof(FwPrmIdType)))) { this->log_WARNING_HI_PrmFileReadError(PrmReadError::RECORD_SIZE_VALUE, static_cast(recordNumTotal), static_cast(recordSize)); return PrmLoadStatus::ERROR; diff --git a/Svc/PrmDb/test/ut/PrmDbTestMain.cpp b/Svc/PrmDb/test/ut/PrmDbTestMain.cpp index 440031277f..34e91a729c 100644 --- a/Svc/PrmDb/test/ut/PrmDbTestMain.cpp +++ b/Svc/PrmDb/test/ut/PrmDbTestMain.cpp @@ -271,6 +271,27 @@ TEST(ParameterDbTest, PrmFileLoadIllegalActions) { tester.runPrmFileLoadIllegal(); } +#if FW_HAS_16_BIT == 1 +TEST(ParameterDbTest, PrmFileLoad16BitRoundTrip) { + TEST_CASE(105.1.4, "16-bit file load/save round trip"); + COMMENT("Verify parameter database file format round-trips a 16-bit parameter value and canonical size field."); + + Svc::PrmDbImpl impl("PrmDbImpl"); + + impl.init(10, 0); + impl.configure("TestFile.prm"); + + Svc::PrmDbTester tester(impl); + + tester.init(); + + // connect ports + connectPorts(impl, tester); + + tester.runPrmFileLoad16BitRoundTrip(); +} +#endif + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/Svc/PrmDb/test/ut/PrmDbTester.cpp b/Svc/PrmDb/test/ut/PrmDbTester.cpp index f13ed6b257..01c2f1398b 100644 --- a/Svc/PrmDb/test/ut/PrmDbTester.cpp +++ b/Svc/PrmDb/test/ut/PrmDbTester.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -139,6 +140,97 @@ void PrmDbTester::runNominalSaveFile() { ASSERT_EVENTS_PrmFileSaveComplete(0, 2); } +#if FW_HAS_16_BIT == 1 +void PrmDbTester::runPrmFileLoad16BitRoundTrip() { + // Populate the database with a 16-bit payload to exercise the size-field serialization path. + this->m_impl.clearDb(PrmDbType::DB_ACTIVE); + this->m_impl.clearDb(PrmDbType::DB_STAGING); + + Os::Stub::File::Test::StaticData::setWriteResult(m_io_data, sizeof m_io_data); + Os::Stub::File::Test::StaticData::setNextStatus(Os::File::OP_OK); + + const U16 value = static_cast(0x1234); + const FwPrmIdType id = static_cast(0x42); + + Fw::ParamBuffer pBuff; + Fw::SerializeStatus stat = pBuff.serializeFrom(value); + EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat); + + this->clearEvents(); + this->clearHistory(); + this->invoke_to_setPrm(0, id, pBuff); + Fw::QueuedComponentBase::MsgDispatchStatus dispatchStatus = this->m_impl.doDispatch(); + EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK); + + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_PrmIdAdded_SIZE(1); + ASSERT_EVENTS_PrmIdAdded(0, id); + + // Save the database to disk so we can validate the serialized file layout. + Os::Stub::File::Test::StaticData::setWriteResult(m_io_data, sizeof m_io_data); + Os::Stub::File::Test::StaticData::setNextStatus(Os::File::OP_OK); + + this->clearEvents(); + this->clearHistory(); + this->sendCmd_PRM_SAVE_FILE(0, 12); + dispatchStatus = this->m_impl.doDispatch(); + EXPECT_EQ(dispatchStatus, Fw::QueuedComponentBase::MSG_DISPATCH_OK); + + ASSERT_CMD_RESPONSE_SIZE(1); + ASSERT_CMD_RESPONSE(0, PrmDbImpl::OPCODE_PRM_SAVE_FILE, 12, Fw::CmdResponse::OK); + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_PrmFileSaveComplete_SIZE(1); + ASSERT_EVENTS_PrmFileSaveComplete(0, 1); + + // Verify the on-disk layout is canonical and can be parsed independently of the host type sizes. + Fw::ExternalSerializeBuffer fileBuff(m_io_data, + static_cast(Os::Stub::File::Test::StaticData::data.pointer)); + fileBuff.resetDeser(); + + U32 crc = 0; + stat = fileBuff.deserializeTo(crc); + EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat); + + U8 delim = 0; + stat = fileBuff.deserializeTo(delim); + EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat); + EXPECT_EQ(PRMDB_ENTRY_DELIMITER, delim); + + FwSizeType recordSize = 0; + stat = fileBuff.deserializeSize(recordSize); + EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat); + EXPECT_EQ(recordSize, static_cast(sizeof(FwPrmIdType) + sizeof(U16))); + + FwPrmIdType decodedId = 0; + stat = fileBuff.deserializeTo(decodedId); + EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat); + EXPECT_EQ(id, decodedId); + + U16 decodedValue = 0; + stat = fileBuff.deserializeTo(decodedValue); + EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat); + EXPECT_EQ(value, decodedValue); + + // Re-load the saved file and verify that the 16-bit parameter round-trips successfully. + 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->m_impl.readParamFile(); + + ASSERT_EVENTS_SIZE(1); + ASSERT_EVENTS_PrmFileLoadComplete_SIZE(1); + ASSERT_EVENTS_PrmFileLoadComplete(0, "ACTIVE", 1, 1, 0); + + pBuff.resetSer(); + this->invoke_to_getPrm(0, id, pBuff); + U16 verifyValue = 0; + stat = pBuff.deserializeTo(verifyValue); + EXPECT_EQ(Fw::FW_SERIALIZE_OK, stat); + EXPECT_EQ(value, verifyValue); +} +#endif + void PrmDbTester::runNominalLoadFile() { // Preconditions to populate the write file this->runNominalSaveFile(); @@ -370,11 +462,11 @@ void PrmDbTester::runFileReadError() { break; case 2: ASSERT_EVENTS_PrmFileReadError_SIZE(1); - ASSERT_EVENTS_PrmFileReadError(0, PrmReadError::RECORD_SIZE_SIZE, 0, sizeof(U32) + 1); + ASSERT_EVENTS_PrmFileReadError(0, PrmReadError::RECORD_SIZE_SIZE, 0, sizeof(FwSizeStoreType) + 1); break; case 3: ASSERT_EVENTS_PrmFileReadError_SIZE(1); - ASSERT_EVENTS_PrmFileReadError(0, PrmReadError::PARAMETER_ID_SIZE, 0, sizeof(FwPrmIdType) + 1); + ASSERT_EVENTS_PrmFileReadError(0, PrmReadError::RECORD_SIZE_SIZE, 0, sizeof(FwSizeStoreType) + 1); break; case 4: ASSERT_EVENTS_PrmFileReadError_SIZE(1); @@ -460,9 +552,9 @@ void PrmDbTester::runFileReadError() { break; case 2: { // Data in this test is corrupted by adding 1 to the first data byte read. Since data is stored in - // big-endian format the highest order byte of the record size (U32) must have one added to it. - // Expected result of '8' inherited from original design of test. - U32 expected_error_value = sizeof(FwPrmIdType) + 4 + (1 << ((sizeof(U32) - 1) * 8)); + // big-endian format the highest order byte of the record size field must have one added to it. + FwSizeType expected_error_value = static_cast(sizeof(FwPrmIdType) + 4) + + (static_cast(1) << ((sizeof(FwSizeStoreType) - 1) * 8)); ASSERT_EVENTS_PrmFileReadError_SIZE(1); ASSERT_EVENTS_PrmFileReadError(0, PrmReadError::RECORD_SIZE_VALUE, 0, expected_error_value); break; @@ -516,7 +608,7 @@ void PrmDbTester::runFileWriteError() { break; case 1: ASSERT_EVENTS_PrmFileWriteError_SIZE(1); - ASSERT_EVENTS_PrmFileWriteError(0, PrmWriteError::RECORD_SIZE_SIZE, 0, sizeof(U32) + 1); + ASSERT_EVENTS_PrmFileWriteError(0, PrmWriteError::RECORD_SIZE_SIZE, 0, sizeof(FwSizeStoreType) + 1); break; case 2: ASSERT_EVENTS_PrmFileWriteError_SIZE(1); diff --git a/Svc/PrmDb/test/ut/PrmDbTester.hpp b/Svc/PrmDb/test/ut/PrmDbTester.hpp index 5077fdd933..f787fedca3 100644 --- a/Svc/PrmDb/test/ut/PrmDbTester.hpp +++ b/Svc/PrmDb/test/ut/PrmDbTester.hpp @@ -32,6 +32,9 @@ class PrmDbTester : public PrmDbGTestBase { void runPrmFileLoadNominal(); void runPrmFileLoadWithErrors(); void runPrmFileLoadIllegal(); +#if FW_HAS_16_BIT == 1 + void runPrmFileLoad16BitRoundTrip(); +#endif void runRefPrmFile();