GCC Code Coverage Report


Directory: ./
File: firmware/controllers/core/state_sequence.h
Date: 2025-11-16 14:52:24
Coverage Exec Excl Total
Lines: 100.0% 29 0 29
Functions: 100.0% 9 0 9
Branches: 100.0% 4 0 4
Decisions: 66.7% 2 - 3

Line Branch Decision Exec Source
1 /**
2 * @file state_sequence.h
3 *
4 * @date May 18, 2014
5 * @author Andrey Belomutskiy, (c) 2012-2020
6 */
7
8 #pragma once
9
10 #include <stdint.h>
11 #include "rusefi_enums.h"
12 #include <rusefi/expected.h>
13
14 enum class TriggerValue : uint8_t {
15 FALL = 0,
16 RISE = 1
17 };
18
19 // see also 'HW_EVENT_TYPES'
20 typedef enum {
21 SHAFT_PRIMARY_FALLING = 0,
22 SHAFT_PRIMARY_RISING = 1,
23 SHAFT_SECONDARY_FALLING = 2,
24 SHAFT_SECONDARY_RISING = 3,
25 } trigger_event_e;
26
27 /**
28 * This layer has two primary usages:
29 * 1) 'simple' PWM generation is used to produce actuator square control wave
30 * 2) 'complex' PWM generation is used for trigger simulator.
31 * Some triggers like Nissan 360 slot optical wheel need a lot of points to describe the shape of the wave.
32 * Looks like 252 is explained by 60 tooth * 2 (number of fronts) * 2 (number of crank rotations within engine cycle)
33 */
34 #ifndef PWM_PHASE_MAX_COUNT
35 // as of April 2020, trigger which requires most array length is REMIX_66_2_2_2
36 // we can probably reduce RAM usage if we have more custom logic of triggers with large number of tooth while
37 // pretty easy logic. like we do not need to REALLY have an array to remember the shape of evenly spaces 360 or 60/2 trigger :)
38 // todo https://github.com/rusefi/rusefi/issues/3003
39 // as of 2025, stm32f4 is kind of on the way out - we are focusing on stm32*7 where we have double the RAM amount
40 #define PWM_PHASE_MAX_COUNT 280
41 #endif /* PWM_PHASE_MAX_COUNT */
42 // todo: rename to TRIGGER_CHANNEL_COUNT?
43 #define PWM_PHASE_MAX_WAVE_PER_PWM 2
44
45 typedef TriggerValue pin_state_t;
46
47 /**
48 * This class represents multi-channel logical signals with shared time axis
49 *
50 * This is a semi-abstract interface so that implementations can exist for either regularized
51 * patterns (60-2, etc) or completely arbitrary patterns stored in arrays.
52 */
53 class MultiChannelStateSequence {
54 public:
55 /**
56 * values in the (0..1] range which refer to points within the period at at which pin state
57 * should be changed So, in the simplest case we turn pin off at 0.3 and turn it on at 1 -
58 * that would give us a 70% duty cycle PWM
59 */
60 virtual float getSwitchTime(int phaseIndex) const = 0;
61 virtual pin_state_t getChannelState(int channelIndex, int phaseIndex) const = 0;
62
63 // Make sure the switch times are in order and end at the very end.
64 void checkSwitchTimes(float scale) const;
65
66 // Find the exact angle, or unexpected if it doesn't exist
67 expected<int> findAngleMatch(float angle) const;
68
69 // returns the index at which given value would need to be inserted into sorted array
70 int findInsertionAngle(float angle) const;
71
72 uint16_t phaseCount = 0; // Number of timestamps
73 uint16_t waveCount = 0; // Number of waveforms
74 };
75
76 template<unsigned max_phase>
77 class MultiChannelStateSequenceWithData : public MultiChannelStateSequence {
78 public:
79
2/2
MultiChannelStateSequenceWithData<2u>::getSwitchTime(int) const:
✓ Decision 'true' taken 3047 times.
MultiChannelStateSequenceWithData<280u>::getSwitchTime(int) const:
✓ Decision 'true' taken 749171 times.
752218 float getSwitchTime(int phaseIndex) const override {
80 752218 return switchTimes[phaseIndex];
81 }
82
83
0/1
✗ Decision 'true' not taken.
1732014 pin_state_t getChannelState(int channelIndex, int phaseIndex) const override {
84 1732014 if (channelIndex >= waveCount) {
85 // todo: would be nice to get this asserting working
86 //criticalError("channel index %d/%d", channelIndex, waveCount);
87 }
88 1732014 return ((waveForm[phaseIndex] >> channelIndex) & 1) ? TriggerValue::RISE : TriggerValue::FALL;
89 }
90
91 3075 void reset() {
92 3075 waveCount = 0;
93 3075 }
94
95 78106 void setSwitchTime(const int phaseIndex, const float value) {
96 78106 switchTimes[phaseIndex] = value;
97 78106 }
98
99 45346 void setChannelState(const int channelIndex, const int phaseIndex, pin_state_t state) {
100 45346 if (channelIndex >= waveCount) {
101 // todo: would be nice to get this asserting working
102 //criticalError("channel index %d/%d", channelIndex, waveCount);
103 }
104 45346 uint8_t & ref = waveForm[phaseIndex];
105
4/4
MultiChannelStateSequenceWithData<280u>::setChannelState(int, int, TriggerValue):
✓ Branch 0 taken 15211 times.
✓ Branch 1 taken 30119 times.
MultiChannelStateSequenceWithData<2u>::setChannelState(int, int, TriggerValue):
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
45346 ref = (ref & ~(1U << channelIndex)) | ((state == TriggerValue::RISE ? 1 : 0) << channelIndex);
106 45346 }
107
108 private:
109 float switchTimes[max_phase];
110 uint8_t waveForm[max_phase];
111 };
112
113