-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathdebounce_button.c
More file actions
111 lines (94 loc) · 2.96 KB
/
Copy pathdebounce_button.c
File metadata and controls
111 lines (94 loc) · 2.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include "debounce_button.h"
static debounce_button_data* debounce_list = NULL; // Holds head of list
static void debounceButtonCallback(uint gpio, uint32_t events);
static int64_t debounceButtonTimerCallback(alarm_id_t id, void *user_data);
void debounceButtonCreate(debounce_button_data* db, uint pin, uint delay_ms, event_callback_t event_callback, bool up, bool high)
{
// Add to end of list
if (!debounce_list)
{
debounce_list = db;
}
else
{
debounce_button_data* db_prev = debounce_list;
while (db_prev->next)
{
db_prev = db_prev->next;
}
db_prev->next = db;
}
db->next = NULL;
db->pin = pin;
db->delay_ms = delay_ms;
db->event_callback = event_callback;
db->up = up;
db->high = high;
db->timer_id = -1;
gpio_init(db->pin);
gpio_set_dir(db->pin, GPIO_IN);
(db->up) ? gpio_pull_up(db->pin) : gpio_pull_down(db->pin);
// Attach the interrupt handler
gpio_set_irq_enabled_with_callback(db->pin, db->high ? GPIO_IRQ_EDGE_RISE : GPIO_IRQ_EDGE_FALL, true, &debounceButtonCallback);
}
void debounceButtonDestroy(debounce_button_data* db)
{
// Disable the IRQ
gpio_set_irq_enabled_with_callback(db->pin, db->high ? GPIO_IRQ_EDGE_RISE : GPIO_IRQ_EDGE_FALL, false, &debounceButtonCallback);
// Kill any timer
if (db->timer_id != -1)
{
// Cancel a timer if it was running
cancel_alarm(db->timer_id);
db->timer_id = -1;
}
// Remove from linked list - strictly speaking this should be interrupt protected
// Is this the head?
if (debounce_list == db)
{
debounce_list = db->next;
}
else
{
// Walk the list to find our position
debounce_button_data* p = debounce_list;
while (p->next != db)
{
p = p->next;
}
// p is now the entry before us, so link to next
p->next = db->next;
}
}
static void debounceButtonCallback(uint gpio, uint32_t events)
{
// Find this block in the linked list
debounce_button_data* db = debounce_list;
while ((db != NULL) && db->pin != gpio)
{
db = db->next;
}
if (db)
{
if (db->timer_id == -1)
{
// Timer not running so create one
db->timer_id = add_alarm_in_ms(db->delay_ms, debounceButtonTimerCallback, db, true);
}
}
gpio_acknowledge_irq(gpio, events);
}
// Called when the timer fires
// Send data back to the application
static int64_t debounceButtonTimerCallback(alarm_id_t id, void* db)
{
// Is the button pressed?
if ((((debounce_button_data*)db)->timer_id != -1) &&
(gpio_get(((debounce_button_data*)db)->pin) == ((debounce_button_data*)db)->high))
{
((debounce_button_data*)db)->event_callback(((debounce_button_data*)db)->pin, single_press);
}
// Clear timer indicator
((debounce_button_data*)db)->timer_id = -1;
return 0;
}