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)
516 farthen 629
        self.logger.info("Running firmware at 0x%X. Bye.\n" % targetaddr)
442 farthen 630
        self.emcore.execfirmware(targetaddr, addr, size)
176 farthen 631
 
632
    @command
171 farthen 633
    def aesencrypt(self, addr, size, keyindex):
634
        """
172 farthen 635
            Encrypts a buffer using a hardware key
402 farthen 636
            <addr>: the starting address of the buffer
637
            <size>: the size of the buffer
638
            <keyindex>: the index of the key in the crypto unit
171 farthen 639
        """
640
        addr = self._hexint(addr)
641
        size = self._hexint(size)
642
        keyindex = self._hexint(keyindex)
427 farthen 643
        self.emcore.aesencrypt(addr, size, keyindex)
82 benedikt93 644
 
171 farthen 645
    @command
646
    def aesdecrypt(self, addr, size, keyindex):
647
        """
172 farthen 648
            Decrypts a buffer using a hardware key
402 farthen 649
            <addr>: the starting address of the buffer
650
            <size>: the size of the buffer
651
            <keyindex>: the index of the key in the crypto unit
171 farthen 652
        """
653
        addr = self._hexint(addr)
654
        size = self._hexint(size)
655
        keyindex = self._hexint(keyindex)
427 farthen 656
        self.emcore.aesdecrypt(addr, size, keyindex)
172 farthen 657
 
658
    @command
659
    def hmac_sha1(self, addr, size, destination):
660
        """
402 farthen 661
            Generates a HMAC-SHA1 hash of the buffer
662
            <addr>: the starting address of the buffer
663
            <size>: the size of the buffer
664
            <destination>: the location where the key will be stored
172 farthen 665
        """
666
        addr = self._hexint(addr)
667
        size = self._hexint(size)
668
        destination = self._hexint(destination)
669
        sha1size = 0x14
516 farthen 670
        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" %
671
                        (addr, size, destination, destination + sha1size))
427 farthen 672
        self.emcore.hmac_sha1(addr, size, destination)
172 farthen 673
        self.logger.info("done\n")
427 farthen 674
        data = self.emcore.read(destination, sha1size)
172 farthen 675
        hash = ord(data)
516 farthen 676
        self.logger.info("The generated hash is 0x%X\n" % hash)
517 farthen 677
 
227 theseven 678
    @command
679
    def ipodnano2g_getnandinfo(self):
680
        """
681
            Target-specific function: ipodnano2g
682
            Gathers some information about the NAND chip used
683
        """
427 farthen 684
        data = self.emcore.ipodnano2g_getnandinfo()
516 farthen 685
        self.logger.info("NAND chip type: 0x%X\n" % data["type"])
686
        self.logger.info("Number of banks: %d\n" % data["banks"])
687
        self.logger.info("Number of blocks: %d\n" % data["blocks"])
688
        self.logger.info("Number of user blocks: %d\n" % data["userblocks"])
689
        self.logger.info("Pages per block: %d\n" % data["pagesperblock"])
517 farthen 690
 
227 theseven 691
    @command
404 farthen 692
    def ipodnano2g_nandread(self, addr, start, count, doecc=True, checkempty=True):
227 theseven 693
        """
694
            Target-specific function: ipodnano2g
695
            Reads data from the NAND chip into memory
402 farthen 696
            <addr>: the memory location where the data is written to
697
            <start>: start block
698
            <count>: block count
404 farthen 699
            [doecc]: use ecc error correction data
700
            [checkempty]: set statusflags if pages are empty
227 theseven 701
        """
702
        addr = self._hexint(addr)
703
        start = self._hexint(start)
704
        count = self._hexint(count)
404 farthen 705
        doecc = self._bool(doecc)
706
        checkempty = self._bool(checkempty)
516 farthen 707
        self.logger.info("Reading 0x%X NAND pages starting at 0x%X to memory at 0x%X..." %
708
                        (count, start, addr))
427 farthen 709
        self.emcore.ipodnano2g_nandread(addr, start, count, doecc, checkempty)
227 theseven 710
        self.logger.info("done\n")
517 farthen 711
 
227 theseven 712
    @command
404 farthen 713
    def ipodnano2g_nandwrite(self, addr, start, count, doecc=True):
