Skip to content

Commit aa6927c

Browse files
committed
feat(srv/gpio-keypad): Add a service implementing keypad using GPIO inputs
1 parent d129faa commit aa6927c

File tree

5 files changed

+205
-0
lines changed

5 files changed

+205
-0
lines changed

services/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ menu "High level device drivers"
233233
source "services/gpio-led/Kconfig"
234234
source "services/shtc3/Kconfig"
235235
source "services/pcal6408a-gpio/Kconfig"
236+
source "services/gpio-keypad/Kconfig"
236237

237238
endmenu
238239

services/gpio-keypad/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
config SERVICE_GPIO_KEYPAD
2+
bool "Service implementing a keypad using GPIO inputs"
3+
default n

services/gpio-keypad/SConscript

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Import("env")
2+
Import("objs")
3+
Import("conf")
4+
5+
if conf["SERVICE_GPIO_KEYPAD"] == "y":
6+
objs.append(env.Object(File(Glob("*.c"))))
7+
env.Append(CPPPATH = [Dir(".")])

services/gpio-keypad/gpio-keypad.c

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/* SPDX-License-Identifier: GPL-3.0-or-later
2+
*
3+
* Keypad implemented using GPIO pins
4+
*
5+
* Copyright (c) 2025, Marek Koza (qyx@krtko.org)
6+
* All rights reserved.
7+
*/
8+
9+
#include <stdint.h>
10+
#include <stdlib.h>
11+
#include <string.h>
12+
#include <stdio.h>
13+
#include <stdbool.h>
14+
15+
#include <main.h>
16+
17+
#include <interfaces/gpio.h>
18+
#include <interfaces/event.h>
19+
20+
#include "gpio-keypad.h"
21+
22+
#define MODULE_NAME "gpio-keypad"
23+
24+
25+
static gpio_keypad_ret_t check_state(GpioKeypad *self) {
26+
for (struct gpio_keypad_key *key = self->keys; key->input != NULL; key++) {
27+
bool new_down = false;
28+
if (key->input == NULL || key->input->vmt->get(key->input, &new_down) != GPIO_RET_OK) {
29+
continue;
30+
}
31+
if (key->invert) {
32+
new_down = !new_down;
33+
}
34+
if (new_down != key->down) {
35+
if (key->counter >= GPIO_KEYPAD_COUNTER_THRESHOLD) {
36+
/* The key is observed to be down. */
37+
key->counter = 0;
38+
key->down = new_down;
39+
40+
//~ u_log(system_log, LOG_TYPE_DEBUG, U_LOG_MODULE_PREFIX("type = %d, code = %d, value = %d"), key->type, key->code, key->down ? 1 : 0);
41+
struct gpio_keypad_event ev = {
42+
.type = key->type ? key->type : EV_TYPE_RAW,
43+
.code = key->code,
44+
.value = key->down ? 1 : 0
45+
};
46+
xQueueSend(self->event_queue, &ev, 0);
47+
} else {
48+
key->counter++;
49+
}
50+
} else {
51+
key->counter = 0;
52+
}
53+
}
54+
55+
return GPIO_KEYPAD_RET_OK;
56+
}
57+
58+
59+
static void keypad_task(void *p) {
60+
GpioKeypad *self = p;
61+
62+
63+
while (true) {
64+
check_state(self);
65+
66+
vTaskDelay(10);
67+
}
68+
vTaskDelete(NULL);
69+
}
70+
71+
72+
/**********************************************************************************************************************
73+
* Event interface implementation
74+
**********************************************************************************************************************/
75+
76+
static event_ret_t gpio_keypad_event_listen(Event *event, enum event_type *type, enum event_code *code, int32_t *value) {
77+
GpioKeypad *self = event->parent;
78+
struct gpio_keypad_event ev = {0};
79+
xQueueReceive(self->event_queue, &ev, portMAX_DELAY);
80+
if (type != NULL) {
81+
*type = ev.type;
82+
}
83+
if (code != NULL) {
84+
*code = ev.code;
85+
}
86+
if (value != NULL) {
87+
*value = ev.value;
88+
}
89+
90+
return EV_RET_OK;
91+
}
92+
93+
94+
static const struct event_vmt gpio_keypad_event_vmt = {
95+
.subscribe = NULL,
96+
.listen = &gpio_keypad_event_listen,
97+
};
98+
99+
100+
/**********************************************************************************************************************
101+
* Service implementation
102+
**********************************************************************************************************************/
103+
104+
105+
106+
gpio_keypad_ret_t gpio_keypad_init(GpioKeypad *self, struct gpio_keypad_key *keys) {
107+
if (u_assert(self != NULL) ||
108+
u_assert(keys != NULL)) {
109+
return GPIO_KEYPAD_RET_FAILED;
110+
}
111+
memset(self, 0, sizeof(GpioKeypad));
112+
self->keys = keys;
113+
114+
for (struct gpio_keypad_key *key = self->keys; key->input != NULL; key++) {
115+
key->input->vmt->set_mode(key->input, MODE_INPUT);
116+
key->input->vmt->set_pull(key->input, PULL_NONE);
117+
}
118+
119+
self->event_queue = xQueueCreate(GPIO_KEYPAD_EVENT_QUEUE_SIZE, sizeof(struct gpio_keypad_event));
120+
if (self->event_queue == NULL) {
121+
u_log(system_log, LOG_TYPE_ERROR, U_LOG_MODULE_PREFIX("cannot allocate event queue"));
122+
goto err;
123+
}
124+
125+
xTaskCreate(keypad_task, "gpio-keypad", configMINIMAL_STACK_SIZE + 192, (void *)self, 1, &(self->keypad_task));
126+
if (self->keypad_task == NULL) {
127+
u_log(system_log, LOG_TYPE_ERROR, U_LOG_MODULE_PREFIX("cannot create task"));
128+
goto err;
129+
}
130+
131+
self->event.parent = self;
132+
self->event.vmt = &gpio_keypad_event_vmt;
133+
134+
u_log(system_log, LOG_TYPE_INFO, U_LOG_MODULE_PREFIX("init ok"));
135+
136+
return GPIO_KEYPAD_RET_OK;
137+
err:
138+
return GPIO_KEYPAD_RET_FAILED;
139+
}
140+
141+

