Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/gpio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_LPC11U6X gpio_lpc11u6x.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_XLNX_AXI gpio_xlnx_axi.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_NPCX gpio_npcx.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_EMUL gpio_emul.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_EMUL_SDL gpio_emul_sdl.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_PSOC6 gpio_psoc6.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_PCAL6408A gpio_pcal6408a.c)
zephyr_library_sources_ifdef(CONFIG_GPIO_EOS_S3 gpio_eos_s3.c)
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ source "drivers/gpio/Kconfig.npcx"

source "drivers/gpio/Kconfig.emul"

source "drivers/gpio/Kconfig.emul_sdl"

source "drivers/gpio/Kconfig.psoc6"

source "drivers/gpio/Kconfig.pcal6408a"
Expand Down
13 changes: 13 additions & 0 deletions drivers/gpio/Kconfig.emul_sdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# GPIO emulation using SDL keyboard events
#
# Copyright (c) 2022, Basalte bv
# SPDX-License-Identifier: Apache-2.0

config GPIO_EMUL_SDL
bool "SDL GPIO emulation"
default y
depends on DT_HAS_ZEPHYR_GPIO_EMUL_SDL_ENABLED
depends on GPIO_EMUL
depends on HAS_SDL
help
Enable GPIO emulation using SDL keyboard events.
2 changes: 1 addition & 1 deletion drivers/gpio/Kconfig.pca953x
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ menuconfig GPIO_PCA953X
bool "PCA953X I2C GPIO chip"
default y
depends on DT_HAS_TI_TCA9538_ENABLED
depends on I2C
select I2C
help
Enable driver for PCA953X I2C GPIO chip.

Expand Down
103 changes: 103 additions & 0 deletions drivers/gpio/gpio_emul_sdl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2022, Basalte bv
*
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT zephyr_gpio_emul_sdl

#include <zephyr/drivers/gpio/gpio_emul.h>
#include <zephyr/logging/log.h>

#include <SDL.h>

LOG_MODULE_REGISTER(gpio_emul_sdl, CONFIG_GPIO_LOG_LEVEL);

struct gpio_sdl_config {
const struct device *emul;

const SDL_Scancode *codes;
uint8_t num_codes;
};

static int sdl_filter(void *arg, SDL_Event *event)
{
const struct device *port = arg;
const struct gpio_sdl_config *config = port->config;
int ret;

gpio_pin_t pin = 0;

/* Only handle keyboard events */
switch (event->type) {
case SDL_KEYDOWN:
case SDL_KEYUP:
break;
default:
return 1;
}

/* Search for the corresponding scancode */
while (pin < config->num_codes) {
if (config->codes[pin] == event->key.keysym.scancode) {
break;
}
pin++;
}

if (pin == config->num_codes) {
/* Not tracked */
return 1;
}

/* Lock the scheduler so we can't be preempted,
* as the gpio_emul driver keeps a mutex locked
* for as long as there are pending interrupts
*/
k_sched_lock();

/* Update the pin state */
ret = gpio_emul_input_set(config->emul, pin, event->type == SDL_KEYDOWN ? 1 : 0);

k_sched_unlock();
if (ret < 0) {
LOG_WRN("Failed to emulate input (%d)", ret);
}

return 0;
}

static int gpio_sdl_init(const struct device *dev)
{
const struct gpio_sdl_config *config = dev->config;

for (uint8_t pin = 0; pin < config->num_codes; ++pin) {
if (config->codes[pin] != SDL_SCANCODE_UNKNOWN) {
LOG_INF("GPIO %s:%u = %u", dev->name, pin, config->codes[pin]);
}
}

SDL_AddEventWatch(sdl_filter, (void *)dev);

return 0;
}

#define GPIO_SDL_DEFINE(inst) \
BUILD_ASSERT(DT_NODE_HAS_COMPAT_STATUS(DT_INST_PARENT(inst), \
zephyr_gpio_emul, okay), \
"Enabled parent zephyr,gpio-emul node is required"); \
\
static const SDL_Scancode gpio_sdl_##inst##_codes[] \
= DT_INST_PROP(inst, scancodes); \
\
static const struct gpio_sdl_config gpio_sdl_##inst##_config = { \
.emul = DEVICE_DT_GET(DT_INST_PARENT(inst)), \
.codes = gpio_sdl_##inst##_codes, \
.num_codes = DT_INST_PROP_LEN(inst, scancodes), \
}; \
\
DEVICE_DT_INST_DEFINE(inst, gpio_sdl_init, NULL, NULL, \
&gpio_sdl_##inst##_config, POST_KERNEL, \
CONFIG_GPIO_INIT_PRIORITY, NULL);

