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
 
171 farthen 29
class Error(Exception):
30
    def __init__(self, value=None):
31
        self.value = value
32
    def __str__(self):
33
        if self.value != None:
34
            return repr(self.value)
56 benedikt93 35
 
171 farthen 36
class ArgumentError(Error):
37
    pass
56 benedikt93 38
 
171 farthen 39
class DeviceNotFoundError(Error):
40
    pass
56 benedikt93 41
 
171 farthen 42
class DeviceError(Error):
43
    pass
56 benedikt93 44
 
171 farthen 45
class SendError(Error):
46
    pass
56 benedikt93 47
 
171 farthen 48
class ReceiveError(Error):
49
    pass
56 benedikt93 50
 
51
 
171 farthen 52
class Bunch(dict):
56 benedikt93 53
    """
171 farthen 54
        This is a dict whose items can also be accessed with
55
        bunchinstance.something.
56 benedikt93 56
    """
171 farthen 57
    def __init__(self, **kw):
58
        dict.__init__(self, kw)
59
        self.__dict__ = self
56 benedikt93 60
 
171 farthen 61
    def __getstate__(self):
62
        return self
56 benedikt93 63
 
171 farthen 64
    def __setstate__(self, state):
65
        self.update(state)
66
        self.__dict__ = self
56 benedikt93 67
 
68
 
171 farthen 69
class Embios(object):
176 farthen 70
    """
71
        Class for all embios functions.
72
    """
171 farthen 73
    def __init__(self):
176 farthen 74
        self.lib = Lib()
75
        self.getpacketsizeinfo()
56 benedikt93 76
 
171 farthen 77
    @staticmethod
78
    def _alignsplit(addr, size, blksize, align):
177 farthen 79
        if size <= blksize: return (size, 0, 0)
171 farthen 80
        end = addr + size
81
        if addr & (align - 1):
82
            bodyaddr = (addr + min(size, blksize)) & ~(align - 1)
83
        else: bodyaddr = addr
84
        headsize = bodyaddr - addr
85
        if (size - headsize) & (align - 1):
86
            tailaddr = (end - min(end - bodyaddr, blksize) + align - 1) & ~(align - 1)
87
        else: tailaddr = end
88
        tailsize = end - tailaddr
89
        return (headsize, tailaddr - bodyaddr, tailsize)
56 benedikt93 90
 
178 farthen 91
    def _readmem(self, addr, size):
92
        """ Reads the memory from location 'addr' with size 'size'
93
            from the device.
94
        """
95
        resp = self.lib.monitorcommand(struct.pack("IIII", 4, addr, size, 0), "III%ds" % size, (None, None, None, "data"))
96
        return resp.data
97
 
98
    def _writemem(self, addr, data):
99
        """ Writes the data in 'data' to the location 'addr'
100
            in the memory of the device.
101
        """
102
        return self.lib.monitorcommand(struct.pack("IIII%ds" % len(data), 5, addr, len(data), 0, data), "III", (None, None, None))
103
 
104
    def _readdma(self, addr, size):
105
        """ Reads the memory from location 'addr' with size 'size'
106
            from the device. This uses DMA and the data in endpoint.
107
        """
108
        self.lib.monitorcommand(struct.pack("IIII", 6, addr, size, 0), "III", (None, None, None))
109
        return struct.unpack("%ds" % size, self.lib.dev.din(size))[0]
110
 
111
    def _writedma(self, addr, data):
112
        """ Writes the data in 'data' to the location 'addr'
113
            in the memory of the device. This uses DMA and the data out endpoint.
114
        """
115
        self.lib.monitorcommand(struct.pack("IIII", 7, addr, len(data), 0), "III", (None, None, None))
116
        return self.lib.dev.dout(data)
117
 
171 farthen 118
    def getversioninfo(self):
119
        """ This returns the emBIOS version and device information. """
120
        return self.lib.monitorcommand(struct.pack("IIII", 1, 0, 0, 0), "IBBBBI", ("revision", "majorv", "minorv", "patchv", "swtypeid", "hwtypeid"))
56 benedikt93 121
 
171 farthen 122
    def getpacketsizeinfo(self):
