aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/multiple/uGFXnetESP8266/gdisp_lld_uGFXnetESP8266.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/multiple/uGFXnetESP8266/gdisp_lld_uGFXnetESP8266.cpp')
-rw-r--r--drivers/multiple/uGFXnetESP8266/gdisp_lld_uGFXnetESP8266.cpp622
1 files changed, 622 insertions, 0 deletions
diff --git a/drivers/multiple/uGFXnetESP8266/gdisp_lld_uGFXnetESP8266.cpp b/drivers/multiple/uGFXnetESP8266/gdisp_lld_uGFXnetESP8266.cpp
new file mode 100644
index 00000000..7963acab
--- /dev/null
+++ b/drivers/multiple/uGFXnetESP8266/gdisp_lld_uGFXnetESP8266.cpp
@@ -0,0 +1,622 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+// 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 <ESP8266WiFi.h>
+
+#define GDISP_DRIVER_VMT GDISPVMT_uGFXnetESP8266
+#include "gdisp_lld_config.h"
+#include "../../../src/gdisp/gdisp_driver.h"
+#include "uGFXnetProtocol.h"
+
+#ifndef GDISP_SCREEN_WIDTH
+ #define GDISP_SCREEN_WIDTH 640
+#endif
+#ifndef GDISP_SCREEN_HEIGHT
+ #define GDISP_SCREEN_HEIGHT 480
+#endif
+#ifndef GDISP_GFXNET_PORT
+ #define GDISP_GFXNET_PORT GNETCODE_DEFAULT_PORT
+#endif
+#ifndef GDISP_DONT_WAIT_FOR_NET_DISPLAY
+ #define GDISP_DONT_WAIT_FOR_NET_DISPLAY FALSE
+#endif
+
+static WiFiServer server(GDISP_GFXNET_PORT);
+static GTimer poller;
+static bool_t uGFXInitDone;
+
+#ifndef GDISP_GFXNET_WIFI_INIT_FUNCTION
+ #define GDISP_GFXNET_WIFI_INIT_FUNCTION uGFXnetArduinoWifiInit
+ #ifndef GDISP_GFXNET_WIFI_SSID
+ #error "uGFXnetArduino: GDISP_GFXNET_WIFI_SSID is not set. You must define the Wifi SSID"
+ #endif
+ #ifndef GDISP_GFXNET_WIFI_PASSWORD
+ #error "uGFXnetArduino: GDISP_GFXNET_WIFI_PASSWORD is not set. You must define the Wifi password"
+ #endif
+
+ static void uGFXnetArduinoWifiInit(WifiServer *ws) {
+ WiFi.begin(GDISP_GFXNET_WIFI_SSID, GDISP_GFXNET_WIFI_PASSWORD);
+ while (WiFi.status() != WL_CONNECTED)
+ gfxYield();
+
+ ws->begin();
+ }
+#else
+ extern "C" void GDISP_GFXNET_WIFI_INIT_FUNCTION(WifiServer *ws);
+#endif
+
+#if GINPUT_NEED_MOUSE
+ // Include mouse support code
+ #define GMOUSE_DRIVER_VMT GMOUSEVMT_uGFXnet
+ #include "../../../src/ginput/ginput_driver_mouse.h"
+
+ // Forward definitions
+ static bool_t NMouseInit(GMouse *m, unsigned driverinstance);
+ static bool_t NMouseRead(GMouse *m, GMouseReading *prd);
+
+ const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{
+ {
+ GDRIVER_TYPE_MOUSE,
+ GMOUSE_VFLG_NOPOLL|GMOUSE_VFLG_DYNAMICONLY,
+ // Extra flags for testing only
+ //GMOUSE_VFLG_TOUCH|GMOUSE_VFLG_SELFROTATION|GMOUSE_VFLG_DEFAULTFINGER
+ //GMOUSE_VFLG_CALIBRATE|GMOUSE_VFLG_CAL_EXTREMES|GMOUSE_VFLG_CAL_TEST|GMOUSE_VFLG_CAL_LOADFREE
+ //GMOUSE_VFLG_ONLY_DOWN|GMOUSE_VFLG_POORUPDOWN
+ 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
+ },
+ NMouseInit, // init
+ 0, // deinit
+ NMouseRead, // get
+ 0, // calsave
+ 0 // calload
+ }};
+#endif
+
+#if GNETCODE_VERSION != GNETCODE_VERSION_1_0
+ #error "GDISP: uGFXnetESP8266 - This driver only support protocol V1.0"
+#endif
+#if GDISP_LLD_PIXELFORMAT != GNETCODE_PIXELFORMAT
+ #error "GDISP: uGFXnetESP8266 - The driver pixel format must match the protocol"
+#endif
+
+#define GDISP_FLG_CONNECTED (GDISP_FLG_DRIVER<<0)
+#define GDISP_FLG_HAVEDATA (GDISP_FLG_DRIVER<<1)
+
+#define CLIENTFD WifiClient *
+
+/*===========================================================================*/
+/* Driver local routines . */
+/*===========================================================================*/
+
+typedef struct netPriv {
+ CLIENTFD netfd; // The current client
+ unsigned databytes; // How many bytes have been read
+ uint16_t data[2]; // Buffer for storing data read.
+ #if GINPUT_NEED_MOUSE
+ coord_t mousex, mousey;
+ uint16_t mousebuttons;
+ GMouse * mouse;
+ #endif
+} netPriv;
+
+#if GDISP_GFXNET_UNSAFE_SOCKETS
+ static gfxMutex uGFXnetMutex;
+ #define MUTEX_INIT gfxMutexInit(&uGFXnetMutex)
+ #define MUTEX_ENTER gfxMutexEnter(&uGFXnetMutex)
+ #define MUTEX_EXIT gfxMutexExit(&uGFXnetMutex)
+#else
+ #define MUTEX_INIT
+ #define MUTEX_ENTER
+ #define MUTEX_EXIT
+#endif
+
+static void endcon(GDisplay *g) {
+ netPriv * priv;
+
+ g->flags &= ~GDISP_FLG_CONNECTED;
+ priv = g->priv;
+ priv->netfd->stop();
+ delete priv->netfd;
+ priv->netfd = 0;
+}
+
+/**
+ * Send a whole packet of data.
+ * Len is specified in the number of uint16_t's we want to send as our protocol only talks uint16_t's.
+ * Note that contents of the packet are modified to ensure it will cross the wire in the correct format.
+ * If the connection closes before we send all the data - the call returns FALSE.
+ */
+static bool_t sendpkt(CLIENTFD fd, uint16_t *pkt, int len) {
+ // Convert each uint16_t to network order
+ #if GFX_CPU_ENDIAN == GFX_CPU_ENDIAN_LITTLE
+ {
+ int i;
+
+ for(i = 0; i < len; i++)
+ pkt[i] = ((pkt[i]>>8)|(pkt[i]<<8));
+ }
+ #endif
+
+ // Send it
+ len *= sizeof(uint16_t);
+ return fd->write((uint8_t *)pkt, len) == len;
+}
+
+static void rxdata(GDisplay *g) {
+ netPriv * priv;
+ CLIENTFD fd;
+ int len;
+
+ if ((g->flags & GDISP_FLG_HAVEDATA)) {
+ // The higher level is still processing the previous data.
+ // Give it a chance to run by coming back to this data.
+ return;
+ }
+
+ priv = g->priv;
+ fd = priv->netfd;
+
+ MUTEX_ENTER;
+ // Are we still connected?
+ if (!fd->connected()) {
+ MUTEX_EXIT;
+ endcon(g);
+ return;
+ }
+
+ // Is there data available
+ if (!fd->available()) {
+ MUTEX_EXIT;
+ return;
+ }
+
+ // Get the data
+ if ((len = fd->read(((uint8_t *)priv->data)+priv->databytes, sizeof(priv->data)-priv->databytes, 0)) <= 0) {
+ // Socket closed or in error state
+ MUTEX_EXIT;
+ endcon(g);
+ return;
+ }
+ MUTEX_EXIT;
+
+ // Do we have a full reply yet
+ priv->databytes += len;
+ if (priv->databytes < sizeof(priv->data))
+ return;
+ priv->databytes = 0;
+
+ // Convert network byte or to host byte order
+ #if GFX_CPU_ENDIAN == GFX_CPU_ENDIAN_LITTLE
+ priv->data[0] = ((priv->data[0]>>8)|(priv->data[0]<<8))
+ priv->data[1] = ((priv->data[1]>>8)|(priv->data[1]<<8))
+ #endif
+
+ // Process the data received
+ switch(priv->data[0]) {
+ #if GINPUT_NEED_MOUSE
+ case GNETCODE_MOUSE_X: priv->mousex = priv->data[1]; break;
+ case GNETCODE_MOUSE_Y: priv->mousey = priv->data[1]; break;
+ case GNETCODE_MOUSE_B:
+ priv->mousebuttons = priv->data[1];
+ // Treat the button event as the sync signal
+ _gmouseWakeup(priv->mouse);
+ break;
+ #endif
+ case GNETCODE_CONTROL:
+ case GNETCODE_READ:
+ g->flags |= GDISP_FLG_HAVEDATA;
+ break;
+ case GNETCODE_KILL:
+ gfxHalt("GDISP: uGFXnet - Display sent KILL command");
+ break;
+
+ default:
+ // Just ignore unrecognised data
+ break;
+ }
+}
+
+void uGFXnetClientPoller(void *param) {
+ GDisplay *g;
+ (void) param;
+
+ // Is there a new server connection?
+ if (server.hasClient()) {
+
+ // Look for a display that isn't connected
+ for(g = 0; (g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, (GDriver *)g));) {
+ // Ignore displays for other controllers
+ #ifdef GDISP_DRIVER_LIST
+ if (gvmt(g) != &GDISPVMT_uGFXnet)
+ continue;
+ #endif
+ if (!(g->flags & GDISP_FLG_CONNECTED)) {
+ netPriv * priv;
+
+ // Reset the priv area
+ priv = g->priv;
+ priv->netfd = new WifiClient(server.available());
+ priv->databytes = 0;
+ priv->mousebuttons = 0;
+
+ // Send the initialisation data (2 words at a time)
+ priv->data[0] = GNETCODE_INIT;
+ priv->data[1] = GNETCODE_VERSION;
+ sendpkt(priv->netfd, priv->data, 2);
+ priv->data[0] = GDISP_SCREEN_WIDTH;
+ priv->data[1] = GDISP_SCREEN_HEIGHT;
+ sendpkt(priv->netfd, priv->data, 2);
+ priv->data[0] = GDISP_LLD_PIXELFORMAT;
+ priv->data[1] = 1; // We have a mouse
+ MUTEX_ENTER;
+ sendpkt(priv->netfd, priv->data, 2);
+ MUTEX_EXIT;
+
+ // The display is now working
+ g->flags |= GDISP_FLG_CONNECTED;
+
+ // Send a redraw all
+ #if GFX_USE_GWIN && GWIN_NEED_WINDOWMANAGER
+ gdispGClear(g, gwinGetDefaultBgColor());
+ gwinRedrawDisplay(g, FALSE);
+ #endif
+ break;
+ }
+ }
+ }
+
+ // Look for a display that is connected so we can check if it has data
+ for(g = 0; (g = (GDisplay *)gdriverGetNext(GDRIVER_TYPE_DISPLAY, (GDriver *)g));) {
+ // Ignore displays for other controllers
+ #ifdef GDISP_DRIVER_LIST
+ if (gvmt(g) != &GDISPVMT_uGFXnet)
+ continue;
+ #endif
+ if ((g->flags & GDISP_FLG_CONNECTED))
+ rxdata(g);
+ }
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
+ netPriv * priv;
+
+ // Initialise the receiver thread (if it hasn't been done already)
+ if (!uGFXInitDone) {
+ MUTEX_INIT;
+ // Init and Start the poller
+ GDISP_GFXNET_WIFI_INIT_FUNCTION(&server);
+
+ // Initialise the poller
+ gtimerInit(&poller);
+ gtimerStart(&poller, uGFXnetClientPoller, 0, TRUE, 50);
+ uGFXInitDone = TRUE;
+ }
+
+ // Create a private area for this window
+ if (!(priv = gfxAlloc(sizeof(netPriv))))
+ gfxHalt("GDISP: uGFXnetESP8266 - Memory allocation failed");
+ memset(priv, 0, sizeof(netPriv));
+ g->priv = priv;
+ g->board = 0; // no board interface for this controller
+
+ // Create the associated mouse
+ #if GINPUT_NEED_MOUSE
+ priv->mouse = (GMouse *)gdriverRegister((const GDriverVMT const *)GMOUSE_DRIVER_VMT, g);
+ #endif
+
+ // Initialise the GDISP structure
+ 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;
+}
+
+#if GDISP_HARDWARE_FLUSH
+ LLDSPEC void gdisp_lld_flush(GDisplay *g) {
+ netPriv * priv;
+ uint16_t buf[1];
+
+ #if GDISP_DONT_WAIT_FOR_NET_DISPLAY
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ return;
+ #else
+ while(!(g->flags & GDISP_FLG_CONNECTED))
+ gfxSleepMilliseconds(200);
+ #endif
+
+ priv = g->priv;
+ buf[0] = GNETCODE_FLUSH;
+ MUTEX_ENTER;
+ sendpkt(priv->netfd, buf, 1);
+ MUTEX_EXIT;
+ }
+#endif
+
+#if GDISP_HARDWARE_DRAWPIXEL
+ LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
+ netPriv * priv;
+ uint16_t buf[4];
+
+ #if GDISP_DONT_WAIT_FOR_NET_DISPLAY
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ return;
+ #else
+ while(!(g->flags & GDISP_FLG_CONNECTED))
+ gfxSleepMilliseconds(200);
+ #endif
+
+ priv = g->priv;
+ buf[0] = GNETCODE_PIXEL;
+ buf[1] = g->p.x;
+ buf[2] = g->p.y;
+ buf[3] = gdispColor2Native(g->p.color);
+ MUTEX_ENTER;
+ sendpkt(priv->netfd, buf, 4);
+ MUTEX_EXIT;
+ }
+#endif
+
+/* ---- Optional Routines ---- */
+
+#if GDISP_HARDWARE_FILLS
+ LLDSPEC void gdisp_lld_fill_area(GDisplay *g) {
+ netPriv * priv;
+ uint16_t buf[6];
+
+ #if GDISP_DONT_WAIT_FOR_NET_DISPLAY
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ return;
+ #else
+ while(!(g->flags & GDISP_FLG_CONNECTED))
+ gfxSleepMilliseconds(200);
+ #endif
+
+ priv = g->priv;
+ buf[0] = GNETCODE_FILL;
+ buf[1] = g->p.x;
+ buf[2] = g->p.y;
+ buf[3] = g->p.cx;
+ buf[4] = g->p.cy;
+ buf[5] = gdispColor2Native(g->p.color);
+ MUTEX_ENTER;
+ sendpkt(priv->netfd, buf, 6);
+ MUTEX_EXIT;
+ }
+#endif
+
+#if GDISP_HARDWARE_BITFILLS
+ LLDSPEC void gdisp_lld_blit_area(GDisplay *g) {
+ netPriv * priv;
+ pixel_t * buffer;
+ uint16_t buf[5];
+ coord_t x, y;
+
+ #if GDISP_DONT_WAIT_FOR_NET_DISPLAY
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ return;
+ #else
+ while(!(g->flags & GDISP_FLG_CONNECTED))
+ gfxSleepMilliseconds(200);
+ #endif
+
+ // Make everything relative to the start of the line
+ buffer = g->p.ptr;
+ buffer += g->p.x2*g->p.y1;
+
+ priv = g->priv;
+ buf[0] = GNETCODE_BLIT;
+ buf[1] = g->p.x;
+ buf[2] = g->p.y;
+ buf[3] = g->p.cx;
+ buf[4] = g->p.cy;
+ MUTEX_ENTER;
+ sendpkt(priv->netfd, buf, 5);
+
+ for(y = 0; y < g->p.cy; y++, buffer += g->p.x2 - g->p.cx) {
+ for(x = 0; x < g->p.cx; x++, buffer++) {
+ buf[0] = gdispColor2Native(buffer[0]);
+ sendpkt(priv->netfd, buf, 1);
+ }
+ }
+ MUTEX_EXIT;
+ }
+#endif
+
+#if GDISP_HARDWARE_PIXELREAD
+ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
+ netPriv * priv;
+ uint16_t buf[3];
+ color_t data;
+
+ #if GDISP_DONT_WAIT_FOR_NET_DISPLAY
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ return 0;
+ #else
+ while(!(g->flags & GDISP_FLG_CONNECTED))
+ gfxSleepMilliseconds(200);
+ #endif
+
+ priv = g->priv;
+ buf[0] = GNETCODE_READ;
+ buf[1] = g->p.x;
+ buf[2] = g->p.y;
+ MUTEX_ENTER;
+ sendpkt(priv->netfd, buf, 3);
+ MUTEX_EXIT;
+
+ // Now wait for a reply
+ while(!(g->flags & GDISP_FLG_HAVEDATA) || priv->data[0] != GNETCODE_READ)
+ gfxSleepMilliseconds(1);
+
+ data = gdispNative2Color(priv->data[1]);
+ g->flags &= ~GDISP_FLG_HAVEDATA;
+
+ return data;
+ }
+#endif
+
+#if GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL
+ LLDSPEC void gdisp_lld_vertical_scroll(GDisplay *g) {
+ netPriv * priv;
+ uint16_t buf[6];
+
+ #if GDISP_DONT_WAIT_FOR_NET_DISPLAY
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ return;
+ #else
+ while(!(g->flags & GDISP_FLG_CONNECTED))
+ gfxSleepMilliseconds(200);
+ #endif
+
+ priv = g->priv;
+ buf[0] = GNETCODE_SCROLL;
+ buf[1] = g->p.x;
+ buf[2] = g->p.y;
+ buf[3] = g->p.cx;
+ buf[4] = g->p.cy;
+ buf[5] = g->p.y1;
+ MUTEX_ENTER;
+ sendpkt(priv->netfd, buf, 6);
+ MUTEX_EXIT;
+ }
+#endif
+
+#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
+ LLDSPEC void gdisp_lld_control(GDisplay *g) {
+ netPriv * priv;
+ uint16_t buf[3];
+ bool_t allgood;
+
+ #if GDISP_DONT_WAIT_FOR_NET_DISPLAY
+ if (!(g->flags & GDISP_FLG_CONNECTED))
+ return;
+ #else
+ while(!(g->flags & GDISP_FLG_CONNECTED))
+ gfxSleepMilliseconds(200);
+ #endif
+
+ // Check if we might support the code
+ switch(g->p.x) {
+ case GDISP_CONTROL_ORIENTATION:
+ if (g->g.Orientation == (orientation_t)g->p.ptr)
+ return;
+ break;
+ case GDISP_CONTROL_POWER:
+ if (g->g.Powermode == (powermode_t)g->p.ptr)
+ return;
+ break;
+ case GDISP_CONTROL_BACKLIGHT:
+ if (g->g.Backlight == (uint16_t)(int)g->p.ptr)
+ return;
+ if ((uint16_t)(int)g->p.ptr > 100)
+ g->p.ptr = (void *)100;
+ break;
+ default:
+ return;
+ }
+
+ // Send the command
+ priv = g->priv;
+ buf[0] = GNETCODE_CONTROL;
+ buf[1] = g->p.x;
+ buf[2] = (uint16_t)(int)g->p.ptr;
+ MUTEX_ENTER;
+ sendpkt(priv->netfd, buf, 3);
+ MUTEX_EXIT;
+
+ // Now wait for a reply
+ while(!(g->flags & GDISP_FLG_HAVEDATA) || priv->data[0] != GNETCODE_CONTROL)
+ gfxSleepMilliseconds(1);
+
+ // Extract the return status
+ allgood = priv->data[1] ? TRUE : FALSE;
+ g->flags &= ~GDISP_FLG_HAVEDATA;
+
+ // Do nothing more if the operation failed
+ if (!allgood) return;
+
+ // Update the local stuff
+ switch(g->p.x) {
+ case GDISP_CONTROL_ORIENTATION:
+ switch((orientation_t)g->p.ptr) {
+ case GDISP_ROTATE_0:
+ case GDISP_ROTATE_180:
+ g->g.Width = GDISP_SCREEN_WIDTH;
+ g->g.Height = GDISP_SCREEN_HEIGHT;
+ break;
+ case GDISP_ROTATE_90:
+ case GDISP_ROTATE_270:
+ g->g.Height = GDISP_SCREEN_WIDTH;
+ g->g.Width = GDISP_SCREEN_HEIGHT;
+ break;
+ default:
+ return;
+ }
+ g->g.Orientation = (orientation_t)g->p.ptr;
+ break;
+ case GDISP_CONTROL_POWER:
+ g->g.Powermode = (powermode_t)g->p.ptr;
+ break;
+ case GDISP_CONTROL_BACKLIGHT:
+ g->g.Backlight = (uint16_t)(int)g->p.ptr;
+ break;
+ }
+ }
+#endif
+
+#if GINPUT_NEED_MOUSE
+ static bool_t NMouseInit(GMouse *m, unsigned driverinstance) {
+ (void) m;
+ (void) driverinstance;
+ return TRUE;
+ }
+ static bool_t NMouseRead(GMouse *m, GMouseReading *pt) {
+ GDisplay * g;
+ netPriv * priv;
+
+ g = m->display;
+ priv = g->priv;
+
+ pt->x = priv->mousex;
+ pt->y = priv->mousey;
+ pt->z = (priv->mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 1 : 0;
+ pt->buttons = priv->mousebuttons;
+ return TRUE;
+ }
+#endif /* GINPUT_NEED_MOUSE */
+
+#endif /* GFX_USE_GDISP */