1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 | /**
* @file actuator_driver.c
* @brief Implementierung der EPB-Aktor-Ansteuerung.
*
* @arch SWA-003
* @reqs SWE-006 SWE-013 SWE-014 SWE-015
*
* ASIL: B.
*/
#include "actuator_driver.h"
typedef struct {
ActuatorStatus status;
uint16_t over_ms; /* Milliseconds above current limit (counts in 1 kHz ISR) */
} ActuatorCtx;
static ActuatorCtx s_ctx[ACTUATOR_COUNT];
static bool is_valid_id(ActuatorId id)
{
return (id == ACTUATOR_LEFT) || (id == ACTUATOR_RIGHT);
}
EpbStatus actuator_init(void)<--- The function 'actuator_init' is never used.
{
for (uint8_t i = 0U; i < ACTUATOR_COUNT; ++i) {
s_ctx[i].status.direction = ACT_DIR_STOP;
s_ctx[i].status.pwm_percent = 0U;
s_ctx[i].status.current_ma = 0U;
s_ctx[i].status.peak_current_ma = 0U;
s_ctx[i].status.clamping_force_n = 0U;
s_ctx[i].status.overcurrent = false;
s_ctx[i].status.last_error = EPB_OK;
s_ctx[i].over_ms = 0U;
}
return EPB_OK;
}
EpbStatus actuator_apply(ActuatorId id, uint8_t pwm_percent)
{
if (!is_valid_id(id)) {
return EPB_EINVAL;
}
if (pwm_percent > 100U) {
return EPB_EINVAL;
}
if (s_ctx[id].status.overcurrent) {
return EPB_EOVERCURRENT;
}
s_ctx[id].status.direction = ACT_DIR_APPLY;
s_ctx[id].status.pwm_percent = pwm_percent;
s_ctx[id].status.peak_current_ma = 0U;
return EPB_OK;
}
EpbStatus actuator_release(ActuatorId id, uint8_t pwm_percent)
{
if (!is_valid_id(id)) {
return EPB_EINVAL;
}
if (pwm_percent > 100U) {
return EPB_EINVAL;
}
if (s_ctx[id].status.overcurrent) {
return EPB_EOVERCURRENT;
}
s_ctx[id].status.direction = ACT_DIR_RELEASE;
s_ctx[id].status.pwm_percent = pwm_percent;
return EPB_OK;
}
EpbStatus actuator_stop(ActuatorId id)
{
if (!is_valid_id(id)) {
return EPB_EINVAL;
}
s_ctx[id].status.direction = ACT_DIR_STOP;
s_ctx[id].status.pwm_percent = 0U;
return EPB_OK;
}
ActuatorStatus actuator_get_status(ActuatorId id)<--- The function 'actuator_get_status' is never used.
{
if (!is_valid_id(id)) {
ActuatorStatus empty = {0};
empty.last_error = EPB_EINVAL;
return empty;
}
return s_ctx[id].status;
}
void actuator_isr_1khz(ActuatorId id, uint16_t current_sample_ma)<--- The function 'actuator_isr_1khz' is never used.
{
if (!is_valid_id(id)) {
return;
}
s_ctx[id].status.current_ma = current_sample_ma;
if (current_sample_ma > s_ctx[id].status.peak_current_ma) {
s_ctx[id].status.peak_current_ma = current_sample_ma;
}
/* SWE-014: Overcurrent cutoff at > 8 A for > 100 ms */
if (current_sample_ma > ACT_OVERCURRENT_LIMIT_MA) {
if (s_ctx[id].over_ms < UINT16_MAX) {
++s_ctx[id].over_ms;
}
if (s_ctx[id].over_ms >= ACT_OVERCURRENT_WINDOW_MS) {
s_ctx[id].status.direction = ACT_DIR_STOP;
s_ctx[id].status.pwm_percent = 0U;
s_ctx[id].status.overcurrent = true;
s_ctx[id].status.last_error = EPB_EOVERCURRENT;
}
} else {
s_ctx[id].over_ms = 0U;
}
/* SWE-015: Estimate clamping force from peak current (only on apply). */
if (s_ctx[id].status.direction == ACT_DIR_APPLY) {
const uint32_t force = ((uint32_t)s_ctx[id].status.peak_current_ma
* ACT_FORCE_PER_AMP_N) / 1000U;
s_ctx[id].status.clamping_force_n =
(force > UINT16_MAX) ? UINT16_MAX : (uint16_t)force;
}
}
|