123
        """ This returns the emBIOS max packet size information.
124
            It also sets the properties of the device object accordingly.
125
        """
126
        resp = self.lib.monitorcommand(struct.pack("IIII", 1, 1, 0, 0), "HHII", ("coutmax", "cinmax", "doutmax", "dinmax"))
127
        self.lib.dev.packetsizelimit['cout'] = resp.coutmax
128
        self.lib.dev.packetsizelimit['cin'] = resp.cinmax
129
        self.lib.dev.packetsizelimit['din'] = resp.dinmax
130
        self.lib.dev.packetsizelimit['dout'] = resp.doutmax
131
        return resp
56 benedikt93 132
 
171 farthen 133
    def getusermemrange(self):
134
        """ This returns the memory range the user has access to. """
135
        return self.lib.monitorcommand(struct.pack("IIII", 1, 2, 0, 0), "III", ("lower", "upper", None))
56 benedikt93 136
 
171 farthen 137
    def reset(self, force=False):
138
        """ Reboot the device """
139
        if force:
140
            return self.lib.monitorcommand(struct.pack("IIII", 2, 0, 0, 0))
141
        else:
142
            return self.lib.monitorcommand(struct.pack("IIII", 2, 1, 0, 0), "III", (None, None, None))
56 benedikt93 143
 
171 farthen 144
    def poweroff(self, force=False):
145
        """ Powers the device off. """
146
        if force:
147
            return self.lib.monitorcommand(struct.pack("IIII", 3, 0, 0, 0))
148
        else:
149
            return self.lib.monitorcommand(struct.pack("IIII", 3, 1, 0, 0), "III", (None, None, None))
56 benedikt93 150
 
171 farthen 151
    def read(self, addr, size):
152
        """ Reads the memory from location 'addr' with size 'size'
153
            from the device. This cares about too long packages
154
            and decides whether to use DMA or not.
155
        """
176 farthen 156
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
171 farthen 157
        din_maxsize = self.lib.dev.packetsizelimit["din"]
158
        data = ""
159
        (headsize, bodysize, tailsize) = self._alignsplit(addr, size, cin_maxsize, 16)
160
        if headsize != 0:
178 farthen 161
            data += self._readmem(addr, headsize)
171 farthen 162
            addr += headsize
163
        while bodysize > 0:
164
            if bodysize >= 2 * cin_maxsize:
165
                readsize = min(bodysize, din_maxsize)
178 farthen 166
                data += self._readdma(addr, readsize)
171 farthen 167
            else:
168
                readsize = min(bodysize, cin_maxsize)
178 farthen 169
                data += self._readmem(addr, readsize)
171 farthen 170
            addr += readsize
171
            bodysize -= readsize
172
        if tailsize != 0:
178 farthen 173
            data += self._readmem(addr, tailsize)
171 farthen 174
        return data
56 benedikt93 175
 
171 farthen 176
    def write(self, addr, data):
177
        """ Writes the data in 'data' to the location 'addr'
178
            in the memory of the device. This cares about too long packages
179
            and decides whether to use DMA or not.
180
        """
176 farthen 181
        cout_maxsize = self.lib.dev.packetsizelimit["cout"] - self.lib.headersize
171 farthen 182
        dout_maxsize = self.lib.dev.packetsizelimit["dout"]
183
        (headsize, bodysize, tailsize) = self._alignsplit(addr, len(data), cout_maxsize, 16)
184
        offset = 0
185
        if headsize != 0:
178 farthen 186
            self._writemem(addr, data[offset:offset+headsize])
171 farthen 187
            offset += headsize
188
            addr += headsize
189
        while bodysize > 0:
190
            if bodysize >= 2 * cout_maxsize:
191
                writesize = min(bodysize, dout_maxsize)
178 farthen 192
                self._writedma(addr, data[offset:offset+writesize])
171 farthen 193
            else:
194
                writesize = min(bodysize, cout_maxsize)
178 farthen 195
                self._writemem(addr, data[offset:offset+writesize])
171 farthen 196
            offset += writesize
197
            addr += writesize
198
            bodysize -= writesize