227 theseven 714
        """
715
            Target-specific function: ipodnano2g
716
            Writes data to the NAND chip
402 farthen 717
            <addr>: the memory location where the data is read from
718
            <start>: start block
719
            <count>: block count
404 farthen 720
            [doecc]: create ecc error correction data
227 theseven 721
        """
722
        addr = self._hexint(addr)
723
        start = self._hexint(start)
724
        count = self._hexint(count)
404 farthen 725
        doecc = self._bool(doecc)
516 farthen 726
        self.logger.info("Writing 0x%X NAND pages starting at 0x%X from memory at 0x%X..." %
727
                        (count, start, addr))
427 farthen 728
        self.emcore.ipodnano2g_nandwrite(addr, start, count, doecc)
227 theseven 729
        self.logger.info("done\n")
517 farthen 730
 
227 theseven 731
    @command
732
    def ipodnano2g_nanderase(self, addr, start, count):
733
        """
734
            Target-specific function: ipodnano2g
735
            Erases blocks on the NAND chip and stores the results to memory
402 farthen 736
            <addr>: the memory location where the results are stored
737
            <start>: start block
738
            <count>: block count
227 theseven 739
        """
740
        addr = self._hexint(addr)
741
        start = self._hexint(start)
742
        count = self._hexint(count)
516 farthen 743
        self.logger.info("Erasing 0x%X NAND pages starting at 0x%X and logging to 0x%X..." %
744
                        (count, start, addr))
427 farthen 745
        self.emcore.ipodnano2g_nanderase(addr, start, count)
227 theseven 746
        self.logger.info("done\n")
517 farthen 747
 
228 theseven 748
    @command
749
    def ipodnano2g_dumpnand(self, filenameprefix):
750
        """
751
            Target-specific function: ipodnano2g
752
            Dumps the whole NAND chip to four files
402 farthen 753
            <filenameprefix>: prefix of the files that will be created
228 theseven 754
        """
427 farthen 755
        info = self.emcore.ipodnano2g_getnandinfo()
228 theseven 756
        self.logger.info("Dumping NAND contents...")
757
        try:
758
            infofile = open(filenameprefix+"_info.txt", 'wb')
759
            datafile = open(filenameprefix+"_data.bin", 'wb')
760
            sparefile = open(filenameprefix+"_spare.bin", 'wb')
761
            statusfile = open(filenameprefix+"_status.bin", 'wb')
762
        except IOError:
763
            raise ArgumentError("Can not open file for writing!")
516 farthen 764
        infofile.write("NAND chip type: 0x%X\r\n" % info["type"])
765
        infofile.write("Number of banks: %d\r\n" % info["banks"])
766
        infofile.write("Number of blocks: %d\r\n" % info["blocks"])
767
        infofile.write("Number of user blocks: %d\r\n" % info["userblocks"])
768
        infofile.write("Pages per block: %d\r\n" % info["pagesperblock"])
228 theseven 769
        for i in range(info["banks"] * info["blocks"] * info["pagesperblock"] / 8192):
770
            self.logger.info(".")
427 farthen 771
            self.emcore.ipodnano2g_nandread(0x08000000, i * 8192, 8192, 1, 1)
772
            datafile.write(self.emcore.read(0x08000000, 0x01000000))
773
            sparefile.write(self.emcore.read(0x09000000, 0x00080000))
774
            statusfile.write(self.emcore.read(0x09080000, 0x00008000))
228 theseven 775
        infofile.close()
776
        datafile.close()
777
        sparefile.close()
778
        statusfile.close()
779
        self.logger.info("done\n")
517 farthen 780
 
228 theseven 781
    @command
782
    def ipodnano2g_wipenand(self, filename, force=False):
783
        """
784
            Target-specific function: ipodnano2g
785
            Wipes the whole NAND chip and logs the result to a file
402 farthen 786
            <filename>: location of the log file
787
            [force]: use this flag to suppress the 5 seconds delay
228 theseven 788
        """
382 farthen 789
        self.logger.warn("Wiping the whole NAND chip!\n")
228 theseven 790
        if force == False:
382 farthen 791
            self.logger.warn("If this was not what you intended press Ctrl-C NOW")
228 theseven 792
            for i in range(10):
