Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_button.c
1 #include <bc_button.h>
2 
3 #define _BC_BUTTON_SCAN_INTERVAL 20
4 #define _BC_BUTTON_DEBOUNCE_TIME 50
5 #define _BC_BUTTON_CLICK_TIMEOUT 500
6 #define _BC_BUTTON_HOLD_TIME 2000
7 
8 static void _bc_button_task(void *param);
9 
10 static void _bc_button_gpio_init(bc_button_t *self);
11 
12 static int _bc_button_gpio_get_input(bc_button_t *self);
13 
14 static const bc_button_driver_t _bc_button_driver_gpio =
15 {
16  .init = _bc_button_gpio_init,
17  .get_input = _bc_button_gpio_get_input,
18 };
19 
20 void bc_button_init(bc_button_t *self, bc_gpio_channel_t gpio_channel, bc_gpio_pull_t gpio_pull, int idle_state)
21 {
22  memset(self, 0, sizeof(*self));
23 
24  self->_channel.gpio = gpio_channel;
25  self->_gpio_pull = gpio_pull;
26  self->_idle_state = idle_state;
27 
28  self->_scan_interval = _BC_BUTTON_SCAN_INTERVAL;
29  self->_debounce_time = _BC_BUTTON_DEBOUNCE_TIME;
30  self->_click_timeout = _BC_BUTTON_CLICK_TIMEOUT;
31  self->_hold_time = _BC_BUTTON_HOLD_TIME;
32  self->_tick_debounce = BC_TICK_INFINITY;
33 
34  self->_driver = &_bc_button_driver_gpio;
35  self->_driver->init(self);
36 
37  bc_gpio_set_pull(self->_channel.gpio, self->_gpio_pull);
38  bc_gpio_set_mode(self->_channel.gpio, BC_GPIO_MODE_INPUT);
39 
40  self->_task_id = bc_scheduler_register(_bc_button_task, self, BC_TICK_INFINITY);
41 }
42 
43 void bc_button_init_virtual(bc_button_t *self, int channel, const bc_button_driver_t *driver, int idle_state)
44 {
45  memset(self, 0, sizeof(*self));
46 
47  self->_channel.virtual = channel;
48  self->_idle_state = idle_state;
49 
50  self->_scan_interval = _BC_BUTTON_SCAN_INTERVAL;
51  self->_debounce_time = _BC_BUTTON_DEBOUNCE_TIME;
52  self->_click_timeout = _BC_BUTTON_CLICK_TIMEOUT;
53  self->_hold_time = _BC_BUTTON_HOLD_TIME;
54  self->_tick_debounce = BC_TICK_INFINITY;
55 
56  self->_driver = driver;
57 
58  if (self->_driver->init != NULL)
59  {
60  self->_driver->init(self);
61  }
62 
63  self->_task_id = bc_scheduler_register(_bc_button_task, self, BC_TICK_INFINITY);
64 }
65 
66 void bc_button_set_event_handler(bc_button_t *self, void (*event_handler)(bc_button_t *, bc_button_event_t, void *), void *event_param)
67 {
68  self->_event_handler = event_handler;
69  self->_event_param = event_param;
70 
71  if (event_handler == NULL)
72  {
73  self->_tick_debounce = BC_TICK_INFINITY;
74 
76  }
77  else
78  {
79  bc_scheduler_plan_now(self->_task_id);
80  }
81 }
82 
84 {
85  self->_scan_interval = scan_interval;
86 }
87 
89 {
90  self->_debounce_time = debounce_time;
91 }
92 
94 {
95  self->_click_timeout = click_timeout;
96 }
97 
99 {
100  self->_hold_time = hold_time;
101 }
102 
103 static void _bc_button_task(void *param)
104 {
105  bc_button_t *self = param;
106 
108 
109  int pin_state;
110 
111  if (self->_driver->get_input != NULL)
112  {
113  pin_state = self->_driver->get_input(self);
114  }
115  else
116  {
117  pin_state = self->_idle_state;
118  }
119 
120  if (self->_idle_state)
121  {
122  pin_state = pin_state == 0 ? 1 : 0;
123  }
124 
125  if ((self->_state == 0 && pin_state != 0) || (self->_state != 0 && pin_state == 0))
126  {
127  if (self->_tick_debounce == BC_TICK_INFINITY)
128  {
129  self->_tick_debounce = tick_now + self->_debounce_time;
130  }
131 
132  if (tick_now >= self->_tick_debounce)
133  {
134  self->_state = self->_state == 0 ? 1 : 0;
135 
136  if (self->_state != 0)
137  {
138  self->_tick_click_timeout = tick_now + self->_click_timeout;
139  self->_tick_hold_threshold = tick_now + self->_hold_time;
140  self->_hold_signalized = false;
141 
142  if (self->_event_handler != NULL)
143  {
144  self->_event_handler(self, BC_BUTTON_EVENT_PRESS, self->_event_param);
145  }
146  }
147  else
148  {
149  if (self->_event_handler != NULL)
150  {
151  self->_event_handler(self, BC_BUTTON_EVENT_RELEASE, self->_event_param);
152  }
153 
154  if (tick_now < self->_tick_click_timeout)
155  {
156  if (self->_event_handler != NULL)
157  {
158  self->_event_handler(self, BC_BUTTON_EVENT_CLICK, self->_event_param);
159  }
160  }
161  }
162  }
163  }
164  else
165  {
166  self->_tick_debounce = BC_TICK_INFINITY;
167  }
168 
169  if (self->_state != 0)
170  {
171  if (!self->_hold_signalized)
172  {
173  if (tick_now >= self->_tick_hold_threshold)
174  {
175  self->_hold_signalized = true;
176 
177  if (self->_event_handler != NULL)
178  {
179  self->_event_handler(self, BC_BUTTON_EVENT_HOLD, self->_event_param);
180  }
181  }
182  }
183  }
184 
185  bc_scheduler_plan_current_relative(self->_scan_interval);
186 }
187 
188 static void _bc_button_gpio_init(bc_button_t *self)
189 {
190  bc_gpio_init(self->_channel.gpio);
191 }
192 
193 static int _bc_button_gpio_get_input(bc_button_t *self)
194 {
195  return bc_gpio_get_input(self->_channel.gpio);
196 }
uint64_t bc_tick_t
Timestamp data type.
Definition: bc_tick.h:16
void bc_button_set_hold_time(bc_button_t *self, bc_tick_t hold_time)
Set hold time (interval after which hold event is recognized when button is steadily pressed) ...
Definition: bc_button.c:98
Button driver interface.
Definition: bc_button.h:36
void bc_scheduler_plan_absolute(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to absolute tick.
Definition: bc_scheduler.c:124
bc_tick_t bc_scheduler_get_spin_tick(void)
Get current tick of spin in which task has been run.
Definition: bc_scheduler.c:104
Event button released.
Definition: bc_button.h:20
Event button pressed.
Definition: bc_button.h:17
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
void bc_scheduler_plan_now(bc_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
Definition: bc_scheduler.c:119
void(* init)(bc_button_t *self)
Callback for initialization.
Definition: bc_button.h:39
void bc_gpio_set_mode(bc_gpio_channel_t channel, bc_gpio_mode_t mode)
Set mode of operation for GPIO channel.
Definition: bc_gpio.c:340
void bc_gpio_set_pull(bc_gpio_channel_t channel, bc_gpio_pull_t pull)
Set pull-up/pull-down configuration for GPIO channel.
Definition: bc_gpio.c:313
bc_gpio_pull_t
GPIO pull-up/pull-down setting.
Definition: bc_gpio.h:81
void bc_scheduler_plan_current_relative(bc_tick_t tick)
Schedule current task to tick relative from current spin.
Definition: bc_scheduler.c:149
int bc_gpio_get_input(bc_gpio_channel_t channel)
Get input state for GPIO channel.
Definition: bc_gpio.c:436
GPIO channel operates as input.
Definition: bc_gpio.h:99
bc_button_event_t
Callback events.
Definition: bc_button.h:14
Event button hold (pressed for longer time)
Definition: bc_button.h:26
void bc_button_set_scan_interval(bc_button_t *self, bc_tick_t scan_interval)
Set scan interval (period of button input sampling)
Definition: bc_button.c:83
void bc_button_init_virtual(bc_button_t *self, int channel, const bc_button_driver_t *driver, int idle_state)
Initialize virtual button.
Definition: bc_button.c:43
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
bc_gpio_channel_t
GPIO channels.
Definition: bc_gpio.h:12
Event button clicked (pressed and released within certain time)
Definition: bc_button.h:23
void bc_button_set_event_handler(bc_button_t *self, void(*event_handler)(bc_button_t *, bc_button_event_t, void *), void *event_param)
Set callback function.
Definition: bc_button.c:66
void bc_button_set_debounce_time(bc_button_t *self, bc_tick_t debounce_time)
Set debounce time (minimum sampling interval during which input cannot change to toggle its state) ...
Definition: bc_button.c:88
struct bc_button_t bc_button_t
Button instance.
Definition: bc_button.h:32
void bc_button_set_click_timeout(bc_button_t *self, bc_tick_t click_timeout)
Set click timeout (maximum interval within which button has to be released to recognize click event) ...
Definition: bc_button.c:93
void bc_button_init(bc_button_t *self, bc_gpio_channel_t gpio_channel, bc_gpio_pull_t gpio_pull, int idle_state)
Initialize button.
Definition: bc_button.c:20
void bc_gpio_init(bc_gpio_channel_t channel)
Initialize GPIO channel.
Definition: bc_gpio.c:301