199
        if tailsize != 0:
178 farthen 200
            self._writemem(addr, data[offset:offset+tailsize])
171 farthen 201
        return data
56 benedikt93 202
 
173 farthen 203
    def readstring(self, addr, maxlength = 256):
204
        """ Reads a zero terminated string from memory 
205
            Reads only a maximum of 'maxlength' chars.
206
        """
176 farthen 207
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
173 farthen 208
        string = ""
209
        while (len(string) < maxlength or maxlength < 0):
178 farthen 210
            data = self._readmem(addr, min(maxlength - len(string), cin_maxsize))
173 farthen 211
            length = data.find("\0")
212
            if length >= 0:
213
                string += data[:length]
214
                break
215
            else:
216
                string += data
217
            addr += cin_maxsize
218
        return string
219
 
171 farthen 220
    def i2cread(self, index, slaveaddr, startaddr, size):
221
        """ Reads data from an i2c slave """
176 farthen 222
        if size > 256 or size < 1:
223
            raise ValueError("Size must be a number between 1 and 256")
224
        if size == 256:
225
            size = 0
226
        resp = self.lib.monitorcommand(struct.pack("IBBBBII", 8, index, slaveaddr, startaddr, size, 0, 0), "III%ds" % size, (None, None, None, "data"))
227
        return resp.data
56 benedikt93 228
 
171 farthen 229
    def i2cwrite(self, index, slaveaddr, startaddr, data):
230
        """ Writes data to an i2c slave """
176 farthen 231
        size = len(data)
232
        if size > 256 or size < 1:
233
            raise ValueError("Size must be a number between 1 and 256")
234
        if size == 256:
235
            size = 0
215 theseven 236
        return self.lib.monitorcommand(struct.pack("IBBBBII%ds" % size, 9, index, slaveaddr, startaddr, size, 0, 0, data), "III", (None, None, None))
56 benedikt93 237
 
176 farthen 238
    def usbcread(self):
239
        """ Reads one packet with the maximal cin size """
240
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
241
        resp = self.lib.monitorcommand(struct.pack("IIII", 10, cin_maxsize, 0, 0), "III%ds" % cin_maxsize, ("validsize", "buffersize", "queuesize", "data"))
242
        resp.data = resp.data[:resp.validsize]
243
        resp.maxsize = cin_maxsize
244
        return resp
56 benedikt93 245
 
171 farthen 246
    def usbcwrite(self, data):
247
        """ Writes data to the USB console """
176 farthen 248
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
249
        size = len(data)
250
        while len(data) > 0:
251
            writesize = min(cin_maxsize, len(data))
252
            resp = self.lib.monitorcommand(struct.pack("IIII%ds" % writesize, 11, writesize, 0, 0, data[:writesize]), "III", ("validsize", "buffersize", "freesize"))
253
            data = data[resp.validsize:]
254
        return size
56 benedikt93 255
 
176 farthen 256
    def cread(self, bitmask=0x1):
257
        """ Reads one packet with the maximal cin size from the device consoles
171 farthen 258
            identified with the specified bitmask
259
        """
176 farthen 260
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
217 theseven 261
        resp = self.lib.monitorcommand(struct.pack("IIII", 13, bitmask, cin_maxsize, 0), "III%ds" % cin_maxsize, ("size", None, None))
176 farthen 262
        resp.data = resp.data[size:]
263
        resp.maxsize = cin_maxsize
264
        return resp
56 benedikt93 265
 
176 farthen 266
    def cwrite(self, data, bitmask=0x1):
171 farthen 267
        """ Writes data to the device consoles 
268
            identified with the specified bitmask.
269
        """
176 farthen 270
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
271
        size = len(data)
272
        while len(data) > 0:
273
            writesize = min(cin_maxsize, len(data))
217 theseven 274
            resp = self.lib.monitorcommand(struct.pack("IIII%ds" % writesize, 12, bitmask, writesize, 0, data[:writesize]), "III", (None, None, None))
176 farthen 275
            data = data[writesize:]
276
        return size
56 benedikt93 277
 
171 farthen 278
    def cflush(self, bitmask):
