Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
56 benedikt93 1
#!/usr/bin/env python
2
#
3
#
171 farthen 4
#    Copyright 2010 TheSeven, benedikt93, Farthen
56 benedikt93 5
#
6
#
7
#    This file is part of emBIOS.
8
#
9
#    emBIOS is free software: you can redistribute it and/or
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
#
14
#    emBIOS is distributed in the hope that it will be useful,
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
#
19
#    You should have received a copy of the GNU General Public License
20
#    along with emBIOS.  If not, see <http://www.gnu.org/licenses/>.
21
#
22
#
23
 
24
import sys
25
import struct
171 farthen 26
import usb.core
27
import libembiosdata
56 benedikt93 28
 
398 farthen 29
from misc import Bunch, Error, gethwname
394 farthen 30
from functools import wraps
31
 
171 farthen 32
class ArgumentError(Error):
33
    pass
56 benedikt93 34
 
171 farthen 35
class DeviceNotFoundError(Error):
36
    pass
56 benedikt93 37
 
171 farthen 38
class DeviceError(Error):
39
    pass
56 benedikt93 40
 
171 farthen 41
class SendError(Error):
42
    pass
56 benedikt93 43
 
171 farthen 44
class ReceiveError(Error):
45
    pass
56 benedikt93 46
 
47
 
398 farthen 48
def command(timeout = None, target = None):
394 farthen 49
    """
50
        Decorator for all commands.
51
        It adds the "timeout" variable to all commands.
52
        It also provides the possibility to set the timeout directly in the decorator.
53
        It also includes some dirty hacks to not learn from.
54
    """
55
    time = timeout # dirty hack because otherwise it would raise a scoping problem.
56
                   # The reason is probably because I suck but I can't find any good explanation of this.
57
    def decorator(func):
58
        @wraps(func)
59
        def wrapper(*args, **kwargs):
398 farthen 60
            self = args[0] # little cheat as it expects self being always the first argument
394 farthen 61
            # precommand stuff
398 farthen 62
            if target is not None:
63
                if self.lib.dev.hwtypeid != target:
64
                    raise DeviceError("Wrong device for target-specific command. Expected \'" + gethwname(target) + "\' but got \'" + gethwname(self.lib.dev.hwtypeid) + "\'")
394 farthen 65
            timeout = None
66
            if "timeout" in kwargs.keys():
67
                timeout = kwargs['timeout']
68
            elif time is not None:
69
                timeout = time
70
            if timeout is not None:
71
                oldtimeout = self.lib.dev.timeout
72
                self.lib.dev.timeout = timeout
73
            # function call
74
            ret = func(*args)
75
            # postcommand stuff
76
            if timeout is not None:
77
                self.lib.dev.timeout = oldtimeout
78
            return ret
396 farthen 79
        func._command = True
80
        wrapper.func = func
394 farthen 81
        return wrapper
82
    return decorator
83
 
84
 
171 farthen 85
class Embios(object):
176 farthen 86
    """
87
        Class for all embios functions.
394 farthen 88
        They all get the "@command()" decorator.
89
        This decorator has a timeout variable that can be set to change the
90
        device timeout for the duration of the function.
91
        It also adds a "timeout" argument to every function to access this
92
        feature from external. So DON'T EVER use a parameter called 'timeout'
93
        in your commands. Variables are ok.
176 farthen 94
    """
171 farthen 95
    def __init__(self):
176 farthen 96
        self.lib = Lib()
343 farthen 97
 
98
        self.getversioninfo()
176 farthen 99
        self.getpacketsizeinfo()
343 farthen 100
        self.getusermemrange()
56 benedikt93 101
 
171 farthen 102
    @staticmethod
103
    def _alignsplit(addr, size, blksize, align):
177 farthen 104
        if size <= blksize: return (size, 0, 0)
171 farthen 105
        end = addr + size
106
        if addr & (align - 1):
107
            bodyaddr = (addr + min(size, blksize)) & ~(align - 1)
108
        else: bodyaddr = addr
109
        headsize = bodyaddr - addr
110
        if (size - headsize) & (align - 1):
111
            tailaddr = (end - min(end - bodyaddr, blksize) + align - 1) & ~(align - 1)
112
        else: tailaddr = end
113
        tailsize = end - tailaddr
114
        return (headsize, tailaddr - bodyaddr, tailsize)
56 benedikt93 115
 
394 farthen 116
    @command()
178 farthen 117
    def _readmem(self, addr, size):
118
        """ Reads the memory from location 'addr' with size 'size'
119
            from the device.
120
        """
121
        resp = self.lib.monitorcommand(struct.pack("IIII", 4, addr, size, 0), "III%ds" % size, (None, None, None, "data"))
122
        return resp.data
394 farthen 123
 
124
    @command()
178 farthen 125
    def _writemem(self, addr, data):
126
        """ Writes the data in 'data' to the location 'addr'
127
            in the memory of the device.
128
        """
129
        return self.lib.monitorcommand(struct.pack("IIII%ds" % len(data), 5, addr, len(data), 0, data), "III", (None, None, None))
130
 
394 farthen 131
    @command()
178 farthen 132
    def _readdma(self, addr, size):
133
        """ Reads the memory from location 'addr' with size 'size'
134
            from the device. This uses DMA and the data in endpoint.
135
        """
136
        self.lib.monitorcommand(struct.pack("IIII", 6, addr, size, 0), "III", (None, None, None))
137
        return struct.unpack("%ds" % size, self.lib.dev.din(size))[0]
138
 
394 farthen 139
    @command()
178 farthen 140
    def _writedma(self, addr, data):
141
        """ Writes the data in 'data' to the location 'addr'
142
            in the memory of the device. This uses DMA and the data out endpoint.
143
        """
144
        self.lib.monitorcommand(struct.pack("IIII", 7, addr, len(data), 0), "III", (None, None, None))
145
        return self.lib.dev.dout(data)
146
 
394 farthen 147
    @command()
171 farthen 148
    def getversioninfo(self):
149
        """ This returns the emBIOS version and device information. """
342 farthen 150
        resp = self.lib.monitorcommand(struct.pack("IIII", 1, 0, 0, 0), "IBBBBI", ("revision", "majorv", "minorv", "patchv", "swtypeid", "hwtypeid"))
151
        self.lib.dev.version.revision = resp.revision
