GCC Code Coverage Report


src/
File: pushbutton/pushbutton.c
Date: 2025-02-10 15:47:30
Lines:
136/136
100.0%
Functions:
21/21
100.0%
Branches:
40/43
93.0%

Line Branch Exec Source
1 /**
2 * @file pushbutton.c
3 * @author niwciu (niwciu@gmail.com)
4 * @brief This file contains the implementation of a pushbutton switch interface with debouncing and repetition
5 * functionality.
6 * @date 2024-02-26
7 *
8 * @copyright Copyright (c) 2024
9 *
10 */
11 #include "pushbutton.h"
12 #include <stddef.h>
13 // #include <stdio.h> // to tylko do printfa
14
15 static void update_pushbutton_input_state(PUSHBUTTON_TypDef *BUTTON);
16 static void update_button_deb_rep_counter(PUSHBUTTON_TypDef *BUTTON);
17 static void debounce_pushbutton_push_state(PUSHBUTTON_TypDef *BUTTON);
18 static void debounce_pushbutton_release_state(PUSHBUTTON_TypDef *BUTTON);
19 static void debounce_pushbutton_short_push_long_push_state(PUSHBUTTON_TypDef *BUTTON);
20
21 static void handle_push_debouncing(PUSHBUTTON_TypDef *BUTTON);
22 static void handle_long_push_no_repetition_phase(PUSHBUTTON_TypDef *BUTTON);
23 static void handle_long_push_phase(PUSHBUTTON_TypDef *BUTTON);
24 static void handle_short_push_phase(PUSHBUTTON_TypDef *BUTTON);
25 static void handle_short_push_phase_pin_pushed(PUSHBUTTON_TypDef *BUTTON);
26 static void handle_short_push_phase_pin_released(PUSHBUTTON_TypDef *BUTTON);
27
28 static void execute_push_callback(PUSHBUTTON_TypDef *BUTTON);
29 static void execute_release_callback(PUSHBUTTON_TypDef *BUTTON);
30
31 1767 static void update_pushbutton_input_state(PUSHBUTTON_TypDef *BUTTON)
32 {
33 1767 BUTTON->input_state = BUTTON->GPIO_interface->get_button_input_state();
34 1767 }
35
36 18 static void update_button_deb_rep_counter(PUSHBUTTON_TypDef *BUTTON)
37 {
38
39
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18 if ((BUTTON->repetition) == REPETITION_ON)
40 {
41
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
15 if ((BUTTON->REPETITION_STATUS_FLAG) == REPETITION_INACTIVE)
42 {
43 6 BUTTON->deb_rep_timer = PUSHBUTTON_FIRST_REPETITION_TIME;
44 6 BUTTON->REPETITION_STATUS_FLAG = REPETITION_ACTIVE;
45 }
46 else
47 {
48 9 BUTTON->deb_rep_timer = PUSHBUTTON_CONTINUOUS_REPETITION_TIME;
49 }
50 }
51 else
52 {
53 3 BUTTON->deb_rep_timer = 0;
54 }
55 18 }
56
57 270 static void debounce_pushbutton_push_state(PUSHBUTTON_TypDef *BUTTON)
58 {
59
2/2
✓ Branch 0 taken 160 times.
✓ Branch 1 taken 110 times.
270 if ((BUTTON->input_state) == PUSHED)
60 {
61
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 142 times.
160 if ((BUTTON->deb_rep_timer) == 1)
62 {
63 18 execute_push_callback(BUTTON);
64 18 update_button_deb_rep_counter(BUTTON);
65 }
66 else
67 {
68 // Empty else statement for case when deb_rep_timer is different then 1
69 }
70 }
71 else
72 {
73 110 BUTTON->deb_rep_timer = PUSHBUTTON_DEBOUNCE_TIME;
74 110 BUTTON->REPETITION_STATUS_FLAG = REPETITION_INACTIVE;
75 }
76 270 }
77
78 237 static void debounce_pushbutton_release_state(PUSHBUTTON_TypDef *BUTTON)
79 {
80
2/2
✓ Branch 0 taken 115 times.
✓ Branch 1 taken 122 times.
237 if ((BUTTON->input_state) == PUSHED)
81 {
82 115 BUTTON->deb_rep_timer = PUSHBUTTON_DEBOUNCE_TIME;
83 }
84 else
85 {
86
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 119 times.
122 if ((BUTTON->deb_rep_timer) == 1)
87 {
88 3 execute_release_callback(BUTTON);
89 3 BUTTON->deb_rep_timer = 0;
90 }
91 else
92 {
93 // Empty else statement for case when deb_rep_timer is different then 1
94 }
95 }
96 237 }
97
98 1260 void debounce_pushbutton_short_push_long_push_state(PUSHBUTTON_TypDef *BUTTON)
99 {
100
5/6
✓ Branch 0 taken 624 times.
✓ Branch 1 taken 504 times.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
1260 switch (BUTTON->pushbutton_state_machine)
101 {
102 624 case BUTTON_RELEASED:
103
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 426 times.
624 if ((BUTTON->input_state) == PUSHED)
104 {
105 198 BUTTON->pushbutton_state_machine = PUSH_DEBOUNCING;
106 198 BUTTON->deb_rep_timer = PUSHBUTTON_DEBOUNCE_TIME;
107 }
108 624 break;
109 504 case PUSH_DEBOUNCING:
110 504 handle_push_debouncing(BUTTON);
111 504 break;
112 84 case SHORT_PUSH_PHASE:
113 84 handle_short_push_phase(BUTTON);
114 84 break;
115 24 case LONG_PUSH_PHASE:
116 24 handle_long_push_phase(BUTTON);
117 24 break;
118 24 case LONG_PUSH_NO_REPETITION_PHASE:
119 24 handle_long_push_no_repetition_phase(BUTTON);
120 24 break;
121 }
122 1260 }
123 504 static void handle_push_debouncing(PUSHBUTTON_TypDef *BUTTON)
124 {
125
2/2
✓ Branch 0 taken 321 times.
✓ Branch 1 taken 183 times.
504 if ((BUTTON->input_state) == PUSHED)
126 {
127
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 306 times.
321 if ((BUTTON->deb_rep_timer) == 0)
128 {
129 15 BUTTON->pushbutton_state_machine = SHORT_PUSH_PHASE;
130 15 BUTTON->deb_rep_timer = PUSHBUTTON_SHORT_PUSH_TIME_MAX;
131 }
132 }
133 else
134 {
135 183 BUTTON->pushbutton_state_machine = BUTTON_RELEASED;
136 }
137 504 }
138 24 static void handle_long_push_no_repetition_phase(PUSHBUTTON_TypDef *BUTTON)
139 {
140
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 21 times.
24 if ((BUTTON->input_state) == RELEASED)
141 {
142 3 BUTTON->pushbutton_state_machine = BUTTON_RELEASED;
143 }
144 else
145 {
146 21 BUTTON->pushbutton_state_machine = LONG_PUSH_NO_REPETITION_PHASE;
147 }
148 24 }
149
150 24 static void handle_long_push_phase(PUSHBUTTON_TypDef *BUTTON)
151 {
152
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 3 times.
24 if ((BUTTON->input_state) == PUSHED)
153 {
154
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 18 times.
21 if ((BUTTON->deb_rep_timer) == 0)
155 {
156 3 execute_push_callback(BUTTON);
157 3 BUTTON->deb_rep_timer = PUSHBUTTON_CONTINUOUS_REPETITION_TIME;
158 }
159 }
160 else
161 {
162 3 BUTTON->deb_rep_timer = PUSHBUTTON_DEBOUNCE_TIME;
163 3 BUTTON->pushbutton_state_machine = BUTTON_RELEASED;
164 }
165 24 }
166
167 84 static void handle_short_push_phase(PUSHBUTTON_TypDef *BUTTON)
168 {
169
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 9 times.
84 if ((BUTTON->input_state) == PUSHED)
170 {
171 75 handle_short_push_phase_pin_pushed(BUTTON);
172 }
173 else
174 {
175 9 handle_short_push_phase_pin_released(BUTTON);
176 }
177 84 }
178
179 75 static void handle_short_push_phase_pin_pushed(PUSHBUTTON_TypDef *BUTTON)
180 {
181
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 69 times.
75 if ((BUTTON->deb_rep_timer) == 0)
182 {
183 6 execute_push_callback(BUTTON);
184
185
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (BUTTON->repetition == REPETITION_ON)
186 {
187 3 BUTTON->pushbutton_state_machine = LONG_PUSH_PHASE;
188 3 BUTTON->deb_rep_timer = PUSHBUTTON_FIRST_REPETITION_TIME;
189 }
190 else
191 {
192 3 BUTTON->pushbutton_state_machine = LONG_PUSH_NO_REPETITION_PHASE;
193 }
194 }
195 75 }
196
197 9 static void handle_short_push_phase_pin_released(PUSHBUTTON_TypDef *BUTTON)
198 {
199 9 execute_release_callback(BUTTON);
200 9 BUTTON->deb_rep_timer = PUSHBUTTON_DEBOUNCE_TIME;
201 9 BUTTON->pushbutton_state_machine = BUTTON_RELEASED;
202 9 }
203
204 27 static void execute_push_callback(PUSHBUTTON_TypDef *BUTTON)
205 {
206
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 if (BUTTON->push_callback != NULL)
207 {
208 27 BUTTON->push_callback(); // push callback to instancja gdzie trzeba zaerejsrować long push
209 }
210 27 }
211
212 12 static void execute_release_callback(PUSHBUTTON_TypDef *BUTTON)
213 {
214
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (BUTTON->release_callback != NULL)
215 {
216 12 BUTTON->release_callback(); // push callback to instancja gdzie trzeba zaerejsrować long push
217 }
218 12 }
219 /**
220 * @brief Initializes pushbuttons.
221 *
222 * This function initializes pushbuttons by obtaining GPIO interfaces,
223 * calling their initialization functions, and setting up the necessary configurations.
224 *
225 * The initialization includes:
226 * - Retrieving GPIO interfaces for PUSHBUTTON.
227 * - Calling the initialization function for each pushbutton through the obtained GPIO interfaces.
228 * - Setting the initial state of the state machines for PUSHBUTTON to BUTTON_RELEASED.
229 *
230 * @param BUTTON Pointer to the pushbutton structure to initialize.
231 * @param PB_repetition_mode The repetition mode for the pushbutton ::PB_repetition_t.
232 * @param PB_triger_mode The trigger mode for the pushbutton events ::PB_trigger_mode_t.
233 * @param PB_get_driver_interface_adr_callback Callback function to obtain GPIO interface address.
234 *
235 *
236 */
237 60 void init_pushbutton(PUSHBUTTON_TypDef *BUTTON,
238 const PB_repetition_t PB_repetition_mode,
239 const PB_trigger_mode_t PB_triger_mode,
240 const PB_GPIO_interface_get_callback PB_get_driver_interface_adr_callback)
241 {
242 60 BUTTON->GPIO_interface = PB_get_driver_interface_adr_callback();
243
244 60 BUTTON->GPIO_interface->GPIO_init();
245 60 BUTTON->repetition = PB_repetition_mode;
246 60 BUTTON->trigger_mode = PB_triger_mode;
247
248 // init other parameters of the structure to default init value
249 60 BUTTON->deb_rep_timer = 0;
250 60 BUTTON->pushbutton_state_machine = BUTTON_RELEASED;
251 60 BUTTON->input_state = UNKNOWN;
252 60 BUTTON->REPETITION_STATUS_FLAG = REPETITION_INACTIVE;
253 60 BUTTON->push_callback = NULL;
254 60 BUTTON->release_callback = NULL;
255 60 }
256
257 /**
258 * @brief Checks the state of a pushbutton and performs debouncing based on the trigger mode.
259 *
260 * This function updates the input state of the specified pushbutton, then determines the trigger mode
261 * and invokes the corresponding debouncing function. The debouncing process ensures reliable detection
262 * of pushbutton events, such as push, release, short push, or long push, based on the configured trigger mode.
263 *
264 * @param BUTTON The pushbutton structure to check and debounce.
265 *
266 * @note Before calling this function, ensure that the pushbutton has been properly initialized using the
267 * @ref init_pushbutton function.
268 *
269 * @see init_pushbutton, update_pushbutton_input_state, debounce_pushbutton_push_state,
270 * debounce_pushbutton_release_state, debounce_pushbutton_short_push_long_push_state
271 */
272 1767 void check_pushbutton(PUSHBUTTON_TypDef *BUTTON)
273 {
274 1767 update_pushbutton_input_state(BUTTON);
275
3/3
✓ Branch 0 taken 270 times.
✓ Branch 1 taken 237 times.
✓ Branch 2 taken 1260 times.
1767 switch (BUTTON->trigger_mode)
276 {
277 270 case TRIGGER_ON_PUSH:
278 270 debounce_pushbutton_push_state(BUTTON);
279 270 break;
280 237 case TRIGGER_ON_RELEASE:
281 237 debounce_pushbutton_release_state(BUTTON);
282 237 break;
283 1260 default:
284 1260 debounce_pushbutton_short_push_long_push_state(BUTTON);
285 1260 break;
286 }
287 1767 }
288
289 /**
290 * @brief Registers a callback function to be called on pushbutton press.
291 *
292 * This function associates a callback function with the specified pushbutton,
293 * to be executed when the pushbutton is pressed. The callback is triggered
294 * by changes in the pushbutton state from released to pressed.
295 *
296 * @param button_name The name of the pushbutton to register the callback for. Use values from #pushbutton_name_t
297 * enumeration.
298 * @param callback_on_push The callback function to be executed on push.
299 *
300 * @note If the pushbutton is not registered, this function has no effect.
301 *
302 * @warning Avoid lengthy operations or blocking code in the callback function, as it may impact the responsiveness
303 * of the system.
304 */
305 10 void register_button_push_callback(PUSHBUTTON_TypDef *BUTTON, PB_callback_t callback_on_push)
306 {
307 10 BUTTON->push_callback = callback_on_push;
308 10 }
309
310 /**
311 * @brief Registers a callback function to be called on pushbutton release.
312 *
313 * This function associates a callback function with the specified pushbutton,
314 * to be executed when the pushbutton is released. The callback is triggered by
315 * changes in the pushbutton state from pressed to released.
316 *
317 * @param button_name The name of the pushbutton to register the release callback for. Use values from
318 * #pushbutton_name_t enumeration.
319 * @param callback_on_button_release The callback function to be executed on pushbutton release.
320 *
321 * @note If the pushbutton is not registered, this function has no effect.
322 *
323 * @warning Avoid lengthy operations or blocking code in the release callback function, as it may impact the
324 * responsiveness of the system.
325 */
326 5 void register_button_release_callback(PUSHBUTTON_TypDef *BUTTON, PB_callback_t callback_on_button_release)
327 {
328 5 BUTTON->release_callback = callback_on_button_release;
329 5 }
330
331 /**
332 * @brief Registers callback functions for short push and long push events on a pushbutton.
333 *
334 * This function associates callback functions with the specified pushbutton,
335 * to be executed when short push and long push events occur. The short push callback
336 * is triggered when the pushbutton is released quickly, and the long push callback is
337 * triggered when the pushbutton is held down for an extended period.
338 *
339 * @param button_name The name of the pushbutton to register the callbacks for. Use values from #pushbutton_name_t
340 * enumeration.
341 * @param callback_on_short_push The callback function to be executed on a short push event.
342 * @param callback_on_long_push The callback function to be executed on a long push event.
343 *
344 * @note If the pushbutton is not registered, this function has no effect.
345 *
346 * @warning Avoid lengthy operations or blocking code in the callback functions, as it may impact the
347 * responsiveness of the system.
348 */
349 18 void register_button_short_push_long_push_callbacks(PUSHBUTTON_TypDef *BUTTON, PB_callback_t callback_on_short_push, PB_callback_t callback_on_long_push)
350 {
351 18 BUTTON->release_callback = callback_on_short_push;
352 18 BUTTON->push_callback = callback_on_long_push;
353 18 }
354
355 /**
356 * @brief Enables pushbutton repetition.
357 *
358 * This function enables pushbutton repetition for the specified pushbutton.
359 *
360 * @param button_name The name of the pushbutton to enable repetition for. Use values from #pushbutton_name_t
361 * enumeration.
362 *
363 * @note If the pushbutton is not registered, this function has no effect.
364 */
365 9 void enable_pusbutton_repetition(PUSHBUTTON_TypDef *BUTTON)
366 {
367 9 BUTTON->repetition = REPETITION_ON;
368 9 }
369
370 /**
371 * @brief Disables pushbutton repetition.
372 *
373 * This function disables pushbutton repetition for the specified pushbutton.
374 *
375 * @param button_name The name of the pushbutton to disable repetition for. Use values from #pushbutton_name_t
376 * enumeration.
377 *
378 * @note If the pushbutton is not registered, this function has no effect.
379 */
380 19 void disable_pusbutton_repetition(PUSHBUTTON_TypDef *BUTTON)
381 {
382 19 BUTTON->repetition = REPETITION_OFF;
383 19 }
384
385 /**
386 * @brief Decrements the debounce and repetition timer of a pushbutton.
387 *
388 * This function decrements the debounce and repetition timer of the specified pushbutton
389 * if the pushbutton is valid and the timer is non-zero. This is typically used in the
390 * context of pushbutton debouncing and repetition control.
391 *
392 * @param button_name The name of the pushbutton to decrement the timer for. Use values from #pushbutton_name_t
393 * enumeration.
394 *
395 * @note Make sure to register the pushbutton with the system before using this function.
396 * The pushbutton state will be updated based on the specified repetition type.
397 * If the pushbutton is not registered or the timer is already at zero, this function has no effect.
398 * It is the responsibility of the caller to manage the timing of this function appropriately.
399 */
400 34875 void dec_pushbutton_deb_rep_timer(PUSHBUTTON_TypDef *BUTTON)
401 {
402 34875 BUTTON->deb_rep_timer--;
403 34875 }
404