793
                self.logger.info(".")
794
                time.sleep(1)
795
            self.logger.info("\n")
427 farthen 796
        info = self.emcore.ipodnano2g_getnandinfo()
228 theseven 797
        self.logger.info("Wiping NAND contents...")
798
        try:
799
            statusfile = open(filename, 'wb')
800
        except IOError:
801
            raise ArgumentError("Can not open file for writing!")
802
        for i in range(info["banks"] * info["blocks"] / 64):
803
            self.logger.info(".")
427 farthen 804
            self.emcore.ipodnano2g_nanderase(0x08000000, i * 64, 64)
805
            statusfile.write(self.emcore.read(0x08000000, 0x00000100))
228 theseven 806
        statusfile.close()
807
        self.logger.info("done\n")
517 farthen 808
 
346 theseven 809
    @command
810
    def ipodclassic_writebbt(self, tempaddr, filename):
811
        """
812
            Target-specific function: ipodclassic
813
            Uploads the bad block table <filename> to
814
            memory at <tempaddr> and writes it to the hard disk
815
        """
816
        tempaddr = self._hexint(tempaddr)
817
        try:
818
            f = open(filename, 'rb')
819
        except IOError:
820
            raise ArgumentError("File not readable. Does it exist?")
821
        self.logger.info("Writing bad block table to disk...")
427 farthen 822
        data = self.emcore.ipodclassic_writebbt(f.read(), tempaddr)
346 theseven 823
        f.close()
824
        self.logger.info(" done\n")
517 farthen 825
 
346 theseven 826
    @command
379 theseven 827
    def getvolumeinfo(self, volume):
828
        """
829
            Gathers some information about a storage volume used
404 farthen 830
            <volume>: volume id
379 theseven 831
        """
832
        volume = self._hexint(volume)
427 farthen 833
        data = self.emcore.storage_get_info(volume)
516 farthen 834
        self.logger.info("Sector size: %d\n" % data["sectorsize"])
835
        self.logger.info("Number of sectors: %d\n" % data["numsectors"])
836
        self.logger.info("Vendor: %s\n" % data["vendor"])
837
        self.logger.info("Product: %s\n" % data["product"])
838
        self.logger.info("Revision: %s\n" % data["revision"])
517 farthen 839
 
379 theseven 840
    @command
841
    def readrawstorage(self, volume, sector, count, addr):
842
        """
843
            Reads <count> sectors starting at <sector> from storage <volume> to memory at <addr>.
844
        """
845
        volume = self._hexint(volume)
846
        sector = self._hexint(sector)
847
        count = self._hexint(count)
848
        addr = self._hexint(addr)
849
        self.logger.info("Reading volume %s sectors %X - %X to %08X..." % (volume, sector, sector + count - 1, addr))
427 farthen 850
        self.emcore.storage_read_sectors_md(volume, sector, count, addr)
379 theseven 851
        self.logger.info("done\n")
517 farthen 852
 
379 theseven 853
    @command
854
    def writerawstorage(self, volume, sector, count, addr):
855
        """
856
            Writes memory contents at <addr> to <count> sectors starting at <sector> on storage <volume>.
857
        """
858
        volume = self._hexint(volume)
859
        sector = self._hexint(sector)
860
        count = self._hexint(count)
861
        addr = self._hexint(addr)
862
        self.logger.info("Writing %08X to volume %s sectors %X - %X..." % (addr, volume, sector, sector + count - 1))
427 farthen 863
        self.emcore.storage_write_sectors_md(volume, sector, count, addr)
379 theseven 864
        self.logger.info("done\n")
517 farthen 865
 
379 theseven 866
    @command
475 farthen 867
    def readrawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
379 theseven 868
        """
869
            Reads <count> sectors starting at <sector> from storage <volume> to file <file>,
402 farthen 870
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
379 theseven 871
        """
872
        volume = self._hexint(volume)
873
        sector = self._hexint(sector)
874
        count = self._hexint(count)
875
        buffsize = self._hexint(buffsize)
876
        try:
479 theseven 877
            f = open(file, 'wb')
878
        except IOError:
879
            raise ArgumentError("Could not open local file for writing.")
880
        try:
482 theseven 881
            storageinfo = self.emcore.storage_get_info(volume)
