Subversion Repositories freemyipod

Rev

Go to most recent revision | 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
#
22
#
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']:
412 farthen 62
                for kwarg, kwvalue in doc[function]['kwargs'].iteritems():
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 = {}
96
    for attr, value in cls.__dict__.iteritems():
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)
427 farthen 128
            except (ArgumentError, libemcore.ArgumentError), 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)
171 farthen 132
            except ArgumentTypeError, 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")
427 farthen 136
            except libemcore.DeviceError, e:
478 farthen 137
                self.logger.error(str(e) + "\n")
171 farthen 138
            except TypeError, 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.
171 farthen 159
            <infotype> may be either of 'version', 'packetsize', 'usermemrange'.
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
 
171 farthen 178
        elif infotype == "usermemrange":
427 farthen 179
            resp = self.emcore.getusermemrange()
516 farthen 180
            self.logger.info("The user memory range is 0x%X - 0x%X" % (
181
                             self.emcore.lib.dev.usermem.lower,
182
                             self.emcore.lib.dev.usermem.upper - 1))
382 farthen 183
 
171 farthen 184
        else:
185
            raise ArgumentTypeError("one out of 'version', 'packetsize', 'usermemrange'", 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
575 theseven 259
    def hexdump(self, addr, size, width = 16, wordsize = 1, separate = 4, \
260
                align = False, relative = False, ascii = True, asciisep = 8):
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
272
        """
273
        addr = to_int(addr)
274
        size = to_int(size)
275
        width = to_int(width)
276
        wordsize = to_int(wordsize)
277
        separate = to_int(separate)
278
        align = to_bool(align)
279
        relative = to_bool(relative)
280
        ascii = to_bool(ascii)
281
        asciisep = to_int(asciisep)
282
        if addr % wordsize != 0: raise ArgumentError("Address is not word aligned!")
283
        if size % wordsize != 0: raise ArgumentError("Size is not word aligned!")
284
        if align: skip = addr % (wordsize * width)
285
        else: skip = 0
286
        if relative: base = 0
287
        else: base = addr
288
        data = self.emcore.read(addr, size)
289
        for r in range(-skip, size, wordsize * width):
290
            sys.stdout.write("%08X:" % (base + r))
291
            for i in range(r, r + wordsize * width, wordsize):
292
                if i - r > 0 and (i - r) % (separate * wordsize) == 0: sys.stdout.write(" ")
293
                if i >= 0 and i < size:
294
                    w = 0
295
                    for b in range(wordsize):
296
                        w = (w << 8) | struct.unpack("B", data[i + b])[0]
297
                    sys.stdout.write((" %%%dX" % (wordsize * 2)) % w)
298
                else: sys.stdout.write(" " * (wordsize * 2 + 1))
299
            if ascii:
300
                sys.stdout.write(" |")
301
                for i in range(r, r + wordsize * width):
302
                    if i - r > 0 and (i - r) % asciisep == 0: sys.stdout.write(" ")
303
                    if i >= 0 and i < size:
304
                        if ord(data[i]) > 0x1f: sys.stdout.write(data[i])
305
                        else: sys.stdout.write(".")
306
                    else: sys.stdout.write(" ")
307
                sys.stdout.write("|")
308
            sys.stdout.write("\n")
309
 
310
    @command
171 farthen 311
    def uploadint(self, addr, integer):
312
        """
313
            Uploads a single integer to the device
260 theseven 314
            <addr>: the address to upload the integer to
315
            <integer>: the integer to upload
171 farthen 316
        """
532 farthen 317
        addr = to_int(addr)
318
        integer = to_int(integer)
171 farthen 319
        if integer > 0xFFFFFFFF:
320
            raise ArgumentError("Specified integer too long")
548 farthen 321
        data = struct.pack("<I", integer)
427 farthen 322
        self.emcore.write(addr, data)
516 farthen 323
        self.logger.info("Integer '0x%X' written successfully to 0x%X\n" % (integer, addr))
517 farthen 324
 
171 farthen 325
    @command
326
    def downloadint(self, addr):
327
        """
328
            Downloads a single integer from the device and prints it to the console window
236 farthen 329
            <addr>: the address to download the integer from
171 farthen 330
        """
532 farthen 331
        addr = to_int(addr)
427 farthen 332
        data = self.emcore.read(addr, 4)
548 farthen 333
        integer = struct.unpack("<I", data)[0]
516 farthen 334
        self.logger.info("Read '0x%X' from address 0x%X\n" % (integer, addr))
517 farthen 335
 
171 farthen 336
    @command
176 farthen 337
    def i2cread(self, bus, slave, addr, size):
171 farthen 338
        """
339
            Reads data from an I2C device
402 farthen 340
            <bus>: the bus index
341
            <slave>: the slave address
342
            <addr>: the start address on the I2C device
343
            <size>: the number of bytes to read
171 farthen 344
        """
532 farthen 345
        bus = to_int(bus)
346
        slave = to_int(slave)
347
        addr = to_int(addr)
348
        size = to_int(size)
427 farthen 349
        data = self.emcore.i2cread(bus, slave, addr, size)
548 farthen 350
        bytes = struct.unpack("<%dB" % len(data), data)
236 farthen 351
        self.logger.info("Data read from I2C:\n")
352
        for index, byte in enumerate(bytes):
533 theseven 353
            self.logger.info("%02X: %02X\n" % (addr + index, byte))
517 farthen 354
 
171 farthen 355
    @command
176 farthen 356
    def i2cwrite(self, bus, slave, addr, *args):
171 farthen 357
        """
358
            Writes data to an I2C device
402 farthen 359
            <bus>: the bus index
360
            <slave>: the slave address
361
            <addr>: the start address on the I2C device
532 farthen 362
            <db1> ... <dbN>: the data in single bytes,
236 farthen 363
                seperated by whitespaces, eg. 37 5A 4F EB
171 farthen 364
        """
532 farthen 365
        bus = to_int(bus)
366
        slave = to_int(slave)
367
        addr = to_int(addr)
176 farthen 368
        data = ""
171 farthen 369
        for arg in args:
532 farthen 370
            data += chr(to_int(arg))
236 farthen 371
        self.logger.info("Writing data to I2C...\n")
427 farthen 372
        self.emcore.i2cwrite(bus, slave, addr, data)
236 farthen 373
        self.logger.info("done\n")
517 farthen 374
 
171 farthen 375
    @command
176 farthen 376
    def console(self):
171 farthen 377
        """
176 farthen 378
            Reads data from the USB console continuously
171 farthen 379
        """
176 farthen 380
        while True:
427 farthen 381
            resp = self.emcore.usbcread()
501 farthen 382
            self.logger.write(resp.data)
176 farthen 383
            time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
517 farthen 384
 
171 farthen 385
    @command
176 farthen 386
    def writeusbconsole(self, *args):
171 farthen 387
        """
176 farthen 388
            Writes the string <db1> ... <dbN> to the USB console.
171 farthen 389
        """
176 farthen 390
        text = ""
391
        for word in args:
392
            text += word + " "
393
        text = text[:-1]
516 farthen 394
        self.logger.info("Writing '%s' to the usb console\n" % text)
427 farthen 395
        self.emcore.usbcwrite(text)
517 farthen 396
 
171 farthen 397
    @command
176 farthen 398
    def readdevconsole(self, bitmask):
171 farthen 399
        """
176 farthen 400
            Reads data continuously from one or more of the device's consoles.
401
            <bitmask>: the bitmask of the consoles to read from.
171 farthen 402
        """
532 farthen 403
        bitmask = to_int(bitmask)
176 farthen 404
        while True:
427 farthen 405
            resp = self.emcore.cread()
501 farthen 406
            self.logger.write(resp.data)
176 farthen 407
            time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
408
 
171 farthen 409
    @command
176 farthen 410
    def writedevconsole(self, bitmask, *args):
171 farthen 411
        """
176 farthen 412
            Writes the string <db1> ... <dbN> to one or more of the device's consoles.
413
            <bitmask>: the bitmask of the consoles to write to
171 farthen 414
        """
532 farthen 415
        bitmask = to_int(bitmask)
176 farthen 416
        text = ""
417
        for word in args:
418
            text += word + " "
419
        text = text[:-1]
516 farthen 420
        self.logger.info("Writing '%s' to the device consoles identified with 0x%X\n" % (text, bitmask))
427 farthen 421
        self.emcore.cwrite(text, bitmask)
517 farthen 422
 
171 farthen 423
    @command
424
    def flushconsolebuffers(self, bitmask):
425
        """
426
            flushes one or more of the device consoles' buffers.
427
            <bitmask>: the bitmask of the consoles to be flushed
428
        """
532 farthen 429
        bitmask = to_int(bitmask)
516 farthen 430
        self.logger.info("Flushing consoles identified with the bitmask 0x%X\n" % bitmask)
427 farthen 431
        self.emcore.cflush(bitmask)
517 farthen 432
 
171 farthen 433
    @command
434
    def getprocinfo(self):
435
        """
436
            Fetches data on the currently running processes
437
        """
173 farthen 438
        import datetime
427 farthen 439
        threads = self.emcore.getprocinfo()
382 farthen 440
        threadload = 0
441
        idleload = 0
173 farthen 442
        for thread in threads:
392 theseven 443
            if thread.id != 0:
444
                threadload += thread.cpuload / 255.
382 farthen 445
            else:
392 theseven 446
                idleload += thread.cpuload / 255.
382 farthen 447
        coreload = 1 - (threadload + idleload)
448
        cpuload = threadload + coreload
392 theseven 449
        self.logger.info("Threads: %d, CPU load: %.1f%%, kernel load: %.1f%%, user load: %.1f%%\n\n"
450
                         % (len(threads), cpuload * 100, coreload * 100, threadload * 100))
382 farthen 451
        self.logger.info("Thread dump:\n")
452
        for thread in threads:
516 farthen 453
            self.logger.info("%s:\n" % thread.name, 2)
454
            self.logger.info("Threadstruct address: 0x%X\n" % thread.addr, 4)
455
            self.logger.info("Thread type: %s\n" % thread.thread_type, 4)
456
            self.logger.info("Thread state: %s\n" % thread.state, 4)
457
            self.logger.info("Block type: %s\n" % thread.block_type, 4)
458
            self.logger.info("Blocked by: 0x%X\n" % thread.blocked_by, 4)
459
            self.logger.info("Priority: %d/255\n" % thread.priority, 4)
396 farthen 460
            self.logger.info("Current CPU load: %.1f%%\n" % ((thread.cpuload * 100) / 255.), 4)
516 farthen 461
            self.logger.info("CPU time (total): %s\n" % datetime.timedelta(microseconds = thread.cputime_total), 4)
462
            self.logger.info("Stack address: 0x%X\n" % thread.stack, 4)
396 farthen 463
            self.logger.info("Registers:\n", 4)
177 farthen 464
            for registerrange in range(4):
465
                self.logger.info("      ")
466
                for register in range(registerrange, 16, 4):
467
                    registerrepr = "r"+str(register)
506 farthen 468
                    self.logger.info("{0:3s}: 0x{1:08X}   ".format(registerrepr, thread.regs[register]))
177 farthen 469
                self.logger.info("\n")
506 farthen 470
            self.logger.info("cpsr: 0x{0:08X}".format(thread.cpsr), 6)
173 farthen 471
            self.logger.info("\n")
472
 
171 farthen 473
    @command
474
    def lockscheduler(self):
475
        """
476
            Locks (freezes) the scheduler
477
        """
176 farthen 478
        self.logger.info("Will now lock scheduler\n")
427 farthen 479
        self.emcore.lockscheduler()
178 farthen 480
 
171 farthen 481
    @command
482
    def unlockscheduler(self):
483
        """
484
            Unlocks (unfreezes) the scheduler
485
        """
176 farthen 486
        self.logger.info("Will now unlock scheduler\n")
427 farthen 487
        self.emcore.unlockscheduler()
178 farthen 488
 
171 farthen 489
    @command
516 farthen 490
    def suspendthread(self, threadaddr):
171 farthen 491
        """
516 farthen 492
            Suspends the thread with the thread address <threadaddr>
171 farthen 493
        """
532 farthen 494
        threadaddr = to_int(threadaddr)
516 farthen 495
        self.logger.info("Suspending the thread with the threadaddr 0x%X\n" % threadaddr)
496
        self.emcore.suspendthread(threadaddr)
517 farthen 497
 
171 farthen 498
    @command
516 farthen 499
    def resumethread(self, threadaddr):
171 farthen 500
        """
516 farthen 501
            Resumes the thread with the thread address <threadaddr>
171 farthen 502
        """
532 farthen 503
        threadaddr = to_int(threadaddr)
516 farthen 504
        self.logger.info("Resuming the thread with the threadaddr 0x%X\n" % threadaddr)
505
        self.emcore.resumethread(threadaddr)
517 farthen 506
 
171 farthen 507
    @command
516 farthen 508
    def killthread(self, threadaddr):
171 farthen 509
        """
516 farthen 510
            Kills the thread with the thread address <threadaddr>
171 farthen 511
        """
532 farthen 512
        threadaddr = to_int(threadaddr)
516 farthen 513
        self.logger.info("Killing the thread with the threadaddr 0x%X\n" % threadaddr)
514
        self.emcore.killthread(threadaddr)
517 farthen 515
 
171 farthen 516
    @command
517
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
518
        """
516 farthen 519
            Creates a new thread and returns its thread pointer
402 farthen 520
            <namepointer>: a pointer to the thread's name
521
            <entrypoint>: a pointer to the entrypoint of the thread
522
            <stackpointer>: a pointer to the stack of the thread
523
            <stacksize>: the size of the thread's stack
516 farthen 524
            <threadtype>: the thread type, vaild are: 0 => user thread, 1 => system thread
402 farthen 525
            <priority>: the priority of the thread, from 1 to 255
526
            <state>: the thread's initial state, valid are: 1 => ready, 0 => suspended
171 farthen 527
        """
532 farthen 528
        nameptr = to_int(nameptr)
529
        entrypoint = to_int(entrypoint)
530
        stackptr = to_int(stackptr)
531
        stacksize = to_int(stacksize)
532
        priority = to_int(priority)
516 farthen 533
        data = self.emcore.createthread(nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state)
427 farthen 534
        name = self.emcore.readstring(nameptr)
516 farthen 535
        self.logger.info("Created a thread with the thread pointer 0x%X, the name \"%s\", the entrypoint at 0x%X," \
536
                         "the stack at 0x%X with a size of 0x%X and a priority of %d/255\n" %
537
                        (data.threadptr, name, entrypoint, stackptr, stacksize, priority))
172 farthen 538
 
539
    @command
540
    def run(self, filename):
541
        """
427 farthen 542
            Uploads the emCORE application <filename> to
236 farthen 543
            the memory and executes it
172 farthen 544
        """
236 farthen 545
        try:
546
            f = open(filename, 'rb')
547
        except IOError:
548
            raise ArgumentError("File not readable. Does it exist?")
238 farthen 549
        with f:
427 farthen 550
            data = self.emcore.run(f.read())
516 farthen 551
        self.logger.info("Executed emCORE application as thread 0x%X\n" % data.thread)
517 farthen 552
 
171 farthen 553
    @command
173 farthen 554
    def execimage(self, addr):
171 farthen 555
        """
427 farthen 556
            Executes the emCORE application at <addr>.
171 farthen 557
        """
532 farthen 558
        addr = to_int(addr)
516 farthen 559
        self.logger.info("Starting emCORE app at 0x%X\n" % addr)
427 farthen 560
        self.emcore.execimage(addr)
176 farthen 561
 
171 farthen 562
    @command
176 farthen 563
    def flushcaches(self):
171 farthen 564
        """
176 farthen 565
            Flushes the CPUs data and instruction caches.
566
        """
567
        self.logger.info("Flushing CPU data and instruction caches...")
427 farthen 568
        self.emcore.flushcaches()
176 farthen 569
        self.logger.info("done\n")
570
 
571
    @command
572
    def readbootflash(self, addr_flash, addr_mem, size):
573
        """
171 farthen 574
            Reads <size> bytes from bootflash to memory.
575
            <addr_bootflsh>: the address in bootflash to read from
576
            <addr_mem>: the address in memory to copy the data to
577
        """
532 farthen 578
        addr_flash = to_int(addr_flash)
579
        addr_mem = to_int(addr_mem)
580
        size = to_int(size)
516 farthen 581
        self.logger.info("Dumping boot flash from 0x%X - 0x%X to 0x%X - 0x%X\n" %
582
                        (addr_flash, addr_flash + size, addr_mem, addr_mem + size))
427 farthen 583
        self.emcore.bootflashread(addr_mem, addr_flash, size)
176 farthen 584
 
171 farthen 585
    @command
176 farthen 586
    def writebootflash(self, addr_flash, addr_mem, size, force=False):
171 farthen 587
        """
588
            Writes <size> bytes from memory to bootflash.
589
            ATTENTION: Don't call this unless you really know what you're doing!
590
            This may BRICK your device (unless it has a good recovery option)
591
            <addr_mem>: the address in memory to copy the data from
592
            <addr_bootflsh>: the address in bootflash to write to
402 farthen 593
            [force]: Use this flag to suppress the 5 seconds delay
171 farthen 594
        """
532 farthen 595
        addr_flash = to_int(addr_flash)
596
        addr_mem = to_int(addr_mem)
597
        size = to_int(size)
598
        force = to_bool(force)
516 farthen 599
        self.logger.warn("Writing boot flash from the memory in 0x%X - 0x%X to 0x%X - 0x%X\n" %
600
                        (addr_mem, addr_mem + size, addr_flash, addr_flash + size))
174 farthen 601
        if force == False:
382 farthen 602
            self.logger.warn("If this was not what you intended press Ctrl-C NOW")
176 farthen 603
            for i in range(10):
174 farthen 604
                self.logger.info(".")
605
                time.sleep(1)
606
            self.logger.info("\n")
427 farthen 607
        self.emcore.bootflashwrite(addr_mem, addr_flash, size)
176 farthen 608
 
171 farthen 609
    @command
442 farthen 610
    def runfirmware(self, targetaddr, filename):
171 farthen 611
        """
402 farthen 612
            Uploads the firmware in <filename>
442 farthen 613
            to an allocated buffer and executes it at <targetaddr>.
171 farthen 614
        """
532 farthen 615
        targetaddr = to_int(targetaddr)
442 farthen 616
        addr, size = self.uploadfile(filename)
617
        self.execfirmware(targetaddr, addr, size)
64 benedikt93 618
 
171 farthen 619
    @command
442 farthen 620
    def execfirmware(self, targetaddr, addr, size):
176 farthen 621
        """
442 farthen 622
            Moves the firmware at <addr> with <size> to <targetaddr> and executes it
176 farthen 623
        """
532 farthen 624
        targetaddr = to_int(targetaddr)
625
        addr = to_int(addr)
536 farthen 626
        size = to_int(size)
627
        self.logger.info("Running firmware at 0x%X. Bye.\n" % targetaddr)
442 farthen 628
        self.emcore.execfirmware(targetaddr, addr, size)
176 farthen 629
 
630
    @command
171 farthen 631
    def aesencrypt(self, addr, size, keyindex):
632
        """
172 farthen 633
            Encrypts a buffer using a hardware key
402 farthen 634
            <addr>: the starting address of the buffer
635
            <size>: the size of the buffer
636
            <keyindex>: the index of the key in the crypto unit
171 farthen 637
        """
532 farthen 638
        addr = to_int(addr)
639
        size = to_int(size)
640
        keyindex = to_int(keyindex)
427 farthen 641
        self.emcore.aesencrypt(addr, size, keyindex)
82 benedikt93 642
 
171 farthen 643
    @command
644
    def aesdecrypt(self, addr, size, keyindex):
645
        """
172 farthen 646
            Decrypts a buffer using a hardware key
402 farthen 647
            <addr>: the starting address of the buffer
648
            <size>: the size of the buffer
649
            <keyindex>: the index of the key in the crypto unit
171 farthen 650
        """
532 farthen 651
        addr = to_int(addr)
652
        size = to_int(size)
653
        keyindex = to_int(keyindex)
427 farthen 654
        self.emcore.aesdecrypt(addr, size, keyindex)
172 farthen 655
 
656
    @command
657
    def hmac_sha1(self, addr, size, destination):
658
        """
402 farthen 659
            Generates a HMAC-SHA1 hash of the buffer
660
            <addr>: the starting address of the buffer
661
            <size>: the size of the buffer
662
            <destination>: the location where the key will be stored
172 farthen 663
        """
532 farthen 664
        addr = to_int(addr)
665
        size = to_int(size)
666
        destination = to_int(destination)
172 farthen 667
        sha1size = 0x14
516 farthen 668
        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" %
669
                        (addr, size, destination, destination + sha1size))
427 farthen 670
        self.emcore.hmac_sha1(addr, size, destination)
172 farthen 671
        self.logger.info("done\n")
427 farthen 672
        data = self.emcore.read(destination, sha1size)
172 farthen 673
        hash = ord(data)
516 farthen 674
        self.logger.info("The generated hash is 0x%X\n" % hash)
517 farthen 675
 
227 theseven 676
    @command
677
    def ipodnano2g_getnandinfo(self):
678
        """
679
            Target-specific function: ipodnano2g
680
            Gathers some information about the NAND chip used
681
        """
427 farthen 682
        data = self.emcore.ipodnano2g_getnandinfo()
516 farthen 683
        self.logger.info("NAND chip type: 0x%X\n" % data["type"])
684
        self.logger.info("Number of banks: %d\n" % data["banks"])
685
        self.logger.info("Number of blocks: %d\n" % data["blocks"])
686
        self.logger.info("Number of user blocks: %d\n" % data["userblocks"])
687
        self.logger.info("Pages per block: %d\n" % data["pagesperblock"])
517 farthen 688
 
227 theseven 689
    @command
404 farthen 690
    def ipodnano2g_nandread(self, addr, start, count, doecc=True, checkempty=True):
227 theseven 691
        """
692
            Target-specific function: ipodnano2g
693
            Reads data from the NAND chip into memory
402 farthen 694
            <addr>: the memory location where the data is written to
695
            <start>: start block
696
            <count>: block count
404 farthen 697
            [doecc]: use ecc error correction data
698
            [checkempty]: set statusflags if pages are empty
227 theseven 699
        """
532 farthen 700
        addr = to_int(addr)
701
        start = to_int(start)
702
        count = to_int(count)
703
        doecc = to_bool(doecc)
704
        checkempty = to_bool(checkempty)
516 farthen 705
        self.logger.info("Reading 0x%X NAND pages starting at 0x%X to memory at 0x%X..." %
706
                        (count, start, addr))
427 farthen 707
        self.emcore.ipodnano2g_nandread(addr, start, count, doecc, checkempty)
227 theseven 708
        self.logger.info("done\n")
517 farthen 709
 
227 theseven 710
    @command
404 farthen 711
    def ipodnano2g_nandwrite(self, addr, start, count, doecc=True):
227 theseven 712
        """
713
            Target-specific function: ipodnano2g
714
            Writes data to the NAND chip
402 farthen 715
            <addr>: the memory location where the data is read from
716
            <start>: start block
717
            <count>: block count
404 farthen 718
            [doecc]: create ecc error correction data
227 theseven 719
        """
532 farthen 720
        addr = to_int(addr)
721
        start = to_int(start)
722
        count = to_int(count)
723
        doecc = to_bool(doecc)
516 farthen 724
        self.logger.info("Writing 0x%X NAND pages starting at 0x%X from memory at 0x%X..." %
725
                        (count, start, addr))
427 farthen 726
        self.emcore.ipodnano2g_nandwrite(addr, start, count, doecc)
227 theseven 727
        self.logger.info("done\n")
517 farthen 728
 
227 theseven 729
    @command
730
    def ipodnano2g_nanderase(self, addr, start, count):
731
        """
732
            Target-specific function: ipodnano2g
733
            Erases blocks on the NAND chip and stores the results to memory
402 farthen 734
            <addr>: the memory location where the results are stored
735
            <start>: start block
736
            <count>: block count
227 theseven 737
        """
532 farthen 738
        addr = to_int(addr)
739
        start = to_int(start)
740
        count = to_int(count)
516 farthen 741
        self.logger.info("Erasing 0x%X NAND pages starting at 0x%X and logging to 0x%X..." %
742
                        (count, start, addr))
427 farthen 743
        self.emcore.ipodnano2g_nanderase(addr, start, count)
227 theseven 744
        self.logger.info("done\n")
517 farthen 745
 
228 theseven 746
    @command
747
    def ipodnano2g_dumpnand(self, filenameprefix):
748
        """
749
            Target-specific function: ipodnano2g
750
            Dumps the whole NAND chip to four files
402 farthen 751
            <filenameprefix>: prefix of the files that will be created
228 theseven 752
        """
427 farthen 753
        info = self.emcore.ipodnano2g_getnandinfo()
228 theseven 754
        self.logger.info("Dumping NAND contents...")
755
        try:
756
            infofile = open(filenameprefix+"_info.txt", 'wb')
757
            datafile = open(filenameprefix+"_data.bin", 'wb')
758
            sparefile = open(filenameprefix+"_spare.bin", 'wb')
759
            statusfile = open(filenameprefix+"_status.bin", 'wb')
760
        except IOError:
761
            raise ArgumentError("Can not open file for writing!")
516 farthen 762
        infofile.write("NAND chip type: 0x%X\r\n" % info["type"])
763
        infofile.write("Number of banks: %d\r\n" % info["banks"])
764
        infofile.write("Number of blocks: %d\r\n" % info["blocks"])
765
        infofile.write("Number of user blocks: %d\r\n" % info["userblocks"])
766
        infofile.write("Pages per block: %d\r\n" % info["pagesperblock"])
228 theseven 767
        for i in range(info["banks"] * info["blocks"] * info["pagesperblock"] / 8192):
768
            self.logger.info(".")
427 farthen 769
            self.emcore.ipodnano2g_nandread(0x08000000, i * 8192, 8192, 1, 1)
770
            datafile.write(self.emcore.read(0x08000000, 0x01000000))
771
            sparefile.write(self.emcore.read(0x09000000, 0x00080000))
772
            statusfile.write(self.emcore.read(0x09080000, 0x00008000))
228 theseven 773
        infofile.close()
774
        datafile.close()
775
        sparefile.close()
776
        statusfile.close()
777
        self.logger.info("done\n")
517 farthen 778
 
228 theseven 779
    @command
780
    def ipodnano2g_wipenand(self, filename, force=False):
781
        """
782
            Target-specific function: ipodnano2g
783
            Wipes the whole NAND chip and logs the result to a file
402 farthen 784
            <filename>: location of the log file
785
            [force]: use this flag to suppress the 5 seconds delay
228 theseven 786
        """
382 farthen 787
        self.logger.warn("Wiping the whole NAND chip!\n")
228 theseven 788
        if force == False:
382 farthen 789
            self.logger.warn("If this was not what you intended press Ctrl-C NOW")
228 theseven 790
            for i in range(10):
791
                self.logger.info(".")
792
                time.sleep(1)
793
            self.logger.info("\n")
427 farthen 794
        info = self.emcore.ipodnano2g_getnandinfo()
228 theseven 795
        self.logger.info("Wiping NAND contents...")
796
        try:
797
            statusfile = open(filename, 'wb')
798
        except IOError:
799
            raise ArgumentError("Can not open file for writing!")
800
        for i in range(info["banks"] * info["blocks"] / 64):
801
            self.logger.info(".")
427 farthen 802
            self.emcore.ipodnano2g_nanderase(0x08000000, i * 64, 64)
803
            statusfile.write(self.emcore.read(0x08000000, 0x00000100))
228 theseven 804
        statusfile.close()
805
        self.logger.info("done\n")
517 farthen 806
 
346 theseven 807
    @command
808
    def ipodclassic_writebbt(self, tempaddr, filename):
809
        """
810
            Target-specific function: ipodclassic
811
            Uploads the bad block table <filename> to
812
            memory at <tempaddr> and writes it to the hard disk
813
        """
532 farthen 814
        tempaddr = to_int(tempaddr)
346 theseven 815
        try:
816
            f = open(filename, 'rb')
817
        except IOError:
818
            raise ArgumentError("File not readable. Does it exist?")
819
        self.logger.info("Writing bad block table to disk...")
427 farthen 820
        data = self.emcore.ipodclassic_writebbt(f.read(), tempaddr)
346 theseven 821
        f.close()
822
        self.logger.info(" done\n")
517 farthen 823
 
346 theseven 824
    @command
379 theseven 825
    def getvolumeinfo(self, volume):
826
        """
827
            Gathers some information about a storage volume used
404 farthen 828
            <volume>: volume id
379 theseven 829
        """
532 farthen 830
        volume = to_int(volume)
427 farthen 831
        data = self.emcore.storage_get_info(volume)
516 farthen 832
        self.logger.info("Sector size: %d\n" % data["sectorsize"])
833
        self.logger.info("Number of sectors: %d\n" % data["numsectors"])
834
        self.logger.info("Vendor: %s\n" % data["vendor"])
835
        self.logger.info("Product: %s\n" % data["product"])
836
        self.logger.info("Revision: %s\n" % data["revision"])
517 farthen 837
 
379 theseven 838
    @command
839
    def readrawstorage(self, volume, sector, count, addr):
840
        """
841
            Reads <count> sectors starting at <sector> from storage <volume> to memory at <addr>.
842
        """
532 farthen 843
        volume = to_int(volume)
844
        sector = to_int(sector)
845
        count = to_int(count)
846
        addr = to_int(addr)
379 theseven 847
        self.logger.info("Reading volume %s sectors %X - %X to %08X..." % (volume, sector, sector + count - 1, addr))
427 farthen 848
        self.emcore.storage_read_sectors_md(volume, sector, count, addr)
379 theseven 849
        self.logger.info("done\n")
517 farthen 850
 
379 theseven 851
    @command
852
    def writerawstorage(self, volume, sector, count, addr):
853
        """
854
            Writes memory contents at <addr> to <count> sectors starting at <sector> on storage <volume>.
855
        """
532 farthen 856
        volume = to_int(volume)
857
        sector = to_int(sector)
858
        count = to_int(count)
859
        addr = to_int(addr)
379 theseven 860
        self.logger.info("Writing %08X to volume %s sectors %X - %X..." % (addr, volume, sector, sector + count - 1))
427 farthen 861
        self.emcore.storage_write_sectors_md(volume, sector, count, addr)
379 theseven 862
        self.logger.info("done\n")
517 farthen 863
 
379 theseven 864
    @command
475 farthen 865
    def readrawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
379 theseven 866
        """
867
            Reads <count> sectors starting at <sector> from storage <volume> to file <file>,
402 farthen 868
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
379 theseven 869
        """
532 farthen 870
        volume = to_int(volume)
871
        sector = to_int(sector)
872
        count = to_int(count)
873
        buffsize = to_int(buffsize)
379 theseven 874
        try:
479 theseven 875
            f = open(file, 'wb')
876
        except IOError:
877
            raise ArgumentError("Could not open local file for writing.")
878
        try:
482 theseven 879
            storageinfo = self.emcore.storage_get_info(volume)
880
            buffsize = min(buffsize, storageinfo.sectorsize * count)
479 theseven 881
            if buffer is None:
882
                buffer = self.emcore.malloc(buffsize)
883
                malloc = True
884
            else:
532 farthen 885
                buffer = to_int(buffer)
479 theseven 886
                malloc = False
472 farthen 887
            try:
479 theseven 888
                self.logger.info("Reading volume %s sectors %X - %X to %s..." % (volume, sector, sector + count - 1, file))
889
                while count > 0:
890
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
891
                    self.emcore.storage_read_sectors_md(volume, sector, sectors, buffsize, buffer)
892
                    f.write(self.emcore.read(buffer, storageinfo.sectorsize * sectors))
893
                    sector = sector + sectors
894
                    count = count - sectors
895
            finally:
896
                if malloc == True:
897
                    self.emcore.free(buffer)
898
        finally:
472 farthen 899
            f.close()
379 theseven 900
        self.logger.info("done\n")
517 farthen 901
 
379 theseven 902
    @command
475 farthen 903
    def writerawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
379 theseven 904
        """
905
            Writes contents of <file> to <count> sectors starting at <sector> on storage <volume>,
402 farthen 906
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
379 theseven 907
        """
532 farthen 908
        volume = to_int(volume)
909
        sector = to_int(sector)
910
        count = to_int(count)
911
        buffsize = to_int(buffsize)
379 theseven 912
        try:
479 theseven 913
            f = open(file, 'rb')
914
        except IOError:
915
            raise ArgumentError("Could not open local file for reading.")
916
        try:
482 theseven 917
            storageinfo = self.emcore.storage_get_info(volume)
918
            buffsize = min(buffsize, storageinfo.sectorsize * count)
479 theseven 919
            if buffer is None:
920
                buffer = self.emcore.malloc(buffsize)
921
                malloc = True
922
            else:
532 farthen 923
                buffer = to_int(buffer)
479 theseven 924
                malloc = False
472 farthen 925
            try:
479 theseven 926
                self.logger.info("Writing %s to volume %s sectors %X - %X..." % (file, volume, sector, sector + count - 1))
927
                while count > 0:
928
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
929
                    bytes = storageinfo.sectorsize * sectors
930
                    data = f.read(bytes)
931
                    if len(data) == 0: break
932
                    while len(data) < bytes: data = data + f.read(bytes - len(data))
933
                    self.emcore.write(buffer, data)
934
                    self.emcore.storage_write_sectors_md(volume, sector, sectors, buffsize, buffer)
935
                    sector = sector + sectors
936
                    count = count - sectors
937
            finally:
938
                if malloc == True:
939
                    self.emcore.free(buffer)
940
        finally:
472 farthen 941
            f.close()
379 theseven 942
        self.logger.info("done\n")
517 farthen 943
 
379 theseven 944
    @command
346 theseven 945
    def mkdir(self, dirname):
946
        """
402 farthen 947
            Creates a directory with the name <dirname>
346 theseven 948
        """
516 farthen 949
        self.logger.info("Creating directory %s..." % dirname)
427 farthen 950
        self.emcore.dir_create(dirname)
346 theseven 951
        self.logger.info(" done\n")
517 farthen 952
 
346 theseven 953
    @command
954
    def rmdir(self, dirname):
955
        """
402 farthen 956
            Removes an empty directory with the name <dirname>
346 theseven 957
        """
516 farthen 958
        self.logger.info("Removing directory %s..." % dirname)
427 farthen 959
        self.emcore.dir_remove(dirname)
346 theseven 960
        self.logger.info(" done\n")
517 farthen 961
 
346 theseven 962
    @command
349 theseven 963
    def rm(self, filename):
346 theseven 964
        """
402 farthen 965
            Removes a file with the name <filename>
346 theseven 966
        """
516 farthen 967
        self.logger.info("Removing file %s..." % filename)
427 farthen 968
        self.emcore.file_unlink(filename)
346 theseven 969
        self.logger.info(" done\n")
517 farthen 970
 
346 theseven 971
    @command
406 theseven 972
    def rmtree(self, path):
973
        """
974
            Recursively removes a folder
975
            <path>: the folder to be removed
976
        """
427 farthen 977
        handle = self.emcore.dir_open(path)
406 theseven 978
        while True:
979
            try:
427 farthen 980
                entry = self.emcore.dir_read(handle)
406 theseven 981
                if entry.name == "." or entry.name == "..": continue
982
                elif entry.attributes & 0x10:
983
                    self.rmtree(path + "/" + entry.name)
984
                else: self.rm(path + "/" + entry.name)
985
            except: break
427 farthen 986
        self.emcore.dir_close(handle)
406 theseven 987
        self.rmdir(path)
517 farthen 988
 
406 theseven 989
    @command
352 theseven 990
    def mv(self, oldname, newname):
350 theseven 991
        """
402 farthen 992
            Renames or moves file or directory <oldname> to <newname>
350 theseven 993
        """
516 farthen 994
        self.logger.info("Renaming %s to %s..." % (oldname, newname))
427 farthen 995
        self.emcore.file_rename(oldname, newname)
350 theseven 996
        self.logger.info(" done\n")
517 farthen 997
 
350 theseven 998
    @command
475 farthen 999
    def get(self, remotename, localname, buffsize = 0x10000, buffer = None):
346 theseven 1000
        """
1001
            Downloads a file
402 farthen 1002
            <remotename>: filename on the device
1003
            <localname>: filename on the computer
472 farthen 1004
            [buffsize]: buffer size (optional)
402 farthen 1005
            [buffer]: buffer address (optional)
346 theseven 1006
        """
532 farthen 1007
        buffsize = to_int(buffsize)
346 theseven 1008
        try:
479 theseven 1009
            f = open(localname, 'wb')
1010
        except IOError:
1011
            raise ArgumentError("Could not open local file for writing.")
1012
        try:
482 theseven 1013
            fd = self.emcore.file_open(remotename, 0)
472 farthen 1014
            try:
482 theseven 1015
                size = self.emcore.file_size(fd)
1016
                buffsize = min(buffsize, size)
1017
                if buffer is None:
1018
                    buffer = self.emcore.malloc(buffsize)
1019
                    malloc = True
1020
                else:
532 farthen 1021
                    buffer = to_int(buffer)
482 theseven 1022
                    malloc = False
479 theseven 1023
                try:
516 farthen 1024
                    self.logger.info("Downloading file %s to %s..." % (remotename, localname))
479 theseven 1025
                    while size > 0:
488 theseven 1026
                        bytes = self.emcore.file_read(fd, buffsize, buffer).rc
479 theseven 1027
                        f.write(self.emcore.read(buffer, bytes))
1028
                        size = size - bytes
1029
                finally:
482 theseven 1030
                    if malloc == True:
1031
                        self.emcore.free(buffer)
479 theseven 1032
            finally:
482 theseven 1033
                self.emcore.file_close(fd)
479 theseven 1034
        finally:
472 farthen 1035
            f.close()
346 theseven 1036
        self.logger.info(" done\n")
517 farthen 1037
 
346 theseven 1038
    @command
475 farthen 1039
    def gettree(self, remotepath, localpath, buffsize = 0x10000, buffer = None):
406 theseven 1040
        """
1041
            Downloads a directory tree
1042
            <remotepath>: path on the device
1043
            <localpath>: path on the computer
472 farthen 1044
            [buffsize]: buffer size (optional)
406 theseven 1045
            [buffer]: buffer address (optional)
1046
        """
532 farthen 1047
        buffsize = to_int(buffsize)
479 theseven 1048
        handle = self.emcore.dir_open(remotepath)
472 farthen 1049
        try:
479 theseven 1050
            if buffer is None:
1051
                buffer = self.emcore.malloc(buffsize)
1052
                malloc = True
1053
            else:
532 farthen 1054
                buffer = to_int(buffer)
479 theseven 1055
                malloc = False
1056
            try:
1057
                try: os.mkdir(localpath)
1058
                except: pass
1059
                while True:
1060
                    try:
1061
                        entry = self.emcore.dir_read(handle)
1062
                    except: break
486 theseven 1063
                    if entry.name == "." or entry.name == "..": continue
1064
                    elif entry.attributes & 0x10:
1065
                        self.gettree(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffsize, buffer)
1066
                    else: self.get(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffsize, buffer)
479 theseven 1067
            finally:
1068
                if malloc == True:
1069
                    self.emcore.free(buffer)
1070
        finally:
472 farthen 1071
            self.emcore.dir_close(handle)
517 farthen 1072
 
406 theseven 1073
    @command
475 farthen 1074
    def put(self, localname, remotename, buffsize = 0x10000, buffer = None):
346 theseven 1075
        """
1076
            Uploads a file
406 theseven 1077
            <localname>: filename on the computer
402 farthen 1078
            <remotename>: filename on the device
472 farthen 1079
            [buffsize]: buffer size (optional)
402 farthen 1080
            [buffer]: buffer address (optional)
346 theseven 1081
        """
532 farthen 1082
        buffsize = to_int(buffsize)
346 theseven 1083
        try:
479 theseven 1084
            f = open(localname, 'rb')
1085
        except IOError:
1086
            raise ArgumentError("Could not open local file for reading.")
1087
        try:
482 theseven 1088
            buffsize = min(buffsize, os.path.getsize(localname))
479 theseven 1089
            if buffer is None:
1090
                buffer = self.emcore.malloc(buffsize)
1091
                malloc = True
1092
            else:
532 farthen 1093
                buffer = to_int(buffer)
479 theseven 1094
                malloc = False
472 farthen 1095
            try:
516 farthen 1096
                self.logger.info("Uploading file %s to %s..." % (localname, remotename))
479 theseven 1097
                fd = self.emcore.file_open(remotename, 0x15)
1098
                try:
1099
                    while True:
1100
                        data = f.read(buffsize)
1101
                        if len(data) == 0: break
1102
                        self.emcore.write(buffer, data)
1103
                        bytes = 0
1104
                        while bytes < len(data):
1105
                            bytes = bytes + self.emcore.file_write(fd, len(data) - bytes, buffer + bytes)
1106
                finally:
1107
                    self.emcore.file_close(fd)
1108
            finally:
1109
                if malloc == True:
1110
                    self.emcore.free(buffer)
1111
        finally:
472 farthen 1112
            f.close()
346 theseven 1113
        self.logger.info(" done\n")
517 farthen 1114
 
346 theseven 1115
    @command
475 farthen 1116
    def puttree(self, localpath, remotepath, buffsize = 0x10000, buffer = None):
406 theseven 1117
        """
1118
            Uploads a directory tree
1119
            <localpath>: path on the computer
1120
            <remotepath>: path on the device
472 farthen 1121
            [buffsize]: buffer size (optional)
406 theseven 1122
            [buffer]: buffer address (optional)
1123
        """
532 farthen 1124
        buffsize = to_int(buffsize)
472 farthen 1125
        if buffer is None:
1126
            buffer = self.emcore.malloc(buffsize)
1127
            malloc = True
1128
        else:
532 farthen 1129
            buffer = to_int(buffer)
472 farthen 1130
            malloc = False
1131
        try:
1132
            try: self.mkdir(remotepath)
1133
            except: self.logger.info(" failed\n")
1134
            pathlen = len(localpath)
1135
            for d in os.walk(localpath):
1136
                prefix = remotepath + "/" + d[0].replace("\\", "/")[pathlen:] + "/"
1137
                for dir in d[1]:
1138
                    if dir != ".svn":
1139
                        try: self.mkdir(prefix + dir)
1140
                        except: self.logger.info(" failed\n")
1141
                for f in d[2]:
479 theseven 1142
                    if prefix.find("/.svn/") == -1:
477 farthen 1143
                        self.put(d[0] + "/" + f, prefix + f, buffsize, buffer)
472 farthen 1144
        finally:
1145
            if malloc == True:
1146
                self.emcore.free(buffer)
517 farthen 1147
 
406 theseven 1148
    @command
351 theseven 1149
    def ls(self, path = "/"):
346 theseven 1150
        """
1151
            Lists all files in the specified path
402 farthen 1152
            [path]: the path which is listed
346 theseven 1153
        """
427 farthen 1154
        handle = self.emcore.dir_open(path)
516 farthen 1155
        self.logger.info("Directory listing of %s:\n" % path)
346 theseven 1156
        while True:
1157
            try:
427 farthen 1158
                entry = self.emcore.dir_read(handle)
346 theseven 1159
            except: break
486 theseven 1160
            if entry.attributes & 0x10: size = "DIR"
1161
            else: size = locale.format("%d", entry.size, True).rjust(13)
1162
            self.logger.info(entry.name.ljust(50) + " - " + size + "\n")
427 farthen 1163
        self.emcore.dir_close(handle)
474 farthen 1164
 
1165
    @command
483 theseven 1166
    def find(self, path = "/"):
1167
        """
1168
            Lists all files in the specified path, recursively
1169
            [path]: the path which is listed
1170
        """
1171
        handle = self.emcore.dir_open(path)
1172
        self.logger.info(path + "/\n")
1173
        while True:
1174
            try:
1175
                entry = self.emcore.dir_read(handle)
1176
            except: break
486 theseven 1177
            if entry.name == "." or entry.name == "..": continue
1178
            elif entry.attributes & 0x10: self.find(path + "/" + entry.name)
1179
            else: self.logger.info(path + "/" + entry.name + "\n")
483 theseven 1180
        self.emcore.dir_close(handle)
1181
 
1182
    @command
474 farthen 1183
    def malloc(self, size):
1184
        """ Allocates <size> bytes and returns a pointer to the allocated memory """
532 farthen 1185
        size = to_int(size)
474 farthen 1186
        self.logger.info("Allocating %d bytes of memory\n" % size)
1187
        addr = self.emcore.malloc(size)
518 farthen 1188
        self.logger.info("Allocated %d bytes of memory at 0x%X\n" % (size, addr))
474 farthen 1189
 
1190
    @command
1191
    def memalign(self, align, size):
1192
        """ Allocates <size> bytes aligned to <align> and returns a pointer to the allocated memory """
532 farthen 1193
        align = to_int(align)
1194
        size = to_int(size)
518 farthen 1195
        self.logger.info("Allocating %d bytes of memory aligned to 0x%X\n" % (size, align))
474 farthen 1196
        addr = self.emcore.memalign(align, size)
518 farthen 1197
        self.logger.info("Allocated %d bytes of memory at 0x%X\n" % (size, addr))
474 farthen 1198
 
1199
    @command
1200
    def realloc(self, ptr, size):
1201
        """ The size of the memory block pointed to by <ptr> is changed to the <size> bytes,
1202
            expanding or reducing the amount of memory available in the block.
1203
            Returns a pointer to the reallocated memory.
1204
        """
532 farthen 1205
        ptr = to_int(ptr)
1206
        size = to_int(size)
518 farthen 1207
        self.logger.info("Reallocating 0x%X to have the new size %d\n" % (ptr, size))
474 farthen 1208
        addr = self.emcore.realloc(ptr, size)
518 farthen 1209
        self.logger.info("Reallocated memory at 0x%X to 0x%X with the new size %d\n" % (ptr, addr, size))
474 farthen 1210
 
1211
    @command
1212
    def reownalloc(self, ptr, owner):
1213
        """ Changes the owner of the memory allocation <ptr> to the thread struct at addr <owner> """
532 farthen 1214
        ptr = to_int(ptr)
1215
        owner = to_int(owner)
518 farthen 1216
        self.logger.info("Changing owner of the memory region 0x%X to 0x%X\n" % (ptr, owner))
474 farthen 1217
        self.emcore.reownalloc(ptr, owner)
518 farthen 1218
        self.logger.info("Successfully changed owner of 0x%X to 0x%X\n" % (ptr, owner))
474 farthen 1219
 
1220
    @command
1221
    def free(self, ptr):
1222
        """ Frees the memory space pointed to by 'ptr' """
532 farthen 1223
        ptr = to_int(ptr)
518 farthen 1224
        self.logger.info("Freeing the memory region at 0x%X\n" % ptr)
474 farthen 1225
        self.emcore.free(ptr)
518 farthen 1226
        self.logger.info("Successfully freed the memory region at 0x%X\n" % ptr)
474 farthen 1227
 
1228
    @command
1229
    def free_all(self):
1230
        """ Frees all memory allocations created by the monitor thread """
1231
        self.logger.info("Freeing all memory allocations created by the monitor thread\n")
1232
        self.emcore.free_all()
1233
        self.logger.info("Successfully freed all memory allocations created by the monitor thread\n")
1234
 
346 theseven 1235
 
171 farthen 1236
if __name__ == "__main__":
1237
    if len(sys.argv) < 2:
502 farthen 1238
        usage("No command specified", docstring = False)
382 farthen 1239
    try:
1240
        interface = Commandline()
1241
        interface._parsecommand(sys.argv[1], sys.argv[2:])
1242
    except KeyboardInterrupt:
1243
        sys.exit()