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