279
        """ Flushes the consoles specified with 'bitmask' """
280
        return self.lib.monitorcommand(struct.pack("IIII", 14, bitmask, 0, 0), "III", (None, None, None))
56 benedikt93 281
 
173 farthen 282
    def getprocinfo(self):
171 farthen 283
        """ Gets current state of the scheduler """
176 farthen 284
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
173 farthen 285
        # Get the size
286
        schedulerstate = self.lockscheduler()
287
        resp = self.lib.monitorcommand(struct.pack("IIII", 15, 0, 0, 0), "III", ("structver", "tablesize", None))
288
        tablesize = resp.tablesize
289
        size = tablesize
290
        structver = resp.structver
291
        offset = 0
292
        data = ""
293
        while size > 0:
294
            if size > cin_maxsize:
295
                readsize = cin_maxsize
296
            else:
297
                readsize = size
298
            resp = self.lib.monitorcommand(struct.pack("IIII", 15, offset, readsize, 0), "III%ds" % readsize, ("structver", "tablesize", None, "data"))
299
            data += resp.data
300
            offset += readsize
301
            size -= readsize
302
        self.lockscheduler(schedulerstate)
303
        threadstructsize = 120
304
        registersize = 32
305
        if len(data) % threadstructsize != 0:
306
            raise DeviceError("The thread struct is not a multiple of "+str(threadsturcsize)+"!")
307
        threadcount = len(data) / threadstructsize
308
        threads = []
309
        id = 0
310
        for thread in range(threadcount):
311
            offset = threadstructsize * thread
312
            threaddata = struct.unpack("<16IIIIIQIIIIIIIBBBB", data[offset:offset+threadstructsize])
313
            info = Bunch()
314
            info.id = id
315
            state = threaddata[17]
316
            info.state = libembiosdata.thread_state[state]
317
            if info.state == "THREAD_FREE":
318
                id += 1
319
                continue
320
            info.regs = Bunch()
321
            for register in range(16):
322
                info.regs["r"+str(register)] = threaddata[register]
323
            info.regs.cpsr = threaddata[16]
324
            info.nameptr = threaddata[18]
325
            if info.nameptr == 0:
326
                info.name = "Thread %d" % info.id
327
            else:
328
                info.name = self.readstring(info.nameptr)
329
            info.cputime_current = threaddata[19]
330
            info.cputime_total = threaddata[20]
331
            info.startusec = threaddata[21]
332
            info.queue_next_ptr = threaddata[22]
333
            info.timeout = threaddata[23]
334
            info.blocked_since = threaddata[24]
335
            info.blocked_by_ptr = threaddata[25]
336
            info.stackaddr = threaddata[26]
337
            info.err_no = threaddata[27]
338
            info.block_type = libembiosdata.thread_block[threaddata[28]]
339
            info.type = libembiosdata.thread_type[threaddata[29]]
340
            info.priority = threaddata[30]
341
            info.cpuload = threaddata[31]
342
            threads.append(info)
343
            id += 1
344
        return threads
56 benedikt93 345
 
173 farthen 346
    def lockscheduler(self, freeze=True):
171 farthen 347
        """ Freezes/Unfreezes the scheduler """
173 farthen 348
        resp = self.lib.monitorcommand(struct.pack("IIII", 16, 1 if freeze else 0, 0, 0), "III", ("before", None, None))
349
        return True if resp.before == 1 else False
67 benedikt93 350
 
173 farthen 351
    def unlockscheduler(self):
171 farthen 352
        """ Unfreezes the scheduler """
353
        return self.lib.monitorcommand(struct.pack("IIII", 16, 0, 0, 0), "III", ("before", None, None))
56 benedikt93 354
 
171 farthen 355
    def suspendthread(self, id, suspend=True):
356
        """ Suspends the thread with the specified id """
173 farthen 357
        resp = self.lib.monitorcommand(struct.pack("IIII", 17, 1 if suspend else 0, id, 0), "III", ("before", None, None))
358
        return True if resp.before == 1 else False
56 benedikt93 359
 
173 farthen 360
    def resumethread(self, id):
361
        """ Resumes the thread with the specified id """