152
        self.lib.dev.version.majorv = resp.majorv
153
        self.lib.dev.version.minorv = resp.minorv
154
        self.lib.dev.version.patchv = resp.patchv
155
        self.lib.dev.swtypeid = resp.swtypeid
156
        self.lib.dev.hwtypeid = resp.hwtypeid
157
        return resp
56 benedikt93 158
 
394 farthen 159
    @command()
171 farthen 160
    def getpacketsizeinfo(self):
161
        """ This returns the emBIOS max packet size information.
162
            It also sets the properties of the device object accordingly.
163
        """
164
        resp = self.lib.monitorcommand(struct.pack("IIII", 1, 1, 0, 0), "HHII", ("coutmax", "cinmax", "doutmax", "dinmax"))
343 farthen 165
        self.lib.dev.packetsizelimit.cout = resp.coutmax
166
        self.lib.dev.packetsizelimit.cin = resp.cinmax
167
        self.lib.dev.packetsizelimit.din = resp.dinmax
168
        self.lib.dev.packetsizelimit.dout = resp.doutmax
171 farthen 169
        return resp
56 benedikt93 170
 
394 farthen 171
    @command()
171 farthen 172
    def getusermemrange(self):
173
        """ This returns the memory range the user has access to. """
342 farthen 174
        resp = self.lib.monitorcommand(struct.pack("IIII", 1, 2, 0, 0), "III", ("lower", "upper", None))
175
        self.lib.dev.usermem.lower = resp.lower
176
        self.lib.dev.usermem.upper = resp.upper
177
        return resp
56 benedikt93 178
 
394 farthen 179
    @command()
171 farthen 180
    def reset(self, force=False):
181
        """ Reboot the device """
182
        if force:
183
            return self.lib.monitorcommand(struct.pack("IIII", 2, 0, 0, 0))
184
        else:
185
            return self.lib.monitorcommand(struct.pack("IIII", 2, 1, 0, 0), "III", (None, None, None))
56 benedikt93 186
 
394 farthen 187
    @command()
171 farthen 188
    def poweroff(self, force=False):
189
        """ Powers the device off. """
190
        if force:
191
            return self.lib.monitorcommand(struct.pack("IIII", 3, 0, 0, 0))
192
        else:
193
            return self.lib.monitorcommand(struct.pack("IIII", 3, 1, 0, 0), "III", (None, None, None))
56 benedikt93 194
 
394 farthen 195
    @command()
171 farthen 196
    def read(self, addr, size):
197
        """ Reads the memory from location 'addr' with size 'size'
198
            from the device. This cares about too long packages
199
            and decides whether to use DMA or not.
200
        """
343 farthen 201
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
202
        din_maxsize = self.lib.dev.packetsizelimit.din
171 farthen 203
        data = ""
204
        (headsize, bodysize, tailsize) = self._alignsplit(addr, size, cin_maxsize, 16)
205
        if headsize != 0:
178 farthen 206
            data += self._readmem(addr, headsize)
171 farthen 207
            addr += headsize
208
        while bodysize > 0:
209
            if bodysize >= 2 * cin_maxsize:
210
                readsize = min(bodysize, din_maxsize)
178 farthen 211
                data += self._readdma(addr, readsize)
171 farthen 212
            else:
213
                readsize = min(bodysize, cin_maxsize)
178 farthen 214
                data += self._readmem(addr, readsize)
171 farthen 215
            addr += readsize
216
            bodysize -= readsize
217
        if tailsize != 0:
178 farthen 218
            data += self._readmem(addr, tailsize)
171 farthen 219
        return data
56 benedikt93 220
 
394 farthen 221
    @command()
171 farthen 222
    def write(self, addr, data):
223
        """ Writes the data in 'data' to the location 'addr'
224
            in the memory of the device. This cares about too long packages
225
            and decides whether to use DMA or not.
226
        """
343 farthen 227
        cout_maxsize = self.lib.dev.packetsizelimit.cout - self.lib.headersize
228
        dout_maxsize = self.lib.dev.packetsizelimit.dout
171 farthen 229
        (headsize, bodysize, tailsize) = self._alignsplit(addr, len(data), cout_maxsize, 16)
230
        offset = 0
231
        if headsize != 0:
178 farthen 232
            self._writemem(addr, data[offset:offset+headsize])
171 farthen 233
            offset += headsize
234
            addr += headsize
235
        while bodysize > 0:
236
            if bodysize >= 2 * cout_maxsize:
237
                writesize = min(bodysize, dout_maxsize)
178 farthen 238
                self._writedma(addr, data[offset:offset+writesize])
171 farthen 239
            else:
240
                writesize = min(bodysize, cout_maxsize)
178 farthen 241
                self._writemem(addr, data[offset:offset+writesize])
171 farthen 242
            offset += writesize
243
            addr += writesize
244
            bodysize -= writesize
245
        if tailsize != 0:
178 farthen 246
            self._writemem(addr, data[offset:offset+tailsize])
171 farthen 247
        return data
56 benedikt93 248
 
394 farthen 249
    @command()
173 farthen 250
    def readstring(self, addr, maxlength = 256):
251
        """ Reads a zero terminated string from memory 
252
            Reads only a maximum of 'maxlength' chars.
253
        """
343 farthen 254
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
173 farthen 255
        string = ""
256
        while (len(string) < maxlength or maxlength < 0):
178 farthen 257
            data = self._readmem(addr, min(maxlength - len(string), cin_maxsize))
173 farthen 258
            length = data.find("\0")
259
            if length >= 0:
260
                string += data[:length]
261
                break
262
            else:
263
                string += data
264
            addr += cin_maxsize
265
        return string
266
 
394 farthen 267
    @command()
171 farthen 268
    def i2cread(self, index, slaveaddr, startaddr, size):
269
        """ Reads data from an i2c slave """
236 farthen 270
        data = ""
271
        for i in range(size):
272
            resp = self.lib.monitorcommand(struct.pack("IBBBBII", 8, index, slaveaddr, startaddr + i, 1, 0, 0), "III1s", (None, None, None, "data"))
273
            data += resp.data
274
        return data
56 benedikt93 275
 
394 farthen 276
    @command()
171 farthen 277
    def i2cwrite(self, index, slaveaddr, startaddr, data):
278
        """ Writes data to an i2c slave """
