Subversion Repositories freemyipod

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
82 benedikt93 1
#!/usr/bin/env python
64 benedikt93 2
#
3
#
171 farthen 4
#    Copyright 2010 TheSeven, benedikt93, Farthen
64 benedikt93 5
#
6
#
427 farthen 7
#    This file is part of emCORE.
64 benedikt93 8
#
427 farthen 9
#    emCORE is free software: you can redistribute it and/or
64 benedikt93 10
#    modify it under the terms of the GNU General Public License as
11
#    published by the Free Software Foundation, either version 2 of the
12
#    License, or (at your option) any later version.
13
#
427 farthen 14
#    emCORE is distributed in the hope that it will be useful,
64 benedikt93 15
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
16
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
#    See the GNU General Public License for more details.
18
#
82 benedikt93 19
#    You should have received a copy of the GNU General Public License
427 farthen 20
#    along with emCORE.  If not, see <http://www.gnu.org/licenses/>.
64 benedikt93 21
#
22
#
23
 
402 farthen 24
"""
427 farthen 25
    Command line interface to communicate with emCORE devices.
402 farthen 26
    Run it without arguments to see usage information.
27
"""
28
 
171 farthen 29
import sys
30
import os
176 farthen 31
import time
215 theseven 32
import struct
346 theseven 33
import locale
64 benedikt93 34
 
176 farthen 35
from functools import wraps
36
 
427 farthen 37
import libemcore
38
import libemcoredata
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:
68
        logger.log("Please provide a command and (if needed) parameters as command line arguments\n\n")
69
        logger.log("Available commands:\n\n")
82 benedikt93 70
    else:
171 farthen 71
        logger.log("\n")
72
    for function in sorted(doc.items()):
73
        function = function[0]
74
        if specific == False or specific == function:
396 farthen 75
            logger.log(function + " ", 2)
171 farthen 76
            for arg in doc[function]['args']:
77
                logger.log("<" + arg + "> ")
78
            if doc[function]['kwargs']:
412 farthen 79
                for kwarg, kwvalue in doc[function]['kwargs'].iteritems():
402 farthen 80
                    logger.log("[" + kwarg + " = " + str(kwvalue) + "] ")
171 farthen 81
            if doc[function]['varargs']:
82
                logger.log("<db1> ... <dbN>")
444 farthen 83
            if docstring and doc[function]['documentation']:
84
                logger.log("\n")
396 farthen 85
                logger.log(doc[function]['documentation']+"\n", 4)
86
            logger.log("\n")
171 farthen 87
    logger.log("\n")
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:
427 farthen 132
            self.emcore = libemcore.Emcore(loglevel = 2)
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:
164
            usage("No such command")
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):
211
        """ Generates a list of functions """
212
        usage(None, False, False)
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()
176 farthen 393
            self.logger.log(resp.data)
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()
176 farthen 417
            self.logger.log(resp.data)
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)
467
            self.logger.info("Thread id: "      + str(thread.id)+"\n", 4)
468
            self.logger.info("Thread type: "    + thread.type+"\n", 4)
469
            self.logger.info("Thread state: "   + thread.state+"\n", 4)
470
            self.logger.info("Block type: "     + thread.block_type+"\n", 4)
471
            self.logger.info("Blocked by: "     + self._hex(thread.blocked_by_ptr)+"\n", 4)
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)
475
            self.logger.info("Stack address: "  + self._hex(thread.stackaddr)+"\n", 4)
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)
318 theseven 481
                    self.logger.info("{0:3s}: 0x{1:08X}   ".format(registerrepr, thread.regs["r"+str(register)]))
177 farthen 482
                self.logger.info("\n")
