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