882
            buffsize = min(buffsize, storageinfo.sectorsize * count)
479 theseven 883
            if buffer is None:
884
                buffer = self.emcore.malloc(buffsize)
885
                malloc = True
886
            else:
887
                buffer = self._hexint(buffer)
888
                malloc = False
472 farthen 889
            try:
479 theseven 890
                self.logger.info("Reading volume %s sectors %X - %X to %s..." % (volume, sector, sector + count - 1, file))
891
                while count > 0:
892
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
893
                    self.emcore.storage_read_sectors_md(volume, sector, sectors, buffsize, buffer)
894
                    f.write(self.emcore.read(buffer, storageinfo.sectorsize * sectors))
895
                    sector = sector + sectors
896
                    count = count - sectors
897
            finally:
898
                if malloc == True:
899
                    self.emcore.free(buffer)
900
        finally:
472 farthen 901
            f.close()
379 theseven 902
        self.logger.info("done\n")
517 farthen 903
 
379 theseven 904
    @command
475 farthen 905
    def writerawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
379 theseven 906
        """
907
            Writes contents of <file> to <count> sectors starting at <sector> on storage <volume>,
402 farthen 908
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
379 theseven 909
        """
910
        volume = self._hexint(volume)
911
        sector = self._hexint(sector)
912
        count = self._hexint(count)
913
        buffsize = self._hexint(buffsize)
914
        try:
479 theseven 915
            f = open(file, 'rb')
916
        except IOError:
917
            raise ArgumentError("Could not open local file for reading.")
918
        try:
482 theseven 919
            storageinfo = self.emcore.storage_get_info(volume)
920
            buffsize = min(buffsize, storageinfo.sectorsize * count)
479 theseven 921
            if buffer is None:
922
                buffer = self.emcore.malloc(buffsize)
923
                malloc = True
924
            else:
925
                buffer = self._hexint(buffer)
926
                malloc = False
472 farthen 927
            try:
479 theseven 928
                self.logger.info("Writing %s to volume %s sectors %X - %X..." % (file, volume, sector, sector + count - 1))
929
                while count > 0:
930
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
931
                    bytes = storageinfo.sectorsize * sectors
932
                    data = f.read(bytes)
933
                    if len(data) == 0: break
934
                    while len(data) < bytes: data = data + f.read(bytes - len(data))
935
                    self.emcore.write(buffer, data)
936
                    self.emcore.storage_write_sectors_md(volume, sector, sectors, buffsize, buffer)
937
                    sector = sector + sectors
938
                    count = count - sectors
939
            finally:
940
                if malloc == True:
941
                    self.emcore.free(buffer)
942
        finally:
472 farthen 943
            f.close()
379 theseven 944
        self.logger.info("done\n")
517 farthen 945
 
379 theseven 946
    @command
346 theseven 947
    def mkdir(self, dirname):
948
        """
402 farthen 949
            Creates a directory with the name <dirname>
346 theseven 950
        """
516 farthen 951
        self.logger.info("Creating directory %s..." % dirname)
427 farthen 952
        self.emcore.dir_create(dirname)
346 theseven 953
        self.logger.info(" done\n")
517 farthen 954
 
346 theseven 955
    @command
956
    def rmdir(self, dirname):
957
        """
402 farthen 958
            Removes an empty directory with the name <dirname>
346 theseven 959
        """
516 farthen 960
        self.logger.info("Removing directory %s..." % dirname)
427 farthen 961
        self.emcore.dir_remove(dirname)
346 theseven 962
        self.logger.info(" done\n")
517 farthen 963
 
346 theseven 964
    @command
349 theseven 965
    def rm(self, filename):
346 theseven 966
        """
402 farthen 967
            Removes a file with the name <filename>
346 theseven 968
        """
516 farthen 969
        self.logger.info("Removing file %s..." % filename)
427 farthen 970
        self.emcore.file_unlink(filename)
346 theseven 971
        self.logger.info(" done\n")
517 farthen 972
 
346 theseven 973
    @command
406 theseven 974
    def rmtree(self, path):
975
        """
976
            Recursively removes a folder
977
            <path>: the folder to be removed
978
        """
427 farthen 979
        handle = self.emcore.dir_open(path)
