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:
134
            self.logger.error("No emCORE device found!")
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:
152
                self.logger.error("This function is not implemented yet!")
427 farthen 153
            except libemcore.DeviceError, e:
171 farthen 154
                self.logger.error(str(e))
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 + "()":
158
                    self.logger.error(usage("Argument Error in '" + func + "': Wrong argument count", specific=func))
159
                else:
160
                    raise
427 farthen 161
            except libemcore.usb.core.USBError:
341 farthen 162
                self.logger.error("There is a problem with the USB connection.")
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) + \
234
                             "\n data out: " + str(self.emcore.lib.dev.packetsizelimit.dout))
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
                             " - " + \
427 farthen 241
                             self._hex(self.emcore.lib.dev.usermem.upper - 1))
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())
452 theseven 567
        self.logger.info("Executed emCORE application as thread " + self._hex(data.thread))
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)
173 farthen 689
        self.logger.info("The generated hash is "+self._hex(hash))
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")
702
        self.logger.info("Pages per block: "        + str(data["pagesperblock"]))
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")
851
        self.logger.info("Revision: "+data["revision"])
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
472 farthen 880
    def readrawstoragefile(self, volume, sector, count, file, buffsize = 100000, 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)
472 farthen 889
        if buffer is None:
890
            buffer = self.emcore.malloc(buffsize)
891
            malloc = True
892
        else:
893
            buffer = self._hexint(buffer)
894
            malloc = False
379 theseven 895
        try:
472 farthen 896
            try:
897
                f = open(file, 'wb')
898
            except IOError:
899
                raise ArgumentError("Could not open local file for writing.")
900
            self.logger.info("Reading volume %s sectors %X - %X to %s..." % (volume, sector, sector + count - 1, file))
901
            storageinfo = self.emcore.storage_get_info(volume)
902
            while count > 0:
903
                sectors = min(count, int(buffsize / storageinfo.sectorsize))
904
                self.emcore.storage_read_sectors_md(volume, sector, sectors, buffsize, buffer)
905
                f.write(self.emcore.read(buffer, storageinfo.sectorsize * sectors))
906
                sector = sector + sectors
907
                count = count - sectors
908
            f.close()
909
        finally:
910
            if malloc == True:
911
                self.emcore.free(buffer)
379 theseven 912
        self.logger.info("done\n")
913
 
914
    @command
472 farthen 915
    def writerawstoragefile(self, volume, sector, count, file, buffsize = 100000, buffer = None):
379 theseven 916
        """
917
            Writes contents of <file> to <count> sectors starting at <sector> on storage <volume>,
402 farthen 918
            buffering them in memory at [buffer] in chunks of [buffsize] bytes (both optional).
379 theseven 919
        """
920
        volume = self._hexint(volume)
921
        sector = self._hexint(sector)
922
        count = self._hexint(count)
923
        buffsize = self._hexint(buffsize)
472 farthen 924
        if buffer is None:
925
            buffer = self.emcore.malloc(buffsize)
926
            malloc = True
927
        else:
928
            buffer = self._hexint(buffer)
929
            malloc = False
379 theseven 930
        try:
472 farthen 931
            try:
932
                f = open(file, 'rb')
933
            except IOError:
934
                raise ArgumentError("Could not open local file for reading.")
935
            self.logger.info("Writing %s to volume %s sectors %X - %X..." % (file, volume, sector, sector + count - 1))
936
            storageinfo = self.emcore.storage_get_info(volume)
937
            while count > 0:
938
                sectors = min(count, int(buffsize / storageinfo.sectorsize))
939
                bytes = storageinfo.sectorsize * sectors
940
                data = f.read(bytes)
941
                if len(data) == 0: break
942
                while len(data) < bytes: data = data + f.read(bytes - len(data))
943
                self.emcore.write(buffer, data)
944
                self.emcore.storage_write_sectors_md(volume, sector, sectors, buffsize, buffer)
945
                sector = sector + sectors
946
                count = count - sectors
947
            f.close()
948
        finally:
949
            if malloc == True:
950
                self.emcore.free(buffer)
379 theseven 951
        self.logger.info("done\n")
