示例#1
0
class AutoBouquetsMaker_FrequencyFinder(Screen):
    skin = skin_downloadBar()

    def __init__(self, session, args=0):
        print "[ABM-FrequencyFinder][__init__] Starting..."
        print "[ABM-FrequencyFinder][__init__] args", args
        self.session = session
        Screen.__init__(self, session)
        Screen.setTitle(self, _("FrequencyFinder"))
        self.skinName = ["AutoBouquetsMaker"]

        self.frontend = None
        self.rawchannel = None

        self["background"] = Pixmap()
        self["action"] = Label(_("Starting scanner"))
        self["status"] = Label("")
        self["progress"] = ProgressBar()
        self["progress_text"] = Progress()
        self["Frontend"] = FrontendStatus(
            frontend_source=lambda: self.frontend, update_interval=100)

        self["actions"] = ActionMap(["SetupActions"], {
            "cancel": self.keyCancel,
        }, -2)

        self.selectedNIM = -1  # -1 is automatic selection
        self.uhf_vhf = "uhf"
        self.networkid = 0  # this is an onid, not a regional network id
        self.restrict_to_networkid = False
        if args:  # These can be added in ABM config at some time in the future
            if "feid" in args:
                self.selectedNIM = args["feid"]
            if "uhf_vhf" in args:
                self.uhf_vhf = args["uhf_vhf"]
            if "networkid" in args:
                self.networkid = args["networkid"]
            if "restrict_to_networkid" in args:
                self.restrict_to_networkid = args["restrict_to_networkid"]
        self.isT2tuner = False  # unlikely any modern internal terrestrial tuner can't play T2, but some USB tuners can't
        self.session.postScanService = None
        self.index = 0
        self.frequency = 0
        self.system = eDVBFrontendParametersTerrestrial.System_DVB_T
        self.lockTimeout = 50  # 100ms for tick - 5 sec
        self.snrTimeout = 100  # 100ms for tick - 10 sec
        #self.bandwidth = 8 # MHz
        self.scanTransponders = []
        if self.uhf_vhf == "uhf_vhf":
            bandwidth = 7
            for a in range(5, 13):  # channel
                for b in (eDVBFrontendParametersTerrestrial.System_DVB_T,
                          eDVBFrontendParametersTerrestrial.System_DVB_T2
                          ):  # system
                    self.scanTransponders.append({
                        "frequency":
                        channel2freq(a, bandwidth),
                        "system":
                        b,
                        "bandwidth":
                        bandwidth
                    })
        if self.uhf_vhf in ("uhf", "uhf_vhf"):
            bandwidth = 8
            for a in range(21, 70):  # channel
                for b in (eDVBFrontendParametersTerrestrial.System_DVB_T,
                          eDVBFrontendParametersTerrestrial.System_DVB_T2
                          ):  # system
                    self.scanTransponders.append({
                        "frequency":
                        channel2freq(a, bandwidth),
                        "system":
                        b,
                        "bandwidth":
                        bandwidth
                    })
        self.transponders_found = []
        self.transponders_unique = {}
        #		self.custom_dir = os.path.dirname(__file__) + "/../custom"
        #		self.customfile = self.custom_dir + "/CustomTranspondersOverride.xml"
        #		self.removeFileIfExists(self.customfile)
        self.providers_dir = os.path.dirname(__file__) + "/../providers"
        self.providersfile = self.providers_dir + "/terrestrial_finder.xml"
        self.network_name = None
        self.onClose.append(self.__onClose)
        self.onFirstExecBegin.append(self.firstExec)

    def showError(self, message):
        question = self.session.open(MessageBox, message,
                                     MessageBox.TYPE_ERROR)
        question.setTitle(_("ABM frequency finder"))
        self.close()

    def showAdvice(self, message):
        question = self.session.open(MessageBox, message, MessageBox.TYPE_INFO)
        question.setTitle(_("ABM frequency finder"))
        self.close()

    def keyCancel(self):
        self.close()

    def firstExec(self):
        png = resolveFilename(SCOPE_CURRENT_SKIN,
                              "FrequencyFinder/background.png")
        if not png or not fileExists(png):
            png = "%s/images/background.png" % os.path.dirname(
                sys.modules[__name__].__file__)
        self["background"].instance.setPixmapFromFile(png)

        if len(self.scanTransponders) > 0:
            self["action"].setText(_('Starting search...'))
            self["status"].setText(_("Scanning for active transponders"))
            self.progresscount = len(self.scanTransponders)
            self.progresscurrent = 1
            self["progress_text"].range = self.progresscount
            self["progress_text"].value = self.progresscurrent
            self["progress"].setRange((0, self.progresscount))
            self["progress"].setValue(self.progresscurrent)
            self.timer = eTimer()
            self.timer.callback.append(self.search)
            self.timer.start(100, 1)
        else:
            self.showError(_('No frequencies to search'))

    def search(self):
        if self.index < len(self.scanTransponders):
            self.system = self.scanTransponders[self.index]["system"]
            self.bandwidth = self.scanTransponders[self.index]["bandwidth"]
            self.frequency = self.scanTransponders[self.index]["frequency"]
            print "[ABM-FrequencyFinder][Search] Scan frequency %d (ch %s)" % (
                self.frequency, getChannelNumber(self.frequency))
            print "[ABM-FrequencyFinder][Search] Scan system %d" % self.system
            print "[ABM-FrequencyFinder][Search] Scan bandwidth %d" % self.bandwidth
            self.progresscurrent = self.index
            self["progress_text"].value = self.progresscurrent
            self["progress"].setValue(self.progresscurrent)
            self["action"].setText(
                _("Tuning %s MHz (ch %s)") %
                (str(self.frequency / 1000000), getChannelNumber(
                    self.frequency)))
            self["status"].setText(
                ngettext("Found %d unique transponder",
                         "Found %d unique transponders",
                         len(self.transponders_unique)) %
                len(self.transponders_unique))
            self.index += 1
            if self.frequency in self.transponders_found or self.system == eDVBFrontendParametersTerrestrial.System_DVB_T2 and self.isT2tuner == False:
                print "[ABM-FrequencyFinder][Search] Skipping T2 search of %s MHz (ch %s)" % (
                    str(self.frequency / 1000000),
                    getChannelNumber(self.frequency))
                self.search()
                return
            self.searchtimer = eTimer()
            self.searchtimer.callback.append(self.getFrontend)
            self.searchtimer.start(100, 1)
        else:
            if len({
                    k: v
                    for k, v in self.transponders_unique.items() if v["system"]
                    == eDVBFrontendParametersTerrestrial.System_DVB_T
            }) > 0:  # check DVB-T transponders exist
                if self.frontend:
                    self.frontend = None
                    del (self.rawchannel)
                self["action"].setText(_("Saving data"))
                if self.session.postScanService:
                    self.session.nav.playService(self.session.postScanService)
                    self.session.postScanService = None