171 farthen 362
        return self.lib.monitorcommand(struct.pack("IIII", 17, 0, id, 0), "III", ("before", None, None))
56 benedikt93 363
 
171 farthen 364
    def killthread(self, id):
365
        """ Kills the thread with the specified id """
366
        return self.lib.monitorcommand(struct.pack("IIII", 18, id, 0, 0), "III", ("before", None, None))
56 benedikt93 367
 
171 farthen 368
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
369
        """ Creates a thread with the specified attributes """
370
        if threadtype == "user":
371
            threadtype = 0
372
        elif threadtype == "system":
373
            threadtype = 1
374
        else:
176 farthen 375
            raise ValueError("Threadtype must be either 'system' or 'user'")
171 farthen 376
        if priority > 256 or priority < 0:
176 farthen 377
            raise ValueError("Priority must be a number between 0 and 256")
171 farthen 378
        if state == "ready":
379
            state = 0
380
        elif state == "suspended":
381
            state = 1
382
        else:
176 farthen 383
            raise ValueError("State must be either 'ready' or 'suspended'")
171 farthen 384
        resp = self.lib.monitorcommand(struct.pack("IIIIIIII", 19, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state), "III", (id, None, None))
385
        if resp.id < 0:
386
            raise DeviceError("The device returned the error code "+str(resp.id))
387
        return resp
56 benedikt93 388
 
172 farthen 389
    def flushcaches(self):
171 farthen 390
        """ Flushes the CPU instruction and data cache """
391
        return self.lib.monitorcommand(struct.pack("IIII", 20, 0, 0, 0), "III", (None, None, None))
56 benedikt93 392
 
172 farthen 393
    def execimage(self, addr):
171 farthen 394
        """ Runs the emBIOS app at 'addr' """
395
        return self.lib.monitorcommand(struct.pack("IIII", 21, addr, 0, 0), "III", ("excecimage", None, None))
56 benedikt93 396
 
171 farthen 397
    def bootflashread(self, memaddr, flashaddr, size):
398
        """ Copies the data in the bootflash at 'flashaddr' of the specified size
399
            to the memory at addr 'memaddr'
400
        """
174 farthen 401
        return self.lib.monitorcommand(struct.pack("IIII", 22, memaddr, flashaddr, size), "III", (None, None, None))
82 benedikt93 402
 
171 farthen 403
    def bootflashwrite(self, memaddr, flashaddr, size):
404
        """ Copies the data in the memory at 'memaddr' of the specified size
405
            to the boot flash at addr 'flashaddr'
406
        """
174 farthen 407
        return self.lib.monitorcommand(struct.pack("IIII", 23, memaddr, flashaddr, size), "III", (None, None, None))
56 benedikt93 408
 
171 farthen 409
    def execfirmware(self, addr):
410
        """ Executes the firmware at 'addr' and passes all control to it. """
411
        return self.lib.monitorcommand(struct.pack("IIII", 24, addr, 0, 0), "III", (None, None, None))
56 benedikt93 412
 
171 farthen 413
    def aesencrypt(self, addr, size, keyindex):
414
        """ Encrypts the buffer at 'addr' with the specified size
415
            with the hardware AES key index 'keyindex'
416
        """
417
        return self.lib.monitorcommand(struct.pack("IBBHII", 25, 1, 0, keyindex, addr, size), "III", (None, None, None))
82 benedikt93 418
 
171 farthen 419
    def aesdecrypt(self, addr, size, keyindex):
420
        """ Decrypts the buffer at 'addr' with the specified size
421
            with the hardware AES key index 'keyindex'
422
        """
423
        return self.lib.monitorcommand(struct.pack("IBBHII", 25, 0, 0, keyindex, addr, size), "III", (None, None, None))
82 benedikt93 424
 
171 farthen 425
    def hmac_sha1(self, addr, size, destination):
426
        """ Generates a HMAC-SHA1 hash of the buffer and saves it to 'destination' """
427
        return self.lib.monitorcommand(struct.pack("IIII", 26, addr, size, destination), "III", (None, None, None))
56 benedikt93 428
 
