diff --git a/.github/workflows/SonarCloud.yml b/.github/workflows/SonarCloud.yml index 340f421ecfe..2bcbf86ca4d 100644 --- a/.github/workflows/SonarCloud.yml +++ b/.github/workflows/SonarCloud.yml @@ -37,6 +37,7 @@ jobs: sudo apt-get install libavahi-client-dev sudo apt-get install libjpeg-turbo8-dev sudo apt-get install libgif-dev + sudo apt-get install libcurl4-openssl-dev - uses: actions/checkout@v3 with: diff --git a/.github/workflows/enigma2.yml b/.github/workflows/enigma2.yml index 436b0773bfe..6758116ba8d 100644 --- a/.github/workflows/enigma2.yml +++ b/.github/workflows/enigma2.yml @@ -39,6 +39,7 @@ jobs: sudo apt-get install libavahi-client-dev sudo apt-get install libjpeg-turbo8-dev sudo apt-get install libgif-dev + sudo apt-get install libcurl4-openssl-dev - uses: actions/checkout@v3 diff --git a/configure.ac b/configure.ac index 73b13493bee..f287f66b96c 100644 --- a/configure.ac +++ b/configure.ac @@ -42,7 +42,7 @@ AC_ARG_WITH(gstversion, PKG_CHECK_MODULES(TUXTXT, tuxbox-tuxtxt) PKG_CHECK_MODULES(GSTREAMER, gstreamer-$GST_MAJORMINOR gstreamer-pbutils-$GST_MAJORMINOR) -PKG_CHECK_MODULES(BASE, [freetype2 fribidi gstreamer-$GST_MAJORMINOR gstreamer-pbutils-$GST_MAJORMINOR libdvbsi++ libpng libxml-2.0 sigc++-2.0 libssl libcrypto]) +PKG_CHECK_MODULES(BASE, [freetype2 fribidi gstreamer-$GST_MAJORMINOR gstreamer-pbutils-$GST_MAJORMINOR libdvbsi++ libpng libxml-2.0 sigc++-2.0 libssl libcrypto libcurl]) PKG_CHECK_MODULES(LIBDDVD, libdreamdvd, HAVE_LIBDDVD="yes", HAVE_LIBDDVD="no") AM_CONDITIONAL(HAVE_LIBDDVD, test "$HAVE_LIBDDVD" = "yes") PKG_CHECK_MODULES(AVAHI, avahi-client) diff --git a/data/menu.xml b/data/menu.xml index 8d83f858046..e735337b181 100644 --- a/data/menu.xml +++ b/data/menu.xml @@ -152,7 +152,6 @@ self.session.openWithCallback(msgClosed, EpgDeleteMsg) - diff --git a/data/setup.xml b/data/setup.xml index a8909a4ccc6..e26647e882a 100644 --- a/data/setup.xml +++ b/data/setup.xml @@ -104,14 +104,6 @@ config.usage.maxchannelnumlen config.usage.servicelist_infokey - - config.cimisc.dvbCiDelay - - config.cimisc.civersion - - config.cimisc.civersion - - config.lcd.fblcddisplay config.lcd.bright @@ -887,6 +879,7 @@ config.usage.swap_time_display_on_osd config.usage.swap_media_time_display_on_osd config.usage.hide_zap_errors + config.usage.hide_ci_messages config.usage.show_cryptoinfo config.usage.infobar_frontend_source config.usage.swap_snr_on_osd diff --git a/lib/actions/action.cpp b/lib/actions/action.cpp index 38c2a182d5a..64bbdaed41b 100644 --- a/lib/actions/action.cpp +++ b/lib/actions/action.cpp @@ -314,8 +314,8 @@ void eActionMap::keyPressed(const std::string &device, int key, int flags) { //eDebug("[eActionMap] python wildcard."); ePyObject pArgs = PyTuple_New(2); - PyTuple_SET_ITEM(pArgs, 0, PyInt_FromLong(key)); - PyTuple_SET_ITEM(pArgs, 1, PyInt_FromLong(flags)); + PyTuple_SET_ITEM(pArgs, 0, PyLong_FromLong(key)); + PyTuple_SET_ITEM(pArgs, 1, PyLong_FromLong(flags)); Py_INCREF(c->second.m_fnc); call_list.push_back(call_entry(c->second.m_fnc, pArgs)); } diff --git a/lib/base/ebase.cpp b/lib/base/ebase.cpp index 081e8a86f1e..f9365e80e86 100644 --- a/lib/base/ebase.cpp +++ b/lib/base/ebase.cpp @@ -281,8 +281,8 @@ int eMainloop::processOneEvent(long user_timeout, PyObject **res, ePyObject addi if (!*res) // NOSONAR *res = PyList_New(0); ePyObject it = PyTuple_New(2); - PyTuple_SET_ITEM(it, 0, PyInt_FromLong(pfd[i].fd)); - PyTuple_SET_ITEM(it, 1, PyInt_FromLong(pfd[i].revents)); + PyTuple_SET_ITEM(it, 0, PyLong_FromLong(pfd[i].fd)); + PyTuple_SET_ITEM(it, 1, PyLong_FromLong(pfd[i].revents)); PyList_Append(*res, it); Py_DECREF(it); } diff --git a/lib/dvb/cahandler.cpp b/lib/dvb/cahandler.cpp index 96081338cae..85916d80870 100644 --- a/lib/dvb/cahandler.cpp +++ b/lib/dvb/cahandler.cpp @@ -253,6 +253,11 @@ void eDVBCAHandler::connectionLost(ePMTClient *client) } } +int eDVBCAHandler::getNumberOfCAServices() +{ + return services.size(); +} + int eDVBCAHandler::registerService(const eServiceReferenceDVB &ref, int adapter, int demux_nums[2], int servicetype, eDVBCAService *&caservice) { CAServiceMap::iterator it = services.find(ref); @@ -308,7 +313,7 @@ int eDVBCAHandler::registerService(const eServiceReferenceDVB &ref, int adapter, return 0; } -int eDVBCAHandler::unregisterService(const eServiceReferenceDVB &ref, int adapter, int demux_nums[2], eTable *ptr) +int eDVBCAHandler::unregisterService(const eServiceReferenceDVB &ref, int adapter, int demux_nums[2], int servicetype, eTable *ptr) { CAServiceMap::iterator it = services.find(ref); if (it == services.end()) @@ -319,6 +324,8 @@ int eDVBCAHandler::unregisterService(const eServiceReferenceDVB &ref, int adapte else { eDVBCAService *caservice = it->second; + caservice->removeServiceType(servicetype); + int loops = demux_nums[0] != demux_nums[1] ? 2 : 1; for (int i = 0; i < loops; ++i) { @@ -352,6 +359,12 @@ int eDVBCAHandler::unregisterService(const eServiceReferenceDVB &ref, int adapte { delete it->second; services.erase(it); + + /* + * this service is completely removed, so we distribute + * a new list of CAPMT objects to all our clients + */ + distributeCAPMT(); } else { @@ -374,8 +387,7 @@ int eDVBCAHandler::unregisterService(const eServiceReferenceDVB &ref, int adapte serviceLeft->startLongTimer(2); usedcaid(0); - /* our servicelist has changed, distribute the list of CAPMT objects to all our clients */ - distributeCAPMT(); + return 0; } @@ -432,7 +444,10 @@ void eDVBCAHandler::processPMTForService(eDVBCAService *service, eTable::iterator client_it = clients.begin(); client_it != clients.end(); ++client_it) { if (client_it->state() == eSocket::Connection) @@ -444,10 +459,18 @@ void eDVBCAHandler::processPMTForService(eDVBCAService *service, eTable::iterator client_it = clients.begin(); client_it != clients.end(); ++client_it) + { + if (client_it->state() == eSocket::Connection) + { + service->writeCAPMTObject(*client_it, list_management); + } + } } } @@ -539,6 +562,11 @@ void eDVBCAService::addServiceType(int type) m_service_type_mask |= (1 << type); } +void eDVBCAService::removeServiceType(int type) +{ + m_service_type_mask ^= (1 << type); +} + void eDVBCAService::connectionLost() { /* reconnect in 1s */ @@ -556,7 +584,7 @@ int eDVBCAService::buildCAPMT(eTable *ptr) int pmtpid = table_spec.pid, pmt_version = table_spec.version; - uint8_t demux_mask = 0; + uint32_t demux_mask = 0; int data_demux = -1; uint32_t crc = 0; @@ -586,11 +614,11 @@ int eDVBCAService::buildCAPMT(eTable *ptr) build_hash <<= 16; build_hash |= pmtpid; build_hash <<= 8; - build_hash |= demux_mask; + build_hash |= (demux_mask & 0xff); build_hash <<= 8; build_hash |= (pmt_version & 0xff); - build_hash <<= 16; - build_hash |= (m_service_type_mask & 0xffff); + //build_hash <<= 16; + //build_hash |= (m_service_type_mask & 0xffff); // don't include in build_hash bool scrambled = false; for (std::vector::const_iterator pmt = ptr->getSections().begin(); @@ -651,7 +679,7 @@ int eDVBCAService::buildCAPMT(eTable *ptr) tmp[0] = 0x82; // demux tmp[1] = 0x02; - tmp[2] = demux_mask; // descramble bitmask + tmp[2] = demux_mask&0xFF; // descramble bitmask tmp[3] = data_demux&0xFF; // read section data from demux number capmt.injectDescriptor(tmp, false); @@ -675,6 +703,11 @@ int eDVBCAService::buildCAPMT(eTable *ptr) tmp[5] = m_service_type_mask & 0xff; capmt.injectDescriptor(tmp, true); + tmp[0] = 0x86; // demux only + tmp[1] = 0x01; + tmp[2] = data_demux&0xFF; // read section data from demux number + capmt.injectDescriptor(tmp, true); + ePtr dvbservice; if (!scrambled && !eDVBDB::getInstance()->getService(m_service, dvbservice)) { @@ -718,7 +751,7 @@ int eDVBCAService::buildCAPMT(eTable *ptr) int eDVBCAService::buildCAPMT(ePtr &dvbservice) { int pmt_version = 0; - uint8_t demux_mask = 0; + uint32_t demux_mask = 0; int data_demux = -1; uint32_t crc = 0; @@ -754,11 +787,11 @@ int eDVBCAService::buildCAPMT(ePtr &dvbservice) build_hash <<= 16; build_hash |= pmtpid; build_hash <<= 8; - build_hash |= demux_mask; + build_hash |= (demux_mask & 0xff); build_hash <<= 8; build_hash |= (pmt_version & 0xff); - build_hash <<= 16; - build_hash |= (m_service_type_mask & 0xffff); + //build_hash <<= 16; + //build_hash |= (m_service_type_mask & 0xffff); // don't include in build_hash int pos = 0; int programInfoLength = 0; @@ -796,7 +829,7 @@ int eDVBCAService::buildCAPMT(ePtr &dvbservice) m_capmt[pos++] = 0x82; // demux m_capmt[pos++] = 0x02; - m_capmt[pos++] = demux_mask; // descramble bitmask + m_capmt[pos++] = demux_mask&0xFF; // descramble bitmask m_capmt[pos++] = data_demux&0xFF; // read section data from demux number programInfoLength += 4; @@ -840,6 +873,12 @@ int eDVBCAService::buildCAPMT(ePtr &dvbservice) programInfoLength += 6; + m_capmt[pos++] = 0x86; // demux + m_capmt[pos++] = 0x01; + m_capmt[pos++] = data_demux&0xFF; // read section data from demux number + + programInfoLength += 3; + std::map pidtype; pidtype[eDVBService::cVPID] = 0x02; // Videostream (MPEG-2) diff --git a/lib/dvb/cahandler.h b/lib/dvb/cahandler.h index 3cb30ff6fb3..8d9d1a5afef 100644 --- a/lib/dvb/cahandler.h +++ b/lib/dvb/cahandler.h @@ -102,7 +102,7 @@ class ePMTClient : public eUnixDomainSocket class eDVBCAService: public eUnixDomainSocket { eServiceReferenceDVB m_service; - uint8_t m_used_demux[8]; + uint8_t m_used_demux[32]; uint8_t m_adapter; uint32_t m_service_type_mask; uint64_t m_prev_build_hash; @@ -122,6 +122,7 @@ class eDVBCAService: public eUnixDomainSocket uint8_t getAdapter(); void setAdapter(uint8_t value); void addServiceType(int type); + void removeServiceType(int type); void sendCAPMT(); int writeCAPMTObject(eSocket *socket, int list_management = -1); int buildCAPMT(eTable *ptr); @@ -136,13 +137,11 @@ typedef std::map CAServiceMap; SWIG_IGNORE(iCryptoInfo); class iCryptoInfo : public iObject { -#ifdef SWIG public: +#ifdef SWIG iCryptoInfo(); ~iCryptoInfo(); -private: #endif -public: PSignal1 clientname; PSignal1 clientinfo; PSignal1 verboseinfo; @@ -176,8 +175,9 @@ DECLARE_REF(eDVBCAHandler); #ifndef SWIG ~eDVBCAHandler(); + int getNumberOfCAServices(); int registerService(const eServiceReferenceDVB &service, int adapter, int demux_nums[2], int servicetype, eDVBCAService *&caservice); - int unregisterService(const eServiceReferenceDVB &service , int adapter, int demux_nums[2], eTable *ptr); + int unregisterService(const eServiceReferenceDVB &service, int adapter, int demux_nums[2], int servicetype, eTable *ptr); void handlePMT(const eServiceReferenceDVB &service, ePtr > &ptr); void handlePMT(const eServiceReferenceDVB &service, ePtr &dvbservice); void connectionLost(ePMTClient *client); diff --git a/lib/dvb/db.cpp b/lib/dvb/db.cpp index 01348b4a069..5e663a9cb81 100644 --- a/lib/dvb/db.cpp +++ b/lib/dvb/db.cpp @@ -1427,7 +1427,7 @@ PyObject *eDVBDB::readSatellites(ePyObject sat_list, ePyObject sat_dict, ePyObje tmp = strtol((const char*)attr->children->content, &end_ptr, 10); if (!*end_ptr) { - sat_flags = PyInt_FromLong(tmp); + sat_flags = PyLong_FromLong(tmp); } } else if (name == "position") @@ -1435,7 +1435,7 @@ PyObject *eDVBDB::readSatellites(ePyObject sat_list, ePyObject sat_dict, ePyObje tmp = strtol((const char*)attr->children->content, &end_ptr, 10); if (!*end_ptr) { - sat_pos = PyInt_FromLong(tmp < 0 ? 3600 + tmp : tmp); + sat_pos = PyLong_FromLong(tmp < 0 ? 3600 + tmp : tmp); } } } @@ -1445,7 +1445,7 @@ PyObject *eDVBDB::readSatellites(ePyObject sat_list, ePyObject sat_dict, ePyObje ePyObject tplist = PyList_New(0); ePyObject tuple = PyTuple_New(3); if (!sat_flags) - sat_flags = PyInt_FromLong(0); + sat_flags = PyLong_FromLong(0); PyTuple_SET_ITEM(tuple, 0, sat_pos); PyTuple_SET_ITEM(tuple, 1, sat_name); PyTuple_SET_ITEM(tuple, 2, sat_flags); @@ -1515,23 +1515,23 @@ PyObject *eDVBDB::readSatellites(ePyObject sat_list, ePyObject sat_dict, ePyObje pls_code = root2gold(pls_code); } tuple = PyTuple_New(17); - PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0)); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(freq)); - PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(sr)); - PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(pol)); - PyTuple_SET_ITEM(tuple, 4, PyInt_FromLong(fec)); - PyTuple_SET_ITEM(tuple, 5, PyInt_FromLong(system)); - PyTuple_SET_ITEM(tuple, 6, PyInt_FromLong(modulation)); - PyTuple_SET_ITEM(tuple, 7, PyInt_FromLong(inv)); - PyTuple_SET_ITEM(tuple, 8, PyInt_FromLong(rolloff)); - PyTuple_SET_ITEM(tuple, 9, PyInt_FromLong(pilot)); - PyTuple_SET_ITEM(tuple, 10, PyInt_FromLong(is_id)); - PyTuple_SET_ITEM(tuple, 11, PyInt_FromLong(pls_mode & 3)); - PyTuple_SET_ITEM(tuple, 12, PyInt_FromLong(pls_code & 0x3FFFF)); - PyTuple_SET_ITEM(tuple, 13, PyInt_FromLong(t2mi_plp_id)); - PyTuple_SET_ITEM(tuple, 14, PyInt_FromLong(t2mi_pid)); - PyTuple_SET_ITEM(tuple, 15, PyInt_FromLong(tsid)); - PyTuple_SET_ITEM(tuple, 16, PyInt_FromLong(onid)); + PyTuple_SET_ITEM(tuple, 0, PyLong_FromLong(0)); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(freq)); + PyTuple_SET_ITEM(tuple, 2, PyLong_FromLong(sr)); + PyTuple_SET_ITEM(tuple, 3, PyLong_FromLong(pol)); + PyTuple_SET_ITEM(tuple, 4, PyLong_FromLong(fec)); + PyTuple_SET_ITEM(tuple, 5, PyLong_FromLong(system)); + PyTuple_SET_ITEM(tuple, 6, PyLong_FromLong(modulation)); + PyTuple_SET_ITEM(tuple, 7, PyLong_FromLong(inv)); + PyTuple_SET_ITEM(tuple, 8, PyLong_FromLong(rolloff)); + PyTuple_SET_ITEM(tuple, 9, PyLong_FromLong(pilot)); + PyTuple_SET_ITEM(tuple, 10, PyLong_FromLong(is_id)); + PyTuple_SET_ITEM(tuple, 11, PyLong_FromLong(pls_mode & 3)); + PyTuple_SET_ITEM(tuple, 12, PyLong_FromLong(pls_code & 0x3FFFF)); + PyTuple_SET_ITEM(tuple, 13, PyLong_FromLong(t2mi_plp_id)); + PyTuple_SET_ITEM(tuple, 14, PyLong_FromLong(t2mi_pid)); + PyTuple_SET_ITEM(tuple, 15, PyLong_FromLong(tsid)); + PyTuple_SET_ITEM(tuple, 16, PyLong_FromLong(onid)); PyList_Append(tplist, tuple); Py_DECREF(tuple); } @@ -1612,7 +1612,7 @@ PyObject *eDVBDB::readCables(ePyObject cab_list, ePyObject tp_dict) { tmp = strtol((const char*)attr->children->content, &end_ptr, 10); if (!*end_ptr) - cab_flags = PyInt_FromLong(tmp); + cab_flags = PyLong_FromLong(tmp); } else if (name == "countrycode") { @@ -1625,7 +1625,7 @@ PyObject *eDVBDB::readCables(ePyObject cab_list, ePyObject tp_dict) ePyObject tplist = PyList_New(0); ePyObject tuple = PyTuple_New(3); if (!cab_flags) - cab_flags = PyInt_FromLong(0); + cab_flags = PyLong_FromLong(0); if (!cab_countrycode) cab_countrycode = PyString_FromString(""); PyTuple_SET_ITEM(tuple, 0, cab_name); @@ -1673,13 +1673,13 @@ PyObject *eDVBDB::readCables(ePyObject cab_list, ePyObject tp_dict) while (freq > 999999) freq /= 10; tuple = PyTuple_New(7); - PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1)); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(freq)); - PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(sr)); - PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(modulation)); - PyTuple_SET_ITEM(tuple, 4, PyInt_FromLong(fec)); - PyTuple_SET_ITEM(tuple, 5, PyInt_FromLong(inversion)); - PyTuple_SET_ITEM(tuple, 6, PyInt_FromLong(system)); + PyTuple_SET_ITEM(tuple, 0, PyLong_FromLong(1)); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(freq)); + PyTuple_SET_ITEM(tuple, 2, PyLong_FromLong(sr)); + PyTuple_SET_ITEM(tuple, 3, PyLong_FromLong(modulation)); + PyTuple_SET_ITEM(tuple, 4, PyLong_FromLong(fec)); + PyTuple_SET_ITEM(tuple, 5, PyLong_FromLong(inversion)); + PyTuple_SET_ITEM(tuple, 6, PyLong_FromLong(system)); PyList_Append(tplist, tuple); Py_DECREF(tuple); } @@ -1765,7 +1765,7 @@ PyObject *eDVBDB::readTerrestrials(ePyObject ter_list, ePyObject tp_dict) tmp = strtol((const char*)attr->children->content, &end_ptr, 10); if (!*end_ptr) { - ter_flags = PyInt_FromLong(tmp); + ter_flags = PyLong_FromLong(tmp); } } else if (name == "countrycode") @@ -1779,7 +1779,7 @@ PyObject *eDVBDB::readTerrestrials(ePyObject ter_list, ePyObject tp_dict) ePyObject tplist = PyList_New(0); ePyObject tuple = PyTuple_New(3); if (!ter_flags) - ter_flags = PyInt_FromLong(0); + ter_flags = PyLong_FromLong(0); if (!ter_countrycode) ter_countrycode = PyString_FromString(""); PyTuple_SET_ITEM(tuple, 0, ter_name); @@ -1850,18 +1850,18 @@ PyObject *eDVBDB::readTerrestrials(ePyObject ter_list, ePyObject tp_dict) if (crl > eDVBFrontendParametersTerrestrial::FEC_8_9) crl = eDVBFrontendParametersTerrestrial::FEC_Auto; tuple = PyTuple_New(12); - PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(2)); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(freq)); - PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(bw)); - PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(constellation)); - PyTuple_SET_ITEM(tuple, 4, PyInt_FromLong(crh)); - PyTuple_SET_ITEM(tuple, 5, PyInt_FromLong(crl)); - PyTuple_SET_ITEM(tuple, 6, PyInt_FromLong(guard)); - PyTuple_SET_ITEM(tuple, 7, PyInt_FromLong(transm)); - PyTuple_SET_ITEM(tuple, 8, PyInt_FromLong(hierarchy)); - PyTuple_SET_ITEM(tuple, 9, PyInt_FromLong(inv)); - PyTuple_SET_ITEM(tuple, 10, PyInt_FromLong(system)); - PyTuple_SET_ITEM(tuple, 11, PyInt_FromLong(plp_id)); + PyTuple_SET_ITEM(tuple, 0, PyLong_FromLong(2)); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(freq)); + PyTuple_SET_ITEM(tuple, 2, PyLong_FromLong(bw)); + PyTuple_SET_ITEM(tuple, 3, PyLong_FromLong(constellation)); + PyTuple_SET_ITEM(tuple, 4, PyLong_FromLong(crh)); + PyTuple_SET_ITEM(tuple, 5, PyLong_FromLong(crl)); + PyTuple_SET_ITEM(tuple, 6, PyLong_FromLong(guard)); + PyTuple_SET_ITEM(tuple, 7, PyLong_FromLong(transm)); + PyTuple_SET_ITEM(tuple, 8, PyLong_FromLong(hierarchy)); + PyTuple_SET_ITEM(tuple, 9, PyLong_FromLong(inv)); + PyTuple_SET_ITEM(tuple, 10, PyLong_FromLong(system)); + PyTuple_SET_ITEM(tuple, 11, PyLong_FromLong(plp_id)); PyList_Append(tplist, tuple); Py_DECREF(tuple); } @@ -1943,7 +1943,7 @@ PyObject *eDVBDB::readATSC(ePyObject atsc_list, ePyObject tp_dict) { tmp = strtol((const char*)attr->children->content, &end_ptr, 10); if (!*end_ptr) - atsc_flags = PyInt_FromLong(tmp); + atsc_flags = PyLong_FromLong(tmp); } } @@ -1952,7 +1952,7 @@ PyObject *eDVBDB::readATSC(ePyObject atsc_list, ePyObject tp_dict) ePyObject tplist = PyList_New(0); ePyObject tuple = PyTuple_New(2); if (!atsc_flags) - atsc_flags = PyInt_FromLong(0); + atsc_flags = PyLong_FromLong(0); PyTuple_SET_ITEM(tuple, 0, atsc_name); PyTuple_SET_ITEM(tuple, 1, atsc_flags); PyList_Append(atsc_list, tuple); @@ -1991,11 +1991,11 @@ PyObject *eDVBDB::readATSC(ePyObject atsc_list, ePyObject tp_dict) if (freq) { tuple = PyTuple_New(5); - PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(3)); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(freq)); - PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(modulation)); - PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(inversion)); - PyTuple_SET_ITEM(tuple, 4, PyInt_FromLong(system)); + PyTuple_SET_ITEM(tuple, 0, PyLong_FromLong(3)); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(freq)); + PyTuple_SET_ITEM(tuple, 2, PyLong_FromLong(modulation)); + PyTuple_SET_ITEM(tuple, 3, PyLong_FromLong(inversion)); + PyTuple_SET_ITEM(tuple, 4, PyLong_FromLong(system)); PyList_Append(tplist, tuple); Py_DECREF(tuple); } @@ -2161,9 +2161,9 @@ PyObject *eDVBDB::getFlag(const eServiceReference &ref) eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref; std::map >::iterator it(m_services.find(service)); if (it != m_services.end()) - return PyInt_FromLong(it->second->m_flags); + return PyLong_FromLong(it->second->m_flags); } - return PyInt_FromLong(0); + return PyLong_FromLong(0); } PyObject *eDVBDB::getCachedPid(const eServiceReference &ref, int id) @@ -2173,9 +2173,9 @@ PyObject *eDVBDB::getCachedPid(const eServiceReference &ref, int id) eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref; std::map >::iterator it(m_services.find(service)); if (it != m_services.end()) - return PyInt_FromLong(it->second->getCacheEntry((eDVBService::cacheID)id)); + return PyLong_FromLong(it->second->getCacheEntry((eDVBService::cacheID)id)); } - return PyInt_FromLong(-1); + return PyLong_FromLong(-1); } bool eDVBDB::isCrypted(const eServiceReference &ref) diff --git a/lib/dvb/decoder.cpp b/lib/dvb/decoder.cpp index aedc3c6ef7c..ea49690d828 100644 --- a/lib/dvb/decoder.cpp +++ b/lib/dvb/decoder.cpp @@ -1649,7 +1649,7 @@ int eTSMPEGDecoder::getVideoGamma() RESULT eTSMPEGDecoder::prepareFCC(int fe_id, int vpid, int vtype, int pcrpid) { - //eDebug("[eTSMPEGDecoder] prepareFCC vp : %d, vt : %d, pp : %d, fe : %d", vpid, vtype, pcrpid, fe_id); + eTrace("[eTSMPEGDecoder] prepareFCC vp : %d, vt : %d, pp : %d, fe : %d", vpid, vtype, pcrpid, fe_id); if ((fccGetFD() == -1) || (fccSetPids(fe_id, vpid, vtype, pcrpid) < 0) || (fccStart() < 0)) { @@ -1715,7 +1715,7 @@ RESULT eTSMPEGDecoder::fccDecoderStop() RESULT eTSMPEGDecoder::fccUpdatePids(int fe_id, int vpid, int vtype, int pcrpid) { - //eDebug("[eTSMPEGDecoder] vp : %d, vt : %d, pp : %d, fe : %d", vpid, vtype, pcrpid, fe_id); + eTrace("[eTSMPEGDecoder] vp : %d, vt : %d, pp : %d, fe : %d", vpid, vtype, pcrpid, fe_id); if ((fe_id != m_fcc_feid) || (vpid != m_fcc_vpid) || (vtype != m_fcc_vtype) || (pcrpid != m_fcc_pcrpid)) { diff --git a/lib/dvb/dvb.cpp b/lib/dvb/dvb.cpp index 2f2ad9b18d3..1bacf04c0fc 100644 --- a/lib/dvb/dvb.cpp +++ b/lib/dvb/dvb.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -30,22 +31,24 @@ DEFINE_REF(eDVBRegisteredDemux); DEFINE_REF(eDVBAllocatedFrontend); -eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe): m_fe(fe) +void eDVBRegisteredFrontend::closeFrontend() +{ + if (!m_inuse && m_frontend->closeFrontend()) // frontend busy + disable->start(60000, true); // retry close in 60secs +} + +eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe, eFBCTunerManager *fbcmng) + : m_fe(fe), m_fbcmng(fbcmng) { m_fe->inc_use(); - if (m_fe->m_frontend->is_FBCTuner()) - { - eFBCTunerManager* fbcmng = eFBCTunerManager::getInstance(); - if (fbcmng) - { - fbcmng->Unlink(m_fe); - } - } } eDVBAllocatedFrontend::~eDVBAllocatedFrontend() { m_fe->dec_use(); + + if (m_fe->m_frontend->is_FBCTuner() && m_fbcmng) + m_fbcmng->Unlink(m_fe); } DEFINE_REF(eDVBAllocatedDemux); @@ -197,8 +200,8 @@ eDVBResourceManager::eDVBResourceManager() eDebug("[eDVBResourceManager] found %zd adapter, %zd frontends(%zd sim) and %zd demux, boxtype %d", m_adapter.size(), m_frontend.size(), m_simulate_frontend.size(), m_demux.size(), m_boxtype); - m_fbc_mng = new eFBCTunerManager(this); - + m_fbcmng = new eFBCTunerManager(instance); + CONNECT(m_releaseCachedChannelTimer->timeout, eDVBResourceManager::releaseCachedChannel); } @@ -281,6 +284,7 @@ int eDVBAdapterLinux::getNumDemux() RESULT eDVBAdapterLinux::getDemux(ePtr &demux, int nr) { eDebug("[eDVBAdapterLinux] get demux %d", nr); + eSmartPtrList::iterator i(m_demux.begin()); while (nr && (i != m_demux.end())) { @@ -996,27 +1000,40 @@ void eDVBResourceManager::setFrontendType(int index, const char *type, bool appe RESULT eDVBResourceManager::allocateFrontend(ePtr &fe, ePtr &feparm, bool simulate, bool returnScoreOnly) { eSmartPtrList &frontends = simulate ? m_simulate_frontend : m_frontend; -// ePtr best; - eDVBRegisteredFrontend *best = NULL; - int bestval = 0; - int foundone = 0; - - int check_fbc_linked = 0; - eDVBRegisteredFrontend *fbc_fe = NULL; - eDVBRegisteredFrontend *best_fbc_fe = NULL; - eFBCTunerManager* fbcmng = m_fbc_mng; + eDVBRegisteredFrontend *best, *fbc_fe, *best_fbc_fe; + int bestval, foundone, current_fbc_setid, c; + bool check_fbc_leaf_linkable, is_configured_sat; + long link; + + fbc_fe = NULL; + best_fbc_fe = NULL; + best = NULL; + bestval = 0; + foundone = 0; + check_fbc_leaf_linkable = false; + current_fbc_setid = -1; for (eSmartPtrList::iterator i(frontends.begin()); i != frontends.end(); ++i) { - int c = 0; + c = 0; + is_configured_sat = false; fbc_fe = NULL; - if (!check_fbc_linked && i->m_frontend->is_FBCTuner() && fbcmng && fbcmng->CanLink(*i)) + if (i->m_frontend->is_FBCTuner() && m_fbcmng->CanLink(*i)) { - check_fbc_linked = 1; - c = fbcmng->IsCompatibleWith(feparm, *i, fbc_fe, simulate); + int fbc_setid = m_fbcmng->GetFBCSetID(i->m_frontend->getSlotID()); + if (fbc_setid != current_fbc_setid) + { + current_fbc_setid = fbc_setid; + check_fbc_leaf_linkable = false; + } -// eDebug("[eDVBResourceManager::allocateFrontend] fbcmng->isCompatibleWith slotid : %p (%d), fbc_fe : %p (%d), score : %d", (eDVBRegisteredFrontend *)*i, i->m_frontend->getSlotID(), fbc_fe, fbc_fe?fbc_fe->m_frontend->getSlotID():-1, c); + if (!check_fbc_leaf_linkable) + { + c = m_fbcmng->IsCompatibleWith(feparm, *i, fbc_fe, simulate); + check_fbc_leaf_linkable = true; + //eDebug("[eDVBResourceManager::allocateFrontend] m_fbcmng->isCompatibleWith slotid : %p (%d), fbc_fe : %p (%d), score : %d", (eDVBRegisteredFrontend *)*i, i->m_frontend->ge); + } } else { @@ -1052,17 +1069,14 @@ RESULT eDVBResourceManager::allocateFrontend(ePtr &fe, eP if (best) { - if (fbcmng && best_fbc_fe) - { - fbcmng->AddLink(best, best_fbc_fe, simulate); - } + if (best_fbc_fe) + m_fbcmng->AddLink(best, best_fbc_fe, simulate); - fe = new eDVBAllocatedFrontend(best); + fe = new eDVBAllocatedFrontend(best, m_fbcmng); return 0; } fe = 0; - if (foundone) return errAllSourcesBusy; else @@ -1115,7 +1129,7 @@ RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr prev->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp); } } - fe = new eDVBAllocatedFrontend(i); + fe = new eDVBAllocatedFrontend(i, m_fbcmng); return 0; } alloc_fe_by_id_not_possible: @@ -1127,9 +1141,8 @@ RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr &demux, int &cap) { - /* find first unused demux which is on same adapter as frontend (or any, if PVR) - never use the first one unless we need a decoding demux. */ - uint8_t d, a; + /* find first unused demux which is on same adapter as frontend (or any, if PVR) + never use the first one unless we need a decoding demux. */ eDebug("[eDVBResourceManager] allocate demux cap=%02X", cap); eSmartPtrList::iterator i(m_demux.begin()); @@ -1137,35 +1150,41 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr unused; iDVBAdapter *adapter = fe ? fe->m_adapter : m_adapter.begin(); /* look for a demux on the same adapter as the frontend, or the first adapter for dvr playback */ - int source = fe ? fe->m_frontend->getDVBID() : -1; - cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux - if (!fe) + int fesource = fe ? fe->m_frontend->getDVBID() : -1; + ePtr unused; + uint8_t d, a; + + /* + * For pvr playback, start with the last demux. + * On some hardware, there are less ca devices than demuxes, so try to leave + * the first demuxes for live tv, and start with the last for pvr playback + */ + +// cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux + bool use_decode_demux = (fe || (cap & iDVBChannel::capDecode)); + + if (!use_decode_demux) { - /* - * For pvr playback, start with the last demux. - * On some hardware, we have less ca devices than demuxes, - * so we should try to leave the first demuxes for live tv, - * and start with the last for pvr playback - */ i = m_demux.end(); --i; } + while (i != m_demux.end()) { if (i->m_adapter == adapter) { if (!i->m_inuse) { - /* mark the first unused demux, we'll use that when we do not find a better match */ - if (!unused) unused = i; + // mark the first unused demux and use that when no better match is found + if (!unused) + unused = i; } else { - /* demux is in use, see if we can share it */ - if (source >= 0 && i->m_demux->getSource() == source) + // demux is in use, see if it can be shared + if (fesource >= 0 && i->m_demux->getSource() == fesource) { i->m_demux->getCAAdapterID(a); i->m_demux->getCADemuxID(d); @@ -1175,12 +1194,14 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtrm_demux->getCAAdapterID(a); unused->m_demux->getCADemuxID(d); - eDebug("[eDVBResourceManager] allocating demux adapter=%d, demux=%d, source=%d", a, d, unused->m_demux->getSource()); + eDebug("[eDVBResourceManager] allocating demux adapter=%d, demux=%d, source=%d fesource=%d", a, d, unused->m_demux->getSource(), fesource); demux = new eDVBAllocatedDemux(unused); if (fe) - demux->get().setSourceFrontend(fe->m_frontend->getDVBID()); + demux->get().setSourceFrontend(fesource); else demux->get().setSourcePVR(0); return 0; @@ -1521,32 +1542,40 @@ int eDVBResourceManager::canAllocateFrontend(ePtr &fepar { eSmartPtrList &frontends = simulate ? m_simulate_frontend : m_frontend; ePtr best; - int bestval = 0; - int check_fbc_linked = 0; - eDVBRegisteredFrontend *fbc_fe = NULL; -// eDVBRegisteredFrontend *best_fbc_fe = NULL; - eFBCTunerManager *fbcmng = m_fbc_mng; + int bestval, current_fbc_setid, c; + bool check_fbc_leaf_linkable; + + bestval = 0; + check_fbc_leaf_linkable = false; + current_fbc_setid = -1; for (eSmartPtrList::iterator i(frontends.begin()); i != frontends.end(); ++i) { if (!i->m_inuse) { - int c = 0; - fbc_fe = NULL; - if (!check_fbc_linked && i->m_frontend->is_FBCTuner() && fbcmng && fbcmng->CanLink(*i)) + c = 0; + if(i->m_frontend->is_FBCTuner() && m_fbcmng->CanLink(*i)) { - check_fbc_linked = 1; - c = fbcmng->IsCompatibleWith(feparm, *i, fbc_fe, simulate); + int fbc_setid = m_fbcmng->GetFBCSetID(i->m_frontend->getSlotID()); + + if (fbc_setid != current_fbc_setid) + { + current_fbc_setid = fbc_setid; + check_fbc_leaf_linkable = false; + } + + if (!check_fbc_leaf_linkable) + { + eDVBRegisteredFrontend *dummy; + c = m_fbcmng->IsCompatibleWith(feparm, *i, dummy, simulate); + check_fbc_leaf_linkable = true; + } } else - { c = i->m_frontend->isCompatibleWith(feparm); - } + if (c > bestval) - { bestval = c; -// best_fbc_fe = fbc_fe; - } } } return bestval; diff --git a/lib/dvb/dvb.h b/lib/dvb/dvb.h index 563c8fceefd..f824235be0d 100644 --- a/lib/dvb/dvb.h +++ b/lib/dvb/dvb.h @@ -27,11 +27,7 @@ class eDVBRegisteredFrontend: public iObject, public sigc::trackable { DECLARE_REF(eDVBRegisteredFrontend); ePtr disable; - void closeFrontend() - { - if (!m_inuse && m_frontend->closeFrontend()) // frontend busy - disable->start(60000, true); // retry close in 60secs - } + void closeFrontend(); public: sigc::signal0 stateChanged; eDVBRegisteredFrontend(eDVBFrontend *fe, iDVBAdapter *adap) @@ -75,7 +71,7 @@ class eDVBAllocatedFrontend DECLARE_REF(eDVBAllocatedFrontend); public: - eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe); + eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe, eFBCTunerManager *fbcmng); ~eDVBAllocatedFrontend(); eDVBFrontend &get() { return *m_fe->m_frontend; } operator eDVBRegisteredFrontend*() { return m_fe; } @@ -83,6 +79,7 @@ class eDVBAllocatedFrontend private: eDVBRegisteredFrontend *m_fe; + eFBCTunerManager *m_fbcmng; }; class eDVBAllocatedDemux @@ -188,12 +185,13 @@ class eDVBResourceManager: public iObject, public sigc::trackable ePtr m_list; ePtr m_sec; static eDVBResourceManager *instance; - ePtr m_fbc_mng; friend class eDVBChannel; friend class eFBCTunerManager; friend class eRTSPStreamClient; + ePtr m_fbcmng; + RESULT addChannel(const eDVBChannelID &chid, eDVBChannel *ch); RESULT removeChannel(eDVBChannel *ch); diff --git a/lib/dvb/fbc.cpp b/lib/dvb/fbc.cpp index bd9c35ab659..4adc190de49 100644 --- a/lib/dvb/fbc.cpp +++ b/lib/dvb/fbc.cpp @@ -1,4 +1,3 @@ -/* FBC Manager */ #include #include #include @@ -7,66 +6,78 @@ #include #include -//#define FBC_DEBUG +#include +#include +#include +#include -#ifdef FBC_DEBUG -#define eFecDebug(arg...) eDebug(arg) -#else -#define eFecDebug(arg...) -#endif - -static int getProcData(const char* filename) +int eFBCTunerManager::ReadProcInt(int fe_index, const std::string & entry) { - int res = -1; - FILE *fp = fopen(filename,"r"); - if(fp) - { - if(fscanf(fp, "%d", &res) != 1) - eFecDebug("[*][eFBCTunerManager::getProcData] read failed, %s: %m", filename); - fclose(fp); - } - else - { - eFecDebug("[*][eFBCTunerManager::getProcData] open failed, %s: %m", filename); - } - return res; + int value; + std::stringstream path; + std::ifstream file; + + path << "/proc/stb/frontend/" << fe_index << "/" << entry; + file.open(path.str().c_str()); + + if(!file.is_open()) + return(-1); + + file >> value; + + if(file.bad() || file.fail()) + return(-1); + + return(value); } -static void setProcData(const char* filename, int value) +void eFBCTunerManager::WriteProcInt(int fe_index, const std::string & entry, int value) { - eDebug("[*] setProcData %s -> %d", filename, value); - FILE *fp = fopen(filename, "w"); - if(fp) - { - fprintf(fp, "%d", value); - fclose(fp); - } - else - { - eFecDebug("[*][eFBCTunerManager::setProcData] open failed, %s: %m", filename); - } + std::stringstream path; + std::ofstream file; + + path << "/proc/stb/frontend/" << fe_index << "/" << entry; + file.open(path.str().c_str()); + + if(!file.is_open()) + return; + + file << value; } -static void loadConnectChoices(const char* filename, bool *connect_choices) +void eFBCTunerManager::LoadConnectChoices(int fe_index, connect_choices_t &choices) { - FILE *fp = fopen(filename,"r"); - if(fp) + std::stringstream path; + std::ifstream file; + std::string line; + std::string::const_iterator it; + int fbc_id; + + path << "/proc/stb/frontend/" << fe_index << "/fbc_connect_choices"; + file.open(path.str().c_str()); + + if(!file.is_open()) + return; + + getline(file, line); + + if(file.bad() || file.fail()) + return; + + choices.reset(); + + for(it = line.begin(); it != line.end(); it++) { - int c; - while(EOF != (c = fgetc(fp))) + if(isdigit(*it)) { - if(isdigit(c)) - connect_choices[c - '0'] = true; // NOSONAR + fbc_id = (char)*it - '0'; + + if((fbc_id >= 0) && (fbc_id < (int)choices.size())) + choices.set(fbc_id); } - fclose(fp); - } - else - { - eFecDebug("[*][eFBCTunerManager::LoadFbcRootChoices] open failed, %s: %m", filename); } } - DEFINE_REF(eFBCTunerManager); eFBCTunerManager* eFBCTunerManager::m_instance = (eFBCTunerManager*)0; @@ -79,137 +90,121 @@ eFBCTunerManager* eFBCTunerManager::getInstance() eFBCTunerManager::eFBCTunerManager(ePtr res_mgr) :m_res_mgr(res_mgr) { - if (!m_instance) - m_instance = this; - eSmartPtrList &frontends = m_res_mgr->m_frontend; eSmartPtrList &frontends_simulate = m_res_mgr->m_simulate_frontend; + tuner_t tuner; + int fe_id, fbc_prev_set_id; /* each FBC set has 8 tuners. */ /* first set : 0, 1, 2, 3, 4, 5, 6, 7 */ /* second set : 8, 9, 10, 11, 12, 13, 14, 15 */ /* first, second frontend is top on a set */ - bool isRoot; - int fe_id = -1; - int fbcSetID = -2; - unsigned int fbcIndex = 0; - int initFbcId = -1; - int prevFbcSetID = -1; - char procFileName[128]; - std::string proc_fe; - bool connect_choices[32] = {false}; + if (!m_instance) + m_instance = this; + + tuner.id = 0; + + fe_id = -1; + fbc_prev_set_id = -1; for (eSmartPtrList::iterator it(frontends.begin()); it != frontends.end(); ++it) { // continue for DVB-C FBC Tuner + + it->m_frontend->setFBCTuner(false); // TODO TEST + if (!(it->m_frontend->supportsDeliverySystem(SYS_DVBS, false) || it->m_frontend->supportsDeliverySystem(SYS_DVBS2, false))) - continue; + continue; // ignore DVB-C/T FBC tuners because they need no special treatment fe_id = FESlotID(it); - snprintf(procFileName, sizeof(procFileName), "/proc/stb/frontend/%d/fbc_set_id", fe_id); - fbcSetID = getProcData(procFileName); - if (fbcSetID != -1) + tuner.set_id = ReadProcInt(fe_id, "fbc_set_id"); + + if(tuner.set_id >= 0) { - if (prevFbcSetID != fbcSetID) + if(fbc_prev_set_id != tuner.set_id) { - prevFbcSetID = fbcSetID; - memset(connect_choices, 0, sizeof(connect_choices)); - snprintf(procFileName, sizeof(procFileName), "/proc/stb/frontend/%d/fbc_connect_choices", fe_id); - loadConnectChoices(procFileName, connect_choices); - fbcIndex = 0; // reset + fbc_prev_set_id = tuner.set_id; + LoadConnectChoices(fe_id, tuner.connect_choices); + tuner.id = 0; } - isRoot = false; - if (fbcIndex < sizeof(connect_choices)/sizeof(connect_choices[0])) - { - isRoot = connect_choices[fbcIndex]; - } + if(tuner.id < (int)tuner.connect_choices.size()) + tuner.is_root = tuner.connect_choices.test(tuner.id); + else + tuner.is_root = false; - initFbcId = isRoot ? fbcIndex : 0; - FBC_TUNER elem = {fbcSetID, fbcIndex, isRoot, initFbcId}; - m_fbc_tuners[fe_id] = elem; + tuner.default_id = tuner.is_root ? tuner.id : 0; + m_tuners[fe_id] = tuner; /* set default fbc ID */ - SetProcFBCID(fe_id, initFbcId, false); + SetProcFBCID(fe_id, tuner.default_id, false); /* enable fbc tuner */ it->m_frontend->setFBCTuner(true); - fbcIndex++; + tuner.id++; } } for (eSmartPtrList::iterator it(frontends_simulate.begin()); it != frontends_simulate.end(); ++it) { // continue for DVB-C FBC Tuner + + it->m_frontend->setFBCTuner(false); // TODO TEST + if (!(it->m_frontend->supportsDeliverySystem(SYS_DVBS, false) || it->m_frontend->supportsDeliverySystem(SYS_DVBS2, false))) continue; - fe_id = FESlotID(it); - snprintf(procFileName, sizeof(procFileName), "/proc/stb/frontend/%d/fbc_set_id", fe_id); - fbcSetID = getProcData(procFileName); - if (fbcSetID != -1) - { - /* enable fbc tuner */ + if(ReadProcInt(FESlotID(it), "fbc_set_id") >= 0) it->m_frontend->setFBCTuner(true); - } } } eFBCTunerManager::~eFBCTunerManager() { - if (m_instance == this) - m_instance = 0; + if(m_instance == this) + m_instance = (eFBCTunerManager*)0; } -int eFBCTunerManager::SetProcFBCID(int fe_id, int fbc_connect, bool is_linked) +void eFBCTunerManager::SetProcFBCID(int fe_id, int fbc_connect, bool fbc_is_linked) { - eFecDebug("[*][eFBCTunerManager::SetProcFBCID] %d -> %d", fe_id, fbc_connect); - char filename[128]; + eTrace("[*][eFBCTunerManager::SetProcFBCID] %d -> %d", fe_id, fbc_connect); /* set root */ - sprintf(filename, "/proc/stb/frontend/%d/fbc_connect", fe_id); - setProcData(filename, fbc_connect); + WriteProcInt(fe_id, "fbc_connect", fbc_connect); /* set linked */ - sprintf(filename, "/proc/stb/frontend/%d/fbc_link", fe_id); - setProcData(filename, (int)is_linked); - - return 0; + WriteProcInt(fe_id, "fbc_link", fbc_is_linked ? 1 : 0); } - -int eFBCTunerManager::FESlotID(const eDVBRegisteredFrontend *fe) const +int eFBCTunerManager::FESlotID(eDVBRegisteredFrontend *fe) { return fe->m_frontend->getSlotID(); } -void eFBCTunerManager::SetDefaultFBCID(eDVBRegisteredFrontend *fe) +void eFBCTunerManager::SetDefaultFBCID(eDVBRegisteredFrontend *fe) const { int fe_id = FESlotID(fe); SetProcFBCID(fe_id, GetDefaultFBCID(fe_id), IsLinked(fe)); } -void eFBCTunerManager::UpdateFBCID(eDVBRegisteredFrontend *next_fe, eDVBRegisteredFrontend *prev_fe) +void eFBCTunerManager::UpdateFBCID(eDVBRegisteredFrontend *next_fe, eDVBRegisteredFrontend *prev_fe) const { SetProcFBCID(FESlotID(next_fe), GetFBCID(FESlotID(GetHead(prev_fe))), IsLinked(next_fe)); } -bool eFBCTunerManager::IsLinked(eDVBRegisteredFrontend *fe) const +bool eFBCTunerManager::IsLinked(eDVBRegisteredFrontend *fe) { - - long linked_prev_ptr = -1; - fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr); - return (linked_prev_ptr != -1); + return(!!(FrontendGetLinkPtr(fe, link_prev))); } -bool eFBCTunerManager::isUnicable(eDVBRegisteredFrontend *fe) const +bool eFBCTunerManager::isUnicable(eDVBRegisteredFrontend *fe) { + ePtr sec = eDVBSatelliteEquipmentControl::getInstance(); int slot_idx = FESlotID(fe); bool is_unicable = false; - ePtr sec = eDVBSatelliteEquipmentControl::getInstance(); for (int idx=0; idx <= sec->m_lnbidx; ++idx ) { eDVBSatelliteLNBParameters &lnb_param = sec->m_lnbs[idx]; @@ -230,87 +225,142 @@ bool eFBCTunerManager::IsFEUsed(eDVBRegisteredFrontend *fe, bool a_simulate) con bool simulate = !a_simulate; eSmartPtrList &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend; + for (eSmartPtrList::iterator it(frontends.begin()); it != frontends.end(); ++it) - { - if (FESlotID(it) == FESlotID(fe)) - { - return (it->m_inuse >0); - } - } + if (FESlotID(*it) == FESlotID(fe)) + return(it->m_inuse > 0); eDebug("[*][eFBCTunerManager::isFeUsed] ERROR! can not found fe ptr (feid : %d, simulate : %d)", FESlotID(fe), simulate); return false; } -bool eFBCTunerManager::IsSameFBCSet(int fe_a, int fe_b) +bool eFBCTunerManager::IsSameFBCSet(int fe_a, int fe_b) const { - return m_fbc_tuners[fe_a].fbcSetID == m_fbc_tuners[fe_b].fbcSetID; + tuners_t::const_iterator a, b; + + a = m_tuners.find(fe_a); + b = m_tuners.find(fe_b); + + if((a == m_tuners.end()) || (b == m_tuners.end())) + return(false); + + return(a->second.set_id == b->second.set_id); } -bool eFBCTunerManager::IsRootFE(eDVBRegisteredFrontend *fe) +bool eFBCTunerManager::IsRootFE(eDVBRegisteredFrontend *fe) const { - return m_fbc_tuners[FESlotID(fe)].isRoot; + tuners_t::const_iterator a; + + if((a = m_tuners.find(FESlotID(fe))) == m_tuners.end()) + return(false); + + return a->second.is_root; } -int eFBCTunerManager::GetFBCID(int fe_id) +int eFBCTunerManager::GetFBCID(int fe_id) const { - return m_fbc_tuners[fe_id].fbcIndex; + tuners_t::const_iterator a; + + if((a = m_tuners.find(fe_id)) == m_tuners.end()) + return(-1); + + return a->second.id; } -int eFBCTunerManager::GetDefaultFBCID(int fe_id) +int eFBCTunerManager::GetDefaultFBCID(int fe_id) const { - return m_fbc_tuners[fe_id].initFbcId; + tuners_t::const_iterator a; + + if((a = m_tuners.find(fe_id)) == m_tuners.end()) + return(-1); + + return a->second.default_id; } -int eFBCTunerManager::getFBCSetID(int fe_id) +int eFBCTunerManager::GetFBCSetID(int fe_id) const { - return m_fbc_tuners[fe_id].fbcSetID; + tuners_t::const_iterator a; + + if((a = m_tuners.find(fe_id)) == m_tuners.end()) + return(-1); + + return(a->second.set_id); } -eDVBRegisteredFrontend *eFBCTunerManager::getPrev(eDVBRegisteredFrontend *fe) const +eDVBRegisteredFrontend *eFBCTunerManager::GetFEPtr(long link) { - eDVBRegisteredFrontend *prev_fe = NULL; - long linked_prev_ptr = -1; - fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr); - if (linked_prev_ptr != -1) - prev_fe = (eDVBRegisteredFrontend *)linked_prev_ptr; - return prev_fe; + if(link == -1) + link = 0; + + return((eDVBRegisteredFrontend *)link); } -eDVBRegisteredFrontend *eFBCTunerManager::getNext(eDVBRegisteredFrontend *fe) const +long eFBCTunerManager::GetFELink(eDVBRegisteredFrontend *ptr) { - eDVBRegisteredFrontend *next_fe = NULL; - long linked_next_ptr = -1; - fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr); - if (linked_next_ptr != -1) - next_fe = (eDVBRegisteredFrontend *)linked_next_ptr; - return next_fe; + long link = (long)ptr; + + if(link == 0) + link = -1; + + return(link); } -eDVBRegisteredFrontend *eFBCTunerManager::GetHead(eDVBRegisteredFrontend *fe) const +eDVBRegisteredFrontend *eFBCTunerManager::FrontendGetLinkPtr(eDVBFrontend *fe, link_ptr_t link_type) { - eDVBRegisteredFrontend *prev_fe = fe; - long linked_prev_ptr = -1; - fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr); - while(linked_prev_ptr != -1) + int data_type; + long data; + + switch(link_type) { - prev_fe = (eDVBRegisteredFrontend *)linked_prev_ptr; - prev_fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr); + case(link_prev): data_type = eDVBFrontend::LINKED_PREV_PTR; break; + case(link_next): data_type = eDVBFrontend::LINKED_NEXT_PTR; break; + default: return(GetFEPtr(-1)); } - return prev_fe; + + if(fe->getData(data_type, data)) // returns != 0 on error + data = -1; + + return(GetFEPtr(data)); } -eDVBRegisteredFrontend *eFBCTunerManager::GetTail(eDVBRegisteredFrontend *fe) const + +eDVBRegisteredFrontend *eFBCTunerManager::FrontendGetLinkPtr(eDVBRegisteredFrontend *fe, link_ptr_t link_type) { - eDVBRegisteredFrontend *next_fe = fe; - long linked_next_ptr = -1; - fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr); - while(linked_next_ptr != -1) + return(FrontendGetLinkPtr(fe->m_frontend, link_type)); +} + +void eFBCTunerManager::FrontendSetLinkPtr(eDVBRegisteredFrontend *fe, link_ptr_t link_type, eDVBRegisteredFrontend *ptr) +{ + int data_type; + + switch(link_type) { - next_fe = (eDVBRegisteredFrontend *)linked_next_ptr; - next_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr); + case(link_prev): data_type = eDVBFrontend::LINKED_PREV_PTR; break; + case(link_next): data_type = eDVBFrontend::LINKED_NEXT_PTR; break; + default: return; } - return next_fe; + + fe->m_frontend->setData(data_type, GetFELink(ptr)); +} + +eDVBRegisteredFrontend *eFBCTunerManager::GetHead(eDVBRegisteredFrontend *fe) +{ + eDVBRegisteredFrontend *prev_fe; + + while((prev_fe = FrontendGetLinkPtr(fe, link_prev))) + fe = prev_fe; + + return(fe); +} + +eDVBRegisteredFrontend *eFBCTunerManager::GetTail(eDVBRegisteredFrontend *fe) +{ + eDVBRegisteredFrontend *next_fe; + + while((next_fe = FrontendGetLinkPtr(fe, link_next))) + fe = next_fe; + + return(fe); } eDVBRegisteredFrontend *eFBCTunerManager::GetSimulFE(eDVBRegisteredFrontend *fe) const @@ -324,49 +374,44 @@ eDVBRegisteredFrontend *eFBCTunerManager::GetSimulFE(eDVBRegisteredFrontend *fe) return((eDVBRegisteredFrontend *)0); } -void eFBCTunerManager::ConnectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, eDVBRegisteredFrontend *next_fe, bool simulate) +void eFBCTunerManager::ConnectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, eDVBRegisteredFrontend *next_fe, bool simulate) const { if (next_fe) - eFecDebug(" [*][eFBCTunerManager::connectLink] connect %d->%d->%d %s", FESlotID(prev_fe), FESlotID(link_fe), FESlotID(next_fe), simulate?"(simulate)":""); + eTrace(" [*][eFBCTunerManager::connectLink] connect %d->%d->%d %s", FESlotID(prev_fe), FESlotID(link_fe), FESlotID(next_fe), simulate?"(simulate)":""); else - eFecDebug(" [*][eFBCTunerManager::connectLink] connect %d->%d %s", FESlotID(prev_fe), FESlotID(link_fe), simulate?"(simulate)":""); + eTrace(" [*][eFBCTunerManager::connectLink] connect %d->%d %s", FESlotID(prev_fe), FESlotID(link_fe), simulate?"(simulate)":""); + + FrontendSetLinkPtr(prev_fe, link_next, link_fe); + FrontendSetLinkPtr(link_fe, link_prev, prev_fe); + FrontendSetLinkPtr(link_fe, link_next, next_fe); - prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)link_fe); - link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe); if (next_fe) - { - link_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)next_fe); - next_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)link_fe); - } + FrontendSetLinkPtr(next_fe, link_prev, link_fe); } -void eFBCTunerManager::DisconnectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, eDVBRegisteredFrontend *next_fe, bool simulate) +void eFBCTunerManager::DisconnectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, eDVBRegisteredFrontend *next_fe, bool simulate) const { if (next_fe) - eFecDebug(" [*][eFBCTunerManager::DisconnectLink] disconnect %d->%d->%d %s", FESlotID(prev_fe), FESlotID(link_fe), FESlotID(next_fe), simulate?"(simulate)":""); + eTrace(" [*][eFBCTunerManager::DisconnectLink] disconnect %d->%d->%d %s", FESlotID(prev_fe), FESlotID(link_fe), FESlotID(next_fe), simulate?"(simulate)":""); else - eFecDebug(" [*][eFBCTunerManager::DisconnectLink] disconnect %d->%d %s", FESlotID(prev_fe), FESlotID(link_fe), simulate?"(simulate)":""); + eTrace(" [*][eFBCTunerManager::DisconnectLink] disconnect %d->%d %s", FESlotID(prev_fe), FESlotID(link_fe), simulate?"(simulate)":""); - if (next_fe) - { - prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)next_fe); - next_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe); + FrontendSetLinkPtr(link_fe, link_prev, (eDVBRegisteredFrontend *)0); + FrontendSetLinkPtr(link_fe, link_next, (eDVBRegisteredFrontend *)0); + FrontendSetLinkPtr(prev_fe, link_next, next_fe); - link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)-1); - link_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)-1); - } - else - { - prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)-1); - link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)-1); - } + if (next_fe) + FrontendSetLinkPtr(next_fe, link_prev, prev_fe); } -int eFBCTunerManager::IsCompatibleWith(ePtr &feparm, eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *&fbc_fe, bool simulate) +int eFBCTunerManager::IsCompatibleWith(ePtr &feparm, eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *&fbc_fe, bool simulate) const { - int best_score = 0; - eSmartPtrList &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend; + eDVBRegisteredFrontend *fe_insert_point; + int best_score, new_score; + + best_score = 0; + for (eSmartPtrList::iterator it(frontends.begin()); it != frontends.end(); ++it) { if (!it->m_frontend->is_FBCTuner()) @@ -390,11 +435,13 @@ int eFBCTunerManager::IsCompatibleWith(ePtr &feparm, eDV if(isUnicable(*it)) continue; - eDVBRegisteredFrontend *top_fe = *it; - eDVBRegisteredFrontend *prev_fe = GetTail(top_fe); + // temporarily add this leaf to the current "linked" chain, at the tail + + fe_insert_point = GetTail(*it); + /* connect link */ - ConnectLink(link_fe, prev_fe, NULL, simulate); + ConnectLink(link_fe, /*prev_fe*/fe_insert_point, /*next_fe*/(eDVBRegisteredFrontend *)0, simulate); /* enable linked fe */ link_fe->m_frontend->setEnabled(true); @@ -403,285 +450,276 @@ int eFBCTunerManager::IsCompatibleWith(ePtr &feparm, eDV UpdateLNBSlotMask(FESlotID(link_fe), FESlotID(*it), false); /* get score */ - int c = link_fe->m_frontend->isCompatibleWith(feparm); - if (c > best_score) + new_score = link_fe->m_frontend->isCompatibleWith(feparm); + if (new_score > best_score) { - best_score = c; - fbc_fe = (eDVBRegisteredFrontend *)*it; + best_score = new_score; + fbc_fe = *it; } - eFecDebug("[*][eFBCTunerManager::isCompatibleWith] score : %d (%d->%d)", c, FESlotID(it), FESlotID(link_fe)); + eTrace("[*][eFBCTunerManager::isCompatibleWith] score : %d (%d->%d)", new_score, FESlotID(it), FESlotID(link_fe)); - ASSERT(!getNext(link_fe)); - ASSERT(getPrev(link_fe)); - ASSERT(GetTail(top_fe) == link_fe); /* disconnect link */ - DisconnectLink(link_fe, prev_fe, NULL, simulate); + DisconnectLink(link_fe, /*prev_fe*/fe_insert_point, /*next_fe*/(eDVBRegisteredFrontend *)0, simulate); /* disable linked fe */ link_fe->m_frontend->setEnabled(false); /* remove slot mask*/ - UpdateLNBSlotMask(FESlotID(link_fe), FESlotID(top_fe), true); + UpdateLNBSlotMask(FESlotID(link_fe), FESlotID(*it), true); } - eFecDebug("[*][eFBCTunerManager::isCompatibleWith] fe : %p(%d), score : %d %s", link_fe, FESlotID(link_fe), best_score, simulate?"(simulate)":""); + eTrace("[*][eFBCTunerManager::isCompatibleWith] fe : %p(%d), score : %d %s", link_fe, FESlotID(link_fe), best_score, simulate?"(simulate)":""); return best_score; } /* attach link_fe to tail of fe linked list */ -void eFBCTunerManager::AddLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *top_fe, bool simulate) +void eFBCTunerManager::AddLink(eDVBRegisteredFrontend *leaf, eDVBRegisteredFrontend *root, bool simulate) const { + eDVBRegisteredFrontend *leaf_insert_after, *leaf_insert_before, *leaf_current, *leaf_next; + //PrintLinks(link_fe); - eFecDebug(" [*][eFBCTunerManager::addLink] addLink : %p(%d)->%p(%d) %s", top_fe, FESlotID(top_fe), link_fe, FESlotID(link_fe), simulate?"(simulate)":""); + eTrace(" [*][eFBCTunerManager::addLink] (leaf: %d, link to top fe: %d, simulate: %d", FESlotID(leaf), FESlotID(root), simulate); + - eDVBRegisteredFrontend *next_fe = NULL; - eDVBRegisteredFrontend *prev_fe = NULL; - if(IsRootFE(link_fe) || !IsRootFE(top_fe)) + if(IsRootFE(leaf) || !IsRootFE(root)) return; - /* search prev/next fe */ - next_fe = top_fe; - while(true) + + // find the entry where to insert the leaf, it must be between slotid(leaf)-1 and slotid(leaf)+1 + + leaf_next = (eDVBRegisteredFrontend *)0; + leaf_insert_after = (eDVBRegisteredFrontend *)0; + leaf_insert_before = (eDVBRegisteredFrontend *)0; + + for(leaf_current = root; leaf_current; leaf_current = leaf_next) { - prev_fe = next_fe; - next_fe = getNext(prev_fe); - if ((next_fe == NULL) || (FESlotID(next_fe) > FESlotID(link_fe))) + leaf_next = FrontendGetLinkPtr(leaf_current, link_next); + + leaf_insert_after = leaf_current; + leaf_insert_before = leaf_next; + + if(leaf_next && (FESlotID(leaf_next) > FESlotID(leaf))) break; } + /* connect */ - ConnectLink(link_fe, prev_fe, next_fe, simulate); + ConnectLink(leaf, leaf_insert_after, leaf_insert_before, simulate); /* enable linked fe */ - link_fe->m_frontend->setEnabled(true); + leaf->m_frontend->setEnabled(true); /* simulate connect */ if (!simulate) { - eDVBRegisteredFrontend *simulate_prev_fe = NULL; - eDVBRegisteredFrontend *simulate_link_fe = NULL; - eDVBRegisteredFrontend *simulate_next_fe = NULL; + eDVBRegisteredFrontend *simul_root, *simul_leaf; + + simul_root = GetSimulFE(root); + simul_leaf = GetSimulFE(leaf); + + if(IsRootFE(simul_root)) + { + leaf_insert_after = (eDVBRegisteredFrontend *)0; + leaf_insert_before = (eDVBRegisteredFrontend *)0; + + for(leaf_current = simul_root; leaf_current; leaf_current = leaf_next) + { + leaf_next = FrontendGetLinkPtr(leaf_current, link_next); - simulate_prev_fe = GetSimulFE(prev_fe); - simulate_link_fe = GetSimulFE(link_fe); + leaf_insert_after = leaf_current; + leaf_insert_before = leaf_next; - if (next_fe) - simulate_next_fe = GetSimulFE(next_fe); + if(leaf_next && (FESlotID(leaf_next) > FESlotID(leaf))) + break; + } + + eTrace(" [*][eFBCTunerManager::addLink] simulate fe : %p -> %p -> %p", leaf_insert_after, simul_leaf, leaf_insert_before); - eFecDebug(" [*][eFBCTunerManager::addLink] simulate fe : %p -> %p -> %p", simulate_prev_fe, simulate_link_fe, simulate_next_fe); - ConnectLink(simulate_link_fe, simulate_prev_fe, simulate_next_fe, !simulate); + ConnectLink(simul_leaf, leaf_insert_after, leaf_insert_before, true); - /* enable simulate linked fe */ - simulate_link_fe->m_frontend->setEnabled(true); + /* enable simulate linked fe */ + simul_leaf->m_frontend->setEnabled(true); + } } /* set proc fbc_id */ if (!simulate) - SetProcFBCID(FESlotID(link_fe), GetFBCID(FESlotID(top_fe)), IsLinked(link_fe)); + SetProcFBCID(FESlotID(leaf), GetFBCID(FESlotID(root)), IsLinked(leaf)); /* add slot mask*/ - UpdateLNBSlotMask(FESlotID(link_fe), FESlotID(top_fe), false); + UpdateLNBSlotMask(FESlotID(leaf), FESlotID(root), false); //PrintLinks(link_fe); } /* if fe, fe_simulated is unused, unlink current frontend from linked things. */ /* all unused linked fbc fe must be unlinked! */ -void eFBCTunerManager::Unlink(eDVBRegisteredFrontend *link_fe) +void eFBCTunerManager::Unlink(eDVBRegisteredFrontend *fe) const { - bool simulate = link_fe->m_frontend->is_simulate(); - eFecDebug(" [*][eFBCTunerManager::unLink] fe id : %p(%d) %s", link_fe, FESlotID(link_fe), simulate?"(simulate)":""); + eDVBRegisteredFrontend *simul_fe; + bool simulate = fe->m_frontend->is_simulate(); + eTrace(" [*][eFBCTunerManager::unLink] fe id : %p(%d) %s", fe, FESlotID(fe), simulate?"(simulate)":""); - if (IsRootFE(link_fe) || IsFEUsed(link_fe, simulate) || isUnicable(link_fe) || !IsLinked(link_fe)) + if (IsRootFE(fe) || IsFEUsed(fe, simulate) || isUnicable(fe) || !IsLinked(fe)) { - eFecDebug(" [*][eFBCTunerManager::unLink] skip.."); + eTrace(" [*][eFBCTunerManager::unLink] skip.."); return; } //PrintLinks(link_fe); - eDVBRegisteredFrontend *prev_fe = getPrev(link_fe); - eDVBRegisteredFrontend *next_fe = getNext(link_fe); - - ASSERT(prev_fe); - - DisconnectLink(link_fe, prev_fe, next_fe, simulate); + DisconnectLink(fe, FrontendGetLinkPtr(fe, link_prev), FrontendGetLinkPtr(fe, link_next), simulate); /* disable linked fe */ - link_fe->m_frontend->setEnabled(false); + fe->m_frontend->setEnabled(false); /* simulate disconnect */ if (!simulate) { - eDVBRegisteredFrontend *simulate_prev_fe = NULL; - eDVBRegisteredFrontend *simulate_link_fe = NULL; - eDVBRegisteredFrontend *simulate_next_fe = NULL; - - simulate_prev_fe = GetSimulFE(prev_fe); - simulate_link_fe = GetSimulFE(link_fe); - - if (next_fe) - simulate_next_fe = GetSimulFE(next_fe); + if((simul_fe = GetSimulFE(fe)) && !IsRootFE(simul_fe) && !IsFEUsed(simul_fe, true) && + !isUnicable(simul_fe) && IsLinked(simul_fe)) + { + DisconnectLink(simul_fe, FrontendGetLinkPtr(simul_fe, link_prev), FrontendGetLinkPtr(simul_fe, link_next), true); + /* enable simulate linked fe */ + simul_fe->m_frontend->setEnabled(false); - DisconnectLink(simulate_link_fe, simulate_prev_fe, simulate_next_fe, !simulate); + } - /* enable simulate linked fe */ - simulate_link_fe->m_frontend->setEnabled(false); } /* set default proc fbc_id */ //SetDefaultFBCID(link_fe); /* remove slot mask*/ - UpdateLNBSlotMask(FESlotID(link_fe), FESlotID(GetHead(prev_fe)), true); + UpdateLNBSlotMask(FESlotID(fe), FESlotID(GetHead(fe)), true); //PrintLinks(link_fe); } -int eFBCTunerManager::UpdateLNBSlotMask(int dest_slot, int src_slot, bool remove) +void eFBCTunerManager::UpdateLNBSlotMask(int dest_slot, int src_slot, bool remove) { ePtr sec = eDVBSatelliteEquipmentControl::getInstance(); + int idx, sec_lnbidx; - int sec_lnbidx = sec->m_lnbidx; + sec_lnbidx = sec->m_lnbidx; int found = 0; - for (int idx=0; idx <= sec_lnbidx; ++idx ) + for (idx=0; idx <= sec_lnbidx; ++idx ) { eDVBSatelliteLNBParameters &lnb_param = sec->m_lnbs[idx]; if ( lnb_param.m_slot_mask & (1 << src_slot) ) { - eFecDebug("[*][eFBCTunerManager::UpdateLNBSlotMask] m_slot_mask : %d", lnb_param.m_slot_mask); + eTrace("[*][eFBCTunerManager::UpdateLNBSlotMask] m_slot_mask : %d", lnb_param.m_slot_mask); - if (!remove) - lnb_param.m_slot_mask |= (1 << dest_slot); - else + if (remove) lnb_param.m_slot_mask &= ~(1 << dest_slot); + else + lnb_param.m_slot_mask |= (1 << dest_slot); - eFecDebug("[*][eFBCTunerManager::UpdateLNBSlotMask] changed m_slot_mask : %d", lnb_param.m_slot_mask); + eTrace("[*][eFBCTunerManager::UpdateLNBSlotMask] changed m_slot_mask : %d", lnb_param.m_slot_mask); found = 1; } } if (!found) - eFecDebug("[*][eFBCTunerManager::UpdateLNBSlotMask] src %d not found", src_slot); + eTrace("[*][eFBCTunerManager::UpdateLNBSlotMask] src %d not found", src_slot); - return 0; } -bool eFBCTunerManager::CanLink(eDVBRegisteredFrontend *fe) +bool eFBCTunerManager::CanLink(eDVBRegisteredFrontend *fe) const { - return !(IsRootFE(fe) || getPrev(fe) || getNext(fe) || isUnicable(fe)); + if(IsRootFE(fe)) + return false; + + if(FrontendGetLinkPtr(fe, link_prev) || FrontendGetLinkPtr(fe, link_next)) + return false; + + if(isUnicable(fe)) + return false; + + return true; } int eFBCTunerManager::getLinkedSlotID(int fe_id) const { int link = -1; + eDVBRegisteredFrontend *prev_fe; eSmartPtrList &frontends = m_res_mgr->m_frontend; - for (eSmartPtrList::iterator it(frontends.begin()); it != frontends.end(); ++it) - { - if(it->m_frontend->getSlotID() == fe_id) - { - long prev_ptr = -1; - it->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, prev_ptr); - if (prev_ptr != -1) - { - eDVBRegisteredFrontend *prev_fe = (eDVBRegisteredFrontend *)prev_ptr; - link = FESlotID(prev_fe); - } + for (eSmartPtrList::iterator it(frontends.begin()); it != frontends.end(); ++it) { + if((it->m_frontend->getSlotID() == fe_id) && ((prev_fe = FrontendGetLinkPtr(it, link_prev)))) { + + link = FESlotID(prev_fe); break; } } - eFecDebug(" [*][eFBCTunerManager::getLinkedSlotID] fe_id : %d, link : %d", fe_id, link); + eTrace(" [*][eFBCTunerManager::getLinkedSlotID] fe_id : %d, link : %d", fe_id, link); return link; } -bool eFBCTunerManager::IsFBCLink(int fe_id) +bool eFBCTunerManager::IsFBCLink(int fe_id) const { - bool res = false; - std::map::iterator it = m_fbc_tuners.find(fe_id); - if (it != m_fbc_tuners.end()) - { - res = !it->second.isRoot; - } - return res; + std::map::const_iterator it; + + if((it = m_tuners.find(fe_id)) == m_tuners.end()) + return(false); + + return(!it->second.is_root); } void eFBCTunerManager::PrintLinks(eDVBRegisteredFrontend *fe) const { - long linked_prev_ptr = -1; - eDVBRegisteredFrontend *linked_prev_fe = fe; - fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr); - while (linked_prev_ptr != -1) - { - linked_prev_fe = (eDVBRegisteredFrontend*) linked_prev_ptr; - linked_prev_fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, (long&)linked_prev_ptr); - } - - long linked_next_ptr = -1; - eDVBRegisteredFrontend *linked_next_fe = linked_prev_fe; - eFecDebug(" [*][eFBCTunerManager::printLinks] fe id : %d (%p), inuse : %d, enabled : %d, fbc : %d", FESlotID(linked_next_fe), linked_next_fe, linked_next_fe->m_inuse, linked_next_fe->m_frontend->getEnabled(), linked_next_fe->m_frontend->is_FBCTuner()); - linked_prev_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr); - while (linked_next_ptr != -1) - { - linked_next_fe = (eDVBRegisteredFrontend*) linked_next_ptr; - eFecDebug(" [*][eFBCTunerManager::printLinks] fe id : %d (%p), inuse : %d, enabled : %d, fbc : %d", FESlotID(linked_next_fe), linked_next_fe, linked_next_fe->m_inuse, linked_next_fe->m_frontend->getEnabled(), linked_next_fe->m_frontend->is_FBCTuner()); - linked_next_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, (long&)linked_next_ptr); - } eSmartPtrList &frontends = m_res_mgr->m_frontend; + eSmartPtrList &simulate_frontends = m_res_mgr->m_simulate_frontend; + + eDVBRegisteredFrontend *current_fe, *prev_ptr, *next_ptr; + int prev, next; + + current_fe = GetHead(fe); + + + eTrace(" [*][eFBCTunerManager::printLinks] fe id : %d (%p), inuse : %d, enabled : %d, fbc : %d", FESlotID(current_fe), current_fe, current_fe->m_inuse, current_fe->m_frontend->getEnabled(), current_fe->m_frontend->is_FBCTuner()); + + while ((current_fe = FrontendGetLinkPtr(current_fe, link_next))) + eTrace(" [*][eFBCTunerManager::printLinks] fe id : %d (%p), inuse : %d, enabled : %d, fbc : %d", FESlotID(current_fe), current_fe, current_fe->m_inuse, current_fe->m_frontend->getEnabled(), current_fe->m_frontend->is_FBCTuner()); + + for (eSmartPtrList::iterator it(frontends.begin()); it != frontends.end(); ++it) { - [[maybe_unused]] int prev = -1; - [[maybe_unused]] int next = -1; - long prev_ptr = -1; - long next_ptr = -1; - it->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, prev_ptr); - it->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, next_ptr); - if (prev_ptr != -1) - { - eDVBRegisteredFrontend *prev_fe = (eDVBRegisteredFrontend *)prev_ptr; - prev = FESlotID(prev_fe); - } + if ((prev_ptr = FrontendGetLinkPtr(&*it->m_frontend, link_prev))) + prev = FESlotID(prev_ptr); + else + prev = -1; - if (next_ptr != -1) - { - eDVBRegisteredFrontend *next_fe = (eDVBRegisteredFrontend *)next_ptr; - next = FESlotID(next_fe); - } - - eFecDebug(" [*][eFBCTunerManager::printLinks] fe_id : %2d, inuse : %d, enabled : %d, fbc : %d, prev : %2d, cur : %2d, next : %2d", FESlotID(it), it->m_inuse, it->m_frontend->getEnabled(), it->m_frontend->is_FBCTuner(), prev, FESlotID(it), next); + if ((next_ptr = FrontendGetLinkPtr(&*it->m_frontend, link_next))) + next = FESlotID(next_ptr); + else + next = -1; + + eTrace(" [*][eFBCTunerManager::printLinks] fe_id : %2d, inuse : %d, enabled : %d, fbc : %d, prev : %2d, cur : %2d, next : %2d", FESlotID(it), it->m_inuse, it->m_frontend->getEnabled(), it->m_frontend->is_FBCTuner(), prev, FESlotID(it), next); } - eSmartPtrList &simulate_frontends = m_res_mgr->m_simulate_frontend; for (eSmartPtrList::iterator it(simulate_frontends.begin()); it != simulate_frontends.end(); ++it) { - [[maybe_unused]] int prev = -1; - [[maybe_unused]] int next = -1; - long prev_ptr = -1; - long next_ptr = -1; - it->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, prev_ptr); - it->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, next_ptr); - if (prev_ptr != -1) - { - eDVBRegisteredFrontend *prev_fe = (eDVBRegisteredFrontend *)prev_ptr; - prev = FESlotID(prev_fe); - } + if ((prev_ptr = FrontendGetLinkPtr(&*it->m_frontend, link_prev))) + prev = FESlotID(prev_ptr); + else + prev = -1; - if (next_ptr != -1) - { - eDVBRegisteredFrontend *next_fe = (eDVBRegisteredFrontend *)next_ptr; - next = FESlotID(next_fe); - } - - eFecDebug(" [*][eFBCTunerManager::printLinks] fe_id : %2d, inuse : %d, enabled : %d, fbc : %d, prev : %2d, cur : %2d, next : %2d (simulate)", FESlotID(it), it->m_inuse, it->m_frontend->getEnabled(), it->m_frontend->is_FBCTuner(), prev, FESlotID(it), next); + if ((next_ptr = FrontendGetLinkPtr(&*it->m_frontend, link_next))) + next = FESlotID(next_ptr); + else + next = -1; + + eTrace(" [*][eFBCTunerManager::printLinks] fe_id : %2d, inuse : %d, enabled : %d, fbc : %d, prev : %2d, cur : %2d, next : %2d (simulate)", FESlotID(it), it->m_inuse, it->m_frontend->getEnabled(), it->m_frontend->is_FBCTuner(), prev, FESlotID(it), next); } } diff --git a/lib/dvb/fbc.h b/lib/dvb/fbc.h index 9630111714c..1f5694921d2 100644 --- a/lib/dvb/fbc.h +++ b/lib/dvb/fbc.h @@ -7,61 +7,79 @@ #include #include #include +#include class eDVBResourceManager; +class eDVBFrontend; class eDVBRegisteredFrontend; -typedef struct fbc_tuner -{ - int fbcSetID; - unsigned int fbcIndex; - bool isRoot; - int initFbcId; -}FBC_TUNER; - - class eFBCTunerManager: public iObject, public sigc::trackable { private: + typedef std::bitset<8> connect_choices_t; + + typedef struct + { + int set_id; + bool is_root; + int id; + int default_id; + connect_choices_t connect_choices; + } tuner_t; + + typedef std::map tuners_t; + + typedef enum + { + link_prev, + link_next + } link_ptr_t; + DECLARE_REF(eFBCTunerManager); ePtr m_res_mgr; - static eFBCTunerManager *m_instance; - std::map m_fbc_tuners; + static eFBCTunerManager* m_instance; + tuners_t m_tuners; - int SetProcFBCID(int fe_id, int root_idx, bool is_linked); - int FESlotID(const eDVBRegisteredFrontend *fe) const; - bool IsLinked(eDVBRegisteredFrontend *fe) const; - bool isUnicable(eDVBRegisteredFrontend *fe) const; - bool IsFEUsed(eDVBRegisteredFrontend *fe, bool a_simulate) const; - bool IsSameFBCSet(int fe_id_a, int fe_id_b); - bool IsRootFE(eDVBRegisteredFrontend *fe); - int GetFBCID(int fe_id); - int GetDefaultFBCID(int fe_id); + static int ReadProcInt(int, const std::string &); + static void WriteProcInt(int, const std::string &, int); + static void LoadConnectChoices(int, connect_choices_t &); + static void SetProcFBCID(int, int, bool); + static int FESlotID(eDVBRegisteredFrontend *); + static bool IsLinked(eDVBRegisteredFrontend *); + static bool isUnicable(eDVBRegisteredFrontend *fe); + static eDVBRegisteredFrontend* FrontendGetLinkPtr(eDVBFrontend *, link_ptr_t); + static eDVBRegisteredFrontend* FrontendGetLinkPtr(eDVBRegisteredFrontend *, link_ptr_t); + static void FrontendSetLinkPtr(eDVBRegisteredFrontend *, link_ptr_t, eDVBRegisteredFrontend *); + static eDVBRegisteredFrontend *GetFEPtr(long); + static long GetFELink(eDVBRegisteredFrontend *ptr); + static eDVBRegisteredFrontend *GetHead(eDVBRegisteredFrontend *); + static eDVBRegisteredFrontend *GetTail(eDVBRegisteredFrontend *); + static void UpdateLNBSlotMask(int, int, bool); + bool IsSameFBCSet(int, int) const; + bool IsRootFE(eDVBRegisteredFrontend *) const; + bool IsFEUsed(eDVBRegisteredFrontend *, bool) const; + int GetFBCID(int) const; + int GetDefaultFBCID(int) const; - eDVBRegisteredFrontend *getPrev(eDVBRegisteredFrontend *fe) const; - eDVBRegisteredFrontend *getNext(eDVBRegisteredFrontend *fe) const; - eDVBRegisteredFrontend *GetHead(eDVBRegisteredFrontend *fe) const; - eDVBRegisteredFrontend *GetTail(eDVBRegisteredFrontend *fe) const; - eDVBRegisteredFrontend *GetSimulFE(eDVBRegisteredFrontend *fe) const; + eDVBRegisteredFrontend *GetSimulFE(eDVBRegisteredFrontend *) const; - void ConnectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, eDVBRegisteredFrontend *next_fe, bool simulate); - void DisconnectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, eDVBRegisteredFrontend *next_fe, bool simulate); - int UpdateLNBSlotMask(int dest_slot, int src_slot, bool remove); + void ConnectLink(eDVBRegisteredFrontend *, eDVBRegisteredFrontend *, eDVBRegisteredFrontend *, bool) const; + void DisconnectLink(eDVBRegisteredFrontend *, eDVBRegisteredFrontend *, eDVBRegisteredFrontend *, bool) const; void PrintLinks(eDVBRegisteredFrontend *fe) const; public: static eFBCTunerManager* getInstance(); eFBCTunerManager(ePtr res_mgr); virtual ~eFBCTunerManager(); - void SetDefaultFBCID(eDVBRegisteredFrontend *fe); - void UpdateFBCID(eDVBRegisteredFrontend *next_fe, eDVBRegisteredFrontend *prev_fe); - int IsCompatibleWith(ePtr &feparm, eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *&fbc_fe, bool simulate); - void AddLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *top_fe, bool simulate); - void Unlink(eDVBRegisteredFrontend *link_fe); - bool CanLink(eDVBRegisteredFrontend *fe); + int GetFBCSetID(int) const; int getLinkedSlotID(int feid) const; - int getFBCSetID(int fe_id); - bool IsFBCLink(int fe_id); + void SetDefaultFBCID(eDVBRegisteredFrontend *) const; + void UpdateFBCID(eDVBRegisteredFrontend *, eDVBRegisteredFrontend *) const; + int IsCompatibleWith(ePtr &, eDVBRegisteredFrontend *, eDVBRegisteredFrontend *&, bool) const; + bool CanLink(eDVBRegisteredFrontend *) const; + void AddLink(eDVBRegisteredFrontend *, eDVBRegisteredFrontend *, bool) const; + void Unlink(eDVBRegisteredFrontend *) const; + bool IsFBCLink(int fe_id) const; }; #endif /* __dvb_fbc_h */ diff --git a/lib/dvb/fcc.cpp b/lib/dvb/fcc.cpp index 5583ec40eac..4c526135818 100644 --- a/lib/dvb/fcc.cpp +++ b/lib/dvb/fcc.cpp @@ -293,8 +293,8 @@ PyObject *eFCCServiceManager::getFCCServiceList() for (;it != m_FCCServices.end();++it) { ePyObject tplist = PyList_New(0); - PyList_Append(tplist, PyInt_FromLong((long)it->second.m_state)); - PyList_Append(tplist, PyInt_FromLong((long)isLocked(it->first))); + PyList_Append(tplist, PyLong_FromLong((long)it->second.m_state)); + PyList_Append(tplist, PyLong_FromLong((long)isLocked(it->first))); PyDict_SetItemString(dest, it->second.m_service_reference.toString().c_str(), tplist); Py_DECREF(tplist); } diff --git a/lib/dvb/frontend.cpp b/lib/dvb/frontend.cpp index 12171a9f122..9d007171ecf 100644 --- a/lib/dvb/frontend.cpp +++ b/lib/dvb/frontend.cpp @@ -195,7 +195,7 @@ void eDVBFrontendParametersCable::set(const CableDeliverySystemDescriptor &descr modulation = Modulation_Auto; inversion = Inversion_Unknown; system = System_DVB_C_ANNEX_A; - eDebug("[eDVBFrontendParametersSatellite] Cable freq %d, mod %d, sr %d, fec %d", + eDebug("[eDVBFrontendParametersCable] Cable freq %d, mod %d, sr %d, fec %d", frequency, modulation, symbol_rate, fec_inner); } @@ -3078,7 +3078,7 @@ RESULT eDVBFrontend::prepare_cable(const eDVBFrontendParametersCable &feparm) return -ENOENT; } m_data[FREQ_OFFSET] = 0; - eDebugNoSimulate("frontend %d tuning dvb-c to %d khz, sr %d, fec %d, modulation %d, inversion %d", + eDebugNoSimulate("[eDVBFrontend%d] tuning dvb-c to %d khz, sr %d, fec %d, modulation %d, inversion %d", m_dvbid, feparm.frequency, feparm.symbol_rate, @@ -3138,7 +3138,7 @@ RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where, bool blindscan) { unsigned int timeout = 5000; int type; - eDebugNoSimulate("tune tuner %d", m_dvbid); + eDebugNoSimulate("[eDVBFrontend%d] tune", m_dvbid); m_timeout->stop(); @@ -3152,7 +3152,7 @@ RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where, bool blindscan) if (!m_sn && !m_simulate) { - eDebug("no frontend device opened... do not try to tune !!!"); + eDebug("[eDVBFrontend] no frontend device opened... do not try to tune !!!"); res = -ENODEV; goto tune_error; } @@ -3272,7 +3272,7 @@ RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where, bool blindscan) eDVBFrontendParametersSatellite feparm; if (where.getDVBS(feparm)) { - eDebug("no dvbs data!"); + eDebug("[eDVBFrontend%d] no dvbs data!", m_dvbid); res = -EINVAL; goto tune_error; } @@ -3286,7 +3286,7 @@ RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where, bool blindscan) sec_fe = linked_fe->m_frontend; sec_fe->getData(LINKED_NEXT_PTR, tmp); } - eDebug("(fe%d) reset diseqc after leave rotor mode!", m_dvbid); + eDebug("[eDVBFrontend%d] reset diseqc after leave rotor mode!", m_dvbid); sec_fe->m_data[CSW] = sec_fe->m_data[UCSW] = sec_fe->m_data[TONEBURST] = sec_fe->m_data[ROTOR_CMD] = sec_fe->m_data[ROTOR_POS] = -1; // reset diseqc } m_rotor_mode = feparm.no_rotor_command_on_tune; @@ -3445,13 +3445,13 @@ RESULT eDVBFrontend::getState(int &state) RESULT eDVBFrontend::setTone(int t) { fe_sec_tone_mode_t tone; + if (m_simulate) + return 0; if (m_type != feSatellite) { - eWarning("[eDVBFrontend] dvb-s mode not aktive!"); + eDebug("[eDVBFrontend%d] sendTone allowed only in feSatellite (%d)", m_dvbid, m_type); return 0; } - if (m_simulate) - return 0; m_data[CUR_TONE]=t; switch (t) { @@ -3469,14 +3469,14 @@ RESULT eDVBFrontend::setTone(int t) RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc) { - struct dvb_diseqc_master_cmd cmd; + struct dvb_diseqc_master_cmd cmd = {}; + if (m_simulate) + return 0; if (m_type != feSatellite) { - eWarning("[eDVBFrontend] dvb-s mode not aktive!"); + eDebug("[eDVBFrontend%d] sendDiseqc allowed only in feSatellite (%d)", m_dvbid, m_type); return 0; } - if (m_simulate) - return 0; memcpy(cmd.msg, diseqc.data, diseqc.len); cmd.msg_len = diseqc.len; if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd)) @@ -3487,13 +3487,13 @@ RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc) RESULT eDVBFrontend::sendToneburst(int burst) { fe_sec_mini_cmd_t cmd; + if (m_simulate) + return 0; if (m_type != feSatellite) { - eWarning("[eDVBFrontend] dvb-s mode not aktive!"); + eDebug("[eDVBFrontend%d] sendToneburst allowed only in feSatellite (%d)", m_dvbid, m_type); return 0; } - if (m_simulate) - return 0; if (burst == eDVBSatelliteDiseqcParameters::B) cmd = SEC_MINI_B; else @@ -3562,7 +3562,7 @@ bool eDVBFrontend::isPreferred(int preferredFrontend, int slotid) return (preferredFrontend >= 0 && slotid == preferredFrontend); } -int eDVBFrontend::isCompatibleWith(ePtr &feparm) +int eDVBFrontend::isCompatibleWith(ePtr &feparm, bool is_configured_sat) { int type; int types; @@ -3606,11 +3606,22 @@ int eDVBFrontend::isCompatibleWith(ePtr &feparm) return 0; } score = m_sec ? m_sec->canTune(parm, this, 1 << m_slotid) : 0; + + /* additional check is orbital position configured for busy tuner use type SATPOS_DEPENDS_PTR/ADVANCED_SATPOSDEPENDS_ROOT(LINK) */ + if (is_configured_sat && !score && m_sec && m_sec->isOrbitalPositionConfigured(parm.orbital_position)) + score = 1; + if (score > 1 && parm.system == eDVBFrontendParametersSatellite::System_DVB_S && can_handle_dvbs2) { /* prefer to use an S tuner, try to keep S2 free for S2 transponders */ score--; } + if (score > 1 && is_multistream() && !multistream) + { + eDebug("[eDVBFrontend] isCompatibleWith NON MULTISTREAM CHANNEL!!!!"); + /* prefer to use a non multistream tuner, try to keep multistream tuners free for multistream transponders */ + score--; + } } else if ((type == eDVBFrontend::feCable) || (types & (1 << eDVBFrontend::feCable))) { diff --git a/lib/dvb/frontend.h b/lib/dvb/frontend.h index 03bef681e49..fbff77086a2 100644 --- a/lib/dvb/frontend.h +++ b/lib/dvb/frontend.h @@ -70,9 +70,13 @@ class eDVBFrontend: public iDVBFrontend, public sigc::trackable NEW_ROTOR_POS, // new rotor position (not validated) ROTOR_CMD, // completed rotor cmd (finalized) ROTOR_POS, // current rotor position + SAT_POSITION, // current frontend satellite position + ADVANCED_LINKED_ROOT, // number slot connected frontend LINKED_PREV_PTR, // prev double linked list (for linked FEs) LINKED_NEXT_PTR, // next double linked list (for linked FEs) SATPOS_DEPENDS_PTR, // pointer to FE with configured rotor (with twin/quattro lnb) + ADVANCED_SATPOSDEPENDS_ROOT, // root frontend with rotor (advanced satpos depending) + ADVANCED_SATPOSDEPENDS_LINK, // link to FE with configured rotor (with twin/quattro lnb, advanced satpos depending) CUR_FREQ, // current frequency CUR_SYM, // current symbolrate CUR_LOF, // current local oszillator frequency @@ -191,7 +195,7 @@ class eDVBFrontend: public iDVBFrontend, public sigc::trackable void getFrontendData(ePtr &dest); bool isPreferred(int preferredFrontend, int slotid); - int isCompatibleWith(ePtr &feparm); + int isCompatibleWith(ePtr &feparm, bool is_configured_sat = false); int getDVBID() { return m_dvbid; } int getSlotID() { return m_slotid; } bool setSlotInfo(int id, const char *descr, bool enabled, bool isDVBS2, int frontendid); @@ -214,9 +218,9 @@ class eDVBFrontend: public iDVBFrontend, public sigc::trackable int openFrontend(); int closeFrontend(bool force=false, bool no_delayed=false); const char *getDescription() const { return m_description; } - bool is_simulate() const { return m_simulate; } const dvb_frontend_info getFrontendInfo() const { return fe_info; } const dvb_frontend_info getFrontendInfo(fe_delivery_system_t delsys) { return m_fe_info[delsys]; } + bool is_simulate() const { return m_simulate; } bool is_FBCTuner() { return m_fbc; } void setFBCTuner(bool enable) { m_fbc = enable; } bool getEnabled() { return m_enabled; } diff --git a/lib/dvb/idvb.h b/lib/dvb/idvb.h index 19cc4d7dbbd..e5354a000f4 100644 --- a/lib/dvb/idvb.h +++ b/lib/dvb/idvb.h @@ -607,7 +607,7 @@ class iDVBFrontend: public iDVBFrontend_ENUMS, public iObject virtual RESULT getData(int num, long &data)=0; virtual RESULT setData(int num, long val)=0; /* 0 means: not compatible. other values are a priority. */ - virtual int isCompatibleWith(ePtr &feparm)=0; + virtual int isCompatibleWith(ePtr &feparm, bool is_configured_sat = false)=0; #endif virtual bool changeType(int type)=0; virtual int getCurrentType()=0; @@ -624,6 +624,10 @@ class iDVBSatelliteEquipmentControl: public iObject virtual void prepareTurnOffSatCR(iDVBFrontend &frontend)=0; virtual int canTune(const eDVBFrontendParametersSatellite &feparm, iDVBFrontend *fe, int frontend_id, int *highest_score_lnb=0)=0; virtual void setRotorMoving(int slotid, bool)=0; + virtual RESULT resetAdvancedsatposdependsRoot(int link)=0; + virtual bool isOrbitalPositionConfigured(int orbital_position)=0; + virtual bool tunerLinkedInUse(int root)=0; + virtual void forceUpdateRotorPos(int slot, int orbital_position)=0; }; struct eDVBCIRouting diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp index 0f7d8861bf3..53489ee8dae 100644 --- a/lib/dvb/pmt.cpp +++ b/lib/dvb/pmt.cpp @@ -534,12 +534,12 @@ PyObject *eDVBServicePMTHandler::getHbbTVApplications() for(HbbTVApplicationInfoListConstIterator infoiter = m_HbbTVApplications.begin() ; infoiter != m_HbbTVApplications.end() ; ++infoiter) { ePyObject tuple = PyTuple_New(6); - PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong((*infoiter)->m_ControlCode)); + PyTuple_SET_ITEM(tuple, 0, PyLong_FromLong((*infoiter)->m_ControlCode)); PyTuple_SET_ITEM(tuple, 1, PyString_FromString((*infoiter)->m_ApplicationName.c_str())); PyTuple_SET_ITEM(tuple, 2, PyString_FromString((*infoiter)->m_HbbTVUrl.c_str())); - PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong((*infoiter)->m_OrgId)); - PyTuple_SET_ITEM(tuple, 4, PyInt_FromLong((*infoiter)->m_AppId)); - PyTuple_SET_ITEM(tuple, 5, PyInt_FromLong((*infoiter)->m_ProfileCode)); + PyTuple_SET_ITEM(tuple, 3, PyLong_FromLong((*infoiter)->m_OrgId)); + PyTuple_SET_ITEM(tuple, 4, PyLong_FromLong((*infoiter)->m_AppId)); + PyTuple_SET_ITEM(tuple, 5, PyLong_FromLong((*infoiter)->m_ProfileCode)); PyList_Append(ret, tuple); Py_DECREF(tuple); } @@ -1194,7 +1194,7 @@ void eDVBServicePMTHandler::free() demuxes[1]=demuxes[0]; ePtr > ptr; m_PMT.getCurrent(ptr); - eDVBCAHandler::getInstance()->unregisterService(m_reference, adapterid, demuxes, ptr); + eDVBCAHandler::getInstance()->unregisterService(m_reference, adapterid, demuxes, (int)m_service_type, ptr); m_ca_servicePtr = 0; } diff --git a/lib/dvb/radiotext.cpp b/lib/dvb/radiotext.cpp index c2bacda3163..d236147215b 100644 --- a/lib/dvb/radiotext.cpp +++ b/lib/dvb/radiotext.cpp @@ -899,10 +899,10 @@ void eDVBRdsDecoder::abortNonAvail() ePyObject eDVBRdsDecoder::getRassPictureMask() { ePyObject ret = PyTuple_New(5); - PyTuple_SET_ITEM(ret, 0, PyInt_FromLong(rass_picture_mask[0])); - PyTuple_SET_ITEM(ret, 1, PyInt_FromLong(rass_picture_mask[1])); - PyTuple_SET_ITEM(ret, 2, PyInt_FromLong(rass_picture_mask[2])); - PyTuple_SET_ITEM(ret, 3, PyInt_FromLong(rass_picture_mask[3])); - PyTuple_SET_ITEM(ret, 4, PyInt_FromLong(rass_picture_mask[4])); + PyTuple_SET_ITEM(ret, 0, PyLong_FromLong(rass_picture_mask[0])); + PyTuple_SET_ITEM(ret, 1, PyLong_FromLong(rass_picture_mask[1])); + PyTuple_SET_ITEM(ret, 2, PyLong_FromLong(rass_picture_mask[2])); + PyTuple_SET_ITEM(ret, 3, PyLong_FromLong(rass_picture_mask[3])); + PyTuple_SET_ITEM(ret, 4, PyLong_FromLong(rass_picture_mask[4])); return ret; } diff --git a/lib/dvb/rtspstreamserver.cpp b/lib/dvb/rtspstreamserver.cpp index 50a17b83632..2e10a08ac46 100644 --- a/lib/dvb/rtspstreamserver.cpp +++ b/lib/dvb/rtspstreamserver.cpp @@ -1333,7 +1333,7 @@ PyObject *eRTSPStreamServer::getConnectedClients() ePyObject tuple = PyTuple_New(3); PyTuple_SET_ITEM(tuple, 0, PyString_FromString((char *)it->getRemoteHost().c_str())); PyTuple_SET_ITEM(tuple, 1, PyString_FromString((char *)it->getServiceref().c_str())); - PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->isUsingEncoder())); + PyTuple_SET_ITEM(tuple, 2, PyLong_FromLong(it->isUsingEncoder())); PyList_SET_ITEM(ret, idx++, tuple); } return ret; diff --git a/lib/dvb/sec.cpp b/lib/dvb/sec.cpp index 8a5da8da567..3f418240c36 100644 --- a/lib/dvb/sec.cpp +++ b/lib/dvb/sec.cpp @@ -2025,9 +2025,91 @@ RESULT eDVBSatelliteEquipmentControl::setTunerDepends(int tu1, int tu2) return -1; } +bool eDVBSatelliteEquipmentControl::tunerLinkedInUse(int root) +{ + long linked_root = -1; + + for (eSmartPtrList::iterator it(m_avail_frontends.begin()); it != m_avail_frontends.end(); ++it) + { + if (it->m_frontend->is_FBCTuner()) + { + it->m_frontend->getData(eDVBFrontend::ADVANCED_LINKED_ROOT, linked_root); + if (linked_root != -1 && linked_root == root && it->m_inuse) + return true; + } + } + return false; +} + +bool eDVBSatelliteEquipmentControl::tunerAdvancedsatposdependsInUse(int root) +{ + long advanced_satposdepends_link = -1; + + for (eSmartPtrList::iterator it(m_avail_frontends.begin()); it != m_avail_frontends.end(); ++it) + { + it->m_frontend->getData(eDVBFrontend::ADVANCED_SATPOSDEPENDS_LINK, advanced_satposdepends_link); + if (advanced_satposdepends_link != -1 && advanced_satposdepends_link == root && it->m_inuse) + { + return true; + } + } + return false; +} + +int eDVBSatelliteEquipmentControl::getRotorAdvancedsatposdependsPosition(int advanced_satposdepends) +{ + long rotor_pos = -1; + + for (eSmartPtrList::iterator it(m_avail_frontends.begin()); it != m_avail_frontends.end(); ++it) + { + if (it->m_frontend->getSlotID() == advanced_satposdepends) + { + it->m_frontend->getData(eDVBFrontend::ROTOR_POS, rotor_pos); + return rotor_pos; + } + } + return rotor_pos; +} + +bool eDVBSatelliteEquipmentControl::setAdvancedsatposdependsRoot(int advanced_satposdepends) +{ + for (eSmartPtrList::iterator it(m_avail_frontends.begin()); it != m_avail_frontends.end(); ++it) + { + if (it->m_frontend->getSlotID() == advanced_satposdepends) + { + it->m_frontend->setData(eDVBFrontend::ADVANCED_SATPOSDEPENDS_ROOT, advanced_satposdepends); + return true; + } + } + return false; +} + +RESULT eDVBSatelliteEquipmentControl::resetAdvancedsatposdependsRoot(int link) +{ + eDVBRegisteredFrontend *root=NULL; + long advanced_satposdepends = -1; + bool in_use = false; + + for (eSmartPtrList::iterator it(m_avail_frontends.begin()); it != m_avail_frontends.end(); ++it) + { + if (it->m_frontend->getSlotID() == link) + root = *it; + it->m_frontend->getData(eDVBFrontend::ADVANCED_SATPOSDEPENDS_LINK, advanced_satposdepends); + if (advanced_satposdepends == link) + in_use = true; + } + + if (root && !in_use) + { + root->m_frontend->setData(eDVBFrontend::ADVANCED_SATPOSDEPENDS_ROOT, -1); + return 0; + } + return -1; +} + void eDVBSatelliteEquipmentControl::setSlotNotLinked(int slot_no) { - eSecDebug("[eDVBSatelliteEquipmentControl] eDVBSatelliteEquipmentControl::setSlotNotLinked(%d)", slot_no); + eSecDebug("[eDVBSatelliteEquipmentControl::setSlotNotLinked] slot=%d", slot_no); m_not_linked_slot_mask |= (1 << slot_no); } @@ -2058,6 +2140,26 @@ bool eDVBSatelliteEquipmentControl::isOrbitalPositionConfigured(int orbital_posi return false; } +int eDVBSatelliteEquipmentControl::frontendLastRotorOrbitalPosition(int slot) +{ + long last_rotor_pos = -1; + + for (eSmartPtrList::iterator it(m_avail_frontends.begin()); it != m_avail_frontends.end(); ++it) + { + if (it->m_frontend->getSlotID() == slot) + { + it->m_frontend->getData(eDVBFrontend::ROTOR_POS, last_rotor_pos); + return last_rotor_pos; + } + } + return last_rotor_pos; +} + +void eDVBSatelliteEquipmentControl::forceUpdateRotorPos(int slot, int orbital_position) +{ + slotRotorSatPosChanged(slot, orbital_position); // emit python +} + PyObject *eDVBSatelliteEquipmentControl::getBandCutOffFrequency(int slot_no, int orbital_position) { PyObject *pyList = PyList_New(0); @@ -2068,7 +2170,7 @@ PyObject *eDVBSatelliteEquipmentControl::getBandCutOffFrequency(int slot_no, int { std::map::iterator sit = lnb_param.m_satellites.find(orbital_position); if ( sit != lnb_param.m_satellites.end()) - PyList_Append(pyList, PyInt_FromLong(lnb_param.m_lof_threshold)); + PyList_Append(pyList, PyLong_FromLong(lnb_param.m_lof_threshold)); } } return pyList; @@ -2097,8 +2199,8 @@ PyObject *eDVBSatelliteEquipmentControl::getFrequencyRangeList(int slot_no, int if ( sit != lnb_param.m_satellites.end()) { PyObject *pyTuple = PyTuple_New(2); - PyTuple_SET_ITEM(pyTuple, 0, PyInt_FromLong(lnb_param.m_lof_lo + fe_info.frequency_min)); - PyTuple_SET_ITEM(pyTuple, 1, PyInt_FromLong(lnb_param.m_lof_hi + fe_info.frequency_max)); + PyTuple_SET_ITEM(pyTuple, 0, PyLong_FromLong(lnb_param.m_lof_lo + fe_info.frequency_min)); + PyTuple_SET_ITEM(pyTuple, 1, PyLong_FromLong(lnb_param.m_lof_hi + fe_info.frequency_max)); PyList_Append(pyList, pyTuple); } } diff --git a/lib/dvb/sec.h b/lib/dvb/sec.h index 5c4d779e7f8..bede38179aa 100644 --- a/lib/dvb/sec.h +++ b/lib/dvb/sec.h @@ -2,9 +2,16 @@ #define __dvb_sec_h #include +#include +#include #include -#include +typedef enum +{ + SatCR_format_none = 0, + SatCR_format_unicable = 1, + SatCR_format_jess = 2 +} SatCR_format_t; #ifndef SWIG class eSecCommand @@ -264,6 +271,8 @@ class eDVBSatelliteLNBParameters eDVBSatelliteRotorParameters m_rotor_parameters; int m_prio; // to override automatic tuner management ... -1 is Auto + int LNBNum; + int m_advanced_satposdepends; #endif public: #define MAX_SATCR 32 @@ -313,6 +322,9 @@ class eDVBSatelliteEquipmentControl: public iDVBSatelliteEquipmentControl DELAY_AFTER_VOLTAGE_CHANGE_BEFORE_SWITCH_CMDS, // delay after change voltage before transmit toneburst/diseqc DELAY_AFTER_DISEQC_RESET_CMD, DELAY_AFTER_DISEQC_PERIPHERIAL_POWERON_CMD, + UNICABLE_DELAY_AFTER_ENABLE_VOLTAGE_BEFORE_SWITCH_CMDS, + UNICABLE_DELAY_AFTER_VOLTAGE_CHANGE_BEFORE_SWITCH_CMDS, + UNICABLE_DELAY_AFTER_LAST_DISEQC_CMD, MAX_PARAMS }; private: @@ -325,6 +337,7 @@ class eDVBSatelliteEquipmentControl: public iDVBSatelliteEquipmentControl int m_rotorMoving; int m_not_linked_slot_mask; bool m_canMeasureInputPower; + int m_target_orbital_position = -1; #endif #ifdef SWIG eDVBSatelliteEquipmentControl(); @@ -392,12 +405,21 @@ class eDVBSatelliteEquipmentControl: public iDVBSatelliteEquipmentControl /* Tuner Specific Parameters */ RESULT setTunerLinked(int from, int to); RESULT setTunerDepends(int from, int to); + RESULT resetAdvancedsatposdependsRoot(int link); + int getRotorAdvancedsatposdependsPosition(int advanced_satposdepends); + bool setAdvancedsatposdependsRoot(int advanced_satposdepends); + bool tunerAdvancedsatposdependsInUse(int root); + bool tunerLinkedInUse(int root); void setSlotNotLinked(int tuner_no); void setRotorMoving(int, bool); // called from the frontend's bool isRotorMoving(); bool canMeasureInputPower() { return m_canMeasureInputPower; } + int getTargetOrbitalPosition() { return m_target_orbital_position; } bool isOrbitalPositionConfigured(int orbital_position); + int frontendLastRotorOrbitalPosition(int slot); + PSignal2 slotRotorSatPosChanged; + void forceUpdateRotorPos(int slot, int orbital_position); // called from the frontend's PyObject *getBandCutOffFrequency(int slot_no, int orbital_position); PyObject *getFrequencyRangeList(int slot_no, int orbital_position); diff --git a/lib/dvb/streamserver.cpp b/lib/dvb/streamserver.cpp index 62c7bcd6f03..692583f8048 100644 --- a/lib/dvb/streamserver.cpp +++ b/lib/dvb/streamserver.cpp @@ -389,7 +389,7 @@ PyObject *eStreamServer::getConnectedClients() ePyObject tuple = PyTuple_New(3); PyTuple_SET_ITEM(tuple, 0, PyString_FromString((char *)it->getRemoteHost().c_str())); PyTuple_SET_ITEM(tuple, 1, PyString_FromString((char *)it->getServiceref().c_str())); - PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->isUsingEncoder())); + PyTuple_SET_ITEM(tuple, 2, PyLong_FromLong(it->isUsingEncoder())); PyList_SET_ITEM(ret, idx++, tuple); } return ret; diff --git a/lib/dvb_ci/Makefile.inc b/lib/dvb_ci/Makefile.inc index 0366b8cb6aa..2873539574e 100644 --- a/lib/dvb_ci/Makefile.inc +++ b/lib/dvb_ci/Makefile.inc @@ -8,7 +8,17 @@ dvb_ci_libenigma_dvb_ci_a_SOURCES = \ dvb_ci/dvbci_mmi.cpp \ dvb_ci/dvbci_resmgr.cpp \ dvb_ci/dvbci_session.cpp \ - dvb_ci/dvbci_ui.cpp + dvb_ci/dvbci_ui.cpp \ + dvb_ci/dvbci_ccmgr.cpp \ + dvb_ci/dvbci_ccmgr_helper.cpp \ + dvb_ci/dvbci_hlcmgr.cpp \ + dvb_ci/dvbci_host_ctrl.cpp \ + dvb_ci/dvbci_cam_upgrade.cpp \ + dvb_ci/dvbci_app_mmi.cpp \ + dvb_ci/dvbci_operatorprofile.cpp \ + dvb_ci/aes_xcbc_mac.cpp \ + dvb_ci/descrambler.cpp + dvbciincludedir = $(pkgincludedir)/lib/dvb_ci dvbciinclude_HEADERS = \ @@ -19,4 +29,13 @@ dvbciinclude_HEADERS = \ dvb_ci/dvbci_mmi.h \ dvb_ci/dvbci_resmgr.h \ dvb_ci/dvbci_session.h \ - dvb_ci/dvbci_ui.h + dvb_ci/dvbci_ui.h \ + dvb_ci/dvbci_ccmgr.h \ + dvb_ci/dvbci_ccmgr_helper.h \ + dvb_ci/dvbci_hlcmgr.h \ + dvb_ci/dvbci_host_ctrl.h \ + dvb_ci/dvbci_cam_upgrade.h \ + dvb_ci/dvbci_app_mmi.h \ + dvb_ci/dvbci_operatorprofile.h \ + dvb_ci/aes_xcbc_mac.h \ + dvb_ci/descrambler.h diff --git a/lib/dvb_ci/aes_xcbc_mac.cpp b/lib/dvb_ci/aes_xcbc_mac.cpp new file mode 100644 index 00000000000..39da7c978d3 --- /dev/null +++ b/lib/dvb_ci/aes_xcbc_mac.cpp @@ -0,0 +1,62 @@ +#include +#include +#include + +#include "aes_xcbc_mac.h" + +int aes_xcbc_mac_init(struct aes_xcbc_mac_ctx *ctx, const uint8_t *key) +{ + AES_KEY aes_key; + int y, x; + + AES_set_encrypt_key(key, 128, &aes_key); + + for (y = 0; y < 3; y++) { + for (x = 0; x < 16; x++) + ctx->K[y][x] = y + 1; + AES_ecb_encrypt(ctx->K[y], ctx->K[y], &aes_key, 1); + } + + /* setup K1 */ + AES_set_encrypt_key(ctx->K[0], 128, &ctx->key); + + memset(ctx->IV, 0, 16); + ctx->buflen = 0; + + return 0; +} + +int aes_xcbc_mac_process(struct aes_xcbc_mac_ctx *ctx, const uint8_t *in, unsigned int len) +{ + while (len) { + if (ctx->buflen == 16) { + AES_ecb_encrypt(ctx->IV, ctx->IV, &ctx->key, 1); + ctx->buflen = 0; + } + ctx->IV[ctx->buflen++] ^= *in++; + --len; + } + + return 0; +} + +int aes_xcbc_mac_done(struct aes_xcbc_mac_ctx *ctx, uint8_t *out) +{ + int i; + + if (ctx->buflen == 16) { + /* K2 */ + for (i = 0; i < 16; i++) + ctx->IV[i] ^= ctx->K[1][i]; + } else { + ctx->IV[ctx->buflen] ^= 0x80; + /* K3 */ + for (i = 0; i < 16; i++) + ctx->IV[i] ^= ctx->K[2][i]; + } + + AES_ecb_encrypt(ctx->IV, ctx->IV, &ctx->key, 1); + memcpy(out, ctx->IV, 16); + + return 0; +} diff --git a/lib/dvb_ci/aes_xcbc_mac.h b/lib/dvb_ci/aes_xcbc_mac.h new file mode 100644 index 00000000000..a0e65a1d35a --- /dev/null +++ b/lib/dvb_ci/aes_xcbc_mac.h @@ -0,0 +1,17 @@ +#ifndef __AES_XCBC_H_ +#define __AES_XCBC_H_ + +#include + +struct aes_xcbc_mac_ctx { + uint8_t K[3][16]; + uint8_t IV[16]; + AES_KEY key; + int buflen; +}; + +int aes_xcbc_mac_init(struct aes_xcbc_mac_ctx *ctx, const uint8_t *key); +int aes_xcbc_mac_process(struct aes_xcbc_mac_ctx *ctx, const uint8_t *in, unsigned int len); +int aes_xcbc_mac_done(struct aes_xcbc_mac_ctx *ctx, uint8_t *out); + +#endif diff --git a/lib/dvb_ci/descrambler.cpp b/lib/dvb_ci/descrambler.cpp new file mode 100644 index 00000000000..b89b55db55d --- /dev/null +++ b/lib/dvb_ci/descrambler.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef CA_SET_PID +/** + * CA_SET_PID and ca_pid struct removed on 4.14 kernel + * Check commit 833ff5e7feda1a042b83e82208cef3d212ca0ef1 +**/ +struct ca_pid { + unsigned int pid; + int index; /* -1 == disable*/ +}; +#define CA_SET_PID _IOW('o', 135, struct ca_pid) +#endif + +enum ca_descr_data_type { + CA_DATA_IV, + CA_DATA_KEY, +}; + +enum ca_descr_parity { + CA_PARITY_EVEN, + CA_PARITY_ODD, +}; + +struct ca_descr_data { + unsigned int index; + enum ca_descr_parity parity; + enum ca_descr_data_type data_type; + unsigned int length; + unsigned char *data; +}; + + +#define CA_SET_DESCR_DATA _IOW('o', 137, struct ca_descr_data) + +int descrambler_set_key(int desc_fd, int index, int parity, unsigned char *data) +{ + struct ca_descr_data d; + + d.index = index; + d.parity = (enum ca_descr_parity)parity; + d.data_type = CA_DATA_KEY; + d.length = 16; + d.data = data; + + if (ioctl(desc_fd, CA_SET_DESCR_DATA, &d) == -1) { + eWarning("[CI descrambler] set key failed"); + return -1; + } + + d.index = index; + d.parity = (enum ca_descr_parity)parity; + d.data_type = CA_DATA_IV; + d.length = 16; + d.data = data + 16; + + if (ioctl(desc_fd, CA_SET_DESCR_DATA, &d) == -1) { + eWarning("[CI descrambler] set iv failed"); + return -1; + } + + return 0; +} + +int descrambler_set_pid(int desc_fd, int index, int enable, int pid) +{ + struct ca_pid p; + unsigned int flags = 0x80; + + if (index) + flags |= 0x40; + + if (enable) + flags |= 0x20; + + p.pid = pid; + p.index = flags; + + if (ioctl(desc_fd, CA_SET_PID, &p) == -1) { + eWarning("[CI descrambler] set pid failed"); + return -1; + } + + return 0; +} + +int descrambler_init(void) +{ + int desc_fd; + const char *filename = "/dev/dvb/adapter0/ca0"; + + desc_fd = open(filename, O_RDWR); + if (desc_fd == -1) { + eWarning("[CI descrambler] can not open %s", filename); + } + + return desc_fd; +} + +void descrambler_deinit(int desc_fd) +{ + close(desc_fd); +} diff --git a/lib/dvb_ci/descrambler.h b/lib/dvb_ci/descrambler.h new file mode 100644 index 00000000000..85e6c56393d --- /dev/null +++ b/lib/dvb_ci/descrambler.h @@ -0,0 +1,9 @@ +#ifndef __DESCR_H_ +#define __DESCR_H_ + +int descrambler_init(void); +void descrambler_deinit(int desc_fd); +int descrambler_set_key(int desc_fd, int index, int parity, unsigned char *data); +int descrambler_set_pid(int desc_fd, int index, int enable, int pid); + +#endif diff --git a/lib/dvb_ci/dvbci.cpp b/lib/dvb_ci/dvbci.cpp index e57a2c7d7dd..684106a47e0 100644 --- a/lib/dvb_ci/dvbci.cpp +++ b/lib/dvb_ci/dvbci.cpp @@ -14,7 +14,6 @@ #include #include // access to python config -#include // access to startup config #include #include #include @@ -23,19 +22,16 @@ #include #include #include +#include #include -//#define CIDEBUG 1 - -#ifdef CIDEBUG - #define eDebugCI(x...) eDebug(x) -#else - #define eDebugCI(x...) -#endif eDVBCIInterfaces *eDVBCIInterfaces::instance = 0; +pthread_mutex_t eDVBCIInterfaces::m_pmt_handler_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +pthread_mutex_t eDVBCIInterfaces::m_slot_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + static char* readInputCI(int NimNumber) { char id1[] = "NIM Socket"; @@ -102,6 +98,7 @@ static std::string getTunerLetterDM(int NimNumber) } eDVBCIInterfaces::eDVBCIInterfaces() + : m_messagepump_thread(this,1, "dvbci"), m_messagepump_main(eApp,1, "dvbci"), m_runTimer(eTimer::create(this)) { int num_ci = 0; std::stringstream path; @@ -110,19 +107,26 @@ eDVBCIInterfaces::eDVBCIInterfaces() m_stream_interface = interface_none; m_stream_finish_mode = finish_none; + CONNECT(m_messagepump_thread.recv_msg, eDVBCIInterfaces::gotMessageThread); + CONNECT(m_messagepump_main.recv_msg, eDVBCIInterfaces::gotMessageMain); + m_runTimer->start(750, false); + eDebug("[CI] scanning for common interfaces.."); + singleLock s(m_slot_lock); + for (;;) { path.str(""); path.clear(); path << "/dev/ci" << num_ci; + if(::access(path.str().c_str(), R_OK) < 0) break; ePtr cislot; - cislot = new eDVBCISlot(eApp, num_ci); + cislot = new eDVBCISlot(this, num_ci); m_slots.push_back(cislot); ++num_ci; @@ -131,7 +135,7 @@ eDVBCIInterfaces::eDVBCIInterfaces() for (eSmartPtrList::iterator it(m_slots.begin()); it != m_slots.end(); ++it) #ifdef DREAMBOX_DUAL_TUNER it->setSource(getTunerLetterDM(0)); -#else +#else it->setSource("A"); #endif @@ -146,7 +150,7 @@ eDVBCIInterfaces::eDVBCIInterfaces() #ifdef DREAMBOX_DUAL_TUNER setInputSource(tuner_no, getTunerLetterDM(tuner_no)); -#else +#else setInputSource(tuner_no, eDVBCISlot::getTunerLetter(tuner_no)); #endif } @@ -184,10 +188,16 @@ eDVBCIInterfaces::eDVBCIInterfaces() eDebug("[CI] Streaming CI finish interface not advertised, assuming \"tuner\" method"); } } + m_ciplus_routing_active = false; + m_ciplus_routing_tunernum = -1; + + run(); } eDVBCIInterfaces::~eDVBCIInterfaces() { + m_messagepump_thread.send(1); // stop thread + kill(); // join } eDVBCIInterfaces *eDVBCIInterfaces::getInstance() @@ -195,13 +205,36 @@ eDVBCIInterfaces *eDVBCIInterfaces::getInstance() return instance; } +void eDVBCIInterfaces::thread() +{ + hasStarted(); + if (nice(4) == -1) + { + eDebug("[CI] thread failed to modify scheduling priority (%m)"); + } + runLoop(); +} + +// runs in the thread +void eDVBCIInterfaces::gotMessageThread(const int &message) +{ + quit(0); // quit thread +} + +// runs in the e2 mainloop +void eDVBCIInterfaces::gotMessageMain(const int &message) +{ + recheckPMTHandlers(); +} + eDVBCISlot *eDVBCIInterfaces::getSlot(int slotid) { + singleLock s(m_slot_lock); for(eSmartPtrList::iterator i(m_slots.begin()); i != m_slots.end(); ++i) if(i->getSlotID() == slotid) return i; - eDebug("[CI] FIXME: request for unknown slot"); + eWarning("[CI] FIXME: request for unknown slot"); return 0; } @@ -210,6 +243,7 @@ int eDVBCIInterfaces::getSlotState(int slotid) { eDVBCISlot *slot; + singleLock s(m_slot_lock); if( (slot = getSlot(slotid)) == 0 ) return eDVBCISlot::stateInvalid; @@ -220,6 +254,7 @@ int eDVBCIInterfaces::reset(int slotid) { eDVBCISlot *slot; + singleLock s(m_slot_lock); if( (slot = getSlot(slotid)) == 0 ) return -1; @@ -230,6 +265,7 @@ int eDVBCIInterfaces::initialize(int slotid) { eDVBCISlot *slot; + singleLock s(m_slot_lock); if( (slot = getSlot(slotid)) == 0 ) return -1; @@ -242,9 +278,11 @@ int eDVBCIInterfaces::sendCAPMT(int slotid) { eDVBCISlot *slot; + singleLock s1(m_slot_lock); if( (slot = getSlot(slotid)) == 0 ) return -1; + singleLock s2(m_pmt_handler_lock); PMTHandlerList::iterator it = m_pmt_handlers.begin(); while (it != m_pmt_handlers.end()) { @@ -266,6 +304,7 @@ int eDVBCIInterfaces::startMMI(int slotid) { eDVBCISlot *slot; + singleLock s(m_slot_lock); if( (slot = getSlot(slotid)) == 0 ) return -1; @@ -276,6 +315,7 @@ int eDVBCIInterfaces::stopMMI(int slotid) { eDVBCISlot *slot; + singleLock s(m_slot_lock); if( (slot = getSlot(slotid)) == 0 ) return -1; @@ -286,6 +326,7 @@ int eDVBCIInterfaces::answerText(int slotid, int answer) { eDVBCISlot *slot; + singleLock s(m_slot_lock); if( (slot = getSlot(slotid)) == 0 ) return -1; @@ -296,6 +337,7 @@ int eDVBCIInterfaces::answerEnq(int slotid, char *value) { eDVBCISlot *slot; + singleLock s(m_slot_lock); if( (slot = getSlot(slotid)) == 0 ) return -1; @@ -306,6 +348,7 @@ int eDVBCIInterfaces::cancelEnq(int slotid) { eDVBCISlot *slot; + singleLock s(m_slot_lock); if( (slot = getSlot(slotid)) == 0 ) return -1; @@ -316,6 +359,8 @@ void eDVBCIInterfaces::ciRemoved(eDVBCISlot *slot) { if (slot->use_count) { + singleLock s1(m_pmt_handler_lock); + singleLock s2(m_slot_lock); eDebug("[CI] Slot %d: removed... usecount %d", slot->getSlotID(), slot->use_count); for (PMTHandlerList::iterator it(m_pmt_handlers.begin()); it != m_pmt_handlers.end(); ++it) @@ -345,29 +390,42 @@ void eDVBCIInterfaces::ciRemoved(eDVBCISlot *slot) slot->plugged=true; slot->user_mapped=false; slot->removeService(0xFFFF); - recheckPMTHandlers(); + executeRecheckPMTHandlersInMainloop(); // calls recheckPMTHandlers in the e2 mainloop } } -static bool canDescrambleMultipleServices(int slotid) +bool eDVBCIInterfaces::canDescrambleMultipleServices(eDVBCISlot* slot) { + singleLock s(m_slot_lock); char configStr[255]; - snprintf(configStr, 255, "config.ci.%d.canDescrambleMultipleServices", slotid); + snprintf(configStr, 255, "config.ci.%d.canDescrambleMultipleServices", slot->getSlotID()); std::string str = eConfigManager::getConfigValue(configStr); if ( str == "auto" ) { - std::string appname = eDVBCI_UI::getInstance()->getAppName(slotid); - if (appname.find("AlphaCrypt") != std::string::npos || appname.find("Multi") != std::string::npos) - return true; + if (slot->getAppManager()) + { + std::string appname = slot->getAppManager()->getAppName(); + if (appname.find("AlphaCrypt") != std::string::npos || appname.find("Multi") != std::string::npos) + return true; + } } else if (str == "yes") return true; return false; } +// executes recheckPMTHandlers in the e2 mainloop +void eDVBCIInterfaces::executeRecheckPMTHandlersInMainloop() +{ + m_messagepump_main.send(1); +} + +// has to run in the e2 mainloop to be able to access the pmt handler void eDVBCIInterfaces::recheckPMTHandlers() { - eDebugCI("[CI] recheckPMTHAndlers()"); + singleLock s1(m_pmt_handler_lock); + singleLock s2(m_slot_lock); + eTrace("[CI] recheckPMTHAndlers()"); for (PMTHandlerList::iterator it(m_pmt_handlers.begin()); it != m_pmt_handlers.end(); ++it) { @@ -382,7 +440,7 @@ void eDVBCIInterfaces::recheckPMTHandlers() pmthandler->getServiceReference(ref); pmthandler->getService(service); - eDebugCI("[CI] recheck %p %s", pmthandler, ref.toString().c_str()); + eTrace("[CI] recheck %p %s", pmthandler, ref.toString().c_str()); for (eSmartPtrList::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it) if (ci_it->plugged && ci_it->getCAManager()) { @@ -402,7 +460,7 @@ void eDVBCIInterfaces::recheckPMTHandlers() } if (tmp) // we dont like to change tsmux for running services { - eDebugCI("[CI] already assigned and running CI!\n"); + eTrace("[CI] already assigned and running CI!\n"); continue; } } @@ -425,7 +483,7 @@ void eDVBCIInterfaces::recheckPMTHandlers() for (eSmartPtrList::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it) { - eDebugCI("[CI] check Slot %d", ci_it->getSlotID()); + eTrace("[CI] check Slot %d", ci_it->getSlotID()); bool useThis=false; bool user_mapped=true; eDVBCICAManagerSession *ca_manager = ci_it->getCAManager(); @@ -520,10 +578,10 @@ void eDVBCIInterfaces::recheckPMTHandlers() } if (tmp) // ignore already assigned cislots... { - eDebugCI("[CI] already assigned!"); + eTrace("[CI] already assigned!"); continue; } - eDebugCI("[CI] current slot %d usecount %d", ci_it->getSlotID(), ci_it->use_count); + eTrace("[CI] current slot %d usecount %d", ci_it->getSlotID(), ci_it->use_count); if (ci_it->use_count) // check if this CI can descramble more than one service { bool found = false; @@ -531,39 +589,39 @@ void eDVBCIInterfaces::recheckPMTHandlers() PMTHandlerList::iterator tmp = m_pmt_handlers.begin(); while (!found && tmp != m_pmt_handlers.end()) { - eDebugCI("[CI] ."); + eTrace("[CI] ."); eDVBCISlot *tmp_cislot = tmp->cislot; while (!found && tmp_cislot) { - eDebugCI("[CI] .."); + eTrace("[CI] .."); eServiceReferenceDVB ref2; tmp->pmthandler->getServiceReference(ref2); if ( tmp_cislot == ci_it && it->pmthandler != tmp->pmthandler ) { - eDebugCI("[CI] check pmthandler %s for same service/tp", ref2.toString().c_str()); + eTrace("[CI] check pmthandler %s for same service/tp", ref2.toString().c_str()); eDVBChannelID s1, s2; if (ref != ref2) { - eDebugCI("[CI] different services!"); + eTrace("[CI] different services!"); ref.getChannelID(s1); ref2.getChannelID(s2); } - if (ref == ref2 || (s1 == s2 && canDescrambleMultipleServices(tmp_cislot->getSlotID()))) + if (ref == ref2 || (s1 == s2 && canDescrambleMultipleServices(tmp_cislot))) { found = true; - eDebugCI("[CI] found!"); + eTrace("[CI] found!"); eDVBCISlot *tmpci = it->cislot = tmp->cislot; while(tmpci) { ++tmpci->use_count; - eDebug("[CI] (2)CISlot %d, usecount now %d", tmpci->getSlotID(), tmpci->use_count); + eTrace("[CI] (2)CISlot %d, usecount now %d", tmpci->getSlotID(), tmpci->use_count); tmpci=tmpci->linked_next; } } } tmp_cislot=tmp_cislot->linked_next; } - eDebugCI("[CI] ..."); + eTrace("[CI] ..."); ++tmp; } } @@ -572,7 +630,7 @@ void eDVBCIInterfaces::recheckPMTHandlers() { if (ci_it->user_mapped) // we dont like to link user mapped CIs { - eDebugCI("[CI] user mapped CI already in use... dont link!"); + eTrace("[CI] user mapped CI already in use... dont link!"); continue; } @@ -599,7 +657,7 @@ void eDVBCIInterfaces::recheckPMTHandlers() setInputSource(tunernum, ci_source.str()); #ifdef DREAMBOX_DUAL_TUNER ci_it->setSource(getTunerLetterDM(tunernum)); -#else +#else ci_it->setSource(eDVBCISlot::getTunerLetter(tunernum)); #endif } @@ -645,13 +703,13 @@ void eDVBCIInterfaces::recheckPMTHandlers() ci_it->linked_next->setSource(ci_source.str()); } it->cislot = ci_it; - eDebugCI("[CI] assigned!"); + eTrace("[CI] assigned!"); gotPMT(pmthandler); } if (it->cislot && user_mapped) // CI assigned to this pmthandler in this run.. and user mapped? then we break here.. we dont like to link other CIs to user mapped CIs { - eDebugCI("[CI] user mapped CI assigned... dont link CIs!"); + eTrace("[CI] user mapped CI assigned... dont link CIs!"); break; } } @@ -661,6 +719,7 @@ void eDVBCIInterfaces::recheckPMTHandlers() void eDVBCIInterfaces::addPMTHandler(eDVBServicePMTHandler *pmthandler) { + singleLock s(m_pmt_handler_lock); // check if this pmthandler is already registered PMTHandlerList::iterator it = m_pmt_handlers.begin(); while (it != m_pmt_handlers.end()) @@ -679,6 +738,8 @@ void eDVBCIInterfaces::addPMTHandler(eDVBServicePMTHandler *pmthandler) void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler) { + singleLock s1(m_pmt_handler_lock); + singleLock s2(m_slot_lock); PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(),m_pmt_handlers.end(),pmthandler); if (it != m_pmt_handlers.end()) { @@ -716,6 +777,7 @@ void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler) caids.push_back(0xFFFF); slot->sendCAPMT(pmthandler, caids); // send a capmt without caids to remove a running service slot->removeService(service_to_remove.getServiceID().get()); + if (slot->current_tuner == -1) { // no previous tuner to go back to, signal to CI interface CI action is finished @@ -728,7 +790,7 @@ void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler) { #ifdef DREAMBOX_DUAL_TUNER finish_source = getTunerLetterDM(0); -#else +#else finish_source = "A"; #endif break; @@ -756,8 +818,8 @@ void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler) #ifdef DREAMBOX_DUAL_TUNER finish_source = getTunerLetterDM(0); #else - finish_source = "A"; -#endif + finish_source = "A"; +#endif } slot->setSource(finish_source); @@ -797,6 +859,12 @@ void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler) void eDVBCIInterfaces::gotPMT(eDVBServicePMTHandler *pmthandler) { + // language config can only be accessed by e2 mainloop + if (m_language == "") + m_language = eConfigManager::getConfigValue("config.osd.language"); + + singleLock s1(m_pmt_handler_lock); + singleLock s2(m_slot_lock); eDebug("[eDVBCIInterfaces] gotPMT"); PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(), m_pmt_handlers.end(), pmthandler); if (it != m_pmt_handlers.end() && it->cislot) @@ -804,8 +872,8 @@ void eDVBCIInterfaces::gotPMT(eDVBServicePMTHandler *pmthandler) eDVBCISlot *tmp = it->cislot; while(tmp) { - eDebugCI("[CI] check slot %d %d %d", tmp->getSlotID(), tmp->running_services.empty(), canDescrambleMultipleServices(tmp->getSlotID())); - if (tmp->running_services.empty() || canDescrambleMultipleServices(tmp->getSlotID())) + eTrace("[CI] check slot %d %d %d", tmp->getSlotID(), tmp->running_services.empty(), canDescrambleMultipleServices(tmp)); + if (tmp->running_services.empty() || canDescrambleMultipleServices(tmp)) tmp->sendCAPMT(pmthandler); tmp = tmp->linked_next; } @@ -816,6 +884,7 @@ int eDVBCIInterfaces::getMMIState(int slotid) { eDVBCISlot *slot; + singleLock s(m_slot_lock); if( (slot = getSlot(slotid)) == 0 ) return -1; @@ -828,36 +897,21 @@ int eDVBCIInterfaces::setInputSource(int tuner_no, const std::string &source) { char buf[64]; snprintf(buf, sizeof(buf), "/proc/stb/tsmux/input%d", tuner_no); - char *srcCI = NULL; - if (source.find("CI") == std::string::npos) - { - srcCI = readInputCI(tuner_no); - } - - if (srcCI && CFile::write(buf, srcCI) == -1) - { - eDebug("[CI] eDVBCIInterfaces setInputSource for input %s failed!", srcCI); - free(srcCI); - srcCI = NULL; - } - else if (CFile::write(buf, source.c_str()) == -1) + if (CFile::write(buf, source.c_str()) == -1) { eDebug("[CI] eDVBCIInterfaces setInputSource for input %s failed!", source.c_str()); - if (srcCI) - free(srcCI); return 0; } eDebug("[CI] eDVBCIInterfaces setInputSource(%d, %s)", tuner_no, source.c_str()); - if (srcCI) - free(srcCI); } return 0; } PyObject *eDVBCIInterfaces::getDescrambleRules(int slotid) { + singleLock s(m_slot_lock); eDVBCISlot *slot = getSlot(slotid); if (!slot) { @@ -884,14 +938,14 @@ PyObject *eDVBCIInterfaces::getDescrambleRules(int slotid) while(services) { --services; - PyList_SET_ITEM(service_list, services, PyString_FromString(ref_it->toString().c_str())); + PyList_SET_ITEM(service_list, services, PyUnicode_FromString(ref_it->toString().c_str())); ++ref_it; } providerSet::iterator provider_it(slot->possible_providers.begin()); while(providers) { ePyObject tuple = PyTuple_New(2); - PyTuple_SET_ITEM(tuple, 0, PyString_FromString(provider_it->first.c_str())); + PyTuple_SET_ITEM(tuple, 0, PyUnicode_FromString(provider_it->first.c_str())); PyTuple_SET_ITEM(tuple, 1, PyLong_FromUnsignedLong(provider_it->second)); --providers; PyList_SET_ITEM(provider_list, providers, tuple); @@ -910,6 +964,7 @@ const char *PyObject_TypeStr(PyObject *o) RESULT eDVBCIInterfaces::setDescrambleRules(int slotid, SWIG_PYOBJECT(ePyObject) obj ) { + singleLock s(m_slot_lock); eDVBCISlot *slot = getSlot(slotid); if (!slot) { @@ -968,7 +1023,7 @@ RESULT eDVBCIInterfaces::setDescrambleRules(int slotid, SWIG_PYOBJECT(ePyObject) if (ref.valid()) slot->possible_services.insert(ref); else - eDebug("eDVBCIInterfaces::setDescrambleRules '%s' is not a valid service reference... ignore!!", tmpstr); + eDebug("[CI] eDVBCIInterfaces::setDescrambleRules '%s' is not a valid service reference... ignore!!", tmpstr); }; size = PyList_Size(provider_list); while(size) @@ -1033,6 +1088,7 @@ RESULT eDVBCIInterfaces::setDescrambleRules(int slotid, SWIG_PYOBJECT(ePyObject) PyObject *eDVBCIInterfaces::readCICaIds(int slotid) { + singleLock s(m_slot_lock); eDVBCISlot *slot = getSlot(slotid); if (!slot) { @@ -1066,20 +1122,129 @@ int eDVBCIInterfaces::setCIEnabled(int slotid, bool enabled) int eDVBCIInterfaces::setCIClockRate(int slotid, int rate) { + singleLock s(m_slot_lock); eDVBCISlot *slot = getSlot(slotid); if (slot) return slot->setClockRate(rate); return -1; } +/* For authentication process transponder data needs to be routed through the CI (doesn't matter which channel) + This is mandatory for many CI+ 1.3 modules. For many CI+ 1.2 modules you can also switch to an encrypted channel + (with correct caid) */ +void eDVBCIInterfaces::setCIPlusRouting(int slotid) +{ + eDebug("[CI] setCIRouting slotid=%d", slotid); + singleLock s(m_pmt_handler_lock); + if (m_pmt_handlers.size() == 0) + { + eDebug("[CI] setCIRouting no pmt handler available! Unplug/plug again the CI module."); + return; + } + if (m_ciplus_routing_active) + { + eDebug("[CI] setCIRouting authentification of other module active. Unplug/plug again the CI module after first authentification was successful."); + return; + } + eDVBCISlot *slot = getSlot(slotid); + PMTHandlerList::iterator it = m_pmt_handlers.begin(); + while (it != m_pmt_handlers.end()) + { + int tunernum = -1; + eUsePtr channel; + if (!it->pmthandler->getChannel(channel)) + { + ePtr frontend; + if (!channel->getFrontend(frontend)) + { + eDVBFrontend *fe = (eDVBFrontend*) &(*frontend); + tunernum = fe->getSlotID(); + } + } + eTrace("[CI] setCIRouting tunernum=%d", tunernum); + if (tunernum < 0) + continue; + + // read and store old routing config + char file_name[64]; + char tmp[8]; + int rd; + + snprintf(file_name, 64, "/proc/stb/tsmux/input%d", tunernum); + int fd = open(file_name, O_RDONLY); + if (fd > -1) + { + rd = read(fd, tmp, 8); + if (rd > 0) + { + if (m_ciplus_routing_tunernum != tunernum) + m_ciplus_routing_input = std::string(tmp, rd-1); + } + else + continue; + close(fd); + } + else + continue; + + snprintf(file_name, 64, "/proc/stb/tsmux/ci%d_input", slotid); + fd = open(file_name, O_RDONLY); + if (fd > -1) + { + rd = read(fd, tmp, 8); + if (rd > 0) + { + if (m_ciplus_routing_tunernum != tunernum) + m_ciplus_routing_ci_input = std::string(tmp, rd-1); + } + else + continue; + close(fd); + } + else + continue; + + std::stringstream new_input_source; + new_input_source << "CI" << slot->getSlotID(); + + setInputSource(tunernum, new_input_source.str()); + slot->setSource(eDVBCISlot::getTunerLetter(tunernum)); + + m_ciplus_routing_tunernum = tunernum; + m_ciplus_routing_active = true; + break; + + ++it; + } + eDebug("[CI] setCIRouting slotid=%d tuner=%d old_input=%s old_ci_input=%s", slotid, m_ciplus_routing_tunernum, m_ciplus_routing_input.c_str(), m_ciplus_routing_ci_input.c_str()); +} + +void eDVBCIInterfaces::revertCIPlusRouting(int slotid) +{ + eDVBCISlot *slot = getSlot(slotid); + + eDebug("[CI] revertCIPlusRouting: active=%d slot=%d tuner=%d input=%s ci_input=%s", m_ciplus_routing_active, slotid, m_ciplus_routing_tunernum, m_ciplus_routing_input.c_str(), m_ciplus_routing_ci_input.c_str()); + + if(m_ciplus_routing_active) + { + slot->setSource(m_ciplus_routing_ci_input); + setInputSource(m_ciplus_routing_tunernum, m_ciplus_routing_input); + } + m_ciplus_routing_active = false; + m_ciplus_routing_tunernum = -1; + m_ciplus_routing_input = ""; + m_ciplus_routing_ci_input = ""; +} + int eDVBCISlot::send(const unsigned char *data, size_t len) { + singleLock s(eDVBCIInterfaces::m_slot_lock); int res=0; - //int i; - //eDebugNoNewLineStart("< "); - //for(i=0;iciRemoved(this); notifier->setRequested(eSocketNotifier::Read); - eDVBCI_UI::getInstance()->setState(getSlotID(),0); + /* emit */ eDVBCI_UI::getInstance()->m_messagepump.send(eDVBCIInterfaces::Message(eDVBCIInterfaces::Message::slotStateChanged, getSlotID(), 0)); } return; } @@ -1120,7 +1286,7 @@ void eDVBCISlot::data(int what) if(state != stateInserted) { eDebug("[CI] ci inserted in slot %d", getSlotID()); state = stateInserted; - eDVBCI_UI::getInstance()->setState(getSlotID(),1); + /* emit */ eDVBCI_UI::getInstance()->m_messagepump.send(eDVBCIInterfaces::Message(eDVBCIInterfaces::Message::slotStateChanged, getSlotID(), 1)); notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority); /* enable PRI to detect removal or errors */ } @@ -1130,11 +1296,11 @@ void eDVBCISlot::data(int what) int r; r = ::read(fd, data, 4096); if(r > 0) { -// int i; -// eDebugNoNewLineStart("> "); -// for(i=0;i "); + for(i=0;isetState(getSlotID(), 3); // state disabled + /* emit */ eDVBCI_UI::getInstance()->m_messagepump.send(eDVBCIInterfaces::Message(eDVBCIInterfaces::Message::slotStateChanged, getSlotID(), 3)); // state disabled } void eDVBCISlot::openDevice() @@ -1178,10 +1344,12 @@ void eDVBCISlot::openDevice() application_manager = 0; mmi_session = 0; ca_manager = 0; + cc_manager = 0; use_count = 0; linked_next = 0; user_mapped = false; plugged = true; + m_ci_version = versionUnknown; sprintf(filename, "/dev/ci%d", slotid); @@ -1191,7 +1359,7 @@ void eDVBCISlot::openDevice() fd = ::open(filename, O_RDWR | O_NONBLOCK | O_CLOEXEC); - eDebugCI("[CI] CI Slot %d has fd %d", getSlotID(), fd); + eTrace("[CI] Slot %d has fd %d", getSlotID(), fd); state = stateInvalid; if (fd >= 0) @@ -1207,6 +1375,7 @@ void eDVBCISlot::openDevice() eDVBCISlot::~eDVBCISlot() { eDVBCISession::deleteSessions(this); + close(fd); } void eDVBCISlot::closeDevice() @@ -1220,32 +1389,118 @@ void eDVBCISlot::closeDevice() void eDVBCISlot::setAppManager(eDVBCIApplicationManagerSession *session) { + singleLock s(eDVBCIInterfaces::m_slot_lock); application_manager=session; } void eDVBCISlot::setMMIManager( eDVBCIMMISession *session ) { + singleLock s(eDVBCIInterfaces::m_slot_lock); mmi_session = session; } void eDVBCISlot::setCAManager( eDVBCICAManagerSession *session ) { + singleLock s(eDVBCIInterfaces::m_slot_lock); ca_manager = session; } +void eDVBCISlot::setCCManager( eDVBCICcSession *session ) +{ + singleLock s(eDVBCIInterfaces::m_slot_lock); + cc_manager = session; +} + int eDVBCISlot::getSlotID() { + singleLock s(eDVBCIInterfaces::m_slot_lock); return slotid; } +int eDVBCISlot::getVersion() +{ + return m_ci_version; +} + +void eDVBCISlot::determineCIVersion() +{ + char lv1Info[256] = { 0 }; + + if (ioctl(fd, 1, lv1Info) < 0) { + eTrace("[CI] Slot %d ioctl not supported: assume CI+ version 1", getSlotID()); + m_ci_version = versionCIPlus1; + return; + } + + if (strlen(lv1Info) == 0) { + eTrace("[CI] Slot %d no LV1 info: assume CI+ version 1", getSlotID()); + m_ci_version = versionCIPlus1; + return; + } + + const char *str1 = "$compatible["; + int len1 = strlen(str1); + char *compatId = 0; + + for(unsigned int i=0;i<=(sizeof(lv1Info)-len1);i++) { + if(strncasecmp(&lv1Info[i], str1, len1) == 0) { + i += len1; + for(unsigned int j=i;j<=(sizeof(lv1Info)-2);j++) { + if(strncmp(&lv1Info[j], "]$", 2) == 0) { + lv1Info[j] = '\0'; + compatId = &lv1Info[i]; + break; + } + } + } + } + + if(!compatId) { + eTrace("[CI] Slot %d CI CAM detected", getSlotID()); + m_ci_version = versionCI; + return; + } + + eTrace("[CI] Slot %d CI+ compatibility ID: %s", getSlotID(), compatId); + + char *label, *id, flag = '+'; + int version = versionCI; + + while((label = strsep(&compatId, " ")) != 0) { + if (*label == '\0') + continue; + + if(strncasecmp(label, "ciplus", 6) == 0) { + id = strchr(label, '='); + if(id) { + *id++ = '\0'; + if(*id == '-' || *id == '+' || *id == '*') + flag = *id++; + + version = strtol(id, 0, 0); + eDebug("[CI] Slot %d CI+ %c%d CAM detected", getSlotID(), flag, version); + break; + } + } + } + + m_ci_version = version; +} + +int eDVBCISlot::getNumOfServices() +{ + singleLock s(eDVBCIInterfaces::m_slot_lock); + return running_services.size(); +} + int eDVBCISlot::reset() { - eDebug("[CI] CI Slot %d: reset requested", getSlotID()); + eDebug("[CI] Slot %d: reset requested", getSlotID()); if (state == stateInvalid) { unsigned char buf[256]; - eDebug("[CI] ci flush"); + eDebug("[CI] flush"); while(::read(fd, buf, 256)>0); state = stateResetted; } @@ -1263,7 +1518,7 @@ int eDVBCISlot::reset() int eDVBCISlot::startMMI() { - eDebug("[CI] CI Slot %d: startMMI()", getSlotID()); + eDebug("[CI] Slot %d: startMMI()", getSlotID()); if(application_manager) application_manager->startMMI(); @@ -1273,7 +1528,7 @@ int eDVBCISlot::startMMI() int eDVBCISlot::stopMMI() { - eDebug("[CI] CI Slot %d: stopMMI()", getSlotID()); + eDebug("[CI] Slot %d: stopMMI()", getSlotID()); if(mmi_session) mmi_session->stopMMI(); @@ -1283,7 +1538,7 @@ int eDVBCISlot::stopMMI() int eDVBCISlot::answerText(int answer) { - eDebug("[CI] CI Slot %d: answerText(%d)", getSlotID(), answer); + eDebug("[CI] Slot %d: answerText(%d)", getSlotID(), answer); if(mmi_session) mmi_session->answerText(answer); @@ -1301,7 +1556,7 @@ int eDVBCISlot::getMMIState() int eDVBCISlot::answerEnq(char *value) { - eDebug("[CI] CI Slot %d: answerENQ(%s)", getSlotID(), value); + eDebug("[CI] Slot %d: answerENQ(%s)", getSlotID(), value); if(mmi_session) mmi_session->answerEnq(value); @@ -1311,7 +1566,7 @@ int eDVBCISlot::answerEnq(char *value) int eDVBCISlot::cancelEnq() { - eDebug("[CI] CI Slot %d: cancelENQ", getSlotID()); + eDebug("[CI] Slot %d: cancelENQ", getSlotID()); if(mmi_session) mmi_session->cancelEnq(); @@ -1347,7 +1602,7 @@ int eDVBCISlot::sendCAPMT(eDVBServicePMTHandler *pmthandler, const std::vectorsecond) && !sendEmpty ) { - eDebug("[eDVBCISlot] dont send self capmt version twice"); + eDebug("[CI] [eDVBCISlot] dont send self capmt version twice"); return -1; } @@ -1358,7 +1613,7 @@ int eDVBCISlot::sendCAPMT(eDVBServicePMTHandler *pmthandler, const std::vectorgetSections().end() ) { - // eDebug("append"); + // eDebug("[CI] append"); capmt.append(*i++); } capmt.writeToBuffer(raw_data); @@ -1394,22 +1649,40 @@ int eDVBCISlot::sendCAPMT(eDVBServicePMTHandler *pmthandler, const std::vectorsendCAPMT(raw_data + hlen, wp - hlen); running_services[program_number] = pmt_version; + + std::vector pids; + int prg_info_len = ((raw_data[hlen + 4] << 8) | raw_data[hlen + 5]) & 0xfff; + int es_info_len = 0; + for (int jj = hlen + prg_info_len + 6; jj < wp; jj += es_info_len + 5) + { + uint16_t es_pid = ((raw_data[jj + 1] << 8) | raw_data[jj + 2]) & 0x1fff; + pids.push_back( es_pid ); + es_info_len = ((raw_data[jj + 3] << 8) | raw_data[jj + 4]) & 0xfff; + } + + if (cc_manager) + { + if (!sendEmpty) + cc_manager->addProgram(program_number, pids); + else + cc_manager->removeProgram(program_number, pids); + } } } return 0; @@ -1428,31 +1701,14 @@ int eDVBCISlot::setSource(const std::string &source) char buf[64]; current_source = source; snprintf(buf, sizeof(buf), "/proc/stb/tsmux/ci%d_input", slotid); - char *srcCI = NULL; - if(source.find("CI") == std::string::npos || source.size() == 1) - { - srcCI = readInputCI(source[0]-65); - } - - if(srcCI && CFile::write(buf, srcCI) == -1) - { - eDebug("[CI] Slot: %d setSource: %s failed!", getSlotID(), srcCI); - free(srcCI); - return 0; - } - else if(CFile::write(buf, source.c_str()) == -1) + if(CFile::write(buf, source.c_str()) == -1) { eDebug("[CI] Slot: %d setSource: %s failed!", getSlotID(), source.c_str()); - if (srcCI) - free(srcCI); return 0; } eDebug("[CI] Slot: %d setSource: %s", getSlotID(), source.c_str()); - if (srcCI) - free(srcCI); - return 0; } @@ -1478,7 +1734,7 @@ int eDVBCISlot::setEnabled(bool enabled) openDevice(); else { closeDevice(); - eDVBCI_UI::getInstance()->setState(getSlotID(), 3); // state disabled + /* emit */ eDVBCI_UI::getInstance()->m_messagepump.send(eDVBCIInterfaces::Message(eDVBCIInterfaces::Message::slotStateChanged, getSlotID(), 3)); // state disabled } return 0; } diff --git a/lib/dvb_ci/dvbci.h b/lib/dvb_ci/dvbci.h index 4e0e151f6d6..d32ee89987a 100644 --- a/lib/dvb_ci/dvbci.h +++ b/lib/dvb_ci/dvbci.h @@ -4,6 +4,8 @@ #ifndef SWIG #include +#include +#include #include #include #include @@ -12,6 +14,7 @@ class eDVBCISession; class eDVBCIApplicationManagerSession; class eDVBCICAManagerSession; +class eDVBCICcSession; class eDVBCIMMISession; class eDVBServicePMTHandler; class eDVBCISlot; @@ -46,9 +49,11 @@ class eDVBCISlot: public iObject, public sigc::trackable int fd; ePtr notifier; int state; + int m_ci_version; std::map running_services; eDVBCIApplicationManagerSession *application_manager; eDVBCICAManagerSession *ca_manager; + eDVBCICcSession *cc_manager; eDVBCIMMISession *mmi_session; std::priority_queue sendqueue; caidSet possible_caids; @@ -62,25 +67,13 @@ class eDVBCISlot: public iObject, public sigc::trackable void data(int); bool plugged; eMainloop *m_context; -public: - enum {stateRemoved, stateInserted, stateInvalid, stateResetted, stateDisabled}; - eDVBCISlot(eMainloop *context, int nr); - ~eDVBCISlot(); - void closeDevice(); - void openDevice(); - - int send(const unsigned char *data, size_t len); - - void setAppManager( eDVBCIApplicationManagerSession *session ); - void setMMIManager( eDVBCIMMISession *session ); - void setCAManager( eDVBCICAManagerSession *session ); eDVBCIApplicationManagerSession *getAppManager() { return application_manager; } eDVBCIMMISession *getMMIManager() { return mmi_session; } eDVBCICAManagerSession *getCAManager() { return ca_manager; } + eDVBCICcSession *getCCManager() { return cc_manager; } int getState() { return state; } - int getSlotID(); int reset(); int startMMI(); int stopMMI(); @@ -90,11 +83,29 @@ class eDVBCISlot: public iObject, public sigc::trackable int getMMIState(); int sendCAPMT(eDVBServicePMTHandler *ptr, const std::vector &caids=std::vector()); void removeService(uint16_t program_number=0xFFFF); - int getNumOfServices() { return running_services.size(); } int setSource(const std::string &source); int setClockRate(int); + void determineCIVersion(); int setEnabled(bool); +public: static std::string getTunerLetter(int tuner_no) { return std::string(1, char(65 + tuner_no)); } + enum {stateRemoved, stateInserted, stateInvalid, stateResetted, stateDisabled}; + enum {versionUnknown = -1, versionCI = 0, versionCIPlus1 = 1, versionCIPlus2 = 2}; + eDVBCISlot(eMainloop *context, int nr); + ~eDVBCISlot(); + void closeDevice(); + void openDevice(); + + int send(const unsigned char *data, size_t len); + + void setAppManager( eDVBCIApplicationManagerSession *session ); + void setMMIManager( eDVBCIMMISession *session ); + void setCAManager( eDVBCICAManagerSession *session ); + void setCCManager( eDVBCICcSession *session ); + + int getSlotID(); + int getNumOfServices(); + int getVersion(); }; struct CIPmtHandler @@ -117,7 +128,7 @@ typedef std::list PMTHandlerList; #endif // SWIG -class eDVBCIInterfaces +class eDVBCIInterfaces: public eMainloop, private eThread { private: typedef enum @@ -136,21 +147,42 @@ class eDVBCIInterfaces } stream_finish_mode_t; DECLARE_REF(eDVBCIInterfaces); + stream_interface_t m_stream_interface; stream_finish_mode_t m_stream_finish_mode; + static eDVBCIInterfaces *instance; eSmartPtrList m_slots; eDVBCISlot *getSlot(int slotid); PMTHandlerList m_pmt_handlers; + std::string m_language; + eFixedMessagePump m_messagepump_thread; // message handling in the thread + eFixedMessagePump m_messagepump_main; // message handling in the e2 mainloop + ePtr m_runTimer; // workaround to interrupt thread mainloop as some ci drivers don't implement poll properly + static pthread_mutex_t m_pmt_handler_lock; + bool m_ciplus_routing_active; + int m_ciplus_routing_tunernum; + std::string m_ciplus_routing_input; + std::string m_ciplus_routing_ci_input; + + int sendCAPMT(int slot); + + void thread(); + void gotMessageThread(const int &message); + void gotMessageMain(const int &message); + #ifndef SWIG public: #endif eDVBCIInterfaces(); ~eDVBCIInterfaces(); + static pthread_mutex_t m_slot_lock; + void addPMTHandler(eDVBServicePMTHandler *pmthandler); void removePMTHandler(eDVBServicePMTHandler *pmthandler); void recheckPMTHandlers(); + void executeRecheckPMTHandlersInMainloop(); void gotPMT(eDVBServicePMTHandler *pmthandler); void ciRemoved(eDVBCISlot *slot); int getSlotState(int slot); @@ -164,9 +196,12 @@ class eDVBCIInterfaces int answerEnq(int slot, char *value); int cancelEnq(int slot); int getMMIState(int slot); - int sendCAPMT(int slot); int setInputSource(int tunerno, const std::string &source); int setCIClockRate(int slot, int rate); + void setCIPlusRouting(int slotid); + void revertCIPlusRouting(int slotid); + bool canDescrambleMultipleServices(eDVBCISlot* slot); + std::string getLanguage() { return m_language; }; #ifdef SWIG public: #endif @@ -175,6 +210,32 @@ class eDVBCIInterfaces PyObject *getDescrambleRules(int slotid); RESULT setDescrambleRules(int slotid, SWIG_PYOBJECT(ePyObject) ); PyObject *readCICaIds(int slotid); + struct Message + { + enum + { + slotStateChanged, + mmiSessionDestroyed, + mmiDataReceived, + appNameChanged + }; + int m_type; + int m_slotid; + int m_state; + unsigned char m_tag[3]; + unsigned char m_data[4096]; + int m_len; + std::string m_appName; + Message(int type, int slotid): m_type(type), m_slotid(slotid) {}; + Message(int type, int slotid, int state): m_type(type), m_slotid(slotid), m_state(state) {}; + Message(int type, int slotid, std::string appName): m_type(type), m_slotid(slotid), m_appName(appName) {}; + Message(int type, int slotid, const unsigned char* tag, unsigned char* data, int len): m_type(type), m_slotid(slotid), m_len(len) + { + memcpy(m_tag, tag, 3); + memcpy(m_data, data, len); + }; + }; + }; #endif diff --git a/lib/dvb_ci/dvbci_app_mmi.cpp b/lib/dvb_ci/dvbci_app_mmi.cpp new file mode 100644 index 00000000000..b390977d23e --- /dev/null +++ b/lib/dvb_ci/dvbci_app_mmi.cpp @@ -0,0 +1,35 @@ +/* DVB CI Application MMI Manager */ + +#include +#include + +int eDVBCIApplicationMMISession::receivedAPDU(const unsigned char *tag,const void *data, int len) +{ + eTraceNoNewLine("[CI AMMI] SESSION(%d)/AMMI %02x %02x %02x: ", session_nb, tag[0], tag[1], tag[2]); + for (int i=0; i + +class eDVBCIApplicationMMISession: public eDVBCISession +{ + int receivedAPDU(const unsigned char *tag, const void *data, int len); + int doAction(); +public: +}; + +#endif diff --git a/lib/dvb_ci/dvbci_appmgr.cpp b/lib/dvb_ci/dvbci_appmgr.cpp index c09de27a024..96b832f8d0b 100644 --- a/lib/dvb_ci/dvbci_appmgr.cpp +++ b/lib/dvb_ci/dvbci_appmgr.cpp @@ -8,6 +8,7 @@ eDVBCIApplicationManagerSession::eDVBCIApplicationManagerSession(eDVBCISlot *tsl { slot = tslot; slot->setAppManager(this); + m_app_name = ""; } eDVBCIApplicationManagerSession::~eDVBCIApplicationManagerSession() @@ -17,10 +18,10 @@ eDVBCIApplicationManagerSession::~eDVBCIApplicationManagerSession() int eDVBCIApplicationManagerSession::receivedAPDU(const unsigned char *tag,const void *data, int len) { - eDebugNoNewLineStart("[CI AM] SESSION(%d)/APP %02x %02x %02x: ", session_nb, tag[0], tag[1], tag[2]); + eTraceNoNewLine("[CI AM] SESSION(%d)/APP %02x %02x %02x: ", session_nb, tag[0], tag[1], tag[2]); for (int i=0; i len) { - eDebugNoNewLine("[CI AM] warning, invalid length (%d vs %d)", dl+6, len); + eDebug("[CI AM] warning, invalid length (%d vs %d)", dl+6, len); dl=len-6; } char str[dl + 1]; memcpy(str, ((char*)data) + 6, dl); - if (dl > 0) - str[dl] = '\0'; //NOSONAR + str[dl] = '\0'; + eDebugNoNewLine("[CI AM] menu string: "); for (int i = 0; i < dl; ++i) eDebugNoNewLine("%c", ((unsigned char*)data)[i+6]); + eDebugNoNewLine("\n"); - eDVBCI_UI::getInstance()->setAppName(slot->getSlotID(), str); + m_app_name = str; + /* emit */ eDVBCI_UI::getInstance()->m_messagepump.send(eDVBCIInterfaces::Message(eDVBCIInterfaces::Message::appNameChanged, slot->getSlotID(), str)); - eDVBCI_UI::getInstance()->setState(slot->getSlotID(), 2); + /* emit */ eDVBCI_UI::getInstance()->m_messagepump.send(eDVBCIInterfaces::Message(eDVBCIInterfaces::Message::slotStateChanged, slot->getSlotID(), 2)); break; } default: - eDebug("[CI AM] unknown APDU tag 9F 80 %02x", tag[2]); + eWarning("[CI AM] unknown APDU tag 9F 80 %02x", tag[2]); break; } } diff --git a/lib/dvb_ci/dvbci_appmgr.h b/lib/dvb_ci/dvbci_appmgr.h index b86aa5335a0..0d22c1309e0 100644 --- a/lib/dvb_ci/dvbci_appmgr.h +++ b/lib/dvb_ci/dvbci_appmgr.h @@ -11,6 +11,8 @@ class eDVBCIApplicationManagerSession: public eDVBCISession eDVBCISlot *slot; + std::string m_app_name; + int wantmenu; int receivedAPDU(const unsigned char *tag, const void *data, int len); int doAction(); @@ -19,6 +21,7 @@ class eDVBCIApplicationManagerSession: public eDVBCISession ~eDVBCIApplicationManagerSession(); int enterMenu(); int startMMI(); + std::string getAppName() { return m_app_name; }; }; #endif diff --git a/lib/dvb_ci/dvbci_cam_upgrade.cpp b/lib/dvb_ci/dvbci_cam_upgrade.cpp new file mode 100644 index 00000000000..2d25906b649 --- /dev/null +++ b/lib/dvb_ci/dvbci_cam_upgrade.cpp @@ -0,0 +1,35 @@ +/* DVB CI CAM Firmware Upgrade Manager */ + +#include +#include + +int eDVBCICAMUpgradeSession::receivedAPDU(const unsigned char *tag,const void *data, int len) +{ + eTraceNoNewLine("[CI CAMUP] SESSION(%d)/CAMUP %02x %02x %02x: ", session_nb, tag[0], tag[1], tag[2]); + for (int i=0; i + +class eDVBCICAMUpgradeSession: public eDVBCISession +{ + int receivedAPDU(const unsigned char *tag, const void *data, int len); + int doAction(); +public: +}; + +#endif diff --git a/lib/dvb_ci/dvbci_camgr.cpp b/lib/dvb_ci/dvbci_camgr.cpp index d2dc3cca1cf..c5b81def13e 100644 --- a/lib/dvb_ci/dvbci_camgr.cpp +++ b/lib/dvb_ci/dvbci_camgr.cpp @@ -16,9 +16,10 @@ eDVBCICAManagerSession::~eDVBCICAManagerSession() int eDVBCICAManagerSession::receivedAPDU(const unsigned char *tag, const void *data, int len) { - eDebugNoNewLineStart("[CI CA] SESSION(%d)/CA %02x %02x %02x: ", session_nb, tag[0], tag[1],tag[2]); + eTraceNoNewLine("[CI CA] SESSION(%d)/CA %02x %02x %02x: ", session_nb, tag[0], tag[1], tag[2]); for (int i=0; irecheckPMTHandlers(); + eDebugNoNewLine("\n"); + eDVBCIInterfaces::getInstance()->executeRecheckPMTHandlersInMainloop(); break; default: - eDebug("[CI CA] unknown APDU tag 9F 80 %02x", tag[2]); + eWarning("[CI CA] unknown APDU tag 9F 80 %02x", tag[2]); break; } } @@ -46,18 +48,18 @@ int eDVBCICAManagerSession::doAction() { switch (state) { - case stateStarted: - { - const unsigned char tag[3]={0x9F, 0x80, 0x30}; // ca info enq - sendAPDU(tag); - state=stateFinal; - return 0; - } - case stateFinal: - eDebug("[CI CA] stateFinal und action! kann doch garnicht sein ;)"); - [[fallthrough]]; - default: - return 0; + case stateStarted: + { + const unsigned char tag[3]={0x9F, 0x80, 0x30}; // ca info enq + sendAPDU(tag); + state=stateFinal; + return 0; + } + case stateFinal: + eWarning("[CI CA] stateFinal and action should not happen"); + [[fallthrough]]; + default: + return 0; } } diff --git a/lib/dvb_ci/dvbci_ccmgr.cpp b/lib/dvb_ci/dvbci_ccmgr.cpp new file mode 100644 index 00000000000..bf03719f306 --- /dev/null +++ b/lib/dvb_ci/dvbci_ccmgr.cpp @@ -0,0 +1,951 @@ +/* DVB CI Content Control Manager */ + +#include + +#include +#include +#include + +#include + + +eDVBCICcSession::eDVBCICcSession(eDVBCISlot *slot, int version): + m_slot(slot), m_akh_index(0), + m_root_ca_store(nullptr), m_cust_cert(nullptr), m_device_cert(nullptr), + m_ci_cust_cert(nullptr), m_ci_device_cert(nullptr), + m_rsa_device_key(nullptr), m_dh(nullptr) +{ + uint8_t buf[32], host_id[8]; + + m_slot->setCCManager(this); + m_descrambler_fd = descrambler_init(); + parameter_init(m_dh_p, m_dh_g, m_dh_q, m_s_key, m_key_data, m_iv); + + m_ci_elements.init(); + + memset(buf, 0, 1); + if (!m_ci_elements.set(STATUS_FIELD, buf, 1)) + eWarning("[CI RCC] can not set status"); + + memset(buf, 0, 32); + buf[31] = 0x01; // URI_PROTOCOL_V1 + if (version == 2) + buf[31] |= 0x02; // URI_PROTOCOL_V2 + + if (!m_ci_elements.set(URI_VERSIONS, buf, 32)) + eWarning("[CI RCC] can not set uri_versions"); + + if (!get_authdata(host_id, m_dhsk, buf, m_slot->getSlotID(), m_akh_index)) + { + memset(buf, 0, sizeof(buf)); + m_akh_index = 5; + } + + if (!m_ci_elements.set(AKH, buf, 32)) + eWarning("[CI RCC] can not set AKH"); + + if (!m_ci_elements.set(HOST_ID, host_id, 8)) + eWarning("[CI RCC] can not set host_id"); +} + +eDVBCICcSession::~eDVBCICcSession() +{ + m_slot->setCCManager(0); + descrambler_deinit(m_descrambler_fd); + + if (m_root_ca_store) + X509_STORE_free(m_root_ca_store); + if (m_cust_cert) + X509_free(m_cust_cert); + if (m_device_cert) + X509_free(m_device_cert); + if (m_ci_cust_cert) + X509_free(m_ci_cust_cert); + if (m_ci_device_cert) + X509_free(m_ci_device_cert); + if (m_rsa_device_key) + RSA_free(m_rsa_device_key); + if (m_dh) + DH_free(m_dh); + + m_ci_elements.init(); +} + +int eDVBCICcSession::receivedAPDU(const unsigned char *tag, const void *data, int len) +{ + eTraceNoNewLineStart("[CI CC] SESSION(%d)/CC %02x %02x %02x: ", session_nb, tag[0], tag[1], tag[2]); + for (int i=0; i& pids) +{ + eDebugNoNewLineStart("[CI CC] SESSION(%d)/ADD PROGRAM %04x: ", session_nb, program_number); + for (std::vector::iterator it = pids.begin(); it != pids.end(); ++it) + eDebugNoNewLine("%02x ", *it); + eDebugNoNewLine("\n"); + + for (std::vector::iterator it = pids.begin(); it != pids.end(); ++it) + descrambler_set_pid(m_descrambler_fd, m_slot->getSlotID(), 1, *it); +} + +void eDVBCICcSession::removeProgram(uint16_t program_number, std::vector& pids) +{ + eDebugNoNewLineStart("[CI CC] SESSION(%d)/REMOVE PROGRAM %04x: ", session_nb, program_number); + for (std::vector::iterator it = pids.begin(); it != pids.end(); ++it) + eDebugNoNewLine("%02x ", *it); + eDebugNoNewLine("\n"); + + for (std::vector::iterator it = pids.begin(); it != pids.end(); ++it) + descrambler_set_pid(m_descrambler_fd, m_slot->getSlotID(), 0, *it); +} + +void eDVBCICcSession::cc_open_req() +{ + const uint8_t tag[3] = { 0x9f, 0x90, 0x02 }; + const uint8_t bitmap = 0x01; + send(tag, &bitmap, 1); +} + +void eDVBCICcSession::cc_data_req(const uint8_t *data, unsigned int len) +{ + uint8_t cc_data_cnf_tag[3] = { 0x9f, 0x90, 0x04 }; + uint8_t dest[BUFSIZ]; + int dt_nr; + int id_bitmask; + int answ_len; + unsigned int rp = 0; + + if (len < 2) + { + eWarning("[CI RCC] too short data"); + return; + } + + id_bitmask = data[rp++]; + + dt_nr = data[rp++]; + rp += data_get_loop(&data[rp], len - rp, dt_nr); + + if (len < rp + 1) + return; + + dt_nr = data[rp++]; + + unsigned int dest_len = sizeof(dest); + if (dest_len < 2) + { + eWarning("[CI RCC] not enough space"); + return; + } + + dest[0] = id_bitmask; + dest[1] = dt_nr; + + answ_len = data_req_loop(&dest[2], dest_len - 2, &data[rp], len - rp, dt_nr); + if (answ_len <= 0) + { + eWarning("[CI RCC] can not get data"); + return; + } + + answ_len += 2; + + send(cc_data_cnf_tag, dest, answ_len); +} + +void eDVBCICcSession::cc_sync_req(const uint8_t *data, unsigned int len) +{ + const uint8_t tag[3] = { 0x9f, 0x90, 0x06 }; + const uint8_t status = 0x00; /* OK */ + + send(tag, &status, 1); +} + +void eDVBCICcSession::cc_sac_data_req(const uint8_t *data, unsigned int len) +{ + const uint8_t data_cnf_tag[3] = { 0x9f, 0x90, 0x08 }; + uint8_t dest[BUFSIZ]; + uint8_t tmp[len]; + int id_bitmask, dt_nr; + unsigned int serial; + int answ_len; + int pos = 0; + unsigned int rp = 0; + + if (len < 10) + return; + + eTraceNoNewLineStart("[CI RCC] cc_sac_data_req: "); + traceHexdump(data, len); + + memcpy(tmp, data, 8); + sac_crypt(&tmp[8], &data[8], len - 8, AES_DECRYPT); + data = tmp; + + if (!sac_check_auth(data, len)) + { + eWarning("[CI RCC] check_auth of message failed"); + return; + } + + serial = UINT32(&data[rp], 4); + //eDebug("%u\n", serial); + + /* skip serial & header */ + rp += 8; + + id_bitmask = data[rp++]; + + /* handle data loop */ + dt_nr = data[rp++]; + rp += data_get_loop(&data[rp], len - rp, dt_nr); + + if (len < rp + 1) + { + eWarning("[CI RCC] check_auth of message too short"); + return; + } + + dt_nr = data[rp++]; + + /* create answer */ + unsigned int dest_len = sizeof(dest); + + if (dest_len < 10) + { + eWarning("[CI RCC] not enough space"); + return; + } + + pos += BYTE32(&dest[pos], serial); + pos += BYTE32(&dest[pos], 0x01000000); + + dest[pos++] = id_bitmask; + dest[pos++] = dt_nr; /* dt_nbr */ + + answ_len = data_req_loop(&dest[pos], dest_len - 10, &data[rp], len - rp, dt_nr); + if (answ_len <= 0) + { + eWarning("[CI RCC] can not get data"); + return; + } + pos += answ_len; + + cc_sac_send(data_cnf_tag, dest, pos); +} + +void eDVBCICcSession::cc_sac_sync_req(const uint8_t *data, unsigned int len) +{ + const uint8_t sync_cnf_tag[3] = { 0x9f, 0x90, 0x10 }; + uint8_t dest[64]; + unsigned int serial; + int pos = 0; + + eTraceNoNewLineStart("[CI RCC] cc_sac_sync_req: "); + traceHexdump(data, len); + + serial = UINT32(data, 4); + eTrace("[CI RCC] serial %u\n", serial); + + pos += BYTE32(&dest[pos], serial); + pos += BYTE32(&dest[pos], 0x01000000); + + /* status OK */ + dest[pos++] = 0; + + cc_sac_send(sync_cnf_tag, dest, pos); +} + +void eDVBCICcSession::cc_sac_send(const uint8_t *tag, uint8_t *data, unsigned int pos) +{ + if (pos < 8) + { + eWarning("[CI RCC] too short data"); + return; + } + + pos += add_padding(&data[pos], pos - 8, 16); + BYTE16(&data[6], pos - 8); /* len in header */ + + pos += sac_gen_auth(&data[pos], data, pos); + sac_crypt(&data[8], &data[8], pos - 8, AES_ENCRYPT); + + send(tag, data, pos); + + return; +} + +int eDVBCICcSession::data_get_loop(const uint8_t *data, unsigned int datalen, unsigned int items) +{ + unsigned int i; + int dt_id, dt_len; + unsigned int pos = 0; + + for (i = 0; i < items; i++) + { + if (pos + 3 > datalen) + return 0; + + dt_id = data[pos++]; + dt_len = data[pos++] << 8; + dt_len |= data[pos++]; + + if (pos + dt_len > datalen) + return 0; + + eTraceNoNewLineStart("[CI RCC] set element %d: ", dt_id); + traceHexdump(&data[pos], dt_len); + + m_ci_elements.set(dt_id, &data[pos], dt_len); + + data_get_handle_new(dt_id); + + pos += dt_len; + } + + return pos; +} + +int eDVBCICcSession::data_req_loop(uint8_t *dest, unsigned int dest_len, const uint8_t *data, unsigned int data_len, unsigned int items) +{ + int dt_id; + unsigned int i; + int pos = 0; + unsigned int len; + + if (items > data_len) + return -1; + + for (i = 0; i < items; i++) + { + dt_id = data[i]; + data_req_handle_new(dt_id); /* check if there is any action needed before we answer */ + + len = m_ci_elements.get_buf(NULL, dt_id); + if ((len + 3) > dest_len) + { + eWarning("[CI RCC] req element %d: not enough space", dt_id); + return -1; + } + + len = m_ci_elements.get_req(dest, dt_id); + if (len > 0) + { + eTraceNoNewLineStart("[CI RCC] req element %d: ", dt_id); + traceHexdump(&dest[3], len - 3); + } + + pos += len; + dest += len; + dest_len -= len; + } + + return pos; +} + +int eDVBCICcSession::data_get_handle_new(unsigned int id) +{ + switch (id) + { + case CICAM_BRAND_CERT: + case DHPM: + case CICAM_DEV_CERT: +// case CICAM_ID: + case SIGNATURE_B: + if (check_ci_certificates()) + break; + + check_dh_challenge(); + break; + + case AUTH_NONCE: + restart_dh_challenge(); + break; + + case NS_MODULE: + generate_ns_host(); + generate_key_seed(); + generate_SAK_SEK(); + break; + + case CICAM_ID: + case KP: + case KEY_REGISTER: + check_new_key(); + break; + + case PROGRAM_NUMBER: + case URI_MESSAGE: + generate_uri_confirm(); + break; + + default: + eWarning("[CI RCC] unhandled id %u", id); + break; + } + + return 0; +} + +int eDVBCICcSession::data_req_handle_new(unsigned int id) +{ + switch (id) + { + case 22: + { + uint8_t akh[32], host_id[8]; + + memset(akh, 0, sizeof(akh)); + + if (m_akh_index != 5) + { + if (!get_authdata(host_id, m_dhsk, akh, m_slot->getSlotID(), m_akh_index++)) + m_akh_index = 5; + + if (!m_ci_elements.set(AKH, akh, 32)) + eWarning("[CI RCC] can not set AKH in elements"); + + if (!m_ci_elements.set(HOST_ID, host_id, 8)) + eWarning("[CI RCC] can not set host_id in elements"); + } + break; + } + default: + break; + } + + return 0; +} + +int eDVBCICcSession::generate_akh() +{ + uint8_t akh[32]; + SHA256_CTX sha; + + SHA256_Init(&sha); + SHA256_Update(&sha, m_ci_elements.get_ptr(CICAM_ID), m_ci_elements.get_buf(NULL, CICAM_ID)); + SHA256_Update(&sha, m_ci_elements.get_ptr(HOST_ID), m_ci_elements.get_buf(NULL, HOST_ID)); + SHA256_Update(&sha, m_dhsk, 256); + SHA256_Final(akh, &sha); + + m_ci_elements.set(AKH, akh, sizeof(akh)); + + return 0; +} + +int eDVBCICcSession::compute_dh_key() +{ + int len = DH_size(m_dh); + if (len > 256) + { + eWarning("[CI RCC] too long shared key"); + return -1; + } + + BIGNUM *bn_in = BN_bin2bn(m_ci_elements.get_ptr(DHPM), 256, NULL); + +#if 0 + // verify DHPM + BN_CTX *ctx = BN_CTX_new(); + BIGNUM *out = BN_new(); + + if (BN_cmp(BN_value_one(), bn_in) >= 0) + eWarning("[CI RCC] DHPM <= 1!!!"); + + if (BN_cmp(bn_in, m_dh->p) >= 0) + eWarning("[CI RCC] DHPM >= dh_p!!!"); + + BN_mod_exp(out, bn_in, m_dh->q, m_dh->p, ctx); + if (BN_cmp(out, BN_value_one()) != 0) + eWarning("[CI RCC] DHPM ^ dh_q mod dh_p != 1!!!"); + + BN_free(out); + BN_CTX_free(ctx); +#endif + + int codes = 0; + int ok = DH_check_pub_key(m_dh, bn_in, &codes); + if (ok == 0) + eDebug("[CI RCC] check_pub_key failed"); + if (codes & DH_CHECK_PUBKEY_TOO_SMALL) + eDebug("[CI RCC] too small public key"); + if (codes & DH_CHECK_PUBKEY_TOO_LARGE) + eDebug("[CI RCC] too large public key"); + + int gap = 256 - len; + memset(m_dhsk, 0, gap); + DH_compute_key(m_dhsk + gap, bn_in, m_dh); + + BN_free(bn_in); + + return 0; +} + +bool eDVBCICcSession::check_dh_challenge() +{ + if (!m_ci_elements.valid(AUTH_NONCE)) + return false; + + if (!m_ci_elements.valid(CICAM_ID)) + return false; + + if (!m_ci_elements.valid(DHPM)) + return false; + + if (!m_ci_elements.valid(SIGNATURE_B)) + return false; + + compute_dh_key(); + generate_akh(); + + m_akh_index = 5; + + eDebug("[CI RCC] writing..."); + write_authdata(m_slot->getSlotID(), m_ci_elements.get_ptr(HOST_ID), m_dhsk, m_ci_elements.get_ptr(AKH)); + + return true; +} + +int eDVBCICcSession::generate_dh_key() +{ + uint8_t dhph[256]; + int len; + unsigned int gap; + BIGNUM *p, *g , *q; + const BIGNUM *pub_key; + + m_dh = DH_new(); + + p = BN_bin2bn(m_dh_p, sizeof(m_dh_p), 0); + g = BN_bin2bn(m_dh_g, sizeof(m_dh_g), 0); + q = BN_bin2bn(m_dh_q, sizeof(m_dh_q), 0); + DH_set0_pqg(m_dh, p, q, g); + DH_set_flags(m_dh, DH_FLAG_NO_EXP_CONSTTIME); + + DH_generate_key(m_dh); + + DH_get0_key(m_dh, &pub_key, NULL); + len = BN_num_bytes(pub_key); + if (len > 256) + { + eWarning("[CI RCC] too long public key"); + return -1; + } + +#if 0 + // verify DHPH + BN_CTX *ctx = BN_CTX_new(); + BIGNUM *out = BN_new(); + + if (BN_cmp(BN_value_one(), m_dh->pub_key) >= 0) + eWarning("[CI RCC] DHPH <= 1!!!"); + if (BN_cmp(m_dh->pub_key, m_dh->p) >= 0) + eWarning("[CI RCC] DHPH >= dh_p!!!"); + BN_mod_exp(out, m_dh->pub_key, m_dh->q, m_dh->p, ctx); + if (BN_cmp(out, BN_value_one()) != 0) + eWarning("[CI RCC] DHPH ^ dh_q mod dh_p != 1!!!"); + + BN_free(out); + BN_CTX_free(ctx); +#endif + + gap = 256 - len; + memset(dhph, 0, gap); + BN_bn2bin(pub_key, &dhph[gap]); + + m_ci_elements.set(DHPH, dhph, sizeof(dhph)); + + return 0; +} + +int eDVBCICcSession::generate_sign_A() +{ + unsigned char dest[302]; + uint8_t hash[20]; + unsigned char dbuf[256]; + unsigned char sign_A[256]; + + if (!m_ci_elements.valid(AUTH_NONCE)) + return -1; + + if (!m_ci_elements.valid(DHPH)) + return -1; + + dest[0x00] = 0x00; /* version */ + dest[0x01] = 0x00; + dest[0x02] = 0x08; /* len (bits) */ + dest[0x03] = 0x01; /* version data */ + + dest[0x04] = 0x01; /* msg_label */ + dest[0x05] = 0x00; + dest[0x06] = 0x08; /* len (bits) */ + dest[0x07] = 0x02; /* message data */ + + dest[0x08] = 0x02; /* auth_nonce */ + dest[0x09] = 0x01; + dest[0x0a] = 0x00; /* len (bits) */ + memcpy(&dest[0x0b], m_ci_elements.get_ptr(AUTH_NONCE), 32); + + dest[0x2b] = 0x04; /* DHPH */ + dest[0x2c] = 0x08; + dest[0x2d] = 0x00; /* len (bits) */ + memcpy(&dest[0x2e], m_ci_elements.get_ptr(DHPH), 256); + + SHA1(dest, 0x12e, hash); + + m_rsa_device_key = rsa_privatekey_open("/etc/ciplus/device.pem"); + if (!m_rsa_device_key) + { + eWarning("[CI RCC] can not read private key"); + return -1; + } + + RSA_padding_add_PKCS1_PSS(m_rsa_device_key, dbuf, hash, EVP_sha1(), 20); + RSA_private_encrypt(sizeof(dbuf), dbuf, sign_A, m_rsa_device_key, RSA_NO_PADDING); + + m_ci_elements.set(SIGNATURE_A, sign_A, sizeof(sign_A)); + + return 0; +} + +int eDVBCICcSession::restart_dh_challenge() +{ + if (!m_ci_elements.valid(AUTH_NONCE)) + return -1; + + //eDebug("[CI RCC] rechecking..."); + + m_root_ca_store = X509_STORE_new(); + if (!m_root_ca_store) + { + eWarning("[CI RCC] can not create root_ca"); + return -1; + } + + if (X509_STORE_load_locations(m_root_ca_store, "/etc/ciplus/root.pem", NULL) != 1) + { + eWarning("[CI RCC] can not load root_ca"); + return -1; + } + + m_cust_cert = certificate_load_and_check(m_root_ca_store, "/etc/ciplus/customer.pem"); + m_device_cert = certificate_load_and_check(m_root_ca_store, "/etc/ciplus/device.pem"); + + if (!m_cust_cert || !m_device_cert) + { + eWarning("[CI RCC] can not check loader certificates"); + return -1; + } + + if (!ci_element_set_certificate(HOST_BRAND_CERT, m_cust_cert)) + eWarning("[CI RCC] can not store brand certificate"); + + if (!ci_element_set_certificate(HOST_DEV_CERT, m_device_cert)) + eWarning("[CI RCC] can not store device certificate"); + + if (!ci_element_set_hostid_from_certificate(HOST_ID, m_device_cert)) + eWarning("[CI RCC] can not store HOST_ID"); + + m_ci_elements.invalidate(CICAM_ID); + m_ci_elements.invalidate(DHPM); + m_ci_elements.invalidate(SIGNATURE_B); + m_ci_elements.invalidate(AKH); + + generate_dh_key(); + generate_sign_A(); + + return 0; +} + +int eDVBCICcSession::generate_uri_confirm() +{ + SHA256_CTX sha; + uint8_t uck[32]; + uint8_t uri_confirm[32]; + + //eDebug("[CI RCC] uri_confirm..."); + + // UCK + SHA256_Init(&sha); + SHA256_Update(&sha, m_sak, 16); + SHA256_Final(uck, &sha); + + // uri_confirm + SHA256_Init(&sha); + SHA256_Update(&sha, m_ci_elements.get_ptr(URI_MESSAGE), m_ci_elements.get_buf(NULL, URI_MESSAGE)); + SHA256_Update(&sha, uck, 32); + SHA256_Final(uri_confirm, &sha); + + m_ci_elements.set(URI_CONFIRM, uri_confirm, 32); + + return 0; +} + +void eDVBCICcSession::check_new_key() +{ + AES_KEY aes_ctx; + uint8_t dec[32]; + uint8_t *kp; + uint8_t slot; + unsigned int i; + + if (!m_ci_elements.valid(KP)) + return; + + if (!m_ci_elements.valid(KEY_REGISTER)) + return; + + //eDebug("[CI RCC] key checking..."); + + kp = m_ci_elements.get_ptr(KP); + m_ci_elements.get_buf(&slot, KEY_REGISTER); + + AES_set_encrypt_key(m_s_key, 128, &aes_ctx); + for (i = 0; i < 32; i += 16) + AES_ecb_encrypt(&kp[i], &dec[i], &aes_ctx, 1); + + for (i = 0; i < 32; i++) + dec[i] ^= kp[i]; + + if (slot != 0 && slot != 1) + slot = 1; + + descrambler_set_key(m_descrambler_fd, m_slot->getSlotID(), slot, dec); + + m_ci_elements.invalidate(KP); + m_ci_elements.invalidate(KEY_REGISTER); +} + +void eDVBCICcSession::generate_key_seed() +{ + SHA256_CTX sha; + + SHA256_Init(&sha); + SHA256_Update(&sha, &m_dhsk[240], 16); + SHA256_Update(&sha, m_ci_elements.get_ptr(AKH), m_ci_elements.get_buf(NULL, AKH)); + SHA256_Update(&sha, m_ci_elements.get_ptr(NS_HOST), m_ci_elements.get_buf(NULL, NS_HOST)); + SHA256_Update(&sha, m_ci_elements.get_ptr(NS_MODULE), m_ci_elements.get_buf(NULL, NS_MODULE)); + SHA256_Final(m_ks_host, &sha); +} + +void eDVBCICcSession::generate_ns_host() +{ + uint8_t buf[8]; + get_random(buf, sizeof(buf)); + m_ci_elements.set(NS_HOST, buf, sizeof(buf)); +} + +int eDVBCICcSession::generate_SAK_SEK() +{ + AES_KEY key; + uint8_t dec[32]; + int i; + + AES_set_encrypt_key(m_key_data, 128, &key); + + for (i = 0; i < 2; i++) + AES_ecb_encrypt(&m_ks_host[16 * i], &dec[16 * i], &key, 1); + + for (i = 0; i < 16; i++) + m_sek[i] = m_ks_host[i] ^ dec[i]; + + for (i = 0; i < 16; i++) + m_sak[i] = m_ks_host[16 + i] ^ dec[16 + i]; + + return 0; +} + +bool eDVBCICcSession::sac_check_auth(const uint8_t *data, unsigned int len) +{ + struct aes_xcbc_mac_ctx ctx; + uint8_t calced_signature[16]; + + if (len < 16) + { + eWarning("[CI RCC] signature too short"); + return false; + } + + aes_xcbc_mac_init(&ctx, m_sak); + aes_xcbc_mac_process(&ctx, (uint8_t *)"\x04", 1); /* header len */ + aes_xcbc_mac_process(&ctx, data, len - 16); + aes_xcbc_mac_done(&ctx, calced_signature); + + if (memcmp(&data[len - 16], calced_signature, 16)) + { + eWarning("[CI RCC] signature wrong"); + return false; + } + + //eDebug("[CI RCC] auth ok!"); + + return true; +} + +int eDVBCICcSession::sac_gen_auth(uint8_t *out, uint8_t *in, unsigned int len) +{ + struct aes_xcbc_mac_ctx ctx; + + aes_xcbc_mac_init(&ctx, m_sak); + aes_xcbc_mac_process(&ctx, (uint8_t *)"\x04", 1); /* header len */ + aes_xcbc_mac_process(&ctx, in, len); + aes_xcbc_mac_done(&ctx, out); + + return 16; +} + +int eDVBCICcSession::sac_crypt(uint8_t *dst, const uint8_t *src, unsigned int len, int encrypt) +{ + AES_KEY key; + uint8_t iv[16]; + memcpy(iv, m_iv, 16); // use copy as iv is changed by AES_cbc_encrypt + + if (encrypt) + AES_set_encrypt_key(m_sek, 128, &key); + else + AES_set_decrypt_key(m_sek, 128, &key); + + AES_cbc_encrypt(src, dst, len, &key, iv, encrypt); + + return 0; +} + +X509 *eDVBCICcSession::import_ci_certificates(unsigned int id) +{ + X509 *cert; + + if (!m_ci_elements.valid(id)) + { + eWarning("[CI RCC] %u not valid", id); + return NULL; + } + + cert = certificate_import_and_check(m_root_ca_store, m_ci_elements.get_ptr(id), m_ci_elements.get_buf(NULL, id)); + if (!cert) + { + eWarning("[CI RCC] can not verify certificate %u", id); + return NULL; + } + + return cert; +} + +int eDVBCICcSession::check_ci_certificates() +{ + if (!m_ci_elements.valid(CICAM_BRAND_CERT)) + return -1; + + if (!m_ci_elements.valid(CICAM_DEV_CERT)) + return -1; + + if ((m_ci_cust_cert = import_ci_certificates(CICAM_BRAND_CERT)) == NULL) + { + eWarning("[CI RCC] can not import CICAM brand certificate"); + return -1; + } + + if ((m_ci_device_cert = import_ci_certificates(CICAM_DEV_CERT)) == NULL) + { + eWarning("[CI RCC] can not import CICAM device certificate"); + return -1; + } + + if (!ci_element_set_hostid_from_certificate(CICAM_ID, m_ci_device_cert)) + { + eWarning("[CI RCC] can not store CICAM_ID"); + return -1; + } + + return 0; +} + +bool eDVBCICcSession::ci_element_set_certificate(unsigned int id, X509 *cert) +{ + unsigned char *cert_der = NULL; + int cert_len; + + cert_len = i2d_X509(cert, &cert_der); + if (cert_len <= 0) + { + eWarning("[CI RCC] can not encode certificate"); + return false; + } + + if (!m_ci_elements.set(id, cert_der, cert_len)) { + eWarning("[CI RCC] can not store certificate id %u", id); + return false; + } + + OPENSSL_free(cert_der); + + return true; +} + +bool eDVBCICcSession::ci_element_set_hostid_from_certificate(unsigned int id, X509 *cert) +{ + X509_NAME *subject; + char hostid[16 + 1]; + uint8_t bin_hostid[8]; + + if ((id != 5) && (id != 6)) + { + eWarning("[CI RCC] wrong datatype_id %u for device id", id); + return false; + } + + subject = X509_get_subject_name(cert); + X509_NAME_get_text_by_NID(subject, NID_commonName, hostid, sizeof(hostid)); + + if (strlen(hostid) != 16) + { + eWarning("[CI RCC] bad device id"); + return false; + } + + //eDebug("[CI RCC] DEVICE_ID: %s", hostid); + + str2bin(bin_hostid, hostid, 16); + + if (!m_ci_elements.set(id, bin_hostid, sizeof(bin_hostid))) + { + eWarning("[CI RCC] can not store device id %u", id); + return false; + } + + return true; +} diff --git a/lib/dvb_ci/dvbci_ccmgr.h b/lib/dvb_ci/dvbci_ccmgr.h new file mode 100644 index 00000000000..61efe6a75e6 --- /dev/null +++ b/lib/dvb_ci/dvbci_ccmgr.h @@ -0,0 +1,290 @@ +#ifndef __dvbci_dvbci_ccmgr_h +#define __dvbci_dvbci_ccmgr_h + +#include +#include +#include + +#include +void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key); +int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g); +void DH_set_flags(DH *dh, int flags); + +class eDVBCICcSessionImpl; + +class eDVBCICcSession: public eDVBCISession +{ + eDVBCISlot *m_slot; + int m_descrambler_fd; + + // CI+ credentials + enum + { + BRAND_ID = 1, + + HOST_ID = 5, + CICAM_ID = 6, + HOST_BRAND_CERT = 7, + CICAM_BRAND_CERT = 8, + + KP = 12, + DHPH = 13, + DHPM = 14, + HOST_DEV_CERT = 15, + CICAM_DEV_CERT = 16, + SIGNATURE_A = 17, + SIGNATURE_B = 18, + AUTH_NONCE = 19, + NS_HOST = 20, + NS_MODULE = 21, + AKH = 22, + AKM = 23, + + URI_MESSAGE = 25, + PROGRAM_NUMBER = 26, + URI_CONFIRM = 27, + KEY_REGISTER = 28, + URI_VERSIONS = 29, + STATUS_FIELD = 30, + SRM_DATA = 31, + SRM_CONFIRM = 32, + + MAX_ELEMENTS = 33 + }; + + struct ciplus_element + { + uint8_t *m_data = NULL; + uint32_t m_size; + bool m_valid; + void init() + { + invalidate(); + }; + void invalidate() + { + if (m_data) + free(m_data); + m_data = NULL; + m_size = 0; + m_valid = false; + }; + void set(const uint8_t *data, uint32_t size) + { + if (m_data) + free(m_data); + m_data = (uint8_t *)malloc(size); + if (m_data) + { + memcpy(m_data, data, size); + m_size = size; + m_valid = true; + } + else + { + m_size = 0; + m_valid = false; + } + }; + }; + + struct ciplus_elements + { + ciplus_element m_elements[MAX_ELEMENTS]; + const uint32_t m_datatype_sizes[MAX_ELEMENTS] = { + 0, 50, 0, 0, 0, 8, 8, 0, + 0, 0, 0, 0, 32, 256, 256, 0, + 0, 256, 256, 32, 8, 8, 32, 32, + 0, 8, 2, 32, 1, 32, 1, 0, + 32 + }; + void init() + { + unsigned int i; + + for (i = 1; i < MAX_ELEMENTS; i++) + m_elements[i].invalidate(); + }; + struct ciplus_element* get(unsigned int id) + { + if ((id < 1) || (id >= MAX_ELEMENTS)) + { + eWarning("[CI RCC] invalid id %u", id); + return NULL; + } + return &m_elements[id]; + }; + uint8_t* get_ptr(unsigned int id) + { + struct ciplus_element *e = get(id); + if (e == NULL) + return NULL; + + if (!e->m_valid) + { + eWarning("[CI RCC] %u not valid", id); + return NULL; + } + + if (!e->m_data) + { + eWarning("[CI RCC] %u doesn't exist", id); + return NULL; + } + + return e->m_data; + }; + unsigned int get_buf(uint8_t *dest, unsigned int id) + { + struct ciplus_element *e = get(id); + if (e == NULL) + return 0; + + if (!e->m_valid) + { + eWarning("[CI RCC] %u not valid", id); + return 0; + } + + if (!e->m_data) + { + eWarning("[CI RCC] %d doesn't exist", id); + return 0; + } + + if (dest) + memcpy(dest, e->m_data, e->m_size); + + return e->m_size; + }; + unsigned int get_req(uint8_t *dest, unsigned int id) + { + unsigned int len = get_buf(&dest[3], id); + + if (len == 0) + { + eWarning("[CI RCC] can not get %u", id); + return 0; + } + + dest[0] = id; + dest[1] = len >> 8; + dest[2] = len; + + return 3 + len; + }; + bool set(unsigned int id, const uint8_t *data, uint32_t size) + { + struct ciplus_element *e = get(id); + if (!e) + return false; + + if ((m_datatype_sizes[id] != 0) && (m_datatype_sizes[id] != size)) + { + eWarning("[CI RCC] size %u of id %u doesn't match", size, id); + return false; + } + + e->set(data, size); + + return e->m_valid; + }; + void invalidate(unsigned int id) + { + struct ciplus_element *e = get(id); + if (e) + e->invalidate(); + }; + bool valid(unsigned int id) + { + struct ciplus_element *e = get(id); + return e && e->m_valid; + }; + } m_ci_elements; + + /* DHSK */ + uint8_t m_dhsk[256]; + + /* KS_host */ + uint8_t m_ks_host[32]; + + /* derived keys */ + uint8_t m_sek[16]; + uint8_t m_sak[16]; + + /* AKH checks - module performs 5 tries to get correct AKH */ + unsigned int m_akh_index; + + /* Root CA */ + X509_STORE *m_root_ca_store; + + /* Host certificates */ + X509 *m_cust_cert; + X509 *m_device_cert; + + /* Module certificates */ + X509 *m_ci_cust_cert; + X509 *m_ci_device_cert; + + /* private key of device-cert */ + RSA *m_rsa_device_key; + + /* DH parameters */ + DH *m_dh; + uint8_t m_dh_p[256]; + uint8_t m_dh_g[256]; + uint8_t m_dh_q[32]; + + /* AES parameters */ + uint8_t m_s_key[16]; + uint8_t m_key_data[16]; + uint8_t m_iv[16]; + + int receivedAPDU(const unsigned char *tag, const void *data, int len); + int doAction(); + + void cc_open_req(); + void cc_data_req(const uint8_t *data, unsigned int len); + void cc_sync_req(const uint8_t *data, unsigned int len); + void cc_sac_data_req(const uint8_t *data, unsigned int len); + void cc_sac_sync_req(const uint8_t *data, unsigned int len); + void cc_sac_send(const uint8_t *tag, uint8_t *data, unsigned int pos); + + int data_get_loop(const uint8_t *data, unsigned int datalen, unsigned int items); + int data_req_loop(uint8_t *dest, unsigned int dest_len, const uint8_t *data, unsigned int data_len, unsigned int items); + + int data_req_handle_new(unsigned int id); + int data_get_handle_new(unsigned int id); + + void generate_key_seed(); + void generate_ns_host(); + int generate_SAK_SEK(); + int generate_akh(); + bool check_dh_challenge(); + int compute_dh_key(); + int generate_dh_key(); + int generate_sign_A(); + int restart_dh_challenge(); + int generate_uri_confirm(); + void check_new_key(); + + bool sac_check_auth(const uint8_t *data, unsigned int len); + int sac_gen_auth(uint8_t *out, uint8_t *in, unsigned int len); + int sac_crypt(uint8_t *dst, const uint8_t *src, unsigned int len, int encrypt); + + X509 *import_ci_certificates(unsigned int id); + int check_ci_certificates(); + + bool ci_element_set_certificate(unsigned int id, X509 *cert); + bool ci_element_set_hostid_from_certificate(unsigned int id, X509 *cert); + +public: + eDVBCICcSession(eDVBCISlot *tslot, int version); + ~eDVBCICcSession(); + + void send(const unsigned char *tag, const void *data, int len); + void addProgram(uint16_t program_number, std::vector& pids); + void removeProgram(uint16_t program_number, std::vector& pids); +}; + +#endif diff --git a/lib/dvb_ci/dvbci_ccmgr_helper.cpp b/lib/dvb_ci/dvbci_ccmgr_helper.cpp new file mode 100644 index 00000000000..80928975fa5 --- /dev/null +++ b/lib/dvb_ci/dvbci_ccmgr_helper.cpp @@ -0,0 +1,435 @@ +#include +#include +#include + +#include + +#include + + +// misc helper functions + +void traceHexdump(const uint8_t *data, unsigned int len) +{ + while (len--) + eTraceNoNewLine("%02x ", *data++); + eTraceNoNewLine("\n"); +} + +int get_random(uint8_t *dest, int len) +{ + int fd; + const char *urnd = "/dev/urandom"; + + fd = open(urnd, O_RDONLY); + if (fd <= 0) + { + eWarning("[CI RCC] cannot open %s", urnd); + return -1; + } + + if (read(fd, dest, len) != len) + { + eWarning("[CI RCC] cannot read from %s", urnd); + close(fd); + return -2; + } + + close(fd); + + return len; +} + +int add_padding(uint8_t *dest, unsigned int len, unsigned int blocklen) +{ + uint8_t padding = 0x80; + int count = 0; + + while (len & (blocklen - 1)) + { + *dest++ = padding; + ++len; + ++count; + padding = 0; + } + + return count; +} + +int get_bin_from_nibble(int in) +{ + if ((in >= '0') && (in <= '9')) + return in - 0x30; + + if ((in >= 'A') && (in <= 'Z')) + return in - 0x41 + 10; + + if ((in >= 'a') && (in <= 'z')) + return in - 0x61 + 10; + + eWarning("[CI RCC] unsupported chars in device id"); + + return 0; +} + +void str2bin(uint8_t *dst, char *data, int len) +{ + int i; + + for (i = 0; i < len; i += 2) + *dst++ = (get_bin_from_nibble(data[i]) << 4) | get_bin_from_nibble(data[i + 1]); +} + +uint32_t UINT32(const uint8_t *in, unsigned int len) +{ + uint32_t val = 0; + unsigned int i; + + for (i = 0; i < len; i++) + { + val <<= 8; + val |= *in++; + } + + return val; +} + +int BYTE32(uint8_t *dest, uint32_t val) +{ + *dest++ = val >> 24; + *dest++ = val >> 16; + *dest++ = val >> 8; + *dest++ = val; + + return 4; +} + +int BYTE16(uint8_t *dest, uint16_t val) +{ + *dest++ = val >> 8; + *dest++ = val; + return 2; +} + +// storage & load of authenticated data (HostID & DHSK & AKH) + +#ifndef FILENAME_MAX +#define FILENAME_MAX 256 +#endif +#define MAX_PAIRS 10 +#define PAIR_SIZE (8 + 256 + 32) + +void get_authdata_filename(char *dest, size_t len, unsigned int slot) +{ + snprintf(dest, len, "/etc/ciplus/ci_auth_slot_%u.bin", slot); +} + +bool get_authdata(uint8_t *host_id, uint8_t *dhsk, uint8_t *akh, unsigned int slot, unsigned int index) +{ + char filename[FILENAME_MAX]; + int fd; + uint8_t chunk[PAIR_SIZE]; + unsigned int i; + + if (index >= MAX_PAIRS) + return false; + + get_authdata_filename(filename, sizeof(filename), slot); + + fd = open(filename, O_RDONLY); + if (fd <= 0) + { + eDebug("[CI RCC] can not open %s", filename); + return false; + } + + for (i = 0; i <= index; i++) + { + if (read(fd, chunk, sizeof(chunk)) != sizeof(chunk)) + { + eDebug("[CI RCC] can not read auth_data"); + close(fd); + return false; + } + } + + close(fd); + + memcpy(host_id, chunk, 8); + memcpy(dhsk, &chunk[8], 256); + memcpy(akh, &chunk[8 + 256], 32); + + return true; +} + +bool write_authdata(unsigned int slot, const uint8_t *host_id, const uint8_t *dhsk, const uint8_t *akh) +{ + char filename[FILENAME_MAX]; + int fd; + uint8_t buf[PAIR_SIZE * MAX_PAIRS]; + int entries; + + for (entries = 0; entries < MAX_PAIRS; entries++) + { + int offset = PAIR_SIZE * entries; + if (!get_authdata(&buf[offset], &buf[offset + 8], &buf[offset + 8 + 256], slot, entries)) + break; + + /* check if we got this pair already */ + if (!memcmp(&buf[offset + 8 + 256], akh, 32)) + { + eDebug("[CI RCC] data already stored"); + return true; + } + } + + if (entries > 0) + { + if (entries == MAX_PAIRS) + entries--; + + memmove(buf + PAIR_SIZE, buf, PAIR_SIZE * entries); + } + + memcpy(buf, host_id, 8); + memcpy(buf + 8, dhsk, 256); + memcpy(buf + 8 + 256, akh, 32); + entries++; + + eDebug("[CI RCC] %d entries for writing", entries); + + get_authdata_filename(filename, sizeof(filename), slot); + fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); + if (fd < 0) + { + eWarning("[CI RCC] can not open %s", filename); + return false; + } + + if (write(fd, buf, PAIR_SIZE * entries) != PAIR_SIZE * entries) + eWarning("[CI RCC] error in write"); + + close(fd); + + return true; +} + +bool parameter_init(uint8_t* dh_p, uint8_t* dh_g, uint8_t* dh_q, uint8_t* s_key, uint8_t* key_data, uint8_t* iv) +{ + int fd; + unsigned char buf[592]; + + fd = open("/etc/ciplus/param", O_RDONLY); + if (fd <= 0) + { + eDebug("[CI RCC] can not param file"); + return false; + } + + if (read(fd, buf, sizeof(buf)) != sizeof(buf)) + { + eDebug("[CI RCC] can not read parameters"); + close(fd); + return false; + } + + close(fd); + + memcpy(dh_p, buf, 256); + memcpy(dh_g, &buf[256], 256); + memcpy(dh_q, &buf[512], 32); + memcpy(s_key, &buf[544], 16); + memcpy(key_data, &buf[560], 16); + memcpy(iv, &buf[576], 16); + + return true; +} + +// CI+ certificates + +RSA *rsa_privatekey_open(const char *filename) +{ + FILE *fp; + RSA *r = NULL; + + fp = fopen(filename, "r"); + if (!fp) + { + eWarning("[CI RCC] can not open %s", filename); + return NULL; + } + + PEM_read_RSAPrivateKey(fp, &r, NULL, NULL); + if (!r) + eWarning("[CI RCC] can not read %s", filename); + + fclose(fp); + + return r; +} + +X509 *certificate_open(const char *filename) +{ + FILE *fp; + X509 *cert; + + fp = fopen(filename, "r"); + if (!fp) + { + eWarning("[CI RCC] can not open %s", filename); + return NULL; + } + + cert = PEM_read_X509(fp, NULL, NULL, NULL); + if (!cert) + eWarning("[CI RCC] can not read %s", filename); + + fclose(fp); + + return cert; +} + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) +{ + /* If the fields p and g in d are NULL, the corresponding input + * parameters MUST be non-NULL. q may remain NULL. + */ + if ((dh->p == NULL && p == NULL) || (dh->g == NULL && g == NULL)) + return 0; + + if (p != NULL) + { + BN_free(dh->p); + dh->p = p; + } + if (q != NULL) + { + BN_free(dh->q); + dh->q = q; + } + if (g != NULL) + { + BN_free(dh->g); + dh->g = g; + } + + if (q != NULL) + { + dh->length = BN_num_bits(q); + } + + return 1; +} + +void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) +{ + if (pub_key != NULL) + *pub_key = dh->pub_key; + if (priv_key != NULL) + *priv_key = dh->priv_key; +} + +void DH_set_flags(DH *dh, int flags) +{ + dh->flags |= flags; +} +#endif + +int verify_cb(int ok, X509_STORE_CTX *ctx) +{ + if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_NOT_YET_VALID) + { + time_t now = time(NULL); + struct tm t; + localtime_r(&now, &t); + if (t.tm_year < 2023) + { + eDebug("[CI RCC] seems our system clock is wrong - ignore!"); + return 1; + } + } + + if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_HAS_EXPIRED) + return 1; + + return 0; +} + +bool certificate_validate(X509_STORE *store, X509 *cert) +{ + X509_STORE_CTX *store_ctx; + int ret; + + store_ctx = X509_STORE_CTX_new(); + + X509_STORE_CTX_init(store_ctx, store, cert, NULL); + X509_STORE_CTX_set_verify_cb(store_ctx, verify_cb); + X509_STORE_CTX_set_flags(store_ctx, X509_V_FLAG_IGNORE_CRITICAL); + + ret = X509_verify_cert(store_ctx); + + if (ret != 1) + eWarning("[CI RCC] %s", X509_verify_cert_error_string(X509_STORE_CTX_get_error(store_ctx))); + + X509_STORE_CTX_free(store_ctx); + + return ret == 1; +} + +X509 *certificate_load_and_check(X509_STORE *store, const char *filename) +{ + X509 *cert; + + cert = certificate_open(filename); + if (!cert) + { + eWarning("[CI RCC] can not open %s", filename); + return NULL; + } + + if (!certificate_validate(store, cert)) + { + eWarning("[CI RCC] can not validate %s", filename); + X509_free(cert); + return NULL; + } + + X509_STORE_add_cert(store, cert); + + return cert; +} + +X509 *certificate_import_and_check(X509_STORE *store, const uint8_t *data, int len) +{ + X509 *cert; + + cert = d2i_X509(NULL, &data, len); + if (!cert) + { + eWarning("[CI RCC] can not read certificate"); + return NULL; + } + + if (!certificate_validate(store, cert)) + { + eWarning("[CI RCC] can not vaildate certificate\n"); + X509_free(cert); + return NULL; + } + + X509_STORE_add_cert(store, cert); + + return cert; +} + +bool ciplus_cert_param_files_exists() +{ + if (access("/etc/ciplus/param", R_OK ) != -1 && + access("/etc/ciplus/root.pem", R_OK ) != -1 && + access("/etc/ciplus/device.pem", R_OK ) != -1 && + access("/etc/ciplus/customer.pem", R_OK ) != -1) + return true; + + return false; +} diff --git a/lib/dvb_ci/dvbci_ccmgr_helper.h b/lib/dvb_ci/dvbci_ccmgr_helper.h new file mode 100644 index 00000000000..b622eb8889c --- /dev/null +++ b/lib/dvb_ci/dvbci_ccmgr_helper.h @@ -0,0 +1,23 @@ +#ifndef __RES_CONTENT_CTRL_HELPER_H +#define __RES_CONTENT_CTRL_HELPER_H + +#include +#include + +void traceHexdump(const uint8_t *data, unsigned int len); +int get_random(uint8_t *dest, int len); +int add_padding(uint8_t *dest, unsigned int len, unsigned int blocklen); +void str2bin(uint8_t *dst, char *data, int len); +uint32_t UINT32(const uint8_t *in, unsigned int len); +int BYTE32(uint8_t *dest, uint32_t val); +int BYTE16(uint8_t *dest, uint16_t val); +bool get_authdata(uint8_t *host_id, uint8_t *dhsk, uint8_t *akh, unsigned int slot, unsigned int index); +bool write_authdata(unsigned int slot, const uint8_t *host_id, const uint8_t *dhsk, const uint8_t *akh); +bool parameter_init(uint8_t* dh_p, uint8_t* dh_g, uint8_t* dh_q, uint8_t* s_key, uint8_t* key_data, uint8_t* iv); +RSA *rsa_privatekey_open(const char *filename); +int verify_cb(int ok, X509_STORE_CTX *ctx); +X509 *certificate_load_and_check(X509_STORE *store, const char *filename); +X509 *certificate_import_and_check(X509_STORE *store, const uint8_t *data, int len); +bool ciplus_cert_param_files_exists(); + +#endif diff --git a/lib/dvb_ci/dvbci_datetimemgr.cpp b/lib/dvb_ci/dvbci_datetimemgr.cpp index 7f7a62e9d7b..9d753a77401 100644 --- a/lib/dvb_ci/dvbci_datetimemgr.cpp +++ b/lib/dvb_ci/dvbci_datetimemgr.cpp @@ -12,10 +12,10 @@ eDVBCIDateTimeSession::eDVBCIDateTimeSession(): int eDVBCIDateTimeSession::receivedAPDU(const unsigned char *tag,const void *data, int len) { - eDebugNoNewLineStart("[CI DT] SESSION(%d)/DATETIME %02x %02x %02x: ", session_nb, tag[0],tag[1], tag[2]); + eTraceNoNewLine("[CI DT] SESSION(%d)/DATETIME %02x %02x %02x: ", session_nb, tag[0],tag[1], tag[2]); for (int i=0; i> 8) & 0xff; msg[1] = mjd & 0xff; msg[2] = ((hh / 10) << 4) | (hh % 10); diff --git a/lib/dvb_ci/dvbci_hlcmgr.cpp b/lib/dvb_ci/dvbci_hlcmgr.cpp new file mode 100644 index 00000000000..2ae9dc46c05 --- /dev/null +++ b/lib/dvb_ci/dvbci_hlcmgr.cpp @@ -0,0 +1,118 @@ +/* DVB CI Host Language and Country Manager */ + +#include +#include +#include + +int eDVBCIHostLanguageAndCountrySession::receivedAPDU(const unsigned char *tag,const void *data, int len) +{ + int ret = 0; + + eTraceNoNewLine("[CI HLC] SESSION(%d)/HLC %02x %02x %02x: ", session_nb, tag[0], tag[1], tag[2]); + for (int i=0; i eDVBCIHostLanguageAndCountrySession::createLanguageMap() +{ + std::map m; + m["ar_AE"] = "ara"; + m["bg_BG"] = "bul"; + m["ca_AD"] = "cat"; + m["cs_CZ"] = "ces"; + m["da_DK"] = "dan"; + m["de_DE"] = "deu"; + m["el_GR"] = "ell"; + m["en_GB"] = "eng"; + m["en_US"] = "eng"; + m["es_ES"] = "spa"; + m["et_EE"] = "est"; + m["fa_IR"] = "fas"; + m["fi_FI"] = "fin"; + m["fr_FR"] = "fra"; + m["fy_NL"] = "fry"; + m["gl_ES"] = "glg"; + m["he_IL"] = "heb"; + m["hr_HR"] = "hrv"; + m["hu_HU"] = "hun"; + m["id_ID"] = "ind"; + m["is_IS"] = "isl"; + m["it_IT"] = "ita"; + m["ku_KU"] = "kur"; + m["lt_LT"] = "lit"; + m["lv_LV"] = "lav"; + m["nb_NO"] = "nob"; + m["nl_NL"] = "nld"; + m["no_NO"] = "nor"; + m["pl_PL"] = "pol"; + m["pt_BR"] = "por"; + m["pt_PT"] = "por"; + m["ro_RO"] = "ron"; + m["ru_RU"] = "rus"; + m["sk_SK"] = "slk"; + m["sl_SI"] = "slv"; + m["sr_YU"] = "srp"; + m["sv_SE"] = "swe"; + m["th_TH"] = "tha"; + m["tr_TR"] = "tur"; + m["uk_UA"] = "ukr"; + m["vi_VN"] = "vie"; + m["zh_CN"] = "zho"; + m["zh_HK"] = "zho"; + return m; +} + +const std::map eDVBCIHostLanguageAndCountrySession::m_languageMap = eDVBCIHostLanguageAndCountrySession::createLanguageMap(); + +int eDVBCIHostLanguageAndCountrySession::doAction() +{ + switch (state) + { + case stateCountryEnquiry: + { + const unsigned char tag[] = {0x9F, 0x81, 0x01}; + sendAPDU(tag, "GBR", 3); + break; + } + case stateLanguageEnquiry: + { + const unsigned char tag[] = {0x9F, 0x81, 0x11}; + std::string language = eDVBCIInterfaces::getInstance()->getLanguage(); + std::map::const_iterator it = m_languageMap.find(language); + if (it != m_languageMap.end()) + sendAPDU(tag, it->second.c_str(), 3); + else + sendAPDU(tag, "eng", 3); + break; + } + default: + eWarning("[CI HLC] unknown state"); + break; + } + + return 0; +} diff --git a/lib/dvb_ci/dvbci_hlcmgr.h b/lib/dvb_ci/dvbci_hlcmgr.h new file mode 100644 index 00000000000..0dd81562e08 --- /dev/null +++ b/lib/dvb_ci/dvbci_hlcmgr.h @@ -0,0 +1,21 @@ +#ifndef __dvbci_dvbci_hlcmgr_h +#define __dvbci_dvbci_hlcmgr_h + +#include + +class eDVBCIHostLanguageAndCountrySession: public eDVBCISession +{ + enum { + stateCountryEnquiry=statePrivate, + stateLanguageEnquiry, + stateFinal + }; + + static const std::map m_languageMap; + static std::map createLanguageMap(); + + int receivedAPDU(const unsigned char *tag, const void *data, int len); + int doAction(); +}; + +#endif diff --git a/lib/dvb_ci/dvbci_host_ctrl.cpp b/lib/dvb_ci/dvbci_host_ctrl.cpp new file mode 100644 index 00000000000..26ded0e101c --- /dev/null +++ b/lib/dvb_ci/dvbci_host_ctrl.cpp @@ -0,0 +1,35 @@ +/* DVB CI Host Control Manager */ + +#include +#include + +int eDVBCIHostControlSession::receivedAPDU(const unsigned char *tag,const void *data, int len) +{ + eTraceNoNewLine("[CI HCTRL] SESSION(%d)/HCTRL %02x %02x %02x: ", session_nb, tag[0], tag[1], tag[2]); + for (int i=0; i + +class eDVBCIHostControlSession: public eDVBCISession +{ + int receivedAPDU(const unsigned char *tag, const void *data, int len); + int doAction(); +public: +}; + +#endif diff --git a/lib/dvb_ci/dvbci_mmi.cpp b/lib/dvb_ci/dvbci_mmi.cpp index c6afd7003af..9e595d9cb6d 100644 --- a/lib/dvb_ci/dvbci_mmi.cpp +++ b/lib/dvb_ci/dvbci_mmi.cpp @@ -9,9 +9,9 @@ PyObject *list = PyList_New(len); for (i=0; isetMMIManager(NULL); if (is_mmi_active) - eDVBCI_UI::getInstance()->mmiSessionDestroyed(slot->getSlotID()); + /* emit */ eDVBCI_UI::getInstance()->m_messagepump.send(eDVBCIInterfaces::Message(eDVBCIInterfaces::Message::mmiSessionDestroyed, slot->getSlotID())); } int eDVBCIMMISession::receivedAPDU(const unsigned char *tag, const void *data, int len) { - eDebugNoNewLineStart("[CI MMI] SESSION(%d)/MMI %02x %02x %02x: ", session_nb, tag[0], tag[1],tag[2]); + eTraceNoNewLineStart("[CI MMI] SESSION(%d)/MMI %02x %02x %02x: ", session_nb, tag[0], tag[1],tag[2]); for (int i=0; iprocessMMIData(slot->getSlotID(), tag, data, len) == 1) + /* emit */ eDVBCI_UI::getInstance()->m_messagepump.send(eDVBCIInterfaces::Message(eDVBCIInterfaces::Message::mmiDataReceived, slot->getSlotID(), tag, (unsigned char*) data, len)); + if (tag[2] == 0x01) { state=stateDisplayReply; return 1; diff --git a/lib/dvb_ci/dvbci_operatorprofile.cpp b/lib/dvb_ci/dvbci_operatorprofile.cpp new file mode 100644 index 00000000000..27ebc61b6da --- /dev/null +++ b/lib/dvb_ci/dvbci_operatorprofile.cpp @@ -0,0 +1,65 @@ +/* DVB CI Operator Profile Manager */ + +#include +#include + +eDVBCIOperatorProfileSession::eDVBCIOperatorProfileSession() +{ +} + +int eDVBCIOperatorProfileSession::receivedAPDU(const unsigned char *tag,const void *data, int len) +{ + eTraceNoNewLine("[CI OP] SESSION(%d)/OPERATOR %02x %02x %02x: ", session_nb, tag[0],tag[1], tag[2]); + for (int i=0; i + +class eDVBCIOperatorProfileSession: public eDVBCISession +{ + enum { + stateFinal=statePrivate + }; + + int receivedAPDU(const unsigned char *tag, const void *data, int len); + int doAction(); +public: + eDVBCIOperatorProfileSession(); +}; + +#endif diff --git a/lib/dvb_ci/dvbci_resmgr.cpp b/lib/dvb_ci/dvbci_resmgr.cpp index 50b20c4acb7..99bd8d194f0 100644 --- a/lib/dvb_ci/dvbci_resmgr.cpp +++ b/lib/dvb_ci/dvbci_resmgr.cpp @@ -2,13 +2,14 @@ #include #include +#include int eDVBCIResourceManagerSession::receivedAPDU(const unsigned char *tag,const void *data, int len) { - eDebugNoNewLineStart("[CI RM] SESSION(%d) %02x %02x %02x: ", session_nb, tag[0], tag[1], tag[2]); + eTraceNoNewLineStart("[CI RM] SESSION(%d) %02x %02x %02x: ", session_nb, tag[0], tag[1], tag[2]); for (int i=0; i #include #include +#include +#include +#include +#include +#include +#include DEFINE_REF(eDVBCISession); @@ -31,7 +37,7 @@ int eDVBCISession::buildLengthField(unsigned char *pkt, int len) return 3; } else { - eDebug("[CI SESS] too big length"); + eWarning("[CI SESS] too big length"); exit(0); } } @@ -144,10 +150,11 @@ void eDVBCISession::createSession(eDVBCISlot *slot, const unsigned char *resourc switch (tag) { case 0x00010041: - session=new eDVBCIResourceManagerSession; + session=new eDVBCIResourceManagerSession(slot->getVersion()); eDebug("[CI SESS] RESOURCE MANAGER"); break; case 0x00020041: + case 0x00020043: session=new eDVBCIApplicationManagerSession(slot); eDebug("[CI SESS] APPLICATION MANAGER"); break; @@ -155,6 +162,11 @@ void eDVBCISession::createSession(eDVBCISlot *slot, const unsigned char *resourc session = new eDVBCICAManagerSession(slot); eDebug("[CI SESS] CA MANAGER"); break; + case 0x00200041: + case 0x00200042: + session = new eDVBCIHostControlSession; + eDebug("[CI SESS] Host Control"); + break; case 0x00240041: session=new eDVBCIDateTimeSession; eDebug("[CI SESS] DATE-TIME"); @@ -163,11 +175,37 @@ void eDVBCISession::createSession(eDVBCISlot *slot, const unsigned char *resourc session = new eDVBCIMMISession(slot); eDebug("[CI SESS] MMI - create session"); break; + case 0x00410041: + case 0x00410042: + session = new eDVBCIApplicationMMISession; + eDebug("[CI SESS] Application MMI"); + break; + case 0x008C1001: + eDVBCIInterfaces::getInstance()->setCIPlusRouting(slot->getSlotID()); + session = new eDVBCICcSession(slot, 1); + eDebug("[CI SESS] Content Control v1"); + break; + case 0x008C1002: + eDVBCIInterfaces::getInstance()->setCIPlusRouting(slot->getSlotID()); + session = new eDVBCICcSession(slot, 2); + eDebug("[CI SESS] Content Control v2"); + break; + case 0x008D1001: + session = new eDVBCIHostLanguageAndCountrySession; + eDebug("[CI SESS] Host Language & Country"); + break; + case 0x008E1001: + session = new eDVBCICAMUpgradeSession; + eDebug("[CI SESS] CAM Upgrade"); + break; + case 0x008F1001: + session = new eDVBCIOperatorProfileSession; + eDebug("[CI SESS] Operator Profile"); + break; case 0x00100041: // session=new eDVBCIAuthSession; eDebug("[CI SESS] AuthSession"); -// break; - case 0x00200041: + [[fallthrough]]; default: eDebug("[CI SESS] unknown resource type %02x %02x %02x %02x", resource_identifier[0], resource_identifier[1], resource_identifier[2],resource_identifier[3]); session=0; @@ -176,7 +214,7 @@ void eDVBCISession::createSession(eDVBCISlot *slot, const unsigned char *resourc if (!session) { - eDebug("[CI SESS] unknown session.. expect crash"); + eWarning("[CI SESS] unknown session.. expect crash"); return; } @@ -225,12 +263,12 @@ void eDVBCISession::receiveData(eDVBCISlot *slot, const unsigned char *ptr, size unsigned char tag = *pkt++; int llen, hlen; - eDebugNoNewLineStart("[CI SESS] slot: %p ",slot); - - eDebugNoNewLineStart("[CI SESS]: "); + eDebug("[CI SESS] slot: %p",slot); + eTraceNoNewLineStart("[CI SESS]: "); for(unsigned int i=0;i= SLMS)) { - eDebug("[CI SESS] PROTOCOL: illegal session number %x", session_nb); + eWarning("[CI SESS] PROTOCOL: illegal session number %x", session_nb); return; } session=sessions[session_nb-1]; if (!session) { - eDebug("[CI SESS] PROTOCOL: data on closed session %x", session_nb); + eWarning("[CI SESS] PROTOCOL: data on closed session %x", session_nb); return; } @@ -316,11 +354,11 @@ void eDVBCISession::receiveData(eDVBCISlot *slot, const unsigned char *ptr, size } if (len) - eDebug("[CI SESS] PROTOCOL: warning, TL-Data has invalid length"); + eWarning("[CI SESS] PROTOCOL: warning, TL-Data has invalid length"); } eDVBCISession::~eDVBCISession() { -// eDebug("destroy %p", this); +// eDebug("[CI SESS] destroy %p", this); } diff --git a/lib/dvb_ci/dvbci_ui.cpp b/lib/dvb_ci/dvbci_ui.cpp index c41bff3babc..edb8f034d67 100644 --- a/lib/dvb_ci/dvbci_ui.cpp +++ b/lib/dvb_ci/dvbci_ui.cpp @@ -15,10 +15,11 @@ eDVBCI_UI *eDVBCI_UI::instance; eDVBCI_UI::eDVBCI_UI() - :eMMI_UI(MAX_SLOTS) + :eMMI_UI(MAX_SLOTS), m_messagepump(eApp,1, "dvb_ui") { ASSERT(!instance); instance = this; + CONNECT(m_messagepump.recv_msg, eDVBCI_UI::gotMessage); } eDVBCI_UI *eDVBCI_UI::getInstance() @@ -26,6 +27,25 @@ eDVBCI_UI *eDVBCI_UI::getInstance() return instance; } +void eDVBCI_UI::gotMessage(const eDVBCIInterfaces::Message &message) +{ + switch (message.m_type) + { + case eDVBCIInterfaces::Message::slotStateChanged: + setState(message.m_slotid, message.m_state); + break; + case eDVBCIInterfaces::Message::mmiSessionDestroyed: + mmiSessionDestroyed(message.m_slotid); + break; + case eDVBCIInterfaces::Message::mmiDataReceived: + processMMIData(message.m_slotid, message.m_tag, message.m_data, message.m_len); + break; + case eDVBCIInterfaces::Message::appNameChanged: + setAppName(message.m_slotid, message.m_appName.c_str()); + break; + } +} + void eDVBCI_UI::setInit(int slot) { eDVBCIInterfaces::getInstance()->initialize(slot); diff --git a/lib/dvb_ci/dvbci_ui.h b/lib/dvb_ci/dvbci_ui.h index 11c076cca20..fea09648268 100644 --- a/lib/dvb_ci/dvbci_ui.h +++ b/lib/dvb_ci/dvbci_ui.h @@ -2,12 +2,17 @@ #define __dvbci_ui_h #include +#include +#include #include #include class eDVBCI_UI: public eMMI_UI { static eDVBCI_UI *instance; +#ifndef SWIG + void gotMessage(const eDVBCIInterfaces::Message &message); +#endif #ifdef SWIG eDVBCI_UI(); #endif @@ -16,6 +21,7 @@ class eDVBCI_UI: public eMMI_UI enum { rateNormal, rateHigh }; PSignal1 ciStateChanged; #ifndef SWIG + eFixedMessagePump m_messagepump; eDVBCI_UI(); #endif static eDVBCI_UI *getInstance(); diff --git a/lib/gui/elistbox.cpp b/lib/gui/elistbox.cpp index bb3afcdcb44..71a4fcfa4e0 100644 --- a/lib/gui/elistbox.cpp +++ b/lib/gui/elistbox.cpp @@ -211,7 +211,8 @@ int eListbox::setScrollbarPosition() if (xOffset > 0) width -= (xOffset * 2); } - else { + else + { if (yOffset > 0) height -= (yOffset * 2); } @@ -260,7 +261,6 @@ int eListbox::setScrollbarPosition() return width; else return height; - } void eListbox::updateScrollBar() @@ -347,7 +347,6 @@ void eListbox::updateScrollBar() { m_scrollbar->setRange(0, m_scrollbar_calcsize - (m_scrollbar_border_width * 2)); } - } // Don't set Start/End if scollbar not visible or entries/maxItems = 0 @@ -466,13 +465,10 @@ int eListbox::event(int event, void *data, void *data2) painter.clippop(); } - int line = 0; int m_max_items = m_orientation == orGrid ? m_max_columns * m_max_rows : m_orientation == orHorizontal ? m_max_columns : m_max_rows; - - for (int posx = 0, posy = 0, i = 0; (m_orientation == orVertical) ? i <= m_max_items : i < m_max_items; posx += m_itemwidth + m_spacing.x(), ++i) { if (m_orientation == orGrid && i > 0) @@ -645,12 +641,13 @@ void eListbox::recalcSize() m_content->setSize(eSize(m_itemwidth, m_itemheight)); int w = size().width() - m_spacing.x(); m_max_columns = w / (m_itemwidth + m_spacing.x()); - if(m_style.m_selection_zoom > 1.0) + if (m_style.m_selection_zoom > 1.0) { int item_w_zoom = (m_itemwidth * m_style.m_selection_zoom) + m_spacing.x(); - if (m_max_columns > 1) { - if(w < (item_w_zoom + (m_max_columns - 1) * (m_itemwidth + m_spacing.x()))) - m_max_columns --; + if (m_max_columns > 1) + { + if (w < (item_w_zoom + (m_max_columns - 1) * (m_itemwidth + m_spacing.x()))) + m_max_columns--; } } } @@ -697,7 +694,6 @@ void eListbox::recalcSize() recalcSizeAlignment(scrollbarVisible); } - moveSelection(justCheck); } @@ -714,7 +710,6 @@ void eListbox::recalcSizeAlignment(bool scrollbarVisible) int xitemSpace = (m_max_columns > 1) ? ((m_max_columns - 1) * (m_itemwidth + m_spacing.x()) + m_itemwidth * m_style.m_selection_zoom) : (m_itemwidth * m_style.m_selection_zoom) + m_spacing.x(); int yitemSpace = (m_max_rows > 1) ? ((m_max_rows - 1) * (m_itemheight + m_spacing.y()) + m_itemheight * m_style.m_selection_zoom) : (m_itemheight * m_style.m_selection_zoom) + m_spacing.y(); - int scrollbarLeftSpace = (m_scrollbar_mode == showLeftOnDemand || m_scrollbar_mode == showLeftAlways) ? xscrollBar : 0; int scrollbarTopSpace = (m_scrollbar_mode == showTopOnDemand || m_scrollbar_mode == showTopAlways) ? yscrollBar : 0; diff --git a/lib/gui/elistboxcontent.cpp b/lib/gui/elistboxcontent.cpp index bed9d19e8ac..302ebd69f23 100644 --- a/lib/gui/elistboxcontent.cpp +++ b/lib/gui/elistboxcontent.cpp @@ -923,7 +923,7 @@ static ePyObject lookupColor(ePyObject color, ePyObject data) void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected) { - + eListboxStyle *local_style = 0; eRect sel_clip(m_selection_clip); bool cursorValid = this->cursorValid(); @@ -977,7 +977,8 @@ void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, c and the list is an unformatted tuple. The template then references items from the list. */ int cursor = 0; - if(!m_servicelist) { + if (!m_servicelist) + { cursor = cursorGet(); items = PyList_GET_ITEM(m_list, cursor); // borrowed reference! } @@ -986,13 +987,16 @@ void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, c { if (PyCallable_Check(m_buildFunc)) // when we have a buildFunc then call it { - if (m_servicelist || PyTuple_Check(items)) { + if (m_servicelist || PyTuple_Check(items)) + { setBuildArgs(selected); - if(m_pArgs) { + if (m_pArgs) + { buildfunc_ret = items = PyObject_CallObject(m_buildFunc, m_pArgs); Py_DECREF(m_pArgs); } - else { + else + { buildfunc_ret = items = PyObject_CallObject(m_buildFunc, items); } } diff --git a/lib/mmi/mmi_ui.cpp b/lib/mmi/mmi_ui.cpp index 7b88a5b056f..121975cbe43 100644 --- a/lib/mmi/mmi_ui.cpp +++ b/lib/mmi/mmi_ui.cpp @@ -204,9 +204,9 @@ int eMMI_UI::mmiScreenEnq(int slot, int blind, int answerLen, char *text) tuple = PyTuple_New(4); PyTuple_SET_ITEM(tuple, 0, PyString_FromString("PIN")); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(answerLen)); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(answerLen)); PyTuple_SET_ITEM(tuple, 2, PyString_FromString(text)); - PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(blind)); + PyTuple_SET_ITEM(tuple, 3, PyLong_FromLong(blind)); PyList_SET_ITEM(data.mmiScreen, 1, tuple); @@ -271,9 +271,9 @@ int eMMI_UI::mmiScreenAddText(int slot, int type, char *value) PyTuple_SET_ITEM(tuple, 1, PyString_FromString(value)); if (type > 2) - PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(type-2)); + PyTuple_SET_ITEM(tuple, 2, PyLong_FromLong(type-2)); else - PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(-1)); + PyTuple_SET_ITEM(tuple, 2, PyLong_FromLong(-1)); PyList_Append(data.mmiScreen, tuple); Py_DECREF(tuple); diff --git a/lib/python/Components/Converter/TemplatedMultiContent.py b/lib/python/Components/Converter/TemplatedMultiContent.py index 0191e1ee1ad..f3c00e86fa3 100644 --- a/lib/python/Components/Converter/TemplatedMultiContent.py +++ b/lib/python/Components/Converter/TemplatedMultiContent.py @@ -8,7 +8,7 @@ def __init__(self, args): StringList.__init__(self, args) from enigma import BT_HALIGN_CENTER, BT_HALIGN_LEFT, BT_HALIGN_RIGHT, BT_KEEP_ASPECT_RATIO, BT_SCALE, BT_VALIGN_BOTTOM, BT_VALIGN_CENTER, BT_VALIGN_TOP, RT_ELLIPSIS, RT_HALIGN_CENTER, RT_HALIGN_LEFT, RT_HALIGN_RIGHT, RT_VALIGN_BOTTOM, RT_VALIGN_CENTER, RT_VALIGN_TOP, RT_WRAP, gFont from skin import getSkinFactor, parseFont - from Components.MultiContent import MultiContentEntryPixmap, MultiContentEntryPixmapAlphaBlend, MultiContentEntryPixmapAlphaTest, MultiContentEntryProgress, MultiContentEntryProgressPixmap, MultiContentEntryText, MultiContentTemplateColor, MultiContentEntryRectangle, MultiContentEntryLinearGradient, MultiContentEntryLinearGradientAlphaBlend + from Components.MultiContent import MultiContentEntryLinearGradient, MultiContentEntryLinearGradientAlphaBlend, MultiContentEntryPixmap, MultiContentEntryPixmapAlphaBlend, MultiContentEntryPixmapAlphaTest, MultiContentEntryProgress, MultiContentEntryProgressPixmap, MultiContentEntryRectangle, MultiContentEntryText, MultiContentTemplateColor f = getSkinFactor() # This is needed for special OpenViX skins using f in the template. loc = locals() del loc["self"] # Cleanup locals a bit. diff --git a/lib/python/Components/EpgList.py b/lib/python/Components/EpgList.py index 2b8959c2631..d806c7ce705 100644 --- a/lib/python/Components/EpgList.py +++ b/lib/python/Components/EpgList.py @@ -81,6 +81,10 @@ def __init__(self, type=EPG_TYPE_SINGLE, selChangedCB=None, timer=None, time_epo self.days = (_("Mon"), _("Tue"), _("Wed"), _("Thu"), _("Fri"), _("Sat"), _("Sun")) #// + self.listRows = 8 + self.listFirstServiceIndex = 0 + self.serviceList = () + self.overjump_empty = overjump_empty self.timer = timer self.onSelChanged = [] @@ -544,6 +548,7 @@ def setItemsPerPage(self): self.listHeight = self.instance.size().height() self.listWidth = self.instance.size().width() self.itemHeight = itemHeight + self.listRows = int(self.listHeight / itemHeight) elif self.type == EPG_TYPE_ENHANCED or self.type == EPG_TYPE_SINGLE or self.type == EPG_TYPE_SIMILAR: if self.listHeight > 0: @@ -1485,7 +1490,7 @@ def updateMultiEPG(self, direction): self.l.setList(self.list) self.selectionChanged() - def fillGraphEPG(self, services, stime=None, getnow=False): + def fillGraphEPG(self, services, stime=None, getnow=False, current_service=None): if (self.type == EPG_TYPE_GRAPH or self.type == EPG_TYPE_INFOBARGRAPH) and not self.graphicsloaded: if self.graphic: self.nowEvPix = loadPNG(resolveFilename(SCOPE_GUISKIN, 'epg/CurrentEvent.png')) @@ -1514,6 +1519,8 @@ def fillGraphEPG(self, services, stime=None, getnow=False): self.graphicsloaded = True + test = ['XRnITBD'] #return record, service ref, service name, event id, event title, begin time, duration + if stime is not None: self.time_base = int(stime) if services is None: @@ -1522,31 +1529,42 @@ def fillGraphEPG(self, services, stime=None, getnow=False): self.time_base = time_base self.offs = 0 #// - test = [(service[0], 0, time_base, self.time_epoch) for service in self.list] - serviceList = self.list - piconIdx = 3 - channelIdx = 4 + endRow = min(self.listFirstServiceIndex + self.listRows, len(self.serviceList)) + for i in range(self.listFirstServiceIndex, endRow): + test.append((self.serviceList[i].ref.toString(), 0, self.time_base, self.time_epoch)) + piconIdx = 0 + channelIdx = None + else: self.cur_event = None self.cur_service = None - test = [(service.ref.toString(), 0, self.time_base, self.time_epoch) for service in services] - serviceList = services + self.listFirstServiceIndex = 0 + self.serviceList = services + if current_service is not None: + for i in range(len(self.serviceList)): + if self.serviceList[i].ref == current_service: + self.listFirstServiceIndex = int(i / self.listRows) * self.listRows + break + endRow = min(self.listFirstServiceIndex + self.listRows, len(self.serviceList)) + for i in range(self.listFirstServiceIndex, endRow): + test.append((self.serviceList[i].ref.toString(), 0, self.time_base, self.time_epoch)) + piconIdx = 0 channelIdx = None - test.insert(0, 'XRnITBD') # return record, service ref, service name, event id, event title, begin time, duration epg_data = self.queryEPG(test) self.list = [] tmp_list = None service = "" sname = "" - serviceIdx = 0 + serviceIdx = self.listFirstServiceIndex + for x in epg_data: if service != x[0]: if tmp_list is not None: - picon = None if piconIdx == 0 else serviceList[serviceIdx][piconIdx] - channel = serviceList[serviceIdx] if (channelIdx == None) else serviceList[serviceIdx][channelIdx] + picon = None if piconIdx == 0 else self.serviceList[serviceIdx][piconIdx] + channel = self.serviceList[serviceIdx] if (channelIdx == None) else self.serviceList[serviceIdx][channelIdx] self.list.append((service, sname, tmp_list[0][0] is not None and tmp_list or None, picon, channel)) serviceIdx += 1 service = x[0] @@ -1554,8 +1572,8 @@ def fillGraphEPG(self, services, stime=None, getnow=False): tmp_list = [] tmp_list.append((x[2], x[3], x[4], x[5])) # (event_id, event_title, begin_time, duration) if tmp_list and len(tmp_list): - picon = None if piconIdx == 0 else serviceList[serviceIdx][piconIdx] - channel = serviceList[serviceIdx] if (channelIdx == None) else serviceList[serviceIdx][channelIdx] + picon = None if piconIdx == 0 else self.serviceList[serviceIdx][piconIdx] + channel = self.serviceList[serviceIdx] if (channelIdx == None) else self.serviceList[serviceIdx][channelIdx] self.list.append((service, sname, tmp_list[0][0] is not None and tmp_list or None, picon, channel)) serviceIdx += 1 @@ -1618,6 +1636,40 @@ def moveToEventId(self, eventId): break index += 1 + def nextPage(self, selectFirstService = False): + if self.listFirstServiceIndex + self.listRows < len(self.serviceList): + self.listFirstServiceIndex += self.listRows + else: + self.listFirstServiceIndex = 0 + self.fillGraphEPG(None) + if selectFirstService: + self.setCurrentIndex(0) + + def prevPage(self, selectLastService = False): + if self.listFirstServiceIndex - self.listRows >= 0: + self.listFirstServiceIndex -= self.listRows + else: + self.listFirstServiceIndex = int(len(self.serviceList) / self.listRows) * self.listRows + self.fillGraphEPG(None) + if selectLastService: + if self.listFirstServiceIndex + self.listRows <= len(self.serviceList): + self.setCurrentIndex(self.listRows - 1) + else: + self.setCurrentIndex(len(self.serviceList) - self.listFirstServiceIndex - 1) + + def moveUp(self): + idx = self.getCurrentIndex() - 1 + if idx < 0: + self.prevPage(True) + else: + self.setCurrentIndex(idx) + + def moveDown(self): + idx = self.getCurrentIndex() + 1 + if idx >= self.listRows or self.listFirstServiceIndex + idx >= len(self.serviceList): + self.nextPage(True) + else: + self.setCurrentIndex(idx) class TimelineText(GUIComponent): def __init__(self, type=EPG_TYPE_GRAPH, graphic=False): diff --git a/lib/python/Components/MenuList.py b/lib/python/Components/MenuList.py index 8ee2e4df4bd..423af51e5ed 100644 --- a/lib/python/Components/MenuList.py +++ b/lib/python/Components/MenuList.py @@ -8,9 +8,9 @@ class MenuList(GUIComponent): def __init__(self, menuList, enableWrapAround=None, content=eListboxPythonStringContent): # enableWrapAround is deprecated as this is now controllable in the skin and windowstyle. GUIComponent.__init__(self) - self.menuList = menuList + self.list = menuList self.l = content() - self.l.setList(self.menuList) + self.l.setList(self.list) self.onSelectionChanged = [] def postWidgetCreate(self, instance): @@ -30,16 +30,14 @@ def selectionEnabled(self, enabled): self.instance.setSelectionEnable(enabled) def getList(self): - return self.menuList + return self.list def setList(self, menuList): - self.menuList = menuList - self.l.setList(self.menuList) - - list = property(getList, setList) + self.list = menuList + self.l.setList(self.list) def count(self): - return len(self.menuList) + return len(self.list) def selectionChanged(self): for callback in self.onSelectionChanged: diff --git a/lib/python/Components/MultiContent.py b/lib/python/Components/MultiContent.py index 49ecb8160ae..70207c832d0 100644 --- a/lib/python/Components/MultiContent.py +++ b/lib/python/Components/MultiContent.py @@ -1,4 +1,3 @@ -from __future__ import print_function from enigma import GRADIENT_VERTICAL, RT_HALIGN_LEFT, RT_VALIGN_TOP, eListboxPythonMultiContent from skin import parseColor diff --git a/lib/python/Components/Renderer/CiModuleControl.py b/lib/python/Components/Renderer/CiModuleControl.py index 579714ce3b9..126be42f177 100644 --- a/lib/python/Components/Renderer/CiModuleControl.py +++ b/lib/python/Components/Renderer/CiModuleControl.py @@ -1,6 +1,10 @@ from Components.Renderer.Renderer import Renderer -from enigma import eDVBCI_UI, eDVBCIInterfaces, eLabel, iPlayableService +from enigma import eDVBCI_UI, eLabel, iPlayableService +from skin import parameters +from Components.SystemInfo import SystemInfo from Components.VariableText import VariableText +from Tools.Hex2strColor import Hex2strColor +from os import popen class CiModuleControl(Renderer, VariableText): @@ -9,9 +13,10 @@ def __init__(self): VariableText.__init__(self) self.eDVBCIUIInstance = eDVBCI_UI.getInstance() self.eDVBCIUIInstance and self.eDVBCIUIInstance.ciStateChanged.get().append(self.ciModuleStateChanged) - self.NUM_CI = eDVBCIInterfaces.getInstance() and eDVBCIInterfaces.getInstance().getNumOfSlots() self.text = "" self.allVisible = False + self.no_visible_state1 = "ciplushelper" in popen("top -n 1").read() + self.colors = parameters.get("CiModuleControlColors", (0x007F7F7F, 0x00FFFF00, 0x0000FF00, 0x00FF2525)) # "state 0 (no module) gray", "state 1 (init module) yellow", "state 2 (module ready) green", "state -1 (error) red" GUI_WIDGET = eLabel @@ -31,26 +36,33 @@ def ciModuleStateChanged(self, slot): def changed(self, what): if what == True or what[0] == self.CHANGED_SPECIFIC and what[1] == iPlayableService.evStart: string = "" - if self.NUM_CI and self.NUM_CI > 0: + NUM_CI = SystemInfo["CommonInterface"] + if NUM_CI and NUM_CI > 0: if self.eDVBCIUIInstance: - for slot in list(range(self.NUM_CI)): + for slot in range(NUM_CI): + state = self.eDVBCIUIInstance.getState(slot) + if state == 1 and self.no_visible_state1: + continue add_num = True if string: string += " " - state = self.eDVBCIUIInstance.getState(slot) - if state != -1: + if state not in (-1, 3): if state == 0: if not self.allVisible: string += "" add_num = False else: - string += "\c007f7f7f" + string += Hex2strColor(self.colors[0]) # no module elif state == 1: - string += "\c00ffff00" + string += Hex2strColor(self.colors[1]) # init module elif state == 2: - string += "\c0000ff00" + string += Hex2strColor(self.colors[2]) # module ready else: - string += "\c00ff2525" + if not self.allVisible: + string += "" + add_num = False + else: + string += Hex2strColor(self.colors[3]) # error if add_num: string += "%d" % (slot + 1) if string: diff --git a/lib/python/Components/StackTrace.py b/lib/python/Components/StackTrace.py index 9af7a5a421b..91720973698 100644 --- a/lib/python/Components/StackTrace.py +++ b/lib/python/Components/StackTrace.py @@ -1,10 +1,10 @@ -from __future__ import print_function -from __future__ import absolute_import -import os -from threading import Thread, current_thread +from os import remove +from os.path import isfile from sys import _current_frames -from traceback import extract_stack +from threading import Thread, current_thread from time import sleep +from traceback import extract_stack + from Components.config import config @@ -16,13 +16,13 @@ def getInstance(self): instance = None def __init__(self): - print("initializing StackTracePrinter") - StackTracePrinter.instance = self Thread.__init__(self) + print("[StackTrace] Initializing StackTracePrinter.") + StackTracePrinter.instance = self self.__running = False def activate(self, MainThread_ident): - print("activating StackTracePrinter") + print("[StackTrace] Activating StackTracePrinter.") self.MainThread_ident = MainThread_ident if not self.__running: self.__running = True @@ -30,29 +30,28 @@ def activate(self, MainThread_ident): def run(self): while (self.__running == True): - if (os.path.isfile("/tmp/doPythonStackTrace")): - os.remove("/tmp/doPythonStackTrace") + if (isfile("/tmp/doPythonStackTrace")): + remove("/tmp/doPythonStackTrace") if config.crash.pystackonspinner.value: - print("StackTrace") - code = [] - code.append("========== Stacktrace of active Python threads ===========") + log = [] + log.append("[StackTrace] ========== Stacktrace of active Python threads ===========") for threadId, stack in list(_current_frames().items()): if (threadId != current_thread().ident): if (threadId == self.MainThread_ident): - code.append("========== MainThread 0x%08x =========================" % threadId) + log.append("[StackTrace] ========== MainThread 0x%08x =========================" % threadId) else: - code.append("========== Thread ID 0x%08x =========================" % threadId) + log.append("[StackTrace] ========== Thread ID 0x%08x =========================" % threadId) for filename, lineno, name, line in extract_stack(stack): - code.append('File: "%s", line %d, in %s' % (filename, lineno, name)) + log.append('[StackTrace] File: "%s", line %d, in %s' % (filename, lineno, name)) if line: - code.append(" %s" % (line.strip())) + log.append("[StackTrace] %s" % (line.strip())) del stack - code.append("========== Stacktrace end ================================") - for line in code: + log.append("[StackTrace] ========== Stacktrace end ================================") + for line in log: # This is done so that each line of the output is timestamped. print(line) sleep(1) Thread.__init__(self) def deactivate(self): - print("deactivating StackTracePrinter") + print("[StackTrace] Deactivating StackTracePrinter.") self.__running = False diff --git a/lib/python/Components/SystemInfo.py b/lib/python/Components/SystemInfo.py index 807a5343b3f..42385b44c16 100644 --- a/lib/python/Components/SystemInfo.py +++ b/lib/python/Components/SystemInfo.py @@ -4,7 +4,7 @@ from os.path import exists, isfile, join as pathjoin, islink from subprocess import PIPE, Popen -from enigma import Misc_Options, eDVBResourceManager, eGetEnigmaDebugLvl, eDBoxLCD +from enigma import Misc_Options, eDVBResourceManager, eGetEnigmaDebugLvl, eDBoxLCD, eDVBCIInterfaces from Tools.Directories import SCOPE_LIBDIR, SCOPE_SKINS, isPluginInstalled, fileCheck, fileReadLine, fileReadLines, resolveFilename, fileExists, fileHas, pathExists from Tools.MultiBoot import MultiBoot @@ -456,5 +456,12 @@ def getWakeOnLANType(fileName): SystemInfo["StatePlayPause"] = False SystemInfo["StandbyState"] = False SystemInfo["FastChannelChange"] = False +SystemInfo["FCCactive"] = False + +SystemInfo["CommonInterface"] = eDVBCIInterfaces.getInstance().getNumOfSlots() +SystemInfo["CommonInterfaceCIDelay"] = fileCheck("/proc/stb/tsmux/rmx_delay") +for cislot in range(0, SystemInfo["CommonInterface"]): + SystemInfo["CI%dSupportsHighBitrates" % cislot] = fileCheck("/proc/stb/tsmux/ci%d_tsclk" % cislot) + SystemInfo["CI%dRelevantPidsRoutingSupport" % cislot] = fileCheck("/proc/stb/tsmux/ci%d_relevant_pids_routing" % cislot) updateSysSoftCam() diff --git a/lib/python/Navigation.py b/lib/python/Navigation.py index 9e343b26607..986b18be0eb 100644 --- a/lib/python/Navigation.py +++ b/lib/python/Navigation.py @@ -314,13 +314,20 @@ def playService(self, ref, checkParentalControl=True, forceRestart=False, adjust if not playref: alternativeref = getBestPlayableServiceReference(ref, eServiceReference(), True) self.stopService() - if alternativeref and self.pnav and self.pnav.playService(alternativeref): - print("[Navigation] Failed to start", alternativeref) - if oldref and "://" in oldref.getPath(): - print("[Navigation] Streaming was active -> try again") # use timer to give the streamserver the time to deallocate the tuner - self.retryServicePlayTimer = eTimer() - self.retryServicePlayTimer.callback.append(boundFunction(self.playService, ref, checkParentalControl, forceRestart, adjust)) - self.retryServicePlayTimer.start(500, True) + if alternativeref and self.pnav: + self.currentlyPlayingServiceReference = alternativeref + self.currentlyPlayingServiceOrGroup = ref + if self.pnav.playService(alternativeref): + print("[Navigation] Failed to start: ", alternativeref.toString()) + self.currentlyPlayingServiceReference = None + self.currentlyPlayingServiceOrGroup = None + if oldref and "://" in oldref.getPath(): + print("[Navigation] Streaming was active -> try again") # use timer to give the streamserver the time to deallocate the tuner + self.retryServicePlayTimer = eTimer() + self.retryServicePlayTimer.callback.append(boundFunction(self.playService, ref, checkParentalControl, forceRestart, adjust)) + self.retryServicePlayTimer.start(500, True) + else: + print("[Navigation] alternative ref as simulate: ", alternativeref.toString()) return 0 elif checkParentalControl and not parentalControl.isServicePlayable(playref, boundFunction(self.playService, checkParentalControl=False)): if self.currentlyPlayingServiceOrGroup and InfoBarInstance and InfoBarInstance.servicelist.servicelist.setCurrent(self.currentlyPlayingServiceOrGroup, adjust): @@ -329,11 +336,15 @@ def playService(self, ref, checkParentalControl=True, forceRestart=False, adjust else: playref = ref if self.pnav: + if not BoxInfo.getItem("FCCactive"): + self.pnav.stopService() + else: + self.skipServiceReferenceReset = True self.currentlyPlayingServiceReference = playref self.currentlyPlayingServiceOrGroup = ref if InfoBarInstance and InfoBarInstance.servicelist.servicelist.setCurrent(ref, adjust): self.currentlyPlayingServiceOrGroup = InfoBarInstance.servicelist.servicelist.getCurrent() - self.skipServiceReferenceReset = True + #self.skipServiceReferenceReset = True if self.pnav.playService(playref): print("[Navigation] Failed to start", playref.toString()) self.currentlyPlayingServiceReference = None diff --git a/lib/python/Plugins/Extensions/SocketMMI/src/socket_mmi.cpp b/lib/python/Plugins/Extensions/SocketMMI/src/socket_mmi.cpp index 804cd074aeb..baf95870c8e 100644 --- a/lib/python/Plugins/Extensions/SocketMMI/src/socket_mmi.cpp +++ b/lib/python/Plugins/Extensions/SocketMMI/src/socket_mmi.cpp @@ -343,7 +343,7 @@ extern "C" { int slot; if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) return NULL; - return PyInt_FromLong(eSocket_UI::getInstance()->availableMMI(slot)); + return PyLong_FromLong(eSocket_UI::getInstance()->availableMMI(slot)); } static PyObject * @@ -361,7 +361,7 @@ extern "C" { int slot; if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) return NULL; - return PyInt_FromLong(eSocket_UI::getInstance()->startMMI(slot)); + return PyLong_FromLong(eSocket_UI::getInstance()->startMMI(slot)); } static PyObject * @@ -370,7 +370,7 @@ extern "C" { int slot; if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) return NULL; - return PyInt_FromLong(eSocket_UI::getInstance()->stopMMI(slot)); + return PyLong_FromLong(eSocket_UI::getInstance()->stopMMI(slot)); } static PyObject * @@ -379,7 +379,7 @@ extern "C" { 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)); + return PyLong_FromLong(eSocket_UI::getInstance()->answerMenu(slot, answer)); } static PyObject * @@ -389,7 +389,7 @@ extern "C" { char *answer; if (PyTuple_Size(args) != 2 || !PyArg_ParseTuple(args, "is", &slot, &answer)) return NULL; - return PyInt_FromLong(eSocket_UI::getInstance()->answerEnq(slot, answer)); + return PyLong_FromLong(eSocket_UI::getInstance()->answerEnq(slot, answer)); } static PyObject * @@ -398,7 +398,7 @@ extern "C" { int slot; if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) return NULL; - return PyInt_FromLong(eSocket_UI::getInstance()->cancelEnq(slot)); + return PyLong_FromLong(eSocket_UI::getInstance()->cancelEnq(slot)); } static PyObject * @@ -407,7 +407,7 @@ extern "C" { int slot; if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) return NULL; - return PyInt_FromLong(eSocket_UI::getInstance()->getState(slot)); + return PyLong_FromLong(eSocket_UI::getInstance()->getState(slot)); } static PyObject * @@ -416,7 +416,7 @@ extern "C" { int slot; if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &slot)) return NULL; - return PyInt_FromLong(eSocket_UI::getInstance()->getMMIState(slot)); + return PyLong_FromLong(eSocket_UI::getInstance()->getMMIState(slot)); } static PyObject * diff --git a/lib/python/Plugins/SystemPlugins/CommonInterfaceAssignment/plugin.py b/lib/python/Plugins/SystemPlugins/CommonInterfaceAssignment/plugin.py index d516799327e..9445741ead3 100644 --- a/lib/python/Plugins/SystemPlugins/CommonInterfaceAssignment/plugin.py +++ b/lib/python/Plugins/SystemPlugins/CommonInterfaceAssignment/plugin.py @@ -1,56 +1,53 @@ -from __future__ import print_function -from Screens.Screen import Screen -from Screens.ChannelSelection import * -from Components.ActionMap import HelpableActionMap, ActionMap, NumberActionMap -from Components.Sources.List import List -from Components.Sources.StaticText import StaticText +import six + +import os +from xml.etree.cElementTree import parse + +from enigma import eDVBCI_UI, eDVBCIInterfaces, eEnv, eServiceCenter + + +from Components.ActionMap import ActionMap from Components.config import ConfigNothing from Components.ConfigList import ConfigList from Components.Label import Label -from Components.SelectionList import SelectionList -from Components.SystemInfo import BoxInfo, getBoxDisplayName from Components.MenuList import MenuList +from Components.SelectionList import SelectionList +from Components.SystemInfo import SystemInfo from ServiceReference import ServiceReference from Plugins.Plugin import PluginDescriptor -from xml.etree.cElementTree import parse as ci_parse -from Tools.XMLTools import elementsWithTag, mergeText, stringToXML +from Screens.ChannelSelection import * +from Screens.ChoiceBox import ChoiceBox +from Screens.MessageBox import MessageBox +from Screens.Screen import Screen +from Components.Sources.List import List +from Components.Sources.StaticText import StaticText +from Screens.Standby import TryQuitMainloop +from Tools.BoundFunction import boundFunction from Tools.CIHelper import cihelper -from enigma import eDVBCI_UI, eDVBCIInterfaces, eEnv, eServiceCenter - -from os import system, path as os_path -import os -import six +from Tools.XMLTools import stringToXML class CIselectMainMenu(Screen): skin = """ - - + + """ def __init__(self, session, args=0): - Screen.__init__(self, session) - self["key_red"] = StaticText(_("Close")) self["key_green"] = StaticText(_("Edit")) - - self["actions"] = ActionMap(["ColorActions", "SetupActions"], + self["actions"] = ActionMap(["CancelSaveActions"], { - "green": self.greenPressed, - "red": self.close, - "ok": self.greenPressed, + "save": self.greenPressed, "cancel": self.close }, -1) - if BoxInfo.getItem("machinebuild") in ('zgemmah9combo',): - NUM_CI = 1 - else: - NUM_CI = eDVBCIInterfaces.getInstance() and eDVBCIInterfaces.getInstance().getNumOfSlots() + NUM_CI = SystemInfo["CommonInterface"] print("[CI_Wizzard] FOUND %d CI Slots " % NUM_CI) @@ -58,7 +55,7 @@ def __init__(self, session, args=0): self.state = {} self.list = [] if NUM_CI and NUM_CI > 0: - for slot in list(range(NUM_CI)): + for slot in range(NUM_CI): state = eDVBCI_UI.getInstance().getState(slot) if state != -1: appname = _("Slot %d") % (slot + 1) + " - " + _("unknown error") @@ -66,9 +63,10 @@ def __init__(self, session, args=0): appname = _("Slot %d") % (slot + 1) + " - " + _("no module found") elif state == 1: appname = _("Slot %d") % (slot + 1) + " - " + _("init modules") - elif state == 2: appname = _("Slot %d") % (slot + 1) + " - " + eDVBCI_UI.getInstance().getAppName(slot) + elif state == 3: + appname = _("Slot %d") % (slot + 1) + " - " + _("module disabled") self.list.append((appname, ConfigNothing(), 0, slot)) else: self.list.append((_("no CI slots found"), ConfigNothing(), 1, -1)) @@ -87,7 +85,7 @@ def greenPressed(self): action = cur[2] slot = cur[3] if action == 1: - print("[CI_Wizzard] there is no CI Slot in your %s %s" % getBoxDisplayName()) + print("[CI_Wizzard] there is no CI Slot in your receiver") else: print("[CI_Wizzard] selected CI Slot : %d" % slot) if config.usage.setup_level.index > 1: # advanced @@ -99,25 +97,25 @@ def greenPressed(self): class CIconfigMenu(Screen): skin = """ - - - - - - - - + + + + + + + + - + """ def __init__(self, session, ci_slot="9"): + Screen.__init__(self, session) - self.setTitle(_("CIconfigMenu")) self.ci_slot = ci_slot self.filename = eEnv.resolve("${sysconfdir}/enigma2/ci") + str(self.ci_slot) + ".xml" @@ -130,12 +128,13 @@ def __init__(self, session, ci_slot="9"): self["ServiceList_desc"] = StaticText(_("Assigned services/provider:")) self["ServiceList_info"] = StaticText() - self["actions"] = ActionMap(["ColorActions", "SetupActions"], + self["actions"] = ActionMap(["ColorActions", "OkCancelActions", "MenuActions"], { "green": self.greenPressed, "red": self.redPressed, "yellow": self.yellowPressed, "blue": self.bluePressed, + "menu": self.menuPressed, "cancel": self.cancel }, -1) @@ -143,7 +142,6 @@ def __init__(self, session, ci_slot="9"): i = 0 self.caidlist = [] - print(eDVBCIInterfaces.getInstance().readCICaIds(self.ci_slot)) for caid in eDVBCIInterfaces.getInstance().readCICaIds(self.ci_slot): i += 1 self.caidlist.append((str(hex(int(caid))), str(caid), i)) @@ -181,9 +179,26 @@ def yellowPressed(self): def bluePressed(self): self.session.openWithCallback(self.finishedCAidSelection, CAidSelect, self.caidlist, self.selectedcaid) + def menuPressed(self): + if os.path.exists(self.filename): + self.session.openWithCallback(self.deleteXMLfile, MessageBox, _("Delete file") + " " + self.filename + "?", MessageBox.TYPE_YESNO) + + def deleteXMLfile(self, answer): + if answer: + try: + os.remove(self.filename) + except: + print("[CI_Config_CI%d] error remove xml..." % self.ci_slot) + else: + self.session.openWithCallback(self.restartGui, MessageBox, _("Restart GUI now?"), MessageBox.TYPE_YESNO) + + def restartGui(self, answer): + if answer: + self.session.open(TryQuitMainloop, 3) + def cancel(self): self.saveXML() - activate_all(self, editcallback=True) + cihelper.load_ci_assignment(force=True) self.close() def setServiceListInfo(self): @@ -200,20 +215,35 @@ def delete(self): self.setServiceListInfo() def finishedChannelSelection(self, *args): - if len(args): - ref = args[0] - service_ref = ServiceReference(ref) - service_name = service_ref.getServiceName() - if find_in_list(self.servicelist, service_name, 0) == False: - split_ref = service_ref.ref.toString().split(":") - if split_ref[0] == "1": # == dvb service und nicht muell von None - self.servicelist.append((service_name, ConfigNothing(), 0, service_ref.ref.toString())) - self["ServiceList"].l.setList(self.servicelist) - self.setServiceListInfo() + item = len(args) + if item > 0: + if item > 2 and args[2] is True: + for ref in args[0]: + service_ref = ServiceReference(ref) + service_name = service_ref.getServiceName() + if len(service_name) and find_in_list(self.servicelist, service_name, 0) == False: + str_service = service_ref.ref.toString() + split_ref = str_service.split(":") + if split_ref[0] == "1" and not str_service.startswith("1:134:") and "%3a//" not in str_service: + self.servicelist.append((service_name, ConfigNothing(), 0, str_service)) + self["ServiceList"].l.setList(self.servicelist) + self.setServiceListInfo() + else: + ref = args[0] + if ref: + service_ref = ServiceReference(ref) + service_name = service_ref.getServiceName() + if find_in_list(self.servicelist, service_name, 0) == False: + str_service = service_ref.ref.toString() + split_ref = str_service.split(":") + if split_ref[0] == "1" and not str_service.startswith("1:134:") and "%3a//" not in str_service: + self.servicelist.append((service_name, ConfigNothing(), 0, str_service)) + self["ServiceList"].l.setList(self.servicelist) + self.setServiceListInfo() def finishedProviderSelection(self, *args): item = len(args) - if item > 1: # bei nix selected kommt nur 1 arg zurueck (==None) + if item > 1: if item > 2 and args[2] is True: for ref in args[0]: service_ref = ServiceReference(ref) @@ -277,15 +307,13 @@ def saveXML(self): except: print("[CI_Config_CI%d] xml not written" % self.ci_slot) os.unlink(self.filename) - cihelper.load_ci_assignment(force=True) def loadXML(self): - if not os_path.exists(self.filename): + if not os.path.exists(self.filename): self.setServiceListInfo() return def getValue(definitions, default): - ret = "" Len = len(definitions) return Len > 0 and definitions[Len - 1].text or default self.read_services = [] @@ -293,13 +321,12 @@ def getValue(definitions, default): self.usingcaid = [] self.ci_config = [] try: - tree = ci_parse(self.filename).getroot() + tree = parse(self.filename).getroot() for slot in tree.findall("slot"): read_slot = six.ensure_str(getValue(slot.findall("id"), False)) - print("ci " + read_slot) i = 0 for caid in slot.findall("caid"): - read_caid = six.ensure_str(caid.get("id")) + read_caid = caid.get("id").encode("UTF-8") self.selectedcaid.append((str(read_caid), str(read_caid), i)) self.usingcaid.append(int(read_caid, 16)) i += 1 @@ -313,10 +340,13 @@ def getValue(definitions, default): read_provider_name = six.ensure_str(provider.get("name")) read_provider_dvbname = six.ensure_str(provider.get("dvbnamespace")) self.read_providers.append((read_provider_name, read_provider_dvbname)) - self.ci_config.append((int(read_slot), (self.read_services, self.read_providers, self.usingcaid))) except: print("[CI_Config_CI%d] error parsing xml..." % self.ci_slot) + try: + os.remove(self.filename) + except: + print("[CI_Activate_Config_CI%d] error remove damaged xml..." % self.ci_slot) for item in self.read_services: if len(item): @@ -333,41 +363,39 @@ def getValue(definitions, default): class easyCIconfigMenu(CIconfigMenu): skin = """ - - - - - - - + + + + + + + """ def __init__(self, session, ci_slot="9"): - ci = ci_slot CIconfigMenu.__init__(self, session, ci_slot) - self.setTitle(_("CI assignment")) - - self["actions"] = ActionMap(["ColorActions", "SetupActions"], - { - "green": self.greenPressed, - "red": self.redPressed, - "yellow": self.yellowPressed, - "cancel": self.cancel - }) + self["actions"] = ActionMap(["ColorActions", "OkCancelActions", "MenuActions"], + { + "green": self.greenPressed, + "red": self.redPressed, + "yellow": self.yellowPressed, + "menu": self.menuPressed, + "cancel": self.cancel + }, -1) class CAidSelect(Screen): skin = """ - - + + - + """ @@ -378,7 +406,7 @@ def __init__(self, session, _list, selected_caids): self.list = SelectionList() self["list"] = self.list - for listindex in list(range(len(_list))): + for listindex in range(len(_list)): if find_in_list(selected_caids, _list[listindex][0], 0): self.list.addSelection(_list[listindex][0], _list[listindex][1], listindex, True) else: @@ -411,13 +439,16 @@ def cancel(self): class myProviderSelection(ChannelSelectionBase): skin = """ - + + + + - + """ @@ -464,7 +495,7 @@ def channelSelected(self): # just return selected service self.dvbnamespace = splited_ref[6] self.enterPath(ref) elif (ref.flags & 7) == 7 and 'provider' in ref.toString(): - menu = [(_("Only provider"), "provider"), (_("All services provider"), "providerlist")] + menu = [(_("Provider"), "provider"), (_("All services provider"), "providerlist")] def addAction(choice): if choice is not None: @@ -548,15 +579,16 @@ def cancel(self): class myChannelSelection(ChannelSelectionBase): skin = """ - - - + + + + - + """ @@ -585,9 +617,46 @@ def __init__(self, session, title): def __onExecCallback(self): self.setModeTv() self.setTitle(_("Select service to add...")) + self.isFavourites() + + def isFavourites(self): + ref = self.getCurrentSelection() + if ref: + if (ref.flags & 7) == 7 and "FROM BOUQUET" in ref.toString(): + self["key_yellow"].setText(_("Add bouquet")) + return True + else: + self["key_yellow"].setText("") + return False + + def showFavourites(self): + ChannelSelectionBase.showFavourites(self) + self.isFavourites() def showProviders(self): - pass + if self.isFavourites(): + self.session.openWithCallback(self.addAllBouquet, MessageBox, _("Add services to this bouquet?"), MessageBox.TYPE_YESNO) + + def addAllBouquet(self, answer): + ref = self.getCurrentSelection() + if answer and ref: + serviceHandler = eServiceCenter.getInstance() + servicelist = serviceHandler.list(ref) + if not servicelist is None: + providerlist = [] + while True: + service = servicelist.getNext() + if not service.valid(): + break + providerlist.append((service)) + if providerlist: + self.close(providerlist, None, True) + else: + self.close(None) + + def showAllServices(self): + ChannelSelectionBase.showAllServices(self) + self.isFavourites() def showSatellites(self, changeMode=False): if changeMode: @@ -597,6 +666,7 @@ def channelSelected(self): # just return selected service ref = self.getCurrentSelection() if (ref.flags & 7) == 7: self.enterPath(ref) + self.isFavourites() elif not (ref.flags & eServiceReference.isMarker): ref = self.getCurrentSelection() self.close(ref) @@ -613,7 +683,7 @@ def cancel(self): self.close(None) -def activate_all(session, editcallback=False): +def activate_all(session): cihelper.load_ci_assignment() @@ -624,19 +694,19 @@ def find_in_list(list, search, listpos=0): return False -global_session = None - - def isModule(): - NUM_CI = eDVBCIInterfaces.getInstance() and eDVBCIInterfaces.getInstance().getNumOfSlots() + NUM_CI = SystemInfo["CommonInterface"] if NUM_CI and NUM_CI > 0: - for slot in list(range(NUM_CI)): + for slot in range(NUM_CI): state = eDVBCI_UI.getInstance().getState(slot) if state > 0: return True return False +global_session = None + + def sessionstart(reason, session): global global_session global_session = session @@ -662,11 +732,9 @@ def menu(menuid, **kwargs): def Plugins(**kwargs): + description = _("a gui to assign services/providers to common interface modules") if config.usage.setup_level.index > 1: - return [PluginDescriptor(where=PluginDescriptor.WHERE_SESSIONSTART, needsRestart=False, fnc=sessionstart), - PluginDescriptor(where=PluginDescriptor.WHERE_AUTOSTART, needsRestart=False, fnc=autostart), - PluginDescriptor(name=_("Common Interface Assignment"), description=_("a gui to assign services/providers/caids to common interface modules"), where=PluginDescriptor.WHERE_MENU, needsRestart=False, fnc=menu)] - else: - return [PluginDescriptor(where=PluginDescriptor.WHERE_SESSIONSTART, needsRestart=False, fnc=sessionstart), - PluginDescriptor(where=PluginDescriptor.WHERE_AUTOSTART, needsRestart=False, fnc=autostart), - PluginDescriptor(name=_("Common Interface Assignment"), description=_("a gui to assign services/providers to common interface modules"), where=PluginDescriptor.WHERE_MENU, needsRestart=False, fnc=menu)] + description = _("a gui to assign services/providers/caids to common interface modules") + return [PluginDescriptor(where=PluginDescriptor.WHERE_SESSIONSTART, needsRestart=False, fnc=sessionstart), + PluginDescriptor(where=PluginDescriptor.WHERE_AUTOSTART, needsRestart=False, fnc=autostart), + PluginDescriptor(name=_("Common Interface Assignment"), description=description, where=PluginDescriptor.WHERE_MENU, needsRestart=False, fnc=menu)] diff --git a/lib/python/Plugins/SystemPlugins/FastChannelChange/plugin.py b/lib/python/Plugins/SystemPlugins/FastChannelChange/plugin.py index f6258070d80..660624b066e 100644 --- a/lib/python/Plugins/SystemPlugins/FastChannelChange/plugin.py +++ b/lib/python/Plugins/SystemPlugins/FastChannelChange/plugin.py @@ -3,6 +3,7 @@ from enigma import iPlayableService, eTimer, eServiceReference, iRecordableService, eFCCServiceManager from Components.config import config, ConfigSubsection, ConfigYesNo, ConfigSelection from Components.ServiceEventTracker import ServiceEventTracker +from Components.SystemInfo import BoxInfo from Plugins.Plugin import PluginDescriptor from Screens.InfoBar import InfoBar from Screens.Setup import Setup @@ -65,6 +66,8 @@ def __init__(self, session): self.__event_tracker = None self.onClose = [] self.changeEventTracker() + BoxInfo.setItem("FCCactive", self.fccSetupActivate) + # from Screens.PictureInPicture import on_pip_start_stop # on_pip_start_stop.append(self.FCCForceStopforPIP) @@ -156,6 +159,8 @@ def FCCSetupChanged(self): if fcc_changed: self.fccmgr.setFCCEnable(int(self.fccSetupActivate)) + BoxInfo.setItem("FCCactive", self.fccSetupActivate) + curPlaying = self.session.nav.getCurrentlyPlayingServiceReference() if curPlaying: self.session.nav.stopService() @@ -222,10 +227,10 @@ def isPlayableFCC(self, sref): if sref.type != 1: playable = False - elif sref.getPath(): # is PVR? or streaming? + elif sref.getPath(): # is PVR? or streaming? playable = False - elif int(sref.getData(0)) in (2, 10): # is RADIO? + elif int(sref.getData(0)) in (2, 10): # is RADIO? playable = False return playable @@ -238,7 +243,7 @@ def getZapUpDownList(self): serviceRefList = [] for idx in range(len(serviceList)): sref = serviceList[idx].toString() - if (sref.split(':')[1] == '0') and self.isPlayableFCC(sref): # remove marker + if (sref.split(':')[1] == '0') and self.isPlayableFCC(sref): # remove marker serviceRefList.append(sref) if curServiceRef in serviceRefList: @@ -246,13 +251,13 @@ def getZapUpDownList(self): curServiceIndex = serviceRefList.index(curServiceRef) for x in range(self.maxFCC - 1): - if x > (serviceRefListSize - 2): # if not ((x+1) <= (serviceRefListSize-1)) + if x > (serviceRefListSize - 2): # if not ((x+1) <= (serviceRefListSize-1)) break idx = (x // 2) + 1 if x % 2: - idx *= -1 # idx : [ 1, -1, 2, -2, 3, -3, 4, -4 ....] - idx = (curServiceIndex + idx) % serviceRefListSize # calc wraparound + idx *= -1 # idx : [ 1, -1, 2, -2, 3, -3, 4, -4 ....] + idx = (curServiceIndex + idx) % serviceRefListSize # calc wraparound try: fccZapUpDownList.append(serviceRefList[idx]) except: @@ -325,13 +330,13 @@ def FCCReconfigureFccList(self): for (sref, value) in currentFCCList.items(): state = value[0] - if state == 2: # fcc_state_failed + if state == 2: # fcc_state_failed stopFCCList.append(sref) - elif sref in self.fccList: # check conflict FCC channel (decoder/prepare) + elif sref in self.fccList: # check conflict FCC channel (decoder/prepare) self.fccList.remove(sref) - elif state == 0: # fcc_state_preparing + elif state == 0: # fcc_state_preparing stopFCCList.append(sref) for sref in stopFCCList: @@ -374,11 +379,11 @@ def FCCApplyEvent(self): self.FCCTimeoutTimerStop() if event in (iPlayableService.evTuneFailed, iPlayableService.evFccFailed): - self.fccmgr.stopFCCService() # stop FCC Services in failed state + self.fccmgr.stopFCCService() # stop FCC Services in failed state if not self.FCCCheckAndTimerStart() and len(self.fccList): sref = self.fccList.pop(0) - if self.isPlayableFCC(sref): # remove PVR, streaming, radio channels + if self.isPlayableFCC(sref): # remove PVR, streaming, radio channels self.fccmgr.playFCCService(eServiceReference(sref)) self.FCCTimeoutTimerStart(sref) @@ -387,7 +392,7 @@ def FCCStopAllServices(self): fccServiceList = self.fccmgr.getFCCServiceList() for (sref, value) in fccServiceList.items(): state = value[0] - if state != 1: # 1 : fcc_state_decoding + if state != 1: # 1 : fcc_state_decoding self.fccmgr.stopFCCService(eServiceReference(sref)) def FCCDisableServices(self): @@ -403,7 +408,7 @@ def FCCCheckNoLocked(self): for (sref, value) in self.fccmgr.getFCCServiceList().items(): state = value[0] locked = value[1] - if state != 1 and locked == 0: # no fcc decoding and no locked + if state != 1 and locked == 0: # no fcc decoding and no locked return sref return None diff --git a/lib/python/Screens/Ci.py b/lib/python/Screens/Ci.py index 51e2cb1e5c9..786bf050017 100644 --- a/lib/python/Screens/Ci.py +++ b/lib/python/Screens/Ci.py @@ -1,36 +1,21 @@ -from os import rename, access, R_OK -from os.path import isfile -import time +from Screens.Screen import Screen +from Screens.MessageBox import MessageBox +from Tools.BoundFunction import boundFunction +from Components.Sources.StaticText import StaticText from Components.ActionMap import ActionMap from Components.ActionMap import NumberActionMap -from Components.ConfigList import ConfigListScreen, ConfigList -from Components.Console import Console -from Components.config import config, ConfigSubsection, ConfigSelection, ConfigSubList, getConfigListEntry, KEY_LEFT, KEY_RIGHT, KEY_0, ConfigNothing, ConfigPIN, ConfigYesNo, NoSave from Components.Label import Label -from Components.Pixmap import Pixmap -from Components.Sources.StaticText import StaticText -from Components.SystemInfo import BoxInfo -from Screens.MessageBox import MessageBox -from Screens.Screen import Screen -from Tools.BoundFunction import boundFunction -from Tools.Directories import fileReadLines, fileWriteLines - +from Components.config import config, ConfigSubsection, ConfigSelection, ConfigSubList, getConfigListEntry, KEY_LEFT, KEY_RIGHT, KEY_0, ConfigNothing, ConfigPIN, ConfigYesNo, NoSave +from Components.ConfigList import ConfigList, ConfigListScreen +from Components.SystemInfo import SystemInfo from enigma import eTimer, eDVBCI_UI, eDVBCIInterfaces +import Screens.Standby - -relevantPidsRoutingChoices = None - -BRAND = BoxInfo.getItem("brand") -MAX_NUM_CI = 1 if BoxInfo.getItem("machinebuild") in ("zgemmah9combo", "pulse4kmini") else 4 -CI_HELPER_CONF = "/etc/cihelper.conf" -CI_HELPER_CONF_TMP = "/etc/cihelper.conf.tmp" +forceNotShowCiMessages = False def setCIBitrate(configElement): - if not configElement.value: - eDVBCI_UI.getInstance().setClockRate(configElement.slotid, eDVBCI_UI.rateNormal) - else: - eDVBCI_UI.getInstance().setClockRate(configElement.slotid, eDVBCI_UI.rateHigh) + eDVBCI_UI.getInstance().setClockRate(configElement.slotid, eDVBCI_UI.rateNormal if configElement.value == "no" else eDVBCI_UI.rateHigh) def setCIEnabled(configElement): @@ -38,71 +23,45 @@ def setCIEnabled(configElement): def setdvbCiDelay(configElement): - with open("/proc/stb/tsmux/rmx_delay", "w") as fd: - fd.write(configElement.value) + open(SystemInfo["CommonInterfaceCIDelay"], "w").write(configElement.value) + configElement.save() def setRelevantPidsRouting(configElement): - fileName = "/proc/stb/tsmux/ci%d_relevant_pids_routing" % (configElement.slotid) - if isfile(fileName): - with open(fileName, "w") as fd: - fd.write(configElement.value) + open(SystemInfo["CI%dRelevantPidsRoutingSupport" % configElement.slotid], "w").write("yes" if configElement.value else "no") def InitCiConfig(): config.ci = ConfigSubList() config.cimisc = ConfigSubsection() - for slot in range(MAX_NUM_CI): - config.ci.append(ConfigSubsection()) - config.ci[slot].enabled = ConfigYesNo(default=True) - config.ci[slot].enabled.slotid = slot - config.ci[slot].enabled.addNotifier(setCIEnabled) - config.ci[slot].canDescrambleMultipleServices = ConfigSelection(choices=[("auto", _("Auto")), ("no", _("No")), ("yes", _("Yes"))], default="auto") - config.ci[slot].use_static_pin = ConfigYesNo(default=True) - config.ci[slot].static_pin = ConfigPIN(default=0) - config.ci[slot].show_ci_messages = ConfigYesNo(default=True) - if BoxInfo.getItem("CommonInterfaceSupportsHighBitrates"): - if BRAND in ("dags", "blackbox"): + if SystemInfo["CommonInterface"]: + for slot in range(SystemInfo["CommonInterface"]): + config.ci.append(ConfigSubsection()) + config.ci[slot].enabled = ConfigYesNo(default=True) + config.ci[slot].enabled.slotid = slot + config.ci[slot].enabled.addNotifier(setCIEnabled) + config.ci[slot].canDescrambleMultipleServices = ConfigSelection(choices=[("auto", _("auto")), ("no", _("no")), ("yes", _("yes"))], default="auto") + config.ci[slot].use_static_pin = ConfigYesNo(default=True) + config.ci[slot].static_pin = ConfigPIN(default=0) + config.ci[slot].show_ci_messages = ConfigYesNo(default=True) + if SystemInfo["CI%dSupportsHighBitrates" % slot]: config.ci[slot].canHandleHighBitrates = ConfigYesNo(default=True) - else: - config.ci[slot].canHandleHighBitrates = ConfigYesNo(default=False) - config.ci[slot].canHandleHighBitrates.slotid = slot - config.ci[slot].canHandleHighBitrates.addNotifier(setCIBitrate) - if BoxInfo.getItem("RelevantPidsRoutingSupport"): - global relevantPidsRoutingChoices - if not relevantPidsRoutingChoices: - relevantPidsRoutingChoices = [("no", _("No")), ("yes", _("Yes"))] - default = "no" - fileName = "/proc/stb/tsmux/ci%d_relevant_pids_routing_choices" % slot - if isfile(fileName): - relevantPidsRoutingChoices = [] - with open(fileName, "r") as fd: - data = fd.read() - data = data.split() - for x in data: - relevantPidsRoutingChoices.append((x, _(x))) - if default not in data: - default = data[0] - config.ci[slot].relevantPidsRouting = ConfigSelection(choices=relevantPidsRoutingChoices, default=default) - config.ci[slot].relevantPidsRouting.slotid = slot - config.ci[slot].relevantPidsRouting.addNotifier(setRelevantPidsRouting) - if BoxInfo.getItem("CommonInterfaceCIDelay"): - config.cimisc.dvbCiDelay = ConfigSelection(default="256", choices=[("16", _("16")), ("32", _("32")), ("64", _("64")), ("128", _("128")), ("256", _("256"))]) - config.cimisc.dvbCiDelay.addNotifier(setdvbCiDelay) - if BRAND in ("entwopia", "tripledot", "dreambox"): - if BoxInfo.getItem("HaveCISSL"): - config.cimisc.civersion = ConfigSelection(default="ciplus1", choices=[("auto", _("Auto")), ("ciplus1", _("CI Plus 1.2")), ("ciplus2", _("CI Plus 1.3")), ("legacy", _("CI Legacy"))]) - else: - config.cimisc.civersion = ConfigSelection(default="legacy", choices=[("legacy", _("CI Legacy"))]) - else: - config.cimisc.civersion = ConfigSelection(default="auto", choices=[("auto", _("Auto")), ("ciplus1", _("CI Plus 1.2")), ("ciplus2", _("CI Plus 1.3")), ("legacy", _("CI Legacy"))]) + config.ci[slot].canHandleHighBitrates.slotid = slot + config.ci[slot].canHandleHighBitrates.addNotifier(setCIBitrate) + if SystemInfo["CI%dRelevantPidsRoutingSupport" % slot]: + config.ci[slot].relevantPidsRouting = ConfigYesNo(default=False) + config.ci[slot].relevantPidsRouting.slotid = slot + config.ci[slot].relevantPidsRouting.addNotifier(setRelevantPidsRouting) + if SystemInfo["CommonInterfaceCIDelay"]: + config.cimisc.dvbCiDelay = ConfigSelection(default="256", choices=[("16", "16"), ("32", "32"), ("64", "64"), ("128", "128"), ("256", "256")]) + config.cimisc.dvbCiDelay.addNotifier(setdvbCiDelay) class MMIDialog(Screen): - def __init__(self, session, slotid, action, handler=eDVBCI_UI.getInstance(), wait_text="wait for ci...", screen_data=None): + def __init__(self, session, slotid, action, handler=eDVBCI_UI.getInstance(), wait_text="", screen_data=None): Screen.__init__(self, session) - print("MMIDialog with action:%s" % str(action)) + print("[CI] MMIDialog with action" + str(action)) self.mmiclosed = False self.tag = None @@ -115,12 +74,14 @@ def __init__(self, session, slotid, action, handler=eDVBCI_UI.getInstance(), wai self["title"] = Label("") self["subtitle"] = Label("") self["bottom"] = Label("") + self["key_menu"] = StaticText(_("MENU")) self["entries"] = ConfigList([]) - self["actions"] = NumberActionMap(["SetupActions"], + self["actions"] = NumberActionMap(["SetupActions", "MenuActions"], { "ok": self.okbuttonClick, "cancel": self.keyCancel, + "menu": self.forceExit, #for PIN "left": self.keyLeft, "right": self.keyRight, @@ -137,17 +98,19 @@ def __init__(self, session, slotid, action, handler=eDVBCI_UI.getInstance(), wai }, -1) self.action = action - - self.handler = handler - self.wait_text = _(wait_text) self.screen_data = screen_data self.is_pin_list = -1 + self.handler = handler + if wait_text == "": + self.wait_text = _("wait for ci...") + else: + self.wait_text = wait_text - if action == 2: # Start MMI + if action == 2: #start MMI handler.startMMI(self.slotid) self.showWait() - elif action == 3: # mmi already there (called from infobar) + elif action == 3: #mmi already there (called from infobar) self.showScreen() def addEntry(self, list, entry): @@ -156,26 +119,35 @@ def addEntry(self, list, entry): if entry[0] == "PIN": pinlength = entry[1] if entry[3] == 1: - x = ConfigPIN(0, pinLength=pinlength, censor="*") # Masked pins + # masked pins: + x = ConfigPIN(0, len=pinlength, censor="*") else: - x = ConfigPIN(0, pinLength=pinlength) # Unmasked pins + # unmasked pins: + x = ConfigPIN(0, len=pinlength) + x.addEndNotifier(self.pinEntered) self["subtitle"].setText(entry[2]) list.append(getConfigListEntry("", x)) - self["bottom"].setText(_("please press OK when ready")) + self["bottom"].setText(_("Please press OK when ready")) + + def pinEntered(self, value): + self.okbuttonClick() def okbuttonClick(self): self.timer.stop() if not self.tag: return if self.tag == "WAIT": - print("do nothing - wait") + print("[CI] do nothing - wait") elif self.tag == "MENU": - print("answer MENU") + print("[CI] answer MENU") cur = self["entries"].getCurrent() - self.handler.answerMenu(self.slotid, cur[2] if cur else 0) + if cur: + self.handler.answerMenu(self.slotid, cur[2]) + else: + self.handler.answerMenu(self.slotid, 0) self.showWait() elif self.tag == "LIST": - print("answer LIST") + print("[CI] answer LIST") self.handler.answerMenu(self.slotid, 0) self.showWait() elif self.tag == "ENQ": @@ -183,7 +155,7 @@ def okbuttonClick(self): answer = str(cur[1].value) length = len(answer) while length < cur[1].getLength(): - answer = "0" + answer + answer = '0' + answer length += 1 self.answer = answer if config.ci[self.slotid].use_static_pin.value: @@ -202,6 +174,14 @@ def closeMmi(self): self.timer.stop() self.close(self.slotid) + def forceExit(self): + self.timer.stop() + if self.tag == "WAIT": + self.handler.stopMMI(self.slotid) + global forceNotShowCiMessages + forceNotShowCiMessages = True + self.close(self.slotid) + def keyCancel(self): self.timer.stop() if not self.tag or self.mmiclosed: @@ -210,15 +190,15 @@ def keyCancel(self): self.handler.stopMMI(self.slotid) self.closeMmi() elif self.tag in ("MENU", "LIST"): - print("cancel list") + print("[CI] cancel list") self.handler.answerMenu(self.slotid, 0) self.showWait() elif self.tag == "ENQ": - print("cancel enq") + print("[CI] cancel enq") self.handler.cancelEnq(self.slotid) self.showWait() else: - print("give cancel action to ci") + print("[CI] give cancel action to ci") def keyConfigEntry(self, key): self.timer.stop() @@ -247,22 +227,22 @@ def keyRight(self): self.is_pin_list += 1 self.keyConfigEntry(KEY_RIGHT) - def updateList(self, items): + def updateList(self, list): List = self["entries"] try: List.instance.moveSelectionTo(0) except: pass - List.l.setList(items) + List.l.setList(list) def showWait(self): self.tag = "WAIT" self["title"].setText("") self["subtitle"].setText("") self["bottom"].setText("") - items = [] - items.append((self.wait_text, ConfigNothing())) - self.updateList(items) + list = [] + list.append((self.wait_text, ConfigNothing())) + self.updateList(list) def showScreen(self): if self.screen_data is not None: @@ -271,7 +251,7 @@ def showScreen(self): else: screen = self.handler.getMMIScreen(self.slotid) - items = [] + list = [] self.timer.stop() if len(screen) > 0 and screen[0][0] == "CLOSE": @@ -290,14 +270,14 @@ def showScreen(self): answer = str(config.ci[self.slotid].static_pin.value) length = len(answer) while length < config.ci[self.slotid].static_pin.getLength(): - answer = "0" + answer + answer = '0' + answer length += 1 self.handler.answerEnq(self.slotid, answer) self.showWait() break else: self.is_pin_list = 0 - self.addEntry(items, entry) + self.addEntry(list, entry) else: if entry[0] == "TITLE": self["title"].setText(entry[1]) @@ -306,17 +286,22 @@ def showScreen(self): elif entry[0] == "BOTTOM": self["bottom"].setText(entry[1]) elif entry[0] == "TEXT": - self.addEntry(items, entry) - self.updateList(items) + self.addEntry(list, entry) + self.updateList(list) def ciStateChanged(self): do_close = False - if self.action == 0 or self.action == 1: #reset = 0 , init = 1 + if self.action == 0: #reset + do_close = True + if self.action == 1: #init do_close = True #module still there ? + if self.handler.getState(self.slotid) != 2: + do_close = True + #mmi session still active ? - if self.handler.getState(self.slotid) != 2 or self.handler.getMMIState(self.slotid) != 1: + if self.handler.getMMIState(self.slotid) != 1: do_close = True if do_close: @@ -330,19 +315,10 @@ def ciStateChanged(self): class CiMessageHandler: def __init__(self): self.session = None + self.auto_close = False self.ci = {} self.dlgs = {} - self.auto_close = False eDVBCI_UI.getInstance().ciStateChanged.get().append(self.ciStateChanged) - # TODO move to systeminfo - if BoxInfo.getItem("machinebuild") in ("vuzero",): - BoxInfo.setItem("CommonInterface", False) - else: - BoxInfo.setItem("CommonInterface", eDVBCIInterfaces.getInstance().getNumOfSlots() > 0) - - BoxInfo.setItem("CommonInterfaceSupportsHighBitrates", access("/proc/stb/tsmux/ci0_tsclk", R_OK)) - BoxInfo.setItem("CommonInterfaceCIDelay", access("/proc/stb/tsmux/rmx_delay", R_OK)) - BoxInfo.setItem("RelevantPidsRoutingSupport", access("/proc/stb/tsmux/ci0_relevant_pids_routing", R_OK)) def setSession(self, session): self.session = session @@ -357,29 +333,32 @@ def ciStateChanged(self, slot): elif handler.availableMMI(slot) == 1: if self.session: show_ui = False - if config.ci[slot].show_ci_messages.value and config.misc.firstrun.value == 0: + if config.ci[slot].show_ci_messages.value: show_ui = True screen_data = handler.getMMIScreen(slot) if config.ci[slot].use_static_pin.value: if screen_data is not None and len(screen_data): ci_tag = screen_data[0][0] - if ci_tag == "ENQ" and len(screen_data) >= 2 and screen_data[1][0] == "PIN": + if ci_tag == 'ENQ' and len(screen_data) >= 2 and screen_data[1][0] == 'PIN': if str(config.ci[slot].static_pin.value) == "0": show_ui = True else: answer = str(config.ci[slot].static_pin.value) length = len(answer) while length < config.ci[slot].static_pin.getLength(): - answer = "0" + answer + answer = '0' + answer length += 1 handler.answerEnq(slot, answer) show_ui = False self.auto_close = True - elif ci_tag == "CLOSE" and self.auto_close: + elif ci_tag == 'CLOSE' and self.auto_close: show_ui = False self.auto_close = False - if show_ui: - self.dlgs[slot] = self.session.openWithCallback(self.dlgClosed, MMIDialog, slot, 3, screen_data=screen_data) + if show_ui and not forceNotShowCiMessages and not Screens.Standby.inStandby: + try: + self.dlgs[slot] = self.session.openWithCallback(self.dlgClosed, MMIDialog, slot, 3, screen_data=screen_data) + except: + pass def dlgClosed(self, slot): if slot in self.dlgs: @@ -401,48 +380,53 @@ class CiSelection(Screen): def __init__(self, session): Screen.__init__(self, session) self.setTitle(_("Common Interface")) - self["actions"] = ActionMap(["OkCancelActions", "CiSelectionActions"], + self["actions"] = ActionMap(["SetupActions", "CiSelectionActions"], { "left": self.keyLeft, "right": self.keyLeft, "ok": self.okbuttonClick, "cancel": self.cancel }, -1) + self["key_red"] = StaticText(_("Cancel")) self.dlg = None self.state = {} - self.slots = [] - self.HighBitrateEntry = {} - self.RelevantPidsRoutingEntry = {} - self.entryData = [] - self.list = [] - self["entries"] = ConfigList(self.list) - self["entries"].list = self.list - self["entries"].l.setList(self.list) - self["text"] = Label(_("Slot %d") % (1)) - self.onLayoutFinish.append(self.initialUpdate) - - def initialUpdate(self): - for slot in range(MAX_NUM_CI): + self.slot = 0 + for slot in range(SystemInfo["CommonInterface"]): state = eDVBCI_UI.getInstance().getState(slot) if state != -1: - self.slots.append(slot) - self.state[slot] = state - self.createEntries(slot) + self.slot += 1 + self.appendEntries(slot, state) CiHandler.registerCIMessageHandler(slot, self.ciStateChanged) - self.updateEntries() + menuList = ConfigList(self.list) + menuList.list = self.list + menuList.l.setList(self.list) + self["entries"] = menuList + self["entries"].onSelectionChanged.append(self.selectionChanged) + self["text"] = Label("") + self.onLayoutFinish.append(self.layoutFinished) + + def layoutFinished(self): + global forceNotShowCiMessages + forceNotShowCiMessages = False + cur = self["entries"].getCurrent() + if cur and len(cur) > 2: + self["text"].setText(_("Slot %d") % (cur[3] + 1)) + elif not cur: + self["text"].setText(_("no module found")) def selectionChanged(self): - entryData = self.entryData[self["entries"].getCurrentIndex()] - self["text"].setText(_("Slot %d") % (entryData[1] + 1)) + if self.slot > 1: + cur = self["entries"].getCurrent() + if cur and len(cur) > 2: + self["text"].setText(cur[0] == "**************************" and " " or cur[0] == _("DVB CI Delay") and _("All slots") or _("Slot %d") % (cur[3] + 1)) def keyConfigEntry(self, key): - current = self["entries"].getCurrent() try: self["entries"].handleKey(key) - current[1].save() + self["entries"].getCurrent()[1].save() except: pass @@ -452,50 +436,66 @@ def keyLeft(self): def keyRight(self): self.keyConfigEntry(KEY_RIGHT) - def createEntries(self, slot): - if BoxInfo.getItem("CommonInterfaceSupportsHighBitrates"): - self.HighBitrateEntry[slot] = getConfigListEntry(_("High bitrate support"), config.ci[slot].canHandleHighBitrates) - if BoxInfo.getItem("RelevantPidsRoutingSupport"): - self.RelevantPidsRoutingEntry[slot] = getConfigListEntry(_("Relevant PIDs Routing"), config.ci[slot].relevantPidsRouting) - - def addToList(self, data, action, slotid): - self.list.append(data) - self.entryData.append((action, slotid)) + def appendEntries(self, slot, state): + self.state[slot] = state + if self.slot > 1: + self.list.append(("**************************", ConfigNothing(), 3, slot)) + self.list.append((_("CI %s enabled" % (slot)), config.ci[slot].enabled, -1, slot)) + self.list.append((_("Reset"), ConfigNothing(), 0, slot)) + self.list.append((_("Init"), ConfigNothing(), 1, slot)) + + if self.state[slot] == 0: # no module + self.list.append((_("no module found"), ConfigNothing(), 2, slot)) + elif self.state[slot] == 1: # module in init + self.list.append((_("init module"), ConfigNothing(), 2, slot)) + elif self.state[slot] == 2: # module ready + appname = eDVBCI_UI.getInstance().getAppName(slot) + self.list.append((appname, ConfigNothing(), 2, slot)) + elif self.state[slot] == 3: # module disabled by the user + self.list.append((_("module disabled"), ConfigNothing(), 2, slot)) + return - def updateEntries(self): - self.list = [] - self.entryData = [] - for slot in self.slots: - self.addToList(getConfigListEntry(_("CI %s enabled" % slot), config.ci[slot].enabled), -1, slot) - if self.state[slot] == 3: # module disabled by the user - continue - self.addToList((_("Reset"), ConfigNothing()), 0, slot) - self.addToList((_("Init"), ConfigNothing()), 1, slot) - - if self.state[slot] == 0: #no module - self.addToList((_("no module found"), ConfigNothing()), 2, slot) - elif self.state[slot] == 1: #module in init - self.addToList((_("init module"), ConfigNothing()), 2, slot) - elif self.state[slot] == 2: #module ready - #get appname - appname = eDVBCI_UI.getInstance().getAppName(slot) - self.addToList((appname, ConfigNothing()), 2, slot) - - self.addToList(getConfigListEntry(_("Set pin code persistent"), config.ci[slot].use_static_pin), -1, slot) - self.addToList((_("Enter persistent PIN code"), ConfigNothing()), 5, slot) - self.addToList((_("Reset persistent PIN code"), ConfigNothing()), 6, slot) - self.addToList(getConfigListEntry(_("Show CI messages"), config.ci[slot].show_ci_messages), -1, slot) - self.addToList(getConfigListEntry(_("Multiple service support"), config.ci[slot].canDescrambleMultipleServices), -1, slot) - - if BoxInfo.getItem("CommonInterfaceSupportsHighBitrates"): - self.addToList(self.HighBitrateEntry[slot], -1, slot) - if BoxInfo.getItem("RelevantPidsRoutingSupport"): - self.addToList(self.RelevantPidsRoutingEntry[slot], -1, slot) - - self["entries"].list = self.list - self["entries"].l.setList(self.list) - if self.selectionChanged not in self["entries"].onSelectionChanged: - self["entries"].onSelectionChanged.append(self.selectionChanged) + self.list.append(getConfigListEntry(_("Set pin code persistent"), config.ci[slot].use_static_pin, 3, slot)) + self.list.append((_("Enter persistent PIN code"), ConfigNothing(), 5, slot)) + self.list.append((_("Reset persistent PIN code"), ConfigNothing(), 6, slot)) + self.list.append(getConfigListEntry(_("Show CI messages"), config.ci[slot].show_ci_messages, 3, slot)) + self.list.append(getConfigListEntry(_("Multiple service support"), config.ci[slot].canDescrambleMultipleServices, 3, slot)) + if SystemInfo["CI%dSupportsHighBitrates" % slot]: + self.list.append(getConfigListEntry(_("High bitrate support"), config.ci[slot].canHandleHighBitrates, 3, slot)) + if SystemInfo["CI%dRelevantPidsRoutingSupport" % slot]: + self.list.append(getConfigListEntry(_("Relevant PIDs Routing"), config.ci[slot].relevantPidsRouting, 3, slot)) + if SystemInfo["CommonInterfaceCIDelay"]: + self.list.append(getConfigListEntry(_("DVB CI Delay"), config.cimisc.dvbCiDelay, 3, slot)) + + def updateState(self, slot): + state = eDVBCI_UI.getInstance().getState(slot) + self.state[slot] = state + + slotidx = 0 + while len(self.list[slotidx]) < 3 or self.list[slotidx][3] != slot: + slotidx += 1 + + if slot > 0: + slotidx += 1 # do not change separator + slotidx += 1 # do not change CI Enabled + slotidx += 1 # do not change Reset + slotidx += 1 # do not change Init + + if state == 0: # no module + self.list[slotidx] = (_("no module found"), ConfigNothing(), 2, slot) + elif state == 1: # module in init + self.list[slotidx] = (_("init module"), ConfigNothing(), 2, slot) + elif state == 2: # module ready + appname = eDVBCI_UI.getInstance().getAppName(slot) + self.list[slotidx] = (appname, ConfigNothing(), 2, slot) + if len(self.list) <= slotidx + 1: + self.list = [] + self.appendEntries(slot, state) + elif state == 3: + self.list = self.list[0:slotidx + 1] + lst = self["entries"] + lst.list = self.list + lst.l.setList(self.list) def ciStateChanged(self, slot): if self.dlg: @@ -503,23 +503,22 @@ def ciStateChanged(self, slot): else: state = eDVBCI_UI.getInstance().getState(slot) if self.state[slot] != state: - #print "something happens" self.state[slot] = state - self.updateEntries() + self.updateState(slot) def dlgClosed(self, slot): self.dlg = None def okbuttonClick(self): cur = self["entries"].getCurrent() - if cur: - idx = self["entries"].getCurrentIndex() - entryData = self.entryData[idx] - action = entryData[0] - slot = entryData[1] - if action == 0: #reset + if cur and len(cur) > 2: + action = cur[2] + slot = cur[3] + if action == 3: + pass + elif action == 0: # reset eDVBCI_UI.getInstance().setReset(slot) - elif action == 1: #init + elif action == 1: # init eDVBCI_UI.getInstance().setInit(slot) elif action == 5: self.session.openWithCallback(self.cancelCB, PermanentPinEntry, config.ci[slot].static_pin, _("Smartcard PIN")) @@ -527,25 +526,24 @@ def okbuttonClick(self): config.ci[slot].static_pin.value = 0 config.ci[slot].static_pin.save() self.session.openWithCallback(self.cancelCB, MessageBox, _("The saved PIN was cleared."), MessageBox.TYPE_INFO) - elif action == 2 and self.state[slot] == 2: + elif self.state[slot] == 2: self.dlg = self.session.openWithCallback(self.dlgClosed, MMIDialog, slot, action) def cancelCB(self, value): pass def cancel(self): - for slot in range(MAX_NUM_CI): + for slot in range(SystemInfo["CommonInterface"]): state = eDVBCI_UI.getInstance().getState(slot) if state != -1: CiHandler.unregisterCIMessageHandler(slot) self.close() -class PermanentPinEntry(Screen, ConfigListScreen): +class PermanentPinEntry(ConfigListScreen, Screen): def __init__(self, session, pin, pin_slot): Screen.__init__(self, session) self.skinName = ["ParentalControlChangePin", "Setup"] - self.setTitle(_("Enter pin code")) self.onChangedEntry = [] self.slot = pin_slot @@ -557,16 +555,9 @@ def __init__(self, session, pin, pin_slot): self.pin2.addEndNotifier(boundFunction(self.valueChanged, 2)) self.list.append(getConfigListEntry(_("Enter PIN"), NoSave(self.pin1))) self.list.append(getConfigListEntry(_("Reenter PIN"), NoSave(self.pin2))) - ConfigListScreen.__init__(self, self.list) - - self["actions"] = NumberActionMap(["DirectionActions", "ColorActions", "OkCancelActions"], - { - "cancel": self.cancel, - "red": self.cancel, - "save": self.keyOK, - }, -1) - self["key_red"] = StaticText(_("Cancel")) - self["key_green"] = StaticText(_("OK")) + ConfigListScreen.__init__(self, self.list, fullUI=True) + + self.setTitle(_("Enter pin code")) def valueChanged(self, pin, value): if pin == 1: @@ -574,7 +565,7 @@ def valueChanged(self, pin, value): elif pin == 2: self.keyOK() - def keyOK(self): + def keySave(self): if self.pin1.value == self.pin2.value: self.pin.value = self.pin1.value self.pin.save() @@ -582,194 +573,5 @@ def keyOK(self): else: self.session.open(MessageBox, _("The PIN codes you entered are different."), MessageBox.TYPE_ERROR) - def cancel(self): + def keyCancel(self): self.close(None) - - def keyNumberGlobal(self, number): - ConfigListScreen.keyNumberGlobal(self, number) - - # for summary: - def changedEntry(self): - for x in self.onChangedEntry: - x() - - def getCurrentEntry(self): - return self["config"].getCurrent()[0] - - def getCurrentValue(self): - return str(self["config"].getCurrent()[1].getText()) - - def createSummary(self): - from Screens.Setup import SetupSummary - return SetupSummary - - -class CIHelper(Screen): - def __init__(self, session): - Screen.__init__(self, session) - Screen.setTitle(self, _("CI Helper Settings")) - self.skinName = "CIHelper" - self.onChangedEntry = [] - self["ci0"] = Label(_("CIHelper for SLOT CI0")) - self["ci0active"] = Pixmap() - self["ci0inactive"] = Pixmap() - self["ci1"] = Label(_("CIHelper for SLOT CI1")) - self["ci1active"] = Pixmap() - self["ci1inactive"] = Pixmap() - - self["autostart"] = Label(_("Autostart:")) - self["labactive"] = Label(_(_("Active"))) - self["labdisabled"] = Label(_(_("Disabled"))) - self["status"] = Label(_("Current Status:")) - self["labstop"] = Label(_("Stopped")) - self["labrun"] = Label(_("Running")) - self["key_red"] = Label() - self["key_green"] = Label(_("Start")) - self["key_yellow"] = Label(_("Autostart")) - self["key_blue"] = Label() - self.Console = Console() - self.my_cihelper_active = False - self.my_cihelper_run = False - self["actions"] = ActionMap(["WizardActions", "ColorActions", "SetupActions"], {"ok": self.setupcihelper, "back": self.close, "menu": self.setupcihelper, "green": self.CIHelperStartStop, "yellow": self.CIHelperset}) - self.onLayoutFinish.append(self.updateService) - - def CIHelperStartStop(self): - if not self.my_cihelper_run: - self.Console.ePopen("/etc/init.d/cihelper.sh start", self.StartStopCallback) - elif self.my_cihelper_run: - self.Console.ePopen("/etc/init.d/cihelper.sh stop", self.StartStopCallback) - - def StartStopCallback(self, result=None, retval=None, extra_args=None): - time.sleep(5) - self.updateService() - - def CIHelperset(self): - if isfile("/etc/rcS.d/S50cihelper.sh") or isfile("/etc/rc4.d/S50cihelper.sh"): - self.Console.ePopen("update-rc.d -f cihelper.sh remove", self.StartStopCallback) - else: - self.Console.ePopen("update-rc.d -f -s cihelper.sh start 50 S .", self.StartStopCallback) - - def updateService(self): - import process - p = process.ProcessList() - cihelper_process = str(p.named("cihelper")).strip("[]") - self["labrun"].hide() - self["labstop"].hide() - self["labactive"].hide() - self["labdisabled"].hide() - self.my_cihelper_active = False - self.my_cihelper_run = False - if isfile("/etc/rcS.d/S50cihelper.sh") or isfile("/etc/rc4.d/S50cihelper.sh"): - self["labdisabled"].hide() - self["labactive"].show() - self.my_cihelper_active = True - autostartstatus_summary = self["autostart"].text + " " + self["labactive"].text - else: - self["labactive"].hide() - self["labdisabled"].show() - autostartstatus_summary = self["autostart"].text + " " + self["labdisabled"].text - if cihelper_process: - self.my_cihelper_run = True - if self.my_cihelper_run: - self["labstop"].hide() - self["labrun"].show() - self["key_green"].setText(_("Stop")) - status_summary = self["status"].text + " " + self["labstop"].text - else: - self["labstop"].show() - self["labrun"].hide() - self["key_green"].setText(_("Start")) - status_summary = self["status"].text + " " + self["labstop"].text - - if isfile(CI_HELPER_CONF): - helperConfig = fileReadLines(CI_HELPER_CONF) - helperConfig = [x.strip() for x in helperConfig if x.strip().startswith("ENABLE_CI")] - self["ci1active"].hide() - self["ci1inactive"].hide() - self["ci1"].hide() - for line in helperConfig: - if line.startswith("ENABLE_CI0="): - if line[11:] == "no": - self["ci0active"].hide() - self["ci0inactive"].show() - else: - self["ci0active"].show() - self["ci0inactive"].hide() - elif line.startswith("ENABLE_CI1=") and access("/dev/ci1", R_OK): - self["ci1"].show() - if line[11:] == "no": - self["ci1active"].hide() - self["ci1inactive"].show() - else: - self["ci1active"].show() - self["ci1inactive"].hide() - title = _("CI Helper Settings") - - for cb in self.onChangedEntry: - cb(title, status_summary, autostartstatus_summary) - - def setupcihelper(self): - self.session.openWithCallback(self.updateService, CIHelperSetup) - - -class CIHelperSetup(Screen, ConfigListScreen): - def __init__(self, session): - Screen.__init__(self, session) - self.onChangedEntry = [] - self.list = [] - ConfigListScreen.__init__(self, self.list, session=session, on_change=self.selectionChanged) - self.setTitle(_("CI Helper Settings")) - self["key_red"] = Label(_("Save")) - self["actions"] = ActionMap(["WizardActions", "ColorActions"], {"red": self.saveCIHelper, "back": self.close}) - self.updateList() - if not self.selectionChanged in self["config"].onSelectionChanged: - self["config"].onSelectionChanged.append(self.selectionChanged) - - def selectionChanged(self): - item = self["config"].getCurrent() - name = str(item[0]) if item else "" - desc = str(item[1].value) if item else "" - for cb in self.onChangedEntry: - cb(name, desc) - - def updateList(self, ret=None): - self.list = [] - self.cihelper_ci0 = NoSave(ConfigYesNo(default=True)) - self.cihelper_ci1 = NoSave(ConfigYesNo(default=True)) if access("/dev/ci1", R_OK) else ConfigNothing() - - if isfile(CI_HELPER_CONF): - helperConfig = fileReadLines(CI_HELPER_CONF) - if helperConfig: - helperConfig = [x.strip() for x in helperConfig if x.strip().startswith("ENABLE_CI")] - for line in helperConfig: - if line.startswith("ENABLE_CI0="): - self.cihelper_ci0.value = (line[11:] != "no") - cihelper_ci0x = getConfigListEntry(_("Enable CIHelper for SLOT CI0") + ":", self.cihelper_ci0) - self.list.append(cihelper_ci0x) - elif line.startswith("ENABLE_CI1="): - self.cihelper_ci1.value = (line[11:] != "no") - if access("/dev/ci1", R_OK): - cihelper_ci1x = getConfigListEntry(_("Enable CIHelper for SLOT CI1") + ":", self.cihelper_ci1) - self.list.append(cihelper_ci1x) - self["config"].list = self.list - - def saveCIHelper(self): - if isfile(CI_HELPER_CONF): - helperConfig = fileReadLines(CI_HELPER_CONF) - newhelperConfig = [] - for line in helperConfig: - line = line.replace("\n", "") - if line.startswith("ENABLE_CI0="): - line = "ENABLE_CI0%s" % ("yes" if self.cihelper_ci0.value else "no") - elif line.startswith("ENABLE_CI1="): - line = "ENABLE_CI1%s" % ("yes" if self.cihelper_ci1.value else "no") - newhelperConfig.append("%s\n" % line) - fileWriteLines(CI_HELPER_CONF_TMP, newhelperConfig) - else: - errorText = _("Sorry CIHelper Config is Missing") - with open("/tmp/CIHelper.log", "a") as fd: - fd.write("%s\n" % errorText) - self.session.open(MessageBox, errorText, MessageBox.TYPE_INFO) - if isfile(CI_HELPER_CONF_TMP): - rename(CI_HELPER_CONF_TMP, CI_HELPER_CONF) - self.close() diff --git a/lib/python/Screens/EpgSelection.py b/lib/python/Screens/EpgSelection.py index 4d1aef067be..1434a62c5ee 100644 --- a/lib/python/Screens/EpgSelection.py +++ b/lib/python/Screens/EpgSelection.py @@ -521,7 +521,7 @@ def onCreate(self): if self.type == EPG_TYPE_MULTI: self["list"].fillMultiEPG(self.services, self.ask_time) else: - self["list"].fillGraphEPG(self.services, self.ask_time) + self["list"].fillGraphEPG(self.services, self.ask_time, current_service=serviceref) self["list"].setCurrentlyPlaying(serviceref) self["list"].moveToService(serviceref) if self.type != EPG_TYPE_MULTI: @@ -592,6 +592,10 @@ def refreshlist(self): self["list" + str(self.activeList)].moveToEventId(curr) def moveUp(self): + if self.type == EPG_TYPE_GRAPH or self.type == EPG_TYPE_INFOBARGRAPH: + self['list'].moveUp() + self.moveTimeLines(True) + return if self.type == EPG_TYPE_VERTICAL and config.epgselection.vertical_updownbtn.value: if self.getEventTime(self.activeList)[0] is None: return @@ -606,19 +610,19 @@ def moveUp(self): if not idx % config.epgselection.vertical_itemsperpage.value: self.syncUp(idx) self["list" + str(self.activeList)].moveTo(self["list" + str(self.activeList)].instance.moveUp) - if self.type == EPG_TYPE_GRAPH or self.type == EPG_TYPE_INFOBARGRAPH: - self.moveTimeLines(True) if self.type == EPG_TYPE_VERTICAL: self.saveLastEventTime() def moveDown(self): + if self.type == EPG_TYPE_GRAPH or self.type == EPG_TYPE_INFOBARGRAPH: + self['list'].moveDown() + self.moveTimeLines(True) + return if self.type == EPG_TYPE_VERTICAL and config.epgselection.vertical_updownbtn.value: idx = self["list" + str(self.activeList)].getCurrentIndex() if not (idx + 1) % config.epgselection.vertical_itemsperpage.value: self.syncDown(idx + 1) self["list" + str(self.activeList)].moveTo(self["list" + str(self.activeList)].instance.moveDown) - if self.type == EPG_TYPE_GRAPH or self.type == EPG_TYPE_INFOBARGRAPH: - self.moveTimeLines(True) if self.type == EPG_TYPE_VERTICAL: self.saveLastEventTime() @@ -653,6 +657,8 @@ def nextPage(self, numberkey=False, reverse=False): self.activeList = 1 self.updateVerticalEPG() self.gotoLasttime() + elif self.type == EPG_TYPE_GRAPH or self.type == EPG_TYPE_INFOBARGRAPH: + self['list'].nextPage() else: self["list"].moveTo(self["list"].instance.pageDown) @@ -680,6 +686,8 @@ def prevPage(self, numberkey=False, reverse=False): self.activeList = (self.Fields - 1) self.updateVerticalEPG() self.gotoLasttime() + elif self.type == EPG_TYPE_GRAPH or self.type == EPG_TYPE_INFOBARGRAPH: + self['list'].prevPage() else: self["list"].moveTo(self["list"].instance.pageUp) diff --git a/lib/python/Screens/Information.py b/lib/python/Screens/Information.py index 494aea80027..9f1ac873505 100644 --- a/lib/python/Screens/Information.py +++ b/lib/python/Screens/Information.py @@ -888,7 +888,7 @@ def displayInformation(self): info.append("") if self.slotImages: slotCode, bootCode = MultiBoot.getCurrentSlotAndBootCodes() - slotImageList = sorted(self.slotImages.keys()) + slotImageList = sorted(self.slotImages.keys(), key=lambda x: (not x.isnumeric(), int(x) if x.isnumeric() else x)) currentMsg = " - %s" % _("Current") imageLists = {} for slot in slotImageList: diff --git a/lib/python/Screens/Satconfig.py b/lib/python/Screens/Satconfig.py index 5221e5b8656..53c00a17586 100644 --- a/lib/python/Screens/Satconfig.py +++ b/lib/python/Screens/Satconfig.py @@ -519,7 +519,7 @@ def fillListWithAdvancedSatEntrys(self, Sat): if isFBCLink(self.nim.slot): if nimConfig_advanced.unicableconnected.value != True: nimConfig_advanced.unicableconnected.value = True - self.advancedConnected = getConfigListEntry(_("connected"), nimConfig_advanced.unicableconnected, _("Select 'yes' if this tuner is connected to the SCR device through another tuner, otherwise select 'no'.")) + self.advancedConnected = getConfigListEntry(_("Connected through another tuner"), nimConfig_advanced.unicableconnected, _("Select 'yes' if this tuner is connected to the SCR device through another tuner, otherwise select 'no'.")) self.list.append(self.advancedConnected) if nimConfig_advanced.unicableconnected.value: nimConfig_advanced.unicableconnectedTo.setChoices(choices) diff --git a/lib/python/Screens/Timers.py b/lib/python/Screens/Timers.py index 056fcf9feff..d2a08448f4e 100644 --- a/lib/python/Screens/Timers.py +++ b/lib/python/Screens/Timers.py @@ -1501,20 +1501,6 @@ def selectionChanged(self): if self.timerType.value != "zap": self.getSpace() - def getSpace(self): - if config.recording.timerviewshowfreespace.value: - try: - device = stat(self.timerLocation.value).st_dev - if device in DEFAULT_INHIBIT_DEVICES: - self.setFootnote(_("Warning: Recordings should not be stored on the Flash disk!")) - else: - status = statvfs(self.timerLocation.value) - total = status.f_blocks * status.f_bsize - free = status.f_bavail * status.f_bsize - self.setFootnote(_("Space total %s, used %s, free %s (%0.f%%).") % (scaleNumber(total), scaleNumber(total - free), scaleNumber(free), 100.0 * free / total)) - except OSError as err: - self.setFootnote(_("Error %d: Unable to check space! (%s)") % (err.errno, err.strerror)) - def keySelect(self): current = self["config"].getCurrent()[1] if current == self.timerLocation: @@ -1712,17 +1698,18 @@ def getLocationCallback(result): self.session.openWithCallback(getLocationCallback, MovieLocationBox, _("Select the location in which to store the recording:"), self.timerLocation.value, minFree=100) # We require at least 100MB free space. def getSpace(self): - try: - device = stat(self.timerLocation.value).st_dev - if device in DEFAULT_INHIBIT_DEVICES: - self.setFootnote(_("Warning: Recordings should not be stored on the Flash disk!")) - else: - status = statvfs(self.timerLocation.value) - total = status.f_blocks * status.f_bsize - free = status.f_bavail * status.f_bsize - self.setFootnote(_("Space total %s, used %s, free %s (%0.f%%).") % (scaleNumber(total), scaleNumber(total - free), scaleNumber(free), 100.0 * free / total)) - except OSError as err: - self.setFootnote(_("Error %d: Unable to check space! (%s)") % (err.errno, err.strerror)) + if config.recording.timerviewshowfreespace.value: + try: + device = stat(self.timerLocation.value).st_dev + if device in DEFAULT_INHIBIT_DEVICES: + self.setFootnote(_("Warning: Recordings should not be stored on the Flash disk!")) + else: + status = statvfs(self.timerLocation.value) + total = status.f_blocks * status.f_bsize + free = status.f_bavail * status.f_bsize + self.setFootnote(_("Space total %s, used %s, free %s (%0.f%%).") % (scaleNumber(total), scaleNumber(total - free), scaleNumber(free), 100.0 * free / total)) + except OSError as err: + self.setFootnote(_("Error %d: Unable to check space! (%s)") % (err.errno, err.strerror)) # # Do not rename the methods above as they are designed to be overwritten in sub-classes. diff --git a/lib/python/Screens/VideoWizard.py b/lib/python/Screens/VideoWizard.py index 62cb1b4a4e5..aaca2ac8dfd 100644 --- a/lib/python/Screens/VideoWizard.py +++ b/lib/python/Screens/VideoWizard.py @@ -58,7 +58,7 @@ def sortKey(name): preferred = "" try: if BoxInfo.getItem("AmlogicFamily"): - fd =open("/sys/class/amhdmitx/amhdmitx0/disp_cap") + fd = open("/sys/class/amhdmitx/amhdmitx0/disp_cap") preferred = fd.read()[:-1].replace('*', '') fd.close() else: @@ -179,5 +179,9 @@ def saveWizardChanges(self): # Called by wizardvideo.xml. config.misc.videowizardenabled.save() configfile.save() + def keyRed(self): # Thats is only a temporary workaround for language selection + self.timeoutTimer.stop() + self.red() + def createSummary(self): return WizardSummary diff --git a/lib/python/Tools/Geolocation.py b/lib/python/Tools/Geolocation.py index 8887321d435..35841a54d2d 100644 --- a/lib/python/Tools/Geolocation.py +++ b/lib/python/Tools/Geolocation.py @@ -1,7 +1,7 @@ from json import loads +from requests import exceptions, get +from enigma import checkInternetAccess -from urllib.request import urlopen -from urllib.error import URLError # Data available from http://ip-api.com/json/: # @@ -39,7 +39,6 @@ # proxy Proxy, VPN or Tor exit address true bool # hosting Hosting, colocated or data center true bool # query IP used for the query 173.194.67.94 string - geolocationFields = { "country": 0x00000001, "countryCode": 0x00000002, @@ -73,8 +72,8 @@ class Geolocation: def __init__(self): self.geolocation = {} - # Enable this line to force load the geolocation data on initialisation. - # NOT: Doing this without user concent may violate privacy laws! + # Enable this line to force load the geolocation data on initialization. + # NOT: Doing this without user consent may violate privacy laws! # self.getGeolocationData(fields=None) def getGeolocationData(self, fields=None, useCache=True): @@ -82,27 +81,36 @@ def getGeolocationData(self, fields=None, useCache=True): if useCache and self.checkGeolocationData(fields): print("[Geolocation] Using cached data.") return self.geolocation - try: - response = urlopen("http://ip-api.com/json/?fields=%s" % fields, data=None, timeout=10).read() - if response: - geolocation = loads(response) - status = geolocation.get("status", "unknown/undefined") - if status and status == "success": - print("[Geolocation] Geolocation data retreived.") - for key in geolocation.keys(): - self.geolocation[key] = geolocation[key] - return self.geolocation - else: - print("[Geolocation] Error: Geolocation lookup returned '%s' status! Message '%s' returned." % (status, geolocation.get("message", None))) - except URLError as err: - if hasattr(err, "code"): - print("[Geolocation] Error: Geolocation data not available! (Code: %s)" % err.code) - if hasattr(err, "reason"): - print("[Geolocation] Error: Geolocation data not available! (Reason: %s)" % err.reason) - except ValueError: - print("[Geolocation] Error: Geolocation data returned can not be processed!") - except Exception: - print("[Geolocation] Error: Geolocation network connection failed!") + internetAccess = checkInternetAccess("ip-api.com", 3) + if internetAccess == 0: # 0=Site reachable, 1=DNS error, 2=Other network error, 3=No link, 4=No active adapter. + try: + response = get("http://ip-api.com/json/?fields=%s" % fields, timeout=(3, 2)) + if response.status_code == 200 and response.content: + geolocation = loads(response.content) + status = geolocation.get("status", "unknown/undefined") + if status and status == "success": + print("[Geolocation] Geolocation data retrieved.") + for key in geolocation.keys(): + self.geolocation[key] = geolocation[key] + return self.geolocation + else: + print("[Geolocation] Error: Geolocation lookup returned '%s' status! Message '%s' returned." % (status, geolocation.get("message", None))) + else: + print("[Geolocation] Error: Geolocation lookup returned a status code of %d!" % response.status_code) + except exceptions.RequestException as err: + print("[Geolocation] Error: Geolocation server connection failure! (%s)" % str(err)) + except ValueError: + print("[Geolocation] Error: Geolocation data returned can not be processed!") + except Exception as err: + print("[Geolocation] Error: Unexpected error! (%s)" % str(err)) + elif internetAccess == 1: + print("[Geolocation] Error: Geolocation server DNS error!") + elif internetAccess == 2: + print("[Geolocation] Error: Internet access error!") + elif internetAccess == 3: + print("[Geolocation] Error: Network adapter not connected to a network!") + elif internetAccess == 4: + print("[Geolocation] Error: No network adapter enabled/available!") return {} def fieldsToNumber(self, fields): diff --git a/lib/python/Tools/MultiBoot.py b/lib/python/Tools/MultiBoot.py index 58285b868aa..6920b5195eb 100644 --- a/lib/python/Tools/MultiBoot.py +++ b/lib/python/Tools/MultiBoot.py @@ -586,7 +586,10 @@ def bootDeviceMounted(self, data, retVal, extraArgs): # Part of activateSlot(). else: bootSlot = self.bootSlots[self.slotCode] startup = bootSlot["startupfile"][self.bootCode] - target = STARTUP_ONCE if startup == STARTUP_RECOVERY else STARTUP_FILE + if fileHas("/proc/cmdline", "kexec=1") and startup == STARTUP_RECOVERY: + target = STARTUP_FILE + else: + target = STARTUP_ONCE if startup == STARTUP_RECOVERY else STARTUP_FILE copyfile(pathjoin(self.tempDir, startup), pathjoin(self.tempDir, target)) if exists(DUAL_BOOT_FILE): slot = self.slotCode if self.slotCode.isdecimal() else "0" diff --git a/lib/python/connections.h b/lib/python/connections.h index 8e889194321..f82ec7c4224 100644 --- a/lib/python/connections.h +++ b/lib/python/connections.h @@ -22,7 +22,7 @@ class PSignal inline PyObject *PyFrom(int v) { - return PyInt_FromLong(v); + return PyLong_FromLong(v); } inline PyObject *PyFrom(const char *c) diff --git a/lib/python/enigma_python.i b/lib/python/enigma_python.i index d4858c9899a..62ab16a067b 100644 --- a/lib/python/enigma_python.i +++ b/lib/python/enigma_python.i @@ -487,6 +487,7 @@ extern void setAnimation_current_listbox(int a); #endif extern void pauseInit(void); extern void resumeInit(void); +extern int checkInternetAccess(const char* host, int timeout = 3); %} extern void addFont(const char *filename, const char *alias, int scale_factor, int is_replacement, int renderflags = 0); @@ -508,6 +509,7 @@ extern void setAnimation_current_listbox(int a); #endif extern void pauseInit(void); extern void resumeInit(void); +extern int checkInternetAccess(const char* host, int timeout = 3); %include %include diff --git a/lib/python/python.h b/lib/python/python.h index ea8381fad83..380cc68312e 100644 --- a/lib/python/python.h +++ b/lib/python/python.h @@ -260,11 +260,6 @@ inline ePyObject Impl_PyString_FromFormat(const char* file, int line, const char return ePyObject(ob, file, line); } -inline ePyObject Impl_PyInt_FromLong(const char* file, int line, long val) -{ - return ePyObject(PyLong_FromLong(val), file, line); -} - inline ePyObject Impl_PyLong_FromLong(const char* file, int line, long val) { return ePyObject(PyLong_FromLong(val), file, line); @@ -357,11 +352,6 @@ inline ePyObject Impl_PyString_FromFormat(const char *fmt, ...) return ePyObject(ob); } -inline ePyObject Impl_PyInt_FromLong(long val) -{ - return PyLong_FromLong(val); -} - inline ePyObject Impl_PyLong_FromLong(long val) { return PyLong_FromLong(val); @@ -423,7 +413,7 @@ inline void Impl_DECREF(PyObject *ob) #define PyDict_New(...) Impl_PyDict_New(__FILE__, __LINE__) #define PyString_FromString(str) Impl_PyString_FromString(__FILE__, __LINE__, str) #define PyString_FromFormat(str, args...) Impl_PyString_FromFormat(__FILE__, __LINE__, str, args) -#define PyInt_FromLong(val) Impl_PyInt_FromLong(__FILE__, __LINE__, val) +#define PyInt_FromLong(val) Impl_PyLong_FromLong(__FILE__, __LINE__, val) #define PyLong_FromLong(val) Impl_PyLong_FromLong(__FILE__, __LINE__, val) #define PyLong_FromUnsignedLong(val) Impl_PyLong_FromUnsignedLong(__FILE__, __LINE__, val) #define PyLong_FromLongLong(val) Impl_PyLong_FromLongLong(__FILE__, __LINE__, val) @@ -439,7 +429,7 @@ inline void Impl_DECREF(PyObject *ob) #define PyDict_New(...) Impl_PyDict_New() #define PyString_FromString(str) Impl_PyString_FromString(str) #define PyString_FromFormat(str, args...) Impl_PyString_FromFormat(str, args) -#define PyInt_FromLong(val) Impl_PyInt_FromLong(val) +#define PyInt_FromLong(val) Impl_PyLong_FromLong(val) #define PyLong_FromLong(val) Impl_PyLong_FromLong(val) #define PyLong_FromUnsignedLong(val) Impl_PyLong_FromUnsignedLong(val) #define PyLong_FromLongLong(val) Impl_PyLong_FromLongLong(val) diff --git a/lib/python/python_base.i b/lib/python/python_base.i index 8e87a14edf4..8aa8ed11799 100644 --- a/lib/python/python_base.i +++ b/lib/python/python_base.i @@ -299,13 +299,13 @@ extern "C" { static PyObject * eSocketNotifierPy_get_fd(eSocketNotifierPy* self) { - return PyInt_FromLong(self->sn->getFD()); + return PyLong_FromLong(self->sn->getFD()); } static PyObject * eSocketNotifierPy_get_requested(eSocketNotifierPy* self) { - return PyInt_FromLong(self->sn->getRequested()); + return PyLong_FromLong(self->sn->getRequested()); } static PyObject * diff --git a/lib/python/python_console.i b/lib/python/python_console.i index d270e15453b..f4f860f867f 100644 --- a/lib/python/python_console.i +++ b/lib/python/python_console.i @@ -170,13 +170,13 @@ extern "C" { argv[argpos++] = PyUnicode_AsUTF8(arg); } argv[argpos] = 0; - return PyInt_FromLong(self->cont->execute(argv[0], argv+1)); + return PyLong_FromLong(self->cont->execute(argv[0], argv+1)); } else { const char *str; if (PyArg_ParseTuple(argt, "s", &str)) - return PyInt_FromLong(self->cont->execute(str)); + return PyLong_FromLong(self->cont->execute(str)); PyErr_SetString(PyExc_TypeError, "cmd is not a string!"); } @@ -243,7 +243,7 @@ extern "C" { static PyObject * eConsolePy_getPID(eConsolePy* self) { - return PyInt_FromLong(self->cont->getPID()); + return PyLong_FromLong(self->cont->getPID()); } static PyObject * diff --git a/lib/python/python_helpers.cpp b/lib/python/python_helpers.cpp index f6299c84425..60c78e562af 100644 --- a/lib/python/python_helpers.cpp +++ b/lib/python/python_helpers.cpp @@ -2,7 +2,7 @@ void PutToDict(ePyObject &dict, const char *key, long value) { - ePyObject item = PyInt_FromLong(value); + ePyObject item = PyLong_FromLong(value); if (item) { if (PyDict_SetItemString(dict, key, item)) @@ -41,7 +41,7 @@ void PutToDict(ePyObject &dict, const char *key, const char *value) static PyObject *createTuple(int pid, const char *type) { PyObject *r = PyTuple_New(2); - PyTuple_SET_ITEM(r, 0, PyInt_FromLong(pid)); + PyTuple_SET_ITEM(r, 0, PyLong_FromLong(pid)); PyTuple_SET_ITEM(r, 1, PyString_FromString(type)); return r; } diff --git a/lib/python/python_pcore.i b/lib/python/python_pcore.i index 23f708c7ac9..076014c35af 100644 --- a/lib/python/python_pcore.i +++ b/lib/python/python_pcore.i @@ -23,7 +23,7 @@ PyObject *getRecordingsTypesOnly(pNavigation::RecordType type=pNavigation::isAny self->getRecordingsTypesOnly(returnedTypes, type); ePyObject result = PyList_New(returnedTypes.size()); for (unsigned int i = 0; i < returnedTypes.size(); i++) - PyList_SET_ITEM(result, i, PyInt_FromLong(int(returnedTypes[i]))); + PyList_SET_ITEM(result, i, PyLong_FromLong(int(returnedTypes[i]))); return result; } PyObject *getRecordingsSlotIDsOnly(pNavigation::RecordType type=pNavigation::isAnyRecording) @@ -32,7 +32,7 @@ PyObject *getRecordingsSlotIDsOnly(pNavigation::RecordType type=pNavigation::isA self->getRecordingsSlotIDsOnly(slotids, type); ePyObject result = PyList_New(slotids.size()); for (unsigned int i = 0; i < slotids.size(); i++) - PyList_SET_ITEM(result, i, PyInt_FromLong(slotids[i])); + PyList_SET_ITEM(result, i, PyLong_FromLong(slotids[i])); return result; } PyObject *getRecordingsServicesAndTypes(pNavigation::RecordType type=pNavigation::isAnyRecording) @@ -46,7 +46,7 @@ PyObject *getRecordingsServicesAndTypes(pNavigation::RecordType type=pNavigation { ePyObject tuple = PyTuple_New(2); PyTuple_SET_ITEM(tuple, 0, PyString_FromString(services[i].toString().c_str())); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(int(returnedTypes[i]))); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(int(returnedTypes[i]))); PyList_Append(l, tuple); Py_DECREF(tuple); } @@ -65,8 +65,8 @@ PyObject *getRecordingsServicesAndTypesAndSlotIDs(pNavigation::RecordType type=p { ePyObject tuple = PyTuple_New(3); PyTuple_SET_ITEM(tuple, 0, PyString_FromString(services[i].toString().c_str())); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(int(returnedTypes[i]))); - PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(slotids[i])); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(int(returnedTypes[i]))); + PyTuple_SET_ITEM(tuple, 2, PyLong_FromLong(slotids[i])); PyList_Append(l, tuple); Py_DECREF(tuple); } diff --git a/lib/python/python_pmt.i b/lib/python/python_pmt.i index 1af17c75514..5148024d9a0 100644 --- a/lib/python/python_pmt.i +++ b/lib/python/python_pmt.i @@ -14,14 +14,14 @@ PyObject *eDVBServicePMTHandler::getCaIds(bool pair) if (pair) { ePyObject tuple = PyTuple_New(3); - PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(caids[i])); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(ecmpids[i])); + PyTuple_SET_ITEM(tuple, 0, PyLong_FromLong(caids[i])); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(ecmpids[i])); PyTuple_SET_ITEM(tuple, 2, PyString_FromString(databytes[i].c_str())); PyList_SET_ITEM(ret, i, tuple); } else { - PyList_SET_ITEM(ret, i, PyInt_FromLong(caids[i])); + PyList_SET_ITEM(ret, i, PyLong_FromLong(caids[i])); } } diff --git a/lib/python/python_service.i b/lib/python/python_service.i index e8a94e08772..3cfed041bab 100644 --- a/lib/python/python_service.i +++ b/lib/python/python_service.i @@ -39,7 +39,7 @@ PyObject *getInfoObject(int w) for (unsigned int i = 0; i < cnt; i++) { - PyList_SET_ITEM(ret, i, PyInt_FromLong(caids[i])); + PyList_SET_ITEM(ret, i, PyLong_FromLong(caids[i])); } return ret; } @@ -56,8 +56,8 @@ PyObject *getInfoObject(int w) for (unsigned int i = 0; i < cnt; i++) { ePyObject tuple = PyTuple_New(3); - PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(caids[i])); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(ecmpids[i])); + PyTuple_SET_ITEM(tuple, 0, PyLong_FromLong(caids[i])); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(ecmpids[i])); PyTuple_SET_ITEM(tuple, 2, PyString_FromString(databytes[i].c_str())); PyList_SET_ITEM(ret, i, tuple); } @@ -71,7 +71,7 @@ PyObject *getInfoObject(int w) ePtr info = self->getInfoObject(w); if (info) { - PyTuple_SetItem(tuple, 0, PyInt_FromLong(info->getInteger(0))); + PyTuple_SetItem(tuple, 0, PyLong_FromLong(info->getInteger(0))); PyTuple_SetItem(tuple, 1, PyString_FromString(info->getString(0).c_str())); PyTuple_SetItem(tuple, 2, PyString_FromString(info->getString(1).c_str())); } @@ -86,7 +86,7 @@ PyObject *getInfoObject(int w) ePtr info = self->getInfoObject(w); if (info) { - PyTuple_SetItem(tuple, 0, PyInt_FromLong(info->getInteger(0))); + PyTuple_SetItem(tuple, 0, PyLong_FromLong(info->getInteger(0))); PyTuple_SetItem(tuple, 1, PyString_FromString(info->getString(0).c_str())); } } @@ -100,8 +100,8 @@ PyObject *getInfoObject(int w) ePtr info = self->getInfoObject(w); if (info) { - PyTuple_SetItem(tuple, 0, PyInt_FromLong(info->getInteger(0))); - PyTuple_SetItem(tuple, 1, PyInt_FromLong(info->getInteger(1))); + PyTuple_SetItem(tuple, 0, PyLong_FromLong(info->getInteger(0))); + PyTuple_SetItem(tuple, 1, PyLong_FromLong(info->getInteger(1))); } } return tuple; @@ -145,7 +145,7 @@ PyObject *getAITApplications() for (std::map::iterator it=aitlist.begin(); it!=aitlist.end(); ++it) { ePyObject tuple = PyTuple_New(2); - PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(it->first)); + PyTuple_SET_ITEM(tuple, 0, PyLong_FromLong(it->first)); PyTuple_SET_ITEM(tuple, 1, PyString_FromString(it->second.c_str())); PyList_Append(l, tuple); Py_DECREF(tuple); @@ -286,11 +286,11 @@ PyObject *getBufferCharge() ePtr info = self->getBufferCharge(); if (info) { - PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(info->getBufferPercentage())); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(info->getAverageInputRate())); - PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(info->getAverageOutputRate())); - PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(info->getBufferSpace())); - PyTuple_SET_ITEM(tuple, 4, PyInt_FromLong(info->getBufferSize())); + PyTuple_SET_ITEM(tuple, 0, PyLong_FromLong(info->getBufferPercentage())); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(info->getAverageInputRate())); + PyTuple_SET_ITEM(tuple, 2, PyLong_FromLong(info->getAverageOutputRate())); + PyTuple_SET_ITEM(tuple, 3, PyLong_FromLong(info->getBufferSpace())); + PyTuple_SET_ITEM(tuple, 4, PyLong_FromLong(info->getBufferSize())); } } return tuple; @@ -374,10 +374,10 @@ PyObject *getSubtitleList() for (unsigned int i = 0; i < subtitlelist.size(); i++) { ePyObject tuple = PyTuple_New(5); - PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(subtitlelist[i].type)); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(subtitlelist[i].pid)); - PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(subtitlelist[i].page_number)); - PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(subtitlelist[i].magazine_number)); + PyTuple_SET_ITEM(tuple, 0, PyLong_FromLong(subtitlelist[i].type)); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(subtitlelist[i].pid)); + PyTuple_SET_ITEM(tuple, 2, PyLong_FromLong(subtitlelist[i].page_number)); + PyTuple_SET_ITEM(tuple, 3, PyLong_FromLong(subtitlelist[i].magazine_number)); PyTuple_SET_ITEM(tuple, 4, PyString_FromString(subtitlelist[i].language_code.c_str())); PyList_Append(l, tuple); Py_DECREF(tuple); @@ -394,10 +394,10 @@ PyObject *getCachedSubtitle() if (self->getCachedSubtitle(track) >= 0) { ePyObject tuple = PyTuple_New(5); - PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(track.type)); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(track.pid)); - PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(track.page_number)); - PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(track.magazine_number)); + PyTuple_SET_ITEM(tuple, 0, PyLong_FromLong(track.type)); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(track.pid)); + PyTuple_SET_ITEM(tuple, 2, PyLong_FromLong(track.page_number)); + PyTuple_SET_ITEM(tuple, 3, PyLong_FromLong(track.magazine_number)); PyTuple_SET_ITEM(tuple, 4, PyString_FromString(track.language_code.c_str())); return tuple; } diff --git a/lib/service/event.cpp b/lib/service/event.cpp index 916e2df068f..cb19401e4c0 100644 --- a/lib/service/event.cpp +++ b/lib/service/event.cpp @@ -397,10 +397,10 @@ PyObject *eServiceEvent::getGenreDataList() const for (std::list::const_iterator it(m_genres.begin()); it != m_genres.end(); ++it) { ePyObject tuple = PyTuple_New(4); - PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(it->getLevel1())); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->getLevel2())); - PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->getUser1())); - PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->getUser2())); + PyTuple_SET_ITEM(tuple, 0, PyLong_FromLong(it->getLevel1())); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(it->getLevel2())); + PyTuple_SET_ITEM(tuple, 2, PyLong_FromLong(it->getUser1())); + PyTuple_SET_ITEM(tuple, 3, PyLong_FromLong(it->getUser2())); PyList_SET_ITEM(ret, cnt++, tuple); } return ret; @@ -426,7 +426,7 @@ PyObject *eServiceEvent::getParentalDataList() const { ePyObject tuple = PyTuple_New(2); PyTuple_SET_ITEM(tuple, 0, PyString_FromString(it->getCountryCode().c_str())); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->getRating())); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(it->getRating())); PyList_SET_ITEM(ret, cnt++, tuple); } return ret; @@ -443,8 +443,8 @@ PyObject *eServiceEvent::getCridData(int mask) const if ((1 << cridMatchType) & mask) { ePyObject tuple = PyTuple_New(3); - PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(it->getType())); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->getLocation())); + PyTuple_SET_ITEM(tuple, 0, PyLong_FromLong(it->getType())); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(it->getLocation())); PyTuple_SET_ITEM(tuple, 2, PyString_FromString(it->getCrid().c_str())); PyList_Append(ret, tuple); } @@ -475,9 +475,9 @@ PyObject *eServiceEvent::getComponentDataList() const for (std::list::const_iterator it(m_component_data.begin()); it != m_component_data.end(); ++it) { ePyObject tuple = PyTuple_New(5); - PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(it->m_componentTag)); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->m_componentType)); - PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->m_streamContent)); + PyTuple_SET_ITEM(tuple, 0, PyLong_FromLong(it->m_componentTag)); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(it->m_componentType)); + PyTuple_SET_ITEM(tuple, 2, PyLong_FromLong(it->m_streamContent)); PyTuple_SET_ITEM(tuple, 3, PyString_FromString(it->m_iso639LanguageCode.c_str())); PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->m_text.c_str())); PyList_SET_ITEM(ret, cnt++, tuple); diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp index 7422abc6cc9..293af61e376 100644 --- a/lib/service/servicedvb.cpp +++ b/lib/service/servicedvb.cpp @@ -2720,7 +2720,7 @@ PyObject *eDVBServicePlay::getCutList() { ePyObject tuple = PyTuple_New(2); PyTuple_SET_ITEM(tuple, 0, PyLong_FromLongLong(i->where)); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(i->what)); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(i->what)); PyList_Append(list, tuple); Py_DECREF(tuple); } diff --git a/lib/service/servicemp3.cpp b/lib/service/servicemp3.cpp index 744f0f68eb8..2fb0b851bfa 100644 --- a/lib/service/servicemp3.cpp +++ b/lib/service/servicemp3.cpp @@ -3117,7 +3117,7 @@ PyObject *eServiceMP3::getCutList() { ePyObject tuple = PyTuple_New(2); PyTuple_SET_ITEM(tuple, 0, PyLong_FromLongLong(i->where)); - PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(i->what)); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(i->what)); PyList_Append(list, tuple); Py_DECREF(tuple); } diff --git a/main/enigma.cpp b/main/enigma.cpp index ebcc8c4d7e5..1e970ff00aa 100644 --- a/main/enigma.cpp +++ b/main/enigma.cpp @@ -5,6 +5,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -123,7 +128,6 @@ void keyEvent(const eRCKey &key) } /************************************************/ -#include #include #include #include @@ -134,7 +138,7 @@ void keyEvent(const eRCKey &key) /* Defined in eerror.cpp */ void setDebugTime(int level); -class eMain: public eApplication, public sigc::trackable +class eMain : public eApplication, public sigc::trackable { eInit init; ePythonConfigQuery config; @@ -169,46 +173,46 @@ class eMain: public eApplication, public sigc::trackable } }; -bool replace(std::string& str, const std::string& from, const std::string& to) +bool replace(std::string &str, const std::string &from, const std::string &to) { size_t start_pos = str.find(from); - if(start_pos == std::string::npos) + if (start_pos == std::string::npos) return false; str.replace(start_pos, from.length(), to); return true; } -static const std::string getConfigCurrentSpinner(const char* key) +static const std::string getConfigCurrentSpinner(const char *key) { auto value = eSimpleConfig::getString(key); // if value is not empty, means config.skin.primary_skin exist in settings file - if (!value.empty()) + if (!value.empty()) { replace(value, "skin.xml", "spinner"); std::string png_location = eEnv::resolve("${datadir}/enigma2/" + value + "/wait1.png"); std::ifstream png(png_location.c_str()); - if (png.good()) { + if (png.good()) + { png.close(); return value; // if value is NOT empty, means config.skin.primary_skin exist in settings file, so return SCOPE_GUISKIN + "/spinner" ( /usr/share/enigma2/MYSKIN/spinner/wait1.png exist ) } - } - // try to find spinner in skin_default/spinner subfolder + // try to find spinner in skin_default/spinner subfolder value = "skin_default/spinner"; // check /usr/share/enigma2/skin_default/spinner/wait1.png std::string png_location = eEnv::resolve("${datadir}/enigma2/" + value + "/wait1.png"); std::ifstream png(png_location.c_str()); - if (png.good()) { + if (png.good()) + { png.close(); return value; // ( /usr/share/enigma2/skin_default/spinner/wait1.png exist ) } else - return "spinner"; // ( /usr/share/enigma2/skin_default/spinner/wait1.png DOES NOT exist ) - + return "spinner"; // ( /usr/share/enigma2/skin_default/spinner/wait1.png DOES NOT exist ) } int exit_code; @@ -298,12 +302,11 @@ int main(int argc, char **argv) ePtr my_dc; gMainDC::getInstance(my_dc); - //int double_buffer = my_dc->haveDoubleBuffering(); + // int double_buffer = my_dc->haveDoubleBuffering(); ePtr my_lcd_dc; gLCDDC::getInstance(my_lcd_dc); - /* ok, this is currently hardcoded for arabic. */ /* some characters are wrong in the regular font, force them to use the replacement font */ for (int i = 0x60c; i <= 0x66d; ++i) @@ -318,11 +321,13 @@ int main(int argc, char **argv) dsk.setStyleID(0); dsk_lcd.setStyleID(my_lcd_dc->size().width() == 96 ? 2 : 1); -/* if (double_buffer) + /* + if (double_buffer) { eDebug("[Enigma] Double buffering found, enable buffered graphics mode."); dsk.setCompositionMode(eWidgetDesktop::cmBuffered); - } */ + } + */ wdsk = &dsk; lcddsk = &dsk_lcd; @@ -330,16 +335,16 @@ int main(int argc, char **argv) dsk.setDC(my_dc); dsk_lcd.setDC(my_lcd_dc); - dsk.setBackgroundColor(gRGB(0,0,0,0xFF)); + dsk.setBackgroundColor(gRGB(0, 0, 0, 0xFF)); #endif - /* redrawing is done in an idle-timer, so we have to set the context */ + /* redrawing is done in an idle-timer, so we have to set the context */ dsk.setRedrawTask(main); dsk_lcd.setRedrawTask(main); std::string active_skin = getConfigCurrentSpinner("config.skin.primary_skin"); std::string spinnerPostion = eSimpleConfig::getString("config.misc.spinnerPosition", "100,100"); - int spinnerPostionX,spinnerPostionY; + int spinnerPostionX, spinnerPostionY; if (sscanf(spinnerPostion.c_str(), "%d,%d", &spinnerPostionX, &spinnerPostionY) != 2) { spinnerPostionX = spinnerPostionY = 100; @@ -360,13 +365,14 @@ int main(int argc, char **argv) rfilename = eEnv::resolve(filename); struct stat st; - if (::stat(rfilename.c_str(), &st) == 0) { + if (::stat(rfilename.c_str(), &st) == 0) + { def = true; skinpath = userpath; } ePtr wait[MAX_SPINNER]; - while(i < MAX_SPINNER) + while (i < MAX_SPINNER) { snprintf(filename, sizeof(filename), "%s/wait%d.png", skinpath.c_str(), i + 1); rfilename = eEnv::resolve(filename); @@ -375,10 +381,10 @@ int main(int argc, char **argv) if (::stat(rfilename.c_str(), &st) == 0) loadPNG(wait[i], rfilename.c_str()); - if (!wait[i]) + if (!wait[i]) { // spinner failed - if (i==0) + if (i == 0) { // retry default spinner only once if (!def) @@ -394,7 +400,7 @@ int main(int argc, char **argv) i++; } eDebug("[Enigma] Found %d spinners.", i); - if (i==0) + if (i == 0) my_dc->setSpinner(eRect(spinnerPostionX, spinnerPostionY, 0, 0), wait, 1); else my_dc->setSpinner(eRect(ePoint(spinnerPostionX, spinnerPostionY), wait[0]->size()), wait, i); @@ -483,7 +489,6 @@ void dump_malloc_stats(void) #ifdef USE_LIBVUGLES2 #include - void setAnimation_current(int a) { gles_set_animation_func(a); @@ -505,3 +510,136 @@ void setAnimation_speed(int speed) {} void setAnimation_current_listbox(int a) {} #endif #endif + +std::string getActiveAdapter() +{ + std::string ret = ""; + struct ifaddrs *ifaddr, *ifa; + int status; + // Get the list of network interfaces + status = getifaddrs(&ifaddr); + if (status != 0) + { + eDebug("[Enigma] getActiveAdapter: Failed to get network interfaces."); + return ""; + } + // Iterate through the network interfaces + for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr == nullptr) + continue; + if (ifa->ifa_flags & IFF_LOOPBACK) // ignore loopback + continue; + // Check if the interface is active and has an IP address + if ((ifa->ifa_flags & IFF_UP) && (ifa->ifa_addr->sa_family == AF_INET || + ifa->ifa_addr->sa_family == AF_INET6)) + { + + if (strstr(ifa->ifa_name, "eth") || strstr(ifa->ifa_name, "wlan")) + { + eDebug("[Enigma] getActiveAdapter: Active network interface: %s.", ifa->ifa_name); + ret = ifa->ifa_name; + break; + } + } + } + freeifaddrs(ifaddr); + return ret; +} + +int checkLinkStatus() +{ + std::string interface = getActiveAdapter(); + if (interface.empty()) + { + eDebug("[Enigma] checkLinkStatus: No valid active network adapter."); + return 4; + } + + int sock; + struct ifreq ifr; + // Create a socket + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + { + eDebug("[Enigma] checkLinkStatus: Failed to create socket."); + return 3; + } + // Set the interface name + strncpy(ifr.ifr_name, interface.c_str(), IFNAMSIZ); + // Get the interface flags + if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) + { + eDebug("[Enigma] checkLinkStatus: Failed to get interface flags."); + close(sock); + return 3; + } + int ret = (ifr.ifr_flags & IFF_RUNNING) ? 0 : 3; + close(sock); + return ret; +} + +#include +#include + +size_t curl_ignore_output(void *ptr, size_t size, size_t nmemb, void *stream) // NOSONAR +{ + (void)ptr; + (void)stream; + return size * nmemb; +} + +int checkInternetAccess(const char *host, int timeout = 3) +{ + + int link = checkLinkStatus(); + if (link != 0) + { + eDebug("[Enigma] checkInternetAccess: No Active link."); + return link; + } + + CURL *curl; + CURLcode res; + int ret = 0; // SUCCESS + curl = curl_easy_init(); + if (curl) + { + eDebug("[Enigma] checkInternetAccess: Check host:'%s' with timeout:%d.", host, timeout); + curl_easy_setopt(curl, CURLOPT_URL, host); + curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); + curl_easy_setopt(curl, CURLOPT_NOBODY, 1); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_ignore_output); + while ((res = curl_easy_perform(curl)) != CURLE_OK) + { + switch (res) + { + case CURLE_COULDNT_RESOLVE_HOST: + eDebug("[Enigma] checkInternetAccess: Failed to resolve host."); + ret = 1; + break; + case CURLE_COULDNT_CONNECT: + case CURLE_COULDNT_RESOLVE_PROXY: + eDebug("[Enigma] checkInternetAccess: Failed."); + ret = 2; + break; + default: + eDebug("[Enigma] checkInternetAccess: Failed with error (%s).", curl_easy_strerror(res)); + ret = 2; + break; + } + if (ret > 0) + break; + } + curl_easy_cleanup(curl); + } + else + { + eDebug("[Enigma] checkInternetAccess: Failed to init curl."); + return 2; + } + if (ret == 0) + eDebug("[Enigma] checkInternetAccess: Success."); + return ret; +}