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