From b5ce2405501aa693fc4c134e3425e74ba0ff7589 Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Thu, 16 May 2013 02:06:53 +1000 Subject: [PATCH] X driver for GDISP and GINPUT_MOUSE --- drivers/multiple/X/gdisp_lld.c | 324 +++++++++++++++++++ drivers/multiple/X/gdisp_lld.mk | 5 + drivers/multiple/X/gdisp_lld_config.h | 44 +++ drivers/multiple/X/ginput_lld_mouse_config.h | 50 +++ drivers/multiple/X/readme.txt | 27 ++ gfxconf.example.h | 1 + include/gdisp/options.h | 6 + 7 files changed, 457 insertions(+) create mode 100644 drivers/multiple/X/gdisp_lld.c create mode 100644 drivers/multiple/X/gdisp_lld.mk create mode 100644 drivers/multiple/X/gdisp_lld_config.h create mode 100644 drivers/multiple/X/ginput_lld_mouse_config.h create mode 100644 drivers/multiple/X/readme.txt diff --git a/drivers/multiple/X/gdisp_lld.c b/drivers/multiple/X/gdisp_lld.c new file mode 100644 index 00000000..139cc420 --- /dev/null +++ b/drivers/multiple/X/gdisp_lld.c @@ -0,0 +1,324 @@ +/* + * This file is subject to the terms of the GFX License, v1.0. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://chibios-gfx.com/license.html + */ + +/** + * @file drivers/multiple/X/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source for X. + */ + +#include "ch.h" +#include "hal.h" +#include "gfx.h" + +#if GFX_USE_GDISP + +/* Our threading model - ChibiOS or POSIX */ +#ifndef GDISP_THREAD_CHIBIOS + #define GDISP_THREAD_CHIBIOS TRUE +#endif + +/** + * Our color model - Default or 24 bit only. + * + * At present we don't define this as we don't need to. + * It may however be useful later if we implement bitblits. + * As this may be dead code we don't include it in gdisp/options.h + */ +#ifndef GDISP_FORCE_24BIT + #define GDISP_FORCE_24BIT FALSE +#endif + +#if GINPUT_NEED_MOUSE + /* Include mouse support code */ + #include "ginput/lld/mouse.h" +#endif + +/* Include the emulation code for things we don't support */ +#include "gdisp/lld/emulation.c" + +#include +#include +#include +#include +#if !GDISP_THREAD_CHIBIOS + #include +#endif + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 480 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 640 +#endif + +Display *dis; +int scr; +Window win; +Pixmap pix; +XEvent evt; +GC gc; +Colormap cmap; +XVisualInfo vis; +int depth; +#if GINPUT_NEED_MOUSE + coord_t mousex, mousey; + uint16_t mousebuttons; +#endif + +static void ProcessEvent(void) { + XColor col; + + switch(evt.type) { + case Expose: + XCopyArea(dis, pix, win, gc, + evt.xexpose.x, evt.xexpose.y, + evt.xexpose.width, evt.xexpose.height, + evt.xexpose.x, evt.xexpose.y); + break; +#if GINPUT_NEED_MOUSE + case ButtonPress: + mousex = evt.xbutton.x; + mousey = evt.xbutton.y; + switch(evt.xbutton.button){ + case 1: mousebuttons |= GINPUT_MOUSE_BTN_LEFT; break; + case 2: mousebuttons |= GINPUT_MOUSE_BTN_MIDDLE; break; + case 3: mousebuttons |= GINPUT_MOUSE_BTN_RIGHT; break; + case 4: mousebuttons |= GINPUT_MOUSE_BTN_4; break; + } + #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE + ginputMouseWakeup(); + #endif + break; + case ButtonRelease: + mousex = evt.xbutton.x; + mousey = evt.xbutton.y; + switch(evt.xbutton.button){ + case 1: mousebuttons &= ~GINPUT_MOUSE_BTN_LEFT; break; + case 2: mousebuttons &= ~GINPUT_MOUSE_BTN_MIDDLE; break; + case 3: mousebuttons &= ~GINPUT_MOUSE_BTN_RIGHT; break; + case 4: mousebuttons &= ~GINPUT_MOUSE_BTN_4; break; + } + #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE + ginputMouseWakeup(); + #endif + break; + case MotionNotify: + mousex = evt.xmotion.x; + mousey = evt.xmotion.y; + #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE + ginputMouseWakeup(); + #endif + break; +#endif + } +} + +/* this is the X11 thread which keeps track of all events */ +#if GDISP_THREAD_CHIBIOS + static WORKING_AREA(waXThread, 1024); + static msg_t ThreadX(void *arg) { + (void)arg; + + while(1) { + chThdSleepMilliseconds(100); + while(XPending(dis)) { + XNextEvent(dis, &evt); + ProcessEvent(); + } + } + return 0; + } +#else + static void * ThreadX(void *arg) { + (void)arg; + + while(1) { + pthread_yield(); // This could be a 100ms delay + while(XPending(dis)) { + XNextEvent(dis, &evt); + ProcessEvent(); + } + } + return 0; + } +#endif + +static int FatalXIOError(Display *d) { + (void) d; + + /* The window has closed */ + fprintf(stderr, "GFX Window closed!\n"); + exit(0); +} + +bool_t gdisp_lld_init(void) +{ + XSizeHints *pSH; + XSetWindowAttributes xa; + XTextProperty WindowTitle; + char * WindowTitleText; + #if !GDISP_THREAD_CHIBIOS + pthread_attr_t thattr; + pthread_t thid; + #endif + + #if !GDISP_THREAD_CHIBIOS + XInitThreads(); + #endif + + dis = XOpenDisplay(NULL); + scr = DefaultScreen(dis); + + #if GDISP_FORCE_24BIT + if (!XMatchVisualInfo(dis, scr, 24, TrueColor, &vis)) { + fprintf(stderr, "Your display has no TrueColor mode\n"); + XCloseDisplay(dis); + return FALSE; + } + cmap = XCreateColormap(dis, RootWindow(dis, scr), + vis.visual, AllocNone); + #else + vis.visual = CopyFromParent; + vis.depth = DefaultDepth(dis, scr); + cmap = DefaultColormap(dis, scr); + #endif + fprintf(stderr, "Running GFX Window in %d bit color\n", vis.depth); + + xa.colormap = cmap; + xa.border_pixel = 0xFFFFFF; + xa.background_pixel = 0x000000; + + win = XCreateWindow(dis, RootWindow(dis, scr), 16, 16, + GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, + 0, vis.depth, InputOutput, vis.visual, + CWBackPixel|CWColormap|CWBorderPixel, &xa); + XSync(dis, TRUE); + + WindowTitleText = "GFX"; + XStringListToTextProperty(&WindowTitleText, 1, &WindowTitle); + XSetWMName(dis, win, &WindowTitle); + XSetWMIconName(dis, win, &WindowTitle); + XSync(dis, TRUE); + + pSH = XAllocSizeHints(); + pSH->flags = PSize | PMinSize | PMaxSize; + pSH->min_width = pSH->max_width = pSH->base_width = GDISP_SCREEN_WIDTH; + pSH->min_height = pSH->max_height = pSH->base_height = GDISP_SCREEN_HEIGHT; + XSetWMNormalHints(dis, win, pSH); + XFree(pSH); + XSync(dis, TRUE); + + pix = XCreatePixmap(dis, win, + GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, vis.depth); + XSync(dis, TRUE); + + gc = XCreateGC(dis, win, 0, 0); + XSetBackground(dis, gc, BlackPixel(dis, scr)); + XSync(dis, TRUE); + + XSelectInput(dis, win, StructureNotifyMask); + XMapWindow(dis, win); + do { XNextEvent(dis, &evt); } while (evt.type != MapNotify); + + /* start the X11 thread */ + XSetIOErrorHandler(FatalXIOError); + XSelectInput(dis, win, + ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask); + + #if GDISP_THREAD_CHIBIOS + if (!chThdCreateStatic(waXThread, sizeof(waXThread), HIGHPRIO, ThreadX, 0)) { + #else + if (pthread_attr_init(&thattr) + || pthread_attr_setdetachstate(&thattr, PTHREAD_CREATE_DETACHED) + || pthread_create(&thid, &thattr, ThreadX, 0)) { + #endif + fprintf(stderr, "Cannot start X Thread\n"); + XCloseDisplay(dis); + exit(0); + } + + /* Initialise the GDISP structure to match */ + GDISP.Orientation = GDISP_ROTATE_0; + GDISP.Powermode = powerOn; + GDISP.Backlight = 100; + GDISP.Contrast = 50; + GDISP.Width = GDISP_SCREEN_WIDTH; + GDISP.Height = GDISP_SCREEN_HEIGHT; + #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP + GDISP.clipx0 = 0; + GDISP.clipy0 = 0; + GDISP.clipx1 = GDISP.Width; + GDISP.clipy1 = GDISP.Height; + #endif + return TRUE; +} + +void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) +{ + XColor col; + + #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP + // Clip pre orientation change + if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; + #endif + + col.red = RED_OF(color) << 8; + col.green = GREEN_OF(color) << 8; + col.blue = BLUE_OF(color) << 8; + XAllocColor(dis, cmap, &col); + XSetForeground(dis, gc, col.pixel); + XDrawPoint(dis, pix, gc, (int)x, (int)y ); + XDrawPoint(dis, win, gc, (int)x, (int)y ); + XFlush(dis); +} + +void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { + XColor col; + + #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP + // Clip pre orientation change + if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } + if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } + if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; + if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; + if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; + #endif + + col.red = RED_OF(color) << 8; + col.green = GREEN_OF(color) << 8; + col.blue = BLUE_OF(color) << 8; + XAllocColor(dis, cmap, &col); + XSetForeground(dis, gc, col.pixel); + XFillRectangle(dis, pix, gc, x, y, cx, cy); + XFillRectangle(dis, win, gc, x, y, cx, cy); + XFlush(dis); +} + +// Start of Bitblit code +//XImage bitmap; +//pixel_t *bits; +// bits = malloc(vis.depth * GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT); +// bitmap = XCreateImage(dis, vis, vis.depth, ZPixmap, +// 0, bits, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, +// 0, 0); + +#if GINPUT_NEED_MOUSE + + void ginput_lld_mouse_init(void) {} + + void ginput_lld_mouse_get_reading(MouseReading *pt) { + pt->x = mousex; + pt->y = mousey; + pt->z = (mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0; + pt->buttons = mousebuttons; + } + +#endif /* GINPUT_NEED_MOUSE */ + +#endif /* GFX_USE_GDISP */ +/** @} */ + diff --git a/drivers/multiple/X/gdisp_lld.mk b/drivers/multiple/X/gdisp_lld.mk new file mode 100644 index 00000000..1a4fc4d7 --- /dev/null +++ b/drivers/multiple/X/gdisp_lld.mk @@ -0,0 +1,5 @@ +# List the required driver. +GFXSRC += $(GFXLIB)/drivers/multiple/X/gdisp_lld.c + +# Required include directories +GFXINC += $(GFXLIB)/drivers/multiple/X diff --git a/drivers/multiple/X/gdisp_lld_config.h b/drivers/multiple/X/gdisp_lld_config.h new file mode 100644 index 00000000..dfa1972d --- /dev/null +++ b/drivers/multiple/X/gdisp_lld_config.h @@ -0,0 +1,44 @@ +/* + * This file is subject to the terms of the GFX License, v1.0. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://chibios-gfx.com/license.html + */ + +/** + * @file drivers/multiple/X/gdisp_lld_config.h + * @brief GDISP Graphic Driver subsystem low level driver header for the X11 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_CONFIG_H +#define _GDISP_LLD_CONFIG_H + +#if GFX_USE_GDISP + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +#define GDISP_DRIVER_NAME "Linux emulator - X11" + +#define GDISP_HARDWARE_CLEARS FALSE +#define GDISP_HARDWARE_FILLS TRUE +#define GDISP_HARDWARE_BITFILLS FALSE +#define GDISP_HARDWARE_SCROLL FALSE +#define GDISP_HARDWARE_PIXELREAD FALSE +#define GDISP_HARDWARE_CONTROL FALSE +#define GDISP_HARDWARE_CIRCLES FALSE +#define GDISP_HARDWARE_CIRCLEFILLS FALSE +#define GDISP_HARDWARE_ARCS FALSE +#define GDISP_HARDWARE_ARCFILLS FALSE + +#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 + +#endif /* GFX_USE_GDISP */ + +#endif /* _GDISP_LLD_CONFIG_H */ +/** @} */ + diff --git a/drivers/multiple/X/ginput_lld_mouse_config.h b/drivers/multiple/X/ginput_lld_mouse_config.h new file mode 100644 index 00000000..93f3d5f8 --- /dev/null +++ b/drivers/multiple/X/ginput_lld_mouse_config.h @@ -0,0 +1,50 @@ +/* + * This file is subject to the terms of the GFX License, v1.0. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://chibios-gfx.com/license.html + */ + +/** + * @file drivers/multiple/X/ginput_lld_mouse_config.h + * @brief GINPUT LLD header file for mouse/touch driver. + * + * @defgroup Mouse Mouse + * @ingroup GINPUT + * + * @{ + */ + +#ifndef _LLD_GINPUT_MOUSE_CONFIG_H +#define _LLD_GINPUT_MOUSE_CONFIG_H + +// This driver supports being both a mouse or a touch device (we don't actually know which it really is) +// When operating in mouse mode a long left button click does not generate a context click. +// When operating in touch mode we allow sloppier clicks etc +#if 1 + #define GINPUT_MOUSE_EVENT_TYPE GEVENT_MOUSE + #define GINPUT_MOUSE_CLICK_TIME TIME_INFINITE // Long click != Context Click + #define GINPUT_MOUSE_NEED_CALIBRATION FALSE + #define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE + #define GINPUT_MOUSE_READ_CYCLES 1 + #define GINPUT_MOUSE_MAX_CALIBRATION_ERROR -1 + #define GINPUT_MOUSE_MAX_CLICK_JITTER 0 + #define GINPUT_MOUSE_MAX_MOVE_JITTER 0 +#else + #define GINPUT_MOUSE_EVENT_TYPE GEVENT_TOUCH + #define GINPUT_MOUSE_CLICK_TIME 700 // Long click = Context Click + #define GINPUT_MOUSE_NEED_CALIBRATION FALSE // Can be set to TRUE just for testing + #define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE + #define GINPUT_MOUSE_READ_CYCLES 1 + #define GINPUT_MOUSE_MAX_CALIBRATION_ERROR 2 + #define GINPUT_MOUSE_MAX_CLICK_JITTER 2 + #define GINPUT_MOUSE_MAX_MOVE_JITTER 2 +#endif + +// This driver supports both an "interrupt" mode, and a polled mode +#define GINPUT_MOUSE_POLL_PERIOD TIME_INFINITE // Interrupt driven by the Window thread +//#define GINPUT_MOUSE_POLL_PERIOD 25 // Poll driven + +#endif /* _LLD_GINPUT_MOUSE_CONFIG_H */ +/** @} */ + diff --git a/drivers/multiple/X/readme.txt b/drivers/multiple/X/readme.txt new file mode 100644 index 00000000..9c54b143 --- /dev/null +++ b/drivers/multiple/X/readme.txt @@ -0,0 +1,27 @@ +To use this driver: + +This driver is special in that it implements both the gdisp low level driver +and a touchscreen driver. + +1. Add in your gfxconf.h: + a) #define GFX_USE_GDISP TRUE + b) #define GFX_USE_GINPUT TRUE + #define GINPUT_USE_MOUSE TRUE + c) Any optional high level driver defines (see gdisp.h) eg: GDISP_NEED_MULTITHREAD + d) Optionally the following (with appropriate values): + #define GDISP_SCREEN_WIDTH 640 + #define GDISP_SCREEN_HEIGHT 480 + e) Optionally change the threading model to POSIX (instead of ChibiOS) + #define GDISP_THREAD_CHIBIOS FALSE + +2. To your makefile add the following lines: + include $(GFXLIB)/gfx.mk + include $(GFXLIB)/drivers/multiple/X/gdisp_lld.mk + +3. Modify your makefile to add -lX11 to the DLIBS line. i.e. + DLIBS = -lX11 + +3. If you changed your threading model to POSIX modify your makefile + to add -pthread to the CC (or DDEFS) line. i.e. + CC = $(TRGT)gcc -pthread + diff --git a/gfxconf.example.h b/gfxconf.example.h index ce4d4ca6..5d6681ce 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -122,6 +122,7 @@ #define GDISP_USE_GPIO #define TDISP_COLUMNS 16 #define TDISP_ROWS 2 + #define GDISP_THREAD_CHIBIOS TRUE */ #endif /* _GFXCONF_H */ diff --git a/include/gdisp/options.h b/include/gdisp/options.h index b4d1dc25..0873a956 100644 --- a/include/gdisp/options.h +++ b/include/gdisp/options.h @@ -276,6 +276,12 @@ */ /* #define GDISP_SCREEN_WIDTH nnnn */ /* #define GDISP_SCREEN_HEIGHT nnnn */ + /** + * @brief Define which threading model to use. + * @details Optional for the X11 driver. + * @note Defaults to TRUE. Setting to FALSE causes POSIX threads to be used + */ + /* #define GDISP_THREAD_CHIBIOS FALSE */ /** * @brief Define which bus interface to use. * @details Only required by the SSD1963 driver.