Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
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
427 farthen 144
            except libemcore.usb.core.USBError:
478 farthen 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)
176 farthen 398
        data = ""
171 farthen 399
        for arg in args:
532 farthen 400
            data += chr(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
        """
176 farthen 410
        while True:
427 farthen 411
            resp = self.emcore.usbcread()
599 farthen 412
            self.logger.write(resp.data, target = "stdout")
774 theseven 413
#            time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
517 farthen 414
 
171 farthen 415
    @command
176 farthen 416
    def writeusbconsole(self, *args):
171 farthen 417
        """
176 farthen 418
            Writes the string <db1> ... <dbN> to the USB console.
171 farthen 419
        """
176 farthen 420
        text = ""
421
        for word in args:
422
            text += word + " "
423
        text = text[:-1]
516 farthen 424
        self.logger.info("Writing '%s' to the usb console\n" % text)
427 farthen 425
        self.emcore.usbcwrite(text)
517 farthen 426
 
171 farthen 427
    @command
176 farthen 428
    def readdevconsole(self, bitmask):
171 farthen 429
        """
176 farthen 430
            Reads data continuously from one or more of the device's consoles.
431
            <bitmask>: the bitmask of the consoles to read from.
171 farthen 432
        """
532 farthen 433
        bitmask = to_int(bitmask)
176 farthen 434
        while True:
427 farthen 435
            resp = self.emcore.cread()
501 farthen 436
            self.logger.write(resp.data)
176 farthen 437
            time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
438
 
171 farthen 439
    @command
176 farthen 440
    def writedevconsole(self, bitmask, *args):
171 farthen 441
        """
176 farthen 442
            Writes the string <db1> ... <dbN> to one or more of the device's consoles.
443
            <bitmask>: the bitmask of the consoles to write to
171 farthen 444
        """
532 farthen 445
        bitmask = to_int(bitmask)
176 farthen 446
        text = ""
447
        for word in args:
448
            text += word + " "
449
        text = text[:-1]
516 farthen 450
        self.logger.info("Writing '%s' to the device consoles identified with 0x%X\n" % (text, bitmask))
427 farthen 451
        self.emcore.cwrite(text, bitmask)
517 farthen 452
 
171 farthen 453
    @command
454
    def flushconsolebuffers(self, bitmask):
455
        """
456
            flushes one or more of the device consoles' buffers.
457
            <bitmask>: the bitmask of the consoles to be flushed
458
        """
532 farthen 459
        bitmask = to_int(bitmask)
516 farthen 460
        self.logger.info("Flushing consoles identified with the bitmask 0x%X\n" % bitmask)
427 farthen 461
        self.emcore.cflush(bitmask)
517 farthen 462
 
171 farthen 463
    @command
464
    def getprocinfo(self):
465
        """
466
            Fetches data on the currently running processes
467
        """
173 farthen 468
        import datetime
427 farthen 469
        threads = self.emcore.getprocinfo()
382 farthen 470
        threadload = 0
471
        idleload = 0
173 farthen 472
        for thread in threads:
392 theseven 473
            if thread.id != 0:
474
                threadload += thread.cpuload / 255.
382 farthen 475
            else:
392 theseven 476
                idleload += thread.cpuload / 255.
382 farthen 477
        coreload = 1 - (threadload + idleload)
478
        cpuload = threadload + coreload
392 theseven 479
        self.logger.info("Threads: %d, CPU load: %.1f%%, kernel load: %.1f%%, user load: %.1f%%\n\n"
480
                         % (len(threads), cpuload * 100, coreload * 100, threadload * 100))
382 farthen 481
        self.logger.info("Thread dump:\n")
482
        for thread in threads:
516 farthen 483
            self.logger.info("%s:\n" % thread.name, 2)
484
            self.logger.info("Threadstruct address: 0x%X\n" % thread.addr, 4)
485
            self.logger.info("Thread type: %s\n" % thread.thread_type, 4)
486
            self.logger.info("Thread state: %s\n" % thread.state, 4)
605 farthen 487
            if thread.block_type != "THREAD_NOT_BLOCKED":
609 farthen 488
                self.logger.info("Block type: %s\n" % thread.block_type, 4)
489
                if thread.block_type == "THREAD_BLOCK_MUTEX":
490
                    self.logger.info("Blocked by mutex: 0x%X\n" % thread.blocked_by, 6)
491
                    self.logger.info("Owner: %s (0x%X)\n" % (thread.blocked_by.owner.name, thread.blocked_by.owner), 8)
492
                elif thread.block_type == "THREAD_BLOCK_WAKEUP":
493
                    self.logger.info("Blocked by wakeup: 0x%X\n" % thread.blocked_by, 6)
516 farthen 494
            self.logger.info("Priority: %d/255\n" % thread.priority, 4)
396 farthen 495
            self.logger.info("Current CPU load: %.1f%%\n" % ((thread.cpuload * 100) / 255.), 4)
516 farthen 496
            self.logger.info("CPU time (total): %s\n" % datetime.timedelta(microseconds = thread.cputime_total), 4)
497
            self.logger.info("Stack address: 0x%X\n" % thread.stack, 4)
396 farthen 498
            self.logger.info("Registers:\n", 4)
177 farthen 499
            for registerrange in range(4):
500
                for register in range(registerrange, 16, 4):
501
                    registerrepr = "r"+str(register)
606 farthen 502
                    self.logger.info("{0:>3s}: 0x{1:08X}   ".format(registerrepr, thread.regs[register]), 5)
177 farthen 503
                self.logger.info("\n")
506 farthen 504
            self.logger.info("cpsr: 0x{0:08X}".format(thread.cpsr), 6)
173 farthen 505
            self.logger.info("\n")
506
 
171 farthen 507
    @command
508
    def lockscheduler(self):
509
        """
510
            Locks (freezes) the scheduler
511
        """
176 farthen 512
        self.logger.info("Will now lock scheduler\n")
427 farthen 513
        self.emcore.lockscheduler()
178 farthen 514
 
171 farthen 515
    @command
516
    def unlockscheduler(self):
517
        """
518
            Unlocks (unfreezes) the scheduler
519
        """
176 farthen 520
        self.logger.info("Will now unlock scheduler\n")
427 farthen 521
        self.emcore.unlockscheduler()
178 farthen 522
 
171 farthen 523
    @command
516 farthen 524
    def suspendthread(self, threadaddr):
171 farthen 525
        """
516 farthen 526
            Suspends the thread with the thread address <threadaddr>
171 farthen 527
        """
532 farthen 528
        threadaddr = to_int(threadaddr)
516 farthen 529
        self.logger.info("Suspending the thread with the threadaddr 0x%X\n" % threadaddr)
530
        self.emcore.suspendthread(threadaddr)
517 farthen 531
 
171 farthen 532
    @command
516 farthen 533
    def resumethread(self, threadaddr):
171 farthen 534
        """
516 farthen 535
            Resumes the thread with the thread address <threadaddr>
171 farthen 536
        """
532 farthen 537
        threadaddr = to_int(threadaddr)
516 farthen 538
        self.logger.info("Resuming the thread with the threadaddr 0x%X\n" % threadaddr)
539
        self.emcore.resumethread(threadaddr)
517 farthen 540
 
171 farthen 541
    @command
516 farthen 542
    def killthread(self, threadaddr):
171 farthen 543
        """
516 farthen 544
            Kills the thread with the thread address <threadaddr>
171 farthen 545
        """
532 farthen 546
        threadaddr = to_int(threadaddr)
516 farthen 547
        self.logger.info("Killing the thread with the threadaddr 0x%X\n" % threadaddr)
548
        self.emcore.killthread(threadaddr)
517 farthen 549
 
171 farthen 550
    @command
551
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
552
        """
516 farthen 553
            Creates a new thread and returns its thread pointer
402 farthen 554
            <namepointer>: a pointer to the thread's name
555
            <entrypoint>: a pointer to the entrypoint of the thread
556
            <stackpointer>: a pointer to the stack of the thread
557
            <stacksize>: the size of the thread's stack
516 farthen 558
            <threadtype>: the thread type, vaild are: 0 => user thread, 1 => system thread
402 farthen 559
            <priority>: the priority of the thread, from 1 to 255
560
            <state>: the thread's initial state, valid are: 1 => ready, 0 => suspended
171 farthen 561
        """
532 farthen 562
        nameptr = to_int(nameptr)
563
        entrypoint = to_int(entrypoint)
564
        stackptr = to_int(stackptr)
565
        stacksize = to_int(stacksize)
566
        priority = to_int(priority)
516 farthen 567
        data = self.emcore.createthread(nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state)
427 farthen 568
        name = self.emcore.readstring(nameptr)
516 farthen 569
        self.logger.info("Created a thread with the thread pointer 0x%X, the name \"%s\", the entrypoint at 0x%X," \
570
                         "the stack at 0x%X with a size of 0x%X and a priority of %d/255\n" %
571
                        (data.threadptr, name, entrypoint, stackptr, stacksize, priority))
172 farthen 572
 
573
    @command
574
    def run(self, filename):
575
        """
427 farthen 576
            Uploads the emCORE application <filename> to
236 farthen 577
            the memory and executes it
172 farthen 578
        """
236 farthen 579
        try:
580
            f = open(filename, 'rb')
581
        except IOError:
582
            raise ArgumentError("File not readable. Does it exist?")
238 farthen 583
        with f:
427 farthen 584
            data = self.emcore.run(f.read())
516 farthen 585
        self.logger.info("Executed emCORE application as thread 0x%X\n" % data.thread)
517 farthen 586
 
171 farthen 587
    @command
173 farthen 588
    def execimage(self, addr):
171 farthen 589
        """
427 farthen 590
            Executes the emCORE application at <addr>.
171 farthen 591
        """
532 farthen 592
        addr = to_int(addr)
516 farthen 593
        self.logger.info("Starting emCORE app at 0x%X\n" % addr)
427 farthen 594
        self.emcore.execimage(addr)
176 farthen 595
 
171 farthen 596
    @command
176 farthen 597
    def flushcaches(self):
171 farthen 598
        """
176 farthen 599
            Flushes the CPUs data and instruction caches.
600
        """
601
        self.logger.info("Flushing CPU data and instruction caches...")
427 farthen 602
        self.emcore.flushcaches()
176 farthen 603
        self.logger.info("done\n")
604
 
605
    @command
606
    def readbootflash(self, addr_flash, addr_mem, size):
607
        """
171 farthen 608
            Reads <size> bytes from bootflash to memory.
609
            <addr_bootflsh>: the address in bootflash to read from
610
            <addr_mem>: the address in memory to copy the data to
611
        """
532 farthen 612
        addr_flash = to_int(addr_flash)
613
        addr_mem = to_int(addr_mem)
614
        size = to_int(size)
516 farthen 615
        self.logger.info("Dumping boot flash from 0x%X - 0x%X to 0x%X - 0x%X\n" %
616
                        (addr_flash, addr_flash + size, addr_mem, addr_mem + size))
427 farthen 617
        self.emcore.bootflashread(addr_mem, addr_flash, size)
176 farthen 618
 
171 farthen 619
    @command
176 farthen 620
    def writebootflash(self, addr_flash, addr_mem, size, force=False):
171 farthen 621
        """
622
            Writes <size> bytes from memory to bootflash.
623
            ATTENTION: Don't call this unless you really know what you're doing!
624
            This may BRICK your device (unless it has a good recovery option)
625
            <addr_mem>: the address in memory to copy the data from
626
            <addr_bootflsh>: the address in bootflash to write to
775 theseven 627
            [force]: Use this flag to suppress the 10 seconds delay
171 farthen 628
        """
532 farthen 629
        addr_flash = to_int(addr_flash)
630
        addr_mem = to_int(addr_mem)
631
        size = to_int(size)
632
        force = to_bool(force)
516 farthen 633
        self.logger.warn("Writing boot flash from the memory in 0x%X - 0x%X to 0x%X - 0x%X\n" %
634
                        (addr_mem, addr_mem + size, addr_flash, addr_flash + size))
174 farthen 635
        if force == False:
382 farthen 636
            self.logger.warn("If this was not what you intended press Ctrl-C NOW")
176 farthen 637
            for i in range(10):
174 farthen 638
                self.logger.info(".")
639
                time.sleep(1)
640
            self.logger.info("\n")
427 farthen 641
        self.emcore.bootflashwrite(addr_mem, addr_flash, size)
176 farthen 642
 
171 farthen 643
    @command
442 farthen 644
    def runfirmware(self, targetaddr, filename):
171 farthen 645
        """
402 farthen 646
            Uploads the firmware in <filename>
442 farthen 647
            to an allocated buffer and executes it at <targetaddr>.
171 farthen 648
        """
532 farthen 649
        targetaddr = to_int(targetaddr)
442 farthen 650
        addr, size = self.uploadfile(filename)
651
        self.execfirmware(targetaddr, addr, size)
64 benedikt93 652
 
171 farthen 653
    @command
442 farthen 654
    def execfirmware(self, targetaddr, addr, size):
176 farthen 655
        """
442 farthen 656
            Moves the firmware at <addr> with <size> to <targetaddr> and executes it
176 farthen 657
        """
532 farthen 658
        targetaddr = to_int(targetaddr)
659
        addr = to_int(addr)
536 farthen 660
        size = to_int(size)
661
        self.logger.info("Running firmware at 0x%X. Bye.\n" % targetaddr)
442 farthen 662
        self.emcore.execfirmware(targetaddr, addr, size)
176 farthen 663
 
664
    @command
171 farthen 665
    def aesencrypt(self, addr, size, keyindex):
666
        """
172 farthen 667
            Encrypts a buffer using a hardware key
402 farthen 668
            <addr>: the starting address of the buffer
669
            <size>: the size of the buffer
670
            <keyindex>: the index of the key in the crypto unit
171 farthen 671
        """
532 farthen 672
        addr = to_int(addr)
673
        size = to_int(size)
674
        keyindex = to_int(keyindex)
427 farthen 675
        self.emcore.aesencrypt(addr, size, keyindex)
82 benedikt93 676
 
171 farthen 677
    @command
678
    def aesdecrypt(self, addr, size, keyindex):
679
        """
172 farthen 680
            Decrypts a buffer using a hardware key
402 farthen 681
            <addr>: the starting address of the buffer
682
            <size>: the size of the buffer
683
            <keyindex>: the index of the key in the crypto unit
171 farthen 684
        """
532 farthen 685
        addr = to_int(addr)
686
        size = to_int(size)
687
        keyindex = to_int(keyindex)
427 farthen 688
        self.emcore.aesdecrypt(addr, size, keyindex)
172 farthen 689
 
690
    @command
691
    def hmac_sha1(self, addr, size, destination):
692
        """
402 farthen 693
            Generates a HMAC-SHA1 hash of the buffer
694
            <addr>: the starting address of the buffer
695
            <size>: the size of the buffer
696
            <destination>: the location where the key will be stored
172 farthen 697
        """
532 farthen 698
        addr = to_int(addr)
699
        size = to_int(size)
700
        destination = to_int(destination)
172 farthen 701
        sha1size = 0x14
516 farthen 702
        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" %
703
                        (addr, size, destination, destination + sha1size))
427 farthen 704
        self.emcore.hmac_sha1(addr, size, destination)
172 farthen 705
        self.logger.info("done\n")
427 farthen 706
        data = self.emcore.read(destination, sha1size)
172 farthen 707
        hash = ord(data)
516 farthen 708
        self.logger.info("The generated hash is 0x%X\n" % hash)
517 farthen 709
 
227 theseven 710
    @command
711
    def ipodnano2g_getnandinfo(self):
712
        """
713
            Target-specific function: ipodnano2g
714
            Gathers some information about the NAND chip used
715
        """
427 farthen 716
        data = self.emcore.ipodnano2g_getnandinfo()
516 farthen 717
        self.logger.info("NAND chip type: 0x%X\n" % data["type"])
718
        self.logger.info("Number of banks: %d\n" % data["banks"])
719
        self.logger.info("Number of blocks: %d\n" % data["blocks"])
720
        self.logger.info("Number of user blocks: %d\n" % data["userblocks"])
721
        self.logger.info("Pages per block: %d\n" % data["pagesperblock"])
517 farthen 722
 
227 theseven 723
    @command
404 farthen 724
    def ipodnano2g_nandread(self, addr, start, count, doecc=True, checkempty=True):
227 theseven 725
        """
726
            Target-specific function: ipodnano2g
727
            Reads data from the NAND chip into memory
402 farthen 728
            <addr>: the memory location where the data is written to
729
            <start>: start block
730
            <count>: block count
404 farthen 731
            [doecc]: use ecc error correction data
732
            [checkempty]: set statusflags if pages are empty
227 theseven 733
        """
532 farthen 734
        addr = to_int(addr)
735
        start = to_int(start)
736
        count = to_int(count)
737
        doecc = to_bool(doecc)
738
        checkempty = to_bool(checkempty)
516 farthen 739
        self.logger.info("Reading 0x%X NAND pages starting at 0x%X to memory at 0x%X..." %
740
                        (count, start, addr))
427 farthen 741
        self.emcore.ipodnano2g_nandread(addr, start, count, doecc, checkempty)
227 theseven 742
        self.logger.info("done\n")
517 farthen 743
 
227 theseven 744
    @command
404 farthen 745
    def ipodnano2g_nandwrite(self, addr, start, count, doecc=True):
227 theseven 746
        """
747
            Target-specific function: ipodnano2g
748
            Writes data to the NAND chip
402 farthen 749
            <addr>: the memory location where the data is read from
750
            <start>: start block
751
            <count>: block count
404 farthen 752
            [doecc]: create ecc error correction data
227 theseven 753
        """
532 farthen 754
        addr = to_int(addr)
755
        start = to_int(start)
756
        count = to_int(count)
757
        doecc = to_bool(doecc)
516 farthen 758
        self.logger.info("Writing 0x%X NAND pages starting at 0x%X from memory at 0x%X..." %
759
                        (count, start, addr))
427 farthen 760
        self.emcore.ipodnano2g_nandwrite(addr, start, count, doecc)
227 theseven 761
        self.logger.info("done\n")
517 farthen 762
 
227 theseven 763
    @command
764
    def ipodnano2g_nanderase(self, addr, start, count):
765
        """
766
            Target-specific function: ipodnano2g
767
            Erases blocks on the NAND chip and stores the results to memory
402 farthen 768
            <addr>: the memory location where the results are stored
769
            <start>: start block
770
            <count>: block count
227 theseven 771
        """
532 farthen 772
        addr = to_int(addr)
773
        start = to_int(start)
774
        count = to_int(count)
516 farthen 775
        self.logger.info("Erasing 0x%X NAND pages starting at 0x%X and logging to 0x%X..." %
776
                        (count, start, addr))
427 farthen 777
        self.emcore.ipodnano2g_nanderase(addr, start, count)
227 theseven 778
        self.logger.info("done\n")
517 farthen 779
 
228 theseven 780
    @command
781
    def ipodnano2g_dumpnand(self, filenameprefix):
782
        """
783
            Target-specific function: ipodnano2g
784
            Dumps the whole NAND chip to four files
402 farthen 785
            <filenameprefix>: prefix of the files that will be created
228 theseven 786
        """
427 farthen 787
        info = self.emcore.ipodnano2g_getnandinfo()
228 theseven 788
        try:
775 theseven 789
            buf = self.emcore.memalign(0x10, 0x1088000)
790
            self.logger.info("Dumping NAND contents...")
791
            try:
792
                infofile = open(filenameprefix+"_info.txt", 'wb')
793
                datafile = open(filenameprefix+"_data.bin", 'wb')
794
                sparefile = open(filenameprefix+"_spare.bin", 'wb')
795
                statusfile = open(filenameprefix+"_status.bin", 'wb')
796
            except IOError:
797
                raise ArgumentError("Can not open file for writing!")
798
            infofile.write("NAND chip type: 0x%X\r\n" % info["type"])
799
            infofile.write("Number of banks: %d\r\n" % info["banks"])
800
            infofile.write("Number of blocks: %d\r\n" % info["blocks"])
801
            infofile.write("Number of user blocks: %d\r\n" % info["userblocks"])
802
            infofile.write("Pages per block: %d\r\n" % info["pagesperblock"])
803
            for i in range(info["banks"] * info["blocks"] * info["pagesperblock"] / 8192):
804
                self.logger.info(".")
805
                self.emcore.ipodnano2g_nandread(buf, i * 8192, 8192, 1, 1)
806
                datafile.write(self.emcore.read(buf, 0x01000000))
807
                sparefile.write(self.emcore.read(buf + 0x01000000, 0x00080000))
808
                statusfile.write(self.emcore.read(buf + 0x01080000, 0x00008000))
809
            infofile.close()
810
            datafile.close()
811
            sparefile.close()
812
            statusfile.close()
813
            self.logger.info("done\n")
814
        finally:
815
            self.emcore.free(buf)
816
 
817
    @command
818
    def ipodnano2g_restorenand(self, filenameprefix, force=False):
819
        """
820
            Target-specific function: ipodnano2g
821
            Restores the whole NAND chip from <filenameprefix>_data.bin and <filenameprefix>_spare.bin
822
            [force]: use this flag to suppress the 10 seconds delay
823
        """
824
        self.logger.warn("Flashing NAND image %s!\n" % filenameprefix)
825
        if force == False:
826
            self.logger.warn("If this was not what you intended press Ctrl-C NOW")
827
            for i in range(10):
828
                self.logger.info(".")
829
                time.sleep(1)
830
            self.logger.info("\n\n")
831
        info = self.emcore.ipodnano2g_getnandinfo()
832
        ppb = info["pagesperblock"]
833
        banks = info["banks"]
834
        blocks = info["blocks"]
835
        try:
836
            if (os.path.getsize(filenameprefix+"_data.bin") != blocks * banks * ppb * 2048):
837
                raise ArgumentError("Data file size does not match flash size!")
838
            if (os.path.getsize(filenameprefix+"_spare.bin") != blocks * banks * ppb * 64):
839
                raise ArgumentError("Spare file size does not match flash size!")
840
            datafile = open(filenameprefix+"_data.bin", 'rb')
841
            sparefile = open(filenameprefix+"_spare.bin", 'rb')
228 theseven 842
        except IOError:
775 theseven 843
            raise ArgumentError("Can not open input files!")
844
        try:
776 theseven 845
            buf = self.emcore.memalign(0x10, 0x844)
775 theseven 846
            for block in range(info["blocks"]):
847
                for bank in range(info["banks"]):
776 theseven 848
                    self.logger.info("\r    Erasing block %d bank %d         " % (block, bank))
775 theseven 849
                    self.emcore.ipodnano2g_nanderase(buf, block * banks + bank, 1)
850
                    rc = struct.unpack("<I", self.emcore.read(buf, 4))[0]
851
                    if rc != 0: self.logger.info("\rBlock %d bank %d erase failed with RC %08X\n" % (block, bank, rc))
852
                for page in range(ppb):
776 theseven 853
                    for bank in range(banks):
854
                        data = datafile.read(2048) + sparefile.read(64)
855
                        if data == "\xff" * 2112: continue
856
                        self.emcore.write(buf, data)
857
                        self.logger.info("\rProgramming block %d page %d bank %d" % (block, page, bank))
858
                        self.emcore.ipodnano2g_nandwrite(buf, ((block * ppb) + page) * banks + bank, 1, 0)
859
                        rc = struct.unpack("<I", self.emcore.read(buf + 2112, 4))[0]
860
                        if rc != 0: self.logger.info("\rBlock %d bank %d page %d programming failed with RC %08X\n" % (block, bank, page, rc))
775 theseven 861
        finally:
862
            self.emcore.free(buf)
228 theseven 863
        datafile.close()
864
        sparefile.close()
776 theseven 865
        self.logger.info("\ndone\n")
517 farthen 866
 
228 theseven 867
    @command
868
    def ipodnano2g_wipenand(self, filename, force=False):
869
        """
870
            Target-specific function: ipodnano2g
871
            Wipes the whole NAND chip and logs the result to a file
402 farthen 872
            <filename>: location of the log file
775 theseven 873
            [force]: use this flag to suppress the 10 seconds delay
228 theseven 874
        """
382 farthen 875
        self.logger.warn("Wiping the whole NAND chip!\n")
228 theseven 876
        if force == False:
382 farthen 877
            self.logger.warn("If this was not what you intended press Ctrl-C NOW")
228 theseven 878
            for i in range(10):
879
                self.logger.info(".")
880
                time.sleep(1)
881
            self.logger.info("\n")
882
        try:
775 theseven 883
            buf = self.emcore.malloc(0x100)
884
            info = self.emcore.ipodnano2g_getnandinfo()
885
            self.logger.info("Wiping NAND contents...")
886
            try:
887
                statusfile = open(filename, 'wb')
888
            except IOError:
889
                raise ArgumentError("Can not open file for writing!")
890
            for i in range(info["banks"] * info["blocks"] / 64):
891
                self.logger.info(".")
892
                self.emcore.ipodnano2g_nanderase(buf, i * 64, 64)
893
                statusfile.write(self.emcore.read(buf, 0x00000100))
894
            statusfile.close()
895
            self.logger.info("done\n")
896
        finally:
897
            self.emcore.free(buf)
517 farthen 898
 
346 theseven 899
    @command
787 theseven 900
    def ipodclassic_readbbt(self, filename, tempaddr = None):
901
        """
902
            Target-specific function: ipodclassic
903
            Reads the bad block table from the hard disk to memory at <tempaddr>
904
            (or an allocated block if not given) and writes it to <filename>
905
        """
906
        tempaddr = to_int(tempaddr)
907
        try:
908
            f = open(filename, 'wb')
909
        except IOError:
910
            raise ArgumentError("File not writable.")
911
        self.logger.info("Reading bad block table from disk...")
912
        f.write(self.emcore.ipodclassic_readbbt(tempaddr))
913
        f.close()
914
        self.logger.info(" done\n")
915
 
916
    @command
585 theseven 917
    def ipodclassic_writebbt(self, filename, tempaddr = None):
346 theseven 918
        """
919
            Target-specific function: ipodclassic
585 theseven 920
            Uploads the bad block table <filename> to memory at <tempaddr>
921
            (or an allocated block if not given) and writes it to the hard disk
346 theseven 922
        """
602 theseven 923
        tempaddr = to_int(tempaddr)
346 theseven 924
        try:
925
            f = open(filename, 'rb')
926
        except IOError:
927
            raise ArgumentError("File not readable. Does it exist?")
928
        self.logger.info("Writing bad block table to disk...")
427 farthen 929
        data = self.emcore.ipodclassic_writebbt(f.read(), tempaddr)
346 theseven 930
        f.close()
931
        self.logger.info(" done\n")
517 farthen 932
 
346 theseven 933
    @command
791 theseven 934
    def ipodclassic_disablebbt(self):
935
        """
936
            Target-specific function: ipodclassic
937
            Disables the hard disk bad block table, if present
938
        """
939
        self.logger.info("Disabling hard disk BBT...")
940
        data = self.emcore.ipodclassic_disablebbt()
941
        self.logger.info(" done\n")
942
 
943
    @command
944
    def ipodclassic_reloadbbt(self):
945
        """
946
            Target-specific function: ipodclassic
947
            Reloads the hard disk bad block table, if present
948
        """
949
        self.logger.info("Reloading hard disk BBT...")
950
        data = self.emcore.ipodclassic_reloadbbt()
951
        self.logger.info(" done\n")
952
 
953
    @command
379 theseven 954
    def getvolumeinfo(self, volume):
955
        """
956
            Gathers some information about a storage volume used
404 farthen 957
            <volume>: volume id
379 theseven 958
        """
532 farthen 959
        volume = to_int(volume)
427 farthen 960
        data = self.emcore.storage_get_info(volume)
516 farthen 961
        self.logger.info("Sector size: %d\n" % data["sectorsize"])
962
        self.logger.info("Number of sectors: %d\n" % data["numsectors"])
963
        self.logger.info("Vendor: %s\n" % data["vendor"])
964
        self.logger.info("Product: %s\n" % data["product"])
965
        self.logger.info("Revision: %s\n" % data["revision"])
517 farthen 966
 
379 theseven 967
    @command
968
    def readrawstorage(self, volume, sector, count, addr):
969
        """
970
            Reads <count> sectors starting at <sector> from storage <volume> to memory at <addr>.
971
        """
532 farthen 972
        volume = to_int(volume)
973
        sector = to_int(sector)
974
        count = to_int(count)
975
        addr = to_int(addr)
379 theseven 976
        self.logger.info("Reading volume %s sectors %X - %X to %08X..." % (volume, sector, sector + count - 1, addr))
427 farthen 977
        self.emcore.storage_read_sectors_md(volume, sector, count, addr)
379 theseven 978
        self.logger.info("done\n")
517 farthen 979
 
379 theseven 980
    @command
981
    def writerawstorage(self, volume, sector, count, addr):
982
        """
983
            Writes memory contents at <addr> to <count> sectors starting at <sector> on storage <volume>.
984
        """
532 farthen 985
        volume = to_int(volume)
986
        sector = to_int(sector)
987
        count = to_int(count)
988
        addr = to_int(addr)
379 theseven 989
        self.logger.info("Writing %08X to volume %s sectors %X - %X..." % (addr, volume, sector, sector + count - 1))
427 farthen 990
        self.emcore.storage_write_sectors_md(volume, sector, count, addr)
379 theseven 991
        self.logger.info("done\n")
517 farthen 992
 
379 theseven 993
    @command
475 farthen 994
    def readrawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
379 theseven 995
        """
996
            Reads <count> sectors starting at <sector> from storage <volume> to file <file>,
402 farthen 997
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
379 theseven 998
        """
532 farthen 999
        volume = to_int(volume)
1000
        sector = to_int(sector)
1001
        count = to_int(count)
1002
        buffsize = to_int(buffsize)
379 theseven 1003
        try:
479 theseven 1004
            f = open(file, 'wb')
1005
        except IOError:
1006
            raise ArgumentError("Could not open local file for writing.")
1007
        try:
482 theseven 1008
            storageinfo = self.emcore.storage_get_info(volume)
1009
            buffsize = min(buffsize, storageinfo.sectorsize * count)
479 theseven 1010
            if buffer is None:
644 theseven 1011
                buffer = self.emcore.memalign(0x10, buffsize)
479 theseven 1012
                malloc = True
1013
            else:
532 farthen 1014
                buffer = to_int(buffer)
479 theseven 1015
                malloc = False
472 farthen 1016
            try:
479 theseven 1017
                self.logger.info("Reading volume %s sectors %X - %X to %s..." % (volume, sector, sector + count - 1, file))
1018
                while count > 0:
1019
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
792 theseven 1020
                    self.emcore.storage_read_sectors_md(volume, sector, sectors, buffer)
479 theseven 1021
                    f.write(self.emcore.read(buffer, storageinfo.sectorsize * sectors))
1022
                    sector = sector + sectors
1023
                    count = count - sectors
1024
            finally:
1025
                if malloc == True:
1026
                    self.emcore.free(buffer)
1027
        finally:
472 farthen 1028
            f.close()
379 theseven 1029
        self.logger.info("done\n")
517 farthen 1030
 
379 theseven 1031
    @command
475 farthen 1032
    def writerawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
379 theseven 1033
        """
1034
            Writes contents of <file> to <count> sectors starting at <sector> on storage <volume>,
402 farthen 1035
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
792 theseven 1036
            If <count> is -1, the number of sectors will be determined from the file size.
379 theseven 1037
        """
532 farthen 1038
        volume = to_int(volume)
1039
        sector = to_int(sector)
1040
        count = to_int(count)
1041
        buffsize = to_int(buffsize)
379 theseven 1042
        try:
479 theseven 1043
            f = open(file, 'rb')
1044
        except IOError:
1045
            raise ArgumentError("Could not open local file for reading.")
1046
        try:
482 theseven 1047
            storageinfo = self.emcore.storage_get_info(volume)
792 theseven 1048
            if count == -1: count = int((os.path.getsize(file) + storageinfo.sectorsize - 1) / storageinfo.sectorsize)
482 theseven 1049
            buffsize = min(buffsize, storageinfo.sectorsize * count)
479 theseven 1050
            if buffer is None:
644 theseven 1051
                buffer = self.emcore.memalign(0x10, buffsize)
479 theseven 1052
                malloc = True
1053
            else:
532 farthen 1054
                buffer = to_int(buffer)
479 theseven 1055
                malloc = False
472 farthen 1056
            try:
479 theseven 1057
                self.logger.info("Writing %s to volume %s sectors %X - %X..." % (file, volume, sector, sector + count - 1))
1058
                while count > 0:
1059
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
1060
                    bytes = storageinfo.sectorsize * sectors
792 theseven 1061
                    data = b""
1062
                    while len(data) < bytes:
1063
                       new = f.read(bytes - len(data))
1064
                       data = data + new
1065
                       if len(new) == 0: break
479 theseven 1066
                    self.emcore.write(buffer, data)
792 theseven 1067
                    self.emcore.storage_write_sectors_md(volume, sector, sectors, buffer)
479 theseven 1068
                    sector = sector + sectors
1069
                    count = count - sectors
1070
            finally:
1071
                if malloc == True:
1072
                    self.emcore.free(buffer)
1073
        finally:
472 farthen 1074
            f.close()
379 theseven 1075
        self.logger.info("done\n")
517 farthen 1076
 
379 theseven 1077
    @command
346 theseven 1078
    def mkdir(self, dirname):
1079
        """
402 farthen 1080
            Creates a directory with the name <dirname>
346 theseven 1081
        """
516 farthen 1082
        self.logger.info("Creating directory %s..." % dirname)
427 farthen 1083
        self.emcore.dir_create(dirname)
346 theseven 1084
        self.logger.info(" done\n")
517 farthen 1085
 
346 theseven 1086
    @command
1087
    def rmdir(self, dirname):
1088
        """
402 farthen 1089
            Removes an empty directory with the name <dirname>
346 theseven 1090
        """
516 farthen 1091
        self.logger.info("Removing directory %s..." % dirname)
427 farthen 1092
        self.emcore.dir_remove(dirname)
346 theseven 1093
        self.logger.info(" done\n")
517 farthen 1094
 
346 theseven 1095
    @command
349 theseven 1096
    def rm(self, filename):
346 theseven 1097
        """
402 farthen 1098
            Removes a file with the name <filename>
346 theseven 1099
        """
516 farthen 1100
        self.logger.info("Removing file %s..." % filename)
427 farthen 1101
        self.emcore.file_unlink(filename)
346 theseven 1102
        self.logger.info(" done\n")
517 farthen 1103
 
346 theseven 1104
    @command
406 theseven 1105
    def rmtree(self, path):
1106
        """
1107
            Recursively removes a folder
1108
            <path>: the folder to be removed
1109
        """
427 farthen 1110
        handle = self.emcore.dir_open(path)
406 theseven 1111
        while True:
1112
            try:
427 farthen 1113
                entry = self.emcore.dir_read(handle)
406 theseven 1114
                if entry.name == "." or entry.name == "..": continue
1115
                elif entry.attributes & 0x10:
1116
                    self.rmtree(path + "/" + entry.name)
1117
                else: self.rm(path + "/" + entry.name)
1118
            except: break
427 farthen 1119
        self.emcore.dir_close(handle)
406 theseven 1120
        self.rmdir(path)
517 farthen 1121
 
406 theseven 1122
    @command
352 theseven 1123
    def mv(self, oldname, newname):
350 theseven 1124
        """
402 farthen 1125
            Renames or moves file or directory <oldname> to <newname>
350 theseven 1126
        """
516 farthen 1127
        self.logger.info("Renaming %s to %s..." % (oldname, newname))
427 farthen 1128
        self.emcore.file_rename(oldname, newname)
350 theseven 1129
        self.logger.info(" done\n")
517 farthen 1130
 
350 theseven 1131
    @command
475 farthen 1132
    def get(self, remotename, localname, buffsize = 0x10000, buffer = None):
346 theseven 1133
        """
1134
            Downloads a file
402 farthen 1135
            <remotename>: filename on the device
1136
            <localname>: filename on the computer
472 farthen 1137
            [buffsize]: buffer size (optional)
402 farthen 1138
            [buffer]: buffer address (optional)
346 theseven 1139
        """
532 farthen 1140
        buffsize = to_int(buffsize)
346 theseven 1141
        try:
479 theseven 1142
            f = open(localname, 'wb')
1143
        except IOError:
1144
            raise ArgumentError("Could not open local file for writing.")
1145
        try:
482 theseven 1146
            fd = self.emcore.file_open(remotename, 0)
472 farthen 1147
            try:
482 theseven 1148
                size = self.emcore.file_size(fd)
1149
                buffsize = min(buffsize, size)
1150
                if buffer is None:
644 theseven 1151
                    buffer = self.emcore.memalign(0x10, buffsize)
482 theseven 1152
                    malloc = True
1153
                else:
532 farthen 1154
                    buffer = to_int(buffer)
482 theseven 1155
                    malloc = False
479 theseven 1156
                try:
516 farthen 1157
                    self.logger.info("Downloading file %s to %s..." % (remotename, localname))
479 theseven 1158
                    while size > 0:
488 theseven 1159
                        bytes = self.emcore.file_read(fd, buffsize, buffer).rc
479 theseven 1160
                        f.write(self.emcore.read(buffer, bytes))
1161
                        size = size - bytes
1162
                finally:
482 theseven 1163
                    if malloc == True:
1164
                        self.emcore.free(buffer)
479 theseven 1165
            finally:
482 theseven 1166
                self.emcore.file_close(fd)
479 theseven 1167
        finally:
472 farthen 1168
            f.close()
346 theseven 1169
        self.logger.info(" done\n")
517 farthen 1170
 
346 theseven 1171
    @command
475 farthen 1172
    def gettree(self, remotepath, localpath, buffsize = 0x10000, buffer = None):
406 theseven 1173
        """
1174
            Downloads a directory tree
1175
            <remotepath>: path on the device
1176
            <localpath>: path on the computer
472 farthen 1177
            [buffsize]: buffer size (optional)
406 theseven 1178
            [buffer]: buffer address (optional)
1179
        """
532 farthen 1180
        buffsize = to_int(buffsize)
479 theseven 1181
        handle = self.emcore.dir_open(remotepath)
472 farthen 1182
        try:
479 theseven 1183
            if buffer is None:
644 theseven 1184
                buffer = self.emcore.memalign(0x10, buffsize)
479 theseven 1185
                malloc = True
1186
            else:
532 farthen 1187
                buffer = to_int(buffer)
479 theseven 1188
                malloc = False
1189
            try:
1190
                try: os.mkdir(localpath)
1191
                except: pass
1192
                while True:
1193
                    try:
1194
                        entry = self.emcore.dir_read(handle)
1195
                    except: break
486 theseven 1196
                    if entry.name == "." or entry.name == "..": continue
1197
                    elif entry.attributes & 0x10:
1198
                        self.gettree(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffsize, buffer)
1199
                    else: self.get(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffsize, buffer)
479 theseven 1200
            finally:
1201
                if malloc == True:
1202
                    self.emcore.free(buffer)
1203
        finally:
472 farthen 1204
            self.emcore.dir_close(handle)
517 farthen 1205
 
406 theseven 1206
    @command
475 farthen 1207
    def put(self, localname, remotename, buffsize = 0x10000, buffer = None):
346 theseven 1208
        """
1209
            Uploads a file
406 theseven 1210
            <localname>: filename on the computer
402 farthen 1211
            <remotename>: filename on the device
472 farthen 1212
            [buffsize]: buffer size (optional)
402 farthen 1213
            [buffer]: buffer address (optional)
346 theseven 1214
        """
532 farthen 1215
        buffsize = to_int(buffsize)
346 theseven 1216
        try:
479 theseven 1217
            f = open(localname, 'rb')
1218
        except IOError:
1219
            raise ArgumentError("Could not open local file for reading.")
1220
        try:
482 theseven 1221
            buffsize = min(buffsize, os.path.getsize(localname))
479 theseven 1222
            if buffer is None:
644 theseven 1223
                buffer = self.emcore.memalign(0x10, buffsize)
479 theseven 1224
                malloc = True
1225
            else:
532 farthen 1226
                buffer = to_int(buffer)
479 theseven 1227
                malloc = False
472 farthen 1228
            try:
516 farthen 1229
                self.logger.info("Uploading file %s to %s..." % (localname, remotename))
479 theseven 1230
                fd = self.emcore.file_open(remotename, 0x15)
1231
                try:
1232
                    while True:
1233
                        data = f.read(buffsize)
1234
                        if len(data) == 0: break
1235
                        self.emcore.write(buffer, data)
1236
                        bytes = 0
1237
                        while bytes < len(data):
1238
                            bytes = bytes + self.emcore.file_write(fd, len(data) - bytes, buffer + bytes)
1239
                finally:
1240
                    self.emcore.file_close(fd)
1241
            finally:
1242
                if malloc == True:
1243
                    self.emcore.free(buffer)
1244
        finally:
472 farthen 1245
            f.close()
346 theseven 1246
        self.logger.info(" done\n")
517 farthen 1247
 
346 theseven 1248
    @command
475 farthen 1249
    def puttree(self, localpath, remotepath, buffsize = 0x10000, buffer = None):
406 theseven 1250
        """
1251
            Uploads a directory tree
1252
            <localpath>: path on the computer
1253
            <remotepath>: path on the device
472 farthen 1254
            [buffsize]: buffer size (optional)
406 theseven 1255
            [buffer]: buffer address (optional)
1256
        """
532 farthen 1257
        buffsize = to_int(buffsize)
472 farthen 1258
        if buffer is None:
644 theseven 1259
            buffer = self.emcore.memalign(0x10, buffsize)
472 farthen 1260
            malloc = True
1261
        else:
532 farthen 1262
            buffer = to_int(buffer)
472 farthen 1263
            malloc = False
1264
        try:
1265
            try: self.mkdir(remotepath)
1266
            except: self.logger.info(" failed\n")
1267
            pathlen = len(localpath)
1268
            for d in os.walk(localpath):
1269
                prefix = remotepath + "/" + d[0].replace("\\", "/")[pathlen:] + "/"
1270
                for dir in d[1]:
1271
                    if dir != ".svn":
1272
                        try: self.mkdir(prefix + dir)
1273
                        except: self.logger.info(" failed\n")
1274
                for f in d[2]:
479 theseven 1275
                    if prefix.find("/.svn/") == -1:
477 farthen 1276
                        self.put(d[0] + "/" + f, prefix + f, buffsize, buffer)
472 farthen 1277
        finally:
1278
            if malloc == True:
1279
                self.emcore.free(buffer)
517 farthen 1280
 
406 theseven 1281
    @command
351 theseven 1282
    def ls(self, path = "/"):
346 theseven 1283
        """
1284
            Lists all files in the specified path
402 farthen 1285
            [path]: the path which is listed
346 theseven 1286
        """
427 farthen 1287
        handle = self.emcore.dir_open(path)
516 farthen 1288
        self.logger.info("Directory listing of %s:\n" % path)
346 theseven 1289
        while True:
1290
            try:
427 farthen 1291
                entry = self.emcore.dir_read(handle)
346 theseven 1292
            except: break
486 theseven 1293
            if entry.attributes & 0x10: size = "DIR"
1294
            else: size = locale.format("%d", entry.size, True).rjust(13)
1295
            self.logger.info(entry.name.ljust(50) + " - " + size + "\n")
427 farthen 1296
        self.emcore.dir_close(handle)
474 farthen 1297
 
1298
    @command
483 theseven 1299
    def find(self, path = "/"):
1300
        """
1301
            Lists all files in the specified path, recursively
1302
            [path]: the path which is listed
1303
        """
1304
        handle = self.emcore.dir_open(path)
1305
        self.logger.info(path + "/\n")
1306
        while True:
1307
            try:
1308
                entry = self.emcore.dir_read(handle)
1309
            except: break
486 theseven 1310
            if entry.name == "." or entry.name == "..": continue
1311
            elif entry.attributes & 0x10: self.find(path + "/" + entry.name)
1312
            else: self.logger.info(path + "/" + entry.name + "\n")
483 theseven 1313
        self.emcore.dir_close(handle)
1314
 
1315
    @command
474 farthen 1316
    def malloc(self, size):
1317
        """ Allocates <size> bytes and returns a pointer to the allocated memory """
532 farthen 1318
        size = to_int(size)
474 farthen 1319
        self.logger.info("Allocating %d bytes of memory\n" % size)
1320
        addr = self.emcore.malloc(size)
518 farthen 1321
        self.logger.info("Allocated %d bytes of memory at 0x%X\n" % (size, addr))
474 farthen 1322
 
1323
    @command
1324
    def memalign(self, align, size):
1325
        """ Allocates <size> bytes aligned to <align> and returns a pointer to the allocated memory """
532 farthen 1326
        align = to_int(align)
1327
        size = to_int(size)
518 farthen 1328
        self.logger.info("Allocating %d bytes of memory aligned to 0x%X\n" % (size, align))
474 farthen 1329
        addr = self.emcore.memalign(align, size)
518 farthen 1330
        self.logger.info("Allocated %d bytes of memory at 0x%X\n" % (size, addr))
474 farthen 1331
 
1332
    @command
1333
    def realloc(self, ptr, size):
1334
        """ The size of the memory block pointed to by <ptr> is changed to the <size> bytes,
1335
            expanding or reducing the amount of memory available in the block.
1336
            Returns a pointer to the reallocated memory.
1337
        """
532 farthen 1338
        ptr = to_int(ptr)
1339
        size = to_int(size)
518 farthen 1340
        self.logger.info("Reallocating 0x%X to have the new size %d\n" % (ptr, size))
474 farthen 1341
        addr = self.emcore.realloc(ptr, size)
518 farthen 1342
        self.logger.info("Reallocated memory at 0x%X to 0x%X with the new size %d\n" % (ptr, addr, size))
474 farthen 1343
 
1344
    @command
1345
    def reownalloc(self, ptr, owner):
1346
        """ Changes the owner of the memory allocation <ptr> to the thread struct at addr <owner> """
532 farthen 1347
        ptr = to_int(ptr)
1348
        owner = to_int(owner)
518 farthen 1349
        self.logger.info("Changing owner of the memory region 0x%X to 0x%X\n" % (ptr, owner))
474 farthen 1350
        self.emcore.reownalloc(ptr, owner)
518 farthen 1351
        self.logger.info("Successfully changed owner of 0x%X to 0x%X\n" % (ptr, owner))
474 farthen 1352
 
1353
    @command
1354
    def free(self, ptr):
1355
        """ Frees the memory space pointed to by 'ptr' """
532 farthen 1356
        ptr = to_int(ptr)
518 farthen 1357
        self.logger.info("Freeing the memory region at 0x%X\n" % ptr)
474 farthen 1358
        self.emcore.free(ptr)
518 farthen 1359
        self.logger.info("Successfully freed the memory region at 0x%X\n" % ptr)
474 farthen 1360
 
1361
    @command
1362
    def free_all(self):
1363
        """ Frees all memory allocations created by the monitor thread """
1364
        self.logger.info("Freeing all memory allocations created by the monitor thread\n")
1365
        self.emcore.free_all()
1366
        self.logger.info("Successfully freed all memory allocations created by the monitor thread\n")
778 farthen 1367
 
1368
    @command
1369
    def rtcread(self):
1370
        """ Reads the real time clock on the device """
1371
        import datetime
1372
        self.logger.info("Reading the clock\n")
1373
        dt = self.emcore.rtcread()
1374
        self.logger.info("Successfully read the clock: %s\n" % (dt.ctime()))
1375
 
1376
    @command
1377
    def rtcwrite(self):
1378
        """ Sets the real time clock on the device to the current local time """
1379
        import datetime
1380
        dt = datetime.datetime.now()
1381
        self.logger.info("Setting the clock to: %s\n" % (dt.ctime()))
1382
        self.emcore.rtcwrite(dt)
1383
        self.logger.info("Successfully set the clock\n")
474 farthen 1384
 
346 theseven 1385
 
171 farthen 1386
if __name__ == "__main__":
1387
    if len(sys.argv) < 2:
502 farthen 1388
        usage("No command specified", docstring = False)
382 farthen 1389
    try:
1390
        interface = Commandline()
1391
        interface._parsecommand(sys.argv[1], sys.argv[2:])
1392
    except KeyboardInterrupt:
778 farthen 1393
        sys.exit()