952
 
953
    @command
346 theseven 954
    def mkdir(self, dirname):
955
        """
402 farthen 956
            Creates a directory with the name <dirname>
346 theseven 957
        """
958
        self.logger.info("Creating directory " + dirname + "...")
427 farthen 959
        self.emcore.dir_create(dirname)
346 theseven 960
        self.logger.info(" done\n")
961
 
962
    @command
963
    def rmdir(self, dirname):
964
        """
402 farthen 965
            Removes an empty directory with the name <dirname>
346 theseven 966
        """
967
        self.logger.info("Removing directory " + dirname + "...")
427 farthen 968
        self.emcore.dir_remove(dirname)
346 theseven 969
        self.logger.info(" done\n")
970
 
971
    @command
349 theseven 972
    def rm(self, filename):
346 theseven 973
        """
402 farthen 974
            Removes a file with the name <filename>
346 theseven 975
        """
976
        self.logger.info("Removing file " + filename + "...")
427 farthen 977
        self.emcore.file_unlink(filename)
346 theseven 978
        self.logger.info(" done\n")
979
 
980
    @command
406 theseven 981
    def rmtree(self, path):
982
        """
983
            Recursively removes a folder
984
            <path>: the folder to be removed
985
        """
427 farthen 986
        handle = self.emcore.dir_open(path)
406 theseven 987
        while True:
988
            try:
427 farthen 989
                entry = self.emcore.dir_read(handle)
406 theseven 990
                if entry.name == "." or entry.name == "..": continue
991
                elif entry.attributes & 0x10:
992
                    self.rmtree(path + "/" + entry.name)
993
                else: self.rm(path + "/" + entry.name)
994
            except: break
427 farthen 995
        self.emcore.dir_close(handle)
406 theseven 996
        self.rmdir(path)
997
 
998
    @command
352 theseven 999
    def mv(self, oldname, newname):
350 theseven 1000
        """
402 farthen 1001
            Renames or moves file or directory <oldname> to <newname>
350 theseven 1002
        """
1003
        self.logger.info("Renaming " + oldname + " to " + newname + "...")
427 farthen 1004
        self.emcore.file_rename(oldname, newname)
350 theseven 1005
        self.logger.info(" done\n")
1006
 
1007
    @command
472 farthen 1008
    def get(self, remotename, localname, buffsize = 10000, buffer = None):
346 theseven 1009
        """
1010
            Downloads a file
402 farthen 1011
            <remotename>: filename on the device
1012
            <localname>: filename on the computer
472 farthen 1013
            [buffsize]: buffer size (optional)
402 farthen 1014
            [buffer]: buffer address (optional)
346 theseven 1015
        """
1016
        buffsize = self._hexint(buffsize)
472 farthen 1017
        if buffer is None:
1018
            buffer = self.emcore.malloc(buffsize)
1019
            malloc = True
1020
        else:
1021
            buffer = self._hexint(buffer)
1022
            malloc = False
346 theseven 1023
        try:
472 farthen 1024
            try:
1025
                f = open(localname, 'wb')
1026
            except IOError:
1027
                raise ArgumentError("Could not open local file for writing.")
1028
            self.logger.info("Downloading file " + remotename + " to " + localname + "...")
1029
            fd = self.emcore.file_open(remotename, 0)
1030
            size = self.emcore.file_size(fd)
1031
            while size > 0:
1032
                bytes = self.emcore.file_read(fd, buffer, buffsize)
1033
                f.write(self.emcore.read(buffer, bytes))
1034
                size = size - bytes
1035
            self.emcore.file_close(fd)
1036
            f.close()
1037
        finally:
1038
            if malloc == True:
1039
                self.emcore.free(buffer)
346 theseven 1040
        self.logger.info(" done\n")
1041
 
1042
    @command
472 farthen 1043
    def gettree(self, remotepath, localpath, buffsize = 10000, buffer = None):
406 theseven 1044
        """
1045
            Downloads a directory tree
1046
            <remotepath>: path on the device
1047
            <localpath>: path on the computer
472 farthen 1048
            [buffsize]: buffer size (optional)
406 theseven 1049
            [buffer]: buffer address (optional)
1050
        """
