diff options
author | horchi <vdr@jwendel.de> | 2017-03-05 16:47:41 +0100 |
---|---|---|
committer | horchi <vdr@jwendel.de> | 2017-03-05 16:47:41 +0100 |
commit | 22ffee20bbacbc3378e4ba0df5b7f0c3daaeffc0 (patch) | |
tree | de46c945c62d43d1febb027b5bfa075e58c5b69a /comthread.c | |
download | vdr-plugin-graphtftng-22ffee20bbacbc3378e4ba0df5b7f0c3daaeffc0.tar.gz vdr-plugin-graphtftng-22ffee20bbacbc3378e4ba0df5b7f0c3daaeffc0.tar.bz2 |
Diffstat (limited to 'comthread.c')
-rw-r--r-- | comthread.c | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/comthread.c b/comthread.c new file mode 100644 index 0000000..266135a --- /dev/null +++ b/comthread.c @@ -0,0 +1,414 @@ +//*************************************************************************** +// Group VDR/GraphTFT +// File comthread.c +// Date 28.10.06 +// This code is distributed under the terms and conditions of the +// GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. +// (c) 2006-2013 Jörg Wendel +//-------------------------------------------------------------------------- +// Class ComThread +//*************************************************************************** + +#include "common.h" +#include "comthread.h" +#include "display.h" + +//*************************************************************************** +// Object +//*************************************************************************** + +ComThread::ComThread(void* aDisplay, int width, int height) + : cRemote("graphtft-fe") +{ + display = aDisplay; + themeWidth = width; + themeHeight = height; + + bufferSize = maxBuf; + + buffer = new char[bufferSize+TB]; + + running = false; + timeout = 5; + checkTime = 60; + port = na; + *host = 0; + pid = 0; + jpgQuality = 60; + width = 720; + height = 576; + + listener = new TcpChannel(timeout); +} + +ComThread::~ComThread() +{ + if (display) + ((cGraphTFTDisplay*)display)->clearComThread(); + + Stop(); + + // close all client connections + + while (clients.size()) + { + clients[0].channel->close(); + delete clients[0].channel; + clients.erase(clients.begin()); + } + + listener->close(); + + delete listener; + delete[] buffer; +} + +//*************************************************************************** +// Init +//*************************************************************************** + +int ComThread::init(Renderer* aRenderer, unsigned int aPort, const char* aHost) +{ + renderer = aRenderer; + + if (aHost) + setHost(aHost); + + if (aPort) + setPort(aPort); + + if (listener->open(port) != 0) + { + tell(0, "Error: Can't establish listener"); + return fail; + } + + tell(0, "Listener established!"); + + return success; +} + +int ComThread::close(TcpClient* client, int status, const char* message) +{ + cMutexLock lock(&_mutex); + + vector<TcpClient>::iterator it; + + for (it = clients.begin(); it < clients.end(); it++) + { + TcpClient* c = &(*it); + + if (c == client) + { + if (message) + tell(0, "(%d) %s", status, message); + + c->channel->close(); + delete c->channel; + c->channel = 0; + clients.erase(it); + + break; + } + } + + return done; +} + +//*************************************************************************** +// Stop +//*************************************************************************** + +void ComThread::Stop() +{ + if (running) + { + isyslog("GraphTFT plugin try to stop communication thread"); + running = false; + Cancel(3); + } +} + +//*************************************************************************** +// Run +//*************************************************************************** + +void ComThread::Action() +{ + TcpClient client; + struct timeval tv; + fd_set readSet; + int maxFD; // the highest-numbered descriptor + int status; + + pid = getpid(); + tell(0, "TCP communication thread started (pid=%d)", pid); + + running = true; + + while (running) + { + if (!(time(0) % 120)) + tell(2, "still running, %ld clients connected", clients.size()); + + // check client connections + // perform select on all connections + + FD_ZERO(&readSet); + FD_SET(listener->getHandle(), &readSet); // file descriptor of listener + maxFD = listener->getHandle(); + + _mutex.Lock(); + + for (unsigned int i = 0; i < clients.size(); i++) + { + FD_SET(clients[i].channel->getHandle(), &readSet); + maxFD = max(maxFD, clients[i].channel->getHandle()); + } + + _mutex.Unlock(); + + tv.tv_sec = 1; + tv.tv_usec = 0; + + // call select and wait up to 1 second + + if ((status = select(maxFD+1, &readSet, 0, 0, &tv)) < 0) + { + tell(0, "Error: Select failed, error was %s", strerror(errno)); + continue; + } + + if (status == 0) + continue; // no data pending + + // at least one tcp message pending + + read(&readSet); + + // check for new connection + + if (FD_ISSET(listener->getHandle(), &readSet)) + { + FD_CLR(listener->getHandle(), &readSet); + + if (listener->listen(client.channel) == success) + { + tell(0, "Client connection accepted, now " + "%ld clients connected", clients.size()+1); + + client.lastCheck = time(0); + client.jpgQuality = 30; // speed up first draw on slow connections + client.channel->write(cGraphTftComService::cmdWelcome); + + // initial refresh + + if (refresh(&client) == success) + { + client.jpgQuality = jpgQuality; + clients.push_back(client); + } + else + close(&client, 0, "initial refresh failed"); + } + } + } + + isyslog("GraphTFT plugin tcp communication thread ended (pid=%d)", pid); +} + +//*************************************************************************** +// read +//*************************************************************************** + +int ComThread::read(fd_set* readSet) +{ + cMutexLock lock(&_mutex); + int status; + + for (unsigned int i = 0; i < clients.size(); i++) + { + if (FD_ISSET(clients[i].channel->getHandle(), readSet)) + { + FD_CLR(clients[i].channel->getHandle(), readSet); + + if ((status = read(&clients[i])) != success && status != TcpChannel::wrnTimeout) + { + close(&clients[i], status, "Error: Communication problems, read failed, closing line!"); + continue; + } + } + + if (time(0) > clients[i].lastCheck + checkTime) + close(&clients[i], 0, "Error: Missing check command on tcp connection, closing line!"); + } + + return done; +} + +//*************************************************************************** +// Read +//*************************************************************************** + +int ComThread::read(TcpClient* client) +{ + int status; + TcpChannel::Header tmp; + TcpChannel::Header header; + + // es stehen Daten an, erst einmal den Header abholen .. + + if ((status = client->channel->read((char*)&tmp, sizeof(TcpChannel::Header))) == 0) + { + header.command = ntohl(tmp.command); + header.size = ntohl(tmp.size); + + tell(3, "Got command %d with %d data bytes", header.command, header.size); + + switch (header.command) + { + case cGraphTftComService::cmdWelcome: + { + tell(1, "Got welcome"); + break; + } + + case cGraphTftComService::cmdLogout: + { + tell(1, "Got logout from client, closing line"); + close(client, 0, "Closing connection due to client logout"); + + break; + } + + case cGraphTftComService::cmdData: + { + tell(7, "Got data"); + status = client->channel->read(buffer, header.size); + break; + } + + case cGraphTftComService::cmdJpegQuality: + { + int quality; + + status = client->channel->read((char*)&quality, header.size); + quality = ntohl(quality); + + tell(0, "Got JPEG quality (%d)", quality); + + if (quality > 0 && quality <= 100) + client->jpgQuality = quality; + + break; + } + + case cGraphTftComService::cmdMouseEvent: + { + GraphTftTouchEvent ev; + + status = client->channel->read((char*)&ev, header.size); + + ev.x = ntohl(ev.x); + ev.y = ntohl(ev.y); + ev.button = ntohl(ev.button); + ev.flag = ntohl(ev.flag); + ev.data = ntohl(ev.data); + + tell(0, "Got mouse event, button (%d/%d) at (%d/%d)", ev.button, ev.flag, ev.x, ev.y); + + if (ev.flag & ComThread::efKeyboard) + Put(ev.button); + else + ((cGraphTFTDisplay*)display)->mouseEvent(ev.x, ev.y, ev.button, + ev.flag, ev.data); + + break; + } + + case cGraphTftComService::cmdStartCalibration: + { + ((cGraphTFTDisplay*)display)->setCalibrate(true); + + break; + } + + case cGraphTftComService::cmdStopCalibration: + { + ((cGraphTFTDisplay*)display)->setCalibrate(false); + + break; + } + + case cGraphTftComService::cmdCheck: + { + client->lastCheck = time(0); + + break; + } + + default: + { + tell(0, "Got unexpected protocol (%d/%d), aborting", + header.command, header.size); + status = fail; + + break; + } + } + } + + return status; +} + +//*************************************************************************** +// Put Key Code +//*************************************************************************** + +bool ComThread::Put(uint64_t Code, bool Repeat, bool Release) +{ + tell(5, "Put key action (%ld)", Code); + + return cRemote::Put(Code, Repeat, Release); +} + +//*************************************************************************** +// Refresh +//*************************************************************************** + +int ComThread::refresh() +{ + cMutexLock lock(&_mutex); + int status; + + for (unsigned int i = 0; i < clients.size(); i++) + { + if ((status = refresh(&clients[i])) != success) + close(&clients[i], status, "Refresh failed, closing connection"); + } + + return done; +} + +int ComThread::refresh(TcpClient* client) +{ + long size; + unsigned char* jpeg = 0; + int status = success; + + if (!client->channel || !client->channel->isConnected()) + return fail; + + LogDuration ld("ComThread::refresh()", 2); + + if ((size = renderer->toJpeg(jpeg, client->jpgQuality)) > 0) + { + tell(7, "Info: Write %ld kb to %d", size/1024, client->channel->getHandle()); + + status = client->channel->write(cGraphTftComService::cmdData, (char*)jpeg, size); + + free(jpeg); + } + + return status; +} |