GPS Device
Loading...
Searching...
No Matches
Button Public API

Public functions to interact with the button subsystem. More...

Collaboration diagram for Button Public API:

Functions

ERR_te button_init_subsys (void)
 Initializes the button subsystem.
ERR_te button_deinit_subsys (void)
 Deinitializes the button subsystem.
ERR_te button_start_subsys (void)
 Starts the button subsystem.
ERR_te button_stop_subsys (void)
 Stops the button subsystem.
ERR_te button_init_handle (BUTTON_CFG_ts *button_cfg, BUTTON_HANDLE_ts **button_handle)
 Initializes and registers a button handle.
ERR_te button_deinit_handle (BUTTON_HANDLE_ts const *button_handle)
 Deinitializes a button handle.
ERR_te button_run_handle (BUTTON_HANDLE_ts *button_handle)
 Executes the state machine for a single button.
ERR_te button_run_handle_all (void)
 Runs the state machine for all registered buttons.
ERR_te button_get_pushed_state (BUTTON_HANDLE_ts const *button_handle, bool *pushed_state_o)
 Retrieves the pushed (pressed) state of a button.
ERR_te button_get_held_state (BUTTON_HANDLE_ts const *button_handle, bool *held_state_o)
 Retrieves the held state of a button.

Detailed Description

Public functions to interact with the button subsystem.

Function Documentation

◆ button_init_subsys()

ERR_te button_init_subsys ( void )

Initializes the button subsystem.

This function initializes the internal state of the button module, sets up required dependencies, and registers subsystem commands.

It must be called before using any other button API functions.

Returns
  • ERR_OK on success
  • ERR_INITIALIZATION_FAILURE if the subsystem is already initialized
  • Other error codes depending on internal failures
Note
This function should only be called once during system startup.
See also
button_init_subsys

Definition at line 159 of file button.c.

159 {
160 ERR_te err;
161
162 if(internal_state.initialized) {
164 }
165
166 internal_state = (struct internal_state_s){ 0 };
167
168 internal_state.log_level = LOG_LEVEL_INFO;
170 internal_state.initialized = true;
171 internal_state.started = false;
172
173 init_log();
174 init_systick();
175
177 if(err != ERR_OK) {
178 LOG_ERROR(
179 internal_state.subsys,
180 internal_state.log_level,
181 "button_init_subsys: cmd_register error"
182 );
183
184 return err;
185 }
186 LOG_INFO(
187 internal_state.subsys,
188 internal_state.log_level,
189 "button_init_subsys: subsys initialized"
190 );
191
192 return ERR_OK;
193}
static struct internal_state_s internal_state
Singleton instance of the SysTick driver internal state.
static CMD_CLIENT_INFO_ts button_cmd_client_info
Registration descriptor passed to the command subsystem.
Definition button.c:146
ERR_te cmd_register(CMD_CLIENT_INFO_ts *cmd_client_info)
Registers a client with the command subsystem.
Definition cmd.c:51
ERR_te
Standard return type used by all public API functions.
Definition err.h:35
@ ERR_OK
Definition err.h:36
@ ERR_INITIALIZATION_FAILURE
Definition err.h:43
ERR_te init_log(void)
Initializes the logging subsystem.
Definition init.c:25
ERR_te init_systick(void)
Initializes the SysTick timer.
Definition init.c:40
#define LOG_ERROR(subsys, lvl, fmt,...)
Definition log.h:258
#define LOG_INFO(subsys, lvl, fmt,...)
Definition log.h:255
@ LOG_LEVEL_INFO
Definition log.h:64
@ MODULES_BUTTON
Definition modules.h:47
Internal state of the SysTick driver.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ button_deinit_subsys()

ERR_te button_deinit_subsys ( void )

Deinitializes the button subsystem.

This function resets the internal state of the button subsystem and deregisters previously registered commands.

It must only be called after the subsystem has been initialized and fully stopped.

Returns
  • ERR_OK on success
  • ERR_DEINITIALIZATION_FAILURE if the subsystem is still running or not initialized
Note
All button handles must be deinitialized before calling this function.
See also
button_deinit_subsys

Definition at line 196 of file button.c.