227 theseven 429
    def ipodnano2g_getnandinfo(self):
430
        """ Target-specific function: ipodnano2g
431
            Gathers some information about the NAND chip used
432
        """
433
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0001, 0, 0, 0), "IHHHH", ("type", "pagesperblock", "banks", "userblocks", "blocks"))
434
 
435
    def ipodnano2g_nandread(self, addr, start, count, doecc, checkempty):
436
        """ Target-specific function: ipodnano2g
437
            Reads data from the NAND chip into memory
438
        """
439
        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))
440
 
441
    def ipodnano2g_nandwrite(self, addr, start, count, doecc):
442
        """ Target-specific function: ipodnano2g
443
            Writes data to the NAND chip
444
        """
445
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0003, addr | (0x80000000 if doecc != 0 else 0), start, count), "III", (None, None, None))
446
 
447
    def ipodnano2g_nanderase(self, addr, start, count):
448
        """ Target-specific function: ipodnano2g
449
            Erases blocks on the NAND chip and stores the results to memory
450
        """
451
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0004, addr, start, count), "III", (None, None, None))
452
 
56 benedikt93 453
 
171 farthen 454
class Lib(object):
176 farthen 455
    def __init__(self):
171 farthen 456
        self.idVendor = 0xFFFF
457
        self.idProduct = 0xE000
176 farthen 458
 
459
        self.headersize = 0x10
460
 
461
        self.connect()
56 benedikt93 462
 
171 farthen 463
    def connect(self):
464
        self.dev = Dev(self.idVendor, self.idProduct)
465
        self.connected = True
56 benedikt93 466
 
171 farthen 467
    def monitorcommand(self, cmd, rcvdatatypes=None, rcvstruct=None):
468
        self.dev.cout(cmd)
469
        if rcvdatatypes:
470
            rcvdatatypes = "I" + rcvdatatypes # add the response
471
            data = self.dev.cin(struct.calcsize(rcvdatatypes))
472
            data = struct.unpack(rcvdatatypes, data)
473
            response = data[0]
474
            if libembiosdata.responsecodes[response] == "ok":
475
                if rcvstruct:
476
                    datadict = Bunch()
477
                    counter = 1 # start with 1, 0 is the id
478
                    for item in rcvstruct:
479
                        if item != None: # else the data is undefined
480
                            datadict[item] = data[counter]
481
                        counter += 1
482
                    return datadict
483
                else:
484
                    return data
485
            elif libembiosdata.responsecodes[response] == "unsupported":
486
                raise DeviceError("The device does not support this command.")
487
            elif libembiosdata.responsecodes[response] == "invalid":
488
                raise DeviceError("Invalid command! This should NOT happen!")
489
            elif libembiosdata.responsecodes[response] == "busy":
490
                raise DeviceError("Device busy")
56 benedikt93 491
 
492
 
171 farthen 493
class Dev(object):
494
    def __init__(self, idVendor, idProduct):
495
        self.idVendor = idVendor
496
        self.idProduct = idProduct
67 benedikt93 497
 
171 farthen 498
        self.interface = 0
499
        self.timeout = 100
176 farthen 500
 
171 farthen 501
        self.connect()
502
        self.findEndpoints()
503
 
504
        self.packetsizelimit = {}
505
        self.packetsizelimit['cout'] = None
506
        self.packetsizelimit['cin'] = None
507
        self.packetsizelimit['dout'] = None
508
        self.packetsizelimit['din'] = None
56 benedikt93 509
 
171 farthen 510
    def __del__(self):
511
        self.disconnect()
56 benedikt93 512
 
171 farthen 513
    def findEndpoints(self):
514
        epcounter = 0
515
        self.endpoint = {}
516
        for cfg in self.dev:
517
            for intf in cfg:
518
                for ep in intf:
519
                    if epcounter == 0:
520
                        self.endpoint['cout'] = ep.bEndpointAddress
521
                    elif epcounter == 1:
522
                        self.endpoint['cin'] = ep.bEndpointAddress
523
                    elif epcounter == 2:
524
                        self.endpoint['dout'] = ep.bEndpointAddress
525
                    elif epcounter == 3:
526
                        self.endpoint['din'] = ep.bEndpointAddress
527
                    epcounter += 1
528
        if epcounter <= 3:
529
            raise DeviceError("Not all endpoints found in the descriptor. Only "+str(epcounter)+" found, we need 4")
56 benedikt93 530
 
171 farthen 531
    def connect(self):
532
        self.dev = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
533
        if self.dev is None:
534
            raise DeviceNotFoundError()
535
        self.dev.set_configuration()
56 benedikt93 536
 
171 farthen 537
    def disconnect(self):
538
        pass
102 benedikt93 539
 
171 farthen 540
    def send(self, endpoint, data):
541
        size = self.dev.write(endpoint, data, self.interface, self.timeout)
542
        if size != len(data):
176 farthen 543
            raise SendError("Not all data was written!")
171 farthen 544
        return len
102 benedikt93 545
 
171 farthen 546
    def receive(self, endpoint, size):
547
        read = self.dev.read(endpoint, size, self.interface, self.timeout)
548
        if len(read) != size:
176 farthen 549
            raise ReceiveError("Requested size and read size don't match!")
171 farthen 550
        return read
56 benedikt93 551
 
171 farthen 552
    def cout(self, data):
553
        if self.packetsizelimit['cout'] and len(data) > self.packetsizelimit['cout']:
554
            raise SendError("Packet too big")
555
        return self.send(self.endpoint['cout'], data)
94 benedikt93 556
 
171 farthen 557
    def cin(self, size):
558
        if self.packetsizelimit['cin'] and size > self.packetsizelimit['cin']:
559
            raise ReceiveError("Packet too big")
560
        return self.receive(self.endpoint['cin'], size)
94 benedikt93 561
 
171 farthen 562
    def dout(self, data):
563
        if self.packetsizelimit['dout'] and len(data) > self.packetsizelimit['dout']:
564
            raise SendError("Packet too big")
565
        return self.send(self.endpoint['dout'], data)
94 benedikt93 566
 
171 farthen 567
    def din(self, size):
568
        if self.packetsizelimit['din'] and size > self.packetsizelimit['din']:
569
            raise ReceiveError("Packet too big")
570
        return self.receive(self.endpoint['din'], size)
56 benedikt93 571
 
96 benedikt93 572
 
171 farthen 573
if __name__ == "__main__":
574
    # Some tests
575
    import sys
576
    embios = Embios()
577
    resp = embios.getversioninfo()
578
    sys.stdout.write("Embios device version information: " + libembiosdata.swtypes[resp.swtypeid] + " v" + str(resp.majorv) + "." + str(resp.minorv) + 
579
                     "." + str(resp.patchv) + " r" + str(resp.revision) + " running on " + libembiosdata.hwtypes[resp.hwtypeid] + "\n")
580
    resp = embios.getusermemrange()
581
    sys.stdout.write("Usermemrange: "+hex(resp.lower)+" - "+hex(resp.upper)+"\n")
582
    memaddr = resp.lower
583
    maxlen = resp.upper - resp.lower
584
    f = open("./embios.py", "rb")
585
    sys.stdout.write("Loading test file (embios.py) to send over USB...\n")
586
    datastr = f.read()[:maxlen]
587
    sys.stdout.write("Sending data...\n")
588
    embios.write(memaddr, datastr)
589
    sys.stdout.write("Encrypting data with the hardware key...\n")
590
    embios.aesencrypt(memaddr, len(datastr), 0)
591
    sys.stdout.write("Reading data back and saving it to 'libembios-test-encrypted.bin'...\n")
592
    f = open("./libembios-test-encrypted.bin", "wb")
593
    f.write(embios.read(memaddr, len(datastr)))
594
    sys.stdout.write("Decrypting the data again...\n")
595
    embios.aesdecrypt(memaddr, len(datastr), 0)
596
    sys.stdout.write("Reading data back from device...\n")
597
    readdata = embios.read(memaddr, len(datastr))
598
    if readdata == datastr:
599
        sys.stdout.write("Data matches!")
600
    else:
601
        sys.stdout.write("Data does NOT match. Something got wrong")