#				self.saveTransponderList()
#				message = "Transponder frequencies updated.\nDo you want to continue with a scan for services."
#				question = self.session.openWithCallback(self.scanMessageCallback, MessageBox, message, type=MessageBox.TYPE_YESNO, default=True)
#				question.setTitle(_("ABM frequency finder"))
                self.saveProviderFile()
                message = 'New provider created called "%s terrestrial".\n Disable the existing ABM terrestrial provider and perform an ABM scan with the new one.' % self.strongestTransponder[
                    "network_name"]
                self.showAdvice(message)
            elif len(self.transponders_unique) > 0:
                print "[ABM-FrequencyFinder][Search] Only DVB-T2 multiplexes found. Insufficient data to create a provider file."
                self.showError(
                    _('Only DVB-T2 multiplexes found. Insufficient data to create a provider file.'
                      ))
            else:
                print "[ABM-FrequencyFinder][Search] No terrestrial multiplexes found."
                self.showError(_('No terrestrial multiplexes found.'))

    def config_mode(self, nim):  # Workaround for OpenATV > 5.3
        try:
            return nim.config_mode
        except AttributeError:
            return nim.isCompatible(
                "DVB-T") and nim.config_mode_dvbt or "nothing"

    def getFrontend(self):
        print "[ABM-FrequencyFinder][getFrontend] searching for available tuner"
        nimList = []
        if self.selectedNIM < 0:  # automatic tuner selection
            for nim in nimmanager.nim_slots:
                if self.config_mode(nim) not in (
                        "nothing", ) and (nim.isCompatible("DVB-T2") or
                                          (nim.isCompatible("DVB-S")
                                           and nim.canBeCompatible("DVB-T2"))):
                    nimList.append(nim.slot)
                    self.isT2tuner = True
            if len(nimList) == 0:
                print "[ABM-FrequencyFinder][getFrontend] No T2 tuner found"
                for nim in nimmanager.nim_slots:
                    if self.config_mode(nim) not in ("nothing", ) and (
                            nim.isCompatible("DVB-T") or
                        (nim.isCompatible("DVB-S")
                         and nim.canBeCompatible("DVB-T"))):
                        nimList.append(nim.slot)
            if len(nimList) == 0:
                print "[ABM-FrequencyFinder][getFrontend] No terrestrial tuner found."
                self.showError(_('No terrestrial tuner found.'))
                return
        else:  # manual tuner selection, and subsequent iterations
            nim = nimmanager.nim_slots[self.selectedNIM]
            if self.config_mode(nim) not in ("nothing", ) and (
                    nim.isCompatible("DVB-T2") or
                (nim.isCompatible("DVB-S") and nim.canBeCompatible("DVB-T2"))):
                nimList.append(nim.slot)
                self.isT2tuner = True
            if len(nimList) == 0:
                print "[ABM-FrequencyFinder][getFrontend] User selected tuner is not T2 compatible"
                if self.config_mode(nim) not in (
                        "nothing", ) and (nim.isCompatible("DVB-T") or
                                          (nim.isCompatible("DVB-S")
                                           and nim.canBeCompatible("DVB-T"))):
                    nimList.append(nim.slot)
            if len(nimList) == 0:
                print "[ABM-FrequencyFinder][getFrontend] User selected tuner not configured"
                self.showError(_('Selected tuner is not configured.'))
                return

        if len(nimList) == 0:
            print "[ABM-FrequencyFinder][getFrontend] No terrestrial tuner found."
            self.showError(_('No terrestrial tuner found.'))
            return

        resmanager = eDVBResourceManager.getInstance()
        if not resmanager:
            print "[ABM-FrequencyFinder][getFrontend] Cannot retrieve Resource Manager instance"
            self.showError(_('Cannot retrieve Resource Manager instance'))
            return

        if self.selectedNIM < 0:  # automatic tuner selection
            print "[ABM-FrequencyFinder][getFrontend] Choosing NIM"

        # stop pip if running
        if self.session.pipshown:
            self.session.pipshown = False
            del self.session.pip
            print "[ABM-FrequencyFinder][getFrontend] Stopping PIP."

        # Find currently playing NIM
        currentlyPlayingNIM = None
        currentService = self.session and self.session.nav.getCurrentService()
        frontendInfo = currentService and currentService.frontendInfo()
        frontendData = frontendInfo and frontendInfo.getAll(True)
        if frontendData is not None:
            currentlyPlayingNIM = frontendData.get("tuner_number", None)
        del frontendInfo
        del currentService

        current_slotid = -1
        if self.rawchannel:
            del (self.rawchannel)

        self.frontend = None
        self.rawchannel = None

        nimList.reverse()  # start from the last
        for slotid in nimList:
            if current_slotid == -1:  # mark the first valid slotid in case of no other one is free
                current_slotid = slotid
            self.rawchannel = resmanager.allocateRawChannel(slotid)
            if self.rawchannel:
                print "[ABM-FrequencyFinder][getFrontend] Nim found on slot id %d" % (
                    slotid)
                current_slotid = slotid
                break

        if current_slotid == -1:
            print "[ABM-FrequencyFinder][getFrontend] No valid NIM found"
            self.showError(_('No valid NIM found for terrestrial.'))
            return

        if not self.rawchannel:
            # if we are here the only possible option is to close the active service
            if currentlyPlayingNIM in nimList:
                slotid = currentlyPlayingNIM
                print "[ABM-FrequencyFinder][getFrontend] Nim found on slot id %d but it's busy. Stopping active service" % slotid
                self.session.postScanService = self.session.nav.getCurrentlyPlayingServiceReference(
                )
                self.session.nav.stopService()
                self.rawchannel = resmanager.allocateRawChannel(slotid)
                if self.rawchannel:
                    print "[ABM-FrequencyFinder][getFrontend] The active service was stopped, and the NIM is now free to use."
                    current_slotid = slotid

            if not self.rawchannel:
                if self.session.nav.RecordTimer.isRecording():
                    print "[ABM-FrequencyFinder][getFrontend] Cannot free NIM because a recording is in progress"
                    self.showError(
                        _('Cannot free NIM because a recording is in progress')
                    )
                    return
                else:
                    print "[ABM-FrequencyFinder][getFrontend] Cannot get the NIM"
                    self.showError(_('Cannot get the NIM'))
                    return

        print "[ABM-FrequencyFinder][getFrontend] Will wait up to %i seconds for tuner lock." % (
            self.lockTimeout / 10)

        self.selectedNIM = current_slotid  # Remember for next iteration

        self.frontend = self.rawchannel.getFrontend()
        if not self.frontend:
            print "[ABM-FrequencyFinder][getFrontend] Cannot get frontend"
            self.showError(_('Cannot get frontend'))
            return

        self.rawchannel.requestTsidOnid()

        self.tsid = None
        self.onid = None

        self.demuxer_id = self.rawchannel.reserveDemux()
        if self.demuxer_id < 0:
            print >> log, "[ABM-FrequencyFinder][getFrontend] Cannot allocate the demuxer."
            self.showError(_('Cannot allocate the demuxer.'))
            return

        self.frontend.tune(
            setParamsFe(setParams(self.frequency, self.system,
                                  self.bandwidth)))

        self.lockcounter = 0
        self.locktimer = eTimer()
        self.locktimer.callback.append(self.checkTunerLock)
        self.locktimer.start(100, 1)

    def checkTunerLock(self):
        self.dict = {}
        self.frontend.getFrontendStatus(self.dict)
        if self.dict["tuner_state"] == "TUNING":
            if self.lockcounter < 1:  # only show this once in the log per retune event
                print "[ABM-FrequencyFinder][checkTunerLock] TUNING"
        elif self.dict["tuner_state"] == "LOCKED":
            print "[ABM-FrequencyFinder][checkTunerLock] LOCKED"
            self["action"].setText(
                _("Reading %s MHz (ch %s)") %
                (str(self.frequency / 1000000), getChannelNumber(
                    self.frequency)))
            self.tsidOnidtimer = eTimer()
            self.tsidOnidtimer.callback.append(self.tsidOnidWait)
            self.tsidOnidtimer.start(100, 1)
            return
        elif self.dict["tuner_state"] in ("LOSTLOCK", "FAILED"):
            print "[ABM-FrequencyFinder][checkTunerLock] TUNING FAILED"
            self.search()
            return

        self.lockcounter += 1
        if self.lockcounter > self.lockTimeout:
            print "[ABM-FrequencyFinder][checkTunerLock] Timeout for tuner lock"
            self.search()
            return
        self.locktimer.start(100, 1)

    def tsidOnidWait(self):
        self.getCurrentTsidOnid()
        if self.tsid is not None and self.onid is not None:
            print "[ABM-FrequencyFinder][tsidOnidWait] tsid & onid found", self.tsid, self.onid
            self.signalQualityWait()
            return

        print "[ABM-FrequencyFinder][tsidOnidWait] tsid & onid wait failed"
        self.search()
        return

    def signalQualityWait(self):
        self.readNIT()  # by the time this is completed SNR should be stable
        signalQuality = self.frontend.readFrontendData(
            iFrontendInformation.signalQuality)
        if signalQuality > 0:
            found = {
                "frequency": self.frequency,
                "tsid": self.tsid,
                "onid": self.onid,
                "system": self.system,
                "bandwidth": self.bandwidth,
                "signalQuality": signalQuality,
                "network_name": self.network_name,
                "custom_transponder_needed": self.custom_transponder_needed
            }
            self.transponders_found.append(self.frequency)
            tsidOnidKey = "%x:%x" % (self.tsid, self.onid)
            if (tsidOnidKey not in self.transponders_unique
                    or self.transponders_unique[tsidOnidKey]["signalQuality"] <
                    signalQuality) and (not self.restrict_to_networkid
                                        or self.networkid == self.onid):
                self.transponders_unique[tsidOnidKey] = found
            print "[ABM-FrequencyFinder][signalQualityWait] transponder details", found
            self.search()
            return

        print "[ABM-FrequencyFinder][signalQualityWait] Failed to collect SNR"
        self.search()

    def getCurrentTsidOnid(self, from_retune=False):
        adapter = 0
        demuxer_device = "/dev/dvb/adapter%d/demux%d" % (adapter,
                                                         self.demuxer_id)
        start = time.time()  # for debug info

        sdt_pid = 0x11
        sdt_current_table_id = 0x42
        mask = 0xff
        tsidOnidTimeout = 5  # maximum time allowed to read the service descriptor table (seconds)
        self.tsid = None
        self.onid = None

        fd = dvbreader.open(demuxer_device, sdt_pid, sdt_current_table_id,
                            mask, self.selectedNIM)
        if fd < 0:
            print "[ABM-FrequencyFinder][getCurrentTsidOnid] Cannot open the demuxer"
            return None

        timeout = datetime.datetime.now()
        timeout += datetime.timedelta(0, tsidOnidTimeout)

        while True:
            if datetime.datetime.now() > timeout:
                print "[ABM-FrequencyFinder][getCurrentTsidOnid] Timed out"
                break

            section = dvbreader.read_sdt(fd, sdt_current_table_id, 0x00)
            if section is None:
                time.sleep(0.1)  # no data.. so we wait a bit
                continue

            if section["header"]["table_id"] == sdt_current_table_id:
                self.tsid = section["header"]["transport_stream_id"]
                self.onid = section["header"]["original_network_id"]
                break

        print "[ABM-FrequencyFinder][getCurrentTsidOnid] Read time %.1f seconds." % (
            time.time() - start)
        dvbreader.close(fd)

    def readNIT(self):
        adapter = 0
        demuxer_device = "/dev/dvb/adapter%d/demux%d" % (adapter,
                                                         self.demuxer_id)
        start = time.time()  # for debug info

        nit_current_pid = 0x10
        nit_current_table_id = 0x40
        nit_other_table_id = 0x00  # don't read other table

        self.network_name = None
        self.custom_transponder_needed = True

        if nit_other_table_id == 0x00:
            mask = 0xff
        else:
            mask = nit_current_table_id ^ nit_other_table_id ^ 0xff
        nit_current_timeout = 20  # maximum time allowed to read the network information table (seconds)

        nit_current_version_number = -1
        nit_current_sections_read = []
        nit_current_sections_count = 0
        nit_current_content = []
        nit_current_completed = False

        fd = dvbreader.open(demuxer_device, nit_current_pid,
                            nit_current_table_id, mask, self.selectedNIM)
        if fd < 0:
            print "[ABM-FrequencyFinder][readNIT] Cannot open the demuxer"
            return

        timeout = datetime.datetime.now()
        timeout += datetime.timedelta(0, nit_current_timeout)

        while True:
            if datetime.datetime.now() > timeout:
                print "[ABM-FrequencyFinder][readNIT] Timed out reading NIT"
                break

            section = dvbreader.read_nit(fd, nit_current_table_id,
                                         nit_other_table_id)
            if section is None:
                time.sleep(0.1)  # no data.. so we wait a bit
                continue

            if section["header"][
                    "table_id"] == nit_current_table_id and not nit_current_completed:
                if section["header"][
                        "version_number"] != nit_current_version_number:
                    nit_current_version_number = section["header"][
                        "version_number"]
                    nit_current_sections_read = []
                    nit_current_sections_count = section["header"][
                        "last_section_number"] + 1
                    nit_current_content = []

                if section["header"][
                        "section_number"] not in nit_current_sections_read:
                    nit_current_sections_read.append(
                        section["header"]["section_number"])
                    nit_current_content += section["content"]

                    if 'network_name' in section["header"] and section[
                            "header"]["network_name"] != "Unknown":
                        self.network_name = section["header"]["network_name"]

                    if len(nit_current_sections_read
                           ) == nit_current_sections_count:
                        nit_current_completed = True

            if nit_current_completed:
                break

        dvbreader.close(fd)

        if not nit_current_content:
            print "[ABM-FrequencyFinder][readNIT] current transponder not found"
            return

        print "[ABM-FrequencyFinder][readNIT] NIT read time %.1f seconds." % (
            time.time() - start)

        # descriptor_tag 0x5A is DVB-T, descriptor_tag 0x7f is DVB-T
        transponders = [
            t for t in nit_current_content
            if "descriptor_tag" in t and t["descriptor_tag"] in (
                0x5A, 0x7f) and t["original_network_id"] == self.onid
            and t["transport_stream_id"] == self.tsid
        ]  # this should only ever have a length of one transponder
        print "[ABM-FrequencyFinder][readNIT] transponders", transponders
        if transponders:

            if transponders[0]["descriptor_tag"] == 0x5A:  # DVB-T
                self.system = eDVBFrontendParametersTerrestrial.System_DVB_T
            else:  # must be DVB-T2
                self.system = eDVBFrontendParametersTerrestrial.System_DVB_T2

            if "frequency" in transponders[0] and abs(
                (transponders[0]["frequency"] * 10) -
                    self.frequency) < 1000000:
                self.custom_transponder_needed = False
                if self.frequency != transponders[0]["frequency"] * 10:
                    print "[ABM-FrequencyFinder][readNIT] updating transponder frequency from %.03f MHz to %.03f MHz" % (
                        self.frequency / 1000000,
                        transponders[0]["frequency"] / 100000)
                    self.frequency = transponders[0]["frequency"] * 10

