diff --git a/platform/drivers/keyboard/keyboard_ttwrplus.c b/platform/drivers/keyboard/keyboard_ttwrplus.c
new file mode 100644
index 00000000..ac82f833
--- /dev/null
+++ b/platform/drivers/keyboard/keyboard_ttwrplus.c
@@ -0,0 +1,108 @@
+/***************************************************************************
+ * Copyright (C) 2020 - 2023 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#include
+#include
+#include
+#include
+
+static const struct device *const buttons_dev = DEVICE_DT_GET(DT_NODELABEL(buttons));
+
+static int8_t old_pos = 0;
+static keyboard_t keys = 0;
+
+
+static void gpio_keys_cb_handler(struct input_event *evt)
+{
+ uint32_t keyCode = 0;
+
+ // Map betweek Zephyr keys and OpenRTX keys
+ switch(evt->code)
+ {
+ case INPUT_KEY_VOLUMEDOWN:
+ keyCode = KEY_DOWN;
+ break;
+
+ case INPUT_BTN_START:
+ keyCode = KEY_ENTER;
+ break;
+
+ case INPUT_BTN_SELECT:
+ keyCode = KEY_ESC;
+ break;
+ }
+
+ if(evt->value != 0)
+ keys |= keyCode;
+ else
+ keys &= ~keyCode;
+}
+
+INPUT_LISTENER_CB_DEFINE(buttons_dev, gpio_keys_cb_handler);
+
+
+void kbd_init()
+{
+ // Initialise old position
+ old_pos = platform_getChSelector();
+}
+
+void kbd_terminate()
+{
+}
+
+keyboard_t kbd_getKeys()
+{
+ keys &= ~KNOB_LEFT;
+ keys &= ~KNOB_RIGHT;
+
+ // Read rotary encoder to send KNOB_LEFT and KNOB_RIGHT events
+ int8_t new_pos = platform_getChSelector();
+ if (old_pos != new_pos)
+ {
+ int8_t delta = new_pos - old_pos;
+
+ // Normal case: handle up/down by looking at the pulse difference
+ if(delta > 0)
+ keys |= KNOB_LEFT;
+ else if (delta < 0)
+ keys |= KNOB_RIGHT;
+
+ // Corner case 1: rollover from negative (old) to positive (new) value.
+ // Delta is positive but it counts as a down key.
+ if((old_pos < 0) && (new_pos > 0))
+ {
+ keys &= ~KNOB_LEFT;
+ keys |= KNOB_RIGHT;
+ }
+
+ // Corner case 2: rollover from positive (old) to negative (new) value.
+ // Delta is negative but it counts as an up key.
+ if((old_pos > 0) && (new_pos < 0))
+ {
+ keys &= ~KNOB_RIGHT;
+ keys |= KNOB_LEFT;
+ }
+
+ old_pos = new_pos;
+ }
+
+ return keys;
+}
diff --git a/platform/targets/ttwrplus/CMakeLists.txt b/platform/targets/ttwrplus/CMakeLists.txt
index 6d8206ad..27432980 100644
--- a/platform/targets/ttwrplus/CMakeLists.txt
+++ b/platform/targets/ttwrplus/CMakeLists.txt
@@ -12,10 +12,10 @@ target_sources(app
${OPENRTX_ROOT}/platform/targets/ttwrplus/platform.c
${OPENRTX_ROOT}/platform/drivers/display/SH1106_ttwrplus.c
+ ${OPENRTX_ROOT}/platform/drivers/keyboard/keyboard_ttwrplus.c
${OPENRTX_ROOT}/platform/drivers/stubs/audio_stub.c
${OPENRTX_ROOT}/platform/drivers/stubs/cps_io_stub.c
- ${OPENRTX_ROOT}/platform/drivers/stubs/keyboard_stub.c
${OPENRTX_ROOT}/platform/drivers/stubs/nvmem_stub.c
${OPENRTX_ROOT}/platform/drivers/stubs/radio_stub.c
)
diff --git a/platform/targets/ttwrplus/platform.c b/platform/targets/ttwrplus/platform.c
index efc98794..b70e9888 100644
--- a/platform/targets/ttwrplus/platform.c
+++ b/platform/targets/ttwrplus/platform.c
@@ -20,6 +20,14 @@
#include
#include
+#include
+#include
+
+#define BUTTON_PTT_NODE DT_NODELABEL(button_ptt)
+
+static const struct gpio_dt_spec button_ptt = GPIO_DT_SPEC_GET_OR(BUTTON_PTT_NODE, gpios, {0});
+static const struct device *const qdec_dev = DEVICE_DT_GET(DT_ALIAS(qdec0));
+
static const hwInfo_t hwInfo =
{
.uhf_maxFreq = 430,
@@ -31,6 +39,20 @@ static const hwInfo_t hwInfo =
void platform_init()
{
+ // Setup GPIO for PTT and rotary encoder
+ if(gpio_is_ready_dt(&button_ptt) == false)
+ printk("Error: button device %s is not ready\n", button_ptt.port->name);
+
+ int ret = gpio_pin_configure_dt(&button_ptt, GPIO_INPUT);
+ if (ret != 0)
+ {
+ printk("Error %d: failed to configure %s pin %d\n", ret,
+ button_ptt.port->name, button_ptt.pin);
+ }
+
+ // Rotary encoder is read using hardware pulse counter
+ if(device_is_ready(qdec_dev) == false)
+ printk("Qdec device is not ready\n");
}
void platform_terminate()
@@ -54,12 +76,29 @@ uint8_t platform_getVolumeLevel()
int8_t platform_getChSelector()
{
- return 0;
+ int rc = sensor_sample_fetch(qdec_dev);
+ if (rc != 0)
+ {
+ printk("Failed to fetch sample (%d)\n", rc);
+ return 0;
+ }
+
+ struct sensor_value val;
+ rc = sensor_channel_get(qdec_dev, SENSOR_CHAN_ROTATION, &val);
+ if (rc != 0)
+ {
+ printk("Failed to get data (%d)\n", rc);
+ return 0;
+ }
+
+ // The esp32-pcnt sensor returns a signed 16-bit value: we remap it into a
+ // signed 8-bit one.
+ return (int8_t) val.val1;
}
bool platform_getPttStatus()
{
- return false;
+ return gpio_pin_get_dt(&button_ptt);
}
bool platform_pwrButtonStatus()
@@ -84,6 +123,7 @@ void platform_beepStart(uint16_t freq)
void platform_beepStop()
{
+ ;
}
const hwInfo_t *platform_getHwInfo()
diff --git a/platform/targets/ttwrplus/ttwrplus.dts b/platform/targets/ttwrplus/ttwrplus.dts
index 8ff7a232..d1f1faf9 100644
--- a/platform/targets/ttwrplus/ttwrplus.dts
+++ b/platform/targets/ttwrplus/ttwrplus.dts
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
#include
#include
@@ -16,6 +17,8 @@
aliases {
i2c-0 = &i2c0;
watchdog0 = &wdt0;
+ radio = &uart0;
+ qdec0 = &pcnt;
};
chosen {
@@ -26,23 +29,27 @@
zephyr,display = &ssd1306;
};
- aliases {
- radio = &uart0;
- };
+ buttons: buttons {
+ compatible = "zephyr,gpio-keys";
- buttons {
- compatible = "gpio-keys";
-
- sw_boot: button_0 {
+ button_boot: button_0 {
gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+ zephyr,code = ;
label = "BOOT Button";
};
- sw_user: button_1 {
- gpios = <&gpio0 3 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
- label = "USER Button";
+ button_user: button_1 {
+ gpios = <&gpio0 21 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
+ zephyr,code = ;
+ label = "Encoder Button";
};
- };
+
+ button_ptt: button_2 {
+ gpios = <&gpio0 3 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
+ zephyr,code = ;
+ label = "PTT Button";
+ };
+ };
};
&cpu0 {
@@ -88,6 +95,27 @@
};
};
+&pcnt {
+ pinctrl-0 = <&pcnt_default>;
+ pinctrl-names = "default";
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ unit0@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ filter = <100>;
+ channelA@0 {
+ reg = <0>;
+ sig-pos-mode = <2>;
+ sig-neg-mode = <1>;
+ ctrl-h-mode = <0>;
+ ctrl-l-mode = <1>;
+ };
+ };
+};
+
&timer0 {
status = "disabled";
};
@@ -133,6 +161,14 @@
output-high;
};
};
+
+ pcnt_default: pcnt_default {
+ group1 {
+ pinmux = ,
+ ;
+ bias-pull-up;
+ };
+ };
};
&flash0 {
diff --git a/platform/targets/ttwrplus/ttwrplus_defconfig b/platform/targets/ttwrplus/ttwrplus_defconfig
index 74021a02..cdcb1c52 100644
--- a/platform/targets/ttwrplus/ttwrplus_defconfig
+++ b/platform/targets/ttwrplus/ttwrplus_defconfig
@@ -10,3 +10,5 @@ CONFIG_DYNAMIC_THREAD_PREFER_POOL=y
CONFIG_DYNAMIC_THREAD_POOL_SIZE=4
CONFIG_COMMON_LIBC_MALLOC=y
CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=131072
+CONFIG_INPUT=y
+CONFIG_SENSOR=y