176 farthen 279
        size = len(data)
280
        if size > 256 or size < 1:
341 farthen 281
            raise ArgumentError("Size must be a number between 1 and 256")
176 farthen 282
        if size == 256:
283
            size = 0
215 theseven 284
        return self.lib.monitorcommand(struct.pack("IBBBBII%ds" % size, 9, index, slaveaddr, startaddr, size, 0, 0, data), "III", (None, None, None))
56 benedikt93 285
 
394 farthen 286
    @command()
176 farthen 287
    def usbcread(self):
288
        """ Reads one packet with the maximal cin size """
343 farthen 289
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
176 farthen 290
        resp = self.lib.monitorcommand(struct.pack("IIII", 10, cin_maxsize, 0, 0), "III%ds" % cin_maxsize, ("validsize", "buffersize", "queuesize", "data"))
291
        resp.data = resp.data[:resp.validsize]
292
        resp.maxsize = cin_maxsize
293
        return resp
56 benedikt93 294
 
394 farthen 295
    @command()
171 farthen 296
    def usbcwrite(self, data):
297
        """ Writes data to the USB console """
343 farthen 298
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
176 farthen 299
        size = len(data)
300
        while len(data) > 0:
301
            writesize = min(cin_maxsize, len(data))
302
            resp = self.lib.monitorcommand(struct.pack("IIII%ds" % writesize, 11, writesize, 0, 0, data[:writesize]), "III", ("validsize", "buffersize", "freesize"))
303
            data = data[resp.validsize:]
304
        return size
56 benedikt93 305
 
394 farthen 306
    @command()
176 farthen 307
    def cread(self, bitmask=0x1):
308
        """ Reads one packet with the maximal cin size from the device consoles
171 farthen 309
            identified with the specified bitmask
310
        """
343 farthen 311
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
217 theseven 312
        resp = self.lib.monitorcommand(struct.pack("IIII", 13, bitmask, cin_maxsize, 0), "III%ds" % cin_maxsize, ("size", None, None))
176 farthen 313
        resp.data = resp.data[size:]
314
        resp.maxsize = cin_maxsize
315
        return resp
394 farthen 316
 
317
    @command()
176 farthen 318
    def cwrite(self, data, bitmask=0x1):
171 farthen 319
        """ Writes data to the device consoles 
320
            identified with the specified bitmask.
321
        """
343 farthen 322
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
176 farthen 323
        size = len(data)
324
        while len(data) > 0:
325
            writesize = min(cin_maxsize, len(data))
217 theseven 326
            resp = self.lib.monitorcommand(struct.pack("IIII%ds" % writesize, 12, bitmask, writesize, 0, data[:writesize]), "III", (None, None, None))
176 farthen 327
            data = data[writesize:]
328
        return size
56 benedikt93 329
 
394 farthen 330
    @command()
171 farthen 331
    def cflush(self, bitmask):
332
        """ Flushes the consoles specified with 'bitmask' """
333
        return self.lib.monitorcommand(struct.pack("IIII", 14, bitmask, 0, 0), "III", (None, None, None))
56 benedikt93 334
 
394 farthen 335
    @command()
173 farthen 336
    def getprocinfo(self):
171 farthen 337
        """ Gets current state of the scheduler """
343 farthen 338
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
173 farthen 339
        # Get the size
340
        schedulerstate = self.lockscheduler()
341
        resp = self.lib.monitorcommand(struct.pack("IIII", 15, 0, 0, 0), "III", ("structver", "tablesize", None))
342
        tablesize = resp.tablesize
343
        size = tablesize
344
        structver = resp.structver
345
        offset = 0
346
        data = ""
347
        while size > 0:
348
            if size > cin_maxsize:
349
                readsize = cin_maxsize
350
            else:
351
                readsize = size
352
            resp = self.lib.monitorcommand(struct.pack("IIII", 15, offset, readsize, 0), "III%ds" % readsize, ("structver", "tablesize", None, "data"))
353
            data += resp.data
354
            offset += readsize
355
            size -= readsize
356
        self.lockscheduler(schedulerstate)
357
        threadstructsize = 120
358
        registersize = 32
359
        if len(data) % threadstructsize != 0:
360
            raise DeviceError("The thread struct is not a multiple of "+str(threadsturcsize)+"!")
361
        threadcount = len(data) / threadstructsize
362
        threads = []
363
        id = 0
364
        for thread in range(threadcount):
365
            offset = threadstructsize * thread
366
            threaddata = struct.unpack("<16IIIIIQIIIIIIIBBBB", data[offset:offset+threadstructsize])
367
            info = Bunch()
368
            info.id = id
369
            state = threaddata[17]
370
            info.state = libembiosdata.thread_state[state]
371
            if info.state == "THREAD_FREE":
372
                id += 1
373
                continue
374
            info.regs = Bunch()
375
            for register in range(16):
376
                info.regs["r"+str(register)] = threaddata[register]
377
            info.regs.cpsr = threaddata[16]
378
            info.nameptr = threaddata[18]
379
            if info.nameptr == 0:
380
                info.name = "Thread %d" % info.id
381
            else:
382
                info.name = self.readstring(info.nameptr)
383
            info.cputime_current = threaddata[19]
384
            info.cputime_total = threaddata[20]
385
            info.startusec = threaddata[21]
386
            info.queue_next_ptr = threaddata[22]
387
            info.timeout = threaddata[23]
388
            info.blocked_since = threaddata[24]
389
            info.blocked_by_ptr = threaddata[25]
390
            info.stackaddr = threaddata[26]
391
            info.err_no = threaddata[27]
392
            info.block_type = libembiosdata.thread_block[threaddata[28]]
393
            info.type = libembiosdata.thread_type[threaddata[29]]
394
            info.priority = threaddata[30]
395
            info.cpuload = threaddata[31]
396
            threads.append(info)
397
            id += 1
398
        return threads
56 benedikt93 399
 
394 farthen 400
    @command()
173 farthen 401
    def lockscheduler(self, freeze=True):
171 farthen 402
        """ Freezes/Unfreezes the scheduler """
173 farthen 403
        resp = self.lib.monitorcommand(struct.pack("IIII", 16, 1 if freeze else 0, 0, 0), "III", ("before", None, None))
404
        return True if resp.before == 1 else False
