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