Branch data MC/DC data Line data Source code
1 : : : /**
2 : : : * @file controller.c
3 : : : * @brief Controller module responsible for managing actuator logic through message queue handling.
4 : : : *
5 : : : * This module handles the reception and processing of CAN messages related to actuators via POSIX
6 : : : * message queues. It spawns a separate thread to continuously read incoming messages, update the
7 : : : * internal state of the actuators accordingly, and log each event for traceability and diagnostics.
8 : : : */
9 : : :
10 : : : #include <stdio.h>
11 : : : #include <stdlib.h>
12 : : : #include <unistd.h>
13 : : : #include <mqueue.h>
14 : : : #include <stdbool.h>
15 : : : #include <pthread.h>
16 : : : #include "mq_utils.h"
17 : : : #include "constants.h"
18 : : : #include "actuators.h"
19 : : : #include "dbc.h"
20 : : : #include "log_utils.h"
21 : : :
22 : : : #define LOOP_EMPTY_ITERATIONS_MAX 11
23 : : :
24 : : : void *actuatorsResponseLoop(void *arg);
25 : : : void actuatorsTranslateCanMsg(can_msg captured_frame);
26 : : : void updateInternalActuatorsState(can_msg captured_frame);
27 : : :
28 : : : mqd_t actuators_mq;
29 : : : pthread_t actuators_id;
30 : : :
31 : : : actuators_abstraction actuators_state = {
32 : : : .belt_tightness = false,
33 : : : .door_lock = true,
34 : : : .should_activate_abs = false,
35 : : : .alarm_led = false,
36 : : : .alarm_buzzer = false};
37 : : :
38 : : : can_msg captured_can_frame = {
39 : : : .identifier = 0x0CFFB027,
40 : : : .dataFrame = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
41 : : :
42 : : :
43 : : : //Workaround to avoid the main function in this file
44 : : : // Write just the main function in the test file
45 : : : //Put the #ifndef TEST_MODE in the test file, as bellow
46 : : : //After the last line of main, put #endif
47 : : :
48 : : : //The next step is put the flag TEST_MODE in the Makefile
49 : : : //See the example:
50 : : : // $(CC) $(CFLAGS) -DTEST_MODE test/test_actuators.c src/actuators.c test/unity.c -o test/test_actuators -Iinc -Itest -lpthread
51 : : : //Put the flag TEST_MODE in the Makefile: -DTEST_MODE
52 : : : #ifndef TEST_MODE
53 : : : int main()
54 : : : {
55 : : : actuators_mq = open_mq(ACTUATORS_MQ);
56 : : :
57 : : : int actuators_thread;
58 : : : actuators_thread = pthread_create(&actuators_id, NULL, actuatorsResponseLoop, NULL);
59 : : : if (actuators_thread != 0)
60 : : : {
61 : : : perror("Actuators: it wasn't possible to create the associated thread\n");
62 : : : exit(54);
63 : : : }
64 : : : actuators_thread = pthread_join(actuators_id, NULL);
65 : : :
66 : : : return 0;
67 : : : }
68 : : : #endif
69 : : :
70 : : :
71 : : : /**
72 : : : * @brief Main loop for processing actuator messages.
73 : : : *
74 : : : * This function runs in a separate thread and continuously reads messages from the actuators message queue.
75 : : : * It processes each message to update the internal state of the actuators and logs the event.
76 : : : * If the message queue is empty for a specified number of iterations (`LOOP_EMPTY_ITERATIONS_MAX`),
77 : : : * the loop exits, signaling that no more messages are expected.
78 : : : *
79 : : : * @param arg Unused parameter (can be NULL).
80 : : : * @return NULL
81 : : : *
82 : : : * @details
83 : : : * - Reads messages from the `actuators_mq` message queue using `read_mq`.
84 : : : * - If a message is successfully read, it resets the `empty_mq_counter` and processes the message using `actuatorsTranslateCanMsg`.
85 : : : * - If the queue is empty, increments the `empty_mq_counter`.
86 : : : * - Logs each processed message using `log_event`, including the current state of the actuators.
87 : : : * - Waits for 200 milliseconds between iterations using `usleep`.
88 : : : * - Exits the loop and prints a message when the `empty_mq_counter` reaches `LOOP_EMPTY_ITERATIONS_MAX`.
89 : : : *
90 : : : * Implements [SwR-4](@ref SwR-4)
91 : : : *
92 : : : * \anchor actuatorsResponseLoop
93 : : : */
94 : : 1 : void *actuatorsResponseLoop(void *arg)
95 : : : {
96 : : 1 : int empty_mq_counter = 0;
97 [ + - ]: [ T f ]: 5 : while (empty_mq_counter < LOOP_EMPTY_ITERATIONS_MAX)
98 : : : {
99 [ + + ]: [ T F ]: 5 : if (read_mq(actuators_mq, &captured_can_frame) != -1)
100 : : : {
101 : : 2 : empty_mq_counter = 0;
102 : : 2 : actuatorsTranslateCanMsg(captured_can_frame);
103 : : : }
104 : : : else
105 : : : {
106 : : 3 : empty_mq_counter++;
107 : : : }
108 : : :
109 : : 5 : uint32_t event_id = captured_can_frame.identifier;
110 : : :
111 : : 5 : log_event("AEB1", event_id, actuators_state); // [SwR-4]
112 : : :
113 : : :
114 : : 5 : usleep(200000); // Deprected, change for function other later
115 : : : }
116 : : :
117 : : 0 : printf("Actuators: empty_mq_counter reached the limit, exiting\n");
118 : : 0 : return NULL;
119 : : : }
120 : : :
121 : : : /**
122 : : : * @brief Translates a CAN message into actuator commands.
123 : : : *
124 : : : * This function processes a captured CAN message and determines the appropriate action
125 : : : * based on the message's identifier. It updates the actuators' internal state or logs
126 : : : * a warning if the message identifier is unknown.
127 : : : *
128 : : : * @param captured_frame The captured CAN message to be processed.
129 : : : *
130 : : : * \anchor actuatorsTranslateCanMsg
131 : : : *
132 : : : * @details
133 : : : * - If the identifier is `ID_AEB_S`, the function calls `updateInternalActuatorsState` to update
134 : : : * the actuators' internal state based on the message's data.
135 : : : * - If the identifier is `ID_EMPTY`, the function does nothing, as it represents an empty message.
136 : : : * - For any other identifier, the function logs a warning indicating that the identifier is unknown.
137 : : : *
138 : : : * @note This function is a key part of the actuators module, as it ensures that the actuators' state
139 : : : * remains synchronized with the incoming CAN messages.
140 : : : *
141 : : : * @see updateInternalActuatorsState
142 : : : */
143 : : 7 : void actuatorsTranslateCanMsg(can_msg captured_frame)
144 : : : {
145 [ + + + ]: : 7 : switch (captured_frame.identifier)
146 : : : {
147 : : 4 : case ID_AEB_S:
148 : : 4 : updateInternalActuatorsState(captured_frame);
149 : : 4 : break;
150 : : 2 : case ID_EMPTY:
151 : : : //printf("Actuators: Empty message received\n");
152 : : 2 : break;
153 : : 1 : default:
154 : : 1 : printf("Actuators: CAN Identifier unknown\n");
155 : : 1 : break;
156 : : : }
157 : : 7 : }
158 : : :
159 : : : /**
160 : : : * @brief Updates the internal state of the actuators based on a CAN message.
161 : : : *
162 : : : * This function processes the data frame of a captured CAN message and updates
163 : : : * the internal state of the actuators accordingly. It determines the state of
164 : : : * various actuators, such as belt tightness, door lock, ABS activation, alarm LED,
165 : : : * and alarm buzzer, based on specific conditions in the message's data frame.
166 : : : *
167 : : : * @param captured_frame The captured CAN message containing the data to update the actuators' state.
168 : : : *
169 : : : * @details
170 : : : * - If `dataFrame[1] == 0x01`, the function sets the actuators to an active state, enabling
171 : : : * features like belt tightness, ABS activation, and alarms.
172 : : : * - If `dataFrame[0] == 0x01`, the function sets the actuators to a partially active state,
173 : : : * enabling some features while disabling others.
174 : : : * - For any other values in the data frame, the function sets the actuators to a default
175 : : : * inactive state, disabling all features except the door lock.
176 : : : *
177 : : : * @note This function is critical for ensuring that the actuators' state reflects the
178 : : : * commands received via CAN messages. It is called by `actuatorsTranslateCanMsg`
179 : : : * when a valid message with the identifier `ID_AEB_S` is received.
180 : : : *
181 : : : * \anchor updateInternalActuatorsState
182 : : :
183 : : : *
184 : : : * @see actuatorsTranslateCanMsg
185 : : : */
186 : : 6 : void updateInternalActuatorsState(can_msg captured_frame)
187 : : : {
188 [ + + ]: [ T F ]: 6 : if (captured_frame.dataFrame[1] == 0x01)
189 : : : {
190 : : 4 : actuators_state.belt_tightness = true;
191 : : 4 : actuators_state.door_lock = false;
192 : : 4 : actuators_state.should_activate_abs = true;
193 : : 4 : actuators_state.alarm_led = true;
194 : : 4 : actuators_state.alarm_buzzer = true;
195 : : : }
196 [ + + ]: [ T F ]: 2 : else if (captured_frame.dataFrame[0] == 0x01)
197 : : : {
198 : : 1 : actuators_state.belt_tightness = false;
199 : : 1 : actuators_state.door_lock = true;
200 : : 1 : actuators_state.should_activate_abs = false;
201 : : 1 : actuators_state.alarm_led = true;
202 : : 1 : actuators_state.alarm_buzzer = true;
203 : : : }
204 : : : else
205 : : : {
206 : : 1 : actuators_state.belt_tightness = false;
207 : : 1 : actuators_state.door_lock = true;
208 : : 1 : actuators_state.should_activate_abs = false;
209 : : 1 : actuators_state.alarm_led = false;
210 : : 1 : actuators_state.alarm_buzzer = false;
211 : : : }
212 : : 6 : }
|