aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/multiple
diff options
context:
space:
mode:
authorOleg Gerasimov <ogerasimov@gmail.com>2016-08-08 00:11:29 +0300
committerOleg Gerasimov <ogerasimov@gmail.com>2016-08-08 00:11:29 +0300
commitcbb06179813b0ae2c54c2b8d0ff14b71dfd1914e (patch)
tree51f7ba6ba0a8c0be6ddbc5dbe606bcfe379e0fd4 /drivers/multiple
parent0c695b2471c347847e579aa19ada5612341bfc2d (diff)
downloaduGFX-cbb06179813b0ae2c54c2b8d0ff14b71dfd1914e.tar.gz
uGFX-cbb06179813b0ae2c54c2b8d0ff14b71dfd1914e.tar.bz2
uGFX-cbb06179813b0ae2c54c2b8d0ff14b71dfd1914e.zip
Added SDL multiply driver
Diffstat (limited to 'drivers/multiple')
-rw-r--r--drivers/multiple/SDL/driver.mk5
-rw-r--r--drivers/multiple/SDL/gdisp_lld_SDL.c477
-rw-r--r--drivers/multiple/SDL/gdisp_lld_config.h26
-rw-r--r--drivers/multiple/SDL/readme.txt26
4 files changed, 534 insertions, 0 deletions
diff --git a/drivers/multiple/SDL/driver.mk b/drivers/multiple/SDL/driver.mk
new file mode 100644
index 00000000..85cdee7d
--- /dev/null
+++ b/drivers/multiple/SDL/driver.mk
@@ -0,0 +1,5 @@
+GFXINC += $(GFXLIB)/drivers/multiple/SDL
+GFXSRC += $(GFXLIB)/drivers/multiple/SDL/gdisp_lld_SDL.c
+GFXDEFS += GFX_OS_PRE_INIT_FUNCTION=sdl_driver_init
+CFLAGS += `sdl2-config --cflags || /usr/local/bin/sdl2-config --cflags`
+LDFLAGS += `sdl2-config --libs --cflags || /usr/local/bin/sdl2-config --libs --cflags`
diff --git a/drivers/multiple/SDL/gdisp_lld_SDL.c b/drivers/multiple/SDL/gdisp_lld_SDL.c
new file mode 100644
index 00000000..6c7748fa
--- /dev/null
+++ b/drivers/multiple/SDL/gdisp_lld_SDL.c
@@ -0,0 +1,477 @@
+/*
+ * Created by Oleg Gerasimov <ogerasimov@gmail.com>
+ * 06.08.2016
+ */
+
+// We need to include stdio.h below. Turn off GFILE_NEED_STDIO just for this file to prevent conflicts
+#define GFILE_NEED_STDIO_MUST_BE_OFF
+
+#include "gfx.h"
+
+#if GFX_USE_GDISP
+
+#include <fcntl.h>
+#include <sys/ipc.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <semaphore.h>
+#include <SDL.h>
+
+#define GDISP_DRIVER_VMT GDISPVMT_SDL
+#include "gdisp_lld_config.h"
+#include "../../../src/gdisp/gdisp_driver.h"
+
+#ifndef GDISP_FORCE_24BIT
+ #define GDISP_FORCE_24BIT FALSE
+#endif
+#ifndef GDISP_SCREEN_WIDTH
+ #define GDISP_SCREEN_WIDTH 640
+#endif
+#ifndef GDISP_SCREEN_HEIGHT
+ #define GDISP_SCREEN_HEIGHT 480
+#endif
+
+#if GINPUT_NEED_MOUSE
+ // Include mouse support code
+ #define GMOUSE_DRIVER_VMT GMOUSEVMT_SDL
+ #include "../../../src/ginput/ginput_driver_mouse.h"
+
+ // Forward definitions
+ static bool_t SDL_MouseInit(GMouse *m, unsigned driverinstance);
+ static bool_t SDL_MouseRead(GMouse *m, GMouseReading *prd);
+ const GMouseVMT GMOUSE_DRIVER_VMT[1] = {{
+ {
+ GDRIVER_TYPE_MOUSE,
+ GMOUSE_VFLG_NOPOLL|GMOUSE_VFLG_DYNAMICONLY,
+ sizeof(GMouse),
+ _gmouseInitDriver, _gmousePostInitDriver, _gmouseDeInitDriver
+ },
+ 1, // z_max
+ 0, // z_min
+ 1, // z_touchon
+ 0, // z_touchoff
+ { // pen_jitter
+ 0, // calibrate
+ 0, // click
+ 0 // move
+ },
+ { // finger_jitter
+ 0, // calibrate
+ 2, // click
+ 2 // move
+ },
+ SDL_MouseInit, // init
+ 0, // deinit
+ SDL_MouseRead, // get
+ 0, // calsave
+ 0 // calload
+ }};
+ static GMouse *mouse = 0;
+#endif
+
+#if GINPUT_NEED_KEYBOARD
+ // Include mouse support code
+ #define GKEYBOARD_DRIVER_VMT GKEYBOARDVMT_SDL
+ #include "../../../src/ginput/ginput_driver_keyboard.h"
+
+ // Forward definitions
+ static bool_t SDL_KeyboardInit(GKeyboard *k, unsigned driverinstance);
+ static int SDL_KeyboardGetData(GKeyboard *k, uint8_t *pch, int sz);
+
+ const GKeyboardVMT GKEYBOARD_DRIVER_VMT[1] = {{
+ {
+ GDRIVER_TYPE_KEYBOARD,
+ GKEYBOARD_VFLG_NOPOLL, // GKEYBOARD_VFLG_DYNAMICONLY
+ sizeof(GKeyboard),
+ _gkeyboardInitDriver, _gkeyboardPostInitDriver, _gkeyboardDeInitDriver
+ },
+ 0,
+ SDL_KeyboardInit, // init
+ 0, // deinit
+ SDL_KeyboardGetData, // getdata
+ 0 // putdata void (*putdata)(GKeyboard *k, char ch); Optional
+ }};
+
+ static struct KeyMap {
+ SDL_Keycode k_sdl;
+ uint16_t k_ugfx;
+ } SDL_keymap[] =
+ {
+ {SDLK_UP, GKEY_UP},
+ {SDLK_DOWN, GKEY_DOWN},
+ {SDLK_RIGHT, GKEY_RIGHT},
+ {SDLK_LEFT, GKEY_LEFT},
+ {SDLK_END, GKEY_END},
+ {SDLK_HOME, GKEY_HOME},
+ {SDLK_PAGEDOWN, GKEY_PAGEDOWN},
+ {SDLK_PAGEUP, GKEY_PAGEUP},
+ {SDLK_F1, GKEY_FN1},
+ {SDLK_F2, GKEY_FN2},
+ {SDLK_F3, GKEY_FN3},
+ {SDLK_F4, GKEY_FN4},
+ {SDLK_F5, GKEY_FN5},
+ {SDLK_F6, GKEY_FN6},
+ {SDLK_F7, GKEY_FN7},
+ {SDLK_F8, GKEY_FN8},
+ {SDLK_F9, GKEY_FN9},
+ {SDLK_F10, GKEY_FN10},
+ {SDLK_F11, GKEY_FN11},
+ {SDLK_F12, GKEY_FN12},
+ {SDLK_F13, GKEY_FN13},
+ {SDLK_F14, GKEY_FN14},
+ {SDLK_F15, GKEY_FN15},
+ {SDLK_BRIGHTNESSDOWN, GKEY_LIGHTDOWN},
+ {SDLK_BRIGHTNESSUP, GKEY_LIGHTUP},
+ {SDLK_AUDIONEXT, GKEY_MEDIANEXT},
+ {SDLK_AUDIOPREV, GKEY_MEDIAPREV},
+ {SDLK_AUDIOPLAY, GKEY_MEDIAPLAY},
+ {SDLK_AUDIOSTOP, GKEY_MEDIASTOP},
+ {SDLK_VOLUMEUP, GKEY_VOLUP},
+ {SDLK_VOLUMEDOWN, GKEY_VOLDOWN},
+ {SDLK_MUTE, GKEY_VOLMUTE},
+ {0,0}
+ };
+ static struct ModMap {
+ SDL_Keycode s_sdl;
+ uint32_t s_ugfx;
+ } SDL_modmap[] = {
+ {KMOD_LSHIFT, GKEYSTATE_SHIFT_L},
+ {KMOD_RSHIFT, GKEYSTATE_SHIFT_R},
+ {KMOD_RCTRL, GKEYSTATE_CTRL_R},
+ {KMOD_LCTRL, GKEYSTATE_CTRL_L},
+ {KMOD_RALT, GKEYSTATE_ALT_R},
+ {KMOD_LALT, GKEYSTATE_ALT_L},
+ {KMOD_CAPS, GKEYSTATE_CAPSLOCK},
+ {KMOD_NUM, GKEYSTATE_NUMLOCK},
+ {0,0}
+ };
+ struct SDL_keymsg {
+ uint32_t key;
+ uint32_t keystate;
+ };
+ static GKeyboard *keyboard = 0;
+#endif
+
+// shared IPC context
+struct SDL_UGFXContext {
+ uint32_t framebuf[GDISP_SCREEN_WIDTH*GDISP_SCREEN_HEIGHT];
+ int16_t need_redraw;
+ int minx,miny,maxx,maxy;
+#if GINPUT_NEED_MOUSE
+ coord_t mousex, mousey;
+ uint16_t buttons;
+#endif
+#if GINPUT_NEED_KEYBOARD
+ uint16_t keypos;
+ struct SDL_keymsg keybuffer[8];
+#endif
+};
+
+static struct SDL_UGFXContext *context;
+static sem_t *ctx_mutex;
+static sem_t *input_event;
+
+#define CTX_MUTEX_NAME "ugfx_ctx_mutex"
+#define INPUT_EVENT_NAME "ugfx_input_event"
+
+
+static int SDL_loop (void) {
+ SDL_Window *window = SDL_CreateWindow("uGFX simulator", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, 0);
+ SDL_Renderer *render = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
+ SDL_Texture *texture = SDL_CreateTexture(render, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT);
+ int done = 0;
+
+ while (!done) {
+
+ if (context->need_redraw) {
+ context->need_redraw = 0;
+ SDL_Rect r;
+ r.x = context->minx;
+ r.y = context->miny;
+ r.w = context->maxx - context->minx + 1;
+ r.h = context->maxy - context->miny + 1;
+ context->minx = GDISP_SCREEN_WIDTH;
+ context->miny = GDISP_SCREEN_HEIGHT;
+ context->maxx = 0;
+ context->maxy = 0;
+
+ SDL_UpdateTexture(texture, &r, context->framebuf+r.y*GDISP_SCREEN_WIDTH+r.x, GDISP_SCREEN_WIDTH*sizeof(uint32_t));
+ SDL_RenderCopy(render, texture, 0, 0);
+ SDL_RenderPresent(render);
+ }
+ SDL_Event event;
+ for (; SDL_PollEvent(&event); ){
+ switch(event.type){
+#if GINPUT_NEED_MOUSE
+#if 0
+ // On osx event contains coordinates of touchpad. We can't use them, we screen coordinates.
+ case SDL_FINGERMOTION:
+ case SDL_FINGERDOWN:
+ case SDL_FINGERUP:
+ context->mousex = (event.tfinger.x<1.0)?event.tfinger.x*GDISP_SCREEN_WIDTH:event.tfinger.x;
+ context->mousey = (event.tfinger.y<1.0)?event.tfinger.y*GDISP_SCREEN_HEIGHT:event.tfinger.y;
+ context->buttons = (event.type != SDL_FINGERUP)?GINPUT_MOUSE_BTN_LEFT:0;
+ sem_post (input_event);
+ break;
+#endif
+ case SDL_MOUSEBUTTONUP:
+ case SDL_MOUSEBUTTONDOWN:
+ context->mousex = event.button.x;
+ context->mousey = event.button.y;
+ context->buttons = (event.type ==SDL_MOUSEBUTTONDOWN)?GINPUT_MOUSE_BTN_LEFT:0;
+ sem_post (input_event);
+ break;
+ case SDL_MOUSEMOTION:
+ if (event.motion.state & SDL_BUTTON_LMASK) {
+ context->mousex = event.motion.x;
+ context->mousey = event.motion.y;
+ context->buttons = GINPUT_MOUSE_BTN_LEFT;
+ sem_post (input_event);
+ }
+ break;
+#endif
+#if GINPUT_NEED_KEYBOARD
+ case SDL_TEXTINPUT: {
+ int i;
+ sem_wait (ctx_mutex);
+ for (i=0; context->keypos < sizeof (context->keybuffer) && event.text.text[i]; ++i) {
+ context->keybuffer[context->keypos].key = event.text.text[i];
+ context->keybuffer[context->keypos++].keystate = 0;
+ }
+ sem_post (ctx_mutex);
+ sem_post (input_event);
+ break;
+
+ }
+ case SDL_KEYDOWN:
+ case SDL_KEYUP: {
+ SDL_Keycode k_sdl = event.key.keysym.sym;
+ uint8_t k_ugfx = 0;
+ uint32_t s_ugfx = (event.type==SDL_KEYDOWN)?0:GKEYSTATE_KEYUP;
+ int i;
+ if (!(k_sdl & ~0x7f) && (k_sdl <32 || k_sdl == 127)) {
+ k_ugfx = k_sdl;
+ }
+ else
+ for (i = 0; SDL_keymap[i].k_sdl; ++i)
+ if (SDL_keymap[i].k_sdl == k_sdl) {
+ k_ugfx = SDL_keymap[i].k_ugfx;
+ s_ugfx |= GKEYSTATE_SPECIAL;
+ break;
+ }
+ for (i = 0; SDL_modmap[i].s_sdl; ++i)
+ if (SDL_modmap[i].s_sdl & event.key.keysym.mod)
+ s_ugfx |= SDL_modmap[i].s_ugfx;
+ sem_wait (ctx_mutex);
+ if (k_ugfx && context->keypos+1 < (int)sizeof (context->keybuffer)) {
+ context->keybuffer[context->keypos].key = k_ugfx;
+ context->keybuffer[context->keypos++].keystate = s_ugfx;
+ }
+ sem_post (ctx_mutex);
+ sem_post (input_event);
+ break;
+ }
+#endif
+ case SDL_QUIT:
+ done = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ SDL_Delay(40);
+ }
+
+ SDL_DestroyTexture (texture);
+ SDL_DestroyRenderer (render);
+ SDL_DestroyWindow (window);
+ return 0;
+}
+
+static void *SDL_input_event_loop (void *arg) {
+ (void)arg;
+ for (;;) {
+ sem_wait (input_event);
+#if GINPUT_NEED_KEYBOARD
+ if (keyboard)
+ _gkeyboardWakeup (keyboard);
+#endif
+#if GINPUT_NEED_MOUSE
+ if (mouse)
+ _gmouseWakeup (mouse);
+#endif
+ }
+ return 0;
+}
+
+// Init driver
+// Must be executed on early stage of initialization: before threads and timer
+
+void sdl_driver_init (void) {
+ if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
+ fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());
+ exit (1) ;
+ }
+
+ if ((context = (struct SDL_UGFXContext*) mmap (0,sizeof (struct SDL_UGFXContext ),PROT_WRITE|PROT_READ,(MAP_ANONYMOUS | MAP_SHARED),0,0)) ==MAP_FAILED) {
+ perror("Failed to allocate shared memory");
+ exit(1);
+ }
+
+ // Create mutex for locking shared context
+ sem_unlink (CTX_MUTEX_NAME);
+ if((ctx_mutex = sem_open(CTX_MUTEX_NAME,O_CREAT,0666,1)) == SEM_FAILED) {
+ perror("Failed init semaphore");
+ exit(1);
+ }
+
+ // Create event for input notifications to ugfx process
+ sem_unlink (INPUT_EVENT_NAME);
+ if((input_event = sem_open(INPUT_EVENT_NAME,O_CREAT,0666,0)) == SEM_FAILED) {
+ perror("Failed init semaphore");
+ exit(1);
+ }
+ pid_t gui_pid = fork ();
+
+ if (gui_pid) {
+ // Main proccess. It's for host UI and SDL
+ int status;
+ memset (context,0,sizeof (*context));
+ context->need_redraw = 1;
+ context->maxx = GDISP_SCREEN_WIDTH-1;
+ context->maxy = GDISP_SCREEN_HEIGHT-1;
+ context->minx = 0;
+ context->miny = 0;
+ SDL_loop ();
+ // cleanup
+ kill(gui_pid,SIGKILL);
+ waitpid(gui_pid, &status, 0);
+ SDL_Quit ();
+ munmap (context,sizeof (*context));
+ sem_close (ctx_mutex);
+ sem_unlink (CTX_MUTEX_NAME);
+ sem_close (input_event);
+ sem_unlink (INPUT_EVENT_NAME);
+ exit (0);
+ }
+
+ // Create thread for input events processing
+ pthread_t thread;
+ pthread_create(&thread, NULL, SDL_input_event_loop, NULL);
+ pthread_detach (thread);
+ // Continue execution of ugfx UI in forked process
+}
+
+
+LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
+ g->board = 0; // No board interface for this driver
+
+#if GINPUT_NEED_MOUSE
+ gdriverRegister((const GDriverVMT *)GMOUSE_DRIVER_VMT, g);
+#endif
+ g->g.Orientation = GDISP_ROTATE_0;
+ g->g.Powermode = powerOn;
+ g->g.Backlight = 100;
+
+ g->g.Contrast = 50;
+ g->g.Width = GDISP_SCREEN_WIDTH;
+ g->g.Height = GDISP_SCREEN_HEIGHT;
+
+ return TRUE;
+}
+
+
+static void SDL_extendUpdateRect (int x,int y) {
+ if (context->minx > x)
+ context->minx = x;
+ if (context->miny > y)
+ context->miny = y;
+ if (context->maxx < x)
+ context->maxx = x;
+ if (context->maxy < y)
+ context->maxy = y;
+}
+
+LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g)
+{
+ if (context) {
+ context->framebuf[(g->p.y*GDISP_SCREEN_WIDTH)+g->p.x] = gdispColor2Native(g->p.color);
+ SDL_extendUpdateRect (g->p.x,g->p.y);
+ context->need_redraw = 1;
+ }
+}
+
+#if GDISP_HARDWARE_FILLS
+ LLDSPEC void gdisp_lld_fill_area(GDisplay *g) {
+ LLDCOLOR_TYPE c = gdispColor2Native(g->p.color);
+ if (context) {
+ int x,y;
+ uint32_t *pbuf = context->framebuf + g->p.y*GDISP_SCREEN_WIDTH + g->p.x;
+ int dy = GDISP_SCREEN_WIDTH - g->p.cx;
+ for (y = 0; y < g->p.cy; ++y) {
+ for (x = 0; x < g->p.cx; ++x)
+ *pbuf++ = c;
+ pbuf += dy;
+ }
+ SDL_extendUpdateRect (g->p.x,g->p.y);
+ SDL_extendUpdateRect (g->p.x+g->p.cx-1,g->p.y+g->p.cy-1);
+ context->need_redraw = 1;
+ }
+ }
+
+#endif
+
+#if GDISP_HARDWARE_PIXELREAD
+ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
+ if (context)
+ return gdispNative2Color(context->framebuf[(g->p.y*GDISP_SCREEN_WIDTH)+g->p.x]);
+ return 0;
+ }
+#endif
+
+#if GINPUT_NEED_MOUSE
+ static bool_t SDL_MouseInit(GMouse *m, unsigned driverinstance) {
+ mouse = m;
+ (void) driverinstance;
+ return TRUE;
+ }
+
+ static bool_t SDL_MouseRead(GMouse *m, GMouseReading *pt) {
+ (void) m;
+ if (!context)
+ return FALSE;
+ pt->x = context->mousex;
+ pt->y = context->mousey;
+ pt->z = (context->buttons & GINPUT_MOUSE_BTN_LEFT) ? 1 : 0;
+ pt->buttons = context->buttons;
+ return TRUE;
+ }
+#endif /* GINPUT_NEED_MOUSE */
+
+#if GINPUT_NEED_KEYBOARD
+ static bool_t SDL_KeyboardInit(GKeyboard *k, unsigned driverinstance) {
+ keyboard = k;
+ (void) driverinstance;
+ return TRUE;
+ }
+
+ static int SDL_KeyboardGetData(GKeyboard *k, uint8_t *pch, int sz) {
+ int i = 0;
+ if (!context || !context->keypos || !sz)
+ return 0;
+
+ sem_wait (ctx_mutex);
+ k->keystate = context->keybuffer[0].keystate;
+ for (i = 0; i < sz && i < context->keypos && context->keybuffer[0].keystate == context->keybuffer[i].keystate; i++)
+ pch[i] = context->keybuffer[i].key;
+ context->keypos -= i;
+ memmove (context->keybuffer,context->keybuffer+i,context->keypos * sizeof (context->keybuffer[0]));
+ sem_post (ctx_mutex);
+ return i;
+ }
+#endif /* GINPUT_NEED_KEYBOARD */
+
+#endif /* GFX_USE_GDISP */
diff --git a/drivers/multiple/SDL/gdisp_lld_config.h b/drivers/multiple/SDL/gdisp_lld_config.h
new file mode 100644
index 00000000..22fc4180
--- /dev/null
+++ b/drivers/multiple/SDL/gdisp_lld_config.h
@@ -0,0 +1,26 @@
+/*
+ * Created by Oleg Gerasimov <ogerasimov@gmail.com>
+ * 06.08.2016
+ */
+
+#ifndef _GDISP_LLD_CONFIG_H
+#define _GDISP_LLD_CONFIG_H
+
+#if GFX_USE_GDISP
+
+/*===========================================================================*/
+/* Driver hardware support. */
+/*===========================================================================*/
+
+#define GDISP_HARDWARE_DRAWPIXEL TRUE
+#define GDISP_HARDWARE_FILLS TRUE
+#define GDISP_HARDWARE_BITFILLS FALSE
+#define GDISP_HARDWARE_SCROLL FALSE
+#define GDISP_HARDWARE_PIXELREAD TRUE
+#define GDISP_HARDWARE_CONTROL FALSE
+
+#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB888
+
+#endif /* GFX_USE_GDISP */
+
+#endif /* _GDISP_LLD_CONFIG_H */
diff --git a/drivers/multiple/SDL/readme.txt b/drivers/multiple/SDL/readme.txt
new file mode 100644
index 00000000..3bbaec59
--- /dev/null
+++ b/drivers/multiple/SDL/readme.txt
@@ -0,0 +1,26 @@
+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
+
+2. To your makefile add the following lines:
+ include $(GFXLIB)/gfx.mk
+ include $(GFXLIB)/drivers/multiple/SDL/gdisp_lld.mk
+
+3. Install sdl2
+ on Linux:
+ sudo apt-get install libsdl2-dev
+ on OSX:
+ brew install sdl2 --universal
+
+4. Modify your makefile to add `sdl2-config --libs --cflags` to the CFLAGS line. i.e.
+ CFLAGS = `sdl2-config --libs --cflags`