67 benedikt93 405
 
394 farthen 406
    @command()
173 farthen 407
    def unlockscheduler(self):
171 farthen 408
        """ Unfreezes the scheduler """
409
        return self.lib.monitorcommand(struct.pack("IIII", 16, 0, 0, 0), "III", ("before", None, None))
56 benedikt93 410
 
394 farthen 411
    @command()
171 farthen 412
    def suspendthread(self, id, suspend=True):
413
        """ Suspends the thread with the specified id """
173 farthen 414
        resp = self.lib.monitorcommand(struct.pack("IIII", 17, 1 if suspend else 0, id, 0), "III", ("before", None, None))
415
        return True if resp.before == 1 else False
56 benedikt93 416
 
394 farthen 417
    @command()
173 farthen 418
    def resumethread(self, id):
419
        """ Resumes the thread with the specified id """
171 farthen 420
        return self.lib.monitorcommand(struct.pack("IIII", 17, 0, id, 0), "III", ("before", None, None))
56 benedikt93 421
 
394 farthen 422
    @command()
171 farthen 423
    def killthread(self, id):
424
        """ Kills the thread with the specified id """
425
        return self.lib.monitorcommand(struct.pack("IIII", 18, id, 0, 0), "III", ("before", None, None))
56 benedikt93 426
 
394 farthen 427
    @command()
171 farthen 428
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
429
        """ Creates a thread with the specified attributes """
430
        if threadtype == "user":
431
            threadtype = 0
432
        elif threadtype == "system":
433
            threadtype = 1
434
        else:
341 farthen 435
            raise ArgumentError("Threadtype must be either 'system' or 'user'")
171 farthen 436
        if priority > 256 or priority < 0:
341 farthen 437
            raise ArgumentError("Priority must be a number between 0 and 256")
171 farthen 438
        if state == "ready":
439
            state = 0
440
        elif state == "suspended":
441
            state = 1
442
        else:
341 farthen 443
            raise ArgumentError("State must be either 'ready' or 'suspended'")
171 farthen 444
        resp = self.lib.monitorcommand(struct.pack("IIIIIIII", 19, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state), "III", (id, None, None))
445
        if resp.id < 0:
446
            raise DeviceError("The device returned the error code "+str(resp.id))
447
        return resp
56 benedikt93 448
 
394 farthen 449
    @command()
172 farthen 450
    def flushcaches(self):
171 farthen 451
        """ Flushes the CPU instruction and data cache """
452
        return self.lib.monitorcommand(struct.pack("IIII", 20, 0, 0, 0), "III", (None, None, None))
56 benedikt93 453
 
394 farthen 454
    @command()
172 farthen 455
    def execimage(self, addr):
171 farthen 456
        """ Runs the emBIOS app at 'addr' """
346 theseven 457
        return self.lib.monitorcommand(struct.pack("IIII", 21, addr, 0, 0), "III", ("rc", None, None))
56 benedikt93 458
 
394 farthen 459
    @command()
238 farthen 460
    def run(self, app):
461
        """ Uploads and runs the emBIOS app in the string 'app' """
462
        try:
463
            appheader = struct.unpack("<8sIIIIIIIIII", app[:48])
464
        except struct.error:
341 farthen 465
            raise ArgumentError("The specified app is not an emBIOS application")
238 farthen 466
        header = appheader[0]
467
        if header != "emBIexec":
341 farthen 468
            raise ArgumentError("The specified app is not an emBIOS application")
238 farthen 469
        baseaddr = appheader[2]
470
        threadnameptr = appheader[8]
471
        nameptr = threadnameptr - baseaddr
472
        name = ""
473
        while True:
474
            char = app[nameptr:nameptr+1]
475
            try:
476
                if ord(char) == 0:
477
                    break
478
            except TypeError:
341 farthen 479
                raise ArgumentError("The specified app is not an emBIOS application")
238 farthen 480
            name += char
481
            nameptr += 1
482
        usermem = self.getusermemrange()
483
        if usermem.lower > baseaddr or usermem.upper < baseaddr + len(app):
484
            raise ArgumentError("The baseaddress of the specified emBIOS application is out of range of the user memory range on the device. Are you sure that this application is compatible with your device?")
485
        self.write(baseaddr, app)
486
        self.execimage(baseaddr)
487
        return Bunch(baseaddr=baseaddr, name=name)
488
 
395 farthen 489
    @command(timeout = 5000)
171 farthen 490
    def bootflashread(self, memaddr, flashaddr, size):
491
        """ Copies the data in the bootflash at 'flashaddr' of the specified size
492
            to the memory at addr 'memaddr'
493
        """
174 farthen 494
        return self.lib.monitorcommand(struct.pack("IIII", 22, memaddr, flashaddr, size), "III", (None, None, None))
82 benedikt93 495
 
395 farthen 496
    @command(timeout = 30000)
171 farthen 497
    def bootflashwrite(self, memaddr, flashaddr, size):
498
        """ Copies the data in the memory at 'memaddr' of the specified size
499
            to the boot flash at addr 'flashaddr'
500
        """
174 farthen 501
        return self.lib.monitorcommand(struct.pack("IIII", 23, memaddr, flashaddr, size), "III", (None, None, None))
56 benedikt93 502
 
394 farthen 503
    @command()
171 farthen 504
    def execfirmware(self, addr):
505
        """ Executes the firmware at 'addr' and passes all control to it. """
269 farthen 506
        return self.lib.monitorcommand(struct.pack("IIII", 24, addr, 0, 0))
56 benedikt93 507
 
395 farthen 508
    @command(timeout = 30000)
171 farthen 509
    def aesencrypt(self, addr, size, keyindex):
510
        """ Encrypts the buffer at 'addr' with the specified size
511
            with the hardware AES key index 'keyindex'
512
        """
513
        return self.lib.monitorcommand(struct.pack("IBBHII", 25, 1, 0, keyindex, addr, size), "III", (None, None, None))
82 benedikt93 514
 
395 farthen 515
    @command(timeout = 30000)
171 farthen 516
    def aesdecrypt(self, addr, size, keyindex):
517
        """ Decrypts the buffer at 'addr' with the specified size
518
            with the hardware AES key index 'keyindex'
519
        """
520
        return self.lib.monitorcommand(struct.pack("IBBHII", 25, 0, 0, keyindex, addr, size), "III", (None, None, None))