406 theseven 980
        while True:
981
            try:
427 farthen 982
                entry = self.emcore.dir_read(handle)
406 theseven 983
                if entry.name == "." or entry.name == "..": continue
984
                elif entry.attributes & 0x10:
985
                    self.rmtree(path + "/" + entry.name)
986
                else: self.rm(path + "/" + entry.name)
987
            except: break
427 farthen 988
        self.emcore.dir_close(handle)
406 theseven 989
        self.rmdir(path)
517 farthen 990
 
406 theseven 991
    @command
352 theseven 992
    def mv(self, oldname, newname):
350 theseven 993
        """
402 farthen 994
            Renames or moves file or directory <oldname> to <newname>
350 theseven 995
        """
516 farthen 996
        self.logger.info("Renaming %s to %s..." % (oldname, newname))
427 farthen 997
        self.emcore.file_rename(oldname, newname)
350 theseven 998
        self.logger.info(" done\n")
517 farthen 999
 
350 theseven 1000
    @command
475 farthen 1001
    def get(self, remotename, localname, buffsize = 0x10000, buffer = None):
346 theseven 1002
        """
1003
            Downloads a file
402 farthen 1004
            <remotename>: filename on the device
1005
            <localname>: filename on the computer
472 farthen 1006
            [buffsize]: buffer size (optional)
402 farthen 1007
            [buffer]: buffer address (optional)
346 theseven 1008
        """
1009
        buffsize = self._hexint(buffsize)
1010
        try:
479 theseven 1011
            f = open(localname, 'wb')
1012
        except IOError:
1013
            raise ArgumentError("Could not open local file for writing.")
1014
        try:
482 theseven 1015
            fd = self.emcore.file_open(remotename, 0)
472 farthen 1016
            try:
482 theseven 1017
                size = self.emcore.file_size(fd)
1018
                buffsize = min(buffsize, size)
1019
                if buffer is None:
1020
                    buffer = self.emcore.malloc(buffsize)
1021
                    malloc = True
1022
                else:
1023
                    buffer = self._hexint(buffer)
1024
                    malloc = False
479 theseven 1025
                try:
516 farthen 1026
                    self.logger.info("Downloading file %s to %s..." % (remotename, localname))
479 theseven 1027
                    while size > 0:
488 theseven 1028
                        bytes = self.emcore.file_read(fd, buffsize, buffer).rc
479 theseven 1029
                        f.write(self.emcore.read(buffer, bytes))
1030
                        size = size - bytes
1031
                finally:
482 theseven 1032
                    if malloc == True:
1033
                        self.emcore.free(buffer)
479 theseven 1034
            finally:
482 theseven 1035
                self.emcore.file_close(fd)
479 theseven 1036
        finally:
472 farthen 1037
            f.close()
346 theseven 1038
        self.logger.info(" done\n")
517 farthen 1039
 
346 theseven 1040
    @command
475 farthen 1041
    def gettree(self, remotepath, localpath, buffsize = 0x10000, buffer = None):
406 theseven 1042
        """
1043
            Downloads a directory tree
1044
            <remotepath>: path on the device
1045
            <localpath>: path on the computer
472 farthen 1046
            [buffsize]: buffer size (optional)
406 theseven 1047
            [buffer]: buffer address (optional)
1048
        """
1049
        buffsize = self._hexint(buffsize)
479 theseven 1050
        handle = self.emcore.dir_open(remotepath)
472 farthen 1051
        try:
479 theseven 1052
            if buffer is None:
1053
                buffer = self.emcore.malloc(buffsize)
1054
                malloc = True
1055
            else:
1056
                buffer = self._hexint(buffer)
1057
                malloc = False
1058
            try:
1059
                try: os.mkdir(localpath)
1060
                except: pass
1061
                while True:
1062
                    try:
1063
                        entry = self.emcore.dir_read(handle)
1064
                    except: break
486 theseven 1065
                    if entry.name == "." or entry.name == "..": continue
1066
                    elif entry.attributes & 0x10:
1067
                        self.gettree(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffsize, buffer)
1068
                    else: self.get(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffsize, buffer)
479 theseven 1069
            finally:
1070
                if malloc == True:
1071
                    self.emcore.free(buffer)
