Line data Source code
1 : /**
2 : * @file test_actuator_driver.c
3 : * @brief Unit tests for the Actuator Driver.
4 : *
5 : * @reqs SWE-006 SWE-013 SWE-014 SWE-015
6 : * @arch SWA-003
7 : */
8 : #include "../unit_test_framework.h"
9 : #include "../../src/actuator_driver.h"
10 :
11 : TestStats g_test_stats = {0, 0};
12 :
13 2 : static void test_init(void)
14 : {
15 2 : TEST_BEGIN("init -> both actuators STOP, 0 mA");
16 2 : ASSERT_EQ(actuator_init(), EPB_OK);
17 2 : ActuatorStatus l = actuator_get_status(ACTUATOR_LEFT);
18 2 : ActuatorStatus r = actuator_get_status(ACTUATOR_RIGHT);
19 2 : ASSERT_EQ(l.direction, ACT_DIR_STOP);
20 2 : ASSERT_EQ(r.direction, ACT_DIR_STOP);
21 2 : ASSERT_EQ(l.current_ma, 0);
22 2 : TEST_END();
23 2 : }
24 :
25 2 : static void test_apply_invalid_id(void)
26 : {
27 2 : TEST_BEGIN("apply: invalid ID -> EINVAL");
28 2 : (void)actuator_init();
29 2 : ASSERT_EQ(actuator_apply((ActuatorId)42, 50), EPB_EINVAL);
30 2 : TEST_END();
31 2 : }
32 :
33 2 : static void test_apply_pwm_out_of_range(void)
34 : {
35 2 : TEST_BEGIN("apply: PWM > 100% -> EINVAL");
36 2 : (void)actuator_init();
37 2 : ASSERT_EQ(actuator_apply(ACTUATOR_LEFT, 101), EPB_EINVAL);
38 2 : TEST_END();
39 2 : }
40 :
41 2 : static void test_apply_normal(void)
42 : {
43 2 : TEST_BEGIN("apply normal -> direction=APPLY, pwm=80");
44 2 : (void)actuator_init();
45 2 : ASSERT_EQ(actuator_apply(ACTUATOR_LEFT, 80), EPB_OK);
46 2 : ActuatorStatus s = actuator_get_status(ACTUATOR_LEFT);
47 2 : ASSERT_EQ(s.direction, ACT_DIR_APPLY);
48 2 : ASSERT_EQ(s.pwm_percent, 80);
49 2 : TEST_END();
50 2 : }
51 :
52 2 : static void test_release_normal(void)
53 : {
54 2 : TEST_BEGIN("release normal -> direction=RELEASE");
55 2 : (void)actuator_init();
56 2 : ASSERT_EQ(actuator_release(ACTUATOR_LEFT, 70), EPB_OK);
57 2 : ActuatorStatus s = actuator_get_status(ACTUATOR_LEFT);
58 2 : ASSERT_EQ(s.direction, ACT_DIR_RELEASE);
59 2 : TEST_END();
60 2 : }
61 :
62 2 : static void test_isr_samples_current(void)
63 : {
64 2 : TEST_BEGIN("ISR sample sets current_ma and peak");
65 2 : (void)actuator_init();
66 2 : (void)actuator_apply(ACTUATOR_LEFT, 80);
67 2 : actuator_isr_1khz(ACTUATOR_LEFT, 3000);
68 2 : ActuatorStatus s = actuator_get_status(ACTUATOR_LEFT);
69 2 : ASSERT_EQ(s.current_ma, 3000);
70 2 : ASSERT_EQ(s.peak_current_ma, 3000);
71 2 : TEST_END();
72 2 : }
73 :
74 2 : static void test_overcurrent_cutoff_after_100ms(void)
75 : {
76 2 : TEST_BEGIN("Overcurrent > 8 A for 100 ms -> STOP + overcurrent flag");
77 2 : (void)actuator_init();
78 2 : (void)actuator_apply(ACTUATOR_LEFT, 80);
79 : /* 100 samples (= 100 ms at 1 kHz) above 8 A */
80 202 : for (int i = 0; i < 100; ++i) {
81 200 : actuator_isr_1khz(ACTUATOR_LEFT, 8500);
82 : }
83 2 : ActuatorStatus s = actuator_get_status(ACTUATOR_LEFT);
84 2 : ASSERT_EQ(s.direction, ACT_DIR_STOP);
85 2 : ASSERT_TRUE(s.overcurrent);
86 2 : ASSERT_EQ(s.last_error, EPB_EOVERCURRENT);
87 2 : TEST_END();
88 2 : }
89 :
90 2 : static void test_overcurrent_below_window_no_cutoff(void)
91 : {
92 2 : TEST_BEGIN("Overcurrent < 100 ms does not trip yet");
93 2 : (void)actuator_init();
94 2 : (void)actuator_apply(ACTUATOR_LEFT, 80);
95 102 : for (int i = 0; i < 50; ++i) {
96 100 : actuator_isr_1khz(ACTUATOR_LEFT, 8500);
97 : }
98 2 : ActuatorStatus s = actuator_get_status(ACTUATOR_LEFT);
99 2 : ASSERT_EQ(s.direction, ACT_DIR_APPLY);
100 2 : ASSERT_TRUE(!s.overcurrent);
101 2 : TEST_END();
102 2 : }
103 :
104 2 : static void test_overcurrent_blocks_subsequent_apply(void)
105 : {
106 2 : TEST_BEGIN("after overcurrent: subsequent apply -> EOVERCURRENT");
107 2 : (void)actuator_init();
108 2 : (void)actuator_apply(ACTUATOR_LEFT, 80);
109 242 : for (int i = 0; i < 120; ++i) {
110 240 : actuator_isr_1khz(ACTUATOR_LEFT, 9000);
111 : }
112 2 : EpbStatus rc = actuator_apply(ACTUATOR_LEFT, 80);
113 2 : ASSERT_EQ(rc, EPB_EOVERCURRENT);
114 2 : TEST_END();
115 2 : }
116 :
117 2 : static void test_clamping_force_estimate(void)
118 : {
119 2 : TEST_BEGIN("Clamping force estimation from peak current (SWE-015)");
120 2 : (void)actuator_init();
121 2 : (void)actuator_apply(ACTUATOR_LEFT, 80);
122 2 : actuator_isr_1khz(ACTUATOR_LEFT, 4000); /* 4 A peak */
123 2 : actuator_isr_1khz(ACTUATOR_LEFT, 3500); /* then lower */
124 2 : ActuatorStatus s = actuator_get_status(ACTUATOR_LEFT);
125 : /* F = (4000 * 2500) / 1000 = 10000 N */
126 2 : ASSERT_EQ(s.clamping_force_n, 10000);
127 2 : TEST_END();
128 2 : }
129 :
130 2 : static void test_stop_clears_pwm(void)
131 : {
132 2 : TEST_BEGIN("stop -> direction=STOP, pwm=0");
133 2 : (void)actuator_init();
134 2 : (void)actuator_apply(ACTUATOR_LEFT, 80);
135 2 : (void)actuator_stop(ACTUATOR_LEFT);
136 2 : ActuatorStatus s = actuator_get_status(ACTUATOR_LEFT);
137 2 : ASSERT_EQ(s.direction, ACT_DIR_STOP);
138 2 : ASSERT_EQ(s.pwm_percent, 0);
139 2 : TEST_END();
140 2 : }
141 :
142 2 : int main(void)
143 : {
144 2 : printf("== test_actuator_driver ==\n");
145 2 : test_init();
146 2 : test_apply_invalid_id();
147 2 : test_apply_pwm_out_of_range();
148 2 : test_apply_normal();
149 2 : test_release_normal();
150 2 : test_isr_samples_current();
151 2 : test_overcurrent_cutoff_after_100ms();
152 2 : test_overcurrent_below_window_no_cutoff();
153 2 : test_overcurrent_blocks_subsequent_apply();
154 2 : test_clamping_force_estimate();
155 2 : test_stop_clears_pwm();
156 2 : TEST_SUMMARY();
157 : }
|