Merge branch 'master' of fraxinas@git.opendreambox.org:/git/enigma2
[enigma2.git] / lib / dvb / pmt.cpp
index 39a2c3d71ccc8a38ee0992264fb27a8ee97c5764..842d6979a3e1c227af1bdd316379e5de8011cc2e 100644 (file)
@@ -1,3 +1,4 @@
+#include <lib/base/nconfig.h> // access to python config
 #include <lib/base/eerror.h>
 #include <lib/dvb/pmt.h>
 #include <lib/dvb/specs.h>
@@ -6,6 +7,7 @@
 #include <lib/dvb_ci/dvbci.h>
 #include <lib/dvb/epgcache.h>
 #include <lib/dvb/scan.h>
+#include <lib/dvb_ci/dvbci_session.h>
 #include <dvbsi++/ca_descriptor.h>
 #include <dvbsi++/ca_program_map_section.h>
 #include <dvbsi++/teletext_descriptor.h>
@@ -14,7 +16,6 @@
 #include <dvbsi++/stream_identifier_descriptor.h>
 #include <dvbsi++/subtitling_descriptor.h>
 #include <dvbsi++/teletext_descriptor.h>
-#include <lib/base/nconfig.h> // access to python config
 
 eDVBServicePMTHandler::eDVBServicePMTHandler()
        :m_ca_servicePtr(0), m_dvb_scan(0), m_decode_demux_num(0xFF)
@@ -50,9 +51,9 @@ void eDVBServicePMTHandler::channelStateChanged(iDVBChannel *channel)
                        eDebug("ok ... now we start!!");
 
                        if (m_pmt_pid == -1)
-                               m_PAT.begin(eApp, eDVBPATSpec(m_reference.path.empty() ? false : true), m_demux);
+                               m_PAT.begin(eApp, eDVBPATSpec(), m_demux);
                        else
-                               m_PMT.begin(eApp, eDVBPMTSpec(m_pmt_pid, m_reference.getServiceID().get(), m_reference.path.empty() ? false : true), m_demux);
+                               m_PMT.begin(eApp, eDVBPMTSpec(m_pmt_pid, m_reference.getServiceID().get()), m_demux);
 
                        if ( m_service && !m_service->cacheEmpty() )
                                serviceEvent(eventNewProgramInfo);
@@ -135,7 +136,7 @@ void eDVBServicePMTHandler::PATready(int)
                if (pmtpid == -1)
                        serviceEvent(eventNoPATEntry);
                else
-                       m_PMT.begin(eApp, eDVBPMTSpec(pmtpid, m_reference.getServiceID().get(), m_reference.path.empty() ? false : true), m_demux);
+                       m_PMT.begin(eApp, eDVBPMTSpec(pmtpid, m_reference.getServiceID().get()), m_demux);
        } else
                serviceEvent(eventNoPAT);
 }
@@ -524,8 +525,15 @@ void eDVBServicePMTHandler::SDTScanEvent(int event)
                                eDebug("no channel list");
                        else
                        {
-                               m_dvb_scan->insertInto(db, true);
-                               eDebug("sdt update done!");
+                               eDVBChannelID chid;
+                               m_reference.getChannelID(chid);
+                               if (chid == m_dvb_scan->getCurrentChannelID())
+                               {
+                                       m_dvb_scan->insertInto(db, true);
+                                       eDebug("sdt update done!");
+                               }
+                               else
+                                       eDebug("ignore sdt update data.... incorrect transponder tuned!!!");
                        }
                        break;
                }
