GCC Code Coverage Report


Directory: ./
File: Svc/PrmDb/PrmDbImpl.cpp
Date: 2026-09-23 22:11:34
Exec Total Coverage
Lines: 172 358 48.0%
Functions: 18 19 94.7%
Branches: 120 377 31.8%

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 61 void PrmDbImpl::pingIn_handler(FwIndexType portNum, U32 key) {
123 // respond to ping
124 61 this->pingOut_out(0, key);
125 61 }
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 ✗ writeSize = static_cast<FwSizeType>(sizeof(delim));
175 ✗ stat = paramFile.write(&delim, writeSize, Os::File::WaitType::WAIT);
176 ✗ if (stat != Os::File::OP_OK) {
177 ✗ this->unLock();
178 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::DELIMITER, static_cast<I32>(numRecords), stat);
179 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
180 ✗ return;
181 }
182 ✗ if (writeSize != sizeof(delim)) {
183 ✗ this->unLock();
184 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::DELIMITER_SIZE, static_cast<I32>(numRecords),
185 static_cast<I32>(writeSize));
186 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
187 ✗ return;
188 }
189
190 // add delimiter to CRC
191 ✗ crc.update(&delim, sizeof(delim));
192
193 // serialize record size = id field + data
194 ✗ U32 recordSize = static_cast<U32>(sizeof(FwPrmIdType) + entry.getValue().getSize());
195
196 // reset buffer
197 ✗ buff.resetSer();
198 ✗ serStat = buff.serializeFrom(recordSize);
199 // should always work
200 ✗ FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, static_cast<FwAssertArgType>(serStat));
201
202 // write record size
203 ✗ writeSize = static_cast<FwSizeType>(buff.getSize());
204 ✗ stat = paramFile.write(buff.getBuffAddr(), writeSize, Os::File::WaitType::WAIT);
205 ✗ if (stat != Os::File::OP_OK) {
206 ✗ this->unLock();
207 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::RECORD_SIZE, static_cast<I32>(numRecords), stat);
208 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
209 ✗ return;
210 }
211 ✗ if (writeSize != sizeof(recordSize)) {
212 ✗ this->unLock();
213 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::RECORD_SIZE_SIZE, static_cast<I32>(numRecords),
214 static_cast<I32>(writeSize));
215 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
216 ✗ return;
217 }
218
219 // add recordSize to CRC
220 ✗ if (buff.getBuffAddr() != nullptr && writeSize != 0) {
221 ✗ crc.update(buff.getBuffAddr(), writeSize);
222 }
223
224 // reset buffer
225 ✗ buff.resetSer();
226
227 // serialize parameter id
228
229 ✗ serStat = buff.serializeFrom(entry.getKey());
230 // should always work
231 ✗ FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, static_cast<FwAssertArgType>(serStat));
232
233 // write parameter ID
234 ✗ writeSize = static_cast<FwSizeType>(buff.getSize());
235 ✗ stat = paramFile.write(buff.getBuffAddr(), writeSize, Os::File::WaitType::WAIT);
236 ✗ if (stat != Os::File::OP_OK) {
237 ✗ this->unLock();
238 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::PARAMETER_ID, static_cast<I32>(numRecords), stat);
239 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
240 ✗ return;
241 }
242 ✗ if (writeSize != static_cast<FwSizeType>(buff.getSize())) {
243 ✗ this->unLock();
244 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::PARAMETER_ID_SIZE, static_cast<I32>(numRecords),
245 static_cast<I32>(writeSize));
246 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
247 ✗ return;
248 }
249
250 // add parameter ID to CRC
251 ✗ if (buff.getBuffAddr() != nullptr && writeSize != 0) {
252 ✗ crc.update(buff.getBuffAddr(), writeSize);
253 }
254
255 // write serialized parameter value
256
257 ✗ writeSize = static_cast<FwSizeType>(entry.getValue().getSize());
258 ✗ stat = paramFile.write(entry.getValue().getBuffAddr(), writeSize, Os::File::WaitType::WAIT);
259 ✗ if (stat != Os::File::OP_OK) {
260 ✗ this->unLock();
261 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::PARAMETER_VALUE, static_cast<I32>(numRecords), stat);
262 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
263 ✗ return;
264 }
265 ✗ if (writeSize != static_cast<FwSizeType>(entry.getValue().getSize())) {
266 ✗ this->unLock();
267 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::PARAMETER_VALUE_SIZE, static_cast<I32>(numRecords),
268 static_cast<I32>(writeSize));
269 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
270 ✗ return;
271 }
272
273 // add serialized parameter value to crc
274 ✗ if (entry.getValue().getBuffAddr() != nullptr && writeSize != 0) {
275 ✗ crc.update(entry.getValue().getBuffAddr(), writeSize);
276 }
277
278 ✗ numRecords++;
279 1 }
280
281
1/1
✓ Branch 1 taken 1 times.
1 this->unLock();
282
283 // save current location of pointer in paramFile
284 FwSizeType currPosInParamFile;
285
286
1/1
✓ Branch 1 taken 1 times.
1 stat = paramFile.position(currPosInParamFile);
287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stat != Os::File::OP_OK) {
288 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::CURR_POSITION, 0, stat);
289 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
290 ✗ return;
291 }
292
293 // seek to beginning and write CRC value
294
1/1
✓ Branch 1 taken 1 times.
1 stat = paramFile.seek(0, Os::File::SeekType::ABSOLUTE);
295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stat != Os::File::OP_OK) {
296 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::SEEK_ZERO, 0, stat);
297 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
298 ✗ return;
299 }
300
1/1
✓ Branch 1 taken 1 times.
1 buff.resetSer();
301 1 U32 crcFinal = 0;
302
1/1
✓ Branch 1 taken 1 times.
1 crc.finalize(crcFinal);
303 1 crcFinal = ~crcFinal;
304
1/1
✓ Branch 1 taken 1 times.
1 serStat = buff.serializeFrom(crcFinal);
305
306 1 FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, static_cast<FwAssertArgType>(serStat));
307
1/1
✓ Branch 1 taken 1 times.
1 writeSize = static_cast<FwSizeType>(buff.getSize());
308
309
1/1
✓ Branch 2 taken 1 times.
1 stat = paramFile.write(buff.getBuffAddr(), writeSize, Os::File::WaitType::WAIT);
310
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stat != Os::File::OP_OK) {
311 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::CRC_REAL, 0, stat);
312 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
313 ✗ return;
314 }
315
316 // Restore pointer to previously saved location
317
1/1
✓ Branch 1 taken 1 times.
1 stat = paramFile.seek(static_cast<FwSignedSizeType>(currPosInParamFile), Os::File::SeekType::ABSOLUTE);
318
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stat != Os::File::OP_OK) {
319 ✗ this->log_WARNING_HI_PrmFileWriteError(PrmWriteError::SEEK_POSITION, 0, stat);
320 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
321 ✗ return;
322 }
323
324
1/1
✓ Branch 1 taken 1 times.
1 this->log_ACTIVITY_HI_PrmFileSaveComplete(numRecords);
325
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
326 1 }
327
328 2 void PrmDbImpl::PRM_LOAD_FILE_cmdHandler(FwOpcodeType opCode,
329 U32 cmdSeq,
330 const Fw::CmdStringArg& fileName,
331 const PrmDb_Merge& merge) {
332 // Reject PRM_LOAD_FILE command during non-idle file load states
333
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (m_state != PrmDbFileLoadState::IDLE) {
334 ✗ this->log_WARNING_LO_PrmDbFileLoadInvalidAction(m_state, PrmDb_PrmLoadAction::LOAD_FILE_COMMAND);
335 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::BUSY);
336 ✗ return;
337 }
338
339 // Reject an empty file name before touching the staging database
340
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (fileName.length() == 0) {
341 ✗ this->log_WARNING_HI_PrmDbFileLoadFailed();
342 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
343 ✗ return;
344 }
345
346 // Set state to loading
347 2 m_state = PrmDbFileLoadState::LOADING_FILE_UPDATES;
348
349 // If reset is true, clear the staging database first
350
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (merge == PrmDb_Merge::MERGE) {
351 // Copy active to staging for merging
352 ✗ dbCopy(PrmDbType::DB_STAGING, PrmDbType::DB_ACTIVE);
353 } else {
354 // reset staging db, all file contents will be loaded but no old parameters will be retained
355
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 this->clearDb(PrmDbType::DB_STAGING);
356 }
357
358 // Load the file into staging database
359 // The readParamFileImpl will emit the relevant EVR if the file load fails
360 // and also if it succeeds will emit EVRs with the number of records
361
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 PrmDbImpl::PrmLoadStatus success = PrmDbImpl::readParamFileImpl(fileName, PrmDbType::DB_STAGING);
362
363
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (success == PrmLoadStatus::SUCCESS) {
364
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
365 1 m_state = PrmDbFileLoadState::FILE_UPDATES_STAGED;
366 } else {
367 1 this->log_WARNING_HI_PrmDbFileLoadFailed();
368 // clear the staging DB and reset to an IDLE state in case of issues
369
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->clearDb(PrmDbType::DB_STAGING);
370 1 m_state = PrmDbFileLoadState::IDLE;
371
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
372 }
373 }
374
375 1 void PrmDbImpl::PRM_COMMIT_STAGED_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
376 // Verify we are in the correct state
377
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (m_state != PrmDbFileLoadState::FILE_UPDATES_STAGED) {
378 ✗ this->log_WARNING_LO_PrmDbFileLoadInvalidAction(m_state, PrmDb_PrmLoadAction::COMMIT_STAGED_COMMAND);
379 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR);
380 ✗ return;
381 }
382
383 // Swap active and staging databases, safely w.r.t. prmGet
384 1 this->lock();
385 1 PrmDbStore* temp = this->m_activeDb;
386 1 this->m_activeDb = this->m_stagingDb;
387 1 this->unLock();
388 1 this->m_stagingDb = temp;
389
390 // Clear the new staging database
391
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->clearDb(PrmDbType::DB_STAGING);
392
393 // Set file load state to idle
394 1 m_state = PrmDbFileLoadState::IDLE;
395
396 1 this->log_ACTIVITY_HI_PrmDbCommitComplete();
397
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
398 }
399
400 //! ----------------------------------------------------------------------
401 //! Helpers for construction/destruction, init, & handlers
402 //! ----------------------------------------------------------------------
403
404 3 PrmDbImpl::PrmLoadStatus PrmDbImpl::readParamFileImpl(const Fw::StringBase& fileName, PrmDbType dbType) {
405 3 FW_ASSERT(dbType == PrmDbType::DB_ACTIVE or dbType == PrmDbType::DB_STAGING);
406 3 FW_ASSERT(fileName.length() > 0);
407
408
2/2
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 3 times.
3 Fw::String dbString = getDbString(dbType);
409
410
1/1
✓ Branch 1 taken 3 times.
3 Os::SandboxedFile paramFile;
411
1/1
✓ Branch 1 taken 3 times.
3 this->applySandbox(paramFile);
412
413
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);
414
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (stat != Os::File::OP_OK) {
415
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 this->log_WARNING_HI_PrmFileReadError(PrmReadError::OPEN, 0, stat);
416 2 return PrmLoadStatus::ERROR;
417 }
418 //===========================================================================
419 // read CRC from beginning of file
420
1/1
✓ Branch 1 taken 1 times.
1 WorkingBuffer buff;
421 U32 fileCrc;
422 1 FwSizeType readSize = static_cast<FwSizeType>(sizeof(fileCrc));
423
424 // Read raw CRC bytes from file
425
1/1
✓ Branch 2 taken 1 times.
1 stat = paramFile.read(buff.getBuffAddr(), readSize);
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::CRC, static_cast<I32>(0), stat);
428 ✗ return PrmLoadStatus::ERROR;
429 }
430
431
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (readSize != sizeof(fileCrc)) {
432 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::CRC_SIZE, static_cast<I32>(0), static_cast<I32>(readSize));
433 ✗ return PrmLoadStatus::ERROR;
434 }
435
436 // Deserialize the CRC in a portable way
437
1/1
✓ Branch 1 taken 1 times.
1 Fw::SerializeStatus serStat = buff.setBuffLen(readSize);
438 1 FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, static_cast<FwAssertArgType>(serStat));
439
1/1
✓ Branch 1 taken 1 times.
1 buff.resetDeser();
440
1/1
✓ Branch 1 taken 1 times.
1 serStat = buff.deserializeTo(fileCrc);
441 1 FW_ASSERT(Fw::FW_SERIALIZE_OK == serStat, static_cast<FwAssertArgType>(serStat));
442
443 1 U32 crc = 0xFFFFFFFF;
444 // read into CRC buffer for checking
445
446
1/1
✓ Branch 1 taken 1 times.
1 Os::File::Status status = paramFile.calculateCrc(crc);
447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (status != Os::File::OP_OK) {
448 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::CRC_BUFFER, static_cast<I32>(0), status);
449 ✗ return PrmLoadStatus::ERROR;
450 }
451
452
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (fileCrc != crc) {
453 ✗ this->log_WARNING_HI_PrmFileBadCrc(fileCrc, crc);
454 ✗ return PrmLoadStatus::ERROR;
455 }
456
457 // seek back to just after CRC
458
1/1
✓ Branch 1 taken 1 times.
1 stat = paramFile.seek(sizeof(fileCrc), Os::File::SeekType::ABSOLUTE);
459
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stat != Os::File::OP_OK) {
460 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::SEEK_ZERO, 0, stat);
461 ✗ return PrmLoadStatus::ERROR;
462 }
463 //===========================================================================
464
465 1 U32 recordNumTotal = 0;
466 1 U32 recordNumAdded = 0;
467 1 U32 recordNumUpdated = 0;
468 1 U32 recordNumDropped = 0;
469
470
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 for (FwSizeType entry = 0; entry < PRMDB_NUM_DB_ENTRIES; entry++) {
471 U8 delimiter;
472 1 readSize = static_cast<FwSizeType>(sizeof(delimiter));
473
474 // read delimiter
475
1/1
✓ Branch 1 taken 1 times.
1 Os::File::Status fStat = paramFile.read(&delimiter, readSize, Os::File::WaitType::WAIT);
476
477 // check for end of file (successful read of size 0); a failed read can
478 // also yield size 0 and must not be mistaken for a clean EOF
479
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)) {
480 1 break;
481 }
482
483 ✗ if (fStat != Os::File::OP_OK) {
484 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::DELIMITER, static_cast<I32>(recordNumTotal), fStat);
485 ✗ return PrmLoadStatus::ERROR;
486 }
487
488 ✗ if (sizeof(delimiter) != readSize) {
489 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::DELIMITER_SIZE, static_cast<I32>(recordNumTotal),
490 static_cast<I32>(readSize));
491 ✗ return PrmLoadStatus::ERROR;
492 }
493
494 ✗ if (PRMDB_ENTRY_DELIMITER != delimiter) {
495 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::DELIMITER_VALUE, static_cast<I32>(recordNumTotal),
496 delimiter);
497 ✗ return PrmLoadStatus::ERROR;
498 }
499
500 ✗ U32 recordSize = 0;
501
502 // read record size
503 ✗ readSize = sizeof(recordSize);
504
505 ✗ fStat = paramFile.read(buff.getBuffAddr(), readSize, Os::File::WaitType::WAIT);
506 ✗ if (fStat != Os::File::OP_OK) {
507 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::RECORD_SIZE, static_cast<I32>(recordNumTotal), fStat);
508 ✗ return PrmLoadStatus::ERROR;
509 }
510 ✗ if (sizeof(recordSize) != readSize) {
511 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::RECORD_SIZE_SIZE, static_cast<I32>(recordNumTotal),
512 static_cast<I32>(readSize));
513 ✗ return PrmLoadStatus::ERROR;
514 }
515 // set serialized size to read size
516 ✗ Fw::SerializeStatus 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 record size is serialized in file
522 ✗ desStat = buff.deserializeTo(recordSize);
523 ✗ FW_ASSERT(Fw::FW_SERIALIZE_OK == desStat);
524
525 // sanity check value. It can't be larger than the maximum parameter buffer size + id
526 // or smaller than the record id
527 ✗ if ((recordSize > FW_PARAM_BUFFER_MAX_SIZE + sizeof(FwPrmIdType)) or (recordSize < sizeof(FwPrmIdType))) {
528 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::RECORD_SIZE_VALUE, static_cast<I32>(recordNumTotal),
529 static_cast<I32>(recordSize));
530 ✗ return PrmLoadStatus::ERROR;
531 }
532
533 // read the parameter ID
534 ✗ FwPrmIdType parameterId = 0;
535 ✗ readSize = static_cast<FwSizeType>(sizeof(FwPrmIdType));
536
537 ✗ fStat = paramFile.read(buff.getBuffAddr(), readSize, Os::File::WaitType::WAIT);
538 ✗ if (fStat != Os::File::OP_OK) {
539 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_ID, static_cast<I32>(recordNumTotal), fStat);
540 ✗ return PrmLoadStatus::ERROR;
541 }
542 ✗ if (sizeof(parameterId) != static_cast<FwSizeType>(readSize)) {
543 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_ID_SIZE, static_cast<I32>(recordNumTotal),
544 static_cast<I32>(readSize));
545 ✗ return PrmLoadStatus::ERROR;
546 }
547
548 // set serialized size to read parameter ID
549 ✗ desStat = buff.setBuffLen(static_cast<Fw::Serializable::SizeType>(readSize));
550 // should never fail
551 ✗ FW_ASSERT(Fw::FW_SERIALIZE_OK == desStat, static_cast<FwAssertArgType>(desStat));
552 // reset deserialization
553 ✗ buff.resetDeser();
554 // deserialize, since parameter ID is serialized in file
555 ✗ desStat = buff.deserializeTo(parameterId);
556 ✗ FW_ASSERT(Fw::FW_SERIALIZE_OK == desStat);
557
558 // copy parameter value from file into a temporary buffer
559 ✗ Fw::ParamBuffer tmpParamBuffer; // temporary param buffer to read parameter value from file
560 ✗ readSize = recordSize - sizeof(parameterId);
561 ✗ desStat = tmpParamBuffer.setBuffLen(static_cast<Fw::Serializable::SizeType>(readSize));
562 ✗ FW_ASSERT(Fw::FW_SERIALIZE_OK == desStat, static_cast<FwAssertArgType>(desStat)); // should never fail
563 ✗ fStat = paramFile.read(tmpParamBuffer.getBuffAddr(), readSize);
564
565 ✗ if (fStat != Os::File::OP_OK) {
566 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_VALUE, static_cast<I32>(recordNumTotal),
567 fStat);
568 ✗ return PrmLoadStatus::ERROR;
569 }
570 ✗ if (static_cast<U32>(readSize) != recordSize - sizeof(parameterId)) {
571 ✗ this->log_WARNING_HI_PrmFileReadError(PrmReadError::PARAMETER_VALUE_SIZE, static_cast<I32>(recordNumTotal),
572 static_cast<I32>(readSize));
573 ✗ return PrmLoadStatus::ERROR;
574 }
575
576 // Actually update or add parameter
577 ✗ PrmUpdateType updateStatus = updateAddPrmImpl(parameterId, tmpParamBuffer, dbType);
578 ✗ if (updateStatus == PARAM_ADDED) {
579 ✗ recordNumAdded++;
580 ✗ } else if (updateStatus == PARAM_UPDATED) {
581 ✗ recordNumUpdated++;
582 }
583
584 ✗ if (updateStatus == NO_SLOTS) {
585 ✗ this->log_WARNING_HI_PrmDbFull(parameterId);
586 ✗ recordNumDropped++;
587 }
588 ✗ recordNumTotal++;
589 ✗ }
590
591 // Dropped records mean the database does not reflect the file: report an error
592
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (recordNumDropped > 0) {
593 ✗ return PrmLoadStatus::ERROR;
594 }
595
596
1/1
✓ Branch 1 taken 1 times.
1 this->log_ACTIVITY_HI_PrmFileLoadComplete(dbString, recordNumTotal, recordNumAdded, recordNumUpdated);
597 1 return PrmLoadStatus::SUCCESS;
598 3 }
599
600 4 PrmDbImpl::PrmUpdateType PrmDbImpl::updateAddPrmImpl(FwPrmIdType id, Fw::ParamBuffer& val, PrmDbType prmDbType) {
601
2/2
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
4 auto* db = getDbPtr(prmDbType);
602
603 4 PrmUpdateType updateStatus = NO_SLOTS;
604
605 4 this->lock();
606
607 4 auto prevSize = db->getSize();
608
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)) {
609 ✗ case Fw::Success::FAILURE:
610 ✗ updateStatus = NO_SLOTS;
611 ✗ break;
612 4 case Fw::Success::SUCCESS:
613
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if (prevSize < db->getSize()) {
614 4 updateStatus = PARAM_ADDED;
615 } else {
616 ✗ FW_ASSERT(prevSize == db->getSize(), static_cast<FwAssertArgType>(prevSize),
617 static_cast<FwAssertArgType>(db->getSize()));
618 ✗ updateStatus = PARAM_UPDATED;
619 }
620 4 break;
621 ✗ default:
622 ✗ FW_ASSERT(false);
623 }
624
625 4 this->unLock();
626 4 return updateStatus;
627 }
628
629 //! ----------------------------------------------------------------------
630 //! Helpers for database management
631 //! ----------------------------------------------------------------------
632
633 8 void PrmDbImpl::clearDb(PrmDbType prmDbType) {
634
3/3
✓ Branch 1 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 7 taken 8 times.
8 getDbPtr(prmDbType)->clear();
635 8 }
636
637 ✗ void PrmDbImpl::dbCopy(PrmDbType dest, PrmDbType src) {
638 ✗ *getDbPtr(dest) = *getDbPtr(src);
639 ✗ this->log_ACTIVITY_HI_PrmDbCopyAllComplete(getDbString(src), getDbString(dest));
640 ✗ }
641
642 13 PrmDbImpl::PrmDbStore* PrmDbImpl::getDbPtr(PrmDbType dbType) {
643 13 FW_ASSERT(dbType == PrmDbType::DB_ACTIVE or dbType == PrmDbType::DB_STAGING);
644
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 6 times.
13 if (dbType == PrmDbType::DB_ACTIVE) {
645 7 return m_activeDb;
646 }
647 6 return m_stagingDb;
648 }
649
650 3 Fw::String PrmDbImpl::getDbString(PrmDbType dbType) {
651 3 FW_ASSERT(dbType == PrmDbType::DB_ACTIVE or dbType == PrmDbType::DB_STAGING);
652
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
3 if (dbType == PrmDbType::DB_ACTIVE) {
653 1 return Fw::String("ACTIVE");
654 }
655 2 return Fw::String("STAGING");
656 }
657
658 } // namespace Svc
659