2 from urllib import urlretrieve
4 from Plugins.Plugin import PluginDescriptor
6 from Components.config import config, getConfigListEntry, ConfigSubsection, ConfigText, ConfigSelection, ConfigYesNo,ConfigText
7 from Components.ConfigList import ConfigListScreen
8 from Components.ActionMap import ActionMap
9 from Components.Sources.StaticText import StaticText
10 from Components.Pixmap import Pixmap
11 from Components.Label import Label
13 from Components.FileList import FileList
14 from Components.Slider import Slider
16 from Screens.Screen import Screen
17 from Screens.MessageBox import MessageBox
19 from enigma import ePoint, eConsoleAppContainer, eTimer, getDesktop
20 from Tools.Directories import resolveFilename, SCOPE_PLUGINS
24 if os.path.exists("/proc/stb/info/vumodel"):
25 vumodel = open("/proc/stb/info/vumodel")
26 info = vumodel.read().strip()
32 ,("fp", _("Front Processor"))
35 "fpga" : ["http://archive.vuplus.com/download/fpga", "fpga.files", "/dev/fpga_dp;/dev/misc/dp;"]
36 ,"fp" : ["http://archive.vuplus.com/download/fp", "fp.files", "/dev/bcm_mu;"]
43 "fpga" : ["http://archive.vuplus.com/download/fpga", "fpga.files", "/dev/fpga_dp;/dev/misc/dp;"]
46 import os, fcntl, thread
51 STATUS_PROGRAMMING = 4
52 STATUS_RETRY_UPGRADE = 5
54 class FPUpgradeCore() :
58 def __init__(self, firmwarefile, devicefile):
59 self.devicefile = devicefile
60 self.firmwarefile = firmwarefile
63 firmware,device = None,None
64 def closefpga(fp, fd):
65 if fd is not None: os.close(fd)
66 if fp is not None: fp.close()
68 size = os.path.getsize(self.firmwarefile)
69 if size == 0: raise Exception, 'data_size is zero'
70 #print '[FPUpgradeCore] data_size :',size
74 self.status = STATUS_READY
76 firmware = open(self.firmwarefile, 'rb')
77 device = os.open(self.devicefile, os.O_RDWR)
78 #print '[FPUpgradeCore] open >> [ok]'
80 rc = fcntl.ioctl(device, 0, size)
81 if rc < 0: raise Exception, 'fail to set size : %d'%(rc)
82 #print '[FPUpgradeCore] set size >> [ok]'
83 self.status = STATUS_PREPARED
86 data = firmware.read(1024)
88 os.write(device, data)
89 #print '[FPUpgradeCore] write data >> [ok]'
91 self.status = STATUS_PROGRAMMING
92 rc = fcntl.ioctl(device, 1, 0)
94 if xx == 2: raise Exception, 'fail to upgrade : %d'%(rc)
95 self.errmsg = 'fail to upgrade, retry..'
96 self.status = STATUS_RETRY_UPGRADE
97 closefpga(firmware, device)
98 #print '[FPUpgradeCore] upgrade done.'
99 if self.callcount < 20: raise Exception, 'wrong fpga file.'
100 except Exception, msg:
102 print '[FPUpgradeCore] ERROR >>',msg
103 closefpga(firmware, device)
107 def upgradeMain(self):
108 self.status = STATUS_READY
109 self.status = self.doUpgrade()
110 if self.status == STATUS_DONE:
111 print 'upgrade done.'
112 elif self.status == STATUS_ERROR:
114 else: print 'unknown.'
116 class FPGAUpgradeCore() :
117 status = STATUS_READY
120 MAX_CALL_COUNT = 1500
121 def __init__(self, firmwarefile, devicefile):
122 print '[FPGAUpgrade]'
123 self.devicefile = devicefile
124 self.firmwarefile = firmwarefile
127 firmware,device = None,None
128 def closefpga(fp, fd):
129 if fd is not None: os.close(fd)
130 if fp is not None: fp.close()
132 size = os.path.getsize(self.firmwarefile)
133 if size == 0: raise Exception, 'data_size is zero'
134 #print '[FPGAUpgradeCore] data_size :',size
136 firmware = open(self.firmwarefile, 'rb')
137 device = os.open(self.devicefile, os.O_RDWR)
138 #print '[FPGAUpgradeCore] open >> [ok]'
140 rc = fcntl.ioctl(device, 0, size)
141 if rc < 0: raise Exception, 'fail to set size : %d'%(rc)
142 #print '[FPGAUpgradeCore] set size >> [ok]'
144 rc = fcntl.ioctl(device, 2, 5)
145 if rc < 0: raise Exception, 'fail to set programming mode : %d'%(rc)
146 #print '[FPGAUpgradeCore] programming mode >> [ok]'
147 self.status = STATUS_PREPARED
150 data = firmware.read(1024)
152 os.write(device, data)
153 #print '[FPGAUpgradeCore] write data >> [ok]'
155 self.status = STATUS_PROGRAMMING
156 rc = fcntl.ioctl(device, 1, 0)
157 if rc < 0: raise Exception, 'fail to programming : %d'%(rc)
158 #print '[FPGAUpgradeCore] upgrade done.'
159 if self.callcount < 20: raise Exception, 'wrong fpga file.'
160 except Exception, msg:
162 print '[FPGAUpgradeCore] ERROR >>',msg
163 closefpga(firmware, device)
165 closefpga(firmware, device)
168 def upgradeMain(self):
169 self.status = STATUS_READY
170 self.status = self.doUpgrade()
171 if self.status == STATUS_DONE:
172 print '[FPGAUpgrade] upgrade done.'
173 elif self.status == STATUS_ERROR:
174 print '[FPGAUpgrade] occur error.'
175 else: print '[FPGAUpgrade] occur unknown error.'
177 class FirmwareUpgradeManager:
179 def getInterval(self):
182 def startUpgrade(self, datafile, device, firmware):
183 if firmware == 'fpga':
184 self.fu = FPGAUpgradeCore(firmwarefile=datafile, devicefile=device)
185 elif firmware == 'fp':
186 self.fu = FPUpgradeCore(firmwarefile=datafile, devicefile=device)
187 thread.start_new_thread(self.fu.upgradeMain, ())
189 def checkError(self):
190 if self.fu.status == STATUS_ERROR:
191 self.fu.callcount = 0
196 if self.fu.status in (STATUS_READY, STATUS_ERROR):
198 elif self.fu.status == STATUS_PREPARED:
200 elif self.fu.status == STATUS_PROGRAMMING:
201 self.fu.callcount += 1
202 ret = (self.fu.callcount * 100) / self.fu.MAX_CALL_COUNT + 2
203 if ret >= 100: ret = 99
204 #print "callcount : [%d]"%(self.fu.callcount);
206 elif self.fu.status == STATUS_DONE:
209 def getErrorMessage(self, errno, errmsg):
210 return str(self.fu.errmsg)
212 class UpgradeStatus(Screen):
214 <screen position="center,center" size="450,130" title=" ">
215 <widget name="name" position="10,0" size="430,20" font="Regular;18" halign="left" valign="bottom"/>
216 <widget name="slider" position="10,25" size="430,30" borderWidth="2" borderColor="#cccccc"/>
217 <widget name="status" position="10,25" zPosition="1" size="430,30" font="Regular;18" halign="center" valign="center" foregroundColor="#9f1313" transparent="1"/>
218 <widget source="info" render="Label" position="10,70" zPosition="1" size="430,60" font="Regular;22" halign="center" valign="center" transparent="1"/>
222 def __init__(self, session, parent, firmware, datafile, device):
223 Screen.__init__(self,session)
224 self.session = session
226 self["actions"] = ActionMap(["OkCancelActions"],
231 self.firmware = firmware
232 self.datafile = datafile
233 #print "[FirmwareUpgrade] - [%s][%s][%s]" % (self.datafile, firmware, device)
235 self["name"] = Label(_(" "))
236 self["info"] = StaticText(_("Can't cancel during upgrade!!"))
238 self["status"] = Label(_("Status : 0%"))
240 self.slider = Slider(0, 100)
241 self["slider"] = self.slider
245 self.setTitle(firmware.upper() + " Upgrade Status")
247 self.FU = FirmwareUpgradeManager()
250 self.status_exit = None
251 self.check_status = eTimer()
252 self.check_status.callback.append(self.cbCheckStatus)
253 self.check_status.start(self.FU.getInterval())
255 self.exitTimerCallCount = 0;
256 self.upgradeLock = True
257 self.FU.startUpgrade(self.datafile, device, firmware)
259 def cbCheckStatus(self):
261 errno = self.FU.checkError()
263 self.check_status.stop()
264 errmsg = self.FU.getErrorMessage(errno, errmsg)
265 print "[FirmwareUpgrade] - ERROR : [%d][%s]" % (errno, errmsg)
266 self.session.open(MessageBox, _(errmsg), MessageBox.TYPE_INFO, timeout = 10)
267 self.cbConfirmExit(False)
269 status = self.FU.getStatus()
270 if self.old_status > status and status != -1:
271 self.session.open(MessageBox, _("Fail to upgrade!! Retry!!"), MessageBox.TYPE_INFO, timeout = 10)
272 self.slider.setValue(status)
273 self["status"].setText(_("%d / 100" % (status)))
275 self.check_status.stop()
276 self["status"].setText(_("Success. Press OK to exit."))
277 self.status_exit = eTimer()
278 self.status_exit.callback.append(self.cbTimerExit)
279 self.status_exit.start(1000)
280 self.upgradeLock = False
281 self.old_status = status
283 def setCallback(self, cb):
286 def cbTimerExit(self):
287 if self.exitTimerCallCount < 10: # exit after 10 sec.
288 self.exitTimerCallCount = self.exitTimerCallCount + 1
289 self.setTitle("%s Upgrade Status (%d)" % (self.firmware.upper(), 10-self.exitTimerCallCount))
291 if self.status_exit is not None:
292 self.status_exit.stop()
295 def cbConfirmExit(self, ret):
297 os.system("rm -f %s %s.md5" % (self.datafile, self.datafile))
303 if self.callback is not None:
304 self.callback("Reboot now for a successful upgrade.", True)
305 self.session.openWithCallback(self.cbConfirmExit, MessageBox, _("Do you want to remove binary data?"), MessageBox.TYPE_YESNO, timeout = 10, default = False)
307 class FUFilebrowser(Screen):
309 <screen position="center,center" size="500,290" title="File Browser" >
310 <ePixmap pixmap="skin_default/buttons/blue.png" position="5,10" size="140,40" alphatest="blend" />
312 <widget source="key_blue" render="Label" position="5,10" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" foregroundColor="#ffffff" transparent="1"/>
314 <widget name="file_list" position="0,70" size="495,160" scrollbarMode="showOnDemand" />
315 <widget source="status" render="Label" position="0,230" zPosition="1" size="495,70" font="Regular;18" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
319 def __init__(self, session, parent, firmware):
320 Screen.__init__(self, session)
321 self.session = session
323 self["key_blue"] = StaticText(_("Download"))
325 self["status"] = StaticText(_(" "))
326 self["file_list"] = FileList("/", matchingPattern = "^.*")
328 self["actions"] = ActionMap(["OkCancelActions", "ShortcutActions", "WizardActions", "ColorActions", ],
330 "ok": self.onClickOk,
331 "cancel": self.onClickCancel,
332 "blue": self.onClickBlue,
333 "up": self.onClickUp,
334 "down": self.onClickDown,
335 "left": self.onClickLeft,
336 "right": self.onClickRight,
340 self.firmware = firmware
343 self.timer_downloading = None
345 self.downloadLock = False
346 self.setTitle(firmware.upper() + " File Browser")
349 self["status"].setText("Select to press OK, Exit to press Cancel.\nPress the BLUE button to download the latest firmware.")
351 def setCallback(self, func):
355 if self.downloadLock:
358 if self["file_list"].canDescent() : # isDir
359 self["file_list"].descent()
363 self.gbin = self["file_list"].getCurrentDirectory() + self["file_list"].getFilename()
364 if not os.path.exists(self.gbin):
365 self.session.open(MessageBox, _("Can't found binary file."), MessageBox.TYPE_INFO, timeout = 10)
367 if not os.path.exists(self.gbin+".md5"):
368 self.session.open(MessageBox, _("Can't found MD5 file."), MessageBox.TYPE_INFO, timeout = 10)
372 name_ext = os.path.splitext(self["file_list"].getFilename())
373 return len(name_ext)==2 and ext.startswith(name_ext[1])
374 self.check_ext = False
375 if (self.firmware == "fp" and checkExt(".bin")) or (self.firmware == "fpga" and checkExt(".dat")):
376 self.check_ext = True
377 if self.check_ext == False:
378 self.session.open(MessageBox, _("You chose the incorrect file."), MessageBox.TYPE_INFO)
381 self.session.open(MessageBox, _("You chose the incorrect file."), MessageBox.TYPE_INFO)
384 if os.path.exists("/usr/bin/md5sum") == False:
385 self.session.open(MessageBox, _("Can't find /usr/bin/md5sum"), MessageBox.TYPE_INFO, timeout = 10)
387 md5sum_A = os.popen("md5sum %s | awk \'{print $1}\'"%(self.gbin)).readline().strip()
388 md5sum_B = os.popen("cat %s.md5 | awk \'{print $1}\'"%(self.gbin)).readline().strip()
389 #print "[FirmwareUpgrade] - Verify : file[%s], md5[%s]"%(md5sum_A,md5sum_B)
391 if md5sum_A != md5sum_B:
392 self.session.open(MessageBox, _("Fail to verify data file. \nfile[%s]\nmd5[%s]"%(md5sum_A,md5sum_B)), MessageBox.TYPE_INFO, timeout = 10)
395 if self.callback is not None:
396 self.callback(_(self.gbin))
399 def onClickCancel(self):
402 # uri : source file url(string)
403 # tf : target file name(string)
404 # bd : target base directory(string)
405 # cbfunc(string) : callback function(function)
406 def doDownload(self, uri, tf, bd='/tmp', cbfunc=None, errmsg="Fail to download."):
408 #print "[FirmwareUpgrade] - Download Info : [%s][%s]" % (uri, tar)
409 def doHook(blockNumber, blockSize, totalSize) :
410 if blockNumber*blockSize > totalSize and cbfunc is not None:
412 opener = urllib.URLopener()
416 #self.session.open(MessageBox, _("File not found in this URL:\n%s"%(uri)), MessageBox.TYPE_INFO, timeout = 10)
417 print "[FirmwareUpgrade] - Fail to download. URL :",uri
418 self.session.open(MessageBox, _(errmsg), MessageBox.TYPE_INFO, timeout = 10)
422 f, h = urlretrieve(uri, tar, doHook)
424 #self.session.open(MessageBox, _(str(msg)), MessageBox.TYPE_INFO, timeout = 10)
425 print "[FirmwareUpgrade] - Fail to download. ERR_MSG :",str(msg)
426 self.session.open(MessageBox, _(errmsg), MessageBox.TYPE_INFO, timeout = 10)
432 def runDownloading(self) :
433 self.timer_downloading.stop()
434 machine = str(open("/proc/stb/info/vumodel").read().strip())
436 def cbDownloadDone(tar):
438 if os.path.splitext(tar)[1] != ".files":
439 self["status"].setText("Downloaded : %s\nSelect to press OK, Exit to press Cancel."%(tar))
444 root_uri = fwdata[self.firmware][0]
445 root_file = fwdata[self.firmware][1]
446 if not self.doDownload("%s/%s"%(root_uri, root_file), root_file, cbfunc=cbDownloadDone):
448 self.downloadLock = False
452 for l in file("/tmp/"+root_file).readlines():
453 if l.startswith(machine):
455 target_path = l.split("=")[1].strip()
459 if target_path == "":
460 self.session.open(MessageBox, _("Firmware does not exist."), MessageBox.TYPE_INFO)
462 self.downloadLock = False
465 self.guri = "%s/vu%s/%s"%(root_uri, machine, target_path)
466 self.gbin = os.path.basename(target_path)
467 #print "[FirmwareUpgrade] - uri[%s], data[%s], data_path[%s]" % (self.gbin, self.guri, target_path)
468 os.system("rm -f /tmp/" + root_file)
471 if not self.doDownload(self.guri+".md5", self.gbin+".md5", cbfunc=cbDownloadDone, errmsg="Can't download the checksum file."):
473 self.downloadLock = False
476 if not self.doDownload(self.guri, self.gbin, cbfunc=cbDownloadDone, errmsg="Can't download the firmware file."):
478 self.downloadLock = False
482 self["file_list"].changeDir("/tmp/")
483 self["file_list"].moveToIndex(0)
484 while cmp(self["file_list"].getFilename(), self.gbin) != 0 :
485 self["file_list"].down()
486 if cmp(t, self["file_list"].getFilename()) == 0:
488 t = self["file_list"].getFilename()
490 del self.timer_downloading
491 self.timer_downloading = None
492 self.downloadLock = False
494 def onClickBlue(self):
495 if self.downloadLock:
497 self.downloadLock = True
498 if not os.path.exists("/proc/stb/info/vumodel"):
499 self.session.open(MessageBox, _("Can't found model name."), MessageBox.TYPE_INFO, timeout = 10)
500 self.downloadLock = False
502 self["status"].setText("Please wait during download.")
503 self.timer_downloading = eTimer()
504 self.timer_downloading.callback.append(self.runDownloading)
505 self.timer_downloading.start(1000)
508 if self.downloadLock:
511 self["file_list"].up()
513 def onClickDown(self):
514 if self.downloadLock:
517 self["file_list"].down()
519 def onClickLeft(self):
520 if self.downloadLock:
523 self["file_list"].pageUp()
525 def onClickRight(self):
526 if self.downloadLock:
529 self["file_list"].pageDown()
534 class FirmwareUpgrade(Screen, ConfigListScreen):
536 <screen position="center,center" size="560,175" title="Firmware Upgrade" >
537 <ePixmap pixmap="skin_default/buttons/red.png" position="110,10" size="140,40" alphatest="blend" />
538 <ePixmap pixmap="skin_default/buttons/green.png" position="310,10" size="140,40" alphatest="blend" />
540 <widget source="key_red" render="Label" position="110,10" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" foregroundColor="#ffffff" transparent="1" />
541 <widget source="key_green" render="Label" position="310,10" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" foregroundColor="#ffffff" transparent="1" />
543 <widget name="config" zPosition="2" position="0,70" itemHeight="36" size="540,40" scrollbarMode="showOnDemand" transparent="1" />
544 <widget source="status" render="Label" position="0,100" zPosition="1" size="540,75" font="Regular;20" halign="center" valign="center" />
548 def __init__(self, session):
549 Screen.__init__(self, session)
550 self.session = session
552 self["shortcuts"] = ActionMap(["ShortcutActions", "SetupActions" ],
555 "cancel": self.keyRed,
557 "green": self.keyGreen,
558 "blue": self.keyBlue,
562 self.updateFilePath = ""
564 self.finishedExit = False
566 self.rebootLock = False
567 self.rebootMessage = ""
568 self.cbRebootCallCount = 0;
570 ConfigListScreen.__init__(self, self.list, session=self.session)
571 self["key_red"] = StaticText(_("Close"))
574 self.old_blue_clicked = 0
575 self.fileopenmode = False
576 self.upgrade_auto_run_timer = eTimer()
577 self.upgrade_auto_run_timer.callback.append(self.keyGreen)
581 self["key_green"] = StaticText(_(" "))
582 self["status"] = StaticText(_("This plugin is supported only the Ultimo/Uno."))
584 self["key_green"] = StaticText(_("Upgrade"))
585 self["status"] = StaticText(_(" "))
591 self._item_firmware = ConfigSelection(default=fwlist[0][0], choices=fwlist)
592 self._entry_firmware = getConfigListEntry(_("Firmware"), self._item_firmware)
593 self.list.append(self._entry_firmware)
594 self["config"].list = self.list
595 self["config"].l.setList(self.list)
598 def setupStatus(self,message=None,reboot=False):
599 self.updateFilePath = ""
600 if message is not None:
601 self.rebootLock = reboot
602 self["status"].setText(message)
604 self.rebootMessage = message
605 self.reboot_timer = eTimer()
606 self.reboot_timer.callback.append(self.cbReboot)
607 self.reboot_timer.start(1000)
609 if not self.rebootLock:
610 self["status"].setText("Press the Green/OK button")
613 from Screens.Standby import TryQuitMainloop
614 self.session.open(TryQuitMainloop, 2)
618 self.finishedExit = True
619 if self.cbRebootCallCount < max_call_count:
620 self.cbRebootCallCount = self.cbRebootCallCount + 1
621 #self["status"].setText("%s (%d)"%(self.rebootMessage, max_call_count-self.cbRebootCallCount))
622 self["status"].setText("Reboot after %d seconds. Press the OK to reboot now."%(max_call_count-self.cbRebootCallCount))
626 # filebrowser window callback function
627 def cbSetStatus(self, data=None):
629 self["status"].setText("Press the Green/OK button, if you want to upgrade to this file:\n%s\n" % (data))
630 self.updateFilePath = data
631 if self.fileopenmode == False:
632 self.upgrade_auto_run_timer.start(1000)
634 # upgrade window callback function
635 def cbFinishedUpgrade(self,message=None,reboot=False):
636 self.setupStatus(message=message,reboot=reboot)
638 def cbRunUpgrade(self, ret):
642 if self.updateFilePath == "":
643 self.session.open(MessageBox, _("No selected binary data!!"), MessageBox.TYPE_INFO, timeout = 10)
646 for d in fwdata[self._item_firmware.value][2].split(';'):
647 if os.path.exists(d):
650 self.session.open(MessageBox, _("Can't found device file!!"), MessageBox.TYPE_INFO, timeout = 10)
652 fbs = self.session.open(UpgradeStatus, self, self._item_firmware.value, self.updateFilePath, device)
653 fbs.setCallback(self.cbFinishedUpgrade)
655 def doFileOpen(self):
656 fbs = self.session.open(FUFilebrowser, self, self._item_firmware.value)
657 fbs.setCallback(self.cbSetStatus)
665 ConfigListScreen.keyLeft(self)
674 ConfigListScreen.keyRight(self)
678 if self.finishedExit:
681 self.upgrade_auto_run_timer.stop()
687 if self.updateFilePath == "":
688 #self.session.open(MessageBox, _("No selected binary data!!"), MessageBox.TYPE_INFO)
691 msg = "You should not be stop during the upgrade.\nDo you want to upgrade?"
692 self.session.openWithCallback(self.cbRunUpgrade, MessageBox, _(msg), MessageBox.TYPE_YESNO, timeout = 15, default = True)
693 self.fileopenmode = False
701 self.fileopenmode = True
710 if self.old_blue_clicked:
713 if os.path.exists("/tmp/onlogmode"):
715 os.system("touch /tmp/onlogmode")
720 if self.logmode is not None and self.old_blue_clicked == 0:
722 if self.old_blue_clicked:
723 self.old_blue_clicked = 0
725 self.old_blue_clicked = 1
726 self.logmode = eTimer()
727 self.logmode.callback.append(self.cbLogMode)
728 self.logmode.start(1000)
733 def main(session, **kwargs):
734 session.open(FirmwareUpgrade)
736 def Plugins(**kwargs):
737 return PluginDescriptor(name=_("Firmware Upgrade"), description="Upgrade Firmware..", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=main)