DT_INST_FOREACH_STATUS_OKAY(GPIO_SDL_DEFINE)
53 changes: 53 additions & 0 deletions dts/bindings/gpio/zephyr,gpio-emul-sdl.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright 2022, Basalte bv
# SPDX-License-Identifier: Apache-2.0

description: |
SDL keyboard GPIO input Emulator

Simulate GPIO state/interrupts using SDL keyboard events. This node has
to be a child of a `zephyr,gpio-emul` compatible.
Add a list of scancodes for the desired keys to be mapped.

Refer to https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
section Keyboard/Keypad (p53) for a list of scancode values.

The following example maps the first 3 numeric keys to GPIO pins:

/* gpio0 has to be a zephyr,gpio-emul device */
&gpio0 {
ngpios = <3>;

sdl_gpio {
compatible = "zephyr,gpio-emul-sdl";
scancodes = <30 31 32>;
};
};

keypad: keypad {
compatible = "gpio-keys";
key1: key1 {
gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
};
key1: key2 {
gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
};
key3: key3 {
gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
};
};

The limitations of usage are:
- Only active high as we don't get events for keys that aren't pressed
- Pressing multiple keys is best effort, state will be kept but no events
are generated once the last key is released

compatible: "zephyr,gpio-emul-sdl"

include: base.yaml

properties:
scancodes:
type: array
required: true
description: |
An array of SDL scancodes mapped to its GPIO index
1 change: 1 addition & 0 deletions samples/subsys/display/lvgl/boards/native_posix.conf
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
CONFIG_LV_COLOR_DEPTH_32=y
CONFIG_GPIO=y
31 changes: 31 additions & 0 deletions samples/subsys/display/lvgl/boards/native_posix.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2022, Basalte bv
*
* SPDX-License-Identifier: Apache-2.0
*/


/ {
aliases {
sw0 = &button0;
};

keys {
compatible = "gpio-keys";
button0: button0 {
/* gpio0 pin 0 is already aliased to led0 */
gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
};
};
};

&gpio0 {
ngpios = <2>;

sdl_gpio {
status = "okay";
compatible = "zephyr,gpio-emul-sdl";
/* Skip pin 0 with the unknown code 0 */
scancodes = <0 21>;
};
};
1 change: 1 addition & 0 deletions samples/subsys/display/lvgl/boards/native_posix_64.conf
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
CONFIG_LV_COLOR_DEPTH_32=y
CONFIG_GPIO=y
6 changes: 6 additions & 0 deletions samples/subsys/display/lvgl/boards/native_posix_64.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
* Copyright (c) 2022, Basalte bv
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "native_posix.overlay"
51 changes: 49 additions & 2 deletions samples/subsys/display/lvgl/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
*/

#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/display.h>
#include <zephyr/drivers/gpio.h>
#include <lvgl.h>
#include <stdio.h>
#include <string.h>
Expand All @@ -15,9 +17,28 @@
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(app);

static uint32_t count;

#ifdef CONFIG_GPIO
static struct gpio_dt_spec button_gpio = GPIO_DT_SPEC_GET_OR(
DT_ALIAS(sw0), gpios, {0});
static struct gpio_callback button_callback;

static void button_isr_callback(const struct device *port,
struct gpio_callback *cb,
uint32_t pins)
{
ARG_UNUSED(port);
ARG_UNUSED(cb);
ARG_UNUSED(pins);

count = 0;
}
#endif

void main(void)
{
uint32_t count = 0U;
int err;
char count_str[11] = {0};
const struct device *display_dev;
lv_obj_t *hello_world_label;
Expand All @@ -29,6 +50,32 @@ void main(void)
return;
}

#ifdef CONFIG_GPIO
if (device_is_ready(button_gpio.port)) {
err = gpio_pin_configure_dt(&button_gpio, GPIO_INPUT);
if (err) {
LOG_ERR("failed to configure button gpio: %d", err);
return;
}

gpio_init_callback(&button_callback, button_isr_callback,
BIT(button_gpio.pin));

err = gpio_add_callback(button_gpio.port, &button_callback);
if (err) {
LOG_ERR("failed to add button callback: %d", err);
return;
}

err = gpio_pin_interrupt_configure_dt(&button_gpio,
GPIO_INT_EDGE_TO_ACTIVE);
if (err) {
LOG_ERR("failed to enable button callback: %d", err);
return;
}
}
#endif

if (IS_ENABLED(CONFIG_LV_Z_POINTER_KSCAN)) {
lv_obj_t *hello_world_button;

Expand All @@ -54,7 +101,7 @@ void main(void)
lv_label_set_text(count_label, count_str);
}
lv_task_handler();
k_sleep(K_MSEC(10));
++count;
k_sleep(K_MSEC(10));
}
}