@@ -605,7 +613,7 @@ int eDVBServicePMTHandler::tune(eServiceReferenceDVB &ref, int use_decode_demux,
 
                        if (ref.path.empty())
                        {
-                               delete m_dvb_scan;
+                               m_dvb_scan = 0;
                                m_dvb_scan = new eDVBScan(m_channel, true, false);
                                m_dvb_scan->connectEvent(slot(*this, &eDVBServicePMTHandler::SDTScanEvent), m_scan_event_connection);
                        }
@@ -631,7 +639,6 @@ int eDVBServicePMTHandler::tune(eServiceReferenceDVB &ref, int use_decode_demux,
 void eDVBServicePMTHandler::free()
 {
        m_dvb_scan = 0;
-       delete m_dvb_scan;
 
        if (m_ca_servicePtr)
        {
@@ -671,10 +678,10 @@ ChannelMap eDVBCAService::exist_channels;
 ePtr<eConnection> eDVBCAService::m_chanAddedConn;
 
 eDVBCAService::eDVBCAService()
-       :m_sn(0), m_prev_build_hash(0), m_sendstate(0), m_retryTimer(eApp)
+       :m_buffer(512), m_prev_build_hash(0), m_sendstate(0), m_retryTimer(eTimer::create(eApp))
 {
        memset(m_used_demux, 0xFF, sizeof(m_used_demux));
-       CONNECT(m_retryTimer.timeout, eDVBCAService::sendCAPMT);
+       CONNECT(m_retryTimer->timeout, eDVBCAService::sendCAPMT);
        Connect();
 }
 
@@ -682,7 +689,6 @@ eDVBCAService::~eDVBCAService()
 {
        eDebug("[eDVBCAService] free service %s", m_service.toString().c_str());
        ::close(m_sock);
-       delete m_sn;
 }
 
 // begin static methods
@@ -859,27 +865,105 @@ channel_data *eDVBCAService::getChannelData(eDVBChannelID &chid)
 }
 // end static methods
 
+#define CA_REPLY_DEBUG
+#define MAX_LENGTH_BYTES 4
+#define MIN_LENGTH_BYTES 1
+
 void eDVBCAService::socketCB(int what)
 {
-       if (what & eSocketNotifier::Read)
-               /*eDebug("[eDVBCAService] data to read\n")*/;
-       if (what & eSocketNotifier::Priority)
-               /*eDebug("[eDVBCAService] priority data to read\n")*/;
+       if (what & (eSocketNotifier::Read | eSocketNotifier::Priority))
+       {
+               char msgbuffer[4096];
+               ssize_t length = read(m_sock, msgbuffer, sizeof(msgbuffer));
+               if (length == -1)
+               {
+                       if (errno != EAGAIN && errno != EINTR && errno != EBUSY)
+                       {
+                               eDebug("[eSocketMMIHandler] read (%m)");
+                               what |= eSocketNotifier::Error;
+                       }
+               } else if (length == 0)
+               {
+                       what |= eSocketNotifier::Hungup;
+               } 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] & 0xFF) != 0x9f))
+                               clear = 0;
+                       if ((len >= 2) && ((data[1] & 0x80) != 0x80))
+                               clear = 0;
+                       if ((len >= 3) && ((data[2] & 0x80) != 0x00))
+                               clear = 0;
+                       if (clear)
+                       {
+                               m_buffer.clear();
+#ifdef CA_REPLY_DEBUG
+                               eDebug("clear buffer");
+#endif
+                       }
+#ifdef CA_REPLY_DEBUG
+                       eDebug("Put to buffer:");
+                       for (int i=0; i < len; ++i)
+                               eDebugNoNewLine("%02x ", data[i]);
+                       eDebug("\n--------");
+#endif
+                       m_buffer.write( data, len );
+
+                       while ( m_buffer.size() >= (3 + MIN_LENGTH_BYTES) )
+                       {
+                               unsigned char tmp[3+MAX_LENGTH_BYTES];
+                               m_buffer.peek(tmp, 3+MIN_LENGTH_BYTES);
+                               if (((tmp[0] & 0xFF) != 0x9f) || ((tmp[1] & 0x80) != 0x80) || ((tmp[2] & 0x80) != 0x00))
+                               {
+                                       m_buffer.skip(1);
+#ifdef CA_REPLY_DEBUG
+                                       eDebug("skip %02x", tmp[0]);
+#endif
+                                       continue;
+                               }
+                               if (tmp[3] & 0x80)
+                               {
+                                       int peekLength = (tmp[3] & 0x7f) + 4;
+                                       if (m_buffer.size() < peekLength)
+                                               continue;
+                                       m_buffer.peek(tmp, peekLength);
+                               }
+                               int size=0;
+                               int LengthBytes=eDVBCISession::parseLengthField(tmp+3, size);
+                               int messageLength = 3+LengthBytes+size;
+                               if ( m_buffer.size() >= messageLength )
+                               {
+                                       unsigned char dest[messageLength];
+                                       m_buffer.read(dest, messageLength);
+#ifdef CA_REPLY_DEBUG
+                                       eDebug("dump ca reply:");
+                                       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 & eSocketNotifier::Hungup) {
-               /*eDebug("[eDVBCAService] connection closed\n")*/;
+               /*eDebug("[eDVBCAService] connection closed")*/;
                m_sendstate=1;
                sendCAPMT();
        }
        if (what & eSocketNotifier::Error)
-               /*eDebug("[eDVBCAService] connection error\n")*/;
+               eDebug("[eDVBCAService] connection error");
 }
 
 void eDVBCAService::Connect()
 {
-       if (m_sn) {
-               delete m_sn;
-               m_sn=0;
-       }
+       m_sn=0;
        memset(&m_servaddr, 0, sizeof(struct sockaddr_un));
        m_servaddr.sun_family = AF_UNIX;
        strcpy(m_servaddr.sun_path, "/tmp/camd.socket");
@@ -892,7 +976,7 @@ void eDVBCAService::Connect()
                        int val=1;
                        fcntl(m_sock, F_SETFL, O_NONBLOCK);
                        setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, &val, 4);
-                       m_sn = new eSocketNotifier(eApp, m_sock,
+                       m_sn = eSocketNotifier::create(eApp, m_sock,
                                eSocketNotifier::Read|eSocketNotifier::Priority|eSocketNotifier::Error|eSocketNotifier::Hungup);
                        CONNECT(m_sn->activated, eDVBCAService::socketCB);
                        
@@ -1044,11 +1128,11 @@ void eDVBCAService::sendCAPMT()
                {
                        case 0xFFFFFFFF:
                                ++m_sendstate;
-                               m_retryTimer.start(0,true);
+                               m_retryTimer->start(0,true);
 //                             eDebug("[eDVBCAService] send failed .. immediate retry");
                                break;
                        default:
-                               m_retryTimer.start(5000,true);
+                               m_retryTimer->start(5000,true);
 //                             eDebug("[eDVBCAService] send failed .. retry in 5 sec");
                                break;
                }