Merge branch 'bug_474_fix_multicontent_clear'
[vuplus_dvbapp] / lib / python / Plugins / SystemPlugins / NFIFlash / flasher.py
1 from Screens.Screen import Screen
2 from Screens.MessageBox import MessageBox
3 from Screens.ChoiceBox import ChoiceBox
4 from Screens.Standby import TryQuitMainloop
5 from Components.ActionMap import ActionMap
6 from Components.Sources.StaticText import StaticText
7 from Components.Sources.Progress import Progress
8 from Components.Sources.Boolean import Boolean
9 from Components.Label import Label
10 from Components.FileList import FileList
11 from Components.Task import Task, Job, JobManager
12 from Tools.Directories import fileExists
13 from Tools.HardwareInfo import HardwareInfo
14 from os import system
15 from enigma import eConsoleAppContainer
16 import re
17
18 class writeNAND(Task):
19         def __init__(self,job,param,box):
20                 Task.__init__(self,job, ("Writing image file to NAND Flash"))
21                 self.setTool("/usr/lib/enigma2/python/Plugins/SystemPlugins/NFIFlash/mywritenand")
22                 if box == "dm7025":
23                         self.end = 256
24                 elif box[:5] == "dm800":
25                         self.end = 512
26                 if box == "dm8000":
27                         self.setTool("/usr/lib/enigma2/python/Plugins/SystemPlugins/NFIFlash/dm8000_writenand")
28                 self.args += param
29                 self.weighting = 1
30
31         def processOutput(self, data):
32                 print "[writeNand] " + data
33                 if data == "." or data.endswith(" ."):
34                         self.progress += 1
35                 elif data.find("*** done!") > 0:
36                         print "data.found done"
37                         self.setProgress(self.end)
38                 else:
39                         self.output_line = data
40
41 class NFISummary(Screen):
42         skin = """
43         <screen position="0,0" size="132,64">
44                 <widget source="title" render="Label" position="2,0" size="120,14" valign="center" font="Regular;12" />
45                 <widget source="content" render="Label" position="2,14" size="120,34" font="Regular;12" transparent="1" zPosition="1"  />
46                 <widget source="job_progresslabel" render="Label" position="66,50" size="60,14" font="Regular;12" transparent="1" halign="right" zPosition="0" />
47                 <widget source="job_progressbar" render="Progress" position="2,50" size="66,14" borderWidth="1" />
48         </screen>"""
49
50         def __init__(self, session, parent):
51                 Screen.__init__(self, session, parent)
52                 self["title"] = StaticText(_("Image flash utility"))
53                 self["content"] = StaticText(_("Please select .NFI flash image file from medium"))
54                 self["job_progressbar"] = Progress()
55                 self["job_progresslabel"] = StaticText("")
56
57         def setText(self, text):
58                 self["content"].setText(text)
59
60 class NFIFlash(Screen):
61         skin = """
62                 <screen name="NFIFlash" position="90,95" size="560,420" title="Image flash utility">
63                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
64                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
65                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
66                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;19" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
67                         <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;19" valign="center" halign="center" backgroundColor="#a08500" transparent="1" />
68                         <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;19" valign="center" halign="center" backgroundColor="#18188b" transparent="1" />
69                         <widget source="listlabel" render="Label" position="10,44" size="250,20" font="Regular;16" />
70                         <widget name="filelist" position="0,68" size="260,260" scrollbarMode="showOnDemand" />
71                         <widget source="infolabel" render="Label" position="270,44" size="280,284" font="Regular;16" />
72                         <widget source="job_progressbar" render="Progress" position="10,374" size="540,26" borderWidth="1" backgroundColor="#254f7497" />
73                         <widget source="job_progresslabel" render="Label" position="180,378" zPosition="2" font="Regular;18" halign="center" transparent="1" size="200,22" foregroundColor="#000000" />
74                         <widget source="statusbar" render="Label" position="10,404" size="540,16" font="Regular;16" foregroundColor="#cccccc" />
75                 </screen>"""
76
77         def __init__(self, session, cancelable = True, close_on_finish = False):
78                 self.skin = NFIFlash.skin
79                 Screen.__init__(self, session)
80                 
81                 self["job_progressbar"] = Progress()
82                 self["job_progresslabel"] = StaticText("")
83                 
84                 self["finished"] = Boolean()
85
86                 self["infolabel"] = StaticText("")
87                 self["statusbar"] = StaticText(_("Please select .NFI flash image file from medium"))
88                 self["listlabel"] = StaticText(_("select .NFI flash file")+":")
89                 
90                 self["key_green"] = StaticText()
91                 self["key_yellow"] = StaticText()
92                 self["key_blue"] = StaticText()
93
94                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "DirectionActions"],
95                 {
96                         "green": self.ok,
97                         "yellow": self.reboot,
98                         "blue": self.runWizard,
99                         "ok": self.ok,
100                         "left": self.left,
101                         "right": self.right,
102                         "up": self.up,
103                         "down": self.down
104                 }, -1)
105
106                 currDir = "/media/usb/"
107                 self.filelist = FileList(currDir, matchingPattern = "^.*\.(nfi|NFI)")
108                 self["filelist"] = self.filelist
109                 self.nfifile = ""
110                 self.md5sum = ""
111                 self.job = None
112                 self.box = HardwareInfo().get_device_name()
113                 self.configuration_restorable = None
114                 self.wizard_mode = False
115                 from enigma import eTimer
116                 self.delayTimer = eTimer()
117                 self.delayTimer.callback.append(self.runWizard)
118                 self.delayTimer.start(50,1)
119
120         def check_for_wizard(self):
121                 if self["filelist"].getCurrentDirectory() is not None and fileExists(self["filelist"].getCurrentDirectory()+"wizard.nfo"):
122                         self["key_blue"].text = _("USB stick wizard")
123                         return True
124                 else:
125                         self["key_blue"].text = ""
126                         return False
127
128         def runWizard(self):
129                 if not self.check_for_wizard():
130                         self.wizard_mode = False
131                         return
132                 wizardcontent = open(self["filelist"].getCurrentDirectory()+"/wizard.nfo", "r").readlines()
133                 nfifile = None
134                 for line in wizardcontent:
135                         line = line.strip()
136                         if line.startswith("image: "):
137                                 nfifile = self["filelist"].getCurrentDirectory()+line[7:]
138                         if line.startswith("configuration: "):
139                                 backupfile = self["filelist"].getCurrentDirectory()+line[15:]
140                                 if fileExists(backupfile):
141                                         print "wizard configuration:", backupfile
142                                         self.configuration_restorable = backupfile
143                                 else:
144                                         self.configuration_restorable = None
145                 if nfifile and fileExists(nfifile):
146                         self.wizard_mode = True
147                         print "wizard image:", nfifile
148                         self.check_for_NFO(nfifile)
149                         self.queryFlash()
150
151         def closeCB(self):
152                 if ( self.job is None or self.job.status is not self.job.IN_PROGRESS ) and not self.no_autostart:
153                         self.close()
154                 #else:
155                         #if self.cancelable:
156                                 #self.cancel()
157
158         def up(self):
159                 self["filelist"].up()
160                 self.check_for_NFO()
161
162         def down(self):
163                 self["filelist"].down()
164                 self.check_for_NFO()
165         
166         def right(self):
167                 self["filelist"].pageDown()
168                 self.check_for_NFO()
169
170         def left(self):
171                 self["filelist"].pageUp()
172                 self.check_for_NFO()
173
174         def check_for_NFO(self, nfifile=None):
175                 self.session.summary.setText(self["filelist"].getFilename())
176                 if nfifile is None:
177                         self.session.summary.setText(self["filelist"].getFilename())
178                         if self["filelist"].getFilename() is None:
179                                 return
180                         if self["filelist"].getCurrentDirectory() is not None:
181                                 self.nfifile = self["filelist"].getCurrentDirectory()+self["filelist"].getFilename()
182                 else:
183                         self.nfifile = nfifile
184
185                 if self.nfifile.upper().endswith(".NFI"):
186                         self["key_green"].text = _("Flash")
187                         nfofilename = self.nfifile[0:-3]+"nfo"
188                         if fileExists(nfofilename):
189                                 nfocontent = open(nfofilename, "r").read()
190                                 self["infolabel"].text = nfocontent
191                                 pos = nfocontent.find("MD5:")
192                                 if pos > 0:
193                                         self.md5sum = nfocontent[pos+5:pos+5+32] + "  " + self.nfifile
194                                 else:
195                                         self.md5sum = ""
196                         else:
197                                 self["infolabel"].text = _("No details for this image file") + (self["filelist"].getFilename() or "")
198                                 self.md5sum = ""
199                 else:
200                         self["infolabel"].text = ""
201                         self["key_green"].text = ""
202
203         def ok(self):
204                 if self.job is None or self.job.status is not self.job.IN_PROGRESS:
205                         if self["filelist"].canDescent(): # isDir
206                                 self["filelist"].descent()
207                                 self.session.summary.setText(self["filelist"].getFilename())
208                                 self.check_for_NFO()
209                                 self.check_for_wizard()
210                         else:
211                                 self.queryFlash()
212         
213         def queryFlash(self):
214                 fd = open(self.nfifile, 'r')
215                 print fd
216                 sign = fd.read(11)
217                 print sign
218                 if sign.find("NFI1" + self.box + "\0") == 0:
219                         if self.md5sum != "":
220                                 self["statusbar"].text = ("Please wait for md5 signature verification...")
221                                 self.session.summary.setText(("Please wait for md5 signature verification..."))
222                                 self.container = eConsoleAppContainer()
223                                 self.container.setCWD(self["filelist"].getCurrentDirectory())
224                                 self.container.appClosed.append(self.md5finished)
225                                 self.container.dataSent.append(self.md5ready)
226                                 self.container.execute("md5sum -cw -")
227                                 self.container.write(self.md5sum)
228                         else:
229                                 self.session.openWithCallback(self.queryCB, MessageBox, _("This .NFI file does not have a md5sum signature and is not guaranteed to work. Do you really want to burn this image to flash memory?"), MessageBox.TYPE_YESNO)
230                 else:
231                         self.session.open(MessageBox, (_("This .NFI file does not contain a valid %s image!") % (self.box.upper())), MessageBox.TYPE_ERROR)
232
233         def md5ready(self, retval):
234                 self.container.sendEOF()
235
236         def md5finished(self, retval):
237                 if retval==0:
238                         if self.wizard_mode:
239                                 self.session.openWithCallback(self.queryCB, MessageBox, _("Shall the USB stick wizard proceed and program the image file %s into flash memory?" % self.nfifile.rsplit('/',1)[-1]), MessageBox.TYPE_YESNO)
240                         else:
241                                 self.session.openWithCallback(self.queryCB, MessageBox, _("This .NFI file has a valid md5 signature. Continue programming this image to flash memory?"), MessageBox.TYPE_YESNO)
242                 else:
243                         self.session.openWithCallback(self.queryCB, MessageBox, _("The md5sum validation failed, the file may be corrupted! Are you sure that you want to burn this image to flash memory? You are doing this at your own risk!"), MessageBox.TYPE_YESNO)
244
245         def queryCB(self, answer):
246                 if answer == True:
247                         self.createJob()
248                 else:
249                         self["statusbar"].text = _("Please select .NFI flash image file from medium")
250                         self.wizard_mode = False
251
252         def createJob(self):
253                 self.job = Job("Image flashing job")
254                 param = [self.nfifile]
255                 writeNAND(self.job,param,self.box)
256                 #writeNAND2(self.job,param)
257                 #writeNAND3(self.job,param)
258                 self.job.state_changed.append(self.update_job)
259                 self.job.end = 540
260                 self.cwd = self["filelist"].getCurrentDirectory()
261                 self["job_progressbar"].range = self.job.end
262                 self.startJob()
263
264         def startJob(self):
265                 self["key_blue"].text = ""
266                 self["key_yellow"].text = ""
267                 self["key_green"].text = ""
268                 #self["progress0"].show()
269                 #self["progress1"].show()
270
271                 self.job.start(self.jobcb)
272
273         def update_job(self):
274                 j = self.job
275                 #print "[job state_changed]"
276                 if j.status == j.IN_PROGRESS:
277                         self.session.summary["job_progressbar"].value = j.progress
278                         self.session.summary["job_progressbar"].range = j.end
279                         self.session.summary["job_progresslabel"].text = "%.2f%%" % (100*j.progress/float(j.end))
280                         self["job_progressbar"].range = j.end
281                         self["job_progressbar"].value = j.progress
282                         #print "[update_job] j.progress=%f, j.getProgress()=%f, j.end=%d, text=%f" % (j.progress, j.getProgress(), j.end,  (100*j.progress/float(j.end)))
283                         self["job_progresslabel"].text = "%.2f%%" % (100*j.progress/float(j.end))
284                         self.session.summary.setText(j.tasks[j.current_task].name)
285                         self["statusbar"].text = (j.tasks[j.current_task].name)
286
287                 elif j.status == j.FINISHED:
288                         self["statusbar"].text = _("Writing NFI image file to flash completed")
289                         self.session.summary.setText(_("NFI image flashing completed. Press Yellow to Reboot!"))
290                         if self.wizard_mode:
291                                 self.restoreConfiguration()
292                         self["key_yellow"].text = _("Reboot")
293
294                 elif j.status == j.FAILED:
295                         self["statusbar"].text = j.tasks[j.current_task].name + " " + _("failed")
296                         self.session.open(MessageBox, (_("Flashing failed") + ":\n" + j.tasks[j.current_task].name + ":\n" + j.tasks[j.current_task].output_line), MessageBox.TYPE_ERROR)
297
298         def jobcb(self, jobref, fasel, blubber):
299                 print "[jobcb] %s %s %s" % (jobref, fasel, blubber)
300                 self["key_green"].text = _("Flash")
301
302         def reboot(self, ret=None):
303                 if self.job.status == self.job.FINISHED:
304                         self["statusbar"].text = ("rebooting...")
305                         TryQuitMainloop(self.session,2)
306
307         def restoreConfiguration(self):
308                 if self.configuration_restorable:
309                         from Screens.Console import Console
310                         cmdlist = [ "mount /dev/mtdblock/3 /mnt/realroot -t jffs2", "tar -xzvf " + self.configuration_restorable + " -C /mnt/realroot/" ]
311                         self.session.open(Console, title = "Restore running", cmdlist = cmdlist, finishedCallback = self.restore_finished, closeOnSuccess = True)
312
313         def restore_finished(self):
314                 self.session.openWithCallback(self.reboot, MessageBox, _("USB stick wizard finished. Your dreambox will now restart with your new image!"), MessageBox.TYPE_INFO)
315
316         def createSummary(self):
317                 return NFISummary