services/gpio-keypad/gpio-keypad.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/* SPDX-License-Identifier: GPL-3.0-or-later
2+
*
3+
* Keypad implemented using GPIO pins
4+
*
5+
* Copyright (c) 2025, Marek Koza (qyx@krtko.org)
6+
* All rights reserved.
7+
*/
8+
9+
#pragma once
10+
11+
#include <main.h>
12+
13+
#include <interfaces/gpio.h>
14+
#include <interfaces/event.h>
15+
16+
17+
#define GPIO_KEYPAD_EVENT_QUEUE_SIZE 4
18+
#define GPIO_KEYPAD_COUNTER_THRESHOLD 3
19+
20+
typedef enum {
21+
GPIO_KEYPAD_RET_OK = 0,
22+
GPIO_KEYPAD_RET_FAILED,
23+
} gpio_keypad_ret_t;
24+
25+
struct gpio_keypad_event {
26+
enum event_type type;
27+
enum event_code code;
28+
int32_t value;
29+
30+
};
31+
32+
struct gpio_keypad_key {
33+
Gpio *input;
34+
enum event_type type;
35+
enum event_code code;
36+
bool invert;
37+
38+
/* Runtime data */
39+
bool down;
40+
int counter;
41+
};
42+
43+
typedef struct gpio_keypad {
44+
struct gpio_keypad_key *keys;
45+
TaskHandle_t keypad_task;
46+
QueueHandle_t event_queue;
47+
48+
Event event;
49+
} GpioKeypad;
50+
51+
52+
gpio_keypad_ret_t gpio_keypad_init(GpioKeypad *self, struct gpio_keypad_key *keys);
53+

0 commit comments

Comments
 (0)