Firmware SDK
twr_button.c
1 #include <twr_button.h>
2 
3 #define _TWR_BUTTON_SCAN_INTERVAL 20
4 #define _TWR_BUTTON_DEBOUNCE_TIME 50
5 #define _TWR_BUTTON_CLICK_TIMEOUT 500
6 #define _TWR_BUTTON_HOLD_TIME 2000
7 
8 static void _twr_button_task(void *param);
9 
10 static void _twr_button_gpio_init(twr_button_t *self);
11 
12 static int _twr_button_gpio_get_input(twr_button_t *self);
13 
14 static const twr_button_driver_t _twr_button_driver_gpio =
15 {
16  .init = _twr_button_gpio_init,
17  .get_input = _twr_button_gpio_get_input,
18 };
19 
20 void twr_button_init(twr_button_t *self, twr_gpio_channel_t gpio_channel, twr_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 = _TWR_BUTTON_SCAN_INTERVAL;
29  self->_debounce_time = _TWR_BUTTON_DEBOUNCE_TIME;
30  self->_click_timeout = _TWR_BUTTON_CLICK_TIMEOUT;
31  self->_hold_time = _TWR_BUTTON_HOLD_TIME;
32  self->_tick_debounce = TWR_TICK_INFINITY;
33 
34  self->_driver = &_twr_button_driver_gpio;
35  self->_driver->init(self);
36 
37  twr_gpio_set_pull(self->_channel.gpio, self->_gpio_pull);
38  twr_gpio_set_mode(self->_channel.gpio, TWR_GPIO_MODE_INPUT);
39 
40  self->_task_id = twr_scheduler_register(_twr_button_task, self, TWR_TICK_INFINITY);
41 }
42 
43 void twr_button_init_virtual(twr_button_t *self, int channel, const twr_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 = _TWR_BUTTON_SCAN_INTERVAL;
51  self->_debounce_time = _TWR_BUTTON_DEBOUNCE_TIME;
52  self->_click_timeout = _TWR_BUTTON_CLICK_TIMEOUT;
53  self->_hold_time = _TWR_BUTTON_HOLD_TIME;
54  self->_tick_debounce = TWR_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 = twr_scheduler_register(_twr_button_task, self, TWR_TICK_INFINITY);
64 }
65 
66 void twr_button_set_event_handler(twr_button_t *self, void (*event_handler)(twr_button_t *, twr_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 = TWR_TICK_INFINITY;
74 
76  }
77  else
78  {
79  twr_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 _twr_button_task(void *param)
104 {
105  twr_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 == TWR_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, TWR_BUTTON_EVENT_PRESS, self->_event_param);
145  }
146  }
147  else
148  {
149  if (self->_event_handler != NULL)
150  {
151  self->_event_handler(self, TWR_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, TWR_BUTTON_EVENT_CLICK, self->_event_param);
159  }
160  }
161  }
162  }
163  }
164  else
165  {
166  self->_tick_debounce = TWR_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, TWR_BUTTON_EVENT_HOLD, self->_event_param);
180  }
181  }
182  }
183  }
184 
185  twr_scheduler_plan_current_relative(self->_scan_interval);
186 }
187 
188 static void _twr_button_gpio_init(twr_button_t *self)
189 {
190  twr_gpio_init(self->_channel.gpio);
191 }
192 
193 static int _twr_button_gpio_get_input(twr_button_t *self)
194 {
195  return twr_gpio_get_input(self->_channel.gpio);
196 }
struct twr_button_t twr_button_t
Button instance.
Definition: twr_button.h:32
void twr_button_set_click_timeout(twr_button_t *self, twr_tick_t click_timeout)
Set click timeout (maximum interval within which button has to be released to recognize click event)
Definition: twr_button.c:93
void twr_button_set_debounce_time(twr_button_t *self, twr_tick_t debounce_time)
Set debounce time (minimum sampling interval during which input cannot change to toggle its state)
Definition: twr_button.c:88
twr_button_event_t
Callback events.
Definition: twr_button.h:15
void twr_button_init_virtual(twr_button_t *self, int channel, const twr_button_driver_t *driver, int idle_state)
Initialize virtual button.
Definition: twr_button.c:43
void twr_button_set_hold_time(twr_button_t *self, twr_tick_t hold_time)
Set hold time (interval after which hold event is recognized when button is steadily pressed)
Definition: twr_button.c:98
void twr_button_set_scan_interval(twr_button_t *self, twr_tick_t scan_interval)
Set scan interval (period of button input sampling)
Definition: twr_button.c:83
void twr_button_init(twr_button_t *self, twr_gpio_channel_t gpio_channel, twr_gpio_pull_t gpio_pull, int idle_state)
Initialize button.
Definition: twr_button.c:20
void twr_button_set_event_handler(twr_button_t *self, void(*event_handler)(twr_button_t *, twr_button_event_t, void *), void *event_param)
Set callback function.
Definition: twr_button.c:66
@ TWR_BUTTON_EVENT_HOLD
Event button hold (pressed for longer time)
Definition: twr_button.h:26
@ TWR_BUTTON_EVENT_PRESS
Event button pressed.
Definition: twr_button.h:17
@ TWR_BUTTON_EVENT_RELEASE
Event button released.
Definition: twr_button.h:20
@ TWR_BUTTON_EVENT_CLICK
Event button clicked (pressed and released within certain time)
Definition: twr_button.h:23
void twr_gpio_set_pull(twr_gpio_channel_t channel, twr_gpio_pull_t pull)
Set pull-up/pull-down configuration for GPIO channel.
Definition: twr_gpio.c:340
void twr_gpio_init(twr_gpio_channel_t channel)
Initialize GPIO channel.
Definition: twr_gpio.c:325
twr_gpio_channel_t
GPIO channels.
Definition: twr_gpio.h:13
twr_gpio_pull_t
GPIO pull-up/pull-down setting.
Definition: twr_gpio.h:88
int twr_gpio_get_input(twr_gpio_channel_t channel)
Get input state for GPIO channel.
Definition: twr_gpio.c:465
void twr_gpio_set_mode(twr_gpio_channel_t channel, twr_gpio_mode_t mode)
Set mode of operation for GPIO channel.
Definition: twr_gpio.c:367
@ TWR_GPIO_MODE_INPUT
GPIO channel operates as input.
Definition: twr_gpio.h:105
void twr_scheduler_plan_current_relative(twr_tick_t tick)
Schedule current task to tick relative from current spin.
void twr_scheduler_plan_absolute(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to absolute tick.
void twr_scheduler_plan_now(twr_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
twr_tick_t twr_scheduler_get_spin_tick(void)
Get current tick of spin in which task has been run.
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
Definition: twr_scheduler.c:53
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16
Button driver interface.
Definition: twr_button.h:37
void(* init)(twr_button_t *self)
Callback for initialization.
Definition: twr_button.h:39
bool(* init)(void)
Callback for initialization.
Definition: twr_lp8.h:56