1051
        buffsize = self._hexint(buffsize)
472 farthen 1052
        if buffer is None:
1053
            buffer = self.emcore.malloc(buffsize)
1054
            malloc = True
1055
        else:
1056
            buffer = self._hexint(buffer)
1057
            malloc = False
1058
        try:
1059
            try: os.mkdir(localpath)
1060
            except: pass
406 theseven 1061
 
472 farthen 1062
            handle = self.emcore.dir_open(remotepath)
1063
            while True:
1064
                try:
1065
                    entry = self.emcore.dir_read(handle)
1066
                    if entry.name == "." or entry.name == "..": continue
1067
                    elif entry.attributes & 0x10:
1068
                        self.gettree(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffer, buffsize)
1069
                    else: self.get(remotepath + "/" + entry.name, localpath + "/" + entry.name, buffer, buffsize)
1070
                except: break
1071
            self.emcore.dir_close(handle)
1072
        finally:
1073
            if malloc == True:
1074
                self.emcore.free(buffer)
406 theseven 1075
 
1076
    @command
472 farthen 1077
    def put(self, localname, remotename, buffsize = 10000, buffer = None):
346 theseven 1078
        """
1079
            Uploads a file
406 theseven 1080
            <localname>: filename on the computer
402 farthen 1081
            <remotename>: filename on the device
472 farthen 1082
            [buffsize]: buffer size (optional)
402 farthen 1083
            [buffer]: buffer address (optional)
346 theseven 1084
        """
1085
        buffsize = self._hexint(buffsize)
472 farthen 1086
        if buffer is None:
1087
            buffer = self.emcore.malloc(buffsize)
1088
            malloc = True
1089
        else:
1090
            buffer = self._hexint(buffer)
1091
            malloc = False
346 theseven 1092
        try:
472 farthen 1093
            try:
1094
                f = open(localname, 'rb')
1095
            except IOError:
1096
                raise ArgumentError("Could not open local file for reading.")
1097
            self.logger.info("Uploading file " + localname + " to " + remotename + "...")
1098
            fd = self.emcore.file_open(remotename, 0x15)
1099
            while True:
1100
                data = f.read(buffsize)
1101
                if len(data) == 0: break
1102
                self.emcore.write(buffer, data)
1103
                bytes = 0
1104
                while bytes < len(data):
1105
                    bytes = bytes + self.emcore.file_write(fd, buffer + bytes, len(data) - bytes)
1106
            self.emcore.file_close(fd)
1107
            f.close()
1108
        finally:
1109
            if malloc == True:
1110
                self.emcore.free(buffer)
346 theseven 1111
        self.logger.info(" done\n")
1112
 
1113
    @command
472 farthen 1114
    def puttree(self, localpath, remotepath, buffsize = 10000, buffer = None):
406 theseven 1115
        """
1116
            Uploads a directory tree
1117
            <localpath>: path on the computer
1118
            <remotepath>: path on the device
472 farthen 1119
            [buffsize]: buffer size (optional)
406 theseven 1120
            [buffer]: buffer address (optional)
1121
        """
1122
        buffsize = self._hexint(buffsize)
472 farthen 1123
        if buffer is None:
1124
            buffer = self.emcore.malloc(buffsize)
1125
            malloc = True
1126
        else:
1127
            buffer = self._hexint(buffer)
1128
            malloc = False
1129
        try:
1130
            try: self.mkdir(remotepath)
1131
            except: self.logger.info(" failed\n")
1132
            pathlen = len(localpath)
1133
            for d in os.walk(localpath):
1134
                prefix = remotepath + "/" + d[0].replace("\\", "/")[pathlen:] + "/"
1135
                for dir in d[1]:
1136
                    if dir != ".svn":
1137
                        try: self.mkdir(prefix + dir)
1138
                        except: self.logger.info(" failed\n")
1139
                for f in d[2]:
1140
                    if not prefix.find("/.svn/") > -1:
1141
                        self.put(d[0] + "/" + f, prefix + f, buffer, buffsize)
1142
        finally:
1143
            if malloc == True:
1144
                self.emcore.free(buffer)
406 theseven 1145
 
1146
    @command
351 theseven 1147
    def ls(self, path = "/"):
346 theseven 1148
        """
1149
            Lists all files in the specified path
402 farthen 1150
            [path]: the path which is listed
346 theseven 1151
        """
427 farthen 1152
        handle = self.emcore.dir_open(path)
346 theseven 1153
        self.logger.info("Directory listing of " + path + ":\n")
1154
        while True:
1155
            try:
427 farthen 1156
                entry = self.emcore.dir_read(handle)
346 theseven 1157
                if entry.attributes & 0x10: size = "DIR"
1158
                else: size = locale.format("%d", entry.size, True).rjust(13)
1159
                self.logger.info(entry.name.ljust(50) + " - " + size + "\n")
1160
            except: break
427 farthen 1161
        self.emcore.dir_close(handle)
474 farthen 1162
 
1163
    @command
1164
    def malloc(self, size):
1165
        """ Allocates <size> bytes and returns a pointer to the allocated memory """
1166
        size = self._hexint(size)
1167
        self.logger.info("Allocating %d bytes of memory\n" % size)
1168
        addr = self.emcore.malloc(size)
1169
        self.logger.info("Allocated %d bytes of memory at 0x%x\n" % (size, addr))
1170
 
1171
    @command
1172
    def memalign(self, align, size):
1173
        """ Allocates <size> bytes aligned to <align> and returns a pointer to the allocated memory """
1174
        align = self._hexint(align)
1175
        size = self._hexint(size)
1176
        self.logger.info("Allocating %d bytes of memory aligned to 0x%x\n" % (size, align))
1177
        addr = self.emcore.memalign(align, size)
1178
        self.logger.info("Allocated %d bytes of memory at 0x%x\n" % (size, addr))
1179
 
1180
    @command
1181
    def realloc(self, ptr, size):
1182
        """ The size of the memory block pointed to by <ptr> is changed to the <size> bytes,
1183
            expanding or reducing the amount of memory available in the block.
1184
            Returns a pointer to the reallocated memory.
1185
        """
1186
        ptr = self._hexint(ptr)
1187
        size = self._hexint(size)
1188
        self.logger.info("Reallocating 0x%x to have the new size %d\n" % (ptr, size))
1189
        addr = self.emcore.realloc(ptr, size)
1190
        self.logger.info("Reallocated memory at 0x%x to 0x%x with the new size %d\n" % (ptr, addr, size))
1191
 
1192
    @command
1193
    def reownalloc(self, ptr, owner):
1194
        """ Changes the owner of the memory allocation <ptr> to the thread struct at addr <owner> """
1195
        ptr = self._hexint(ptr)
1196
        owner = self._hexint(owner)
1197
        self.logger.info("Changing owner of the memory region 0x%x to 0x%x" % (ptr, owner))
1198
        self.emcore.reownalloc(ptr, owner)
1199
        self.logger.info("Successfully changed owner of 0x%x to 0x%x" % (ptr, owner))
1200
 
1201
    @command
1202
    def free(self, ptr):
1203
        """ Frees the memory space pointed to by 'ptr' """
1204
        ptr = self._hexint(ptr)
1205
        self.logger.info("Freeing the memory region at 0x%x\n" % ptr)
1206
        self.emcore.free(ptr)
1207
        self.logger.info("Successfully freed the memory region at 0x%x\n" % ptr)
1208
 
1209
    @command
1210
    def free_all(self):
1211
        """ Frees all memory allocations created by the monitor thread """
1212
        self.logger.info("Freeing all memory allocations created by the monitor thread\n")
1213
        self.emcore.free_all()
1214
        self.logger.info("Successfully freed all memory allocations created by the monitor thread\n")
1215
 
346 theseven 1216
 
171 farthen 1217
if __name__ == "__main__":
1218
    if len(sys.argv) < 2:
1219
        usage("No command specified")
382 farthen 1220
    try:
1221
        interface = Commandline()
1222
        interface._parsecommand(sys.argv[1], sys.argv[2:])
1223
    except KeyboardInterrupt:
1224
        sys.exit()