#	def saveTransponderList(self):
#		# make custom transponders file content
#		customTransponderList = []
#		customTransponderList.append('<provider>\n')
#		customTransponderList.append('\t<customtransponders>\n')
#		for tsidOnidKey in self.iterateUniqueTranspondersByFrequency():
#			transponder = self.transponders_unique[tsidOnidKey]
#			customTransponderList.append('\t\t<customtransponder key="_OVERRIDE_" frequency="%d" transport_stream_id="%04x" system="%d"/><!-- original_network_id="%04x" signalQuality="%05d" -->\n' % (transponder["frequency"], transponder["tsid"], transponder["system"], transponder["onid"], transponder["signalQuality"]))
#		customTransponderList.append('\t</customtransponders>\n')
#		customTransponderList.append('</provider>\n')
#
#		# save to ABM custom folder
#		outFile = open(self.customfile, "w")
#		outFile.write(''.join(customTransponderList))
#		outFile.close()
#		print "[ABM-FrequencyFinder][saveTransponderList] Custom transponders file saved."

    def saveProviderFile(self):
        customProviderList = []
        self.strongestTransponder = self.transponders_unique[
            self.iterateUniqueTranspondersBySignalQuality()[-1]]
        for tsidOnidKey in self.iterateUniqueTranspondersBySignalQuality(
        )[::
          -1]:  # iterate in reverse order and select the first system 0 transponder
            transponder = self.transponders_unique[tsidOnidKey]
            if transponder["system"] == 0:
                self.strongestTransponder = transponder
                break
        network_name = re.sub(
            r'&(?![A-Za-z]+[0-9]*;|#[0-9]+;|#x[0-9a-fA-F]+;)', r'&amp;',
            self.strongestTransponder["network_name"]
        )  # regex to avoid unencoded ampersands that are not entities
        customProviderList.append('<provider>\n')
        customProviderList.append('\t<name>%s terrestrial</name>\n' %
                                  network_name)
        customProviderList.append('\t<streamtype>dvbt</streamtype>\n')
        customProviderList.append('\t<protocol>lcn</protocol>\n')
        customProviderList.append('\t<dvbtconfigs>\n')
        customProviderList.append(
            '\t\t<configuration key="custom" frequency="%d" system="%d">%s terrestrial</configuration>\n'
            % (self.strongestTransponder["frequency"],
               self.strongestTransponder["system"], network_name))
        customProviderList.append('\t</dvbtconfigs>\n\n')
        customProviderList.append('\t<customtransponders>\n')
        for tsidOnidKey in self.iterateUniqueTranspondersByFrequency():
            transponder = self.transponders_unique[tsidOnidKey]
            if transponder["custom_transponder_needed"]:
                customProviderList.append(
                    '\t\t<customtransponder key="custom" frequency="%d" transport_stream_id="%04x" system="%d"/><!-- original_network_id="%04x" signalQuality="%05d" channel="%s" -->\n'
                    % (transponder["frequency"], transponder["tsid"],
                       transponder["system"], transponder["onid"],
                       transponder["signalQuality"],
                       getChannelNumber(transponder["frequency"])))
            else:
                customProviderList.append(
                    '\t\t<!-- customtransponder key="custom" frequency="%d" transport_stream_id="%04x" system="%d"/ --><!-- original_network_id="%04x" signalQuality="%05d" channel="%s" -->\n'
                    % (transponder["frequency"], transponder["tsid"],
                       transponder["system"], transponder["onid"],
                       transponder["signalQuality"],
                       getChannelNumber(transponder["frequency"])))
        customProviderList.append('\t</customtransponders>\n\n')
        customProviderList.append('\t<sections>\n')
        customProviderList.append(
            '\t\t<section number="1">Entertainment</section>\n')
        customProviderList.append(
            '\t\t<section number="100">High Definition</section>\n')
        customProviderList.append(
            '\t\t<section number="201">Children</section>\n')
        customProviderList.append('\t\t<section number="230">News</section>\n')
        customProviderList.append(
            '\t\t<section number="260">BBC Interactive</section>\n')
        customProviderList.append(
            '\t\t<section number="670">Adult</section>\n')
        customProviderList.append('\t</sections>\n\n')
        customProviderList.append('\t<swapchannels>\n')
        customProviderList.append(
            '\t\t<channel number="1" with="101"/>	<!-- BBC One HD -->\n')
        customProviderList.append(
            '\t\t<channel number="2" with="102"/>	<!-- BBC TWO HD -->\n')
        customProviderList.append(
            '\t\t<channel number="3" with="103"/>	<!-- ITV HD -->\n')
        customProviderList.append(
            '\t\t<channel number="4" with="104"/>	<!-- Channel 4 HD -->\n')
        customProviderList.append(
            '\t\t<channel number="5" with="105"/>	<!-- Channel 5 HD -->\n')
        customProviderList.append(
            '\t\t<channel number="9" with="106"/>	<!-- BBC FOUR HD -->\n')
        customProviderList.append(
            '\t\t<channel number="13" with="109"/>	<!-- Channel 4+1 HD -->\n')
        customProviderList.append(
            '\t\t<channel number="47" with="110"/>	<!-- 4seven HD -->\n')
        customProviderList.append(
            '\t\t<channel number="201" with="204"/>	<!-- CBBC HD -->\n')
        customProviderList.append(
            '\t\t<channel number="202" with="205"/>	<!-- CBeebies HD -->\n')
        customProviderList.append(
            '\t\t<channel number="231" with="107"/>	<!-- BBC NEWS HD -->\n')
        customProviderList.append('\t</swapchannels>\n\n')
        customProviderList.append('\t<servicehacks>\n')
        customProviderList.append('\t<![CDATA[\n\n')
        customProviderList.append('tsidonidlist= [\n')
        for tsidOnidKey in self.iterateUniqueTranspondersByFrequency():
            customProviderList.append('\t"%s",\n' % tsidOnidKey)
        customProviderList.append(']\n\n')
        customProviderList.append(
            'tsidonidkey = "%x:%x" % (service["transport_stream_id"], service["original_network_id"])\n'
        )
        customProviderList.append('if tsidonidkey not in tsidonidlist:\n')
        customProviderList.append('\tskip = True\n\n')
        customProviderList.append('\t]]>\n')
        customProviderList.append('\t</servicehacks>\n')
        customProviderList.append('</provider>\n')

        # save to ABM providers folder
        outFile = open(self.providersfile, "w")
        outFile.write(''.join(customProviderList))
        outFile.close()
        print "[ABM-FrequencyFinder][saveProviderFile] Provider file saved."

    def iterateUniqueTranspondersByFrequency(self):
        # returns an iterator list for self.transponders_unique in frequency order ascending
        sort_list = [(x[0], x[1]["frequency"])
                     for x in self.transponders_unique.items()]
        return [
            x[0] for x in sorted(sort_list, key=lambda listItem: listItem[1])
        ]

    def iterateUniqueTranspondersBySignalQuality(self):
        # returns an iterator list for self.transponders_unique in SignalQuality order ascending
        sort_list = [(x[0], x[1]["signalQuality"])
                     for x in self.transponders_unique.items()]
        return [
            x[0] for x in sorted(sort_list, key=lambda listItem: listItem[1])
        ]