82 benedikt93 521
 
395 farthen 522
    @command(timeout = 30000)
171 farthen 523
    def hmac_sha1(self, addr, size, destination):
524
        """ Generates a HMAC-SHA1 hash of the buffer and saves it to 'destination' """
525
        return self.lib.monitorcommand(struct.pack("IIII", 26, addr, size, destination), "III", (None, None, None))
56 benedikt93 526
 
398 farthen 527
    @command(target = 0x47324e49)
227 theseven 528
    def ipodnano2g_getnandinfo(self):
529
        """ Target-specific function: ipodnano2g
530
            Gathers some information about the NAND chip used
531
        """
532
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0001, 0, 0, 0), "IHHHH", ("type", "pagesperblock", "banks", "userblocks", "blocks"))
533
 
398 farthen 534
    @command(timeout = 30000, target = 0x47324e49)
227 theseven 535
    def ipodnano2g_nandread(self, addr, start, count, doecc, checkempty):
536
        """ Target-specific function: ipodnano2g
537
            Reads data from the NAND chip into memory
538
        """
539
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0002, addr | (0x80000000 if doecc != 0 else 0) | (0x40000000 if checkempty != 0 else 0), start, count), "III", (None, None, None))
540
 
398 farthen 541
    @command(timeout = 30000, target = 0x47324e49)
227 theseven 542
    def ipodnano2g_nandwrite(self, addr, start, count, doecc):
543
        """ Target-specific function: ipodnano2g
544
            Writes data to the NAND chip
545
        """
546
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0003, addr | (0x80000000 if doecc != 0 else 0), start, count), "III", (None, None, None))
547
 
398 farthen 548
    @command(timeout = 30000, target = 0x47324e49)
227 theseven 549
    def ipodnano2g_nanderase(self, addr, start, count):
550
        """ Target-specific function: ipodnano2g
551
            Erases blocks on the NAND chip and stores the results to memory
552
        """
553
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0004, addr, start, count), "III", (None, None, None))
554
 
398 farthen 555
    @command(target = 0x4c435049)
346 theseven 556
    def ipodclassic_gethddinfo(self):
557
        """ Target-specific function: ipodclassic
558
            Gather information about the hard disk drive
559
        """
560
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0001, 0, 0, 0), "IQQII", ("identifyptr", "totalsectors", "virtualsectors", "bbtptr", "bbtsize"))
561
 
398 farthen 562
    @command(timeout = 30000, target = 0x4c435049)
346 theseven 563
    def ipodclassic_hddaccess(self, type, sector, count, addr):
564
        """ Target-specific function: ipodclassic
565
            Access the hard disk, type = 0 (read) / 1 (write)
566
        """
567
        rc = self.lib.monitorcommand(struct.pack("IIQIIII", 0xffff0002, type, sector, count, addr, 0, 0), "III", ("rc", None, None))
568
        if (rc > 0x80000000):
569
            raise DeviceError("HDD access (type=%d, sector=%d, count=%d, addr=0x%08X) failed with RC 0x%08X" % (type, sector, count, addr, rc))
570
 
398 farthen 571
    @command(target = 0x4c435049)
346 theseven 572
    def ipodclassic_writebbt(self, bbt, tempaddr):
573
        """ Target-specific function: ipodclassic
574
            Write hard drive bad block table
575
        """
576
        try:
577
            bbtheader = struct.unpack("<8s2024sQII512I", bbt[:4096])
578
        except struct.error:
579
            raise ArgumentError("The specified file is not an emBIOS hard disk BBT")
580
        if bbtheader[0] != "emBIbbth":
581
            raise ArgumentError("The specified file is not an emBIOS hard disk BBT")
582
        virtualsectors = bbtheader[2]
583
        bbtsectors = bbtheader[3]
584
        self.write(tempaddr, bbt)
585
        sector = 0
586
        count = 1
587
        offset = 0
588
        for i in range(bbtsectors):
589
            if bbtheader[4][i] == sector + count:
590
                count = count + 1
591
            else:
592
                self.ipodclassic_hddaccess(1, sector, count, tempaddr + offset)
593
                offset = offset + count * 4096
594
                sector = bbtheader[4][i]
595
                count = 1
596
        self.ipodclassic_hddaccess(1, sector, count, tempaddr + offset)
597
 
394 farthen 598
    @command()
379 theseven 599
    def storage_get_info(self, volume):
346 theseven 600
        """ Get information about a storage device """
379 theseven 601
        result = self.lib.monitorcommand(struct.pack("IIII", 27, volume, 0, 0), "IIIIIIII", ("version", None, None, "sectorsize", "numsectors", "vendorptr", "productptr", "revisionptr"))
346 theseven 602
        if result.version != 1:
603
            raise ValueError("Unknown version of storage_info struct: %d" % result.version)
379 theseven 604
        result.vendor = self.readstring(result.vendorptr)
605
        result.product = self.readstring(result.productptr)
606
        result.revision = self.readstring(result.revisionptr)
346 theseven 607
        return result
608
 
395 farthen 609
    @command(timeout = 50000)
346 theseven 610
    def storage_read_sectors_md(self, volume, sector, count, addr):
611
        """ Read sectors from as storage device """
612
        result = self.lib.monitorcommand(struct.pack("IIQIIII", 28, volume, sector, count, addr, 0, 0), "III", ("rc", None, None, None))
613
        if result.rc > 0x80000000:
614
            raise DeviceError("storage_read_sectors_md(volume=%d, sector=%d, count=%d, addr=0x%08X) failed with RC 0x%08X" % (volume, sector, count, addr, rc))
394 farthen 615
 
395 farthen 616
    @command(timeout = 50000)
346 theseven 617
    def storage_write_sectors_md(self, volume, sector, count, addr):
618
        """ Read sectors from as storage device """
619
        result = self.lib.monitorcommand(struct.pack("IIQIIII", 29, volume, sector, count, addr, 0, 0), "III", ("rc", None, None, None))
620
        if result.rc > 0x80000000:
621
            raise DeviceError("storage_read_sectors_md(volume=%d, sector=%d, count=%d, addr=0x%08X) failed with RC 0x%08X" % (volume, sector, count, addr, rc))
394 farthen 622
 
395 farthen 623
    @command(timeout = 30000)
