GCC Code Coverage Report


Directory: ./
File: Svc/PrmDb/PrmDbImpl.cpp
Date: 2026-10-14 22:11:56
Exec Total Coverage
Lines: 172 327 52.6%
Functions: 18 20 90.0%
Branches: 120 322 37.3%

Line Branch Exec Source
1 /*
2 * PrmDbImpl.cpp
3 *
4 * Created on: March 9, 2015
5 * Author: Timothy Canham
6 */
7
8 #include <Fw/Types/Assert.hpp>
9 #include <Svc/PrmDb/PrmDbImpl.hpp>
10
11 #include <Os/File.hpp>
12 #include <Utils/Hash/Hash.hpp>
13
14 #include <cstdio>
15 #include <cstring>
16
17 static_assert(std::numeric_limits<FwSizeType>::max() >= PRMDB_NUM_DB_ENTRIES,
18 "PRMDB_NUM_DB_ENTRIES must fit within range of FwSizeType");
19
20 namespace Svc {
21
22 // anonymous namespace for buffer declaration
23 namespace {
24 class WorkingBuffer : public Fw::LinearBufferBase {
25 public:
26 2 WorkingBuffer() : Fw::LinearBufferBase(m_buff, sizeof(m_buff)) {}
27
28 private:
29 // Set to max of parameter buffer + id
30 U8 m_buff[FW_PARAM_BUFFER_MAX_SIZE + sizeof(FwPrmIdType)];
31 static_assert(sizeof(m_buff) >= sizeof(U32), "Size of parameter buffer storage must be >= sizeof(U32)");
32 };
33 } // namespace
34
35 //! ----------------------------------------------------------------------
36 //! Construction, initialization, and destruction
37 //! ----------------------------------------------------------------------
38
5/5
✓ Branch 2 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 8 taken 1 times.
✓ Branch 11 taken 1 times.
✓ Branch 14 taken 1 times.
1 PrmDbImpl::PrmDbImpl(const char* name) : PrmDbComponentBase(name), m_state(PrmDbFileLoadState::IDLE) {
39 1 this->m_activeDb = &this->m_dbStore1;
40 1 this->m_stagingDb = &this->m_dbStore2;
41
42
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->clearDb(PrmDbType::DB_ACTIVE);
43
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->clearDb(PrmDbType::DB_STAGING);
44 1 }
45
46 2 PrmDbImpl::~PrmDbImpl() {}
47
48 1 void PrmDbImpl::configure(const char* file) {
49 1 FW_ASSERT(file != nullptr);
50 1 this->m_fileName = file;
51 1 }
52
53 2 void PrmDbImpl::configureSandbox(const char* directory) {
54 2 FW_ASSERT(directory != nullptr);
55 2 this->m_sandboxDir = directory;
56 2 }
57
58 4 void PrmDbImpl::applySandbox(Os::SandboxedFile& file) const {
59 // Left unconfigured (fail-closed) when configureSandbox() was never called
60
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if (this->m_sandboxDir.length() > 0) {
61 4 file.configure(this->m_sandboxDir.toChar());
62 }
63 4 }
64
65 1 void PrmDbImpl::readParamFile() {
66 // Assumed to run at initialization time
67 // State should be IDLE upon entry
68 1 FW_ASSERT(static_cast<FwAssertArgType>(m_state == PrmDbFileLoadState::IDLE));
69
70 // Clear databases
71
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->clearDb(PrmDbType::DB_ACTIVE);
72
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->clearDb(PrmDbType::DB_STAGING);
73
74 // Read parameter file to active database
75
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 (void)readParamFileImpl(this->m_fileName, PrmDbType::DB_ACTIVE);
76 1 }
77
78 //! ----------------------------------------------------------------------
79 //! Port & Command Handlers
80 //! ----------------------------------------------------------------------
81
82 // If ports are no longer guarded, these accesses need to be protected from each other
83 // If there are a lot of accesses, perhaps an interrupt lock could be used instead of guarded ports
84
85 12 Fw::ParamValid PrmDbImpl::getPrm_handler(FwIndexType portNum, FwPrmIdType id, Fw::ParamBuffer& val) {
86 // search for entry
87
1/1
✓ Branch 1 taken 12 times.
12 auto success = this->m_activeDb->find(id, val);
88
89
1/3
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
12 switch (success.e) {
90 12 case Fw::Success::FAILURE:
91 // if unable to find parameter, send error message
92
1/1
✓ Branch 1 taken 12 times.
12 this->log_WARNING_LO_PrmIdNotFound(id);
93
1/1
✓ Branch 1 taken 12 times.
12 return Fw::ParamValid::INVALID;
94 ✗ case Fw::Success::SUCCESS:
95 ✗ return Fw::ParamValid::VALID;
96 ✗ default:
97 ✗ FW_ASSERT(false, success.e);
98 ✗ return Fw::ParamValid::INVALID;
99 }
100 12 }
101
102 4 void PrmDbImpl::setPrm_handler(FwIndexType portNum, FwPrmIdType id, Fw::ParamBuffer& val) {
103 // Reject parameter updates during non-idle file load states
104
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (m_state != PrmDbFileLoadState::IDLE) {
105 ✗ this->log_WARNING_LO_PrmDbFileLoadInvalidAction(m_state, PrmDb_PrmLoadAction::SET_PARAMETER);
106 ✗ return;
107 }
108
109 // Update the parameter in the active database
110
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
4 PrmUpdateType update_status = updateAddPrmImpl(id, val, PrmDbType::DB_ACTIVE);
111
112 // Issue relevant EVR
113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (update_status == PARAM_UPDATED) {
114 ✗ this->log_ACTIVITY_HI_PrmIdUpdated(id);
115
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 } else if (update_status == NO_SLOTS) {
116 ✗ this->log_WARNING_HI_PrmDbFull(id);
117 } else {
118 4 this->log_ACTIVITY_HI_PrmIdAdded(id);
119 }
120 }
121
122 62 void PrmDbImpl::pingIn_handler(FwIndexType portNum, U32 key) {
123 // respond to ping
124 62 this->pingOut_out(0, key);
125 62 }
126
127 1 void PrmDbImpl::PRM_SAVE_FILE_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
128 // Reject PRM_SAVE_FILE command during non-idle file load states
129
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (m_state != PrmDbFileLoadState::IDLE) {
130 ✗ this->log_WARNING_LO_PrmDbFileLoadInvalidAction(m_state, PrmDb_PrmLoadAction::SAVE_FILE_COMMAND);
131 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::BUSY);
132 ✗ return;
133 }
134
135 1 FW_ASSERT(this->m_fileName.length() > 0);
136
137
1/1
✓ Branch 1 taken 1 times.
1 Os::SandboxedFile paramFile;
138
1/1
✓ Branch 1 taken 1 times.
1 this->applySandbox(paramFile);
139
1/1
✓ Branch 1 taken 1 times.
1 WorkingBuffer buff;
140
141
1/1
✓ Branch 2 taken 1 times.
1 Os::File::Status stat = paramFile.open(this->m_fileName.toChar(), Os::File::OPEN_WRITE, Os::File::OVERWRITE);
142
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stat != Os::File::OP_OK) {
143 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::OPEN, 0, stat);
144 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
145 ✗ return;
146 }
147
148 // write placeholder for the CRC
149
1/1
✓ Branch 1 taken 1 times.
1 Utils::Hash crc;
150 1 U32 crcInitial = 0xFFFFFFFF;
151
1/1
✓ Branch 1 taken 1 times.
1 buff.resetSer();
152
1/1
✓ Branch 1 taken 1 times.
1 Fw::SerializeStatus serStat = buff.serializeFrom(crcInitial);
153 1 FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, static_cast<FwAssertArgType>(serStat));
154
1/1
✓ Branch 1 taken 1 times.
1 FwSizeType writeSize = static_cast<FwSizeType>(buff.getSize());
155
1/1
✓ Branch 2 taken 1 times.
1 stat = paramFile.write(buff.getBuffAddr(), writeSize, Os::File::WaitType::WAIT);
156
157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stat != Os::File::OP_OK) {
158 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::CRC_PLACE, 0, stat);
159 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
160 ✗ return;
161 }
162
163
1/1
✓ Branch 1 taken 1 times.
1 this->lock();
164
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 auto db = getDbPtr(PrmDbType::DB_ACTIVE);
165 1 FW_ASSERT(db != nullptr);
166
167 // Traverse the parameter list, saving each entry
168
169 1 U32 numRecords = 0;
170
171
4/6
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 for (const auto& entry : *db) {
172 // write delimiter
173 static const U8 delim = PRMDB_ENTRY_DELIMITER;
174 ✗ if (!this->writeSaveFileChunk(paramFile, &delim, sizeof(delim), PrmWriteError::DELIMITER,
175 PrmWriteError::DELIMITER_SIZE, numRecords, opCode, cmdSeq, crc)) {
176 ✗ return;
177 }
178
179 // serialize record size = id field + data
180 ✗ U32 recordSize = static_cast<U32>(sizeof(FwPrmIdType) + entry.getValue().getSize());
181
182 // reset buffer
183 ✗ buff.resetSer();
184 ✗ serStat = buff.serializeFrom(recordSize);
185 // should always work
186 ✗ FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, static_cast<FwAssertArgType>(serStat));
187
188 // write record size
189 ✗ if (!this->writeSaveFileChunk(paramFile, buff.getBuffAddr(), buff.getSize(), PrmWriteError::RECORD_SIZE,
190 PrmWriteError::RECORD_SIZE_SIZE, numRecords, opCode, cmdSeq, crc)) {
191 ✗ return;
192 }
193
194 // reset buffer
195 ✗ buff.resetSer();
196
197 // serialize parameter id
198
199 ✗ serStat = buff.serializeFrom(entry.getKey());
200 // should always work
201 ✗ FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, static_cast<FwAssertArgType>(serStat));
202
203 // write parameter ID
204 ✗ if (!this->writeSaveFileChunk(paramFile, buff.getBuffAddr(), buff.getSize(), PrmWriteError::PARAMETER_ID,
205 PrmWriteError::PARAMETER_ID_SIZE, numRecords, opCode, cmdSeq, crc)) {
206 ✗ return;
207 }
208
209 // write serialized parameter value
210 ✗ if (!this->writeSaveFileChunk(paramFile, entry.getValue().getBuffAddr(), entry.getValue().getSize(),
211 PrmWriteError::PARAMETER_VALUE, PrmWriteError::PARAMETER_VALUE_SIZE, numRecords,
212 opCode, cmdSeq, crc)) {
213 ✗ return;
214 }
215
216 ✗ numRecords++;
217 1 }
218
219
1/1
✓ Branch 1 taken 1 times.
1 this->unLock();
220
221 // save current location of pointer in paramFile
222 FwSizeType currPosInParamFile;
223
224
1/1
✓ Branch 1 taken 1 times.
1 stat = paramFile.position(currPosInParamFile);
225
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stat != Os::File::OP_OK) {
226 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::CURR_POSITION, 0, stat);
227 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
228 ✗ return;
229 }
230
231 // seek to beginning and write CRC value
232
1/1
✓ Branch 1 taken 1 times.
1 stat = paramFile.seek(0, Os::File::SeekType::ABSOLUTE);
233
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stat != Os::File::OP_OK) {
234 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::SEEK_ZERO, 0, stat);
235 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
236 ✗ return;
237 }
238
1/1
✓ Branch 1 taken 1 times.
1 buff.resetSer();
239 1 U32 crcFinal = 0;
240
1/1
✓ Branch 1 taken 1 times.
1 crc.finalize(crcFinal);
241 1 crcFinal = ~crcFinal;
242
1/1
✓ Branch 1 taken 1 times.
1 serStat = buff.serializeFrom(crcFinal);
243
244 1 FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, static_cast<FwAssertArgType>(serStat));
245
1/1
✓ Branch 1 taken 1 times.
1 writeSize = static_cast<FwSizeType>(buff.getSize());
246
247
1/1
✓ Branch 2 taken 1 times.
1 stat = paramFile.write(buff.getBuffAddr(), writeSize, Os::File::WaitType::WAIT);
248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stat != Os::File::OP_OK) {
249 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::CRC_REAL, 0, stat);
250 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
251 ✗ return;
252 }
253
254 // Restore pointer to previously saved location
255
1/1
✓ Branch 1 taken 1 times.
1 stat = paramFile.seek(static_cast<FwSignedSizeType>(currPosInParamFile), Os::File::SeekType::ABSOLUTE);
256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stat != Os::File::OP_OK) {
257 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::SEEK_POSITION, 0, stat);
258 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
259 ✗ return;
260 }
261
262
1/1
✓ Branch 1 taken 1 times.
1 this->log_ACTIVITY_HI_PrmFileSaveComplete(numRecords);
263
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
264 1 }
265
266 ✗ bool PrmDbImpl::writeSaveFileChunk(Os::SandboxedFile& paramFile,
267 const U8* data,
268 FwSizeType size,
269 PrmWriteError::T statusStage,
270 PrmWriteError::T sizeStage,
271 U32 numRecords,
272 FwOpcodeType opCode,
273 U32 cmdSeq,
274 Utils::Hash& crc) {
275 ✗ FwSizeType writeSize = size;
276 ✗ Os::File::Status stat = paramFile.write(data, writeSize, Os::File::WaitType::WAIT);
277 ✗ if (stat != Os::File::OP_OK) {
278 ✗ this->unLock();
279 ✗ this->log_WARNING_HI_PrmFileWriteError(statusStage, static_cast<I32>(numRecords), stat);
280 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
281 ✗ return false;
282 }
283 ✗ if (writeSize != size) {
284 ✗ this->unLock();
285 ✗ this->log_WARNING_HI_PrmFileWriteError(sizeStage, static_cast<I32>(numRecords), static_cast<I32>(writeSize));
286 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
287 ✗ return false;
288 }
289 ✗ if (data != nullptr && writeSize != 0) {
290 ✗ crc.update(data, writeSize);
291 }
292 ✗ return true;
293 }
294
295 2 void PrmDbImpl::PRM_LOAD_FILE_cmdHandler(FwOpcodeType opCode,
296 U32 cmdSeq,
297 const Fw::CmdStringArg& fileName,
298 const PrmDb_Merge& merge) {
299 // Reject PRM_LOAD_FILE command during non-idle file load states
300
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (m_state != PrmDbFileLoadState::IDLE) {
301 ✗ this->log_WARNING_LO_PrmDbFileLoadInvalidAction(m_state, PrmDb_PrmLoadAction::LOAD_FILE_COMMAND);
302 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::BUSY);
303 ✗ return;
304 }
305
306 // Reject an empty file name before touching the staging database
307
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (fileName.length() == 0) {
308 ✗ this->log_WARNING_HI_PrmDbFileLoadFailed();
309 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
310 ✗ return;
311 }
312
313 // Set state to loading
314 2 m_state = PrmDbFileLoadState::LOADING_FILE_UPDATES;
315
316 // If reset is true, clear the staging database first
317
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (merge == PrmDb_Merge::MERGE) {
318 // Copy active to staging for merging
319 ✗ dbCopy(PrmDbType::DB_STAGING, PrmDbType::DB_ACTIVE);
320 } else {
321 // reset staging db, all file contents will be loaded but no old parameters will be retained
322
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 this->clearDb(PrmDbType::DB_STAGING);
323 }
324
325 // Load the file into staging database
326 // The readParamFileImpl will emit the relevant EVR if the file load fails
327 // and also if it succeeds will emit EVRs with the number of records
328
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 PrmDbImpl::PrmLoadStatus success = PrmDbImpl::readParamFileImpl(fileName, PrmDbType::DB_STAGING);
329
330
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (success == PrmLoadStatus::SUCCESS) {
331
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
332 1 m_state = PrmDbFileLoadState::FILE_UPDATES_STAGED;
333 } else {
334 1 this->log_WARNING_HI_PrmDbFileLoadFailed();
335 // clear the staging DB and reset to an IDLE state in case of issues
336
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->clearDb(PrmDbType::DB_STAGING);
337 1 m_state = PrmDbFileLoadState::IDLE;
338
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
339 }
340 }
341
342 1 void PrmDbImpl::PRM_COMMIT_STAGED_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
343 // Verify we are in the correct state
344
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (m_state != PrmDbFileLoadState::FILE_UPDATES_STAGED) {
345 ✗ this->log_WARNING_LO_PrmDbFileLoadInvalidAction(m_state, PrmDb_PrmLoadAction::COMMIT_STAGED_COMMAND);
346 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
347 ✗ return;
348 }
349
350 // Swap active and staging databases, safely w.r.t. prmGet
351 1 this->lock();
352 1 PrmDbStore* temp = this->m_activeDb;
353 1 this->m_activeDb = this->m_stagingDb;
354 1 this->unLock();
355 1 this->m_stagingDb = temp;
356
357 // Clear the new staging database
358
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->clearDb(PrmDbType::DB_STAGING);
359
360 // Set file load state to idle
361 1 m_state = PrmDbFileLoadState::IDLE;
362
363 1 this->log_ACTIVITY_HI_PrmDbCommitComplete();
364
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
365 }
366
367 //! ----------------------------------------------------------------------
368 //! Helpers for construction/destruction, init, & handlers
369 //! ----------------------------------------------------------------------
370
371 3 PrmDbImpl::PrmLoadStatus PrmDbImpl::readParamFileImpl(const Fw::StringBase& fileName, PrmDbType dbType) {
372 3 FW_ASSERT(dbType == PrmDbType::DB_ACTIVE or dbType == PrmDbType::DB_STAGING);
373 3 FW_ASSERT(fileName.length() > 0);
374
375
2/2
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 3 times.
3 Fw::String dbString = getDbString(dbType);
376
377
1/1
✓ Branch 1 taken 3 times.
3 Os::SandboxedFile paramFile;
378
1/1
✓ Branch 1 taken 3 times.
3 this->applySandbox(paramFile);
379
380
2/2
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 3 times.
3 Os::File::Status stat = paramFile.open(fileName.toChar(), Os::File::OPEN_READ);
381
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (stat != Os::File::OP_OK) {
382
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 this->log_WARNING_HI_PrmFileReadError(PrmReadError::OPEN, 0, stat);
383 2 return PrmLoadStatus::ERROR;
384 }
385 //===========================================================================
386 // read CRC from beginning of file
387
1/1
✓ Branch 1 taken 1 times.
1 WorkingBuffer buff;
388 U32 fileCrc;
389 1 FwSizeType readSize = static_cast<FwSizeType>(sizeof(fileCrc));
390
391 // Read raw CRC bytes from file
392
1/1
✓ Branch 2 taken 1 times.
1 stat = paramFile.read(buff.getBuffAddr(), readSize);
393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stat != Os::File::OP_OK) {
394 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::CRC, static_cast<I32>(0), stat);
395 ✗ return PrmLoadStatus::ERROR;
396 }
397
398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (readSize != sizeof(fileCrc)) {
399 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::CRC_SIZE, static_cast<I32>(0), static_cast<I32>(readSize));
400 ✗ return PrmLoadStatus::ERROR;
401 }
402
403 // Deserialize the CRC in a portable way
404
1/1
✓ Branch 1 taken 1 times.
1 Fw::SerializeStatus serStat = buff.setBuffLen(readSize);
405 1 FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, static_cast<FwAssertArgType>(serStat));
406
1/1
✓ Branch 1 taken 1 times.
1 buff.resetDeser();
407
1/1
✓ Branch 1 taken 1 times.
1 serStat = buff.deserializeTo(fileCrc);
408 1 FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, static_cast<FwAssertArgType>(serStat));
409
410 1 U32 crc = 0xFFFFFFFF;
411 // read into CRC buffer for checking
412
413
1/1
✓ Branch 1 taken 1 times.
1 Os::File::Status status = paramFile.calculateCrc(crc);
414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (status != Os::File::OP_OK) {
415 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::CRC_BUFFER, static_cast<I32>(0), status);
416 ✗ return PrmLoadStatus::ERROR;
417 }
418
419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (fileCrc != crc) {
420 ✗ this->log_WARNING_HI_PrmFileBadCrc(fileCrc, crc);
421 ✗ return PrmLoadStatus::ERROR;
422 }
423
424 // seek back to just after CRC
425
1/1
✓ Branch 1 taken 1 times.
1 stat = paramFile.seek(sizeof(fileCrc), Os::File::SeekType::ABSOLUTE);
426
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stat != Os::File::OP_OK) {
427 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::SEEK_ZERO, 0, stat);
428 ✗ return PrmLoadStatus::ERROR;
429 }
430 //===========================================================================
431
432 1 U32 recordNumTotal = 0;
433 1 U32 recordNumAdded = 0;
434 1 U32 recordNumUpdated = 0;
435 1 U32 recordNumDropped = 0;
436
437
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 for (FwSizeType entry = 0; entry < PRMDB_NUM_DB_ENTRIES; entry++) {
438 U8 delimiter;
439 1 readSize = static_cast<FwSizeType>(sizeof(delimiter));
440
441 // read delimiter
442
1/1
✓ Branch 1 taken 1 times.
1 Os::File::Status fStat = paramFile.read(&delimiter, readSize, Os::File::WaitType::WAIT);
443
444 // check for end of file (successful read of size 0); a failed read can
445 // also yield size 0 and must not be mistaken for a clean EOF
446
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if ((Os::File::OP_OK == fStat) && (0 == readSize)) {
447 1 break;
448 }
449
450 ✗ if (fStat != Os::File::OP_OK) {
451 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::DELIMITER, static_cast<I32>(recordNumTotal), fStat);
452 ✗ return PrmLoadStatus::ERROR;
453 }
454
455 ✗ if (sizeof(delimiter) != readSize) {
456 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::DELIMITER_SIZE, static_cast<I32>(recordNumTotal),
457 static_cast<I32>(readSize));
458 ✗ return PrmLoadStatus::ERROR;
459 }
460
461 ✗ if (PRMDB_ENTRY_DELIMITER != delimiter) {
462 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::DELIMITER_VALUE, static_cast<I32>(recordNumTotal),
463 delimiter);
464 ✗ return PrmLoadStatus::ERROR;
465 }
466
467 ✗ U32 recordSize = 0;
468
469 // read record size
470 ✗ readSize = sizeof(recordSize);
471
472 ✗ fStat = paramFile.read(buff.getBuffAddr(), readSize, Os::File::WaitType::WAIT);
473 ✗ if (fStat != Os::File::OP_OK) {
474 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::RECORD_SIZE, static_cast<I32>(recordNumTotal), fStat);
475 ✗ return PrmLoadStatus::ERROR;
476 }
477 ✗ if (sizeof(recordSize) != readSize) {
478 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::RECORD_SIZE_SIZE, static_cast<I32>(recordNumTotal),
479 static_cast<I32>(readSize));
480 ✗ return PrmLoadStatus::ERROR;
481 }
482 // set serialized size to read size
483 ✗ Fw::SerializeStatus desStat = buff.setBuffLen(static_cast<Fw::Serializable::SizeType>(readSize));
484 // should never fail
485 ✗ FW_ASSERT(Fw::FW_SERIALIZE_OK == desStat, static_cast<FwAssertArgType>(desStat));
486 // reset deserialization
487 ✗ buff.resetDeser();
488 // deserialize, since record size is serialized in file
489 ✗ desStat = buff.deserializeTo(recordSize);
490 ✗ FW_ASSERT(Fw::FW_SERIALIZE_OK == desStat);
491
492 // sanity check value. It can't be larger than the maximum parameter buffer size + id
493 // or smaller than the record id
494 ✗ if ((recordSize > FW_PARAM_BUFFER_MAX_SIZE + sizeof(FwPrmIdType)) or (recordSize < sizeof(FwPrmIdType))) {
495 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::RECORD_SIZE_VALUE, static_cast<I32>(recordNumTotal),
496 static_cast<I32>(recordSize));
497 ✗ return PrmLoadStatus::ERROR;
498 }
499
500 // read the parameter ID
501 ✗ FwPrmIdType parameterId = 0;
502 ✗ readSize = static_cast<FwSizeType>(sizeof(FwPrmIdType));
503
504 ✗ fStat = paramFile.read(buff.getBuffAddr(), readSize, Os::File::WaitType::WAIT);
505 ✗ if (fStat != Os::File::OP_OK) {
506 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_ID, static_cast<I32>(recordNumTotal), fStat);
507 ✗ return PrmLoadStatus::ERROR;
508 }
509 ✗ if (sizeof(parameterId) != static_cast<FwSizeType>(readSize)) {
510 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_ID_SIZE, static_cast<I32>(recordNumTotal),
511 static_cast<I32>(readSize));
512 ✗ return PrmLoadStatus::ERROR;
513 }
514
515 // set serialized size to read parameter ID
516 ✗ desStat = buff.setBuffLen(static_cast<Fw::Serializable::SizeType>(readSize));
517 // should never fail
518 ✗ FW_ASSERT(Fw::FW_SERIALIZE_OK == desStat, static_cast<FwAssertArgType>(desStat));
519 // reset deserialization
520 ✗ buff.resetDeser();
521 // deserialize, since parameter ID is serialized in file
522 ✗ desStat = buff.deserializeTo(parameterId);
523 ✗ FW_ASSERT(Fw::FW_SERIALIZE_OK == desStat);
524
525 // copy parameter value from file into a temporary buffer
526 ✗ Fw::ParamBuffer tmpParamBuffer; // temporary param buffer to read parameter value from file
527 ✗ readSize = recordSize - sizeof(parameterId);
528 ✗ desStat = tmpParamBuffer.setBuffLen(static_cast<Fw::Serializable::SizeType>(readSize));
529 ✗ FW_ASSERT(Fw::FW_SERIALIZE_OK == desStat, static_cast<FwAssertArgType>(desStat)); // should never fail
530 ✗ fStat = paramFile.read(tmpParamBuffer.getBuffAddr(), readSize);
531
532 ✗ if (fStat != Os::File::OP_OK) {
533 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_VALUE, static_cast<I32>(recordNumTotal),
534 fStat);
535 ✗ return PrmLoadStatus::ERROR;
536 }
537 ✗ if (static_cast<U32>(readSize) != recordSize - sizeof(parameterId)) {
538 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_VALUE_SIZE, static_cast<I32>(recordNumTotal),
539 static_cast<I32>(readSize));
540 ✗ return PrmLoadStatus::ERROR;
541 }
542
543 // Actually update or add parameter
544 ✗ PrmUpdateType updateStatus = updateAddPrmImpl(parameterId, tmpParamBuffer, dbType);
545 ✗ if (updateStatus == PARAM_ADDED) {
546 ✗ recordNumAdded++;
547 ✗ } else if (updateStatus == PARAM_UPDATED) {
548 ✗ recordNumUpdated++;
549 }
550
551 ✗ if (updateStatus == NO_SLOTS) {
552 ✗ this->log_WARNING_HI_PrmDbFull(parameterId);
553 ✗ recordNumDropped++;
554 }
555 ✗ recordNumTotal++;
556 ✗ }
557
558 // Dropped records mean the database does not reflect the file: report an error
559
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (recordNumDropped > 0) {
560 ✗ return PrmLoadStatus::ERROR;
561 }
562
563
1/1
✓ Branch 1 taken 1 times.
1 this->log_ACTIVITY_HI_PrmFileLoadComplete(dbString, recordNumTotal, recordNumAdded, recordNumUpdated);
564 1 return PrmLoadStatus::SUCCESS;
565 3 }
566
567 4 PrmDbImpl::PrmUpdateType PrmDbImpl::updateAddPrmImpl(FwPrmIdType id, Fw::ParamBuffer& val, PrmDbType prmDbType) {
568
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
4 auto* db = getDbPtr(prmDbType);
569
570 4 PrmUpdateType updateStatus = NO_SLOTS;
571
572 4 this->lock();
573
574 4 auto prevSize = db->getSize();
575
2/4
✓ Branch 1 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
4 switch (db->insert(id, val)) {
576 ✗ case Fw::Success::FAILURE:
577 ✗ updateStatus = NO_SLOTS;
578 ✗ break;
579 4 case Fw::Success::SUCCESS:
580
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if (prevSize < db->getSize()) {
581 4 updateStatus = PARAM_ADDED;
582 } else {
583 ✗ FW_ASSERT(prevSize == db->getSize(), static_cast<FwAssertArgType>(prevSize),
584 static_cast<FwAssertArgType>(db->getSize()));
585 ✗ updateStatus = PARAM_UPDATED;
586 }
587 4 break;
588 ✗ default:
589 ✗ FW_ASSERT(false);
590 }
591
592 4 this->unLock();
593 4 return updateStatus;
594 }
595
596 //! ----------------------------------------------------------------------
597 //! Helpers for database management
598 //! ----------------------------------------------------------------------
599
600 8 void PrmDbImpl::clearDb(PrmDbType prmDbType) {
601
3/3
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 7 taken 8 times.
8 getDbPtr(prmDbType)->clear();
602 8 }
603
604 ✗ void PrmDbImpl::dbCopy(PrmDbType dest, PrmDbType src) {
605 ✗ *getDbPtr(dest) = *getDbPtr(src);
606 ✗ this->log_ACTIVITY_HI_PrmDbCopyAllComplete(getDbString(src), getDbString(dest));
607 ✗ }
608
609 13 PrmDbImpl::PrmDbStore* PrmDbImpl::getDbPtr(PrmDbType dbType) {
610 13 FW_ASSERT(dbType == PrmDbType::DB_ACTIVE or dbType == PrmDbType::DB_STAGING);
611
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 6 times.
13 if (dbType == PrmDbType::DB_ACTIVE) {
612 7 return m_activeDb;
613 }
614 6 return m_stagingDb;
615 }
616
617 3 Fw::String PrmDbImpl::getDbString(PrmDbType dbType) {
618 3 FW_ASSERT(dbType == PrmDbType::DB_ACTIVE or dbType == PrmDbType::DB_STAGING);
619
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
3 if (dbType == PrmDbType::DB_ACTIVE) {
620 1 return Fw::String("ACTIVE");
621 }
622 2 return Fw::String("STAGING");
623 }
624
625 } // namespace Svc
626