396 farthen 483
            self.logger.info("cpsr: 0x{0:08X}".format(thread.regs.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:
894
            if buffer is None:
895
                buffer = self.emcore.malloc(buffsize)
896
                malloc = True
897
            else:
898
                buffer = self._hexint(buffer)
899
                malloc = False
472 farthen 900
            try:
479 theseven 901
                self.logger.info("Reading volume %s sectors %X - %X to %s..." % (volume, sector, sector + count - 1, file))
902
                storageinfo = self.emcore.storage_get_info(volume)
903
                while count > 0:
904
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
905
                    self.emcore.storage_read_sectors_md(volume, sector, sectors, buffsize, buffer)
906
                    f.write(self.emcore.read(buffer, storageinfo.sectorsize * sectors))
907
                    sector = sector + sectors
908
                    count = count - sectors
909
            finally:
910
                if malloc == True:
911
                    self.emcore.free(buffer)
912
        finally:
472 farthen 913
            f.close()
379 theseven 914
        self.logger.info("done\n")
915
 
916
    @command
475 farthen 917
    def writerawstoragefile(self, volume, sector, count, file, buffsize = 0x100000, buffer = None):
379 theseven 918
        """
919
            Writes contents of <file> to <count> sectors starting at <sector> on storage <volume>,
402 farthen 920
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
379 theseven 921
        """
922
        volume = self._hexint(volume)
923
        sector = self._hexint(sector)
924
        count = self._hexint(count)
925
        buffsize = self._hexint(buffsize)
926
        try:
479 theseven 927
            f = open(file, 'rb')
928
        except IOError:
929
            raise ArgumentError("Could not open local file for reading.")
930
        try:
931
            if buffer is None:
932
                buffer = self.emcore.malloc(buffsize)
933
                malloc = True
934
            else:
935
                buffer = self._hexint(buffer)
936
                malloc = False
472 farthen 937
            try:
479 theseven 938
                self.logger.info("Writing %s to volume %s sectors %X - %X..." % (file, volume, sector, sector + count - 1))
939
                storageinfo = self.emcore.storage_get_info(volume)
940
                while count > 0:
941
                    sectors = min(count, int(buffsize / storageinfo.sectorsize))
942
                    bytes = storageinfo.sectorsize * sectors
943
                    data = f.read(bytes)
944
                    if len(data) == 0: break
945
                    while len(data) < bytes: data = data + f.read(bytes - len(data))
946
                    self.emcore.write(buffer, data)
947
                    self.emcore.storage_write_sectors_md(volume, sector, sectors, buffsize, buffer)
948
                    sector = sector + sectors
949
                    count = count - sectors
950
            finally:
951
                if malloc == True:
952
                    self.emcore.free(buffer)
953
        finally:
472 farthen 954
            f.close()
379 theseven 955
        self.logger.info("done\n")
956
 
957
    @command
346 theseven 958
    def mkdir(self, dirname):
959
        """
402 farthen 960
            Creates a directory with the name <dirname>
346 theseven 961
        """
962
        self.logger.info("Creating directory " + dirname + "...")
427 farthen 963
        self.emcore.dir_create(dirname)
346 theseven 964
        self.logger.info(" done\n")
965
 
966
    @command
967
    def rmdir(self, dirname):
968
        """
402 farthen 969
            Removes an empty directory with the name <dirname>
346 theseven 970
        """
971
        self.logger.info("Removing directory " + dirname + "...")
427 farthen 972
        self.emcore.dir_remove(dirname)
346 theseven 973
        self.logger.info(" done\n")
974
 
975
    @command
349 theseven 976
    def rm(self, filename):
346 theseven 977
        """
402 farthen 978
            Removes a file with the name <filename>
346 theseven 979
        """
980
        self.logger.info("Removing file " + filename + "...")
427 farthen 981
        self.emcore.file_unlink(filename)
346 theseven 982
        self.logger.info(" done\n")
983
 
984
    @command
406 theseven 985
    def rmtree(self, path):
986
        """
987
            Recursively removes a folder
988
            <path>: the folder to be removed
989
        """
427 farthen 990
        handle = self.emcore.dir_open(path)
406 theseven 991
        while True:
992
            try:
427 farthen 993
                entry = self.emcore.dir_read(handle)
406 theseven 994
                if entry.name == "." or entry.name == "..": continue
995
                elif entry.attributes & 0x10:
996
                    self.rmtree(path + "/" + entry.name)
997
                else: self.rm(path + "/" + entry.name)
998
            except: break
427 farthen 999
        self.emcore.dir_close(handle)
406 theseven 1000
        self.rmdir(path)
1001
 
1002
    @command
352 theseven 1003
    def mv(self, oldname, newname):
350 theseven 1004
        """
402 farthen 1005
            Renames or moves file or directory <oldname> to <newname>
350 theseven 1006
        """
1007
        self.logger.info("Renaming " + oldname + " to " + newname + "...")
427 farthen 1008
        self.emcore.file_rename(oldname, newname)
350 theseven 1009
        self.logger.info(" done\n")
1010
 
1011
    @command
475 farthen 1012
    def get(self, remotename, localname, buffsize = 0x10000, buffer = None):
346 theseven 1013
        """
1014
            Downloads a file
402 farthen 1015
            <remotename>: filename on the device
1016
            <localname>: filename on the computer
472 farthen 1017
            [buffsize]: buffer size (optional)
402 farthen 1018
            [buffer]: buffer address (optional)
346 theseven 1019
        """
1020
        buffsize = self._hexint(buffsize)
1021
        try:
479 theseven 1022
            f = open(localname, 'wb')
1023
        except IOError:
1024
            raise ArgumentError("Could not open local file for writing.")
1025
        try:
1026
            if buffer is None:
1027
                buffer = self.emcore.malloc(buffsize)
1028
                malloc = True
1029
            else:
1030
                buffer = self._hexint(buffer)
1031
                malloc = False
472 farthen 1032
            try:
479 theseven 1033
                self.logger.info("Downloading file " + remotename + " to " + localname + "...")
1034
                fd = self.emcore.file_open(remotename, 0)
1035
                try:
1036
                    size = self.emcore.file_size(fd)
1037
                    while size > 0:
1038
                        bytes = self.emcore.file_read(fd, buffsize, buffer)
1039
                        f.write(self.emcore.read(buffer, bytes))
1040
                        size = size - bytes
1041
                finally:
1042
                    self.emcore.file_close(fd)
1043
            finally:
1044
                if malloc == True:
1045
                    self.emcore.free(buffer)
1046
        finally:
472 farthen 1047
            f.close()
346 theseven 1048
        self.logger.info(" done\n")
1049
 
1050
    @command
475 farthen 1051
    def gettree(self, remotepath, localpath, buffsize = 0x10000, buffer = None):
406 theseven 1052
        """
1053
            Downloads a directory tree
1054
            <remotepath>: path on the device
1055
            <localpath>: path on the computer
472 farthen 1056
            [buffsize]: buffer size (optional)
406 theseven 1057
            [buffer]: buffer address (optional)
1058
        """
1059
        buffsize = self._hexint(buffsize)
479 theseven 1060
        handle = self.emcore.dir_open(remotepath)
472 farthen 1061
        try:
479 theseven 1062
            if buffer is None:
1063
                buffer = self.emcore.malloc(buffsize)
1064
                malloc = True
1065
            else:
1066
                buffer = self._hexint(buffer)
1067
                malloc = False
1068
            try:
1069
                try: os.mkdir(localpath)
1070
                except: pass
1071
                while True:
1072
                    try:
1073
                        entry = self.emcore.dir_read(handle)
1074
                        if entry.name == "." or entry.name == "..": continue
1075
                        elif entry.attributes & 0x10:
1076
                            self.gettree(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffsize, buffer)
1077
                        else: self.get(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffsize, buffer)
1078
                    except: break
1079
            finally:
1080
                if malloc == True:
1081
                    self.emcore.free(buffer)
1082
        finally:
472 farthen 1083
            self.emcore.dir_close(handle)
406 theseven 1084
 
1085
    @command
475 farthen 1086
    def put(self, localname, remotename, buffsize = 0x10000, buffer = None):
346 theseven 1087
        """
1088
            Uploads a file
406 theseven 1089
            <localname>: filename on the computer
402 farthen 1090
            <remotename>: filename on the device
472 farthen 1091
            [buffsize]: buffer size (optional)
402 farthen 1092
            [buffer]: buffer address (optional)
346 theseven 1093
        """
1094
        buffsize = self._hexint(buffsize)
1095
        try:
479 theseven 1096
            f = open(localname, 'rb')
1097
        except IOError:
1098
            raise ArgumentError("Could not open local file for reading.")
1099
        try:
1100
            if buffer is None:
1101
                buffer = self.emcore.malloc(buffsize)
1102
                malloc = True
1103
            else:
1104
                buffer = self._hexint(buffer)
1105
                malloc = False
472 farthen 1106
            try:
479 theseven 1107
                self.logger.info("Uploading file " + localname + " to " + remotename + "...")
1108
                fd = self.emcore.file_open(remotename, 0x15)
1109
                try:
1110
                    while True:
1111
                        data = f.read(buffsize)
1112
                        if len(data) == 0: break
1113
                        self.emcore.write(buffer, data)
1114
                        bytes = 0
1115
                        while bytes < len(data):
1116
                            bytes = bytes + self.emcore.file_write(fd, len(data) - bytes, buffer + bytes)
1117
                finally:
1118
                    self.emcore.file_close(fd)
1119
            finally:
1120
                if malloc == True:
1121
                    self.emcore.free(buffer)
1122
        finally:
472 farthen 1123
            f.close()
346 theseven 1124
        self.logger.info(" done\n")
1125
 
1126
    @command
475 farthen 1127
    def puttree(self, localpath, remotepath, buffsize = 0x10000, buffer = None):
406 theseven 1128
        """
1129
            Uploads a directory tree
1130
            <localpath>: path on the computer
1131
            <remotepath>: path on the device
472 farthen 1132
            [buffsize]: buffer size (optional)
406 theseven 1133
            [buffer]: buffer address (optional)
1134
        """
1135
        buffsize = self._hexint(buffsize)
472 farthen 1136
        if buffer is None:
1137
            buffer = self.emcore.malloc(buffsize)
1138
            malloc = True
1139
        else:
1140
            buffer = self._hexint(buffer)
1141
            malloc = False
1142
        try:
1143
            try: self.mkdir(remotepath)
1144
            except: self.logger.info(" failed\n")
1145
            pathlen = len(localpath)
1146
            for d in os.walk(localpath):
1147
                prefix = remotepath + "/" + d[0].replace("\\", "/")[pathlen:] + "/"
1148
                for dir in d[1]:
1149
                    if dir != ".svn":
1150
                        try: self.mkdir(prefix + dir)
1151
                        except: self.logger.info(" failed\n")
1152
                for f in d[2]:
479 theseven 1153
                    if prefix.find("/.svn/") == -1:
477 farthen 1154
                        self.put(d[0] + "/" + f, prefix + f, buffsize, buffer)
472 farthen 1155
        finally:
1156
            if malloc == True:
1157
                self.emcore.free(buffer)
406 theseven 1158
 
1159
    @command
351 theseven 1160
    def ls(self, path = "/"):
346 theseven 1161
        """
1162
            Lists all files in the specified path
402 farthen 1163
            [path]: the path which is listed
346 theseven 1164
        """
427 farthen 1165
        handle = self.emcore.dir_open(path)
346 theseven 1166
        self.logger.info("Directory listing of " + path + ":\n")
1167
        while True:
1168
            try:
427 farthen 1169
                entry = self.emcore.dir_read(handle)
346 theseven 1170
                if entry.attributes & 0x10: size = "DIR"
1171
                else: size = locale.format("%d", entry.size, True).rjust(13)
1172
                self.logger.info(entry.name.ljust(50) + " - " + size + "\n")
1173
            except: break
427 farthen 1174
        self.emcore.dir_close(handle)
474 farthen 1175
 
1176
    @command
1177
    def malloc(self, size):
1178
        """ Allocates <size> bytes and returns a pointer to the allocated memory """
1179
        size = self._hexint(size)
1180
        self.logger.info("Allocating %d bytes of memory\n" % size)
1181
        addr = self.emcore.malloc(size)
1182
        self.logger.info("Allocated %d bytes of memory at 0x%x\n" % (size, addr))
1183
 
1184
    @command
1185
    def memalign(self, align, size):
1186
        """ Allocates <size> bytes aligned to <align> and returns a pointer to the allocated memory """
1187
        align = self._hexint(align)
1188
        size = self._hexint(size)
1189
        self.logger.info("Allocating %d bytes of memory aligned to 0x%x\n" % (size, align))
1190
        addr = self.emcore.memalign(align, size)
1191
        self.logger.info("Allocated %d bytes of memory at 0x%x\n" % (size, addr))
1192
 
1193
    @command
1194
    def realloc(self, ptr, size):
1195
        """ The size of the memory block pointed to by <ptr> is changed to the <size> bytes,
1196
            expanding or reducing the amount of memory available in the block.
1197
            Returns a pointer to the reallocated memory.
1198
        """
1199
        ptr = self._hexint(ptr)
1200
        size = self._hexint(size)
1201
        self.logger.info("Reallocating 0x%x to have the new size %d\n" % (ptr, size))
1202
        addr = self.emcore.realloc(ptr, size)
1203
        self.logger.info("Reallocated memory at 0x%x to 0x%x with the new size %d\n" % (ptr, addr, size))
1204
 
1205
    @command
1206
    def reownalloc(self, ptr, owner):
1207
        """ Changes the owner of the memory allocation <ptr> to the thread struct at addr <owner> """
1208
        ptr = self._hexint(ptr)
1209
        owner = self._hexint(owner)
478 farthen 1210
        self.logger.info("Changing owner of the memory region 0x%x to 0x%x\n" % (ptr, owner))
474 farthen 1211
        self.emcore.reownalloc(ptr, owner)
478 farthen 1212
        self.logger.info("Successfully changed owner of 0x%x to 0x%x\n" % (ptr, owner))
474 farthen 1213
 
1214
    @command
1215
    def free(self, ptr):
1216
        """ Frees the memory space pointed to by 'ptr' """
1217
        ptr = self._hexint(ptr)
1218
        self.logger.info("Freeing the memory region at 0x%x\n" % ptr)
1219
        self.emcore.free(ptr)
1220
        self.logger.info("Successfully freed the memory region at 0x%x\n" % ptr)
1221
 
1222
    @command
1223
    def free_all(self):
1224
        """ Frees all memory allocations created by the monitor thread """
1225
        self.logger.info("Freeing all memory allocations created by the monitor thread\n")
1226
        self.emcore.free_all()
1227
        self.logger.info("Successfully freed all memory allocations created by the monitor thread\n")
1228
 
346 theseven 1229
 
171 farthen 1230
if __name__ == "__main__":
1231
    if len(sys.argv) < 2:
1232
        usage("No command specified")
382 farthen 1233
    try:
1234
        interface = Commandline()
1235
        interface._parsecommand(sys.argv[1], sys.argv[2:])
1236
    except KeyboardInterrupt:
1237
        sys.exit()