Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

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