#	def scanMessageCallback(self, answer):
#		if answer:
#			self.session.open(AutoBouquetsMaker)
#		self.close()

#	def removeFileIfExists(self, filename):
#		try:
#			os.remove(filename)
#		except OSError as e:
#			if e.errno != errno.ENOENT: # errno.ENOENT = no such file or directory
#				raise # re-raise exception if a different error occurred

    def __onClose(self):
        if self.frontend:
            self.frontend = None
            del (self.rawchannel)

        if self.session.postScanService:
            self.session.nav.playService(self.session.postScanService)
            self.session.postScanService = None
示例#2
0
class AutoBouquetsMaker(Screen):
    skin = skin_downloadBar()

    LOCK_TIMEOUT_FIXED = 100  # 100ms for tick - 10 sec
    LOCK_TIMEOUT_ROTOR = 1200  # 100ms for tick - 120 sec
    ABM_BOUQUET_PREFIX = "userbouquet.abm."

    def __init__(self, session, args=0):
        self.printconfig()
        self.session = session
        Screen.__init__(self, session)
        Screen.setTitle(self, _("AutoBouquetsMaker"))

        self.frontend = None
        self.rawchannel = None
        self.postScanService = None
        self.providers = Manager().getProviders()

        self["actions"] = ActionMap(["OkCancelActions", "ColorActions"], {
            "cancel": self.keyCancel,
            "red": self.keyCancel,
        }, -2)

        #		self["background"] = Pixmap()
        self["action"] = Label(_("Starting scanner"))
        self["status"] = Label("")
        self["progress"] = ProgressBar()
        self["progress_text"] = Progress()
        self["tuner_text"] = Label("")
        self["Frontend"] = FrontendStatus(
            frontend_source=lambda: self.frontend, update_interval=100)

        # dependent providers
        self.dependents = {}
        for provider_key in self.providers:
            if len(self.providers[provider_key]
                   ["dependent"]) > 0 and self.providers[provider_key][
                       "dependent"] in self.providers:
                if self.providers[provider_key][
                        "dependent"] not in self.dependents:
                    self.dependents[self.providers[provider_key]
                                    ["dependent"]] = []
                self.dependents[self.providers[provider_key]
                                ["dependent"]].append(provider_key)

        # get ABM config string including dependents
        self.abm_settings_str = self.getABMsettings()

        self.actionsList = []

        self.onFirstExecBegin.append(self.firstExec)

    def firstExec(self, postScanService=None):
        from Screens.Standby import inStandby
        #		if not inStandby:
        #			png = resolveFilename(SCOPE_CURRENT_SKIN, "autobouquetsmaker/background.png")
        #			if not png or not fileExists(png):
        #				png = "%s/../images/background.png" % os.path.dirname(sys.modules[__name__].__file__)
        #			self["background"].instance.setPixmapFromFile(png)

        if len(self.abm_settings_str) > 0:
            if not inStandby:
                self["action"].setText(_('Loading bouquets...'))
                self["status"].setText(_("Services: 0 video - 0 radio"))
            self.timer = eTimer()
            self.timer.callback.append(self.go)
            self.timer.start(100, 1)
        else:
            self.showError(_('Please first setup, in configuration'))

    def showError(self, message):
        from Screens.Standby import inStandby
        self.releaseFrontend()
        self.restartService()
        if not inStandby:
            question = self.session.open(MessageBox, message,
                                         MessageBox.TYPE_ERROR)
            question.setTitle(_("AutoBouquetsMaker"))
        self.close()

    def keyCancel(self):
        self.releaseFrontend()
        self.restartService()
        self.close()

    def go(self):
        from Screens.Standby import inStandby
        self.manager = Manager()
        self.manager.setPath("/etc/enigma2")
        self.manager.setAddPrefix(config.autobouquetsmaker.addprefix.value)

        self.selectedProviders = {}
        self.actionsList = []

        providers_tmp = self.abm_settings_str.split("|")

        for provider_tmp in providers_tmp:
            provider_config = ProviderConfig(provider_tmp)
            if provider_config.isValid() and Providers().providerFileExists(
                    provider_config.getProvider()):
                self.actionsList.append(provider_config.getProvider())
                self.selectedProviders[
                    provider_config.getProvider()] = provider_config

        if config.autobouquetsmaker.keepallbouquets.getValue():
            bouquets = Manager().getBouquetsList()
            bouquets_tv = []
            bouquets_radio = []
            for bouquet in bouquets["tv"]:
                if bouquet["filename"][:len(self.ABM_BOUQUET_PREFIX
                                            )] == self.ABM_BOUQUET_PREFIX:
                    continue
                if len(bouquet["filename"]) > 0:
                    bouquets_tv.append(bouquet["filename"])
            for bouquet in bouquets["radio"]:
                if bouquet["filename"][:len(self.ABM_BOUQUET_PREFIX
                                            )] == self.ABM_BOUQUET_PREFIX:
                    continue
                if len(bouquet["filename"]) > 0:
                    bouquets_radio.append(bouquet["filename"])
            self.manager.setBouquetsToKeep(bouquets_tv, bouquets_radio)
        else:
            bouquets = config.autobouquetsmaker.keepbouquets.value.split("|")
            bouquets_tv = []
            bouquets_radio = []
            for bouquet in bouquets:
                if bouquet.endswith(".tv"):
                    bouquets_tv.append(bouquet)
                elif bouquet.endswith(".radio"):
                    bouquets_radio.append(bouquet)
            self.manager.setBouquetsToKeep(bouquets_tv, bouquets_radio)

        bouquetsToHide = {}
        bouquets = config.autobouquetsmaker.hidesections.value.split("|")
        for bouquet in bouquets:
            tmp = bouquet.split(":")
            if len(tmp) != 2:
                continue

            if tmp[0].strip() not in bouquetsToHide:
                bouquetsToHide[tmp[0].strip()] = []

            bouquetsToHide[tmp[0].strip()].append(int(tmp[1].strip()))
        self.manager.setBouquetsToHide(bouquetsToHide)

        self.manager.load()

        self.progresscount = (len(self.actionsList) * 2) + 3
        self.progresscurrent = 1

        if not inStandby:
            self["progress_text"].range = self.progresscount
            self["progress_text"].value = self.progresscurrent
            self["progress"].setRange((0, self.progresscount))
            self["progress"].setValue(self.progresscurrent)

        self.timer = eTimer()
        self.timer.callback.append(self.doActions)
        self.timer.start(100, 1)

    def doActions(self):
        from Screens.Standby import inStandby
        if len(self.actionsList) == 0:
            self.progresscurrent += 1
            self["actions"].setEnabled(
                False
            )  # disable action map here so we can't abort half way through writing result to settings files
            if not inStandby:
                self["progress_text"].value = self.progresscurrent
                self["progress"].setValue(self.progresscurrent)
                self["action"].setText(_('Bouquets generation...'))
                self["status"].setText(
                    _("Services: %d video - %d radio") %
                    (self.manager.getServiceVideoRead(),
                     self.manager.getServiceAudioRead()))
                self["tuner_text"].setText("")
            self.timer = eTimer()
            self.timer.callback.append(self.doBuildIndex)
            self.timer.start(100, 1)
            return

        self.currentAction = self.actionsList[0]
        del (self.actionsList[0])

        self.progresscurrent += 1
        if not inStandby:
            self["progress_text"].value = self.progresscurrent
            self["progress"].setValue(self.progresscurrent)
            self["action"].setText(
                _("Tuning %s...") %
                str(self.providers[self.currentAction]["name"]))
            self["status"].setText(
                _("Services: %d video - %d radio") %
                (self.manager.getServiceVideoRead(),
                 self.manager.getServiceAudioRead()))
            self["tuner_text"].setText("")
        self.timer = eTimer()
        self.timer.callback.append(self.doTune)
        self.timer.start(100, 1)

    def doTune(self):
        print("[ABM-main][doTune] searching for tuner for %s" %
              self.providers[self.currentAction]["name"],
              file=log)
        from Screens.Standby import inStandby
        if self.providers[self.currentAction]["streamtype"] == "dvbs":
            transponder = self.providers[self.currentAction]["transponder"]
        else:
            bouquet_key = None
            providers_tmp = self.abm_settings_str.split("|")
            for provider_tmp in providers_tmp:
                provider_config = ProviderConfig(provider_tmp)
                provider_key = provider_config.getProvider()
                if self.currentAction != provider_key:
                    continue
                bouquet_key = provider_config.getArea()

            if not bouquet_key:
                print("[ABM-main][doTune] No area found", file=log)
                self.showError(_('No area found'))
                return

            transponder = self.providers[
                self.currentAction]["bouquets"][bouquet_key]

        self.transponder = transponder

        nimList = []
        tunerSelectionAlgorithm = "UNKNOWN"  # for debug
        for nim in nimmanager.nim_slots:
            if self.providers[self.currentAction][
                    "streamtype"] == "dvbs" and nim.isCompatible("DVB-S"):
                try:
                    if nim.isFBCLink():
                        continue  # do not load FBC links, only root tuners
                except:
                    pass
            try:  # OpenPLi Hot Switch compatible image
                if (nim.config_mode not in ("loopthrough", "satposdepends", "nothing")) and \
                 {"dvbs": "DVB-S", "dvbc": "DVB-C", "dvbt": "DVB-T"}.get(self.providers[self.currentAction]["streamtype"], "UNKNOWN") in [x[:5] for x in nim.getTunerTypesEnabled()]:
                    if self.validNIM(nim.slot):
                        nimList.append(nim.slot)
                    tunerSelectionAlgorithm = "OpenPLi Hot Switch compatible"
            except AttributeError:
                try:
                    if (nim.config_mode not in ("loopthrough", "satposdepends", "nothing")) and \
                     ((self.providers[self.currentAction]["streamtype"] == "dvbs" and nim.isCompatible("DVB-S")) or
                     (self.providers[self.currentAction]["streamtype"] == "dvbc" and (nim.isCompatible("DVB-C") or (nim.isCompatible("DVB-S") and nim.canBeCompatible("DVB-C")))) or
                     (self.providers[self.currentAction]["streamtype"] == "dvbt" and (nim.isCompatible("DVB-T") or (nim.isCompatible("DVB-S") and nim.canBeCompatible("DVB-T"))))):
                        if self.validNIM(nim.slot):
                            nimList.append(nim.slot)
                        tunerSelectionAlgorithm = "Conventional"
                except AttributeError:  # OpenATV > 5.3
                    if (self.providers[self.currentAction]["streamtype"] == "dvbs" and nim.canBeCompatible("DVB-S") and nim.config_mode_dvbs not in ("loopthrough", "satposdepends", "nothing")) or \
                     (self.providers[self.currentAction]["streamtype"] == "dvbc" and nim.canBeCompatible("DVB-C") and nim.config_mode_dvbc != "nothing") or \
                     (self.providers[self.currentAction]["streamtype"] == "dvbt" and nim.canBeCompatible("DVB-T") and nim.config_mode_dvbt != "nothing"):
                        if self.validNIM(nim.slot):
                            nimList.append(nim.slot)
                        tunerSelectionAlgorithm = "OpenATV > 5.3"

        print("[ABM-main][doTune] tuner selection algorithm '%s'" %
              tunerSelectionAlgorithm,
              file=log)

        if len(nimList) == 0:
            print("[ABM-main][doTune] No NIMs found", file=log)
            self.showError(
                _('No NIMs found for ') +
                self.providers[self.currentAction]["name"])
            return

        resmanager = eDVBResourceManager.getInstance()
        if not resmanager:
            print(
                "[ABM-main][doTune] Cannot retrieve Resource Manager instance",
                file=log)
            self.showError(_('Cannot retrieve Resource Manager instance'))
            return

        if self.providers[self.currentAction][
                "streamtype"] == "dvbs":  # If we have a choice of dishes sort the nimList so "fixed" dishes have a higher priority than "motorised".
            nimList = [
                slot for slot in nimList
                if not self.isRotorSat(slot, transponder["orbital_position"])
            ] + [
                slot for slot in nimList
                if self.isRotorSat(slot, transponder["orbital_position"])
            ]

        # stop pip if running
        if self.session.pipshown:
            self.session.pipshown = False
            del self.session.pip
            print("[ABM-main][doTune] Stopping PIP.", file=log)

        # find currently playing nim
        currentlyPlayingNIM = None
        currentService = self.session and self.session.nav.getCurrentService()
        frontendInfo = currentService and currentService.frontendInfo()
        frontendData = frontendInfo and frontendInfo.getAll(True)
        if frontendData is not None:
            currentlyPlayingNIM = frontendData.get("tuner_number", None)
            # stop currently playing service if it is using a tuner in ("loopthrough", "satposdepends"), as running in this configuration will prevent getting rawchannel on the root tuner.
            if self.providers[self.currentAction][
                    "streamtype"] == "dvbs" and currentlyPlayingNIM is not None and nimmanager.nim_slots[
                        currentlyPlayingNIM].isCompatible("DVB-S"):
                try:
                    nimConfigMode = nimmanager.nim_slots[
                        currentlyPlayingNIM].config_mode
                except AttributeError:  # OpenATV > 5.3
                    nimConfigMode = nimmanager.nim_slots[
                        currentlyPlayingNIM].config_mode_dvbs
                if nimConfigMode in ("loopthrough", "satposdepends"):
                    self.postScanService = self.session.nav.getCurrentlyPlayingServiceReference(
                    )
                    self.session.nav.stopService()
                    currentlyPlayingNIM = None
                    print(
                        "[ABM-main][doTune] The active service was using a %s tuner, so had to be stopped (slot id %s)."
                        % (nimConfigMode, currentlyPlayingNIM),
                        file=log)
        del frontendInfo
        del currentService

        self.releaseFrontend()

        for current_slotid in nimList:
            self.rawchannel = resmanager.allocateRawChannel(current_slotid)
            if self.rawchannel:
                print("[ABM-main][doTune] Tuner %s selected%s" %
                      (chr(ord('A') + current_slotid),
                       (" for orbital position %d" %
                        transponder["orbital_position"]
                        if "orbital_position" in transponder else "")),
                      file=log)
                break

        if not self.rawchannel:
            # if we are here the only possible option is to close the active service
            if currentlyPlayingNIM in nimList:
                print(
                    "[ABM-main][doTune] Tuner %s has been selected but it's busy. Stopping currently playing service."
                    % chr(ord('A') + currentlyPlayingNIM),
                    file=log)
                self.postScanService = self.session.nav.getCurrentlyPlayingServiceReference(
                )
                self.session.nav.stopService()
                self.rawchannel = resmanager.allocateRawChannel(
                    currentlyPlayingNIM)
                if self.rawchannel:
                    print(
                        "[ABM-main][doTune] The active service was stopped, and tuner %s is now free to use."
                        % chr(ord('A') + currentlyPlayingNIM),
                        file=log)
                    current_slotid = currentlyPlayingNIM

            if not self.rawchannel:
                if self.session.nav.RecordTimer.isRecording():
                    print(
                        "[ABM-main][doTune] Cannot free NIM because a recording is in progress",
                        file=log)
                    self.showError(
                        _('Cannot free NIM because a recording is in progress')
                    )
                    return
                else:
                    print("[ABM-main][doTune] Cannot get the NIM", file=log)
                    self.showError(_('Cannot get the NIM'))
                    return

        # set extended timeout for rotors
        self.motorised = False
        if self.providers[self.currentAction][
                "streamtype"] == "dvbs" and self.isRotorSat(
                    current_slotid, transponder["orbital_position"]):
            self.motorised = True
            self.LOCK_TIMEOUT = self.LOCK_TIMEOUT_ROTOR
            print(
                "[ABM-main][doTune] Motorised dish. Will wait up to %i seconds for tuner lock."
                % (self.LOCK_TIMEOUT // 10),
                file=log)
        else:
            self.LOCK_TIMEOUT = self.LOCK_TIMEOUT_FIXED
            print(
                "[ABM-main][doTune] Fixed dish. Will wait up to %i seconds for tuner lock."
                % (self.LOCK_TIMEOUT // 10),
                file=log)

        if not inStandby:
            self["tuner_text"].setText(chr(ord('A') + current_slotid))

        self.frontend = self.rawchannel.getFrontend()
        if not self.frontend:
            print("[ABM-main][doTune] Cannot get frontend", file=log)
            self.showError(_('Cannot get frontend'))
            return

        demuxer_id = self.rawchannel.reserveDemux()
        if demuxer_id < 0:
            print("[ABM-main][doTune] Cannot allocate the demuxer.", file=log)
            self.showError(_('Cannot allocate the demuxer.'))
            return

        if self.providers[self.currentAction]["streamtype"] == "dvbs":
            params = eDVBFrontendParametersSatellite()
            params.frequency = transponder["frequency"]
            params.symbol_rate = transponder["symbol_rate"]
            params.polarisation = transponder["polarization"]
            params.fec = transponder["fec_inner"]
            params.inversion = transponder["inversion"]
            params.orbital_position = transponder["orbital_position"]
            params.system = transponder["system"]
            params.modulation = transponder["modulation"]
            params.rolloff = transponder["roll_off"]
            params.pilot = transponder["pilot"]
            if hasattr(eDVBFrontendParametersSatellite, "No_Stream_Id_Filter"):
                params.is_id = eDVBFrontendParametersSatellite.No_Stream_Id_Filter
            if hasattr(eDVBFrontendParametersSatellite, "PLS_Gold"):
                params.pls_mode = eDVBFrontendParametersSatellite.PLS_Gold
            if hasattr(eDVBFrontendParametersSatellite,
                       "PLS_Default_Gold_Code"):
                params.pls_code = eDVBFrontendParametersSatellite.PLS_Default_Gold_Code
            if hasattr(eDVBFrontendParametersSatellite, "No_T2MI_PLP_Id"):
                params.t2mi_plp_id = eDVBFrontendParametersSatellite.No_T2MI_PLP_Id
            if hasattr(eDVBFrontendParametersSatellite, "T2MI_Default_Pid"):
                params.t2mi_pid = eDVBFrontendParametersSatellite.T2MI_Default_Pid
            params_fe = eDVBFrontendParameters()
            params_fe.setDVBS(params, False)

        elif self.providers[self.currentAction]["streamtype"] == "dvbt":
            params = eDVBFrontendParametersTerrestrial()
            params.frequency = transponder["frequency"]
            params.bandwidth = transponder["bandwidth"]
            params.code_rate_hp = transponder["code_rate_hp"]
            params.code_rate_lp = transponder["code_rate_lp"]
            params.inversion = transponder["inversion"]
            params.system = transponder["system"]
            params.modulation = transponder["modulation"]
            params.transmission_mode = transponder["transmission_mode"]
            params.guard_interval = transponder["guard_interval"]
            params.hierarchy = transponder["hierarchy"]
            params_fe = eDVBFrontendParameters()
            params_fe.setDVBT(params)

        elif self.providers[self.currentAction]["streamtype"] == "dvbc":
            params = eDVBFrontendParametersCable()
            params.frequency = transponder["frequency"]
            params.symbol_rate = transponder["symbol_rate"]
            params.fec_inner = transponder["fec_inner"]
            params.inversion = transponder["inversion"]
            params.modulation = transponder["modulation"]
            params_fe = eDVBFrontendParameters()
            params_fe.setDVBC(params)

        try:
            self.rawchannel.requestTsidOnid()
        except TypeError:
            # for compatibility with some third party images
            self.rawchannel.requestTsidOnid(self.gotTsidOnid)

        self.frontend.tune(params_fe)
        self.manager.setAdapter(0)  # FIX: use the correct device
        self.manager.setDemuxer(demuxer_id)
        self.manager.setFrontend(current_slotid)

        self.current_slotid = current_slotid
        self.lockcounter = 0
        self.locktimer = eTimer()
        self.locktimer.callback.append(self.checkTunerLock)
        self.locktimer.start(100, 1)

    def checkTunerLock(self):
        from Screens.Standby import inStandby
        fe_status_dict = {}
        self.frontend and self.frontend.getFrontendStatus(fe_status_dict)
        tuner_state = fe_status_dict.get("tuner_state", "UNKNOWN")
        if tuner_state == "TUNING":
            print("[ABM-main][checkTunerLock] TUNING", file=log)
        elif tuner_state == "LOCKED":
            print("[ABM-main][checkTunerLock] ACQUIRING TSID/ONID", file=log)
            self.progresscurrent += 1
            if not inStandby:
                self["progress_text"].value = self.progresscurrent
                self["progress"].setValue(self.progresscurrent)
                self["action"].setText(
                    _("Reading %s...") %
                    str(self.providers[self.currentAction]["name"]))
                self["status"].setText(
                    _("Services: %d video - %d radio") %
                    (self.manager.getServiceVideoRead(),
                     self.manager.getServiceAudioRead()))
            self.timer = eTimer()
            self.timer.callback.append(self.doScan)
            self.timer.start(100, 1)
            return
        elif tuner_state == "LOSTLOCK":
            print("[ABM-main][checkTunerLock] LOSTLOCK", file=log)
        elif tuner_state == "FAILED":
            print("[ABM-main][checkTunerLock] TUNING FAILED FATAL", file=log)
            self.showError(
                _('Tuning failed!\n\nProvider: %s\nTuner: %s\nFrequency: %d MHz\n\nPlease check affected tuner for:\n\nTuner configuration errors,\nSignal cabling issues,\nAny other reception issues.'
                  ) % (str(self.providers[self.currentAction]["name"]),
                       chr(ord('A') + self.current_slotid),
                       self.transponder["frequency"] // 1000))
            return

        self.lockcounter += 1
        if self.lockcounter > self.LOCK_TIMEOUT:
            print("[AutoBouquetsMaker] Timeout for tuner lock, ", file=log)
            self.showError(
                _('Tuning lock timed out!\n\nProvider: %s\nTuner: %s\nFrequency: %d MHz\n\nPlease check affected tuner for:\n\nTuner configuration errors,\nSignal cabling issues,\nAny other reception issues.'
                  ) % (str(self.providers[self.currentAction]["name"]),
                       chr(ord('A') + self.current_slotid),
                       self.transponder["frequency"] // 1000))
            return

        self.locktimer.start(100, 1)

    # for compatibility with some third party images
    def gotTsidOnid(self, tsid, onid):
        print("[ABM-main][gotTsidOnid] tsid, onid:", tsid, onid, file=log)

        INTERNAL_PID_STATUS_NOOP = 0
        INTERNAL_PID_STATUS_WAITING = 1
        INTERNAL_PID_STATUS_SUCCESSFUL = 2
        INTERNAL_PID_STATUS_FAILED = 3

        if tsid is not None and onid is not None:
            self.pidStatus = INTERNAL_PID_STATUS_SUCCESSFUL
            self.tsid = tsid
            self.onid = onid
        else:
            self.pidStatus = INTERNAL_PID_STATUS_FAILED
            self.tsid = -1
            self.onid = -1
        self.timer.start(100, True)

    def doScan(self):
        if not self.manager.read(self.selectedProviders[self.currentAction],
                                 self.providers, self.motorised):
            print("[ABM-main][doScan] Cannot read data", file=log)
            self.showError(_('Cannot read data'))
            return
        self.doActions()

    def doBuildIndex(self):
        self.manager.save(self.providers, self.dependents)
        self.scanComplete()

    def scanComplete(self):
        from Screens.Standby import inStandby
        self.releaseFrontend()
        self.restartService()

        eDVBDB.getInstance().reloadServicelist()
        eDVBDB.getInstance().reloadBouquets()
        self.progresscurrent += 1
        if not inStandby:
            self["progress_text"].value = self.progresscurrent
            self["progress"].setValue(self.progresscurrent)
            self["action"].setText(_('Done'))
            self["status"].setText(
                _("Services: %d video - %d radio") %
                (self.manager.getServiceVideoRead(),
                 self.manager.getServiceAudioRead()))

        self.timer = eTimer()
        self.timer.callback.append(self.close)
        self.timer.start(2000, 1)

    def releaseFrontend(self):
        if hasattr(self, 'frontend'):
            del self.frontend
        if hasattr(self, 'rawchannel'):
            del self.rawchannel
        self.frontend = None
        self.rawchannel = None

    def restartService(self):
        if self.postScanService:
            self.session.nav.playService(self.postScanService)
            self.postScanService = None

    def isRotorSat(self, slot, orb_pos):
        rotorSatsForNim = nimmanager.getRotorSatListForNim(slot)
        if len(rotorSatsForNim) > 0:
            for sat in rotorSatsForNim:
                if sat[0] == orb_pos:
                    return True
        return False

    def validNIM(self, slot):
        return self.providers[
            self.currentAction]["streamtype"] != "dvbs" or self.providers[
                self.currentAction]["transponder"]["orbital_position"] in [
                    sat[0] for sat in nimmanager.getSatListForNim(slot)
                ]

    def printconfig(self):
        print("[ABM-config] level: ",
              config.autobouquetsmaker.level.value,
              file=log)
        print("[ABM-config] providers: ",
              config.autobouquetsmaker.providers.value,
              file=log)
        if config.autobouquetsmaker.bouquetsorder.value:
            print("[ABM-config] bouquetsorder: ",
                  config.autobouquetsmaker.bouquetsorder.value,
                  file=log)
        if config.autobouquetsmaker.keepallbouquets.value:
            print("[ABM-config] keepbouquets: All", file=log)
        else:
            print("[ABM-config] keepbouquets: ",
                  config.autobouquetsmaker.keepbouquets.value,
                  file=log)
        if config.autobouquetsmaker.hidesections.value:
            print("[ABM-config] hidesections: ",
                  config.autobouquetsmaker.hidesections.value,
                  file=log)
        print("[ABM-config] add provider prefix: ",
              config.autobouquetsmaker.addprefix.value,
              file=log)
        print("[ABM-config] show in extensions menu: ",
              config.autobouquetsmaker.extensions.value,
              file=log)
        print("[ABM-config] placement: ",
              config.autobouquetsmaker.placement.value,
              file=log)
        print("[ABM-config] skip services on non-configured satellites: ",
              config.autobouquetsmaker.skipservices.value,
              file=log)
        print("[ABM-config] show non-indexed: ",
              config.autobouquetsmaker.showextraservices.value,
              file=log)
        if config.autobouquetsmaker.FTA_only.value:
            print("[ABM-config] FTA_only: ",
                  config.autobouquetsmaker.FTA_only.value,
                  file=log)
        print("[ABM-config] schedule: ",
              config.autobouquetsmaker.schedule.value,
              file=log)
        if config.autobouquetsmaker.schedule.value:
            print("[ABM-config] schedule time: ",
                  config.autobouquetsmaker.scheduletime.value,
                  file=log)
            print(
                "[ABM-config] schedule days: ",
                [("Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
                  "Saturday", "Sunday")[i]
                 for i in range(7) if config.autobouquetsmaker.days[i].value],
                file=log)

    def getABMsettings(self):
        providers_extra = []
        providers_tmp = config.autobouquetsmaker.providers.value.split("|")
        for provider_str in providers_tmp:
            provider = provider_str.split(":", 1)[0]
            if provider in self.dependents:
                for descendent in self.dependents[provider]:
                    providers_extra.append('|' + descendent + ':' +
                                           provider_str.split(":", 1)[1])
        return config.autobouquetsmaker.providers.value + ''.join(
            providers_extra)

    def about(self):
        self.session.open(
            MessageBox,
            "AutoBouquetsMaker\nVersion date - 21/10/2012\n\nCoded by:\n\nSkaman and AndyBlac",
            MessageBox.TYPE_INFO)

    def help(self):
        self.session.open(MessageBox, "AutoBouquetsMaker\nto be coded.",
                          MessageBox.TYPE_INFO)

    def cancel(self):
        self.close(None)