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