drivers/input: Create Single Button Multi Actions
This commit creates a sbutton device that uses a single button to create a keyboard driver that returns TAB or ENTER depending how long the user keeps the button pressed. Signed-off-by: Alan C. Assis <acassis@gmail.com>
This commit is contained in:
parent
3c8859b509
commit
54b2381c42
15 changed files with 849 additions and 0 deletions
|
|
@ -6,5 +6,6 @@ Input Devices
|
|||
:caption: Supported Drivers
|
||||
|
||||
keypad.rst
|
||||
sbutton.rst
|
||||
|
||||
See ``include/nuttx/input/*.h`` for registration information.
|
||||
|
|
|
|||
41
Documentation/components/drivers/character/input/sbutton.rst
Normal file
41
Documentation/components/drivers/character/input/sbutton.rst
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
==================================
|
||||
Single Button Multi Actions Driver
|
||||
==================================
|
||||
|
||||
**Single Button (aka SButton)** is an kind of keyboard that uses
|
||||
only a single physical button (Switch) in the board. This kind of
|
||||
button is used with simple interfaces like those used on 3D Printers
|
||||
or other devices where all the user needs is to move to the next
|
||||
option and confirm the selection.
|
||||
|
||||
It could be done detecting if the button was pressed for a short
|
||||
period of time (i.e. less than 500ms) or long pressed. If it is a
|
||||
short press the driver will return **TAB** and if it is a long
|
||||
press the driver will return **ENTER**. Using it is possible to
|
||||
navigate on those kind of menu.
|
||||
|
||||
**How does it work?**. The driver uses a simple config data (this
|
||||
config data is equivalent to the platform data on Linux kernel) to
|
||||
map the pin from MCU will be used to register and detect the
|
||||
interrupt from this pin physically connected to the button.
|
||||
|
||||
It uses a kind of "polymorphism" in C to allow the driver to get
|
||||
access to the functions responsible to attach and enable the
|
||||
interrupt and to get the status of the pin.
|
||||
See ``include/nuttx/input/sbutton.h``
|
||||
and ``boards/arm/stm32/common/src/stm32_sbutton.c`` to understand
|
||||
better how it works. But basically the board file (config data)
|
||||
creates a struct when the first field (variable) is the config
|
||||
struct used the but SButton driver (``drivers/input/sbutton.c``).
|
||||
|
||||
Every time the user presses or releases the key button an interrupt
|
||||
is generated. The ISR of this interrupt inside sbutton
|
||||
(``sbutton_interrupt()``) calls a workqueue to process it (because
|
||||
we cannot spend time inside the ISR processing data, it could
|
||||
degradate the performance of the RTOS). All that workqueue
|
||||
(``sbutton_worker()``) needs to do it measure the elapsed time
|
||||
(ticks) from the moment the key was pressed until the moment it
|
||||
was released to decide if it is a "KEY_1" (**TAB**) or a "KEY_2"
|
||||
(**ENTER**). Then is call the ``keyboard_event()`` from the
|
||||
keyboard upper to send this key stroke to the user application.
|
||||
|
||||
|
|
@ -1970,6 +1970,27 @@ the second dongle you will connect to UART3 (PB10 and PB11).
|
|||
In the main NSH console (in USART2) type: "pts_test &". It will create a
|
||||
new console in UART3. Just press ENTER and start typing commands on it.
|
||||
|
||||
sbutton
|
||||
-------
|
||||
|
||||
This is a configuration to test the Single Button Dual Action feature.
|
||||
To test it just compile and flash nuttx.bin in the board. Then run the
|
||||
``kbd`` command inside ``nsh>`` and short press and long press User
|
||||
Button (B1) on the board.
|
||||
|
||||
You will see something like this::
|
||||
|
||||
NuttShell (NSH) NuttX-12.10.0
|
||||
nsh> kbd
|
||||
kbd_main: nsamples: 0
|
||||
kbd_main: Opening /dev/kbd0
|
||||
Sample :
|
||||
code : 65
|
||||
type : 0
|
||||
Sample :
|
||||
code : 66
|
||||
type : 0
|
||||
|
||||
sporadic
|
||||
--------
|
||||
|
||||
|
|
|
|||
83
boards/arm/stm32/common/include/board_sbutton.h
Normal file
83
boards/arm/stm32/common/include/board_sbutton.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/****************************************************************************
|
||||
* boards/arm/stm32/common/include/board_sbutton.h
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __BOARDS_ARM_STM32_COMMON_INCLUDE_BOARD_SBUTTON_H
|
||||
#define __BOARDS_ARM_STM32_COMMON_INCLUDE_BOARD_SBUTTON_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Inline Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32_sbutton_initialize
|
||||
*
|
||||
* Description:
|
||||
* This function is called by application-specific, setup logic to
|
||||
* configure the Single Button Dual Action.
|
||||
*
|
||||
* Input Parameters:
|
||||
* devno - The device number, used to build the device path as /dev/distN
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned on success. Otherwise, a negated errno value is
|
||||
* returned to indicate the nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int board_sbutton_initialize(int devno);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BOARDS_ARM_STM32_COMMON_INCLUDE_BOARD_SBUTTON_H */
|
||||
|
|
@ -154,4 +154,8 @@ if(CONFIG_STEPPER_DRV8825)
|
|||
list(APPEND SRCS stm32_drv8825.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_INPUT_SBUTTON)
|
||||
list(APPEND SRCS stm32_sbutton.c)
|
||||
endif()
|
||||
|
||||
target_sources(board PRIVATE ${SRCS})
|
||||
|
|
|
|||
|
|
@ -162,6 +162,10 @@ ifeq ($(CONFIG_STEPPER_DRV8825),y)
|
|||
CSRCS += stm32_drv8825.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INPUT_SBUTTON),y)
|
||||
CSRCS += stm32_sbutton.c
|
||||
endif
|
||||
|
||||
DEPPATH += --dep-path src
|
||||
VPATH += :src
|
||||
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src
|
||||
|
|
|
|||
182
boards/arm/stm32/common/src/stm32_sbutton.c
Normal file
182
boards/arm/stm32/common/src/stm32_sbutton.c
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/****************************************************************************
|
||||
* boards/arm/stm32/common/src/stm32_sbutton.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/arch.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/board.h>
|
||||
#include <arch/board/board.h>
|
||||
#include <nuttx/input/sbutton.h>
|
||||
|
||||
#include "stm32.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct stm32_sbtnconfig_s
|
||||
{
|
||||
/* Configuration structure as seen by the HC-SR04 driver */
|
||||
|
||||
struct sbutton_config_s config;
|
||||
|
||||
/* Additional private definitions only known to this driver */
|
||||
|
||||
void *arg; /* Argument to pass to the interrupt handler */
|
||||
xcpt_t isr; /* ISR Handler */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int sbtn_irq_attach(const struct sbutton_config_s *config,
|
||||
xcpt_t isr, void *arg);
|
||||
static void sbtn_irq_enable(const struct sbutton_config_s *config,
|
||||
bool enable);
|
||||
static void sbtn_irq_clear(const struct sbutton_config_s *config);
|
||||
|
||||
static bool sbtn_pin_status(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* A reference to a structure of this type must be passed to the SButton
|
||||
* driver. This structure provides information about the configuration
|
||||
* of the SButton and provides some board-specific hooks.
|
||||
*
|
||||
* Memory for this structure is provided by the caller. It is not copied
|
||||
* by the driver and is presumed to persist while the driver is active.
|
||||
*/
|
||||
|
||||
static struct stm32_sbtnconfig_s g_sbtnconfig =
|
||||
{
|
||||
.config =
|
||||
{
|
||||
.attach = sbtn_irq_attach,
|
||||
.enable = sbtn_irq_enable,
|
||||
.clear = sbtn_irq_clear,
|
||||
.status = sbtn_pin_status,
|
||||
},
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/* Attach the SBUTTON interrupt handler to the GPIO interrupt */
|
||||
|
||||
static int sbtn_irq_attach(const struct sbutton_config_s *state, xcpt_t isr,
|
||||
void *arg)
|
||||
{
|
||||
struct stm32_sbtnconfig_s *priv = (struct stm32_sbtnconfig_s *)state;
|
||||
irqstate_t flags;
|
||||
|
||||
sinfo("sbtn_irq_attach\n");
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
priv->isr = isr;
|
||||
priv->arg = arg;
|
||||
|
||||
stm32_gpiosetevent(BOARD_SBUTTON_GPIO_INT, true, true,
|
||||
true, isr, arg);
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Enable or disable the GPIO interrupt */
|
||||
|
||||
static void sbtn_irq_enable(const struct sbutton_config_s *state,
|
||||
bool enable)
|
||||
{
|
||||
struct stm32_sbtnconfig_s *priv = (struct stm32_sbtnconfig_s *)state;
|
||||
|
||||
iinfo("%d\n", enable);
|
||||
|
||||
stm32_gpiosetevent(BOARD_SBUTTON_GPIO_INT, true, true,
|
||||
true, enable ? priv->isr : NULL, priv->arg);
|
||||
}
|
||||
|
||||
/* Acknowledge/clear any pending GPIO interrupt */
|
||||
|
||||
static void sbtn_irq_clear(const struct sbutton_config_s *state)
|
||||
{
|
||||
/* FIXME: Nothing to do ? */
|
||||
}
|
||||
|
||||
/* Read and return the status of button (PRESSED = true; RELEASED = false */
|
||||
|
||||
static bool sbtn_pin_status(void)
|
||||
{
|
||||
/* STM32F4Discovery button B1 is high level when press
|
||||
* then just returned the status of the pin directly.
|
||||
*/
|
||||
|
||||
return stm32_gpioread(BOARD_SBUTTON_GPIO_INT);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: board_sbutton_initialize
|
||||
*
|
||||
* Description:
|
||||
* This function is called by application-specific, setup logic to
|
||||
* configure the Single Button Dual Action.
|
||||
*
|
||||
* Input Parameters:
|
||||
* devno - The device number, used to build the device path as /dev/kbdN
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned on success. Otherwise, a negated errno value is
|
||||
* returned to indicate the nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int board_sbutton_initialize(int devno)
|
||||
{
|
||||
/* Configure the Single Button Dual Action interrupt pin */
|
||||
|
||||
stm32_configgpio(BOARD_SBUTTON_GPIO_INT);
|
||||
|
||||
/* Register the Single Button with overlay config pointer */
|
||||
|
||||
return sbutton_register(&g_sbtnconfig.config, devno);
|
||||
}
|
||||
56
boards/arm/stm32/stm32f4discovery/configs/sbutton/defconfig
Normal file
56
boards/arm/stm32/stm32f4discovery/configs/sbutton/defconfig
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#
|
||||
# This file is autogenerated: PLEASE DO NOT EDIT IT.
|
||||
#
|
||||
# You can use "make menuconfig" to make any modifications to the installed .config file.
|
||||
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
|
||||
# modifications.
|
||||
#
|
||||
# CONFIG_ARCH_FPU is not set
|
||||
# CONFIG_ASSERTIONS_FILENAME is not set
|
||||
# CONFIG_NDEBUG is not set
|
||||
# CONFIG_NSH_ARGCAT is not set
|
||||
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
|
||||
CONFIG_ARCH="arm"
|
||||
CONFIG_ARCH_BOARD="stm32f4discovery"
|
||||
CONFIG_ARCH_BOARD_COMMON=y
|
||||
CONFIG_ARCH_BOARD_STM32F4_DISCOVERY=y
|
||||
CONFIG_ARCH_CHIP="stm32"
|
||||
CONFIG_ARCH_CHIP_STM32=y
|
||||
CONFIG_ARCH_CHIP_STM32F407VG=y
|
||||
CONFIG_ARCH_STACKDUMP=y
|
||||
CONFIG_BOARD_LATE_INITIALIZE=y
|
||||
CONFIG_BOARD_LOOPSPERMSEC=16717
|
||||
CONFIG_BUILTIN=y
|
||||
CONFIG_EXAMPLES_HELLO=y
|
||||
CONFIG_EXAMPLES_KEYBOARD=y
|
||||
CONFIG_FS_PROCFS=y
|
||||
CONFIG_HAVE_CXX=y
|
||||
CONFIG_HAVE_CXXINITIALIZE=y
|
||||
CONFIG_INIT_ENTRYPOINT="nsh_main"
|
||||
CONFIG_INPUT=y
|
||||
CONFIG_INPUT_SBUTTON=y
|
||||
CONFIG_INTELHEX_BINARY=y
|
||||
CONFIG_LINE_MAX=64
|
||||
CONFIG_MM_REGIONS=2
|
||||
CONFIG_NSH_BUILTIN_APPS=y
|
||||
CONFIG_NSH_FILEIOSIZE=512
|
||||
CONFIG_NSH_READLINE=y
|
||||
CONFIG_PREALLOC_TIMERS=4
|
||||
CONFIG_RAM_SIZE=114688
|
||||
CONFIG_RAM_START=0x20000000
|
||||
CONFIG_RAW_BINARY=y
|
||||
CONFIG_RR_INTERVAL=200
|
||||
CONFIG_SCHED_HPWORK=y
|
||||
CONFIG_SCHED_WAITPID=y
|
||||
CONFIG_START_DAY=6
|
||||
CONFIG_START_MONTH=12
|
||||
CONFIG_START_YEAR=2011
|
||||
CONFIG_STM32_JTAG_SW_ENABLE=y
|
||||
CONFIG_STM32_PWR=y
|
||||
CONFIG_STM32_SPI1=y
|
||||
CONFIG_STM32_USART2=y
|
||||
CONFIG_SYSTEM_NSH=y
|
||||
CONFIG_USART2_RXBUFSIZE=128
|
||||
CONFIG_USART2_SERIAL_CONSOLE=y
|
||||
CONFIG_USART2_TXBUFSIZE=128
|
||||
CONFIG_WQUEUE_NOTIFIER=y
|
||||
|
|
@ -465,6 +465,9 @@
|
|||
|
||||
#define BOARD_XEN1210_GPIO_INT GPIO_XEN1210_INT
|
||||
|
||||
#define BOARD_SBUTTON_GPIO_INT (GPIO_INPUT|GPIO_FLOAT|GPIO_EXTI|\
|
||||
GPIO_OPENDRAIN|GPIO_PORTA|GPIO_PIN0)
|
||||
|
||||
/* Define what timer to use as XEN1210 CLK (will use channel 1) */
|
||||
|
||||
#define BOARD_XEN1210_PWMTIMER 1
|
||||
|
|
|
|||
|
|
@ -98,6 +98,10 @@
|
|||
#include "stm32_nunchuck.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INPUT_SBUTTON
|
||||
#include "board_sbutton.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SENSORS_ZEROCROSS
|
||||
#include "stm32_zerocross.h"
|
||||
#endif
|
||||
|
|
@ -452,6 +456,16 @@ int stm32_bringup(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INPUT_SBUTTON
|
||||
/* Register the Single Button Dual Action driver */
|
||||
|
||||
ret = board_sbutton_initialize(0);
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ERROR: board_sbtn_initialize() failed: %d\n", ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SENSORS_APDS9960
|
||||
/* Register the APDS-9960 gesture sensor */
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,10 @@ if(CONFIG_INPUT)
|
|||
list(APPEND SRCS keyboard_upper.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_INPUT_SBUTTON)
|
||||
list(APPEND SRCS sbutton.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_INPUT_DJOYSTICK)
|
||||
list(APPEND SRCS djoystick.c)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -622,6 +622,47 @@ config INPUT_BUTTONS_NPOLLWAITERS
|
|||
|
||||
endif # INPUT_BUTTONS
|
||||
|
||||
config INPUT_SBUTTON
|
||||
bool "Single Button Multi Actions"
|
||||
select INPUT_KEYBOARD
|
||||
default n
|
||||
---help---
|
||||
Enable the Single Button Multi Actions upper half driver.
|
||||
This driver allows using a single button to generate two
|
||||
events (mapped to short press and long press). Using it
|
||||
is possible navigate a menu interface when using with a
|
||||
LCD/OLED display.
|
||||
|
||||
if INPUT_SBUTTON
|
||||
|
||||
config INPUT_SBUTTON_KEY1
|
||||
int "ASCII code to generate for short press"
|
||||
default 9
|
||||
---help---
|
||||
Which key will be generated when user do a short press.
|
||||
Default key is TAB (ASCII 9)
|
||||
|
||||
config INPUT_SBUTTON_KEY2
|
||||
int "ASCII code to generate for long press"
|
||||
default 13
|
||||
---help---
|
||||
Which key will be generated when user do a short press.
|
||||
Default key is ENTER (ASCII 13)
|
||||
|
||||
config INPUT_SBUTTON_BUFSIZE
|
||||
int "Buffer size to store keys"
|
||||
default 8
|
||||
|
||||
config INPUT_SBUTTON_KEY_THRESH_MS
|
||||
int "Threshold in milliseconds for short press"
|
||||
default 500
|
||||
|
||||
config INPUT_SBUTTON_KEY_DEBOUNCE_MS
|
||||
int "Key Debounce value in milliseconds"
|
||||
default 30
|
||||
|
||||
endif # INPUT_SBUTTON
|
||||
|
||||
config INPUT_DJOYSTICK
|
||||
bool "Discrete Joystick"
|
||||
default n
|
||||
|
|
|
|||
|
|
@ -118,6 +118,10 @@ ifeq ($(CONFIG_INPUT_NUNCHUCK),y)
|
|||
CSRCS += nunchuck.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INPUT_SBUTTON),y)
|
||||
CSRCS += sbutton.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INPUT_SPQ10KBD),y)
|
||||
CSRCS += spq10kbd.c
|
||||
endif
|
||||
|
|
|
|||
278
drivers/input/sbutton.c
Normal file
278
drivers/input/sbutton.c
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
/****************************************************************************
|
||||
* drivers/input/sbutton.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <nuttx/input/sbutton.h>
|
||||
#include <nuttx/fs/fs.h>
|
||||
#include <nuttx/clock.h>
|
||||
#include <nuttx/ascii.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/mutex.h>
|
||||
#include <nuttx/wqueue.h>
|
||||
#include <nuttx/semaphore.h>
|
||||
#include <nuttx/input/keyboard.h>
|
||||
#include <nuttx/input/kbd_codec.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* This format is used to construct the /dev/kbd[n] device driver path. It
|
||||
* defined here so that it will be used consistently in all places.
|
||||
*/
|
||||
|
||||
#define DEV_FORMAT "/dev/kbd%d"
|
||||
#define DEV_NAMELEN 12
|
||||
|
||||
#define KEY_PRESS true
|
||||
#define KEY_RELEASE false
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct sbutton_dev_s
|
||||
{
|
||||
FAR const struct sbutton_config_s *config; /* Board configuration data */
|
||||
|
||||
mutex_t lock; /* Exclusive access to dev */
|
||||
clock_t start; /* Clock tick when the key was pressed */
|
||||
clock_t end; /* Clock tick when the key was released */
|
||||
bool pressed; /* Keep previous status of button */
|
||||
struct work_s work; /* Supports the interrupt handling "bottom half" */
|
||||
|
||||
/* Keyboard lowerhalf of the registered keyboard */
|
||||
|
||||
struct keyboard_lowerhalf_s lower;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Static Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int sbutton_interrupt(int irq, FAR void *context, FAR void *arg);
|
||||
static void sbutton_worker(FAR void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sbutton_worker
|
||||
****************************************************************************/
|
||||
|
||||
static void sbutton_worker(FAR void *arg)
|
||||
{
|
||||
FAR struct sbutton_dev_s *priv = (FAR struct sbutton_dev_s *)arg;
|
||||
uint8_t state;
|
||||
int ret;
|
||||
|
||||
ret = nxmutex_lock(&priv->lock);
|
||||
if (ret < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read the status of the button */
|
||||
|
||||
state = priv->config->status();
|
||||
|
||||
/* If the user just pressed the button, start measuring */
|
||||
|
||||
if (state == KEY_PRESS && !priv->pressed)
|
||||
{
|
||||
iinfo("Button pressed\n");
|
||||
|
||||
priv->pressed = true;
|
||||
priv->start = clock_systime_ticks();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state == KEY_RELEASE && priv->pressed)
|
||||
{
|
||||
uint32_t elapsed;
|
||||
|
||||
iinfo("Button released\n");
|
||||
|
||||
priv->pressed = false;
|
||||
|
||||
priv->end = clock_systime_ticks();
|
||||
elapsed = priv->end - priv->start;
|
||||
|
||||
/* Debounce to avoid getting wrong press/release event */
|
||||
|
||||
if (elapsed < MSEC2TICK(CONFIG_INPUT_SBUTTON_KEY_DEBOUNCE_MS))
|
||||
{
|
||||
iwarn("Button event too short, ignoring it\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (elapsed < MSEC2TICK(CONFIG_INPUT_SBUTTON_KEY_THRESH_MS))
|
||||
{
|
||||
iinfo("KEY_1\n");
|
||||
keyboard_event(&priv->lower, CONFIG_INPUT_SBUTTON_KEY1,
|
||||
KEYBOARD_PRESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
iinfo("KEY_2\n");
|
||||
keyboard_event(&priv->lower, CONFIG_INPUT_SBUTTON_KEY2,
|
||||
KEYBOARD_PRESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Unlock and return */
|
||||
|
||||
nxmutex_unlock(&priv->lock);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sbutton_interrupt
|
||||
****************************************************************************/
|
||||
|
||||
static int sbutton_interrupt(int irq, FAR void *context, FAR void *arg)
|
||||
{
|
||||
FAR struct sbutton_dev_s *priv = (FAR struct sbutton_dev_s *)arg;
|
||||
int ret;
|
||||
|
||||
/* Let the event worker know that it has an interrupt event to handle
|
||||
* It is possible that we will already have work scheduled from a
|
||||
* previous interrupt event. That is OK we will service all the events
|
||||
* in the same work job.
|
||||
*/
|
||||
|
||||
if (work_available(&priv->work))
|
||||
{
|
||||
ret = work_queue(HPWORK, &priv->work, sbutton_worker, priv, 0);
|
||||
if (ret != 0)
|
||||
{
|
||||
ierr("ERROR: Failed to queue work: %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sbutton_register
|
||||
*
|
||||
* Description:
|
||||
* Configure the Single Button Multi Key Keyboard to use the provided
|
||||
* instance. This will register the driver as /dev/kbdN where N is the
|
||||
* minor device number.
|
||||
*
|
||||
* Input Parameters:
|
||||
* config - Persistent board configuration data
|
||||
* kbdminor - The keyboard input device minor number
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned on success. Otherwise, a negated errno value is
|
||||
* returned to indicate the nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int sbutton_register(FAR const struct sbutton_config_s *config,
|
||||
char kbdminor)
|
||||
{
|
||||
FAR struct sbutton_dev_s *priv;
|
||||
char kbddevname[DEV_NAMELEN];
|
||||
int ret;
|
||||
|
||||
/* Debug Sanity Checks */
|
||||
|
||||
DEBUGASSERT(config != NULL);
|
||||
DEBUGASSERT(config->attach != NULL);
|
||||
DEBUGASSERT(config->enable != NULL);
|
||||
DEBUGASSERT(config->clear != NULL);
|
||||
|
||||
priv = kmm_zalloc(sizeof(struct sbutton_dev_s));
|
||||
if (!priv)
|
||||
{
|
||||
ierr("ERROR: kmm_zalloc(%d) failed\n", sizeof(struct sbutton_dev_s));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Initialize the device driver instance */
|
||||
|
||||
priv->config = config; /* Save the board configuration */
|
||||
priv->pressed = false;
|
||||
|
||||
nxmutex_init(&priv->lock); /* Initialize device mutex */
|
||||
|
||||
config->clear(config);
|
||||
config->enable(config, false);
|
||||
|
||||
/* Attach the interrupt handler */
|
||||
|
||||
ret = config->attach(config, sbutton_interrupt, priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
ierr("ERROR: Failed to attach interrupt\n");
|
||||
goto errout_with_priv;
|
||||
}
|
||||
|
||||
/* Start servicing events */
|
||||
|
||||
priv->config->enable(priv->config, true);
|
||||
|
||||
snprintf(kbddevname, sizeof(kbddevname), DEV_FORMAT, kbdminor);
|
||||
|
||||
/* Register the device as a keyboard device */
|
||||
|
||||
ret = keyboard_register(&priv->lower, kbddevname,
|
||||
CONFIG_INPUT_SBUTTON_BUFSIZE);
|
||||
if (ret < 0)
|
||||
{
|
||||
ierr("ERROR: keyboard_register() failed: %d\n", ret);
|
||||
goto errout_with_priv;
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
errout_with_priv:
|
||||
nxmutex_destroy(&priv->lock);
|
||||
kmm_free(priv);
|
||||
return ret;
|
||||
}
|
||||
113
include/nuttx/input/sbutton.h
Normal file
113
include/nuttx/input/sbutton.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/****************************************************************************
|
||||
* include/nuttx/input/sbutton.h
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* The single button driver exports a standard character driver interface. By
|
||||
* convention, the driver is exposed as /dev/kbd[n] and works like a common
|
||||
* keyboard device, but generates only INPUT_TAB and INPUT_ENTER events.
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_INPUT_SBUTTON_H
|
||||
#define __INCLUDE_NUTTX_INPUT_SBUTTON_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
#include <stdbool.h>
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* A reference to a structure of this type must be passed to the
|
||||
* single button keyboard driver. This structure provides information
|
||||
* about the configuration and provides some board-specific hooks.
|
||||
*/
|
||||
|
||||
struct sbutton_config_s
|
||||
{
|
||||
/* IRQ/GPIO access callbacks. These operations all hidden behind
|
||||
* callbacks to isolate the Q10 Keyboard driver from differences in GPIO
|
||||
* interrupt handling by varying boards and MCUs.
|
||||
*
|
||||
* attach - Attach the Q10 kbd interrupt handler to the GPIO interrupt
|
||||
* enable - Enable or disable the GPIO interrupt
|
||||
* clear - Acknowledge/clear any pending GPIO interrupt
|
||||
*/
|
||||
|
||||
int (*attach)(FAR const struct sbutton_config_s *config, xcpt_t isr,
|
||||
FAR void *arg);
|
||||
void (*enable)(FAR const struct sbutton_config_s *config, bool enable);
|
||||
void (*clear)(FAR const struct sbutton_config_s *config);
|
||||
bool (*status)(void);
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: spq10kbd_register
|
||||
*
|
||||
* Description:
|
||||
* Configure the single button driver to use the provided instance.
|
||||
* This will register the driver as /dev/kbdN where N is the
|
||||
* minor device number.
|
||||
*
|
||||
* Input Parameters:
|
||||
* config - Persistent board configuration data
|
||||
* kbdminor - The keyboard input device minor number
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned on success. Otherwise, a negated errno value is
|
||||
* returned to indicate the nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int sbutton_register(FAR const struct sbutton_config_s *config,
|
||||
char kbdminor);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_INPUT_SBUTTON_H */
|
||||
Loading…
Add table
Reference in a new issue