[firmwareupgrade] change the order for the list of firmware.
[vuplus_dvbapp] / lib / python / Plugins / SystemPlugins / FirmwareUpgrade / plugin.py
1 import os, urllib
2 from urllib import urlretrieve
3
4 from Plugins.Plugin import PluginDescriptor
5
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
12
13 from Components.FileList import FileList 
14 from Components.Slider import Slider
15
16 from Screens.Screen import Screen
17 from Screens.MessageBox import MessageBox
18
19 from enigma import ePoint, eConsoleAppContainer, eTimer
20 from Tools.Directories import resolveFilename, SCOPE_PLUGINS
21
22 fwlist = None
23 fwdata = None
24 if os.path.exists("/proc/stb/info/vumodel"):
25         vumodel = open("/proc/stb/info/vumodel")
26         info = vumodel.read().strip()
27         vumodel.close()
28
29         if info == "ultimo":
30                 fwlist= [
31                          ("fpga", _("FPGA"))
32                         ,("fp", _("Front Processor"))
33                         ]
34                 fwdata= { 
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;"]
37                         }
38         elif info == "uno":
39                 fwlist= [
40                         ("fpga", _("FPGA"))
41                         ]
42                 fwdata= { 
43                         "fpga" : ["http://archive.vuplus.com/download/fpga", "fpga.file", "/dev/fpga_dp;/dev/misc/dp;"]
44                         }
45
46 class UpgradeStatus(Screen):
47         skin =  """
48                 <screen position="center,center" size="450,100" title=" ">
49                         <widget name="name" position="10,0" size="430,20" font="Regular;18" halign="left" valign="bottom"/>
50                         <widget name="slider" position="10,25" size="430,30" backgroundColor="white"/>
51                         <widget name="status" position="10,25" zPosition="1" size="430,30" font="Regular;18" halign="center" valign="center" foregroundColor="black" backgroundColor="black" transparent="1"/>
52                         <widget source="info" render="Label" position="10,70" zPosition="1" size="430,30" font="Regular;22" halign="center" valign="center" backgroundColor="#a08500" transparent="1"/>
53                 </screen>
54                 """
55
56         def __init__(self, session, parent, firmware, datafile, device):
57                 Screen.__init__(self,session)
58                 self.session = session
59
60                 self["actions"] = ActionMap(["OkCancelActions"],
61                 {
62                         "ok": self.keyExit,
63                 }, -1)
64
65                 self.firmware = firmware
66                 self.datafile = datafile
67                 #print "[FirmwareUpgrade] - [%s][%s][%s]" % (self.datafile, firmware, device)
68
69                 self["name"] = Label(_(" "))
70                 self["info"] = StaticText(_("Can't cancel during upgrade!!"))
71
72                 self["status"] = Label(_("Status : 0%"))
73
74                 self.slider = Slider(0, 100)
75                 self["slider"] = self.slider
76
77                 self.callback = None
78
79                 self.setTitle(firmware.upper() + " Upgrade Status")
80
81                 import fu
82                 self.FU = fu.FU()
83
84                 self.old_status   = 0
85                 self.status_exit  = None
86                 self.check_status = eTimer()
87                 self.check_status.callback.append(self.cbCheckStatus)
88                 self.check_status.start(self.FU.getInterval())
89
90                 self.exitTimerCallCount = 0;
91                 self.upgradeLock = True
92                 self.FU.startUpgrade(self.datafile, device, firmware)
93
94         def cbCheckStatus(self):
95                 errmsg = ""
96                 errno  = self.FU.checkError()
97                 if errno:
98                         self.check_status.stop()
99                         errmsg = self.FU.getErrorMessage(errno, errmsg)
100                         print "[FirmwareUpgrade] - ERROR : [%d][%s]" % (errno, errmsg)
101                         self.session.open(MessageBox, _(errmsg), MessageBox.TYPE_INFO, timeout = 10)
102                         self.cbConfirmExit(False)
103                         return
104                 status = self.FU.getStatus()
105                 if self.old_status > status:
106                         self.session.open(MessageBox, _("Fail to upgrade!! Retry!!"), MessageBox.TYPE_INFO, timeout = 10)
107                 self.slider.setValue(status)
108                 self["status"].setText(_("%d / 100" % (status)))
109                 if status == 100:
110                         self.check_status.stop()
111                         self["status"].setText(_("Success. Press OK to exit."))
112                         self.status_exit = eTimer()
113                         self.status_exit.callback.append(self.cbTimerExit)
114                         self.status_exit.start(1000)
115                         self.upgradeLock = False
116                 self.old_status = status
117
118         def setCallback(self, cb):
119                 self.callback = cb
120
121         def cbTimerExit(self):
122                 if self.exitTimerCallCount < 10: # exit after 10 sec.
123                         self.exitTimerCallCount = self.exitTimerCallCount + 1
124                         self.setTitle("%s Upgrade Status (%d)" % (self.firmware.upper(), 10-self.exitTimerCallCount))
125                         return
126                 if self.status_exit is not None:
127                         self.status_exit.stop()
128                 self.keyExit()
129
130         def cbConfirmExit(self, ret):
131                 if ret:
132                         os.system("rm -f %s %s.md5" % (self.datafile, self.datafile))
133                 self.close()
134
135         def keyExit(self):
136                 if self.upgradeLock:
137                         return
138                 if self.callback is not None:
139                         self.callback("Reboot now for a successful upgrade.", True)
140                 self.session.openWithCallback(self.cbConfirmExit, MessageBox, _("Do you want to remove binary data?"), MessageBox.TYPE_YESNO, timeout = 10, default = False)
141
142 class Filebrowser(Screen):
143         skin =  """
144                 <screen position="center,center" size="500,260" title="File Browser" >
145                         <ePixmap pixmap="Vu_HD/buttons/blue.png" position="5,7" size="80,40" alphatest="blend" />
146                         <widget source="key_blue" render="Label" position="40,0" zPosition="1" size="180,40" font="Regular;20" halign="left" valign="center" transparent="1"/>
147                         <widget name="file_list" position="0,50" size="500,160" scrollbarMode="showOnDemand" />
148
149                         <widget source="status" render="Label" position="0,220" zPosition="1" size="500,40" font="Regular;18" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
150                 </screen>
151                 """
152
153         def __init__(self, session, parent, firmware):
154                 Screen.__init__(self, session)
155                 self.session = session 
156                 
157                 self["key_blue"] = StaticText(_("Download"))
158
159                 self["status"]    = StaticText(_(" "))
160                 self["file_list"] = FileList("/", matchingPattern = "^.*")
161
162                 self["actions"] = ActionMap(["OkCancelActions", "ShortcutActions", "WizardActions", "ColorActions", ],
163                 {
164                         "ok":     self.onClickOk,
165                         "cancel": self.onClickCancel,
166                         "blue":   self.onClickBlue,
167                         "up":     self.onClickUp,
168                         "down":   self.onClickDown,
169                         "left":   self.onClickLeft,
170                         "right":  self.onClickRight,
171                 }, -1) 
172
173                 self.resetGUI()
174                 self.firmware = firmware
175
176                 self.callback = None
177                 self.timer_downloading = None
178
179                 self.downloadLock = False
180                 self.setTitle(firmware.upper() + " File Browser")
181
182         def resetGUI(self):
183                 self["status"].setText("Select to press OK, Exit to press Cancel.")
184
185         def setCallback(self, func):
186                 self.callback = func
187
188         def onClickOk(self):
189                 if self.downloadLock:
190                         return
191
192                 if self["file_list"].canDescent() : # isDir
193                         self["file_list"].descent()
194                         return
195
196                 # verify data
197                 self.gbin = self["file_list"].getCurrentDirectory() + self["file_list"].getFilename()
198                 if not os.path.exists(self.gbin):
199                         self.session.open(MessageBox, _("Can't found binary file."), MessageBox.TYPE_INFO, timeout = 10)
200                         return
201                 if not os.path.exists(self.gbin+".md5"):
202                         self.session.open(MessageBox, _("Can't found MD5 file."), MessageBox.TYPE_INFO, timeout = 10)
203                         return
204                 try:
205                         def checkExt(ext):
206                                 name_ext = os.path.splitext(self["file_list"].getFilename())
207                                 return len(name_ext)==2 and ext.startswith(name_ext[1])
208                         self.check_ext = False
209                         if (self.firmware == "fp" and checkExt(".bin")) or (self.firmware == "fpga" and checkExt(".dat")):
210                                 self.check_ext = True
211                         if self.check_ext == False:
212                                 self.session.open(MessageBox, _("You chose the incorrect file."), MessageBox.TYPE_INFO)
213                                 return
214                 except:
215                         self.session.open(MessageBox, _("You chose the incorrect file."), MessageBox.TYPE_INFO)
216                         return
217
218                 if os.path.exists("/usr/bin/md5sum") == False:
219                         self.session.open(MessageBox, _("Can't find /usr/bin/md5sum"), MessageBox.TYPE_INFO, timeout = 10)
220                         return
221                 md5sum_A = os.popen("md5sum %s | awk \'{print $1}\'"%(self.gbin)).readline().strip()
222                 md5sum_B = os.popen("cat %s.md5 | awk \'{print $1}\'"%(self.gbin)).readline().strip()
223                 #print "[FirmwareUpgrade] - Verify : file[%s], md5[%s]"%(md5sum_A,md5sum_B)
224
225                 if md5sum_A != md5sum_B:
226                         self.session.open(MessageBox, _("Fail to verify data file. \nfile[%s]\nmd5[%s]"%(md5sum_A,md5sum_B)), MessageBox.TYPE_INFO, timeout = 10)
227                         return 
228
229                 if self.callback is not None:
230                         self.callback(_(self.gbin))
231                 self.close()
232
233         def onClickCancel(self):
234                 self.close()
235
236         # uri : source file url(string)
237         # tf  : target file name(string)
238         # bd  : target base directory(string)
239         # cbfunc(string) : callback function(function)
240         def doDownload(self, uri, tf, bd='/tmp', cbfunc=None):
241                 tar = bd + "/" + tf
242                 #print "[FirmwareUpgrade] - Download Info : [%s][%s]" % (uri, tar)
243                 def doHook(blockNumber, blockSize, totalSize) :
244                         if blockNumber*blockSize > totalSize and cbfunc is not None:
245                                 cbfunc(tar)
246                 opener = urllib.URLopener()
247                 try:
248                         opener.open(uri)
249                 except:
250                         self.session.open(MessageBox, _("File not found in this URL:\n%s"%(uri)), MessageBox.TYPE_INFO, timeout = 10)
251                         del opener
252                         return False
253                 try :
254                         f, h = urlretrieve(uri, tar, doHook)
255                 except IOError, msg:
256                         self.session.open(MessageBox, _(str(msg)), MessageBox.TYPE_INFO, timeout = 10)
257                         del opener
258                         return False
259                 del opener
260                 return True
261
262         def runDownloading(self) :
263                 self.timer_downloading.stop()
264                 machine = str(open("/proc/stb/info/vumodel").read().strip())
265
266                 def cbDownloadDone(tar):
267                         try:
268                                 if os.path.splitext(tar)[1] != ".files":
269                                         self["status"].setText("Downloaded : %s\nSelect to press OK, Exit to press Cancel."%(tar))
270                         except:
271                                 pass
272                 # target
273                 global fwdata
274                 root_uri  = fwdata[self.firmware][0]
275                 root_file = fwdata[self.firmware][1]
276                 if not self.doDownload("%s/%s"%(root_uri, root_file), root_file, cbfunc=cbDownloadDone):
277                         self.resetGUI()
278                         self.downloadLock = False
279                         return
280
281                 target_path = ""
282                 for l in file("/tmp/"+root_file).readlines():
283                         if l.startswith(machine):
284                                 try:
285                                         target_path = l.split("=")[1].strip()
286                                 except:
287                                         target_path = ""
288                                         pass
289                 if target_path == "":
290                         self.session.open(MessageBox, _("Firmware does not exist."), MessageBox.TYPE_INFO)
291                         self.resetGUI()
292                         self.downloadLock = False
293                         return
294
295                 self.guri = "%s/vu%s/%s"%(root_uri, machine, target_path)
296                 self.gbin = os.path.basename(target_path)
297                 #print "[FirmwareUpgrade] - uri[%s], data[%s], data_path[%s]" % (self.gbin, self.guri, target_path)
298                 os.system("rm -f /tmp/" + root_file)
299
300                 # md5
301                 if not self.doDownload(self.guri+".md5", self.gbin+".md5", cbfunc=cbDownloadDone):
302                         self.resetGUI()
303                         self.downloadLock = False
304                         return
305                 # data
306                 if not self.doDownload(self.guri, self.gbin, cbfunc=cbDownloadDone):
307                         self.resetGUI()
308                         self.downloadLock = False
309                         return
310
311                 t = ''
312                 self["file_list"].changeDir("/tmp/")
313                 self["file_list"].moveToIndex(0)
314                 while cmp(self["file_list"].getFilename(), self.gbin) != 0 :
315                         self["file_list"].down()
316                         if cmp(t, self["file_list"].getFilename()) == 0:
317                                 break
318                         t = self["file_list"].getFilename()
319
320                 del self.timer_downloading
321                 self.timer_downloading = None
322                 self.downloadLock = False
323
324         def onClickBlue(self):
325                 if self.downloadLock:
326                         return
327                 self.downloadLock = True
328                 if not os.path.exists("/proc/stb/info/vumodel"):
329                         self.session.open(MessageBox, _("Can't found model name."), MessageBox.TYPE_INFO, timeout = 10)
330                         self.downloadLock = False
331                         return
332                 self["status"].setText("Please wait during download.")
333                 self.timer_downloading = eTimer()
334                 self.timer_downloading.callback.append(self.runDownloading)
335                 self.timer_downloading.start(1000)
336
337         def onClickUp(self):
338                 if self.downloadLock:
339                         return
340                 self.resetGUI()
341                 self["file_list"].up()
342
343         def onClickDown(self):
344                 if self.downloadLock:
345                         return
346                 self.resetGUI()
347                 self["file_list"].down()
348
349         def onClickLeft(self):
350                 if self.downloadLock:
351                         return
352                 self.resetGUI()
353                 self["file_list"].pageUp()
354
355         def onClickRight(self):
356                 if self.downloadLock:
357                         return
358                 self.resetGUI()
359                 self["file_list"].pageDown()
360
361         def keyNone(self):
362                 None
363
364 class FirmwareUpgrade(Screen, ConfigListScreen):
365         skin =  """
366                 <screen position="center,center" size="560,175" title="Firmware Upgrade" >
367                         <ePixmap pixmap="Vu_HD/buttons/red.png" position="125,7" size="80,40" alphatest="blend" />
368                         <ePixmap pixmap="Vu_HD/buttons/green.png" position="330,7" size="80,40" alphatest="blend" />
369
370                         <widget source="key_red" render="Label" position="160,0" zPosition="1" size="155,40" font="Regular;20" halign="left" valign="center" transparent="1" />
371                         <widget source="key_green" render="Label" position="365,0" zPosition="1" size="155,40" font="Regular;20" halign="left" valign="center" transparent="1" />
372
373                         <widget name="config" zPosition="2" position="0,50" itemHeight="36" size="540,40" scrollbarMode="showOnDemand" transparent="1" />
374                         <widget source="status" render="Label" position="0,100" zPosition="1" size="540,75" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
375                 </screen>
376                 """
377
378         def __init__(self, session): 
379                 Screen.__init__(self, session)
380                 self.session = session 
381
382                 self["shortcuts"] = ActionMap(["ShortcutActions", "SetupActions" ],
383                 {
384                         "ok":      self.keyGreen,
385                         "cancel":  self.keyRed,
386                         "red":     self.keyRed,
387                         "green":   self.keyGreen,
388                         "blue":    self.keyBlue,
389                 }, -2)
390
391                 self.list = []
392                 self.updateFilePath = ""
393
394                 self.rebootLock = False
395                 self.rebootMessage = ""
396                 self.cbRebootCallCount = 0;
397
398                 ConfigListScreen.__init__(self, self.list, session=self.session)
399                 self["key_red"] = StaticText(_("Close"))
400
401                 self.logmode = None
402                 self.old_blue_clicked = 0
403                 self.fileopenmode = False
404                 self.upgrade_auto_run_timer = eTimer()
405                 self.upgrade_auto_run_timer.callback.append(self.keyGreen)
406
407                 global fwlist
408                 if fwlist is None:
409                         self["key_green"] = StaticText(_(" "))
410                         self["status"] = StaticText(_("This plugin is supported only the Ultimo/Uno."))
411                 else:
412                         self["key_green"] = StaticText(_("Upgrade"))
413                         self["status"] = StaticText(_(" "))
414                         self.setupUI()
415
416         def setupUI(self):
417                 global fwlist
418                 self.list = []
419                 self._item_firmware  = ConfigSelection(default=fwlist[0][0],  choices=fwlist)
420                 self._entry_firmware = getConfigListEntry(_("Firmware"), self._item_firmware)
421                 self.list.append(self._entry_firmware)
422                 self["config"].list = self.list
423                 self["config"].l.setList(self.list)
424                 self.setupStatus()
425
426         def setupStatus(self,message=None,reboot=False):
427                 self.updateFilePath = ""
428                 if message is not None:
429                         self.rebootLock = reboot
430                         self["status"].setText(message)
431                         if reboot:
432                                 self.rebootMessage = message
433                                 self.reboot_timer = eTimer()
434                                 self.reboot_timer.callback.append(self.cbReboot)
435                                 self.reboot_timer.start(500)
436                         return
437                 if not self.rebootLock:
438                         self["status"].setText("Press the Green/OK button")
439
440         def cbReboot(self):
441                 if self.cbRebootCallCount < 6:
442                         self.cbRebootCallCount = self.cbRebootCallCount + 1
443                         self["status"].setText("%s (%d)"%(self.rebootMessage, 6-self.cbRebootCallCount))
444                         return
445                 from Screens.Standby import TryQuitMainloop
446                 self.session.open(TryQuitMainloop, 2)
447
448         # filebrowser window callback function
449         def cbSetStatus(self, data=None):
450                 if data is not None:
451                         self["status"].setText("Press the Green/OK button, if you want to upgrade to this file:\n%s\n" % (data))
452                         self.updateFilePath = data
453                         if self.fileopenmode == False:
454                                 self.upgrade_auto_run_timer.start(1000)
455
456         # upgrade window callback function
457         def cbFinishedUpgrade(self,message=None,reboot=False):
458                 self.setupStatus(message=message,reboot=reboot)
459
460         def cbRunUpgrade(self, ret):
461                 if ret == False:
462                         return
463
464                 if self.updateFilePath == "":
465                         self.session.open(MessageBox, _("No selected binary data!!"), MessageBox.TYPE_INFO, timeout = 10)
466                         return
467                 device = None
468                 for d in fwdata[self._item_firmware.value][2].split(';'):
469                         if os.path.exists(d):
470                                 device = d                      
471                 if device is None:
472                         self.session.open(MessageBox, _("Can't found device file!!"), MessageBox.TYPE_INFO, timeout = 10)
473                         return
474                 fbs = self.session.open(UpgradeStatus, self, self._item_firmware.value, self.updateFilePath, device)
475                 fbs.setCallback(self.cbFinishedUpgrade)
476         
477         def doFileOpen(self):
478                 fbs = self.session.open(Filebrowser, self, self._item_firmware.value)
479                 fbs.setCallback(self.cbSetStatus)
480
481         def keyLeft(self):
482                 if self.rebootLock:
483                         return
484                 global fwlist
485                 if fwlist is None:
486                         return
487                 ConfigListScreen.keyLeft(self)
488                 self.setupStatus()
489
490         def keyRight(self):
491                 global fwlist
492                 if fwlist is None:
493                         return
494                 ConfigListScreen.keyRight(self)
495                 self.setupStatus()
496
497         def keyGreen(self):
498                 self.upgrade_auto_run_timer.stop()
499                 if self.rebootLock:
500                         return
501                 global fwlist
502                 if fwlist is None:
503                         return
504                 if self.updateFilePath == "":
505                         #self.session.open(MessageBox, _("No selected binary data!!"), MessageBox.TYPE_INFO)
506                         self.doFileOpen()
507                         return
508                 msg = "You should not be stop during the upgrade.\nDo you want to upgrade?"
509                 self.session.openWithCallback(self.cbRunUpgrade, MessageBox, _(msg), MessageBox.TYPE_YESNO, timeout = 15, default = True)
510                 self.fileopenmode = False
511
512         def keyYellow(self):
513                 if self.rebootLock:
514                         return
515                 global fwlist
516                 if fwlist is None:
517                         return
518                 self.fileopenmode = True
519                 self.doFileOpen()
520
521         def keyRed(self):
522                 if self.rebootLock:
523                         return
524                 self.close()
525
526         def cbLogMode(self):
527                 if self.old_blue_clicked:
528                         return
529                 self.logmode.stop()
530                 if os.path.exists("/tmp/onlogmode"):
531                         return
532                 os.system("touch /tmp/onlogmode")
533
534         def keyBlue(self):
535                 if self.rebootLock:
536                         return
537                 if self.logmode is not None and self.old_blue_clicked == 0:
538                         return
539                 if self.old_blue_clicked:
540                         self.old_blue_clicked = 0
541                         return
542                 self.old_blue_clicked = 1
543                 self.logmode = eTimer()
544                 self.logmode.callback.append(self.cbLogMode)
545                 self.logmode.start(1000)
546                 
547         def keyNone(self):
548                 None
549
550 def main(session, **kwargs):
551         session.open(FirmwareUpgrade)
552                                                            
553 def Plugins(**kwargs):            
554         return PluginDescriptor(name=_("Firmware Upgrade"), description="Upgrade Firmware..", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=main)
555