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