GCC Code Coverage Report


Directory: ./
File: firmware/controllers/tcu/gc_generic.cpp
Date: 2025-11-16 14:52:24
Coverage Exec Excl Total
Lines: 45.3% 43 0 95
Functions: 100.0% 6 0 6
Branches: 45.9% 28 0 61
Decisions: 50.0% 21 - 42

Line Branch Decision Exec Source
1 #include "pch.h"
2
3 #include "math.h"
4 #include "gc_generic.h"
5
6 #if EFI_TCU
7 GenericGearController genericGearController;
8
9 1 GenericGearController::GenericGearController() {
10 1 }
11
12 3 void GenericGearController::init() {
13 #if EFI_PROD_CODE
14 for (size_t i = 0; i < efi::size(engineConfiguration->tcu_rangeInput); i++) {
15 if (isBrainPinValid(engineConfiguration->tcu_rangeInput[i])) {
16 efiSetPadMode("Range Input", engineConfiguration->tcu_rangeInput[i], getInputMode(engineConfiguration->tcu_rangeInputMode[i]));
17 }
18 }
19 #endif /* EFI_PROD_CODE */
20
21 3 GearControllerBase::init();
22 3 }
23
24 17 SensorType GenericGearController::getAnalogSensorType(int zeroBasedSensorIndex) {
25 17 return static_cast<SensorType>(zeroBasedSensorIndex + static_cast<int>(SensorType::RangeInput1));
26 }
27
28 10 bool GenericGearController::isNearest(float value, int pinIndex, float* rangeStates) {
29 10 float distance = fabs(rangeStates[pinIndex] - value);
30
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 25 times.
✓ Decision 'false' taken 1 time.
26 for (int i = 1; i <= TCU_RANGE_COUNT; i++) {
31 25 float pinDistance = fabs(getRangeStateArray(i)[pinIndex] - value);
32
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 16 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 16 times.
25 if (pinDistance < distance) {
33 9 return false;
34 }
35 }
36 1 return true;
37 }
38
39 2 void GenericGearController::update() {
40 2 SelectedGear gear = SelectedGear::Invalid;
41 // Loop through possible range states
42 // 1 based because 0 is SelectedGear::Invalid
43
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 17 times.
✓ Decision 'false' taken 1 time.
18 for (int i = 1; i <= TCU_RANGE_COUNT; i++) {
44 17 float *rangeStates = getRangeStateArray(i);
45 // Loop through inputs
46
2/2
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 1 time.
2/2
✓ Decision 'true' taken 31 times.
✓ Decision 'false' taken 1 time.
32 for (size_t p = 0; p < efi::size(engineConfiguration->tcu_rangeInput); p++) {
47 31 float cellState = rangeStates[p];
48 // We allow the user to configure either a digital input or an analog input for each pin,
49 // so we need to check which is valid.
50
2/2
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 14 times.
2/2
✓ Decision 'true' taken 17 times.
✓ Decision 'false' taken 14 times.
31 if (isAdcChannelValid(engineConfiguration->tcu_rangeAnalogInput[p])) {
51 17 float pinState = Sensor::getOrZero(getAnalogSensorType(p));
52
6/6
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 7 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 9 times.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 9 times.
17 if (getRangeStateArray(i)[p] == 0 || isNearest(pinState, p, rangeStates)) {
53 // Set the gear to the one we're checking, and continue to the next pin
54 8 gear = static_cast<SelectedGear>(i);
55 } else {
56 // This possibility doesn't match, set to invalid
57 9 gear = SelectedGear::Invalid;
58 9 break;
59 }
60
2/2
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 3 times.
2/2
✓ Decision 'true' taken 11 times.
✓ Decision 'false' taken 3 times.
14 } else if (isBrainPinValid(engineConfiguration->tcu_rangeInput[p])) {
61 11 bool pinState = efiReadPin(engineConfiguration->tcu_rangeInput[p]) ^ (engineConfiguration->tcu_rangeInputMode[p] == PI_PULLUP);
62 // If the pin doesn't matter, or if it matches the cellState
63
5/10
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 7 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 7 times.
11 if (cellState == 2 || (pinState && cellState == 1) || (!pinState && cellState == 0)) {
64 // Set the gear to the one we're checking, and continue to the next pin
65 4 gear = static_cast<SelectedGear>(i);
66 } else {
67 // This possibility doesn't match, set to invalid
68 7 gear = SelectedGear::Invalid;
69 7 break;
70 }
71 }
72 }
73 // If we didn't find it, try the next range
74
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 16 times.
✓ Decision 'false' taken 1 time.
17 if (gear == SelectedGear::Invalid) {
75 16 continue;
76 // We found a match
77 } else {
78 1 break;
79 }
80 }
81
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2/2
✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 1 time.
2 if (gear != SelectedGear::Invalid) {
82
1/9
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 8 not taken.
1 switch (gear) {
83 case SelectedGear::Manual3 :
84 setDesiredGear(GEAR_3);
85 break;
86 case SelectedGear::Manual2 :
87 setDesiredGear(GEAR_2);
88 break;
89 case SelectedGear::Manual1 :
90 setDesiredGear(GEAR_1);
91 break;
92 case SelectedGear::Reverse :
93 setDesiredGear(REVERSE);
94 break;
95 case SelectedGear::Park :
96 case SelectedGear::Neutral :
97 setDesiredGear(NEUTRAL);
98 break;
99 case SelectedGear::ManualPlus :
100 // Only allow manual shift once per 500 ms,
101 // and if the selected range was Manual prior to this update
102 if (!shiftTimer.hasElapsedMs(500) || lastRange != SelectedGear::Manual) {
103 break;
104 }
105 shiftTimer.reset();
106 switch (getDesiredGear()) {
107 case GEAR_1 :
108 setDesiredGear(GEAR_2);
109 break;
110 case GEAR_2 :
111 setDesiredGear(GEAR_3);
112 break;
113 case GEAR_3 :
114 setDesiredGear(GEAR_4);
115 break;
116 default:
117 break;
118 }
119 break;
120 case SelectedGear::ManualMinus :
121 // Only allow manual shift once per 500 ms,
122 // and if the selected range was Manual prior to this update
123 if (!shiftTimer.hasElapsedMs(500) || lastRange != SelectedGear::Manual) {
124 break;
125 }
126 shiftTimer.reset();
127 switch (getDesiredGear()) {
128 case GEAR_2 :
129 setDesiredGear(GEAR_1);
130 break;
131 case GEAR_3 :
132 setDesiredGear(GEAR_2);
133 break;
134 case GEAR_4 :
135 setDesiredGear(GEAR_3);
136 break;
137 default:
138 break;
139 }
140 break;
141
1/1
✓ Decision 'true' taken 1 time.
1 case SelectedGear::Drive :
142 // If the gear selector is in drive, let AutomaticGearController,
143 // which this class inherits from, decide what gear the transmission should be in.
144 1 AutomaticGearController::update();
145 1 return;
146 default:
147 break;
148 }
149
150 lastRange = gear;
151 }
152
153 1 GearControllerBase::update();
154 }
155
156 3 GenericGearController* getGenericGearController() {
157 3 return &genericGearController;
158 }
159 #endif // EFI_TCU
160