GCC Code Coverage Report


Directory: ./
File: Svc/PrmDb/PrmDbImpl.cpp
Date: 2026-10-14 21:15:02
Exec Total Coverage
Lines: 305 330 92.4%
Functions: 19 20 95.0%
Branches: 289 324 89.2%

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