/* * 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 */ /** * @file drivers/multiple/Win32/gdisp_lld.c * @brief GDISP Graphics Driver subsystem low level driver source for uGFX network display. */ #include "gfx.h" #if GFX_USE_GDISP #define GDISP_DRIVER_VMT GDISPVMT_uGFXnet #include "../drivers/multiple/uGFXnet/gdisp_lld_config.h" #include "gdisp/lld/gdisp_lld.h" #include "../drivers/multiple/uGFXnet/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 #if GNETCODE_VERSION != GNETCODE_VERSION_1_0 #error "GDISP: uGFXnet - This driver only support protocol V1.0" #endif #if GDISP_LLD_PIXELFORMAT != GNETCODE_PIXELFORMAT #error "GDISP: uGFXnet - The driver pixel format must match the protocol" #endif #include #include #include #if defined(WIN32) || GFX_USE_OS_WIN32 #include static void StopSockets(void) { WSACleanup(); } static void StartSockets(void) { WSADATA wsaData; if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) gfxHalt("GDISP: uGFXnet - WSAStartup failed"); atexit(StopSockets); } #else #include #include #include #include #include #define closesocket(fd) close(fd) #define ioctlsocket(fd,cmd,arg) ioctl(fd,cmd,arg) #define StartSockets() #ifndef SOCKET #define SOCKET int #endif #endif #define GDISP_FLG_HASMOUSE (GDISP_FLG_DRIVER<<0) #define GDISP_FLG_CONNECTED (GDISP_FLG_DRIVER<<1) #define GDISP_FLG_HAVEDATA (GDISP_FLG_DRIVER<<2) #if GINPUT_NEED_MOUSE /* Include mouse support code */ #include "ginput/lld/mouse.h" #endif /*===========================================================================*/ /* Driver local routines . */ /*===========================================================================*/ typedef struct netPriv { SOCKET netfd; // The current socket 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; #endif } netPriv; static gfxThreadHandle hThread; static GDisplay * mouseDisplay; /** * 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(SOCKET netfd, uint16_t *pkt, int len) { int i; // Convert each uint16_t to network order for(i = 0; i < len; i++) pkt[i] = htons(pkt[i]); // Send it len *= sizeof(uint16_t); return send(netfd, (const char *)pkt, len, 0) == len; } static DECLARE_THREAD_STACK(waNetThread, 512); static DECLARE_THREAD_FUNCTION(NetThread, param) { SOCKET listenfd, fdmax, i, clientfd; int len; unsigned disp; fd_set master, read_fds; struct sockaddr_in addr; GDisplay * g; netPriv * priv; (void)param; // Start the sockets layer StartSockets(); /* clear the master and temp sets */ FD_ZERO(&master); FD_ZERO(&read_fds); if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == (SOCKET)-1) gfxHalt("GDISP: uGFXnet - Socket failed"); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(GDISP_GFXNET_PORT); if (bind(listenfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) gfxHalt("GDISP: uGFXnet - Bind failed"); if (listen(listenfd, 10) == -1) gfxHalt("GDISP: uGFXnet - Listen failed"); /* add the listener to the master set */ FD_SET(listenfd, &master); /* keep track of the biggest file descriptor */ fdmax = listenfd; /* so far, it's this one*/ /* loop */ for(;;) { /* copy it */ read_fds = master; if (select(fdmax+1, &read_fds, 0, 0, 0) == -1) gfxHalt("GDISP: uGFXnet - Select failed"); // Run through the existing connections looking for data to be read for(i = 0; i <= fdmax; i++) { if(!FD_ISSET(i, &read_fds)) continue; // Handle new connections if(i == listenfd) { len = sizeof(addr); if((clientfd = accept(listenfd, (struct sockaddr *)&addr, &len)) == (SOCKET)-1) gfxHalt("GDISP: uGFXnet - Accept failed"); // Look for a display that isn't connected for(disp = 0; disp < GDISP_TOTAL_DISPLAYS; disp++) { if (!(g = gdispGetDisplay(disp))) continue; #if GDISP_TOTAL_CONTROLLERS > 1 // Ignore displays for other controllers if (g->vmt != &GDISPVMT_uGFXnet) continue; #endif if (!(g->flags & GDISP_FLG_CONNECTED)) break; } // Was anything found? if (disp >= GDISP_TOTAL_DISPLAYS) { // No Just close the connection closesocket(clientfd); //printf(New connection from %s on socket %d rejected as all displays are already connected\n", inet_ntoa(addr.sin_addr), clientfd); continue; } // Save the descriptor FD_SET(clientfd, &master); if (clientfd > fdmax) fdmax = clientfd; priv = g->priv; memset(priv, 0, sizeof(netPriv)); priv->netfd = clientfd; //printf(New connection from %s on socket %d allocated to display %u\n", inet_ntoa(addr.sin_addr), clientfd, disp+1); // 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] = (g->flags & GDISP_FLG_HASMOUSE) ? 1 : 0; sendpkt(priv->netfd, priv->data, 2); // 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 continue; } // Handle data from a client // Look for a display that is connected and the socket descriptor matches for(disp = 0; disp < GDISP_TOTAL_DISPLAYS; disp++) { if (!(g = gdispGetDisplay(disp))) continue; #if GDISP_TOTAL_CONTROLLERS > 1 // Ignore displays for other controllers if (g->vmt != &GDISPVMT_uGFXnet) continue; #endif priv = g->priv; if ((g->flags & GDISP_FLG_CONNECTED) && priv->netfd == i) break; } if (disp >= GDISP_TOTAL_DISPLAYS) gfxHalt("GDISP: uGFXnet - Got data from unrecognized connection"); 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. gfxSleepMilliseconds(1); continue; } /* handle data from a client */ if ((len = recv(i, ((char *)priv->data)+priv->databytes, sizeof(priv->data)-priv->databytes, 0)) <= 0) { // Socket closed or in error state g->flags &= ~GDISP_FLG_CONNECTED; memset(priv, 0, sizeof(netPriv)); closesocket(i); FD_CLR(i, &master); continue; } // Do we have a full reply yet priv->databytes += len; if (priv->databytes < sizeof(priv->data)) continue; priv->databytes = 0; // Convert network byte or to host byte order priv->data[0] = ntohs(priv->data[0]); priv->data[1] = ntohs(priv->data[1]); // 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 #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE ginputMouseWakeup(); #endif 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; } } } return 0; } /*===========================================================================*/ /* 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 (!hThread) { hThread = gfxThreadCreate(waNetThread, sizeof(waNetThread), HIGH_PRIORITY, NetThread, 0); gfxThreadClose(hThread); } // Only turn on mouse on the first window for now #if GINPUT_NEED_MOUSE if (!g->controllerdisplay) { mouseDisplay = g; g->flags |= GDISP_FLG_HASMOUSE; } #endif // Create a private area for this window if (!(priv = (netPriv *)gfxAlloc(sizeof(netPriv)))) gfxHalt("GDISP: uGFXnet - Memory allocation failed"); memset(priv, 0, sizeof(netPriv)); g->priv = priv; g->board = 0; // no board interface for this controller // 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; sendpkt(priv->netfd, buf, 1); } #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] = COLOR2NATIVE(g->p.color); sendpkt(priv->netfd, buf, 4); } #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] = COLOR2NATIVE(g->p.color); sendpkt(priv->netfd, buf, 6); } #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; 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] = COLOR2NATIVE(buffer[0]); sendpkt(priv->netfd, buf, 1); } } } #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; sendpkt(priv->netfd, buf, 3); // Now wait for a reply while(!(g->flags & GDISP_FLG_HAVEDATA) || priv->data[0] != GNETCODE_READ) gfxSleepMilliseconds(1); data = NATIVE2COLOR(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; sendpkt(priv->netfd, buf, 6); } #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; sendpkt(priv->netfd, buf, 3); // 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 void ginput_lld_mouse_init(void) {} void ginput_lld_mouse_get_reading(MouseReading *pt) { GDisplay * g; netPriv * priv; g = mouseDisplay; priv = g->priv; pt->x = priv->mousex; pt->y = priv->mousey; pt->z = (priv->mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0; pt->buttons = priv->mousebuttons; } #endif /* GINPUT_NEED_MOUSE */ #endif /* GFX_USE_GDISP */