| 82 |
benedikt93 |
1 |
#!/usr/bin/env python
|
| 64 |
benedikt93 |
2 |
#
|
|
|
3 |
#
|
| 171 |
farthen |
4 |
# Copyright 2010 TheSeven, benedikt93, Farthen
|
| 64 |
benedikt93 |
5 |
#
|
|
|
6 |
#
|
| 427 |
farthen |
7 |
# This file is part of emCORE.
|
| 64 |
benedikt93 |
8 |
#
|
| 427 |
farthen |
9 |
# emCORE is free software: you can redistribute it and/or
|
| 64 |
benedikt93 |
10 |
# modify it under the terms of the GNU General Public License as
|
|
|
11 |
# published by the Free Software Foundation, either version 2 of the
|
|
|
12 |
# License, or (at your option) any later version.
|
|
|
13 |
#
|
| 427 |
farthen |
14 |
# emCORE is distributed in the hope that it will be useful,
|
| 64 |
benedikt93 |
15 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
16 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
17 |
# See the GNU General Public License for more details.
|
|
|
18 |
#
|
| 82 |
benedikt93 |
19 |
# You should have received a copy of the GNU General Public License
|
| 427 |
farthen |
20 |
# along with emCORE. If not, see <http://www.gnu.org/licenses/>.
|
| 64 |
benedikt93 |
21 |
#
|
| 787 |
theseven |
22 |
#
|
| 64 |
benedikt93 |
23 |
|
| 402 |
farthen |
24 |
"""
|
| 427 |
farthen |
25 |
Command line interface to communicate with emCORE devices.
|
| 402 |
farthen |
26 |
Run it without arguments to see usage information.
|
|
|
27 |
"""
|
|
|
28 |
|
| 171 |
farthen |
29 |
import sys
|
|
|
30 |
import os
|
| 176 |
farthen |
31 |
import time
|
| 215 |
theseven |
32 |
import struct
|
| 346 |
theseven |
33 |
import locale
|
| 64 |
benedikt93 |
34 |
|
| 176 |
farthen |
35 |
from functools import wraps
|
|
|
36 |
|
| 427 |
farthen |
37 |
import libemcore
|
|
|
38 |
import libemcoredata
|
| 532 |
farthen |
39 |
from misc import Error, ArgumentError, ArgumentTypeError, Logger, getfuncdoc, gethwname, to_bool, to_int
|
| 64 |
benedikt93 |
40 |
|
| 236 |
farthen |
41 |
|
| 444 |
farthen |
42 |
def usage(errormsg=None, specific=False, docstring=True):
|
| 171 |
farthen |
43 |
"""
|
|
|
44 |
Prints the usage information.
|
|
|
45 |
It is auto generated from various places.
|
|
|
46 |
"""
|
|
|
47 |
logger = Logger()
|
| 396 |
farthen |
48 |
cmddict = Commandline.cmddict
|
|
|
49 |
doc = getfuncdoc(cmddict)
|
| 171 |
farthen |
50 |
if not specific:
|
| 501 |
farthen |
51 |
logger.write("Please provide a command and (if needed) parameters as command line arguments\n\n")
|
|
|
52 |
logger.write("Available commands:\n\n")
|
| 82 |
benedikt93 |
53 |
else:
|
| 501 |
farthen |
54 |
logger.write("\n")
|
| 171 |
farthen |
55 |
for function in sorted(doc.items()):
|
|
|
56 |
function = function[0]
|
|
|
57 |
if specific == False or specific == function:
|
| 501 |
farthen |
58 |
logger.write(function + " ", 2)
|
| 171 |
farthen |
59 |
for arg in doc[function]['args']:
|
| 501 |
farthen |
60 |
logger.write("<" + arg + "> ")
|
| 171 |
farthen |
61 |
if doc[function]['kwargs']:
|
| 579 |
farthen |
62 |
for kwarg, kwvalue in doc[function]['kwargs']:
|
| 501 |
farthen |
63 |
logger.write("[" + kwarg + " = " + str(kwvalue) + "] ")
|
| 171 |
farthen |
64 |
if doc[function]['varargs']:
|
| 501 |
farthen |
65 |
logger.write("<db1> ... <dbN>")
|
| 444 |
farthen |
66 |
if docstring and doc[function]['documentation']:
|
| 501 |
farthen |
67 |
logger.write("\n")
|
|
|
68 |
logger.write(doc[function]['documentation']+"\n", 4)
|
|
|
69 |
logger.write("\n")
|
|
|
70 |
logger.write("\n")
|
| 517 |
farthen |
71 |
|
| 171 |
farthen |
72 |
if errormsg:
|
|
|
73 |
logger.error(str(errormsg)+"\n")
|
|
|
74 |
exit(2)
|
|
|
75 |
|
|
|
76 |
|
|
|
77 |
def command(func):
|
|
|
78 |
"""
|
|
|
79 |
Decorator for all commands.
|
|
|
80 |
The decorated function is called with (self, all, other, arguments, ...)
|
|
|
81 |
"""
|
| 176 |
farthen |
82 |
@wraps(func)
|
| 172 |
farthen |
83 |
def decorator(*args):
|
| 171 |
farthen |
84 |
return func(args[0], *args[1:])
|
|
|
85 |
func._command = True
|
|
|
86 |
decorator.func = func
|
|
|
87 |
return decorator
|
|
|
88 |
|
|
|
89 |
|
|
|
90 |
def commandClass(cls):
|
|
|
91 |
"""
|
|
|
92 |
Decorator for the class. Sets the self.cmddict of the class
|
|
|
93 |
to all functions decorated with @command
|
|
|
94 |
"""
|
|
|
95 |
cls.cmddict = {}
|
| 582 |
farthen |
96 |
for attr, value in cls.__dict__.items():
|
| 171 |
farthen |
97 |
if getattr(value, 'func', False):
|
|
|
98 |
if getattr(value.func, '_command', False):
|
|
|
99 |
cls.cmddict[value.func.__name__] = value
|
|
|
100 |
return cls
|
|
|
101 |
|
|
|
102 |
|
|
|
103 |
@commandClass
|
|
|
104 |
class Commandline(object):
|
|
|
105 |
"""
|
|
|
106 |
If you want to create a new commandline function you just need to
|
|
|
107 |
create a function with the name of it in this class and decorate
|
|
|
108 |
it with the decorator @command. If you don't want to call the desired
|
|
|
109 |
function (wrong arguments etc) just raise ArgumentError with or
|
| 341 |
farthen |
110 |
without an error message.
|
| 171 |
farthen |
111 |
"""
|
|
|
112 |
def __init__(self):
|
|
|
113 |
self.logger = Logger()
|
|
|
114 |
try:
|
| 499 |
farthen |
115 |
self.emcore = libemcore.Emcore(logger = self.logger)
|
| 427 |
farthen |
116 |
except libemcore.DeviceNotFoundError:
|
| 478 |
farthen |
117 |
self.logger.error("No emCORE device found!\n")
|
| 176 |
farthen |
118 |
exit(1)
|
|
|
119 |
self.getinfo("version")
|
| 517 |
farthen |
120 |
|
| 171 |
farthen |
121 |
def _parsecommand(self, func, args):
|
|
|
122 |
# adds self to the commandline args.
|
|
|
123 |
# this is needed because the functions need access to their class.
|
|
|
124 |
args.insert(0, self)
|
|
|
125 |
if func in self.cmddict:
|
|
|
126 |
try:
|
| 172 |
farthen |
127 |
self.cmddict[func](*args)
|
| 582 |
farthen |
128 |
except (ArgumentError, libemcore.ArgumentError) as e:
|
| 176 |
farthen |
129 |
usage(e, specific=func)
|
| 427 |
farthen |
130 |
except (ArgumentError, libemcore.ArgumentError):
|
| 176 |
farthen |
131 |
usage("Syntax Error in function '" + func + "'", specific=func)
|
| 582 |
farthen |
132 |
except ArgumentTypeError as e:
|
| 176 |
farthen |
133 |
usage(e, specific=func)
|
| 171 |
farthen |
134 |
except NotImplementedError:
|
| 478 |
farthen |
135 |
self.logger.error("This function is not implemented yet!\n")
|
| 582 |
farthen |
136 |
except libemcore.DeviceError as e:
|
| 478 |
farthen |
137 |
self.logger.error(str(e) + "\n")
|
| 582 |
farthen |
138 |
except TypeError as e:
|
| 341 |
farthen |
139 |
# Only act on TypeErrors for the function we called, not on TypeErrors raised by another function.
|
| 171 |
farthen |
140 |
if str(e).split(" ", 1)[0] == func + "()":
|
| 516 |
farthen |
141 |
self.logger.error(usage("Argument Error in '%s': Wrong argument count" % func, specific=func))
|
| 171 |
farthen |
142 |
else:
|
|
|
143 |
raise
|
| 951 |
theseven |
144 |
# except libemcore.usb.core.USBError:
|
|
|
145 |
# self.logger.error("There is a problem with the USB connection.\n")
|
| 171 |
farthen |
146 |
else:
|
| 502 |
farthen |
147 |
usage("No such command!", docstring = False)
|
| 532 |
farthen |
148 |
|
| 67 |
benedikt93 |
149 |
|
| 171 |
farthen |
150 |
@command
|
| 444 |
farthen |
151 |
def help(self):
|
| 502 |
farthen |
152 |
""" Displays this help """
|
|
|
153 |
usage(docstring = True)
|
| 444 |
farthen |
154 |
|
|
|
155 |
@command
|
| 171 |
farthen |
156 |
def getinfo(self, infotype):
|
|
|
157 |
"""
|
| 427 |
farthen |
158 |
Get info on the running emCORE.
|
| 675 |
farthen |
159 |
<infotype> may be either of 'version', 'packetsize', 'mallocpoolbounds'.
|
| 171 |
farthen |
160 |
"""
|
|
|
161 |
if infotype == "version":
|
| 427 |
farthen |
162 |
hwtype = gethwname(self.emcore.lib.dev.hwtypeid)
|
| 516 |
farthen |
163 |
self.logger.info("Connected to %s v%d.%d.%d r%d running on %s\n" % (
|
|
|
164 |
libemcoredata.swtypes[self.emcore.lib.dev.swtypeid],
|
|
|
165 |
self.emcore.lib.dev.version.majorv,
|
|
|
166 |
self.emcore.lib.dev.version.minorv,
|
|
|
167 |
self.emcore.lib.dev.version.patchv,
|
|
|
168 |
self.emcore.lib.dev.version.revision,
|
|
|
169 |
hwtype))
|
| 343 |
farthen |
170 |
|
| 171 |
farthen |
171 |
elif infotype == "packetsize":
|
| 516 |
farthen |
172 |
self.logger.info("Maximum packet sizes:\n")
|
|
|
173 |
self.logger.info("command out: %d\n" % self.emcore.lib.dev.packetsizelimit.cout, 4)
|
|
|
174 |
self.logger.info("command in: %d\n" % self.emcore.lib.dev.packetsizelimit.cin, 4)
|
|
|
175 |
self.logger.info("data out: %d\n" % self.emcore.lib.dev.packetsizelimit.dout, 4)
|
|
|
176 |
self.logger.info("data in: %d\n" % self.emcore.lib.dev.packetsizelimit.din, 4)
|
| 343 |
farthen |
177 |
|
| 675 |
farthen |
178 |
elif infotype == "mallocpoolbounds":
|
|
|
179 |
resp = self.emcore.getmallocpoolbounds()
|
|
|
180 |
self.logger.info("The malloc pool is 0x%X - 0x%X" % (
|
|
|
181 |
self.emcore.lib.dev.mallocpool.lower,
|
|
|
182 |
self.emcore.lib.dev.mallocpool.upper - 1))
|
| 382 |
farthen |
183 |
|
| 171 |
farthen |
184 |
else:
|
| 675 |
farthen |
185 |
raise ArgumentTypeError("one out of 'version', 'packetsize', 'mallocpoolbounds'", infotype)
|
| 64 |
benedikt93 |
186 |
|
| 171 |
farthen |
187 |
@command
|
|
|
188 |
def reset(self, force=False):
|
|
|
189 |
"""
|
|
|
190 |
Resets the device"
|
| 402 |
farthen |
191 |
If [force] is 1, the reset will be forced, otherwise it will be gracefully,
|
| 171 |
farthen |
192 |
which may take some time.
|
|
|
193 |
"""
|
| 532 |
farthen |
194 |
force = to_bool(force)
|
| 171 |
farthen |
195 |
if force: self.logger.info("Resetting forcefully...\n")
|
|
|
196 |
else: self.logger.info("Resetting...\n")
|
| 427 |
farthen |
197 |
self.emcore.reset(force)
|
| 64 |
benedikt93 |
198 |
|
| 171 |
farthen |
199 |
@command
|
|
|
200 |
def poweroff(self, force=False):
|
|
|
201 |
"""
|
|
|
202 |
Powers the device off
|
| 402 |
farthen |
203 |
If [force] is 1, the poweroff will be forced, otherwise it will be gracefully,
|
| 171 |
farthen |
204 |
which may take some time.
|
|
|
205 |
"""
|
| 532 |
farthen |
206 |
force = to_bool(force)
|
| 281 |
farthen |
207 |
if force: self.logger.info("Powering off forcefully...\n")
|
|
|
208 |
else: self.logger.info("Powering off...\n")
|
| 427 |
farthen |
209 |
self.emcore.poweroff(force)
|
| 64 |
benedikt93 |
210 |
|
| 171 |
farthen |
211 |
@command
|
| 442 |
farthen |
212 |
def uploadfile(self, filename, addr = None):
|
| 171 |
farthen |
213 |
"""
|
|
|
214 |
Uploads a file to the device
|
| 442 |
farthen |
215 |
<filename>: The path to the file
|
|
|
216 |
[addr]: The address to upload the file to. Allocates a chunk of memory if not given.
|
| 171 |
farthen |
217 |
"""
|
| 532 |
farthen |
218 |
addr = to_int(addr)
|
| 171 |
farthen |
219 |
try:
|
|
|
220 |
f = open(filename, 'rb')
|
|
|
221 |
except IOError:
|
|
|
222 |
raise ArgumentError("File not readable. Does it exist?")
|
| 442 |
farthen |
223 |
if addr is not None:
|
| 516 |
farthen |
224 |
self.logger.info("Writing file '%s' to memory at 0x%X...\n" % (filename, addr))
|
| 442 |
farthen |
225 |
else:
|
| 516 |
farthen |
226 |
self.logger.info("Writing file '%s' to an allocated memory region...\n" % filename)
|
| 171 |
farthen |
227 |
with f:
|
| 442 |
farthen |
228 |
if addr is not None:
|
|
|
229 |
self.emcore.write(addr, f.read())
|
|
|
230 |
else:
|
|
|
231 |
addr = self.emcore.upload(f.read())
|
|
|
232 |
size = f.tell()
|
| 178 |
farthen |
233 |
f.close()
|
| 516 |
farthen |
234 |
self.logger.info("Done uploading %d bytes to 0x%X\n" % (size, addr))
|
| 442 |
farthen |
235 |
return addr, size
|
| 176 |
farthen |
236 |
|
| 171 |
farthen |
237 |
@command
|
|
|
238 |
def downloadfile(self, addr, size, filename):
|
|
|
239 |
"""
|
| 574 |
theseven |
240 |
Downloads a region of memory from the device to a file
|
|
|
241 |
<addr>: the address to download the data from
|
| 171 |
farthen |
242 |
<size>: the number of bytes to be read
|
|
|
243 |
<filename>: the path to the file
|
|
|
244 |
"""
|
| 532 |
farthen |
245 |
addr = to_int(addr)
|
|
|
246 |
size = to_int(size)
|
| 171 |
farthen |
247 |
try:
|
|
|
248 |
f = open(filename, 'wb')
|
|
|
249 |
except IOError:
|
|
|
250 |
raise ArgumentError("Can not open file for write!")
|
| 516 |
farthen |
251 |
self.logger.info("Reading data from address 0x%X with the size 0x%X to '%s'..." %
|
|
|
252 |
(addr, size, filename))
|
| 171 |
farthen |
253 |
with f:
|
| 427 |
farthen |
254 |
f.write(self.emcore.read(addr, size))
|
| 178 |
farthen |
255 |
f.close()
|
| 171 |
farthen |
256 |
self.logger.info("done\n")
|
| 517 |
farthen |
257 |
|
| 171 |
farthen |
258 |
@command
|
| 578 |
theseven |
259 |
def hexdump(self, addr, size, width = 16, wordsize = 1, separate = 4, align = False, \
|
|
|
260 |
relative = False, ascii = True, asciisep = 8, asciirep = ".", zeropad = True):
|
| 575 |
theseven |
261 |
"""
|
|
|
262 |
Downloads a region of memory from the device and hexdumps it
|
|
|
263 |
<addr>: the address to download the data from
|
|
|
264 |
<size>: the number of bytes to be dumped
|
|
|
265 |
[width]: the number of words per output line
|
|
|
266 |
[wordsize]: the number of bytes per word (little endian)
|
|
|
267 |
[separate]: add an additional space character every [separate] words
|
|
|
268 |
[align]: if true, output lines are aligned to the line size
|
|
|
269 |
[relative]: if true, the addresses displayed are relative to the <addr>, not zero
|
|
|
270 |
[ascii]: add ASCII representations of the bytes to the output
|
|
|
271 |
[asciisep]: add an additional space character every [asciisep] ASCII characters
|
| 578 |
theseven |
272 |
[asciirep]: replacement character for non-printable ASCII characters
|
|
|
273 |
[zeropad]: pad hex values with zero instead of space characters
|
| 575 |
theseven |
274 |
"""
|
|
|
275 |
addr = to_int(addr)
|
|
|
276 |
size = to_int(size)
|
|
|
277 |
width = to_int(width)
|
|
|
278 |
wordsize = to_int(wordsize)
|
|
|
279 |
separate = to_int(separate)
|
|
|
280 |
align = to_bool(align)
|
|
|
281 |
relative = to_bool(relative)
|
|
|
282 |
ascii = to_bool(ascii)
|
|
|
283 |
asciisep = to_int(asciisep)
|
| 578 |
theseven |
284 |
zeropad = to_bool(zeropad)
|
| 575 |
theseven |
285 |
if addr % wordsize != 0: raise ArgumentError("Address is not word aligned!")
|
|
|
286 |
if size % wordsize != 0: raise ArgumentError("Size is not word aligned!")
|
|
|
287 |
if align: skip = addr % (wordsize * width)
|
|
|
288 |
else: skip = 0
|
|
|
289 |
if relative: base = 0
|
|
|
290 |
else: base = addr
|
|
|
291 |
data = self.emcore.read(addr, size)
|
|
|
292 |
for r in range(-skip, size, wordsize * width):
|
|
|
293 |
sys.stdout.write("%08X:" % (base + r))
|
|
|
294 |
for i in range(r, r + wordsize * width, wordsize):
|
|
|
295 |
if i - r > 0 and (i - r) % (separate * wordsize) == 0: sys.stdout.write(" ")
|
|
|
296 |
if i >= 0 and i < size:
|
|
|
297 |
w = 0
|
|
|
298 |
for b in range(wordsize):
|
| 851 |
theseven |
299 |
w = w | (struct.unpack("B", data[i + b : i + b + 1])[0] << (8 * b))
|
| 578 |
theseven |
300 |
sys.stdout.write(((" %%0%dX" if zeropad else " %%%dX") % (wordsize * 2)) % w)
|
| 575 |
theseven |
301 |
else: sys.stdout.write(" " * (wordsize * 2 + 1))
|
|
|
302 |
if ascii:
|
|
|
303 |
sys.stdout.write(" |")
|
|
|
304 |
for i in range(r, r + wordsize * width):
|
|
|
305 |
if i - r > 0 and (i - r) % asciisep == 0: sys.stdout.write(" ")
|
|
|
306 |
if i >= 0 and i < size:
|
| 851 |
theseven |
307 |
if ord(data[i : i + 1]) > 0x1f and ord(data[i : i + 1]) < 0x80:
|
|
|
308 |
sys.stdout.write(data[i : i + 1].decode("latin1"))
|
| 578 |
theseven |
309 |
else: sys.stdout.write(asciirep)
|
| 575 |
theseven |
310 |
else: sys.stdout.write(" ")
|
|
|
311 |
sys.stdout.write("|")
|
|
|
312 |
sys.stdout.write("\n")
|
|
|
313 |
|
|
|
314 |
@command
|
| 774 |
theseven |
315 |
def uploadbyte(self, addr, byte):
|
|
|
316 |
"""
|
|
|
317 |
Uploads a single byte to the device
|
|
|
318 |
<addr>: the address to upload the byte to
|
|
|
319 |
<byte>: the byte to upload
|
|
|
320 |
"""
|
|
|
321 |
addr = to_int(addr)
|
|
|
322 |
byte = to_int(byte)
|
|
|
323 |
if byte > 0xFF:
|
|
|
324 |
raise ArgumentError("Specified integer too long")
|
|
|
325 |
data = struct.pack("B", byte)
|
|
|
326 |
self.emcore.write(addr, data)
|
|
|
327 |
self.logger.info("Byte '0x%X' written successfully to 0x%X\n" % (byte, addr))
|
|
|
328 |
|
|
|
329 |
@command
|
|
|
330 |
def downloadbyte(self, addr):
|
|
|
331 |
"""
|
|
|
332 |
Downloads a single byte from the device and prints it to the console window
|
|
|
333 |
<addr>: the address to download the byte from
|
|
|
334 |
"""
|
|
|
335 |
addr = to_int(addr)
|
|
|
336 |
data = self.emcore.read(addr, 1)
|
|
|
337 |
byte = struct.unpack("B", data)[0]
|
|
|
338 |
self.logger.info("Read '0x%X' from address 0x%X\n" % (byte, addr))
|
|
|
339 |
|
|
|
340 |
@command
|
| 171 |
farthen |
341 |
def uploadint(self, addr, integer):
|
|
|
342 |
"""
|
|
|
343 |
Uploads a single integer to the device
|
| 260 |
theseven |
344 |
<addr>: the address to upload the integer to
|
|
|
345 |
<integer>: the integer to upload
|
| 171 |
farthen |
346 |
"""
|
| 532 |
farthen |
347 |
addr = to_int(addr)
|
|
|
348 |
integer = to_int(integer)
|
| 171 |
farthen |
349 |
if integer > 0xFFFFFFFF:
|
|
|
350 |
raise ArgumentError("Specified integer too long")
|
| 548 |
farthen |
351 |
data = struct.pack("<I", integer)
|
| 427 |
farthen |
352 |
self.emcore.write(addr, data)
|
| 516 |
farthen |
353 |
self.logger.info("Integer '0x%X' written successfully to 0x%X\n" % (integer, addr))
|
| 517 |
farthen |
354 |
|
| 171 |
farthen |
355 |
@command
|
|
|
356 |
def downloadint(self, addr):
|
|
|
357 |
"""
|
|
|
358 |
Downloads a single integer from the device and prints it to the console window
|
| 236 |
farthen |
359 |
<addr>: the address to download the integer from
|
| 171 |
farthen |
360 |
"""
|
| 532 |
farthen |
361 |
addr = to_int(addr)
|
| 427 |
farthen |
362 |
data = self.emcore.read(addr, 4)
|
| 548 |
farthen |
363 |
integer = struct.unpack("<I", data)[0]
|
| 516 |
farthen |
364 |
self.logger.info("Read '0x%X' from address 0x%X\n" % (integer, addr))
|
| 517 |
farthen |
365 |
|
| 171 |
farthen |
366 |
@command
|
| 176 |
farthen |
367 |
def i2cread(self, bus, slave, addr, size):
|
| 171 |
farthen |
368 |
"""
|
|
|
369 |
Reads data from an I2C device
|
| 402 |
farthen |
370 |
<bus>: the bus index
|
|
|
371 |
<slave>: the slave address
|
|
|
372 |
<addr>: the start address on the I2C device
|
|
|
373 |
<size>: the number of bytes to read
|
| 171 |
farthen |
374 |
"""
|
| 532 |
farthen |
375 |
bus = to_int(bus)
|
|
|
376 |
slave = to_int(slave)
|
|
|
377 |
addr = to_int(addr)
|
|
|
378 |
size = to_int(size)
|
| 427 |
farthen |
379 |
data = self.emcore.i2cread(bus, slave, addr, size)
|
| 548 |
farthen |
380 |
bytes = struct.unpack("<%dB" % len(data), data)
|
| 236 |
farthen |
381 |
self.logger.info("Data read from I2C:\n")
|
|
|
382 |
for index, byte in enumerate(bytes):
|
| 533 |
theseven |
383 |
self.logger.info("%02X: %02X\n" % (addr + index, byte))
|
| 517 |
farthen |
384 |
|
| 171 |
farthen |
385 |
@command
|
| 176 |
farthen |
386 |
def i2cwrite(self, bus, slave, addr, *args):
|
| 171 |
farthen |
387 |
"""
|
|
|
388 |
Writes data to an I2C device
|
| 402 |
farthen |
389 |
<bus>: the bus index
|
|
|
390 |
<slave>: the slave address
|
|
|
391 |
<addr>: the start address on the I2C device
|
| 532 |
farthen |
392 |
<db1> ... <dbN>: the data in single bytes,
|
| 236 |
farthen |
393 |
seperated by whitespaces, eg. 37 5A 4F EB
|
| 171 |
farthen |
394 |
"""
|
| 532 |
farthen |
395 |
bus = to_int(bus)
|
|
|
396 |
slave = to_int(slave)
|
|
|
397 |
addr = to_int(addr)
|
| 937 |
theseven |
398 |
data = b""
|
| 171 |
farthen |
399 |
for arg in args:
|
| 938 |
theseven |
400 |
data += struct.pack("B", to_int(arg))
|
| 236 |
farthen |
401 |
self.logger.info("Writing data to I2C...\n")
|
| 427 |
farthen |
402 |
self.emcore.i2cwrite(bus, slave, addr, data)
|
| 236 |
farthen |
403 |
self.logger.info("done\n")
|
| 517 |
farthen |
404 |
|
| 171 |
farthen |
405 |
@command
|
| 176 |
farthen |
406 |
def console(self):
|
| 171 |
farthen |
407 |
"""
|
| 176 |
farthen |
408 |
Reads data from the USB console continuously
|
| 171 |
farthen |
409 |
"""
|
| 896 |
theseven |
410 |
size = 48
|
| 176 |
farthen |
411 |
while True:
|
| 896 |
theseven |
412 |
resp = self.emcore.usbcread(size)
|
| 599 |
farthen |
413 |
self.logger.write(resp.data, target = "stdout")
|
| 896 |
theseven |
414 |
size = max(48, min(len(resp.data), size) + resp.queuesize)
|
|
|
415 |
if size < 0x800:
|
|
|
416 |
time.sleep(0.1 / 0x800 * (0x800 - size))
|
| 517 |
farthen |
417 |
|
| 171 |
farthen |
418 |
@command
|
| 176 |
farthen |
419 |
def writeusbconsole(self, *args):
|
| 171 |
farthen |
420 |
"""
|
| 176 |
farthen |
421 |
Writes the string <db1> ... <dbN> to the USB console.
|
| 171 |
farthen |
422 |
"""
|
| 176 |
farthen |
423 |
text = ""
|
|
|
424 |
for word in args:
|
|
|
425 |
text += word + " "
|
|
|
426 |
text = text[:-1]
|
| 516 |
farthen |
427 |
self.logger.info("Writing '%s' to the usb console\n" % text)
|
| 427 |
farthen |
428 |
self.emcore.usbcwrite(text)
|
| 517 |
farthen |
429 |
|
| 171 |
farthen |
430 |
@command
|
| 176 |
farthen |
431 |
def readdevconsole(self, bitmask):
|
| 171 |
farthen |
432 |
"""
|
| 176 |
farthen |
433 |
Reads data continuously from one or more of the device's consoles.
|
|
|
434 |
<bitmask>: the bitmask of the consoles to read from.
|
| 171 |
farthen |
435 |
"""
|
| 532 |
farthen |
436 |
bitmask = to_int(bitmask)
|
| 176 |
farthen |
437 |
while True:
|
| 427 |
farthen |
438 |
resp = self.emcore.cread()
|
| 501 |
farthen |
439 |
self.logger.write(resp.data)
|
| 176 |
farthen |
440 |
time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
|
|
|
441 |
|
| 171 |
farthen |
442 |
@command
|
| 176 |
farthen |
443 |
def writedevconsole(self, bitmask, *args):
|
| 171 |
farthen |
444 |
"""
|
| 176 |
farthen |
445 |
Writes the string <db1> ... <dbN> to one or more of the device's consoles.
|
|
|
446 |
<bitmask>: the bitmask of the consoles to write to
|
| 171 |
farthen |
447 |
"""
|
| 532 |
farthen |
448 |
bitmask = to_int(bitmask)
|
| 176 |
farthen |
449 |
text = ""
|
|
|
450 |
for word in args:
|
|
|
451 |
text += word + " "
|
|
|
452 |
text = text[:-1]
|
| 516 |
farthen |
453 |
self.logger.info("Writing '%s' to the device consoles identified with 0x%X\n" % (text, bitmask))
|
| 427 |
farthen |
454 |
self.emcore.cwrite(text, bitmask)
|
| 517 |
farthen |
455 |
|
| 171 |
farthen |
456 |
@command
|
|
|
457 |
def flushconsolebuffers(self, bitmask):
|
|
|
458 |
"""
|
|
|
459 |
flushes one or more of the device consoles' buffers.
|
|
|
460 |
<bitmask>: the bitmask of the consoles to be flushed
|
|
|
461 |
"""
|
| 532 |
farthen |
462 |
bitmask = to_int(bitmask)
|
| 516 |
farthen |
463 |
self.logger.info("Flushing consoles identified with the bitmask 0x%X\n" % bitmask)
|
| 427 |
farthen |
464 |
self.emcore.cflush(bitmask)
|
| 517 |
farthen |
465 |
|
| 171 |
farthen |
466 |
@command
|
|
|
467 |
def getprocinfo(self):
|
|
|
468 |
"""
|
|
|
469 |
Fetches data on the currently running processes
|
|
|
470 |
"""
|
| 173 |
farthen |
471 |
import datetime
|
| 427 |
farthen |
472 |
threads = self.emcore.getprocinfo()
|
| 382 |
farthen |
473 |
threadload = 0
|
|
|
474 |
idleload = 0
|
| 173 |
farthen |
475 |
for thread in threads:
|
| 392 |
theseven |
476 |
if thread.id != 0:
|
|
|
477 |
threadload += thread.cpuload / 255.
|
| 382 |
farthen |
478 |
else:
|
| 392 |
theseven |
479 |
idleload += thread.cpuload / 255.
|
| 382 |
farthen |
480 |
coreload = 1 - (threadload + idleload)
|
|
|
481 |
cpuload = threadload + coreload
|
| 392 |
theseven |
482 |
self.logger.info("Threads: %d, CPU load: %.1f%%, kernel load: %.1f%%, user load: %.1f%%\n\n"
|
|
|
483 |
% (len(threads), cpuload * 100, coreload * 100, threadload * 100))
|
| 382 |
farthen |
484 |
self.logger.info("Thread dump:\n")
|
|
|
485 |
for thread in threads:
|
| 516 |
farthen |
486 |
self.logger.info("%s:\n" % thread.name, 2)
|
|
|
487 |
self.logger.info("Threadstruct address: 0x%X\n" % thread.addr, 4)
|
|
|
488 |
self.logger.info("Thread type: %s\n" % thread.thread_type, 4)
|
|
|
489 |
self.logger.info("Thread state: %s\n" % thread.state, 4)
|
| 605 |
farthen |
490 |
if thread.block_type != "THREAD_NOT_BLOCKED":
|
| 609 |
farthen |
491 |
self.logger.info("Block type: %s\n" % thread.block_type, 4)
|
|
|
492 |
if thread.block_type == "THREAD_BLOCK_MUTEX":
|
|
|
493 |
self.logger.info("Blocked by mutex: 0x%X\n" % thread.blocked_by, 6)
|
|
|
494 |
self.logger.info("Owner: %s (0x%X)\n" % (thread.blocked_by.owner.name, thread.blocked_by.owner), 8)
|
|
|
495 |
elif thread.block_type == "THREAD_BLOCK_WAKEUP":
|
|
|
496 |
self.logger.info("Blocked by wakeup: 0x%X\n" % thread.blocked_by, 6)
|
| 516 |
farthen |
497 |
self.logger.info("Priority: %d/255\n" % thread.priority, 4)
|
| 396 |
farthen |
498 |
self.logger.info("Current CPU load: %.1f%%\n" % ((thread.cpuload * 100) / 255.), 4)
|
| 516 |
farthen |
499 |
self.logger.info("CPU time (total): %s\n" % datetime.timedelta(microseconds = thread.cputime_total), 4)
|
|
|
500 |
self.logger.info("Stack address: 0x%X\n" % thread.stack, 4)
|
| 396 |
farthen |
501 |
self.logger.info("Registers:\n", 4)
|
| 177 |
farthen |
502 |
for registerrange in range(4):
|
|
|
503 |
for register in range(registerrange, 16, 4):
|
|
|
504 |
registerrepr = "r"+str(register)
|
| 606 |
farthen |
505 |
self.logger.info("{0:>3s}: 0x{1:08X} ".format(registerrepr, thread.regs[register]), 5)
|
| 177 |
farthen |
506 |
self.logger.info("\n")
|
| 506 |
farthen |
507 |
self.logger.info("cpsr: 0x{0:08X}".format(thread.cpsr), 6)
|
| 173 |
farthen |
508 |
self.logger.info("\n")
|
|
|
509 |
|
| 171 |
farthen |
510 |
@command
|
|
|
511 |
def lockscheduler(self):
|
|
|
512 |
"""
|
|
|
513 |
Locks (freezes) the scheduler
|
|
|
514 |
"""
|
| 176 |
farthen |
515 |
self.logger.info("Will now lock scheduler\n")
|
| 427 |
farthen |
516 |
self.emcore.lockscheduler()
|
| 178 |
farthen |
517 |
|
| 171 |
farthen |
518 |
@command
|
|
|
519 |
def unlockscheduler(self):
|
|
|
520 |
"""
|
|
|
521 |
Unlocks (unfreezes) the scheduler
|
|
|
522 |
"""
|
| 176 |
farthen |
523 |
self.logger.info("Will now unlock scheduler\n")
|
| 427 |
farthen |
524 |
self.emcore.unlockscheduler()
|
| 178 |
farthen |
525 |
|
| 171 |
farthen |
526 |
@command
|
| 516 |
farthen |
527 |
def suspendthread(self, threadaddr):
|
| 171 |
farthen |
528 |
"""
|
| 516 |
farthen |
529 |
Suspends the thread with the thread address <threadaddr>
|
| 171 |
farthen |
530 |
"""
|
| 532 |
farthen |
531 |
threadaddr = to_int(threadaddr)
|
| 516 |
farthen |
532 |
self.logger.info("Suspending the thread with the threadaddr 0x%X\n" % threadaddr)
|
|
|
533 |
self.emcore.suspendthread(threadaddr)
|
| 517 |
farthen |
534 |
|
| 171 |
farthen |
535 |
@command
|
| 516 |
farthen |
536 |
def resumethread(self, threadaddr):
|
| 171 |
farthen |
537 |
"""
|
| 516 |
farthen |
538 |
Resumes the thread with the thread address <threadaddr>
|
| 171 |
farthen |
539 |
"""
|
| 532 |
farthen |
540 |
threadaddr = to_int(threadaddr)
|
| 516 |
farthen |
541 |
self.logger.info("Resuming the thread with the threadaddr 0x%X\n" % threadaddr)
|
|
|
542 |
self.emcore.resumethread(threadaddr)
|
| 517 |
farthen |
543 |
|
| 171 |
farthen |
544 |
@command
|
| 516 |
farthen |
545 |
def killthread(self, threadaddr):
|
| 171 |
farthen |
546 |
"""
|
| 516 |
farthen |
547 |
Kills the thread with the thread address <threadaddr>
|
| 171 |
farthen |
548 |
"""
|
| 532 |
farthen |
549 |
threadaddr = to_int(threadaddr)
|
| 516 |
farthen |
550 |
self.logger.info("Killing the thread with the threadaddr 0x%X\n" % threadaddr)
|
|
|
551 |
self.emcore.killthread(threadaddr)
|
| 517 |
farthen |
552 |
|
| 171 |
farthen |
553 |
@command
|
|
|
554 |
def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
|
|
|
555 |
"""
|
| 516 |
farthen |
556 |
Creates a new thread and returns its thread pointer
|
| 402 |
farthen |
557 |
<namepointer>: a pointer to the thread's name
|
|
|
558 |
<entrypoint>: a pointer to the entrypoint of the thread
|
|
|
559 |
<stackpointer>: a pointer to the stack of the thread
|
|
|
560 |
<stacksize>: the size of the thread's stack
|
| 516 |
farthen |
561 |
<threadtype>: the thread type, vaild are: 0 => user thread, 1 => system thread
|
| 402 |
farthen |
562 |
<priority>: the priority of the thread, from 1 to 255
|
|
|
563 |
<state>: the thread's initial state, valid are: 1 => ready, 0 => suspended
|
| 171 |
farthen |
564 |
"""
|
| 532 |
farthen |
565 |
nameptr = to_int(nameptr)
|
|
|
566 |
entrypoint = to_int(entrypoint)
|
|
|
567 |
stackptr = to_int(stackptr)
|
|
|
568 |
stacksize = to_int(stacksize)
|
|
|
569 |
priority = to_int(priority)
|
| 516 |
farthen |
570 |
data = self.emcore.createthread(nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state)
|
| 427 |
farthen |
571 |
name = self.emcore.readstring(nameptr)
|
| 516 |
farthen |
572 |
self.logger.info("Created a thread with the thread pointer 0x%X, the name \"%s\", the entrypoint at 0x%X," \
|
|
|
573 |
"the stack at 0x%X with a size of 0x%X and a priority of %d/255\n" %
|
|
|
574 |
(data.threadptr, name, entrypoint, stackptr, stacksize, priority))
|
| 172 |
farthen |
575 |
|
|
|
576 |
@command
|
|
|
577 |
def run(self, filename):
|
|
|
578 |
"""
|
| 427 |
farthen |
579 |
Uploads the emCORE application <filename> to
|
| 236 |
farthen |
580 |
the memory and executes it
|
| 172 |
farthen |
581 |
"""
|
| 236 |
farthen |
582 |
try:
|
|
|
583 |
f = open(filename, 'rb')
|
|
|
584 |
except IOError:
|
|
|
585 |
raise ArgumentError("File not readable. Does it exist?")
|
| 238 |
farthen |
586 |
with f:
|
| 427 |
farthen |
587 |
data = self.emcore.run(f.read())
|
| 516 |
farthen |
588 |
self.logger.info("Executed emCORE application as thread 0x%X\n" % data.thread)
|
| 517 |
farthen |
589 |
|
| 171 |
farthen |
590 |
@command
|
| 173 |
farthen |
591 |
def execimage(self, addr):
|
| 171 |
farthen |
592 |
"""
|
| 427 |
farthen |
593 |
Executes the emCORE application at <addr>.
|
| 171 |
farthen |
594 |
"""
|
| 532 |
farthen |
595 |
addr = to_int(addr)
|
| 516 |
farthen |
596 |
self.logger.info("Starting emCORE app at 0x%X\n" % addr)
|
| 427 |
farthen |
597 |
self.emcore.execimage(addr)
|
| 176 |
farthen |
598 |
|
| 171 |
farthen |
599 |
@command
|
| 176 |
farthen |
600 |
def flushcaches(self):
|
| 171 |
farthen |
601 |
"""
|
| 176 |
farthen |
602 |
Flushes the CPUs data and instruction caches.
|
|
|
603 |
"""
|
|
|
604 |
self.logger.info("Flushing CPU data and instruction caches...")
|
| 427 |
farthen |
605 |
self.emcore.flushcaches()
|
| 176 |
farthen |
606 |
self.logger.info("done\n")
|
|
|
607 |
|
|
|
608 |
@command
|
|
|
609 |
def readbootflash(self, addr_flash, addr_mem, size):
|
|
|
610 |
"""
|
| 171 |
farthen |
611 |
Reads <size> bytes from bootflash to memory.
|
|
|
612 |
<addr_bootflsh>: the address in bootflash to read from
|
|
|
613 |
<addr_mem>: the address in memory to copy the data to
|
|
|
614 |
"""
|
| 532 |
farthen |
615 |
addr_flash = to_int(addr_flash)
|
|
|
616 |
addr_mem = to_int(addr_mem)
|
|
|
617 |
size = to_int(size)
|
| 516 |
farthen |
618 |
self.logger.info("Dumping boot flash from 0x%X - 0x%X to 0x%X - 0x%X\n" %
|
|
|
619 |
(addr_flash, addr_flash + size, addr_mem, addr_mem + size))
|
| 427 |
farthen |
620 |
self.emcore.bootflashread(addr_mem, addr_flash, size)
|
| 176 |
farthen |
621 |
|
| 171 |
farthen |
622 |
@command
|
| 176 |
farthen |
623 |
def writebootflash(self, addr_flash, addr_mem, size, force=False):
|
| 171 |
farthen |
624 |
"""
|
|
|
625 |
Writes <size> bytes from memory to bootflash.
|
|
|
626 |
ATTENTION: Don't call this unless you really know what you're doing!
|
|
|
627 |
This may BRICK your device (unless it has a good recovery option)
|
|
|
628 |
<addr_mem>: the address in memory to copy the data from
|
|
|
629 |
<addr_bootflsh>: the address in bootflash to write to
|
| 775 |
theseven |
630 |
[force]: Use this flag to suppress the 10 seconds delay
|
| 171 |
farthen |
631 |
"""
|
| 532 |
farthen |
632 |
addr_flash = to_int(addr_flash)
|
|
|
633 |
addr_mem = to_int(addr_mem)
|
|
|
634 |
size = to_int(size)
|
|
|
635 |
force = to_bool(force)
|
| 516 |
farthen |
636 |
self.logger.warn("Writing boot flash from the memory in 0x%X - 0x%X to 0x%X - 0x%X\n" %
|
|
|
637 |
(addr_mem, addr_mem + size, addr_flash, addr_flash + size))
|
| 174 |
farthen |
638 |
if force == False:
|
| 382 |
farthen |
639 |
self.logger.warn("If this was not what you intended press Ctrl-C NOW")
|
| 176 |
farthen |
640 |
for i in range(10):
|
| 174 |
farthen |
641 |
self.logger.info(".")
|
|
|
642 |
time.sleep(1)
|
|
|
643 |
self.logger.info("\n")
|
| 427 |
farthen |
644 |
self.emcore.bootflashwrite(addr_mem, addr_flash, size)
|
| 176 |
farthen |
645 |
|
| 171 |
farthen |
646 |
@command
|
| 442 |
farthen |
647 |
def runfirmware(self, targetaddr, filename):
|
| 171 |
farthen |
648 |
"""
|
| 402 |
farthen |
649 |
Uploads the firmware in <filename>
|
| 442 |
farthen |
650 |
to an allocated buffer and executes it at <targetaddr>.
|
| 171 |
farthen |
651 |
"""
|
| 532 |
farthen |
652 |
targetaddr = to_int(targetaddr)
|
| 442 |
farthen |
653 |
addr, size = self.uploadfile(filename)
|
|
|
654 |
self.execfirmware(targetaddr, addr, size)
|
| 64 |
benedikt93 |
655 |
|
| 171 |
farthen |
656 |
@command
|
| 442 |
farthen |
657 |
def execfirmware(self, targetaddr, addr, size):
|
| 176 |
farthen |
658 |
"""
|
| 442 |
farthen |
659 |
Moves the firmware at <addr> with <size> to <targetaddr> and executes it
|
| 176 |
farthen |
660 |
"""
|
| 532 |
farthen |
661 |
targetaddr = to_int(targetaddr)
|
|
|
662 |
addr = to_int(addr)
|
| 536 |
farthen |
663 |
size = to_int(size)
|
|
|
664 |
self.logger.info("Running firmware at 0x%X. Bye.\n" % targetaddr)
|
| 442 |
farthen |
665 |
self.emcore.execfirmware(targetaddr, addr, size)
|
| 176 |
farthen |
666 |
|
|
|
667 |
@command
|
| 171 |
farthen |
668 |
def aesencrypt(self, addr, size, keyindex):
|
|
|
669 |
"""
|
| 172 |
farthen |
670 |
Encrypts a buffer using a hardware key
|
| 402 |
farthen |
671 |
<addr>: the starting address of the buffer
|
|
|
672 |
<size>: the size of the buffer
|
|
|
673 |
<keyindex>: the index of the key in the crypto unit
|
| 171 |
farthen |
674 |
"""
|
| 532 |
farthen |
675 |
addr = to_int(addr)
|
|
|
676 |
size = to_int(size)
|
|
|
677 |
keyindex = to_int(keyindex)
|
| 427 |
farthen |
678 |
self.emcore.aesencrypt(addr, size, keyindex)
|
| 82 |
benedikt93 |
679 |
|
| 171 |
farthen |
680 |
@command
|
|
|
681 |
def aesdecrypt(self, addr, size, keyindex):
|
|
|
682 |
"""
|
| 172 |
farthen |
683 |
Decrypts a buffer using a hardware key
|
| 402 |
farthen |
684 |
<addr>: the starting address of the buffer
|
|
|
685 |
<size>: the size of the buffer
|
|
|
686 |
<keyindex>: the index of the key in the crypto unit
|
| 171 |
farthen |
687 |
"""
|
| 532 |
farthen |
688 |
addr = to_int(addr)
|
|
|
689 |
size = to_int(size)
|
|
|
690 |
keyindex = to_int(keyindex)
|
| 427 |
farthen |
691 |
self.emcore.aesdecrypt(addr, size, keyindex)
|
| 172 |
farthen |
692 |
|
|
|
693 |
@command
|
|
|
694 |
def hmac_sha1(self, addr, size, destination):
|
|
|
695 |
"""
|
| 402 |
farthen |
696 |
Generates a HMAC-SHA1 hash of the buffer
|
|
|
697 |
<addr>: the starting address of the buffer
|
|
|
698 |
<size>: the size of the buffer
|
|
|
699 |
<destination>: the location where the key will be stored
|
| 172 |
farthen |
700 |
"""
|
| 532 |
farthen |
701 |
addr = to_int(addr)
|
|
|
702 |
size = to_int(size)
|
|
|
703 |
destination = to_int(destination)
|
| 172 |
farthen |
704 |
sha1size = 0x14
|
| 516 |
farthen |
705 |
self.logger.info("Generating hmac-sha1 hash from the buffer at 0x%X with the size 0x%X and saving it to 0x%X - 0x%X\n" %
|
|
|
706 |
(addr, size, destination, destination + sha1size))
|
| 427 |
farthen |
707 |
self.emcore.hmac_sha1(addr, size, destination)
|
| 172 |
farthen |
708 |
self.logger.info("done\n")
|
| 427 |
farthen |
709 |
data = self.emcore.read(destination, sha1size)
|
| 172 |
farthen |
710 |
hash = ord(data)
|
| 516 |
farthen |
711 |
self.logger.info("The generated hash is 0x%X\n" % hash)
|
| 517 |
farthen |
712 |
|
| 227 |
theseven |
713 |
@command
|
|
|
714 |
def ipodnano2g_getnandinfo(self):
|
|
|
715 |
"""
|
|
|
716 |
Target-specific function: ipodnano2g
|
|
|
717 |
Gathers some information about the NAND chip used
|
|
|
718 |
"""
|
| 427 |
farthen |
719 |
data = self.emcore.ipodnano2g_getnandinfo()
|
| 516 |
farthen |
720 |
self.logger.info("NAND chip type: 0x%X\n" % data["type"])
|
|
|
721 |
self.logger.info("Number of banks: %d\n" % data["banks"])
|
|
|
722 |
self.logger.info("Number of blocks: %d\n" % data["blocks"])
|
|
|
723 |
self.logger.info("Number of user blocks: %d\n" % data["userblocks"])
|
|
|
724 |
self.logger.info("Pages per block: %d\n" % data["pagesperblock"])
|
| 517 |
farthen |
725 |
|
| 227 |
theseven |
726 |
@command
|
| 404 |
farthen |
727 |
def ipodnano2g_nandread(self, addr, start, count, doecc=True, checkempty=True):
|
| 227 |
theseven |
728 |
"""
|
|
|
729 |
Target-specific function: ipodnano2g
|
|
|
730 |
Reads data from the NAND chip into memory
|
| 402 |
farthen |
731 |
<addr>: the memory location where the data is written to
|
|
|
732 |
<start>: start block
|
|
|
733 |
<count>: block count
|
| 404 |
farthen |
734 |
[doecc]: use ecc error correction data
|
|
|
735 |
[checkempty]: set statusflags if pages are empty
|
| 227 |
theseven |
736 |
"""
|
| 532 |
farthen |
737 |
addr = to_int(addr)
|
|
|
738 |
start = to_int(start)
|
|
|
739 |
count = to_int(count)
|
|
|
740 |
doecc = to_bool(doecc)
|
|
|
741 |
checkempty = to_bool(checkempty)
|
| 516 |
farthen |
742 |
self.logger.info("Reading 0x%X NAND pages starting at 0x%X to memory at 0x%X..." %
|
|
|
743 |
(count, start, addr))
|
| 427 |
farthen |
744 |
self.emcore.ipodnano2g_nandread(addr, start, count, doecc, checkempty)
|
| 227 |
theseven |
745 |
self.logger.info("done\n")
|
| 517 |
farthen |
746 |
|
| 227 |
theseven |
747 |
@command
|
| 404 |
farthen |
748 |
def ipodnano2g_nandwrite(self, addr, start, count, doecc=True):
|
| 227 |
theseven |
749 |
"""
|
|
|
750 |
Target-specific function: ipodnano2g
|
|
|
751 |
Writes data to the NAND chip
|
| 402 |
farthen |
752 |
<addr>: the memory location where the data is read from
|
|
|
753 |
<start>: start block
|
|
|
754 |
<count>: block count
|
| 404 |
farthen |
755 |
[doecc]: create ecc error correction data
|
| 227 |
theseven |
756 |
"""
|
| 532 |
farthen |
757 |
addr = to_int(addr)
|
|
|
758 |
start = to_int(start)
|
|
|
759 |
count = to_int(count)
|
|
|
760 |
doecc = to_bool(doecc)
|
| 516 |
farthen |
761 |
self.logger.info("Writing 0x%X NAND pages starting at 0x%X from memory at 0x%X..." %
|
|
|
762 |
(count, start, addr))
|
| 427 |
farthen |
763 |
self.emcore.ipodnano2g_nandwrite(addr, start, count, doecc)
|
| 227 |
theseven |
764 |
self.logger.info("done\n")
|
| 517 |
farthen |
765 |
|
| 227 |
theseven |
766 |
@command
|
|
|
767 |
def ipodnano2g_nanderase(self, addr, start, count):
|
|
|
768 |
"""
|
|
|
769 |
Target-specific function: ipodnano2g
|
|
|
770 |
Erases blocks on the NAND chip and stores the results to memory
|
| 402 |
farthen |
771 |
<addr>: the memory location where the results are stored
|
|
|
772 |
<start>: start block
|
|
|
773 |
<count>: block count
|
| 227 |
theseven |
774 |
"""
|
| 532 |
farthen |
775 |
addr = to_int(addr)
|
|
|
776 |
start = to_int(start)
|
|
|
777 |
count = to_int(count)
|
| 516 |
farthen |
778 |
self.logger.info("Erasing 0x%X NAND pages starting at 0x%X and logging to 0x%X..." %
|
|
|
779 |
(count, start, addr))
|
| 427 |
farthen |
780 |
self.emcore.ipodnano2g_nanderase(addr, start, count)
|
| 227 |
theseven |
781 |
self.logger.info("done\n")
|
| 517 |
farthen |
782 |
|
| 228 |
theseven |
783 |
@command
|
|
|
784 |
def ipodnano2g_dumpnand(self, filenameprefix):
|
|
|
785 |
"""
|
|
|
786 |
Target-specific function: ipodnano2g
|
|
|
787 |
Dumps the whole NAND chip to four files
|
| 402 |
farthen |
788 |
<filenameprefix>: prefix of the files that will be created
|
| 228 |
theseven |
789 |
"""
|
| 427 |
farthen |
790 |
info = self.emcore.ipodnano2g_getnandinfo()
|
| 228 |
theseven |
791 |
try:
|
| 775 |
theseven |
792 |
buf = self.emcore.memalign(0x10, 0x1088000)
|
|
|
793 |
self.logger.info("Dumping NAND contents...")
|
|
|
794 |
try:
|
|
|
795 |
infofile = open(filenameprefix+"_info.txt", 'wb')
|
|
|
796 |
datafile = open(filenameprefix+"_data.bin", 'wb')
|
|
|
797 |
sparefile = open(filenameprefix+"_spare.bin", 'wb')
|
|
|
798 |
statusfile = open(filenameprefix+"_status.bin", 'wb')
|
|
|
799 |
except IOError:
|
|
|
800 |
raise ArgumentError("Can not open file for writing!")
|
|
|
801 |
infofile.write("NAND chip type: 0x%X\r\n" % info["type"])
|
|
|
802 |
infofile.write("Number of banks: %d\r\n" % info["banks"])
|
|
|
803 |
infofile.write("Number of blocks: %d\r\n" % info["blocks"])
|
|
|
804 |
infofile.write("Number of user blocks: %d\r\n" % info["userblocks"])
|
|
|
805 |
infofile.write("Pages per block: %d\r\n" % info["pagesperblock"])
|
|
|
806 |
for i in range(info["banks"] * info["blocks"] * info["pagesperblock"] / 8192):
|
|
|
807 |
self.logger.info(".")
|
|
|
808 |
self.emcore.ipodnano2g_nandread(buf, i * 8192, 8192, 1, 1)
|
|
|
809 |
datafile.write(self.emcore.read(buf, 0x01000000))
|
|
|
810 |
sparefile.write(self.emcore.read(buf + 0x01000000, 0x00080000))
|
|
|
811 |
statusfile.write(self.emcore.read(buf + 0x01080000, 0x00008000))
|
|
|
812 |
infofile.close()
|
|
|
813 |
datafile.close()
|
|
|
814 |
sparefile.close()
|
|
|
815 |
statusfile.close()
|
|
|
816 |
self.logger.info("done\n")
|
|
|
817 |
finally:
|
|
|
818 |
self.emcore.free(buf)
|
|
|
819 |
|
|
|
820 |
@command
|
|
|
821 |
def ipodnano2g_restorenand(self, filenameprefix, force=False):
|
|
|
822 |
"""
|
|
|
823 |
Target-specific function: ipodnano2g
|
|
|
824 |
Restores the whole NAND chip from <filenameprefix>_data.bin and <filenameprefix>_spare.bin
|
|
|
825 |
[force]: use this flag to suppress the 10 seconds delay
|
|
|
826 |
"""
|
|
|
827 |
self.logger.warn("Flashing NAND image %s!\n" % filenameprefix)
|
|
|
828 |
if force == False:
|
|
|
829 |
self.logger.warn("If this was not what you intended press Ctrl-C NOW")
|
|
|
830 |
for i in range(10):
|
|
|
831 |
self.logger.info(".")
|
|
|
832 |
time.sleep(1)
|
|
|
833 |
self.logger.info("\n\n")
|
|
|
834 |
info = self.emcore.ipodnano2g_getnandinfo()
|
|
|
835 |
ppb = info["pagesperblock"]
|
|
|
836 |
banks = info["banks"]
|
|
|
837 |
blocks = info["blocks"]
|
|
|
838 |
try:
|
|
|
839 |
if (os.path.getsize(filenameprefix+"_data.bin") != blocks * banks * ppb * 2048):
|
|
|
840 |
raise ArgumentError("Data file size does not match flash size!")
|
|
|
841 |
if (os.path.getsize(filenameprefix+"_spare.bin") != blocks * banks * ppb * 64):
|
|
|
842 |
raise ArgumentError("Spare file size does not match flash size!")
|
|
|
843 |
datafile = open(filenameprefix+"_data.bin", 'rb')
|
|
|
844 |
sparefile = open(filenameprefix+"_spare.bin", 'rb')
|
| 228 |
theseven |
845 |
except IOError:
|
| 775 |
theseven |
846 |
raise ArgumentError("Can not open input files!")
|
|
|
847 |
try:
|
| 776 |
theseven |
848 |
buf = self.emcore.memalign(0x10, 0x844)
|
| 775 |
theseven |
849 |
for block in range(info["blocks"]):
|
|
|
850 |
for bank in range(info["banks"]):
|
| 776 |
theseven |
851 |
self.logger.info("\r Erasing block %d bank %d " % (block, bank))
|
| 775 |
theseven |
852 |
self.emcore.ipodnano2g_nanderase(buf, block * banks + bank, 1)
|
|
|
853 |
rc = struct.unpack("<I", self.emcore.read(buf, 4))[0]
|
|
|
854 |
if rc != 0: self.logger.info("\rBlock %d bank %d erase failed with RC %08X\n" % (block, bank, rc))
|
|
|
855 |
for page in range(ppb):
|
| 776 |
theseven |
856 |
for bank in range(banks):
|
|
|
857 |
data = datafile.read(2048) + sparefile.read(64)
|
|
|
858 |
if data == "\xff" * 2112: continue
|
|
|
859 |
self.emcore.write(buf, data)
|
|
|
860 |
self.logger.info("\rProgramming block %d page %d bank %d" % (block, page, bank))
|
|
|
861 |
self.emcore.ipodnano2g_nandwrite(buf, ((block * ppb) + page) * banks + bank, 1, 0)
|
|
|
862 |
rc = struct.unpack("<I", self.emcore.read(buf + 2112, 4))[0]
|
|
|
863 |
if rc != 0: self.logger.info("\rBlock %d bank %d page %d programming failed with RC %08X\n" % (block, bank, page, rc))
|
| 775 |
theseven |
864 |
finally:
|
|
|
865 |
self.emcore.free(buf)
|
| 228 |
theseven |
866 |
datafile.close()
|
|
|
867 |
sparefile.close()
|
| 776 |
theseven |
868 |
self.logger.info("\ndone\n")
|
| 517 |
farthen |
869 |
|
| 228 |
theseven |
870 |
@command
|
|
|
871 |
def ipodnano2g_wipenand(self, filename, force=False):
|
|
|
872 |
"""
|
|
|
873 |
Target-specific function: ipodnano2g
|
|
|
874 |
Wipes the whole NAND chip and logs the result to a file
|
| 402 |
farthen |
875 |
<filename>: location of the log file
|
| 775 |
theseven |
876 |
[force]: use this flag to suppress the 10 seconds delay
|
| 228 |
theseven |
877 |
"""
|
| 382 |
farthen |
878 |
self.logger.warn("Wiping the whole NAND chip!\n")
|
| 228 |
theseven |
879 |
if force == False:
|
| 382 |
farthen |
880 |
self.logger.warn("If this was not what you intended press Ctrl-C NOW")
|
| 228 |
theseven |
881 |
for i in range(10):
|
|
|
882 |
self.logger.info(".")
|
|
|
883 |
time.sleep(1)
|
|
|
884 |
self.logger.info("\n")
|
|
|
885 |
try:
|
| 775 |
theseven |
886 |
buf = self.emcore.malloc(0x100)
|
|
|
887 |
info = self.emcore.ipodnano2g_getnandinfo()
|
|
|
888 |
self.logger.info("Wiping NAND contents...")
|
|
|
889 |
try:
|
|
|
890 |
statusfile = open(filename, 'wb')
|
|
|
891 |
except IOError:
|
|
|
892 |
raise ArgumentError("Can not open file for writing!")
|
|
|
893 |
for i in range(info["banks"] * info["blocks"] / 64):
|
|
|
894 |
self.logger.info(".")
|
|
|
895 |
self.emcore.ipodnano2g_nanderase(buf, i * 64, 64)
|
|
|
896 |
statusfile.write(self.emcore.read(buf, 0x00000100))
|
|
|
897 |
statusfile.close()
|
|
|
898 |
self.logger.info("done\n")
|
|
|
899 |
finally:
|
|
|
900 |
self.emcore.free(buf)
|
| 517 |
farthen |
901 |
|
| 346 |
theseven |
902 |
@command
|
| 787 |
theseven |
903 |
def ipodclassic_readbbt(self, filename, tempaddr = None):
|
|
|
904 |
"""
|
|
|
905 |
Target-specific function: ipodclassic
|
|
|
906 |
Reads the bad block table from the hard disk to memory at <tempaddr>
|
|
|
907 |
(or an allocated block if not given) and writes it to <filename>
|
|
|
908 |
"""
|
|
|
909 |
tempaddr = to_int(tempaddr)
|
|
|
910 |
try:
|
|
|
911 |
f = open(filename, 'wb')
|
|
|
912 |
except IOError:
|
|
|
913 |
raise ArgumentError("File not writable.")
|
|
|
914 |
self.logger.info("Reading bad block table from disk...")
|
|
|
915 |
f.write(self.emcore.ipodclassic_readbbt(tempaddr))
|
|
|
916 |
f.close()
|
|
|
917 |
self.logger.info(" done\n")
|
|
|
918 |
|
|
|
919 |
@command
|
| 585 |
theseven |
920 |
def ipodclassic_writebbt(self, filename, tempaddr = None):
|
| 346 |
theseven |
921 |
"""
|
|
|
922 |
Target-specific function: ipodclassic
|
| 585 |
theseven |
923 |
Uploads the bad block table <filename> to memory at <tempaddr>
|
|
|
924 |
(or an allocated block if not given) and writes it to the hard disk
|
| 346 |
theseven |
925 |
"""
|
| 602 |
theseven |
926 |
tempaddr = to_int(tempaddr)
|
| 346 |
theseven |
927 |
try:
|
|
|
928 |
f = open(filename, 'rb')
|
|
|
929 |
except IOError:
|
|
|
930 |
raise ArgumentError("File not readable. Does it exist?")
|
|
|
931 |
self.logger.info("Writing bad block table to disk...")
|
| 427 |
farthen |
932 |
data = self.emcore.ipodclassic_writebbt(f.read(), tempaddr)
|
| 346 |
theseven |
933 |
f.close()
|
|
|
934 |
self.logger.info(" done\n")
|
| 517 |
farthen |
935 |
|
| 346 |
theseven |
936 |
@command
|
| 791 |
theseven |
937 |
def ipodclassic_disablebbt(self):
|
|
|
938 |
"""
|
|
|
939 |
Target-specific function: ipodclassic
|
|
|
940 |
Disables the hard disk bad block table, if present
|
|
|
941 |
"""
|
|
|
942 |
self.logger.info("Disabling hard disk BBT...")
|
|
|
943 |
data = self.emcore.ipodclassic_disablebbt()
|
|
|
944 |
self.logger.info(" done\n")
|
|
|
945 |
|
|
|
946 |
@command
|
|
|
947 |
def ipodclassic_reloadbbt(self):
|
|
|
948 |
"""
|
|
|
949 |
Target-specific function: ipodclassic
|
|
|
950 |
Reloads the hard disk bad block table, if present
|
|
|
951 |
"""
|
|
|
952 |
self.logger.info("Reloading hard disk BBT...")
|
|
|
953 |
data = self.emcore.ipodclassic_reloadbbt()
|
|
|
954 |
self.logger.info(" done\n")
|
|
|
955 |
|
|
|
956 |
@command
|
| 379 |
theseven |
957 |
def getvolumeinfo(self, volume):
|
|
|
958 |
"""
|
|
|
959 |
Gathers some information about a storage volume used
|
| 404 |
farthen |
960 |
<volume>: volume id
|
| 379 |
theseven |
961 |
"""
|
| 532 |
farthen |
962 |
volume = to_int(volume)
|
| 427 |
farthen |
963 |
data = self.emcore.storage_get_info(volume)
|
| 516 |
farthen |
964 |
self.logger.info("Sector size: %d\n" % data["sectorsize"])
|
|
|
965 |
self.logger.info("Number of sectors: %d\n" % data["numsectors"])
|
|
|
966 |
self.logger.info("Vendor: %s\n" % data["vendor"])
|
|
|
967 |
self.logger.info("Product: %s\n" % data["product"])
|
|
|
968 |
self.logger.info("Revision: %s\n" % data["revision"])
|
| 517 |
farthen |
969 |
|
| 379 |
theseven |
970 |
@command
|
|
|
971 |
def readrawstorage(self, volume, sector, count, addr):
|
|
|
972 |
"""
|
|
|
973 |
Reads <count> sectors starting at <sector> from storage <volume> to memory at <addr>.
|
|
|
974 |
"""
|
| 532 |
farthen |
975 |
volume = to_int(volume)
|
|
|
976 |
sector = to_int(sector)
|
|
|
977 |
count = to_int(count)
|
|
|
978 |
addr = to_int(addr)
|
| 379 |
theseven |
979 |
self.logger.info("Reading volume %s sectors %X - %X to %08X..." % (volume, sector, sector + count - 1, addr))
|
| 427 |
farthen |
980 |
self.emcore.storage_read_sectors_md(volume, sector, count, addr)
|
| 379 |
theseven |
981 |
self.logger.info("done\n")
|
| 517 |
farthen |
982 |
|
| 379 |
theseven |
983 |
@command
|
|
|
984 |
def writerawstorage(self, volume, sector, count, addr):
|
|
|
985 |
"""
|
|
|
986 |
Writes memory contents at <addr> to <count> sectors starting at <sector> on storage <volume>.
|
|
|
987 |
"""
|
| 532 |
farthen |
988 |
volume = to_int(volume)
|
|
|
989 |
sector = to_int(sector)
|
|
|
990 |
count = to_int(count)
|
|
|
991 |
addr = to_int(addr)
|
| 379 |
theseven |
992 |
self.logger.info("Writing %08X to volume %s sectors %X - %X..." % (addr, volume, sector, sector + count - 1))
|
| 427 |
farthen |
993 |
self.emcore.storage_write_sectors_md(volume, sector, count, addr)
|
| 379 |
theseven |
994 |
self.logger.info("done\n")
|
| 517 |
farthen |
995 |
|
| 379 |
theseven |
996 |
@command
|
| 475 |
farthen |
997 |
def readrawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
|
| 379 |
theseven |
998 |
"""
|
|
|
999 |
Reads <count> sectors starting at <sector> from storage <volume> to file <file>,
|
| 402 |
farthen |
1000 |
buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
|
| 379 |
theseven |
1001 |
"""
|
| 532 |
farthen |
1002 |
volume = to_int(volume)
|
|
|
1003 |
sector = to_int(sector)
|
|
|
1004 |
count = to_int(count)
|
|
|
1005 |
buffsize = to_int(buffsize)
|
| 379 |
theseven |
1006 |
try:
|
| 479 |
theseven |
1007 |
f = open(file, 'wb')
|
|
|
1008 |
except IOError:
|
|
|
1009 |
raise ArgumentError("Could not open local file for writing.")
|
|
|
1010 |
try:
|
| 482 |
theseven |
1011 |
storageinfo = self.emcore.storage_get_info(volume)
|
|
|
1012 |
buffsize = min(buffsize, storageinfo.sectorsize * count)
|
| 479 |
theseven |
1013 |
if buffer is None:
|
| 644 |
theseven |
1014 |
buffer = self.emcore.memalign(0x10, buffsize)
|
| 479 |
theseven |
1015 |
malloc = True
|
|
|
1016 |
else:
|
| 532 |
farthen |
1017 |
buffer = to_int(buffer)
|
| 479 |
theseven |
1018 |
malloc = False
|
| 472 |
farthen |
1019 |
try:
|
| 479 |
theseven |
1020 |
self.logger.info("Reading volume %s sectors %X - %X to %s..." % (volume, sector, sector + count - 1, file))
|
|
|
1021 |
while count > 0:
|
|
|
1022 |
sectors = min(count, int(buffsize / storageinfo.sectorsize))
|
| 792 |
theseven |
1023 |
self.emcore.storage_read_sectors_md(volume, sector, sectors, buffer)
|
| 479 |
theseven |
1024 |
f.write(self.emcore.read(buffer, storageinfo.sectorsize * sectors))
|
|
|
1025 |
sector = sector + sectors
|
|
|
1026 |
count = count - sectors
|
|
|
1027 |
finally:
|
|
|
1028 |
if malloc == True:
|
|
|
1029 |
self.emcore.free(buffer)
|
|
|
1030 |
finally:
|
| 472 |
farthen |
1031 |
f.close()
|
| 379 |
theseven |
1032 |
self.logger.info("done\n")
|
| 517 |
farthen |
1033 |
|
| 379 |
theseven |
1034 |
@command
|
| 475 |
farthen |
1035 |
def writerawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
|
| 379 |
theseven |
1036 |
"""
|
|
|
1037 |
Writes contents of <file> to <count> sectors starting at <sector> on storage <volume>,
|
| 402 |
farthen |
1038 |
buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
|
| 792 |
theseven |
1039 |
If <count> is -1, the number of sectors will be determined from the file size.
|
| 379 |
theseven |
1040 |
"""
|
| 532 |
farthen |
1041 |
volume = to_int(volume)
|
|
|
1042 |
sector = to_int(sector)
|
|
|
1043 |
count = to_int(count)
|
|
|
1044 |
buffsize = to_int(buffsize)
|
| 379 |
theseven |
1045 |
try:
|
| 479 |
theseven |
1046 |
f = open(file, 'rb')
|
|
|
1047 |
except IOError:
|
|
|
1048 |
raise ArgumentError("Could not open local file for reading.")
|
|
|
1049 |
try:
|
| 482 |
theseven |
1050 |
storageinfo = self.emcore.storage_get_info(volume)
|
| 792 |
theseven |
1051 |
if count == -1: count = int((os.path.getsize(file) + storageinfo.sectorsize - 1) / storageinfo.sectorsize)
|
| 482 |
theseven |
1052 |
buffsize = min(buffsize, storageinfo.sectorsize * count)
|
| 479 |
theseven |
1053 |
if buffer is None:
|
| 644 |
theseven |
1054 |
buffer = self.emcore.memalign(0x10, buffsize)
|
| 479 |
theseven |
1055 |
malloc = True
|
|
|
1056 |
else:
|
| 532 |
farthen |
1057 |
buffer = to_int(buffer)
|
| 479 |
theseven |
1058 |
malloc = False
|
| 472 |
farthen |
1059 |
try:
|
| 479 |
theseven |
1060 |
self.logger.info("Writing %s to volume %s sectors %X - %X..." % (file, volume, sector, sector + count - 1))
|
|
|
1061 |
while count > 0:
|
|
|
1062 |
sectors = min(count, int(buffsize / storageinfo.sectorsize))
|
|
|
1063 |
bytes = storageinfo.sectorsize * sectors
|
| 792 |
theseven |
1064 |
data = b""
|
|
|
1065 |
while len(data) < bytes:
|
|
|
1066 |
new = f.read(bytes - len(data))
|
|
|
1067 |
data = data + new
|
|
|
1068 |
if len(new) == 0: break
|
| 479 |
theseven |
1069 |
self.emcore.write(buffer, data)
|
| 792 |
theseven |
1070 |
self.emcore.storage_write_sectors_md(volume, sector, sectors, buffer)
|
| 479 |
theseven |
1071 |
sector = sector + sectors
|
|
|
1072 |
count = count - sectors
|
|
|
1073 |
finally:
|
|
|
1074 |
if malloc == True:
|
|
|
1075 |
self.emcore.free(buffer)
|
|
|
1076 |
finally:
|
| 472 |
farthen |
1077 |
f.close()
|
| 379 |
theseven |
1078 |
self.logger.info("done\n")
|
| 517 |
farthen |
1079 |
|
| 379 |
theseven |
1080 |
@command
|
| 346 |
theseven |
1081 |
def mkdir(self, dirname):
|
|
|
1082 |
"""
|
| 402 |
farthen |
1083 |
Creates a directory with the name <dirname>
|
| 346 |
theseven |
1084 |
"""
|
| 516 |
farthen |
1085 |
self.logger.info("Creating directory %s..." % dirname)
|
| 427 |
farthen |
1086 |
self.emcore.dir_create(dirname)
|
| 346 |
theseven |
1087 |
self.logger.info(" done\n")
|
| 517 |
farthen |
1088 |
|
| 346 |
theseven |
1089 |
@command
|
|
|
1090 |
def rmdir(self, dirname):
|
|
|
1091 |
"""
|
| 402 |
farthen |
1092 |
Removes an empty directory with the name <dirname>
|
| 346 |
theseven |
1093 |
"""
|
| 516 |
farthen |
1094 |
self.logger.info("Removing directory %s..." % dirname)
|
| 427 |
farthen |
1095 |
self.emcore.dir_remove(dirname)
|
| 346 |
theseven |
1096 |
self.logger.info(" done\n")
|
| 517 |
farthen |
1097 |
|
| 346 |
theseven |
1098 |
@command
|
| 349 |
theseven |
1099 |
def rm(self, filename):
|
| 346 |
theseven |
1100 |
"""
|
| 402 |
farthen |
1101 |
Removes a file with the name <filename>
|
| 346 |
theseven |
1102 |
"""
|
| 516 |
farthen |
1103 |
self.logger.info("Removing file %s..." % filename)
|
| 427 |
farthen |
1104 |
self.emcore.file_unlink(filename)
|
| 346 |
theseven |
1105 |
self.logger.info(" done\n")
|
| 517 |
farthen |
1106 |
|
| 346 |
theseven |
1107 |
@command
|
| 406 |
theseven |
1108 |
def rmtree(self, path):
|
|
|
1109 |
"""
|
|
|
1110 |
Recursively removes a folder
|
|
|
1111 |
<path>: the folder to be removed
|
|
|
1112 |
"""
|
| 427 |
farthen |
1113 |
handle = self.emcore.dir_open(path)
|
| 406 |
theseven |
1114 |
while True:
|
|
|
1115 |
try:
|
| 427 |
farthen |
1116 |
entry = self.emcore.dir_read(handle)
|
| 406 |
theseven |
1117 |
if entry.name == "." or entry.name == "..": continue
|
|
|
1118 |
elif entry.attributes & 0x10:
|
|
|
1119 |
self.rmtree(path + "/" + entry.name)
|
|
|
1120 |
else: self.rm(path + "/" + entry.name)
|
|
|
1121 |
except: break
|
| 427 |
farthen |
1122 |
self.emcore.dir_close(handle)
|
| 406 |
theseven |
1123 |
self.rmdir(path)
|
| 517 |
farthen |
1124 |
|
| 406 |
theseven |
1125 |
@command
|
| 352 |
theseven |
1126 |
def mv(self, oldname, newname):
|
| 350 |
theseven |
1127 |
"""
|
| 402 |
farthen |
1128 |
Renames or moves file or directory <oldname> to <newname>
|
| 350 |
theseven |
1129 |
"""
|
| 516 |
farthen |
1130 |
self.logger.info("Renaming %s to %s..." % (oldname, newname))
|
| 427 |
farthen |
1131 |
self.emcore.file_rename(oldname, newname)
|
| 350 |
theseven |
1132 |
self.logger.info(" done\n")
|
| 517 |
farthen |
1133 |
|
| 350 |
theseven |
1134 |
@command
|
| 475 |
farthen |
1135 |
def get(self, remotename, localname, buffsize = 0x10000, buffer = None):
|
| 346 |
theseven |
1136 |
"""
|
|
|
1137 |
Downloads a file
|
| 402 |
farthen |
1138 |
<remotename>: filename on the device
|
|
|
1139 |
<localname>: filename on the computer
|
| 472 |
farthen |
1140 |
[buffsize]: buffer size (optional)
|
| 402 |
farthen |
1141 |
[buffer]: buffer address (optional)
|
| 346 |
theseven |
1142 |
"""
|
| 532 |
farthen |
1143 |
buffsize = to_int(buffsize)
|
| 346 |
theseven |
1144 |
try:
|
| 479 |
theseven |
1145 |
f = open(localname, 'wb')
|
|
|
1146 |
except IOError:
|
|
|
1147 |
raise ArgumentError("Could not open local file for writing.")
|
|
|
1148 |
try:
|
| 482 |
theseven |
1149 |
fd = self.emcore.file_open(remotename, 0)
|
| 472 |
farthen |
1150 |
try:
|
| 482 |
theseven |
1151 |
size = self.emcore.file_size(fd)
|
|
|
1152 |
buffsize = min(buffsize, size)
|
|
|
1153 |
if buffer is None:
|
| 644 |
theseven |
1154 |
buffer = self.emcore.memalign(0x10, buffsize)
|
| 482 |
theseven |
1155 |
malloc = True
|
|
|
1156 |
else:
|
| 532 |
farthen |
1157 |
buffer = to_int(buffer)
|
| 482 |
theseven |
1158 |
malloc = False
|
| 479 |
theseven |
1159 |
try:
|
| 516 |
farthen |
1160 |
self.logger.info("Downloading file %s to %s..." % (remotename, localname))
|
| 479 |
theseven |
1161 |
while size > 0:
|
| 488 |
theseven |
1162 |
bytes = self.emcore.file_read(fd, buffsize, buffer).rc
|
| 479 |
theseven |
1163 |
f.write(self.emcore.read(buffer, bytes))
|
|
|
1164 |
size = size - bytes
|
|
|
1165 |
finally:
|
| 482 |
theseven |
1166 |
if malloc == True:
|
|
|
1167 |
self.emcore.free(buffer)
|
| 479 |
theseven |
1168 |
finally:
|
| 482 |
theseven |
1169 |
self.emcore.file_close(fd)
|
| 479 |
theseven |
1170 |
finally:
|
| 472 |
farthen |
1171 |
f.close()
|
| 346 |
theseven |
1172 |
self.logger.info(" done\n")
|
| 517 |
farthen |
1173 |
|
| 346 |
theseven |
1174 |
@command
|
| 475 |
farthen |
1175 |
def gettree(self, remotepath, localpath, buffsize = 0x10000, buffer = None):
|
| 406 |
theseven |
1176 |
"""
|
|
|
1177 |
Downloads a directory tree
|
|
|
1178 |
<remotepath>: path on the device
|
|
|
1179 |
<localpath>: path on the computer
|
| 472 |
farthen |
1180 |
[buffsize]: buffer size (optional)
|
| 406 |
theseven |
1181 |
[buffer]: buffer address (optional)
|
|
|
1182 |
"""
|
| 532 |
farthen |
1183 |
buffsize = to_int(buffsize)
|
| 479 |
theseven |
1184 |
handle = self.emcore.dir_open(remotepath)
|
| 472 |
farthen |
1185 |
try:
|
| 479 |
theseven |
1186 |
if buffer is None:
|
| 644 |
theseven |
1187 |
buffer = self.emcore.memalign(0x10, buffsize)
|
| 479 |
theseven |
1188 |
malloc = True
|
|
|
1189 |
else:
|
| 532 |
farthen |
1190 |
buffer = to_int(buffer)
|
| 479 |
theseven |
1191 |
malloc = False
|
|
|
1192 |
try:
|
|
|
1193 |
try: os.mkdir(localpath)
|
|
|
1194 |
except: pass
|
|
|
1195 |
while True:
|
|
|
1196 |
try:
|
|
|
1197 |
entry = self.emcore.dir_read(handle)
|
|
|
1198 |
except: break
|
| 486 |
theseven |
1199 |
if entry.name == "." or entry.name == "..": continue
|
|
|
1200 |
elif entry.attributes & 0x10:
|
|
|
1201 |
self.gettree(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffsize, buffer)
|
|
|
1202 |
else: self.get(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffsize, buffer)
|
| 479 |
theseven |
1203 |
finally:
|
|
|
1204 |
if malloc == True:
|
|
|
1205 |
self.emcore.free(buffer)
|
|
|
1206 |
finally:
|
| 472 |
farthen |
1207 |
self.emcore.dir_close(handle)
|
| 517 |
farthen |
1208 |
|
| 406 |
theseven |
1209 |
@command
|
| 475 |
farthen |
1210 |
def put(self, localname, remotename, buffsize = 0x10000, buffer = None):
|
| 346 |
theseven |
1211 |
"""
|
|
|
1212 |
Uploads a file
|
| 406 |
theseven |
1213 |
<localname>: filename on the computer
|
| 402 |
farthen |
1214 |
<remotename>: filename on the device
|
| 472 |
farthen |
1215 |
[buffsize]: buffer size (optional)
|
| 402 |
farthen |
1216 |
[buffer]: buffer address (optional)
|
| 346 |
theseven |
1217 |
"""
|
| 532 |
farthen |
1218 |
buffsize = to_int(buffsize)
|
| 346 |
theseven |
1219 |
try:
|
| 479 |
theseven |
1220 |
f = open(localname, 'rb')
|
|
|
1221 |
except IOError:
|
|
|
1222 |
raise ArgumentError("Could not open local file for reading.")
|
|
|
1223 |
try:
|
| 482 |
theseven |
1224 |
buffsize = min(buffsize, os.path.getsize(localname))
|
| 479 |
theseven |
1225 |
if buffer is None:
|
| 644 |
theseven |
1226 |
buffer = self.emcore.memalign(0x10, buffsize)
|
| 479 |
theseven |
1227 |
malloc = True
|
|
|
1228 |
else:
|
| 532 |
farthen |
1229 |
buffer = to_int(buffer)
|
| 479 |
theseven |
1230 |
malloc = False
|
| 472 |
farthen |
1231 |
try:
|
| 516 |
farthen |
1232 |
self.logger.info("Uploading file %s to %s..." % (localname, remotename))
|
| 479 |
theseven |
1233 |
fd = self.emcore.file_open(remotename, 0x15)
|
|
|
1234 |
try:
|
|
|
1235 |
while True:
|
|
|
1236 |
data = f.read(buffsize)
|
|
|
1237 |
if len(data) == 0: break
|
|
|
1238 |
self.emcore.write(buffer, data)
|
|
|
1239 |
bytes = 0
|
|
|
1240 |
while bytes < len(data):
|
|
|
1241 |
bytes = bytes + self.emcore.file_write(fd, len(data) - bytes, buffer + bytes)
|
|
|
1242 |
finally:
|
|
|
1243 |
self.emcore.file_close(fd)
|
|
|
1244 |
finally:
|
|
|
1245 |
if malloc == True:
|
|
|
1246 |
self.emcore.free(buffer)
|
|
|
1247 |
finally:
|
| 472 |
farthen |
1248 |
f.close()
|
| 346 |
theseven |
1249 |
self.logger.info(" done\n")
|
| 517 |
farthen |
1250 |
|
| 346 |
theseven |
1251 |
@command
|
| 475 |
farthen |
1252 |
def puttree(self, localpath, remotepath, buffsize = 0x10000, buffer = None):
|
| 406 |
theseven |
1253 |
"""
|
|
|
1254 |
Uploads a directory tree
|
|
|
1255 |
<localpath>: path on the computer
|
|
|
1256 |
<remotepath>: path on the device
|
| 472 |
farthen |
1257 |
[buffsize]: buffer size (optional)
|
| 406 |
theseven |
1258 |
[buffer]: buffer address (optional)
|
|
|
1259 |
"""
|
| 532 |
farthen |
1260 |
buffsize = to_int(buffsize)
|
| 472 |
farthen |
1261 |
if buffer is None:
|
| 644 |
theseven |
1262 |
buffer = self.emcore.memalign(0x10, buffsize)
|
| 472 |
farthen |
1263 |
malloc = True
|
|
|
1264 |
else:
|
| 532 |
farthen |
1265 |
buffer = to_int(buffer)
|
| 472 |
farthen |
1266 |
malloc = False
|
|
|
1267 |
try:
|
|
|
1268 |
try: self.mkdir(remotepath)
|
|
|
1269 |
except: self.logger.info(" failed\n")
|
|
|
1270 |
pathlen = len(localpath)
|
|
|
1271 |
for d in os.walk(localpath):
|
|
|
1272 |
prefix = remotepath + "/" + d[0].replace("\\", "/")[pathlen:] + "/"
|
|
|
1273 |
for dir in d[1]:
|
|
|
1274 |
if dir != ".svn":
|
|
|
1275 |
try: self.mkdir(prefix + dir)
|
|
|
1276 |
except: self.logger.info(" failed\n")
|
|
|
1277 |
for f in d[2]:
|
| 479 |
theseven |
1278 |
if prefix.find("/.svn/") == -1:
|
| 477 |
farthen |
1279 |
self.put(d[0] + "/" + f, prefix + f, buffsize, buffer)
|
| 472 |
farthen |
1280 |
finally:
|
|
|
1281 |
if malloc == True:
|
|
|
1282 |
self.emcore.free(buffer)
|
| 517 |
farthen |
1283 |
|
| 406 |
theseven |
1284 |
@command
|
| 351 |
theseven |
1285 |
def ls(self, path = "/"):
|
| 346 |
theseven |
1286 |
"""
|
|
|
1287 |
Lists all files in the specified path
|
| 402 |
farthen |
1288 |
[path]: the path which is listed
|
| 346 |
theseven |
1289 |
"""
|
| 427 |
farthen |
1290 |
handle = self.emcore.dir_open(path)
|
| 516 |
farthen |
1291 |
self.logger.info("Directory listing of %s:\n" % path)
|
| 346 |
theseven |
1292 |
while True:
|
|
|
1293 |
try:
|
| 427 |
farthen |
1294 |
entry = self.emcore.dir_read(handle)
|
| 346 |
theseven |
1295 |
except: break
|
| 486 |
theseven |
1296 |
if entry.attributes & 0x10: size = "DIR"
|
|
|
1297 |
else: size = locale.format("%d", entry.size, True).rjust(13)
|
|
|
1298 |
self.logger.info(entry.name.ljust(50) + " - " + size + "\n")
|
| 427 |
farthen |
1299 |
self.emcore.dir_close(handle)
|
| 474 |
farthen |
1300 |
|
|
|
1301 |
@command
|
| 483 |
theseven |
1302 |
def find(self, path = "/"):
|
|
|
1303 |
"""
|
|
|
1304 |
Lists all files in the specified path, recursively
|
|
|
1305 |
[path]: the path which is listed
|
|
|
1306 |
"""
|
|
|
1307 |
handle = self.emcore.dir_open(path)
|
|
|
1308 |
self.logger.info(path + "/\n")
|
|
|
1309 |
while True:
|
|
|
1310 |
try:
|
|
|
1311 |
entry = self.emcore.dir_read(handle)
|
|
|
1312 |
except: break
|
| 486 |
theseven |
1313 |
if entry.name == "." or entry.name == "..": continue
|
|
|
1314 |
elif entry.attributes & 0x10: self.find(path + "/" + entry.name)
|
|
|
1315 |
else: self.logger.info(path + "/" + entry.name + "\n")
|
| 483 |
theseven |
1316 |
self.emcore.dir_close(handle)
|
|
|
1317 |
|
|
|
1318 |
@command
|
| 474 |
farthen |
1319 |
def malloc(self, size):
|
|
|
1320 |
""" Allocates <size> bytes and returns a pointer to the allocated memory """
|
| 532 |
farthen |
1321 |
size = to_int(size)
|
| 474 |
farthen |
1322 |
self.logger.info("Allocating %d bytes of memory\n" % size)
|
|
|
1323 |
addr = self.emcore.malloc(size)
|
| 518 |
farthen |
1324 |
self.logger.info("Allocated %d bytes of memory at 0x%X\n" % (size, addr))
|
| 474 |
farthen |
1325 |
|
|
|
1326 |
@command
|
|
|
1327 |
def memalign(self, align, size):
|
|
|
1328 |
""" Allocates <size> bytes aligned to <align> and returns a pointer to the allocated memory """
|
| 532 |
farthen |
1329 |
align = to_int(align)
|
|
|
1330 |
size = to_int(size)
|
| 518 |
farthen |
1331 |
self.logger.info("Allocating %d bytes of memory aligned to 0x%X\n" % (size, align))
|
| 474 |
farthen |
1332 |
addr = self.emcore.memalign(align, size)
|
| 518 |
farthen |
1333 |
self.logger.info("Allocated %d bytes of memory at 0x%X\n" % (size, addr))
|
| 474 |
farthen |
1334 |
|
|
|
1335 |
@command
|
|
|
1336 |
def realloc(self, ptr, size):
|
|
|
1337 |
""" The size of the memory block pointed to by <ptr> is changed to the <size> bytes,
|
|
|
1338 |
expanding or reducing the amount of memory available in the block.
|
|
|
1339 |
Returns a pointer to the reallocated memory.
|
|
|
1340 |
"""
|
| 532 |
farthen |
1341 |
ptr = to_int(ptr)
|
|
|
1342 |
size = to_int(size)
|
| 518 |
farthen |
1343 |
self.logger.info("Reallocating 0x%X to have the new size %d\n" % (ptr, size))
|
| 474 |
farthen |
1344 |
addr = self.emcore.realloc(ptr, size)
|
| 518 |
farthen |
1345 |
self.logger.info("Reallocated memory at 0x%X to 0x%X with the new size %d\n" % (ptr, addr, size))
|
| 474 |
farthen |
1346 |
|
|
|
1347 |
@command
|
|
|
1348 |
def reownalloc(self, ptr, owner):
|
|
|
1349 |
""" Changes the owner of the memory allocation <ptr> to the thread struct at addr <owner> """
|
| 532 |
farthen |
1350 |
ptr = to_int(ptr)
|
|
|
1351 |
owner = to_int(owner)
|
| 518 |
farthen |
1352 |
self.logger.info("Changing owner of the memory region 0x%X to 0x%X\n" % (ptr, owner))
|
| 474 |
farthen |
1353 |
self.emcore.reownalloc(ptr, owner)
|
| 518 |
farthen |
1354 |
self.logger.info("Successfully changed owner of 0x%X to 0x%X\n" % (ptr, owner))
|
| 474 |
farthen |
1355 |
|
|
|
1356 |
@command
|
|
|
1357 |
def free(self, ptr):
|
|
|
1358 |
""" Frees the memory space pointed to by 'ptr' """
|
| 532 |
farthen |
1359 |
ptr = to_int(ptr)
|
| 518 |
farthen |
1360 |
self.logger.info("Freeing the memory region at 0x%X\n" % ptr)
|
| 474 |
farthen |
1361 |
self.emcore.free(ptr)
|
| 518 |
farthen |
1362 |
self.logger.info("Successfully freed the memory region at 0x%X\n" % ptr)
|
| 474 |
farthen |
1363 |
|
|
|
1364 |
@command
|
|
|
1365 |
def free_all(self):
|
|
|
1366 |
""" Frees all memory allocations created by the monitor thread """
|
|
|
1367 |
self.logger.info("Freeing all memory allocations created by the monitor thread\n")
|
|
|
1368 |
self.emcore.free_all()
|
|
|
1369 |
self.logger.info("Successfully freed all memory allocations created by the monitor thread\n")
|
| 778 |
farthen |
1370 |
|
|
|
1371 |
@command
|
|
|
1372 |
def rtcread(self):
|
|
|
1373 |
""" Reads the real time clock on the device """
|
|
|
1374 |
import datetime
|
|
|
1375 |
self.logger.info("Reading the clock\n")
|
|
|
1376 |
dt = self.emcore.rtcread()
|
|
|
1377 |
self.logger.info("Successfully read the clock: %s\n" % (dt.ctime()))
|
|
|
1378 |
|
|
|
1379 |
@command
|
|
|
1380 |
def rtcwrite(self):
|
|
|
1381 |
""" Sets the real time clock on the device to the current local time """
|
|
|
1382 |
import datetime
|
|
|
1383 |
dt = datetime.datetime.now()
|
|
|
1384 |
self.logger.info("Setting the clock to: %s\n" % (dt.ctime()))
|
|
|
1385 |
self.emcore.rtcwrite(dt)
|
|
|
1386 |
self.logger.info("Successfully set the clock\n")
|
| 474 |
farthen |
1387 |
|
| 346 |
theseven |
1388 |
|
| 171 |
farthen |
1389 |
if __name__ == "__main__":
|
|
|
1390 |
if len(sys.argv) < 2:
|
| 502 |
farthen |
1391 |
usage("No command specified", docstring = False)
|
| 382 |
farthen |
1392 |
try:
|
|
|
1393 |
interface = Commandline()
|
|
|
1394 |
interface._parsecommand(sys.argv[1], sys.argv[2:])
|
|
|
1395 |
except KeyboardInterrupt:
|
| 778 |
farthen |
1396 |
sys.exit()
|