196 {
197 if(internal_state.initialized && !internal_state.started) {
198 internal_state = (struct internal_state_s){ 0 };
199
201 }
202 else {
203 LOG_ERROR(
204 internal_state.subsys,
205 internal_state.log_level,
206 "button_deinit_subsys: subsys is not initialized or not stopped"
207 );
208
210 }
211 LOG_INFO(
212 internal_state.subsys,
213 internal_state.log_level,
214 "button_deinit_subsys: subsys deinitialized"
215 );
216
217 return ERR_OK;
218}
ERR_te cmd_deregister(CMD_CLIENT_INFO_ts const *cmd_client_info)
Deregisters a client from the command subsystem.
Definition cmd.c:66
@ ERR_DEINITIALIZATION_FAILURE
Definition err.h:44
Here is the call graph for this function:

◆ button_start_subsys()

ERR_te button_start_subsys ( void )

Starts the button subsystem.

Enables runtime processing of button handles. After calling this function, button state updates via button_run_handle() or button_run_handle_all() are allowed.

Returns
  • ERR_OK on success
  • ERR_UNKNOWN if the subsystem is not initialized or already started
Note
Must be called after button_init_subsys().
See also
button_start_subsys

Definition at line 221 of file button.c.

221 {
222 if(internal_state.initialized && !internal_state.started) {
223 internal_state.started = true;
224
225 LOG_INFO(
226 internal_state.subsys,
227 internal_state.log_level,
228 "button_start_subsys: subsys started"
229 );
230 }
231 else {
232 LOG_ERROR(
233 internal_state.subsys,
234 internal_state.log_level,
235 "button_start_subsys: subsys not initialized or already started"
236 );
237
238 return ERR_UNKNOWN;
239 }
240
241 return ERR_OK;
242}
@ ERR_UNKNOWN
Definition err.h:37
Here is the caller graph for this function:

◆ button_stop_subsys()

ERR_te button_stop_subsys ( void )

Stops the button subsystem.

Disables runtime processing of button handles. After calling this function, no button state updates should be performed.

Returns
  • ERR_OK on success
  • ERR_UNKNOWN if the subsystem is not initialized or already stopped
Note
Call this before deinitializing the subsystem or handles.
See also
button_stop_subsys

Definition at line 245 of file button.c.

245 {
246 if(internal_state.initialized && internal_state.started) {
247 internal_state.started = false;
248
249 LOG_INFO(
250 internal_state.subsys,
251 internal_state.log_level,
252 "button_stop_subsys: subsys stopped"
253 );
254 }
255 else {
256 LOG_ERROR(
257 internal_state.subsys,
258 internal_state.log_level,
259 "button_stop_subsys: subsys not initialized or already already stopped"
260 );
261
262 return ERR_UNKNOWN;
263 }
264
265 return ERR_OK;
266}

◆ button_init_handle()

ERR_te button_init_handle ( BUTTON_CFG_ts * button_cfg,
BUTTON_HANDLE_ts ** button_handle_o )

Initializes and registers a button handle.

Configures the GPIO associated with the button and allocates an internal handle from the subsystem pool.

The returned handle must be used for all subsequent operations on the button.

Parameters
[in]button_cfgPointer to the button configuration structure.
[out]button_handle_oPointer to a handle pointer that will be set to the allocated button instance.
Returns
  • ERR_OK on success
  • ERR_UNINITIALZIED_OBJECT if the subsystem is not initialized
  • ERR_NOT_ENOUGH_SPACE if the maximum number of buttons is reached
  • ERR_INVALID_ARGUMENT if input arguments are NULL
Note
GPIO is configured internally as input during initialization.
See also
button_init_handle

Definition at line 269 of file button.c.