346 theseven 624
    def file_open(self, filename, mode):
625
        """ Opens a file and returns the handle """
626
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(filename), 30, mode, 0, 0, filename, 0), "III", ("fd", None, None))
627
        if result.fd > 0x80000000:
628
            raise DeviceError("file_open(filename=\"%s\", mode=0x%X) failed with RC=0x%08X, errno=%d" % (filename, mode, result.fd, self.errno()))
629
        return result.fd
630
 
395 farthen 631
    @command(timeout = 30000)
346 theseven 632
    def file_size(self, fd):
633
        """ Gets the size of a file referenced by a handle """
634
        result = self.lib.monitorcommand(struct.pack("IIII", 31, fd, 0, 0), "III", ("size", None, None))
635
        if result.size > 0x80000000:
636
            raise DeviceError("file_size(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.size, self.errno()))
637
        return result.size
394 farthen 638
 
395 farthen 639
    @command(timeout = 30000)
346 theseven 640
    def file_read(self, fd, addr, size):
641
        """ Reads data from a file referenced by a handle """
642
        result = self.lib.monitorcommand(struct.pack("IIII", 32, fd, addr, size), "III", ("rc", None, None))
643
        if result.rc > 0x80000000:
644
            raise DeviceError("file_read(fd=%d, addr=0x%08X, size=0x%08X) failed with RC=0x%08X, errno=%d" % (fd, addr, size, result.rc, self.errno()))
645
        return result.rc
394 farthen 646
 
395 farthen 647
    @command(timeout = 30000)
346 theseven 648
    def file_write(self, fd, addr, size):
649
        """ Writes data from a file referenced by a handle """
650
        result = self.lib.monitorcommand(struct.pack("IIII", 33, fd, addr, size), "III", ("rc", None, None))
651
        if result.rc > 0x80000000:
652
            raise DeviceError("file_write(fd=%d, addr=0x%08X, size=0x%08X) failed with RC=0x%08X, errno=%d" % (fd, addr, size, result.rc, self.errno()))
653
        return result.rc
654
 
395 farthen 655
    @command(timeout = 30000)
346 theseven 656
    def file_seek(self, fd, offset, whence):
657
        """ Seeks the file handle to the specified position in the file """
658
        result = self.lib.monitorcommand(struct.pack("IIII", 34, fd, offset, whence), "III", ("rc", None, None))
659
        if result.rc > 0x80000000:
660
            raise DeviceError("file_seek(fd=%d, offset=0x%08X, whence=%d) failed with RC=0x%08X, errno=%d" % (fd, offset, whence, result.rc, self.errno()))
661
        return result.rc
662
 
395 farthen 663
    @command(timeout = 30000)
346 theseven 664
    def file_truncate(self, fd, length):
665
        """ Truncates a file referenced by a handle to a specified length """
666
        result = self.lib.monitorcommand(struct.pack("IIII", 35, fd, offset, 0), "III", ("rc", None, None))
667
        if result.rc > 0x80000000:
668
            raise DeviceError("file_truncate(fd=%d, length=0x%08X) failed with RC=0x%08X, errno=%d" % (fd, length, result.rc, self.errno()))
669
        return result.rc
670
 
395 farthen 671
    @command(timeout = 30000)
346 theseven 672
    def file_sync(self, fd):
673
        """ Flushes a file handles' buffers """
674
        result = self.lib.monitorcommand(struct.pack("IIII", 36, fd, 0, 0), "III", ("rc", None, None))
675
        if result.rc > 0x80000000:
676
            raise DeviceError("file_sync(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.rc, self.errno()))
677
        return result.rc
678
 
395 farthen 679
    @command(timeout = 30000)
346 theseven 680
    def file_close(self, fd):
681
        """ Closes a file handle """
682
        result = self.lib.monitorcommand(struct.pack("IIII", 37, fd, 0, 0), "III", ("rc", None, None))
683
        if result.rc > 0x80000000:
684
            raise DeviceError("file_close(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.rc, self.errno()))
685
        return result.rc
686
 
395 farthen 687
    @command(timeout = 30000)
346 theseven 688
    def file_close_all(self):
689
        """ Closes all file handles opened through the debugger """
690
        result = self.lib.monitorcommand(struct.pack("IIII", 38, 0, 0, 0), "III", ("rc", None, None))
691
        if result.rc > 0x80000000:
692
            raise DeviceError("file_close_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
693
        return result.rc
694
 
395 farthen 695
    @command(timeout = 30000)
346 theseven 696
    def file_kill_all(self):
697
        """ Kills all file handles (in the whole system) """
698
        result = self.lib.monitorcommand(struct.pack("IIII", 39, 0, 0, 0), "III", ("rc", None, None))
699
        if result.rc > 0x80000000:
700
            raise DeviceError("file_kill_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
701
        return result.rc
702
 
395 farthen 703
    @command(timeout = 30000)
346 theseven 704
    def file_unlink(self, filename):
705
        """ Removes a file """
706
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(filename), 40, 0, 0, 0, filename, 0), "III", ("rc", None, None))
707
        if result.rc > 0x80000000:
708
            raise DeviceError("file_unlink(filename=\"%s\") failed with RC=0x%08X, errno=%d" % (filename, result.rc, self.errno()))
709
        return result.rc
710
 
395 farthen 711
    @command(timeout = 30000)
346 theseven 712
    def file_rename(self, oldname, newname):
713
        """ Renames a file """
714
        result = self.lib.monitorcommand(struct.pack("IIII248s%dsB" % min(247, len(newname)), 41, 0, 0, 0, oldname, newname, 0), "III", ("rc", None, None))
715
        if result.rc > 0x80000000:
716
            raise DeviceError("file_rename(oldname=\"%s\", newname=\"%s\") failed with RC=0x%08X, errno=%d" % (oldname, newname, result.rc, self.errno()))
717
        return result.rc
718
 
395 farthen 719
    @command(timeout = 30000)
346 theseven 720
    def dir_open(self, dirname):
721
        """ Opens a directory and returns the handle """
722
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 42, 0, 0, 0, dirname, 0), "III", ("handle", None, None))
723
        if result.handle == 0:
724
            raise DeviceError("dir_open(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.handle, self.errno()))
725
        return result.handle
726
 
395 farthen 727
    @command(timeout = 30000)
346 theseven 728
    def dir_read(self, handle):
729
        """ Reads the next entry from a directory """
730
        result = self.lib.monitorcommand(struct.pack("IIII", 43, handle, 0, 0), "III", ("version", "maxpath", "ptr"))
731
        if result.ptr == 0:
732
            raise DeviceError("dir_read(handle=0x%08X) failed with RC=0x%08X, errno=%d" % (handle, result.ptr, self.errno()))
733
        if result.version != 1:
734
            raise ValueError("Unknown version of dirent struct: %d" % result.version)
735
        dirent = self.read(result.ptr, result.maxpath + 16)
736
        ret = Bunch()
737
        (ret.name, ret.attributes, ret.size, ret.startcluster, ret.wrtdate, ret.wrttime) = struct.unpack("%dsIIIHH" % result.maxpath, dirent)
738
        ret.name = ret.name[:ret.name.index('\x00')]
739
        return ret
740
 
395 farthen 741
    @command(timeout = 30000)
346 theseven 742
    def dir_close(self, handle):
743
        """ Closes a directory handle """
744
        result = self.lib.monitorcommand(struct.pack("IIII", 44, handle, 0, 0), "III", ("rc", None, None))
745
        if result.rc > 0x80000000:
746
            raise DeviceError("dir_close(handle=0x%08X) failed with RC=0x%08X, errno=%d" % (handle, result.rc, self.errno()))
747
        return result.rc
748
 
395 farthen 749
    @command(timeout = 30000)
346 theseven 750
    def dir_close_all(self):
751
        """ Closes all directory handles opened through the debugger """
752
        result = self.lib.monitorcommand(struct.pack("IIII", 45, 0, 0, 0), "III", ("rc", None, None))
753
        if result.rc > 0x80000000:
754
            raise DeviceError("dir_close_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
755
        return result.rc
756
 
395 farthen 757
    @command(timeout = 30000)
346 theseven 758
    def dir_kill_all(self):
759
        """ Kills all directory handles (in the whole system) """
760
        result = self.lib.monitorcommand(struct.pack("IIII", 46, 0, 0, 0), "III", ("rc", None, None))
761
        if result.rc > 0x80000000:
762
            raise DeviceError("dir_kill_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
763
        return result.rc
764
 
395 farthen 765
    @command(timeout = 30000)
346 theseven 766
    def dir_create(self, dirname):
767
        """ Creates a directory """
768
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 47, 0, 0, 0, dirname, 0), "III", ("rc", None, None))
769
        if result.rc > 0x80000000:
770
            raise DeviceError("dir_create(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.rc, self.errno()))
771
        return result.rc
772
 
395 farthen 773
    @command(timeout = 30000)
346 theseven 774
    def dir_remove(self, dirname):
775
        """ Removes an (empty) directory """
776
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 48, 0, 0, 0, dirname, 0), "III", ("rc", None, None))
777
        if result.rc > 0x80000000:
778
            raise DeviceError("dir_remove(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.rc, self.errno()))
779
        return result.rc
780
 
394 farthen 781
    @command()
346 theseven 782
    def errno(self):
783
        """ Returns the number of the last error that happened """
784
        result = self.lib.monitorcommand(struct.pack("IIII", 49, 0, 0, 0), "III", ("errno", None, None))
785
        return result.errno
786
 
394 farthen 787
    @command()
346 theseven 788
    def disk_mount(self, volume):
789
        """ Mounts a volume """
790
        result = self.lib.monitorcommand(struct.pack("IIII", 50, volume, 0, 0), "III", ("rc", None, None))
791
        if result.rc > 0x80000000:
792
            raise DeviceError("disk_mount(volume=%d) failed with RC=0x%08X, errno=%d" % (volume, result.rc, self.errno()))
793
        return result.rc
794
 
394 farthen 795
    @command()
346 theseven 796
    def disk_unmount(self, volume):
797
        """ Unmounts a volume """
798
        result = self.lib.monitorcommand(struct.pack("IIII", 51, volume, 0, 0), "III", ("rc", None, None))
799
        if result.rc > 0x80000000:
800
            raise DeviceError("disk_unmount(volume=%d) failed with RC=0x%08X, errno=%d" % (volume, result.rc, self.errno()))
801
        return result.rc
802
 
803
 
171 farthen 804
class Lib(object):
176 farthen 805
    def __init__(self):
171 farthen 806
        self.idVendor = 0xFFFF
807
        self.idProduct = 0xE000
176 farthen 808
 
809
        self.headersize = 0x10
810
 
811
        self.connect()
56 benedikt93 812
 
171 farthen 813
    def connect(self):
814
        self.dev = Dev(self.idVendor, self.idProduct)
815
        self.connected = True
56 benedikt93 816
 
171 farthen 817
    def monitorcommand(self, cmd, rcvdatatypes=None, rcvstruct=None):
269 farthen 818
        writelen = self.dev.cout(cmd)
171 farthen 819
        if rcvdatatypes:
820
            rcvdatatypes = "I" + rcvdatatypes # add the response
821
            data = self.dev.cin(struct.calcsize(rcvdatatypes))
822
            data = struct.unpack(rcvdatatypes, data)
823
            response = data[0]
824
            if libembiosdata.responsecodes[response] == "ok":
825
                if rcvstruct:
826
                    datadict = Bunch()
827
                    counter = 1 # start with 1, 0 is the id
828
                    for item in rcvstruct:
829
                        if item != None: # else the data is undefined
830
                            datadict[item] = data[counter]
831
                        counter += 1
832
                    return datadict
833
                else:
834
                    return data
835
            elif libembiosdata.responsecodes[response] == "unsupported":
836
                raise DeviceError("The device does not support this command.")
837
            elif libembiosdata.responsecodes[response] == "invalid":
838
                raise DeviceError("Invalid command! This should NOT happen!")
839
            elif libembiosdata.responsecodes[response] == "busy":
840
                raise DeviceError("Device busy")
269 farthen 841
        else:
842
            return writelen
56 benedikt93 843
 
844
 
171 farthen 845
class Dev(object):
846
    def __init__(self, idVendor, idProduct):
847
        self.idVendor = idVendor
848
        self.idProduct = idProduct
67 benedikt93 849
 
171 farthen 850
        self.interface = 0
851
        self.timeout = 100
176 farthen 852
 
171 farthen 853
        self.connect()
854
        self.findEndpoints()
855
 
342 farthen 856
 
857
        # Device properties
343 farthen 858
        self.packetsizelimit = Bunch()
859
        self.packetsizelimit.cout = None
860
        self.packetsizelimit.cin = None
861
        self.packetsizelimit.dout = None
862
        self.packetsizelimit.din = None
342 farthen 863
 
343 farthen 864
        self.version = Bunch()
342 farthen 865
        self.version.revision = None
866
        self.version.majorv = None
867
        self.version.minorv = None
868
        self.version.patchv = None
869
        self.swtypeid = None
870
        self.hwtypeid = None
871
 
343 farthen 872
        self.usermem = Bunch()
342 farthen 873
        self.usermem.lower = None
874
        self.usermem.upper = None
56 benedikt93 875
 
171 farthen 876
    def __del__(self):
877
        self.disconnect()
56 benedikt93 878
 
171 farthen 879
    def findEndpoints(self):
880
        epcounter = 0
343 farthen 881
        self.endpoint = Bunch()
171 farthen 882
        for cfg in self.dev:
883
            for intf in cfg:
884
                for ep in intf:
885
                    if epcounter == 0:
343 farthen 886
                        self.endpoint.cout = ep.bEndpointAddress
171 farthen 887
                    elif epcounter == 1:
343 farthen 888
                        self.endpoint.cin = ep.bEndpointAddress
171 farthen 889
                    elif epcounter == 2:
343 farthen 890
                        self.endpoint.dout = ep.bEndpointAddress
171 farthen 891
                    elif epcounter == 3:
343 farthen 892
                        self.endpoint.din = ep.bEndpointAddress
171 farthen 893
                    epcounter += 1
894
        if epcounter <= 3:
895
            raise DeviceError("Not all endpoints found in the descriptor. Only "+str(epcounter)+" found, we need 4")
56 benedikt93 896
 
171 farthen 897
    def connect(self):
898
        self.dev = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
899
        if self.dev is None:
900
            raise DeviceNotFoundError()
901
        self.dev.set_configuration()
56 benedikt93 902
 
171 farthen 903
    def disconnect(self):
904
        pass
102 benedikt93 905
 
171 farthen 906
    def send(self, endpoint, data):
907
        size = self.dev.write(endpoint, data, self.interface, self.timeout)
908
        if size != len(data):
176 farthen 909
            raise SendError("Not all data was written!")
171 farthen 910
        return len
102 benedikt93 911
 
171 farthen 912
    def receive(self, endpoint, size):
913
        read = self.dev.read(endpoint, size, self.interface, self.timeout)
914
        if len(read) != size:
176 farthen 915
            raise ReceiveError("Requested size and read size don't match!")
171 farthen 916
        return read
56 benedikt93 917
 
171 farthen 918
    def cout(self, data):
343 farthen 919
        if self.packetsizelimit.cout and len(data) > self.packetsizelimit.cout:
171 farthen 920
            raise SendError("Packet too big")
343 farthen 921
        return self.send(self.endpoint.cout, data)
94 benedikt93 922
 
171 farthen 923
    def cin(self, size):
343 farthen 924
        if self.packetsizelimit.cin and size > self.packetsizelimit.cin:
171 farthen 925
            raise ReceiveError("Packet too big")
343 farthen 926
        return self.receive(self.endpoint.cin, size)
94 benedikt93 927
 
171 farthen 928
    def dout(self, data):
343 farthen 929
        if self.packetsizelimit.dout and len(data) > self.packetsizelimit.dout:
171 farthen 930
            raise SendError("Packet too big")
343 farthen 931
        return self.send(self.endpoint.dout, data)
94 benedikt93 932
 
171 farthen 933
    def din(self, size):
343 farthen 934
        if self.packetsizelimit.din and size > self.packetsizelimit.din:
171 farthen 935
            raise ReceiveError("Packet too big")
343 farthen 936
        return self.receive(self.endpoint.din, size)
56 benedikt93 937
 
96 benedikt93 938
 
171 farthen 939
if __name__ == "__main__":
396 farthen 940
    from misc import Logger
941
    logger = Logger()
942
    if sys.argv[1] == "test":
943
        # Some tests
944
        import sys
945
        embios = Embios()
946
        resp = embios.getversioninfo()
947
        logger.log("Embios device version information: " + libembiosdata.swtypes[resp.swtypeid] + " v" + str(resp.majorv) + "." + str(resp.minorv) + 
948
                         "." + str(resp.patchv) + " r" + str(resp.revision) + " running on " + libembiosdata.hwtypes[resp.hwtypeid] + "\n")
949
        resp = embios.getusermemrange()
950
        logger.log("Usermemrange: "+hex(resp.lower)+" - "+hex(resp.upper)+"\n")
951
        memaddr = resp.lower
952
        maxlen = resp.upper - resp.lower
953
        f = open("./embios.py", "rb")
954
        logger.log("Loading test file (embios.py) to send over USB...\n")
955
        datastr = f.read()[:maxlen]
956
        logger.log("Sending data...\n")
957
        embios.write(memaddr, datastr)
958
        logger.log("Encrypting data with the hardware key...\n")
959
        embios.aesencrypt(memaddr, len(datastr), 0)
960
        logger.log("Reading data back and saving it to 'libembios-test-encrypted.bin'...\n")
961
        f = open("./libembios-test-encrypted.bin", "wb")
962
        f.write(embios.read(memaddr, len(datastr)))
963
        logger.log("Decrypting the data again...\n")
964
        embios.aesdecrypt(memaddr, len(datastr), 0)
965
        logger.log("Reading data back from device...\n")
966
        readdata = embios.read(memaddr, len(datastr))
967
        if readdata == datastr:
968
            logger.log("Data matches!")
969
        else:
970
            logger.log("Data does NOT match. Something went wrong")
971
 
972
    elif sys.argv[1] == "gendoc":
973
        # Generates Documentation
974
        from misc import gendoc
975
        logger.log("Generating documentation\n")
976
        cmddict = {}
977
        for attr, value in Embios.__dict__.iteritems():
978
            if getattr(value, 'func', False):
979
                if getattr(value.func, '_command', False):
980
                    cmddict[value.func.__name__] = value
981
        logger.log(gendoc(cmddict))