From 6e1084116b33cc9f7f440593406e1604f02f71c6 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 14 Dec 2014 10:19:07 -0600 Subject: [PATCH] SIM: Add an X11 mouse-based simulation of an analog joystick device --- arch/sim/Kconfig | 19 ++- arch/sim/src/Makefile | 5 + arch/sim/src/up_ajoystick.c | 274 +++++++++++++++++++++++++++++++ arch/sim/src/up_idle.c | 2 +- arch/sim/src/up_internal.h | 22 ++- arch/sim/src/up_x11eventloop.c | 21 ++- arch/sim/src/up_x11framebuffer.c | 4 +- configs/sim/src/Makefile | 1 + configs/sim/src/sim_boot.c | 8 + configs/sim/traveler/defconfig | 2 + 10 files changed, 348 insertions(+), 10 deletions(-) create mode 100644 arch/sim/src/up_ajoystick.c diff --git a/arch/sim/Kconfig b/arch/sim/Kconfig index 4fda868f12..e5fcad556b 100644 --- a/arch/sim/Kconfig +++ b/arch/sim/Kconfig @@ -98,13 +98,28 @@ config SIM_FBBPP endif # SIM_FRAMEBUFFER +if SIM_X11FB && INPUT +choice + prompt "X11 Simulated Input Device" + default SIM_NOINPUT + config SIM_TOUCHSCREEN - bool "Support an X11 mouse-based touchscreen emulation" + bool "X11 mouse-based touchscreen emulation" default n - depends on SIM_X11FB && INPUT ---help--- Support an X11 mouse-based touchscreen emulation. Also needs INPUT=y +config SIM_AJOYSTICK + bool "X11 mouse-based analog joystick emulation" + ---help--- + Support an X11 mouse-based anallog joystick emulation. Also needs INPUT=y` + +config SIM_NOINPUT + bool "No input device" + +endchoice # X11 Simulated Input Device +endif # SIM_X11FB && INPUT + config SIM_TCNWAITERS bool "Maximum number poll() waiters" default 4 diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index ae537c173b..4507ce60de 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -77,6 +77,11 @@ ifeq ($(CONFIG_SIM_X11FB),y) ifeq ($(CONFIG_SIM_TOUCHSCREEN),y) CSRCS += up_touchscreen.c HOSTSRCS += up_x11eventloop.c +else +ifeq ($(CONFIG_SIM_AJOYSTICK),y) + CSRCS += up_ajoystick.c + HOSTSRCS += up_x11eventloop.c +endif endif endif endif diff --git a/arch/sim/src/up_ajoystick.c b/arch/sim/src/up_ajoystick.c new file mode 100644 index 0000000000..69dd149e83 --- /dev/null +++ b/arch/sim/src/up_ajoystick.c @@ -0,0 +1,274 @@ +/**************************************************************************** + * arch/sim/src/up_ajoystick.c + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "up_internal.h" + +#ifdef CONFIG_AJOYSTICK + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +# define AJOY_SUPPORTED (AJOY_BUTTON_1_BIT | AJOY_BUTTON_2_BIT | \ + AJOY_BUTTON_3_BIT) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static ajoy_buttonset_t ajoy_supported(FAR const struct ajoy_lowerhalf_s *lower); +static int ajoy_sample(FAR const struct ajoy_lowerhalf_s *lower, + FAR struct ajoy_sample_s *sample); +static ajoy_buttonset_t ajoy_buttons(FAR const struct ajoy_lowerhalf_s *lower); +static void ajoy_enable(FAR const struct ajoy_lowerhalf_s *lower, + ajoy_buttonset_t press, ajoy_buttonset_t release, + ajoy_handler_t handler, FAR void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This is the button joystick lower half driver interface */ + +static const struct ajoy_lowerhalf_s g_ajoylower = +{ + .al_supported = ajoy_supported, + .al_sample = ajoy_sample, + .al_buttons = ajoy_buttons, + .al_enable = ajoy_enable, +}; + +/* Driver state data */ + +static volatile bool g_ajoy_valid; /* True: Sample data is valid */ +static volatile bool g_ajoy_waiting; /* True: Waiting for button data */ +static sem_t g_ajoy_waitsem; /* Semaphore used to support waiting */ +static struct ajoy_sample_s g_ajoy_sample; /* Last sample data */ +static ajoy_buttonset_t g_ajoy_buttons; /* Last buttons set */ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ajoy_supported + * + * Description: + * Return the set of buttons supported on the button joystick device + * + ****************************************************************************/ + +static ajoy_buttonset_t ajoy_supported(FAR const struct ajoy_lowerhalf_s *lower) +{ + return (ajoy_buttonset_t)AJOY_SUPPORTED; +} + +/**************************************************************************** + * Name: ajoy_sample + * + * Description: + * Return the current state of all button joystick buttons + * + ****************************************************************************/ + +static int ajoy_sample(FAR const struct ajoy_lowerhalf_s *lower, + FAR struct ajoy_sample_s *sample) +{ + memcpy(sample, &g_ajoy_sample, sizeof(struct ajoy_sample_s)); + g_ajoy_buttons = g_ajoy_sample.as_buttons; + g_ajoy_valid = false; + return OK; +} + +/**************************************************************************** + * Name: ajoy_buttons + * + * Description: + * Return the current state of button data (only) + * + ****************************************************************************/ + +static ajoy_buttonset_t ajoy_buttons(FAR const struct ajoy_lowerhalf_s *lower) +{ + g_ajoy_valid = false; + g_ajoy_buttons = g_ajoy_sample.as_buttons; + return g_ajoy_buttons; +} + +/**************************************************************************** + * Name: ajoy_enable + * + * Description: + * Enable interrupts on the selected set of joystick buttons. And empty + * set will disable all interrupts. + * + ****************************************************************************/ + +static void ajoy_enable(FAR const struct ajoy_lowerhalf_s *lower, + ajoy_buttonset_t pressset, ajoy_buttonset_t releaseset, + ajoy_handler_t handler, FAR void *arg) +{ + if (handler) + { + ajoy_buttonset_t changed; + ajoy_buttonset_t pressed; + ajoy_buttonset_t released; + + g_ajoy_waiting = true; + while (!g_ajoy_valid) + { + (void)sem_wait(&g_ajoy_waitsem); + + if (g_ajoy_valid) + { + g_ajoy_valid = false; + changed = g_ajoy_buttons ^ g_ajoy_sample.as_buttons; + + pressed = changed & (AJOY_SUPPORTED & g_ajoy_buttons); + if ((pressed & pressset) != 0 ) + { + break; + } + + released = changed & (AJOY_SUPPORTED & ~g_ajoy_buttons); + if ((released & releaseset) != 0) + { + break; + } + } + } + + g_ajoy_waiting = false; + + /* Call the interrupt handler */ + + handler(&g_ajoylower, arg); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sim_ajoy_initialize + * + * Description: + * Initialize and register the button joystick driver + * + ****************************************************************************/ + +int sim_ajoy_initialize(void) +{ + int ret; + + /* Initialize the wait semaphore */ + + sem_init(&g_ajoy_waitsem, 0, 0); + + /* Register the joystick device as /dev/ajoy0 */ + + ret = ajoy_register("/dev/ajoy0", &g_ajoylower); + if (ret == OK) + { + /* Enable X11 event processing from the IDLE loop */ + + g_eventloop = 1; + } +} + +/**************************************************************************** + * Name: up_buttonevent + ****************************************************************************/ + +int up_buttonevent(int x, int y, int buttons) +{ + /* Same the positional data */ + + g_ajoy_sample.as_x = x; + g_ajoy_sample.as_y = y; + + /* Map X11 buttons to joystick buttons */ + + g_ajoy_sample.as_buttons = 0; + if ((buttons & 1) != 0) + { + g_ajoy_sample.as_buttons |= AJOY_BUTTON_1_BIT; + } + + if ((buttons & 1) != 0) + { + g_ajoy_sample.as_buttons |= AJOY_BUTTON_2_BIT; + } + + if ((buttons & 1) != 0) + { + g_ajoy_sample.as_buttons |= AJOY_BUTTON_3_BIT; + } + + /* Sample data is valid */ + + g_ajoy_valid = true; + + /* Is there a task waiting for joystick input? */ + + if (g_ajoy_waiting) + { + sem_post(&g_ajoy_waitsem); + } + + return OK; +} + +#endif /* CONFIG_AJOYSTICK */ diff --git a/arch/sim/src/up_idle.c b/arch/sim/src/up_idle.c index cfe4a7d6d0..ae7c2d7040 100644 --- a/arch/sim/src/up_idle.c +++ b/arch/sim/src/up_idle.c @@ -153,7 +153,7 @@ void up_idle(void) #ifdef CONFIG_SIM_X11FB if (g_x11initialized) { -#ifdef CONFIG_SIM_TOUCHSCREEN +#if defined(CONFIG_SIM_TOUCHSCREEN) || defined(CONFIG_SIM_AJOYSTICK) /* Drive the X11 event loop */ if (g_eventloop) diff --git a/arch/sim/src/up_internal.h b/arch/sim/src/up_internal.h index c2fac55d25..80c9cc81a8 100644 --- a/arch/sim/src/up_internal.h +++ b/arch/sim/src/up_internal.h @@ -61,6 +61,10 @@ # error "CONFIG_SIM_TOUCHSCREEN depends on CONFIG_SIM_X11FB" # undef CONFIG_SIM_TOUCHSCREEN # endif +# ifdef CONFIG_SIM_AJOYSTICK +# error "CONFIG_SIM_AJOYSTICK depends on CONFIG_SIM_X11FB" +# undef CONFIG_SIM_AJOYSTICK +# endif #endif #ifndef CONFIG_INPUT @@ -68,6 +72,10 @@ # error "CONFIG_SIM_TOUCHSCREEN depends on CONFIG_INPUT" # undef CONFIG_SIM_TOUCHSCREEN # endif +# ifdef CONFIG_SIM_AJOYSTICK +# error "CONFIG_SIM_AJOYSTICK depends on CONFIG_INPUT" +# undef CONFIG_SIM_AJOYSTICK +# endif #endif /* Determine which (if any) console driver to use */ @@ -184,7 +192,7 @@ #ifdef CONFIG_SIM_X11FB extern int g_x11initialized; -#ifdef CONFIG_SIM_TOUCHSCREEN +#if defined(CONFIG_SIM_TOUCHSCREEN) || defined(CONFIG_SIM_AJOYSTICK) extern volatile int g_eventloop; #endif #endif @@ -251,16 +259,24 @@ int up_x11cmap(unsigned short first, unsigned short len, /* up_eventloop.c *********************************************************/ -#if defined(CONFIG_SIM_X11FB) && defined(CONFIG_SIM_TOUCHSCREEN) +#if defined(CONFIG_SIM_X11FB) && \ + (defined(CONFIG_SIM_TOUCHSCREEN) || defined(CONFIG_SIM_AJOYSTICK)) void up_x11events(void); #endif /* up_eventloop.c *********************************************************/ -#if defined(CONFIG_SIM_X11FB) && defined(CONFIG_SIM_TOUCHSCREEN) +#if defined(CONFIG_SIM_X11FB) && \ + (defined(CONFIG_SIM_TOUCHSCREEN) || defined(CONFIG_SIM_AJOYSTICK)) int up_buttonevent(int x, int y, int buttons); #endif +/* up_ajoystick.c *********************************************************/ + +#ifdef CONFIG_SIM_AJOYSTICK +int sim_ajoy_initialize(void); +#endif + /* up_tapdev.c ************************************************************/ #if defined(CONFIG_NET) && !defined(__CYGWIN__) diff --git a/arch/sim/src/up_x11eventloop.c b/arch/sim/src/up_x11eventloop.c index 630bc80e1b..a7c29e1eca 100644 --- a/arch/sim/src/up_x11eventloop.c +++ b/arch/sim/src/up_x11eventloop.c @@ -83,9 +83,26 @@ volatile int g_eventloop; static int up_buttonmap(int state) { - /* Remove any X11 dependencies. Just maps Button1Mask to bit 0. */ + int buttons = 0; - return ((state & Button1Mask) != 0) ? 1 : 0; + /* Remove any X11 dependencies. Just maps ButtonNMask to bit N. */ + + if ((state & Button1Mask) != 0) + { + buttons |= 1; + } + + if ((state & Button2Mask) != 0) + { + buttons |= 2; + } + + if ((state & Button3Mask) != 0) + { + buttons |= 4; + } + + return buttons; } /**************************************************************************** diff --git a/arch/sim/src/up_x11framebuffer.c b/arch/sim/src/up_x11framebuffer.c index 39bd3647e3..5eb3b2a23e 100644 --- a/arch/sim/src/up_x11framebuffer.c +++ b/arch/sim/src/up_x11framebuffer.c @@ -136,7 +136,7 @@ static inline int up_x11createframe(void) /* Release queued events on the display */ -#ifdef CONFIG_SIM_TOUCHSCREEN +#if defined(CONFIG_SIM_TOUCHSCREEN) || defined(CONFIG_SIM_AJOYSTICK) (void)XAllowEvents(g_display, AsyncBoth, CurrentTime); /* Grab mouse button 1, enabling mouse-related events */ @@ -222,7 +222,7 @@ static void up_x11uninitX(void) /* Un-grab the mouse buttons */ -#ifdef CONFIG_SIM_TOUCHSCREEN +#if defined(CONFIG_SIM_TOUCHSCREEN) || defined(CONFIG_SIM_AJOYSTICK) XUngrabButton(g_display, Button1, AnyModifier, g_window); #endif g_x11initialized = 0; diff --git a/configs/sim/src/Makefile b/configs/sim/src/Makefile index 73de2f5b57..c07947f976 100644 --- a/configs/sim/src/Makefile +++ b/configs/sim/src/Makefile @@ -36,6 +36,7 @@ include $(TOPDIR)/Make.defs CFLAGS += -I$(TOPDIR)/sched +CFLAGS += -I$(TOPDIR)/arch/sim/src ASRCS = AOBJS = $(ASRCS:.S=$(OBJEXT)) diff --git a/configs/sim/src/sim_boot.c b/configs/sim/src/sim_boot.c index ef84a689e9..e4e282c784 100644 --- a/configs/sim/src/sim_boot.c +++ b/configs/sim/src/sim_boot.c @@ -40,6 +40,8 @@ #include #include +#include "up_internal.h" + #ifdef CONFIG_GRAPHICS_TRAVELER_ROMFSDEMO int trv_mount_world(int minor, FAR const char *mountpoint); #endif @@ -80,6 +82,12 @@ int trv_mount_world(int minor, FAR const char *mountpoint); #ifdef CONFIG_BOARD_INITIALIZE void board_initialize(void) { +#ifdef CONFIG_AJOYSTICK + /* Initialize the simulated analog joystick input device */ + + sim_ajoy_initialize(); +#endif + #ifdef CONFIG_GRAPHICS_TRAVELER_ROMFSDEMO /* Special initialization for the Traveler game simulation */ diff --git a/configs/sim/traveler/defconfig b/configs/sim/traveler/defconfig index 4f4f2d63a2..f12eb8df7d 100644 --- a/configs/sim/traveler/defconfig +++ b/configs/sim/traveler/defconfig @@ -102,6 +102,8 @@ CONFIG_SIM_FBHEIGHT=400 CONFIG_SIM_FBWIDTH=640 CONFIG_SIM_FBBPP=32 # CONFIG_SIM_TOUCHSCREEN is not set +CONFIG_SIM_AJOYSTICK=y +# CONFIG_SIM_NOINPUT is not set # CONFIG_SIM_SPIFLASH is not set #