269 {
270 if(!internal_state.initialized) {
271 LOG_INFO(
272 internal_state.subsys,
273 internal_state.log_level,
274 "button_init_handle: subsys not initialized"
275 );
276
278 }
279
280 if(internal_state.button_num == CONFIG_BUTTON_MAX_OBJECTS) {
281 LOG_ERROR(
282 internal_state.subsys,
283 internal_state.log_level,
284 "button_init_handle: subsystem out of memory space"
285 );
286
288 }
289
290 if(!button_cfg) {
291 LOG_ERROR(
292 internal_state.subsys,
293 internal_state.log_level,
294 "button_init_handle: invalid argument"
295 );
297 }
298
299 GPIO_CFG_ts gpio = { 0 };
300 gpio.port = button_cfg->gpio_port;
301 gpio.pin = button_cfg->gpio_pin;
303 gpio.mode = GPIO_MODE_INPUT;
304
305 gpio_init(&gpio);
306
307 for(uint32_t i = 0; i < CONFIG_BUTTON_MAX_OBJECTS; i++) {
308 if(internal_state.buttons[i].in_use == false) {
309 str_cpy(
310 internal_state.buttons[i].name,
311 button_cfg->name,
312 get_str_len(button_cfg->name) + 1
313 );
314
315 internal_state.buttons[i].debounce_limit_ms = button_cfg->debounce_limit_ms;
316 internal_state.buttons[i].gpio_port = button_cfg->gpio_port;
317 internal_state.buttons[i].gpio_pin = button_cfg->gpio_pin;
318 internal_state.buttons[i].pushed_type = button_cfg->pushed_type;
319 internal_state.buttons[i].held_limit_ms = button_cfg->held_limit_ms;
320 internal_state.buttons[i].held = false;
321 internal_state.buttons[i].held_started_ms = 0;
322 internal_state.buttons[i].debounce_started = false;
323 internal_state.buttons[i].held_started = false;
324 internal_state.buttons[i].pushed = false;
325 internal_state.buttons[i].debounce_started_ms = 0;
326 internal_state.buttons[i].in_use = true;
327
328 *button_handle_o = &internal_state.buttons[i];
329
330 internal_state.button_num++;
331
332 LOG_INFO(
333 internal_state.subsys,
334 internal_state.log_level,
335 "button_init_handle: button handle %s initialized",
336 internal_state.buttons[i].name
337 );
338
339 break;
340 }
341 }
342
343 return ERR_OK;
344}
int str_cpy(char *str_to, const char *str_from, uint32_t len)
Copies a null-terminated string into a destination buffer.
Definition common.c:333
uint32_t get_str_len(char const *str)
Returns the length of a string, excluding the null terminator.
Definition common.c:22
@ ERR_UNINITIALZIED_OBJECT
Definition err.h:42
@ ERR_NOT_ENOUGH_SPACE
Definition err.h:49
@ ERR_INVALID_ARGUMENT
Definition err.h:38
void gpio_init(GPIO_CFG_ts *gpio_cfg)
Initializes a GPIO pin according to the given configuration.
@ GPIO_OUTPUT_TYPE_PUSHPULL
@ GPIO_MODE_INPUT
uint32_t debounce_limit_ms
Definition button.h:94
uint32_t held_limit_ms
Definition button.h:97
char name[CONFIG_BUTTON_MAX_NAME_LEN]
Definition button.h:78
GPIO_PIN_te gpio_pin
Definition button.h:84
GPIO_REGDEF_ts * gpio_port
Definition button.h:81
BUTTON_PUSHED_TYPE_te pushed_type
Definition button.h:91
Configuration structure for initializing a GPIO pin.
GPIO_REGDEF_ts * port
GPIO_OUTPUT_TYPE_te output_type
GPIO_PIN_te pin
GPIO_MODE_te mode
Here is the call graph for this function:
Here is the caller graph for this function:

◆ button_deinit_handle()

ERR_te button_deinit_handle ( BUTTON_HANDLE_ts const * button_handle)

Deinitializes a button handle.

Releases the internal resources associated with the given button handle and marks the slot as available for reuse.

Parameters
[in]button_handlePointer to the button handle to deinitialize.
Returns
  • ERR_OK on success
  • ERR_ILLEGAL_ACTION if the subsystem is still running
  • ERR_UNINITIALZIED_OBJECT if the handle is invalid or not found
Note
The subsystem must be stopped before calling this function.
See also
button_deinit_handle

Definition at line 347 of file button.c.

347 {
348 if(internal_state.started) {
349 LOG_INFO(
350 internal_state.subsys,
351 internal_state.log_level,
352 "button_deinit_handle: subsys not stopped"
353 );
354 return ERR_ILLEGAL_ACTION;
355 }
356
357 if(internal_state.button_num == 0) {
358 LOG_ERROR(
359 internal_state.subsys,
360 internal_state.log_level,
361 "button_deinit_handle: no such handle to deinitialize"
362 );
363
365 }
366
367 for(uint32_t i = 0; i < CONFIG_BUTTON_MAX_OBJECTS; i++) {
368 if(&internal_state.buttons[i] == button_handle) {
369 uint8_t name_len = get_str_len(internal_state.buttons[i].name) + 1;
370 char name[name_len];
371 str_cpy(name, internal_state.buttons[i].name, name_len);
372
373 internal_state.buttons[i] = (BUTTON_HANDLE_ts){ 0 };
374
375 internal_state.button_num--;
376
377 LOG_INFO(
378 internal_state.subsys,
379 internal_state.log_level,
380 "button_deinit_handle: io handle %s deinitialized",
381 name
382 );
383
384 break;
385 }
386
387 if(i == CONFIG_BUTTON_MAX_OBJECTS - 1) {
388 LOG_ERROR(
389 internal_state.subsys,
390 internal_state.log_level,
391 "button_deinit_handle: no such handle to deinitialize"
392 );
393
395 }
396 }
397
398 return ERR_OK;
399}
struct button_handle_s BUTTON_HANDLE_ts
Opaque handle representing a button instance.
Definition button.h:110
@ ERR_ILLEGAL_ACTION
Definition err.h:50
Here is the call graph for this function:

◆ button_run_handle()

ERR_te button_run_handle ( BUTTON_HANDLE_ts * button_handle)

Executes the state machine for a single button.

This function performs debounce handling, press detection, and hold detection for the specified button handle.

It should be called periodically (e.g., in a main loop or scheduler).

Parameters
[in,out]button_handlePointer to the button handle to process.
Returns
  • ERR_OK on success
  • ERR_UNKNOWN if the subsystem is not initialized or started
Note
Timing is based on the system tick (systick_get_ms()).

Executes the state machine for a single button.

See also
button_run_handle

Definition at line 402 of file button.c.

402 {
403 if(!internal_state.initialized || !internal_state.started) {
404 LOG_ERROR(
405 internal_state.subsys,
406 internal_state.log_level,
407 "button_run_handle: subsystem not initialized or started"
408 );
409
410 return ERR_UNKNOWN;
411 }
412
413 PIN_STATUS_te pin_status = gpio_read(button_handle->gpio_port, button_handle->gpio_pin);
414
415 // If the debounce has not yet been completed, complete it (if it's enabled)
416 if(button_handle->pushed == false) {
417 if((button_handle->pushed_type == BUTTON_PUSHED_TYPE_HIGH &&
418 pin_status == HIGH) ||
419 (button_handle->pushed_type == BUTTON_PUSHED_TYPE_LOW &&
420 pin_status == LOW)) {
421 uint32_t current_ms = systick_get_ms();
422
423 if(!button_handle->debounce_started) {
424 button_handle->debounce_started = true;
425 button_handle->debounce_started_ms = current_ms;
426 }
427
428 if(button_handle->debounce_started &&
429 current_ms - button_handle->debounce_started_ms >= button_handle->debounce_limit_ms) {
430 button_handle->pushed = true;
431 button_handle->debounce_started = false;
432 }
433 }
434 else {
435 if(button_handle->debounce_started) {
436 button_handle->debounce_started = false;
437 button_handle->debounce_started_ms = 0;
438 }
439 }
440 }
441
442 // If the held property is enabled, check if button is held for long enough
443 if(button_handle->pushed == true && button_handle->held == false) {
444 if((button_handle->pushed_type == BUTTON_PUSHED_TYPE_HIGH &&
445 pin_status == HIGH) ||
446 (button_handle->pushed_type == BUTTON_PUSHED_TYPE_LOW &&
447 pin_status == LOW)) {
448 uint32_t current_ms = systick_get_ms();
449
450 if(!button_handle->held_started) {
451 button_handle->held_started = true;
452 button_handle->held_started_ms = current_ms;
453 }
454
455 if(button_handle->held_started &&
456 current_ms - button_handle->held_started_ms >= button_handle->held_limit_ms) {
457 button_handle->held = true;
458 button_handle->held_started = false;
459 }
460 }
461 else {
462 if(button_handle->held_started) {
463 button_handle->held_started = false;
464 button_handle->held_started_ms = 0;
465 }
466 }
467 }
468
469 // If the button has been pushed, check for button release then restore states and counters
470 if(button_handle->pushed == true) {
471 if((button_handle->pushed_type == BUTTON_PUSHED_TYPE_HIGH &&
472 pin_status == LOW) ||
473 (button_handle->pushed_type == BUTTON_PUSHED_TYPE_LOW &&
474 pin_status == HIGH)) {
475 uint32_t current_ms = systick_get_ms();
476
477 if(!button_handle->debounce_started) {
478 button_handle->debounce_started = true;
479 button_handle->debounce_started_ms = current_ms;
480 }
481
482 if(button_handle->debounce_started &&
483 current_ms - button_handle->debounce_started_ms >= button_handle->debounce_limit_ms) {
484 button_handle->pushed = false;
485 button_handle->held = false;
486 button_handle->debounce_started = false;
487 button_handle->held_started = false;
488 }
489 }
490 else {
491 if(button_handle->debounce_started) {
492 button_handle->debounce_started = false;
493 button_handle->debounce_started_ms = 0;
494 }
495 }
496 }
497
498 return ERR_OK;
499}
@ BUTTON_PUSHED_TYPE_HIGH
Definition button.h:64
@ BUTTON_PUSHED_TYPE_LOW
Definition button.h:61
PIN_STATUS_te
Represents the logical level of a GPIO pin.
Definition common.h:84
@ HIGH
Definition common.h:89
@ LOW
Definition common.h:86
uint32_t systick_get_ms(void)
Returns the number of milliseconds elapsed since SysTick was initialized.
PIN_STATUS_te gpio_read(GPIO_REGDEF_ts const *gpio_port, uint8_t gpio_pin)
Reads the current logic level of a GPIO input pin.
bool held_started
Definition button.c:63
BUTTON_PUSHED_TYPE_te pushed_type
Definition button.c:45
uint32_t debounce_started_ms
Definition button.c:54
GPIO_REGDEF_ts * gpio_port
Definition button.c:39
uint32_t held_started_ms
Definition button.c:57
bool debounce_started
Definition button.c:60
GPIO_PIN_te gpio_pin
Definition button.c:42
uint32_t debounce_limit_ms
Definition button.c:48
uint32_t held_limit_ms
Definition button.c:51
Here is the call graph for this function:
Here is the caller graph for this function:

◆ button_run_handle_all()

ERR_te button_run_handle_all ( void )

Runs the state machine for all registered buttons.

Iterates over all active button handles and processes their state machines.

Returns

Runs the state machine for all registered buttons.

See also
button_run_handle_all

Definition at line 502 of file button.c.

502 {
503 for(uint32_t i = 0; i < CONFIG_BUTTON_MAX_OBJECTS; i++) {
504 if(internal_state.buttons[i].in_use == true) {
505 ERR_te err = button_run_handle(&internal_state.buttons[i]);
506 if(err != ERR_OK) {
507 return err;
508 }
509 }
510 }
511
512 return ERR_OK;
513}
ERR_te button_run_handle(BUTTON_HANDLE_ts *button_handle)
Runs the state machine for a single button handle.
Definition button.c:402
Here is the call graph for this function:
Here is the caller graph for this function:

◆ button_get_pushed_state()

ERR_te button_get_pushed_state ( BUTTON_HANDLE_ts const * button_handle,
bool * pushed_state_o )

Retrieves the pushed (pressed) state of a button.

Parameters
[in]button_handlePointer to the button handle.
[out]pushed_state_oPointer to a boolean that will receive the state.
Returns
  • ERR_OK on success
  • ERR_ILLEGAL_ACTION if the subsystem is not initialized or started
Note
The returned state reflects the debounced logical state.

Retrieves the pushed (pressed) state of a button.

See also
button_get_pushed_state

Definition at line 516 of file button.c.

516 {
517 if(!internal_state.initialized || !internal_state.started) {
518 LOG_ERROR(
519 internal_state.subsys,
520 internal_state.log_level,
521 "button_get_pushed_state: handle not initialized or subsystem not started"
522 );
523
524 return ERR_ILLEGAL_ACTION;
525 }
526
527 *pushed_state_o = button_handle->pushed;
528
529 return ERR_OK;
530}
Here is the caller graph for this function:

◆ button_get_held_state()

ERR_te button_get_held_state ( BUTTON_HANDLE_ts const * button_handle,
bool * held_state_o )

Retrieves the held state of a button.

Parameters
[in]button_handlePointer to the button handle.
[out]held_state_oPointer to a boolean that will receive the state.
Returns
  • ERR_OK on success
  • ERR_ILLEGAL_ACTION if the subsystem is not initialized or started
Note
The held state becomes true after the configured held time threshold.
See also
button_get_held_state

Definition at line 533 of file button.c.

533 {
534 if(!internal_state.initialized || !internal_state.started) {
535 LOG_ERROR(
536 internal_state.subsys,
537 internal_state.log_level,
538 "button_get_held_state: handle not initialized or subsystem not started"
539 );
540
541 return ERR_ILLEGAL_ACTION;
542 }
543
544 *held_state_o = button_handle->held;
545
546 return ERR_OK;
547}
Here is the caller graph for this function: