From 04ddd458458ad1087173c5a1854677288d47c453 Mon Sep 17 00:00:00 2001 From: Andreas Monzner Date: Tue, 20 May 2008 21:07:38 +0000 Subject: [PATCH] move c++ part of socket mmi to plugin --- configure.ac | 1 + lib/mmi/Makefile.am | 2 +- .../Plugins/Extensions/SocketMMI/Makefile.am | 3 + .../Plugins/Extensions/SocketMMI/SocketMMI.py | 13 +- .../Extensions/SocketMMI/src/.cvsignore | 5 + .../Extensions/SocketMMI/src/Makefile.am | 6 + .../Extensions/SocketMMI/src/socket_mmi.cpp | 484 ++++++++++++++++++ .../Extensions/SocketMMI/src/socket_mmi.h | 62 +++ lib/python/enigma_python.i | 2 - 9 files changed, 568 insertions(+), 10 deletions(-) create mode 100644 lib/python/Plugins/Extensions/SocketMMI/src/.cvsignore create mode 100644 lib/python/Plugins/Extensions/SocketMMI/src/Makefile.am create mode 100644 lib/python/Plugins/Extensions/SocketMMI/src/socket_mmi.cpp create mode 100644 lib/python/Plugins/Extensions/SocketMMI/src/socket_mmi.h diff --git a/configure.ac b/configure.ac index c2ecec9c..156f34ec 100644 --- a/configure.ac +++ b/configure.ac @@ -129,6 +129,7 @@ lib/python/Plugins/Extensions/PicturePlayer/Makefile lib/python/Plugins/Extensions/PicturePlayer/data/Makefile lib/python/Plugins/Extensions/GraphMultiEPG/Makefile lib/python/Plugins/Extensions/SocketMMI/Makefile +lib/python/Plugins/Extensions/SocketMMI/src/Makefile lib/python/Tools/Makefile lib/service/Makefile lib/components/Makefile diff --git a/lib/mmi/Makefile.am b/lib/mmi/Makefile.am index e6d6ebd4..020c988e 100644 --- a/lib/mmi/Makefile.am +++ b/lib/mmi/Makefile.am @@ -3,4 +3,4 @@ INCLUDES = \ noinst_LIBRARIES = libenigma_mmi.a -libenigma_mmi_a_SOURCES = mmi_ui.cpp socket_mmi.cpp +libenigma_mmi_a_SOURCES = mmi_ui.cpp diff --git a/lib/python/Plugins/Extensions/SocketMMI/Makefile.am b/lib/python/Plugins/Extensions/SocketMMI/Makefile.am index ee985fb0..ce4d432f 100644 --- a/lib/python/Plugins/Extensions/SocketMMI/Makefile.am +++ b/lib/python/Plugins/Extensions/SocketMMI/Makefile.am @@ -1,6 +1,9 @@ +SUBDIRS = src + installdir = $(LIBDIR)/enigma2/python/Plugins/Extensions/SocketMMI install_PYTHON = \ + src/socketmmi.so \ __init__.py \ plugin.py \ SocketMMI.py diff --git a/lib/python/Plugins/Extensions/SocketMMI/SocketMMI.py b/lib/python/Plugins/Extensions/SocketMMI/SocketMMI.py index 69e10971..a7640df3 100644 --- a/lib/python/Plugins/Extensions/SocketMMI/SocketMMI.py +++ b/lib/python/Plugins/Extensions/SocketMMI/SocketMMI.py @@ -1,32 +1,31 @@ from Screens.Ci import MMIDialog -from enigma import eSocket_UI +import socketmmi class SocketMMIMessageHandler: def __init__(self): self.session = None self.dlgs = { } - self.handler = eSocket_UI.getInstance() - self.handler.socketStateChanged.get().append(self.socketStateChanged) + socketmmi.getSocketStateChangedCallbackList().append(self.socketStateChanged) def setSession(self, session): self.session = session def connected(self): - return self.handler.getState(0) + return socketmmi.getState(0) def getName(self): - return self.handler.getName(0) + return socketmmi.getName(0) def startMMI(self): slot = 0 - self.dlgs[slot] = self.session.openWithCallback(self.dlgClosed, MMIDialog, slot, 2, self.handler, _("wait for mmi...")) + self.dlgs[slot] = self.session.openWithCallback(self.dlgClosed, MMIDialog, slot, 2, socketmmi, _("wait for mmi...")) def socketStateChanged(self, slot): if slot in self.dlgs: self.dlgs[slot].ciStateChanged() elif self.handler.availableMMI(slot) == 1: if self.session: - self.dlgs[slot] = self.session.openWithCallback(self.dlgClosed, MMIDialog, slot, 3, self.handler, _("wait for mmi...")) + self.dlgs[slot] = self.session.openWithCallback(self.dlgClosed, MMIDialog, slot, 3, socketmmi, _("wait for mmi...")) def dlgClosed(self, slot): if slot in self.dlgs: diff --git a/lib/python/Plugins/Extensions/SocketMMI/src/.cvsignore b/lib/python/Plugins/Extensions/SocketMMI/src/.cvsignore new file mode 100644 index 00000000..41818695 --- /dev/null +++ b/lib/python/Plugins/Extensions/SocketMMI/src/.cvsignore @@ -0,0 +1,5 @@ +*.pyc +*.pyo +*.so +Makefile +Makefile.in diff --git a/lib/python/Plugins/Extensions/SocketMMI/src/Makefile.am b/lib/python/Plugins/Extensions/SocketMMI/src/Makefile.am new file mode 100644 index 00000000..ea2ab1e0 --- /dev/null +++ b/lib/python/Plugins/Extensions/SocketMMI/src/Makefile.am @@ -0,0 +1,6 @@ +socketmmi.so: socket_mmi.cpp socket_mmi.h + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEFS) -I$(top_srcdir)/include -Wall -W socket_mmi.cpp -shared -fPIC -Wl,-soname,socketmmi.so -o socketmmi.so $(LDFLAGS) + +all: socketmmi.so + +CLEANFILES = socketmmi.so diff --git a/lib/python/Plugins/Extensions/SocketMMI/src/socket_mmi.cpp b/lib/python/Plugins/Extensions/SocketMMI/src/socket_mmi.cpp new file mode 100644 index 00000000..36ce9f40 --- /dev/null +++ b/lib/python/Plugins/Extensions/SocketMMI/src/socket_mmi.cpp @@ -0,0 +1,484 @@ +#include "socket_mmi.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MAX_LENGTH_BYTES 4 +#define MIN_LENGTH_BYTES 1 +//#define MMIDEBUG + +eSocket_UI *eSocket_UI::instance; + +eSocket_UI::eSocket_UI() + :eMMI_UI(1) +{ + ASSERT(!instance); + instance = this; + CONNECT(handler.mmi_progress, eMMI_UI::processMMIData); +} + +eSocket_UI *eSocket_UI::getInstance() +{ + return instance; +} + +void eSocket_UI::setInit(int) +{ + //NYI +} + +void eSocket_UI::setReset(int) +{ + //NYI +} + +int eSocket_UI::startMMI(int) +{ + unsigned char buf[]={0x9F,0x80,0x22,0x00}; // ENTER MMI + if (handler.send_to_mmisock( buf, 4 )) + { + eDebug("eSocket_UI::startMMI failed"); + return -1; + } + return 0; +} + +int eSocket_UI::stopMMI(int) +{ + unsigned char buf[]={0x9F,0x88,0x00,0x00}; // CLOSE MMI + if (handler.send_to_mmisock( buf, 4 )) + { + eDebug("eSocket_UI::stopMMI failed"); + return -1; + } + return 0; +} + +int eSocket_UI::answerMenu(int, int answer) +{ + unsigned char data[]={0x9f,0x88,0x0B,0x01,0x00}; + data[4] = answer & 0xff; + if (handler.send_to_mmisock( data, 5 )) + { + eDebug("eSocket_UI::answerMenu failed"); + return -1; + } + return 0; +} + +int eSocket_UI::answerEnq(int, char *answer) +{ + unsigned int len = strlen(answer); + unsigned char data[4+len+MAX_LENGTH_BYTES]; + data[0] = 0x9f; + data[1] = 0x88; + data[2] = 0x08; + int LengthBytes=eDVBCISession::buildLengthField(data+3, len+1); + data[3+LengthBytes] = 0x01; + memcpy(data+4+LengthBytes, answer, len); + if (handler.send_to_mmisock( data, len+4+LengthBytes )) + { + eDebug("eSocket_UI::answerEnq failed"); + return -1; + } + return 0; +} + +int eSocket_UI::cancelEnq(int) +{ + unsigned char data[]={0x9f,0x88,0x08,0x01,0x00}; + if (handler.send_to_mmisock( data, 5 )) + { + eDebug("eSocket_UI::cancelEnq failed"); + return -1; + } + return 0; +} + +int eSocket_UI::getState(int) +{ + return handler.connected() ? 2 : 0; +} + +int eSocket_UI::getMMIState(int) +{ + return handler.connected(); +} + +//FIXME: correct "run/startlevel" +eAutoInitP0 init_socketui(eAutoInitNumbers::rc, "Socket MMI"); + +int eSocketMMIHandler::send_to_mmisock( void* buf, size_t len) +{ + int ret = write(connfd, buf, len); + if ( ret < 0 ) + eDebug("[eSocketMMIHandler] write (%m)"); + else if ( (uint)ret != len ) + eDebug("[eSocketMMIHandler] only %d bytes sent.. %d bytes should be sent", ret, len ); + else + return 0; + return ret; +} + +eSocketMMIHandler::eSocketMMIHandler() + :buffer(512), connfd(-1), connsn(0), sockname("/tmp/mmi.socket"), name(0) +{ + memset(&servaddr, 0, sizeof(struct sockaddr_un)); + servaddr.sun_family = AF_UNIX; + unlink(sockname); + strcpy(servaddr.sun_path, sockname); + clilen = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path); + if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + { + eDebug("[eSocketMMIHandler] socket (%m)"); + return; + } + + int val = 1; + if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == -1) + eDebug("[eSocketMMIHandler] SO_REUSEADDR (%m)"); + else if ((val = fcntl(listenfd, F_GETFL)) == -1) + eDebug("[eSocketMMIHandler] F_GETFL (%m)"); + else if (fcntl(listenfd, F_SETFL, val | O_NONBLOCK) == -1) + eDebug("[eSocketMMIHandler] F_SETFL (%m)"); + else if (bind(listenfd, (struct sockaddr *) &servaddr, clilen) == -1) + eDebug("[eSocketMMIHandler] bind (%m)"); + else if (listen(listenfd, 0) == -1) + eDebug("[eSocketMMIHandler] listen (%m)"); + else { + listensn = new eSocketNotifier( eApp, listenfd, POLLIN ); + listensn->start(); + CONNECT( listensn->activated, eSocketMMIHandler::listenDataAvail ); + eDebug("[eSocketMMIHandler] created successfully"); + return; + } + + close(listenfd); + listenfd = -1; +} + +#define CMD_SET_NAME "\x01\x02\x03\x04" + +void eSocketMMIHandler::listenDataAvail(int what) +{ + if (what & POLLIN) { + if ( connsn ) { + eDebug("[eSocketMMIHandler] connsn != NULL"); + return; + } + connfd = accept(listenfd, (struct sockaddr *) &servaddr, (socklen_t *) &clilen); + if (connfd == -1) { + eDebug("[eSocketMMIHandler] accept (%m)"); + return; + } + + int val; + if ((val = fcntl(connfd, F_GETFL)) == -1) + eDebug("[eSocketMMIHandler] F_GETFL (%m)"); + else if (fcntl(connfd, F_SETFL, val | O_NONBLOCK) == -1) + eDebug("[eSocketMMIHandler] F_SETFL (%m)"); + else { + connsn = new eSocketNotifier( eApp, connfd, POLLIN|POLLHUP|POLLERR ); + CONNECT( connsn->activated, eSocketMMIHandler::connDataAvail ); + return; + } + + close(connfd); + connfd = -1; + } +} + +void eSocketMMIHandler::connDataAvail(int what) +{ + if (what & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) { + char msgbuffer[4096]; + ssize_t length = read(connfd, msgbuffer, sizeof(msgbuffer)); + + if (length == -1) { + if (errno != EAGAIN && errno != EINTR && errno != EBUSY) { + eDebug("[eSocketMMIHandler] read (%m)"); + what |= POLLERR; + } + } else if (length == 0){ + what |= POLLHUP; + } else if ((!name) && (length > 4) && (!memcmp(msgbuffer, CMD_SET_NAME, 4))) { + length -= 4; + delete [] name; + name = new char[length + 1]; + memcpy(name, &msgbuffer[4], length); + name[length] = '\0'; + eDebug("MMI NAME %s", name); + } else { + int len = length; + unsigned char *data = (unsigned char*)msgbuffer; + int clear = 1; + // If a new message starts, then the previous message + // should already have been processed. Otherwise the + // previous message was incomplete and should therefore + // be deleted. + if ((len >= 1) && (data[0] != 0x9f)) + clear = 0; + if ((len >= 2) && (data[1] != 0x88)) + clear = 0; + if (clear) + { + buffer.clear(); +#ifdef MMIDEBUG + eDebug("clear buffer"); +#endif + } +#ifdef MMIDEBUG + eDebug("Put to buffer:"); + for (int i=0; i < len; ++i) + eDebugNoNewLine("%02x ", data[i]); + eDebug("\n--------"); +#endif + buffer.write( data, len ); + + while ( buffer.size() >= (3 + MIN_LENGTH_BYTES) ) + { + unsigned char tmp[3+MAX_LENGTH_BYTES]; + buffer.peek(tmp, 3+MIN_LENGTH_BYTES); + if (tmp[0] != 0x9f || tmp[1] != 0x88) + { + buffer.skip(1); +#ifdef MMIDEBUG + eDebug("skip %02x", tmp[0]); +#endif + continue; + } + if (tmp[3] & 0x80) { + int peekLength = (tmp[3] & 0x7f) + 4; + if (buffer.size() < peekLength) + continue; + buffer.peek(tmp, peekLength); + } + int size=0; + int LengthBytes=eDVBCISession::parseLengthField(tmp+3, size); + int messageLength = 3+LengthBytes+size; + if ( buffer.size() >= messageLength ) + { + unsigned char dest[messageLength]; + buffer.read(dest, messageLength); +#ifdef MMIDEBUG + eDebug("dump mmi:"); + for (int i=0; i < messageLength; ++i) + eDebugNoNewLine("%02x ", dest[i]); + eDebug("\n--------"); +#endif + /*emit*/ mmi_progress(0, dest, (const void*)(dest+3+LengthBytes), messageLength-3-LengthBytes); + } + } + } + } + + if (what & (POLLERR | POLLHUP)) { + eDebug("pollhup/pollerr"); + closeConn(); + /*emit*/ mmi_progress(0, (const unsigned char*)"\x9f\x88\x00", "\x00", 1); + } +} + +void eSocketMMIHandler::closeConn() +{ + if ( connfd != -1 ) + { + close(connfd); + connfd=-1; + } + if ( connsn ) + { + delete connsn; + connsn=0; + } + if ( name ) + { + delete [] name; + name=0; + } +} + +eSocketMMIHandler::~eSocketMMIHandler() +{ + closeConn(); + delete listensn; + unlink(sockname); +} + +extern "C" { + +static PyObject * +socketmmi_get_socket_state_changed_cb_list(PyObject *self) +{ + return eSocket_UI::getInstance()->socketStateChanged.get(); +} + +static PyObject * +socketmmi_set_init(PyObject *self, PyObject *args) +{ + int slot; + if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) + return NULL; + eSocket_UI::getInstance()->setInit(slot); + Py_RETURN_NONE; +} + +static PyObject * +socketmmi_set_reset(PyObject *self, PyObject *args) +{ + int slot; + if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) + return NULL; + eSocket_UI::getInstance()->setReset(slot); + Py_RETURN_NONE; +} + +static PyObject * +socketmmi_available_mmi(PyObject *self, PyObject *args) +{ + int slot; + if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) + return NULL; + return PyInt_FromLong(eSocket_UI::getInstance()->availableMMI(slot)); +} + +static PyObject * +socketmmi_get_mmi_screen(PyObject *self, PyObject *args) +{ + int slot; + if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) + return NULL; + return eSocket_UI::getInstance()->getMMIScreen(slot); +} + +static PyObject * +socketmmi_start_mmi(PyObject *self, PyObject *args) +{ + int slot; + if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) + return NULL; + return PyInt_FromLong(eSocket_UI::getInstance()->startMMI(slot)); +} + +static PyObject * +socketmmi_stop_mmi(PyObject *self, PyObject *args) +{ + int slot; + if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) + return NULL; + return PyInt_FromLong(eSocket_UI::getInstance()->stopMMI(slot)); +} + +static PyObject * +socketmmi_answer_menu(PyObject *self, PyObject *args) +{ + int slot, answer; + if (PyTuple_Size(args) != 2 || !PyArg_ParseTuple(args, "ii", &slot, &answer)) + return NULL; + return PyInt_FromLong(eSocket_UI::getInstance()->answerMenu(slot, answer)); +} + +static PyObject * +socketmmi_answer_enq(PyObject *self, PyObject *args) +{ + int slot; + char *answer; + if (PyTuple_Size(args) != 2 || !PyArg_ParseTuple(args, "is", &slot, &answer)) + return NULL; + return PyInt_FromLong(eSocket_UI::getInstance()->answerEnq(slot, answer)); +} + +static PyObject * +socketmmi_cancel_enq(PyObject *self, PyObject *args) +{ + int slot; + if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) + return NULL; + return PyInt_FromLong(eSocket_UI::getInstance()->cancelEnq(slot)); +} + +static PyObject * +socketmmi_get_state(PyObject *self, PyObject *args) +{ + int slot; + if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) + return NULL; + return PyInt_FromLong(eSocket_UI::getInstance()->getState(slot)); +} + +static PyObject * +socketmmi_get_mmi_state(PyObject *self, PyObject *args) +{ + int slot; + if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) + return NULL; + return PyInt_FromLong(eSocket_UI::getInstance()->getMMIState(slot)); +} + +static PyObject * +socketmmi_get_name(PyObject *self, PyObject *args) +{ + int slot; + if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) + return NULL; + return PyString_FromString(eSocket_UI::getInstance()->getName(slot)); +} + +static PyMethodDef module_methods[] = { + {"getSocketStateChangedCallbackList", (PyCFunction)socketmmi_get_socket_state_changed_cb_list, METH_NOARGS, + "get socket state change callback list" + }, + {"setInit", (PyCFunction)socketmmi_set_init, METH_VARARGS, + "set init" + }, + {"setReset", (PyCFunction)socketmmi_set_reset, METH_VARARGS, + "set reset" + }, + {"availableMMI", (PyCFunction)socketmmi_available_mmi, METH_VARARGS, + "available mmi" + }, + {"getMMIScreen", (PyCFunction)socketmmi_get_mmi_screen, METH_VARARGS, + "get mmi screen" + }, + {"startMMI", (PyCFunction)socketmmi_start_mmi, METH_VARARGS, + "start mmi" + }, + {"stopMMI", (PyCFunction)socketmmi_stop_mmi, METH_VARARGS, + "start mmi" + }, + {"answerMenu", (PyCFunction)socketmmi_answer_menu, METH_VARARGS, + "answer menu" + }, + {"answerEnq", (PyCFunction)socketmmi_answer_enq, METH_VARARGS, + "answer enq" + }, + {"cancelEnq", (PyCFunction)socketmmi_cancel_enq, METH_VARARGS, + "cancel enq" + }, + {"getState", (PyCFunction)socketmmi_get_state, METH_VARARGS, + "get state of socket" + }, + {"getMMIState", (PyCFunction)socketmmi_get_mmi_state, METH_VARARGS, + "get state of mmi" + }, + {"getName", (PyCFunction)socketmmi_get_name, METH_VARARGS, + "get name of socket user" + }, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +PyMODINIT_FUNC +initsocketmmi(void) +{ + Py_InitModule3("socketmmi", module_methods, + "Module that implements mmi via unix domain socket."); +} +}; diff --git a/lib/python/Plugins/Extensions/SocketMMI/src/socket_mmi.h b/lib/python/Plugins/Extensions/SocketMMI/src/socket_mmi.h new file mode 100644 index 00000000..ebba9a62 --- /dev/null +++ b/lib/python/Plugins/Extensions/SocketMMI/src/socket_mmi.h @@ -0,0 +1,62 @@ +#ifndef __socket_mmi_h +#define __socket_mmi_h + +#include +#include +#include + +#ifndef SWIG +#include +#include +#include +#include +#include +class eSocketMMIHandler: public Object +{ + eIOBuffer buffer; + int listenfd, connfd, clilen; + struct sockaddr_un servaddr; + eSocketNotifier *listensn, *connsn; + void listenDataAvail(int what); + void connDataAvail(int what); + void closeConn(); + const char *sockname; + char *name; +public: + const char *getName() const { return name; } + Signal4 mmi_progress; + int send_to_mmisock( void *, size_t ); + bool connected() { return !!connsn; } + eSocketMMIHandler(); + ~eSocketMMIHandler(); +}; +#endif + +class eSocket_UI: public eMMI_UI +{ + eSocketMMIHandler handler; + static eSocket_UI *instance; +#ifdef SWIG + eSocket_UI(); + ~eSocket_UI(); +#endif + void stateChanged(int val) { socketStateChanged(val); } +public: + PSignal1 socketStateChanged; +#ifndef SWIG + eSocket_UI(); +#endif + static eSocket_UI *getInstance(); + void setInit(int slot); + void setReset(int slot); + int startMMI(int slot); + int stopMMI(int slot); + int answerMenu(int slot, int answer); + int answerEnq(int slot, char *val); + int cancelEnq(int slot); + int getState(int slot); + int getMMIState(int slot); + const char *getName(int) const { return handler.getName() ? handler.getName() : "MMI Socket"; } +}; + +#endif diff --git a/lib/python/enigma_python.i b/lib/python/enigma_python.i index bc5c9466..7f141a94 100644 --- a/lib/python/enigma_python.i +++ b/lib/python/enigma_python.i @@ -93,7 +93,6 @@ is usually caused by not marking PSignals as immutable. #include #include #include -#include #include #include #include @@ -210,7 +209,6 @@ typedef long time_t; %include %include %include -%include %include %include %include -- 2.30.2