firmware/controllers/engine_cycle/rotational_idle.cpp
| Line | Branch | Decision | Exec | Source |
|---|---|---|---|---|
| 1 | #include "pch.h" | |||
| 2 | #include "rotational_idle.h" | |||
| 3 | ||||
| 4 | 701 | RotationalIdle::RotationalIdle(){ | ||
| 5 | ||||
| 6 | 701 | } | ||
| 7 | ||||
| 8 | 21 | bool RotationalIdle::shouldEngageRotationalIdle() { | ||
| 9 | 21 | rotationalIdleEngaged = false; | ||
| 10 | ||||
| 11 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 19 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 19 times.
|
21 | if (!engineConfiguration->rotationalIdleController.enabled) { |
| 12 | 2 | return false; | ||
| 13 | } | |||
| 14 | ||||
| 15 | //TODO: we need to use deadbands ond this!! (and on the tps/pps) | |||
| 16 |
6/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 17 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 18 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 18 times.
|
19 | if (engineConfiguration->rotationalIdleController.auto_engage_clt_enable && Sensor::getOrZero(SensorType::Clt) > engineConfiguration->rotationalIdleController.auto_engage_clt) { |
| 17 | 1 | rotationalIdleEngaged = true; | ||
| 18 | 1 | return true; | ||
| 19 | } | |||
| 20 | ||||
| 21 | // TODO: auto_engage sounds too generic, maybe better auto_engage_pps_enable? | |||
| 22 |
6/6✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 16 times.
✓ Branch 6 taken 2 times.
|
2/2✓ Decision 'true' taken 16 times.
✓ Decision 'false' taken 2 times.
|
18 | if (engineConfiguration->rotationalIdleController.auto_engage && Sensor::getOrZero(SensorType::DriverThrottleIntent) <= engineConfiguration->rotationalIdleController.max_tps) { |
| 23 | 16 | rotationalIdleEngaged = true; | ||
| 24 | 16 | return true; // tps is below the maximum | ||
| 25 | } | |||
| 26 | ||||
| 27 | 2 | return false; | ||
| 28 | } | |||
| 29 | ||||
| 30 | 42 | static bool calculateSkip(uint32_t counter, uint8_t max, uint8_t adder) { | ||
| 31 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 18 times.
|
2/2✓ Decision 'true' taken 24 times.
✓ Decision 'false' taken 18 times.
|
42 | if (max == 0) { |
| 32 | 24 | return false; | ||
| 33 | } | |||
| 34 | 18 | return ((counter % max) + adder) >= max; | ||
| 35 | } | |||
| 36 | ||||
| 37 | /** | |||
| 38 | * Determines whether to skip spark based on rotational idle skip pattern configuration. | |||
| 39 | * | |||
| 40 | * The skip pattern works using modulo arithmetic with configurable accumulators: | |||
| 41 | * - Each accumulator has: acc_max (pattern period), acc_adder (phase shift), acc_offset (cylinder offset) | |||
| 42 | * - For each accumulator: counter = globalSparkCounter + offset + acc_offset | |||
| 43 | * - Skip condition: ((counter % acc_max) + acc_adder) >= acc_max | |||
| 44 | * | |||
| 45 | * Example with acc_max=2, acc_adder=1, acc_offset=0: | |||
| 46 | * counter=0: (0 % 2) + 1 = 1 < 2 -> fire spark | |||
| 47 | * counter=1: (1 % 2) + 1 = 2 >= 2 -> skip spark | |||
| 48 | * counter=2: (2 % 2) + 1 = 1 < 2 -> fire spark | |||
| 49 | * counter=3: (3 % 2) + 1 = 2 >= 2 -> skip spark | |||
| 50 | * | |||
| 51 | * If acc_max=0, that accumulator is disabled and won't skip. | |||
| 52 | * | |||
| 53 | * @return True if should skip a spark event. | |||
| 54 | */ | |||
| 55 | 16 | bool RotationalIdle::shouldSkipSparkRotationalIdle() { | ||
| 56 | 16 | bool result = false; | ||
| 57 | 16 | auto cutMode = engineConfiguration->rotationalIdleController.cut_mode; | ||
| 58 | ||||
| 59 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 15 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 15 times.
|
16 | if (cutMode == RotationalCutMode::Fuel) { |
| 60 | 1 | return false; | ||
| 61 | } | |||
| 62 | ||||
| 63 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 14 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 14 times.
|
15 | if (!shouldEngageRotationalIdle()) { |
| 64 | 1 | rotationalIdleEngaged = false; | ||
| 65 | 1 | return false; | ||
| 66 | } | |||
| 67 | ||||
| 68 | 14 | rotationalIdleEngaged = true; | ||
| 69 | ||||
| 70 | ||||
| 71 |
2/2✓ Branch 1 taken 42 times.
✓ Branch 2 taken 14 times.
|
2/2✓ Decision 'true' taken 42 times.
✓ Decision 'false' taken 14 times.
|
56 | for (size_t i = 0; i < efi::size(engineConfiguration->rotationalIdleController.accumulators); i++){ |
| 72 | 42 | const auto& accConfig = engineConfiguration->rotationalIdleController.accumulators[i]; | ||
| 73 | ||||
| 74 | 42 | uint32_t counter = engine->engineState.globalSparkCounter + accConfig.acc_offset; | ||
| 75 | 42 | result |= calculateSkip(counter, accConfig.acc_max, accConfig.acc_adder); | ||
| 76 | } | |||
| 77 | ||||
| 78 | 14 | return result; | ||
| 79 | } | |||
| 80 |