GCC Code Coverage Report


Directory: ./
File: Svc/PassiveRateGroup/PassiveRateGroup.cpp
Date: 2026-09-23 22:11:34
Exec Total Coverage
Lines: 0 67 0.0%
Functions: 0 7 0.0%
Branches: 0 48 0.0%

Line Branch Exec Source
1 /*
2 * \author: Tim Canham
3 * \file:
4 * \brief
5 *
6 * This file implements the PassiveRateGroup component,
7 * which invokes a set of components the comprise the rate group.
8 *
9 * Copyright 2014-2015, by the California Institute of Technology.
10 * ALL RIGHTS RESERVED. United States Government Sponsorship
11 * acknowledged.
12 */
13
14 #include <Fw/FPrimeBasicTypes.hpp>
15 #include <Fw/Types/Assert.hpp>
16 #include <Os/Console.hpp>
17 #include <Svc/PassiveRateGroup/PassiveRateGroup.hpp>
18 #include <config/PassiveRateGroupCfg.hpp>
19 #include "config/FwSizeTypeAliasAc.h"
20
21 namespace Svc {
22 ✗ PassiveRateGroup::PassiveRateGroup(const char* compName)
23 : PassiveRateGroupComponentBase(compName),
24 ✗ m_cycles(0),
25 ✗ m_maxTime(0),
26 ✗ m_portCycleTimeHWMUsec{}, // Zero-initialize atomic array
27 ✗ m_rawTimeSource(Os::RAWTIME_DEFAULT),
28 ✗ m_numContexts(0) {}
29
30 ✗ PassiveRateGroup::~PassiveRateGroup() {}
31
32 ✗ Os::RawTime PassiveRateGroup::createRawTime() const {
33 ✗ return Os::RawTime(this->m_rawTimeSource);
34 }
35
36 ✗ void PassiveRateGroup::configure(const ContextArray& contexts, const Os::RawTimeSource rawTimeSource) {
37 static_assert(FW_NUM_ARRAY_ELEMENTS(m_contexts) == NUM_RATEGROUPMEMBEROUT_OUTPUT_PORTS,
38 "Context table size must match the number of rate group member output ports");
39
40 ✗ this->m_numContexts = CONNECTION_COUNT_MAX;
41 // copy context values
42 ✗ for (FwIndexType entry = 0; entry < this->m_numContexts; entry++) {
43 ✗ this->m_contexts[entry] = contexts[static_cast<FwSizeType>(entry)];
44 }
45
46 ✗ this->m_rawTimeSource = rawTimeSource;
47 ✗ }
48
49 ✗ void PassiveRateGroup::configure(const U32 contexts[], const FwIndexType numContexts) {
50 ✗ FW_ASSERT(contexts != nullptr);
51 ✗ FW_ASSERT(numContexts == this->getNum_RateGroupMemberOut_OutputPorts(), static_cast<FwAssertArgType>(numContexts),
52 static_cast<FwAssertArgType>(this->getNum_RateGroupMemberOut_OutputPorts()));
53
54 ✗ ContextArray contextArray;
55 ✗ for (FwIndexType entry = 0; entry < numContexts; entry++) {
56 ✗ contextArray[static_cast<FwSizeType>(entry)] = static_cast<U32>(contexts[entry]);
57 }
58 ✗ this->configure(contextArray);
59 ✗ }
60
61 ✗ void PassiveRateGroup::CycleIn_handler(FwIndexType portNum, Os::RawTime& cycleStart) {
62 ✗ Os::RawTime endTime = this->createRawTime();
63 ✗ FW_ASSERT(this->m_numContexts != 0);
64
65 // Pre-allocate RawTime objects outside loop to avoid repeated constructor calls
66 ✗ Os::RawTime portStart = this->createRawTime();
67 ✗ Os::RawTime portEnd = this->createRawTime();
68 ✗ PassiveRateGroup_CycleTime portTimes;
69
70 // invoke any members of the rate group
71 ✗ for (FwIndexType port = 0; port < this->getNum_RateGroupMemberOut_OutputPorts(); port++) {
72 ✗ if (this->isConnected_RateGroupMemberOut_OutputPort(port)) {
73 if (Svc::PassiveRateGroupCfg::PortCycleTime) {
74 ✗ (void)portStart.now();
75 }
76
77 ✗ this->RateGroupMemberOut_out(port, this->m_contexts[port]);
78
79 if (Svc::PassiveRateGroupCfg::PortCycleTime) {
80 ✗ (void)portEnd.now();
81 ✗ U32 cycleTime = 0;
82 ✗ (void)portEnd.getDiffUsec(portStart, cycleTime);
83 ✗ portTimes[static_cast<FwSizeType>(port)] = cycleTime;
84 // Update high water mark if current cycle time exceeds it (lock-free atomic)
85 U32 currentHWM =
86 ✗ this->m_portCycleTimeHWMUsec[static_cast<FwSizeType>(port)].load(std::memory_order_relaxed);
87 ✗ while (cycleTime > currentHWM) {
88 ✗ if (this->m_portCycleTimeHWMUsec[static_cast<FwSizeType>(port)].compare_exchange_weak(
89 currentHWM, cycleTime, std::memory_order_relaxed)) {
90 ✗ break;
91 }
92 }
93 }
94 }
95 }
96
97 // grab timer for endTime of cycle
98 ✗ (void)endTime.now();
99
100 // get rate group execution time
101 ✗ U32 cycleTime = 0;
102 // Cast to void: overflow is capped to U32 max by getDiffUsec, and a mismatched
103 // RawTimeSource (see sdd.md) leaves cycleTime at zero
104 ✗ (void)endTime.getDiffUsec(cycleStart, cycleTime);
105
106 // Update max time atomically (lock-free, ISR-safe)
107 ✗ U32 currentMax = this->m_maxTime.load(std::memory_order_relaxed);
108 ✗ while (cycleTime > currentMax) {
109 ✗ if (this->m_maxTime.compare_exchange_weak(currentMax, cycleTime, std::memory_order_relaxed)) {
110 ✗ break;
111 }
112 }
113
114 ✗ U32 maxTime = this->m_maxTime.load(std::memory_order_relaxed);
115 ✗ U32 cycles = ++this->m_cycles;
116
117 if (Svc::PassiveRateGroupCfg::PortCycleTime) {
118 // Copy atomic array to telemetry structure for sending
119 ✗ PassiveRateGroup_CycleTime portCycleTimeHWM;
120 ✗ for (FwIndexType port = 0; port < this->getNum_RateGroupMemberOut_OutputPorts(); port++) {
121 ✗ portCycleTimeHWM[static_cast<FwSizeType>(port)] =
122 ✗ this->m_portCycleTimeHWMUsec[static_cast<FwSizeType>(port)].load(std::memory_order_relaxed);
123 }
124 ✗ this->tlmWrite_PortCycleTime(portTimes);
125 ✗ this->tlmWrite_PortCycleTimeHWM(portCycleTimeHWM);
126 ✗ }
127
128 ✗ this->tlmWrite_MaxCycleTime(maxTime);
129 ✗ this->tlmWrite_CycleTime(cycleTime);
130 ✗ this->tlmWrite_CycleCount(cycles);
131 ✗ }
132
133 ✗ void PassiveRateGroup::CLEAR_STATISTICS_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
134 // Clear max cycle time (lock-free atomic)
135 ✗ this->m_maxTime.store(0, std::memory_order_relaxed);
136 // Note: m_cycles is intentionally NOT cleared - it's a running total
137
138 // Clear all port cycle time high water marks (lock-free atomic)
139 ✗ for (FwIndexType port = 0; port < this->getNum_RateGroupMemberOut_OutputPorts(); port++) {
140 ✗ this->m_portCycleTimeHWMUsec[static_cast<FwSizeType>(port)].store(0, std::memory_order_relaxed);
141 }
142
143 ✗ this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
144 ✗ }
145
146 } // namespace Svc
147