1072
        finally:
472 farthen 1073
            self.emcore.dir_close(handle)
517 farthen 1074
 
406 theseven 1075
    @command
475 farthen 1076
    def put(self, localname, remotename, buffsize = 0x10000, buffer = None):
346 theseven 1077
        """
1078
            Uploads a file
406 theseven 1079
            <localname>: filename on the computer
402 farthen 1080
            <remotename>: filename on the device
472 farthen 1081
            [buffsize]: buffer size (optional)
402 farthen 1082
            [buffer]: buffer address (optional)
346 theseven 1083
        """
1084
        buffsize = self._hexint(buffsize)
1085
        try:
479 theseven 1086
            f = open(localname, 'rb')
1087
        except IOError:
1088
            raise ArgumentError("Could not open local file for reading.")
1089
        try:
482 theseven 1090
            buffsize = min(buffsize, os.path.getsize(localname))
479 theseven 1091
            if buffer is None:
1092
                buffer = self.emcore.malloc(buffsize)
1093
                malloc = True
1094
            else:
1095
                buffer = self._hexint(buffer)
1096
                malloc = False
472 farthen 1097
            try:
516 farthen 1098
                self.logger.info("Uploading file %s to %s..." % (localname, remotename))
479 theseven 1099
                fd = self.emcore.file_open(remotename, 0x15)
1100
                try:
1101
                    while True:
1102
                        data = f.read(buffsize)
1103
                        if len(data) == 0: break
1104
                        self.emcore.write(buffer, data)
1105
                        bytes = 0
1106
                        while bytes < len(data):
1107
                            bytes = bytes + self.emcore.file_write(fd, len(data) - bytes, buffer + bytes)
1108
                finally:
1109
                    self.emcore.file_close(fd)
1110
            finally:
1111
                if malloc == True:
1112
                    self.emcore.free(buffer)
1113
        finally:
472 farthen 1114
            f.close()
346 theseven 1115
        self.logger.info(" done\n")
517 farthen 1116
 
346 theseven 1117
    @command
475 farthen 1118
    def puttree(self, localpath, remotepath, buffsize = 0x10000, buffer = None):
406 theseven 1119
        """
1120
            Uploads a directory tree
1121
            <localpath>: path on the computer
1122
            <remotepath>: path on the device
472 farthen 1123
            [buffsize]: buffer size (optional)
406 theseven 1124
            [buffer]: buffer address (optional)
1125
        """
1126
        buffsize = self._hexint(buffsize)
472 farthen 1127
        if buffer is None:
1128
            buffer = self.emcore.malloc(buffsize)
1129
            malloc = True
1130
        else:
1131
            buffer = self._hexint(buffer)
1132
            malloc = False
1133
        try:
1134
            try: self.mkdir(remotepath)
1135
            except: self.logger.info(" failed\n")
1136
            pathlen = len(localpath)
1137
            for d in os.walk(localpath):
1138
                prefix = remotepath + "/" + d[0].replace("\\", "/")[pathlen:] + "/"
1139
                for dir in d[1]:
1140
                    if dir != ".svn":
1141
                        try: self.mkdir(prefix + dir)
1142
                        except: self.logger.info(" failed\n")
1143
                for f in d[2]:
479 theseven 1144
                    if prefix.find("/.svn/") == -1:
477 farthen 1145
                        self.put(d[0] + "/" + f, prefix + f, buffsize, buffer)
472 farthen 1146
        finally:
1147
            if malloc == True:
1148
                self.emcore.free(buffer)
517 farthen 1149
 
406 theseven 1150
    @command
351 theseven 1151
    def ls(self, path = "/"):
346 theseven 1152
        """
1153
            Lists all files in the specified path
402 farthen 1154
            [path]: the path which is listed
346 theseven 1155
        """
427 farthen 1156
        handle = self.emcore.dir_open(path)
516 farthen 1157
        self.logger.info("Directory listing of %s:\n" % path)
346 theseven 1158
        while True:
1159
            try:
427 farthen 1160
                entry = self.emcore.dir_read(handle)
346 theseven 1161
            except: break
486 theseven 1162
            if entry.attributes & 0x10: size = "DIR"
1163
            else: size = locale.format("%d", entry.size, True).rjust(13)
