graphlcd-base/glcddrivers/network.c
author root@rika
Wed, 06 Feb 2008 17:32:55 +0000
changeset 4 df6a40031aa5
permissions -rw-r--r--
added graphlcd-base
     1 /*
     2  * GraphLCD driver library
     3  *
     4  * network.c  -  Network output device
     5  *               Output goes to a network client.
     6  *
     7  * This file is released under the GNU General Public License. Refer
     8  * to the COPYING file distributed with this package.
     9  *
    10  * (c) 2004 Andreas Regel <andreas.regel AT powarman.de>
    11  */
    12 
    13 #include <stdio.h>
    14 #include <syslog.h>
    15 #include <unistd.h>
    16 #include <sys/types.h>
    17 #include <sys/socket.h>
    18 #include <netinet/in.h>
    19 #include <arpa/inet.h>
    20 #include <errno.h>
    21 
    22 #include "common.h"
    23 #include "config.h"
    24 #include "network.h"
    25 
    26 
    27 namespace GLCD
    28 {
    29 
    30 cDriverNetwork::cDriverNetwork(cDriverConfig * config)
    31 :   config(config)
    32 {
    33     oldConfig = new cDriverConfig(*config);
    34     childTid = 0;
    35     running = false;
    36     clientConnected = false;
    37 }
    38 
    39 cDriverNetwork::~cDriverNetwork()
    40 {
    41     delete oldConfig;
    42 }
    43 
    44 int cDriverNetwork::Init()
    45 {
    46     width = config->width;
    47     if (width <= 0)
    48         width = 240;
    49     height = config->height;
    50     if (height <= 0)
    51         height = 128;
    52     lineSize = (width + 7) / 8;
    53 
    54     for (unsigned int i = 0; i < config->options.size(); i++)
    55     {
    56         if (config->options[i].name == "")
    57         {
    58         }
    59     }
    60 
    61     newLCD = new unsigned char[lineSize * height];
    62     if (newLCD)
    63         memset(newLCD, 0, lineSize * height);
    64     oldLCD = new unsigned char[lineSize * height];
    65     if (oldLCD)
    66         memset(oldLCD, 0, lineSize * height);
    67 
    68     *oldConfig = *config;
    69 
    70     // clear display
    71     Clear();
    72 
    73     running = true;
    74     if (pthread_create(&childTid, NULL, (void *(*) (void *)) &ServerThread, (void *)this) != 0)
    75     {
    76         syslog(LOG_ERR, "%s: error creating server thread.\n", config->name.c_str());
    77         running = false;
    78         return 1;
    79     }
    80     syslog(LOG_INFO, "%s: network driver initialized.\n", config->name.c_str());
    81     return 0;
    82 }
    83 
    84 int cDriverNetwork::DeInit()
    85 {
    86     // stop server thread
    87     running = false;
    88     usleep(3000000); // wait 3 seconds
    89     pthread_cancel(childTid);
    90     childTid = 0;
    91 
    92     if (newLCD)
    93         delete[] newLCD;
    94     if (oldLCD)
    95         delete[] oldLCD;
    96     return 0;
    97 }
    98 
    99 int cDriverNetwork::CheckSetup()
   100 {
   101     if (config->width != oldConfig->width ||
   102         config->height != oldConfig->height)
   103     {
   104         DeInit();
   105         Init();
   106         return 0;
   107     }
   108 
   109     if (config->upsideDown != oldConfig->upsideDown ||
   110         config->invert != oldConfig->invert)
   111     {
   112         oldConfig->upsideDown = config->upsideDown;
   113         oldConfig->invert = config->invert;
   114         return 1;
   115     }
   116     return 0;
   117 }
   118 
   119 void cDriverNetwork::Clear()
   120 {
   121     memset(newLCD, 0, lineSize * height);
   122 }
   123 
   124 void cDriverNetwork::Set8Pixels(int x, int y, unsigned char data)
   125 {
   126     if (x >= width || y >= height)
   127         return;
   128 
   129     if (!config->upsideDown)
   130     {
   131         // normal orientation
   132         newLCD[lineSize * y + x / 8] |= data;
   133     }
   134     else
   135     {
   136         // upside down orientation
   137         x = width - 1 - x;
   138         y = height - 1 - y;
   139         newLCD[lineSize * y + x / 8] |= ReverseBits(data);
   140     }
   141 }
   142 
   143 void cDriverNetwork::Refresh(bool refreshAll)
   144 {
   145     int i;
   146     bool refresh;
   147 
   148     refresh = false;
   149     if (CheckSetup() > 0)
   150         refresh = true;
   151 
   152     for (i = 0; i < lineSize * height; i++)
   153     {
   154         if (newLCD[i] != oldLCD[i])
   155         {
   156             refresh = true;
   157             break;
   158         }
   159     }
   160 
   161     if (refresh && clientConnected)
   162     {
   163         char msg[1024];
   164         int x;
   165         int y;
   166         int sent;
   167 
   168         sprintf(msg, "update begin %d %d\r\n", width, height);
   169         sent = send(clientSocket, msg, strlen(msg), 0);
   170         if (sent == -1)
   171         {
   172             syslog(LOG_ERR, "%s: error sending message: %s.\n", config->name.c_str(), strerror(errno));
   173             clientConnected = false;
   174             return;
   175         }
   176         for (y = 0; y < height; y++)
   177         {
   178             sprintf(msg, "update line %d ", y);
   179             for (x = 0; x < lineSize; x++)
   180             {
   181                 char tmp[3];
   182                 sprintf(tmp, "%02X", newLCD[y * lineSize + x]);
   183                 strcat(msg, tmp);
   184                 oldLCD[i] = newLCD[i];
   185             }
   186             strcat(msg, "\r\n");
   187             sent = send(clientSocket, msg, strlen(msg), 0);
   188             if (sent == -1)
   189             {
   190                 syslog(LOG_ERR, "%s: error sending message: %s.\n", config->name.c_str(), strerror(errno));
   191                 clientConnected = false;
   192                 return;
   193             }
   194         }
   195         sprintf(msg, "update end\r\n");
   196         sent = send(clientSocket, msg, strlen(msg), 0);
   197         if (sent == -1)
   198         {
   199             syslog(LOG_ERR, "%s: error sending message: %s.\n", config->name.c_str(), strerror(errno));
   200             clientConnected = false;
   201             return;
   202         }
   203     }
   204 }
   205 
   206 void * cDriverNetwork::ServerThread(cDriverNetwork * Driver)
   207 {
   208     int serverSocket;
   209     struct sockaddr_in address;
   210     socklen_t addrlen;
   211     int clientSocket;
   212     fd_set set;
   213     fd_set setsave;
   214     struct timeval timeout;
   215 
   216     serverSocket = socket(AF_INET, SOCK_STREAM, 0);
   217     if (serverSocket == -1)
   218     {
   219         syslog(LOG_ERR, "%s: error creating server socket.\n", Driver->config->name.c_str());
   220         return NULL;
   221     }
   222 
   223     int y = 1;
   224     setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(int));
   225 
   226     address.sin_family = AF_INET;
   227     address.sin_addr.s_addr = INADDR_ANY;
   228     address.sin_port = htons(2003);
   229     if (bind(serverSocket, (struct sockaddr *) &address, sizeof(address)) != 0)
   230     {
   231         syslog(LOG_ERR, "%s: error port %d is already used.\n", Driver->config->name.c_str(), 2003);
   232         return NULL;
   233     }
   234 
   235     listen(serverSocket, 1);
   236     addrlen = sizeof(struct sockaddr_in);
   237 
   238     FD_ZERO(&set);
   239     FD_SET(serverSocket, &set);
   240     setsave = set;
   241 
   242     while (Driver->running)
   243     {
   244         set = setsave;
   245         timeout.tv_sec = 1;
   246         timeout.tv_usec = 0;
   247         if (select(FD_SETSIZE, &set, NULL, NULL, &timeout) < 0)
   248         {
   249             syslog(LOG_ERR, "%s: error during select.\n", Driver->config->name.c_str());
   250             break;
   251         }
   252 
   253         if (FD_ISSET(serverSocket, &set))
   254         {
   255             clientSocket = accept(serverSocket, (struct sockaddr *) &address, &addrlen);
   256             if (clientSocket > 0)
   257             {
   258                 Driver->clientSocket = clientSocket;
   259                 Driver->clientConnected = true;
   260             }
   261         }
   262     }
   263     close(serverSocket);
   264     return NULL;
   265 }
   266 
   267 } // end of namespace