GCC Code Coverage Report


Directory: /home/runner/work/fprime/fprime/Svc/PassiveRateGroup/
File: PassiveRateGroup.cpp
Date: 2026-09-03 22:13:50
Exec Total Coverage
Lines: 0 65 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;
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;
102 // Cast to void as the only possible error is overflow, which we can't handle other
103 // than capping cycleTime to max value of U32 (which is done in getDiffUsec anyways)
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