1164
            self.logger.info(entry.name.ljust(50) + " - " + size + "\n")
427 farthen 1165
        self.emcore.dir_close(handle)
474 farthen 1166
 
1167
    @command
483 theseven 1168
    def find(self, path = "/"):
1169
        """
1170
            Lists all files in the specified path, recursively
1171
            [path]: the path which is listed
1172
        """
1173
        handle = self.emcore.dir_open(path)
1174
        self.logger.info(path + "/\n")
1175
        while True:
1176
            try:
1177
                entry = self.emcore.dir_read(handle)
1178
            except: break
486 theseven 1179
            if entry.name == "." or entry.name == "..": continue
1180
            elif entry.attributes & 0x10: self.find(path + "/" + entry.name)
1181
            else: self.logger.info(path + "/" + entry.name + "\n")
483 theseven 1182
        self.emcore.dir_close(handle)
1183
 
1184
    @command
474 farthen 1185
    def malloc(self, size):
1186
        """ Allocates <size> bytes and returns a pointer to the allocated memory """
1187
        size = self._hexint(size)
1188
        self.logger.info("Allocating %d bytes of memory\n" % size)
1189
        addr = self.emcore.malloc(size)
1190
        self.logger.info("Allocated %d bytes of memory at 0x%x\n" % (size, addr))
1191
 
1192
    @command
1193
    def memalign(self, align, size):
1194
        """ Allocates <size> bytes aligned to <align> and returns a pointer to the allocated memory """
1195
        align = self._hexint(align)
1196
        size = self._hexint(size)
1197
        self.logger.info("Allocating %d bytes of memory aligned to 0x%x\n" % (size, align))
1198
        addr = self.emcore.memalign(align, size)
1199
        self.logger.info("Allocated %d bytes of memory at 0x%x\n" % (size, addr))
1200
 
1201
    @command
1202
    def realloc(self, ptr, size):
1203
        """ The size of the memory block pointed to by <ptr> is changed to the <size> bytes,
1204
            expanding or reducing the amount of memory available in the block.
1205
            Returns a pointer to the reallocated memory.
1206
        """
1207
        ptr = self._hexint(ptr)
1208
        size = self._hexint(size)
1209
        self.logger.info("Reallocating 0x%x to have the new size %d\n" % (ptr, size))
1210
        addr = self.emcore.realloc(ptr, size)
1211
        self.logger.info("Reallocated memory at 0x%x to 0x%x with the new size %d\n" % (ptr, addr, size))
1212
 
1213
    @command
1214
    def reownalloc(self, ptr, owner):
1215
        """ Changes the owner of the memory allocation <ptr> to the thread struct at addr <owner> """
1216
        ptr = self._hexint(ptr)
1217
        owner = self._hexint(owner)
478 farthen 1218
        self.logger.info("Changing owner of the memory region 0x%x to 0x%x\n" % (ptr, owner))
474 farthen 1219
        self.emcore.reownalloc(ptr, owner)
478 farthen 1220
        self.logger.info("Successfully changed owner of 0x%x to 0x%x\n" % (ptr, owner))
474 farthen 1221
 
1222
    @command
1223
    def free(self, ptr):
1224
        """ Frees the memory space pointed to by 'ptr' """
1225
        ptr = self._hexint(ptr)
1226
        self.logger.info("Freeing the memory region at 0x%x\n" % ptr)
1227
        self.emcore.free(ptr)
1228
        self.logger.info("Successfully freed the memory region at 0x%x\n" % ptr)
1229
 
1230
    @command
1231
    def free_all(self):
1232
        """ Frees all memory allocations created by the monitor thread """
1233
        self.logger.info("Freeing all memory allocations created by the monitor thread\n")
1234
        self.emcore.free_all()
1235
        self.logger.info("Successfully freed all memory allocations created by the monitor thread\n")
1236
 
346 theseven 1237
 
171 farthen 1238
if __name__ == "__main__":
1239
    if len(sys.argv) < 2:
502 farthen 1240
        usage("No command specified", docstring = False)
382 farthen 1241
    try:
1242
        interface = Commandline()
1243
        interface._parsecommand(sys.argv[1], sys.argv[2:])
1244
    except KeyboardInterrupt:
1245
        sys.exit()