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 """
236 farthen 222
        data = ""
223
        for i in range(size):
224
            resp = self.lib.monitorcommand(struct.pack("IBBBBII", 8, index, slaveaddr, startaddr + i, 1, 0, 0), "III1s", (None, None, None, "data"))
225
            data += resp.data
226
        return data
56 benedikt93 227
 
171 farthen 228
    def i2cwrite(self, index, slaveaddr, startaddr, data):
229
        """ Writes data to an i2c slave """
176 farthen 230
        size = len(data)
231
        if size > 256 or size < 1:
232
            raise ValueError("Size must be a number between 1 and 256")
233
        if size == 256:
234
            size = 0
215 theseven 235
        return self.lib.monitorcommand(struct.pack("IBBBBII%ds" % size, 9, index, slaveaddr, startaddr, size, 0, 0, data), "III", (None, None, None))
56 benedikt93 236
 
176 farthen 237
    def usbcread(self):
238
        """ Reads one packet with the maximal cin size """
239
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
240
        resp = self.lib.monitorcommand(struct.pack("IIII", 10, cin_maxsize, 0, 0), "III%ds" % cin_maxsize, ("validsize", "buffersize", "queuesize", "data"))
241
        resp.data = resp.data[:resp.validsize]
242
        resp.maxsize = cin_maxsize
243
        return resp
56 benedikt93 244
 
171 farthen 245
    def usbcwrite(self, data):
246
        """ Writes data to the USB console """
176 farthen 247
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
248
        size = len(data)
249
        while len(data) > 0:
250
            writesize = min(cin_maxsize, len(data))
251
            resp = self.lib.monitorcommand(struct.pack("IIII%ds" % writesize, 11, writesize, 0, 0, data[:writesize]), "III", ("validsize", "buffersize", "freesize"))
252
            data = data[resp.validsize:]
253
        return size
56 benedikt93 254
 
176 farthen 255
    def cread(self, bitmask=0x1):
256
        """ Reads one packet with the maximal cin size from the device consoles
171 farthen 257
            identified with the specified bitmask
258
        """
176 farthen 259
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
217 theseven 260
        resp = self.lib.monitorcommand(struct.pack("IIII", 13, bitmask, cin_maxsize, 0), "III%ds" % cin_maxsize, ("size", None, None))
176 farthen 261
        resp.data = resp.data[size:]
262
        resp.maxsize = cin_maxsize
263
        return resp
56 benedikt93 264
 
176 farthen 265
    def cwrite(self, data, bitmask=0x1):
171 farthen 266
        """ Writes data to the device consoles 
267
            identified with the specified bitmask.
268
        """
176 farthen 269
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
270
        size = len(data)
271
        while len(data) > 0:
272
            writesize = min(cin_maxsize, len(data))
217 theseven 273
            resp = self.lib.monitorcommand(struct.pack("IIII%ds" % writesize, 12, bitmask, writesize, 0, data[:writesize]), "III", (None, None, None))
176 farthen 274
            data = data[writesize:]
275
        return size
56 benedikt93 276
 
171 farthen 277
    def cflush(self, bitmask):
278
        """ Flushes the consoles specified with 'bitmask' """
279
        return self.lib.monitorcommand(struct.pack("IIII", 14, bitmask, 0, 0), "III", (None, None, None))
56 benedikt93 280
 
173 farthen 281
    def getprocinfo(self):
171 farthen 282
        """ Gets current state of the scheduler """
176 farthen 283
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
173 farthen 284
        # Get the size
285
        schedulerstate = self.lockscheduler()
286
        resp = self.lib.monitorcommand(struct.pack("IIII", 15, 0, 0, 0), "III", ("structver", "tablesize", None))
287
        tablesize = resp.tablesize
288
        size = tablesize
289
        structver = resp.structver
290
        offset = 0
291
        data = ""
292
        while size > 0:
293
            if size > cin_maxsize:
294
                readsize = cin_maxsize
295
            else:
296
                readsize = size
297
            resp = self.lib.monitorcommand(struct.pack("IIII", 15, offset, readsize, 0), "III%ds" % readsize, ("structver", "tablesize", None, "data"))
298
            data += resp.data
299
            offset += readsize
300
            size -= readsize
301
        self.lockscheduler(schedulerstate)
302
        threadstructsize = 120
303
        registersize = 32
304
        if len(data) % threadstructsize != 0:
305
            raise DeviceError("The thread struct is not a multiple of "+str(threadsturcsize)+"!")
306
        threadcount = len(data) / threadstructsize
307
        threads = []
308
        id = 0
309
        for thread in range(threadcount):
310
            offset = threadstructsize * thread
311
            threaddata = struct.unpack("<16IIIIIQIIIIIIIBBBB", data[offset:offset+threadstructsize])
312
            info = Bunch()
313
            info.id = id
314
            state = threaddata[17]
315
            info.state = libembiosdata.thread_state[state]
316
            if info.state == "THREAD_FREE":
317
                id += 1
318
                continue
319
            info.regs = Bunch()
320
            for register in range(16):
321
                info.regs["r"+str(register)] = threaddata[register]
322
            info.regs.cpsr = threaddata[16]
323
            info.nameptr = threaddata[18]
324
            if info.nameptr == 0:
325
                info.name = "Thread %d" % info.id
326
            else:
327
                info.name = self.readstring(info.nameptr)
328
            info.cputime_current = threaddata[19]
329
            info.cputime_total = threaddata[20]
330
            info.startusec = threaddata[21]
331
            info.queue_next_ptr = threaddata[22]
332
            info.timeout = threaddata[23]
333
            info.blocked_since = threaddata[24]
334
            info.blocked_by_ptr = threaddata[25]
335
            info.stackaddr = threaddata[26]
336
            info.err_no = threaddata[27]
337
            info.block_type = libembiosdata.thread_block[threaddata[28]]
338
            info.type = libembiosdata.thread_type[threaddata[29]]
339
            info.priority = threaddata[30]
340
            info.cpuload = threaddata[31]
341
            threads.append(info)
342
            id += 1
343
        return threads
56 benedikt93 344
 
173 farthen 345
    def lockscheduler(self, freeze=True):
171 farthen 346
        """ Freezes/Unfreezes the scheduler """
173 farthen 347
        resp = self.lib.monitorcommand(struct.pack("IIII", 16, 1 if freeze else 0, 0, 0), "III", ("before", None, None))
348
        return True if resp.before == 1 else False
67 benedikt93 349
 
173 farthen 350
    def unlockscheduler(self):
171 farthen 351
        """ Unfreezes the scheduler """
352
        return self.lib.monitorcommand(struct.pack("IIII", 16, 0, 0, 0), "III", ("before", None, None))
56 benedikt93 353
 
171 farthen 354
    def suspendthread(self, id, suspend=True):
355
        """ Suspends the thread with the specified id """
173 farthen 356
        resp = self.lib.monitorcommand(struct.pack("IIII", 17, 1 if suspend else 0, id, 0), "III", ("before", None, None))
357
        return True if resp.before == 1 else False
56 benedikt93 358
 
173 farthen 359
    def resumethread(self, id):
360
        """ Resumes the thread with the specified id """
171 farthen 361
        return self.lib.monitorcommand(struct.pack("IIII", 17, 0, id, 0), "III", ("before", None, None))
56 benedikt93 362
 
171 farthen 363
    def killthread(self, id):
364
        """ Kills the thread with the specified id """
365
        return self.lib.monitorcommand(struct.pack("IIII", 18, id, 0, 0), "III", ("before", None, None))
56 benedikt93 366
 
171 farthen 367
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
368
        """ Creates a thread with the specified attributes """
369
        if threadtype == "user":
370
            threadtype = 0
371
        elif threadtype == "system":
372
            threadtype = 1
373
        else:
176 farthen 374
            raise ValueError("Threadtype must be either 'system' or 'user'")
171 farthen 375
        if priority > 256 or priority < 0:
176 farthen 376
            raise ValueError("Priority must be a number between 0 and 256")
171 farthen 377
        if state == "ready":
378
            state = 0
379
        elif state == "suspended":
380
            state = 1
381
        else:
176 farthen 382
            raise ValueError("State must be either 'ready' or 'suspended'")
171 farthen 383
        resp = self.lib.monitorcommand(struct.pack("IIIIIIII", 19, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state), "III", (id, None, None))
384
        if resp.id < 0:
385
            raise DeviceError("The device returned the error code "+str(resp.id))
386
        return resp
56 benedikt93 387
 
172 farthen 388
    def flushcaches(self):
171 farthen 389
        """ Flushes the CPU instruction and data cache """
390
        return self.lib.monitorcommand(struct.pack("IIII", 20, 0, 0, 0), "III", (None, None, None))
56 benedikt93 391
 
172 farthen 392
    def execimage(self, addr):
171 farthen 393
        """ Runs the emBIOS app at 'addr' """
394
        return self.lib.monitorcommand(struct.pack("IIII", 21, addr, 0, 0), "III", ("excecimage", None, None))
56 benedikt93 395
 
238 farthen 396
    def run(self, app):
397
        """ Uploads and runs the emBIOS app in the string 'app' """
398
        try:
399
            appheader = struct.unpack("<8sIIIIIIIIII", app[:48])
400
        except struct.error:
401
            raise ArgumentError("The specified file is not an emBIOS application")
402
        header = appheader[0]
403
        if header != "emBIexec":
404
            raise ArgumentError("The specified file is not an emBIOS application")
405
        baseaddr = appheader[2]
406
        threadnameptr = appheader[8]
407
        nameptr = threadnameptr - baseaddr
408
        name = ""
409
        while True:
410
            char = app[nameptr:nameptr+1]
411
            try:
412
                if ord(char) == 0:
413
                    break
414
            except TypeError:
415
                raise ArgumentError("The specified file is not an emBIOS application")
416
            name += char
417
            nameptr += 1
418
        usermem = self.getusermemrange()
419
        if usermem.lower > baseaddr or usermem.upper < baseaddr + len(app):
420
            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?")
421
        self.write(baseaddr, app)
422
        self.execimage(baseaddr)
423
        return Bunch(baseaddr=baseaddr, name=name)
424
 
171 farthen 425
    def bootflashread(self, memaddr, flashaddr, size):
426
        """ Copies the data in the bootflash at 'flashaddr' of the specified size
427
            to the memory at addr 'memaddr'
428
        """
174 farthen 429
        return self.lib.monitorcommand(struct.pack("IIII", 22, memaddr, flashaddr, size), "III", (None, None, None))
82 benedikt93 430
 
171 farthen 431
    def bootflashwrite(self, memaddr, flashaddr, size):
432
        """ Copies the data in the memory at 'memaddr' of the specified size
433
            to the boot flash at addr 'flashaddr'
434
        """
174 farthen 435
        return self.lib.monitorcommand(struct.pack("IIII", 23, memaddr, flashaddr, size), "III", (None, None, None))
56 benedikt93 436
 
171 farthen 437
    def execfirmware(self, addr):
438
        """ Executes the firmware at 'addr' and passes all control to it. """
269 farthen 439
        return self.lib.monitorcommand(struct.pack("IIII", 24, addr, 0, 0))
56 benedikt93 440
 
171 farthen 441
    def aesencrypt(self, addr, size, keyindex):
442
        """ Encrypts the buffer at 'addr' with the specified size
443
            with the hardware AES key index 'keyindex'
444
        """
445
        return self.lib.monitorcommand(struct.pack("IBBHII", 25, 1, 0, keyindex, addr, size), "III", (None, None, None))
82 benedikt93 446
 
171 farthen 447
    def aesdecrypt(self, addr, size, keyindex):
448
        """ Decrypts the buffer at 'addr' with the specified size
449
            with the hardware AES key index 'keyindex'
450
        """
451
        return self.lib.monitorcommand(struct.pack("IBBHII", 25, 0, 0, keyindex, addr, size), "III", (None, None, None))
82 benedikt93 452
 
171 farthen 453
    def hmac_sha1(self, addr, size, destination):
454
        """ Generates a HMAC-SHA1 hash of the buffer and saves it to 'destination' """
455
        return self.lib.monitorcommand(struct.pack("IIII", 26, addr, size, destination), "III", (None, None, None))
56 benedikt93 456
 
227 theseven 457
    def ipodnano2g_getnandinfo(self):
458
        """ Target-specific function: ipodnano2g
459
            Gathers some information about the NAND chip used
460
        """
461
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0001, 0, 0, 0), "IHHHH", ("type", "pagesperblock", "banks", "userblocks", "blocks"))
462
 
463
    def ipodnano2g_nandread(self, addr, start, count, doecc, checkempty):
464
        """ Target-specific function: ipodnano2g
465
            Reads data from the NAND chip into memory
466
        """
467
        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))
468
 
469
    def ipodnano2g_nandwrite(self, addr, start, count, doecc):
470
        """ Target-specific function: ipodnano2g
471
            Writes data to the NAND chip
472
        """
473
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0003, addr | (0x80000000 if doecc != 0 else 0), start, count), "III", (None, None, None))
474
 
475
    def ipodnano2g_nanderase(self, addr, start, count):
476
        """ Target-specific function: ipodnano2g
477
            Erases blocks on the NAND chip and stores the results to memory
478
        """
479
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0004, addr, start, count), "III", (None, None, None))
480
 
56 benedikt93 481
 
171 farthen 482
class Lib(object):
176 farthen 483
    def __init__(self):
171 farthen 484
        self.idVendor = 0xFFFF
485
        self.idProduct = 0xE000
176 farthen 486
 
487
        self.headersize = 0x10
488
 
489
        self.connect()
56 benedikt93 490
 
171 farthen 491
    def connect(self):
492
        self.dev = Dev(self.idVendor, self.idProduct)
493
        self.connected = True
56 benedikt93 494
 
171 farthen 495
    def monitorcommand(self, cmd, rcvdatatypes=None, rcvstruct=None):
269 farthen 496
        writelen = self.dev.cout(cmd)
171 farthen 497
        if rcvdatatypes:
498
            rcvdatatypes = "I" + rcvdatatypes # add the response
499
            data = self.dev.cin(struct.calcsize(rcvdatatypes))
500
            data = struct.unpack(rcvdatatypes, data)
501
            response = data[0]
502
            if libembiosdata.responsecodes[response] == "ok":
503
                if rcvstruct:
504
                    datadict = Bunch()
505
                    counter = 1 # start with 1, 0 is the id
506
                    for item in rcvstruct:
507
                        if item != None: # else the data is undefined
508
                            datadict[item] = data[counter]
509
                        counter += 1
510
                    return datadict
511
                else:
512
                    return data
513
            elif libembiosdata.responsecodes[response] == "unsupported":
514
                raise DeviceError("The device does not support this command.")
515
            elif libembiosdata.responsecodes[response] == "invalid":
516
                raise DeviceError("Invalid command! This should NOT happen!")
517
            elif libembiosdata.responsecodes[response] == "busy":
518
                raise DeviceError("Device busy")
269 farthen 519
        else:
520
            return writelen
56 benedikt93 521
 
522
 
171 farthen 523
class Dev(object):
524
    def __init__(self, idVendor, idProduct):
525
        self.idVendor = idVendor
526
        self.idProduct = idProduct
67 benedikt93 527
 
171 farthen 528
        self.interface = 0
529
        self.timeout = 100
176 farthen 530
 
171 farthen 531
        self.connect()
532
        self.findEndpoints()
533
 
534
        self.packetsizelimit = {}
535
        self.packetsizelimit['cout'] = None
536
        self.packetsizelimit['cin'] = None
537
        self.packetsizelimit['dout'] = None
538
        self.packetsizelimit['din'] = None
56 benedikt93 539
 
171 farthen 540
    def __del__(self):
541
        self.disconnect()
56 benedikt93 542
 
171 farthen 543
    def findEndpoints(self):
544
        epcounter = 0
545
        self.endpoint = {}
546
        for cfg in self.dev:
547
            for intf in cfg:
548
                for ep in intf:
549
                    if epcounter == 0:
550
                        self.endpoint['cout'] = ep.bEndpointAddress
551
                    elif epcounter == 1:
552
                        self.endpoint['cin'] = ep.bEndpointAddress
553
                    elif epcounter == 2:
554
                        self.endpoint['dout'] = ep.bEndpointAddress
555
                    elif epcounter == 3:
556
                        self.endpoint['din'] = ep.bEndpointAddress
557
                    epcounter += 1
558
        if epcounter <= 3:
559
            raise DeviceError("Not all endpoints found in the descriptor. Only "+str(epcounter)+" found, we need 4")
56 benedikt93 560
 
171 farthen 561
    def connect(self):
562
        self.dev = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
563
        if self.dev is None:
564
            raise DeviceNotFoundError()
565
        self.dev.set_configuration()
56 benedikt93 566
 
171 farthen 567
    def disconnect(self):
568
        pass
102 benedikt93 569
 
171 farthen 570
    def send(self, endpoint, data):
571
        size = self.dev.write(endpoint, data, self.interface, self.timeout)
572
        if size != len(data):
176 farthen 573
            raise SendError("Not all data was written!")
171 farthen 574
        return len
102 benedikt93 575
 
171 farthen 576
    def receive(self, endpoint, size):
577
        read = self.dev.read(endpoint, size, self.interface, self.timeout)
578
        if len(read) != size:
176 farthen 579
            raise ReceiveError("Requested size and read size don't match!")
171 farthen 580
        return read
56 benedikt93 581
 
171 farthen 582
    def cout(self, data):
583
        if self.packetsizelimit['cout'] and len(data) > self.packetsizelimit['cout']:
584
            raise SendError("Packet too big")
585
        return self.send(self.endpoint['cout'], data)
94 benedikt93 586
 
171 farthen 587
    def cin(self, size):
588
        if self.packetsizelimit['cin'] and size > self.packetsizelimit['cin']:
589
            raise ReceiveError("Packet too big")
590
        return self.receive(self.endpoint['cin'], size)
94 benedikt93 591
 
171 farthen 592
    def dout(self, data):
593
        if self.packetsizelimit['dout'] and len(data) > self.packetsizelimit['dout']:
594
            raise SendError("Packet too big")
595
        return self.send(self.endpoint['dout'], data)
94 benedikt93 596
 
171 farthen 597
    def din(self, size):
598
        if self.packetsizelimit['din'] and size > self.packetsizelimit['din']:
599
            raise ReceiveError("Packet too big")
600
        return self.receive(self.endpoint['din'], size)
56 benedikt93 601
 
96 benedikt93 602
 
171 farthen 603
if __name__ == "__main__":
604
    # Some tests
605
    import sys
606
    embios = Embios()
607
    resp = embios.getversioninfo()
608
    sys.stdout.write("Embios device version information: " + libembiosdata.swtypes[resp.swtypeid] + " v" + str(resp.majorv) + "." + str(resp.minorv) + 
609
                     "." + str(resp.patchv) + " r" + str(resp.revision) + " running on " + libembiosdata.hwtypes[resp.hwtypeid] + "\n")
610
    resp = embios.getusermemrange()
611
    sys.stdout.write("Usermemrange: "+hex(resp.lower)+" - "+hex(resp.upper)+"\n")
612
    memaddr = resp.lower
613
    maxlen = resp.upper - resp.lower
614
    f = open("./embios.py", "rb")
615
    sys.stdout.write("Loading test file (embios.py) to send over USB...\n")
616
    datastr = f.read()[:maxlen]
617
    sys.stdout.write("Sending data...\n")
618
    embios.write(memaddr, datastr)
619
    sys.stdout.write("Encrypting data with the hardware key...\n")
620
    embios.aesencrypt(memaddr, len(datastr), 0)
621
    sys.stdout.write("Reading data back and saving it to 'libembios-test-encrypted.bin'...\n")
622
    f = open("./libembios-test-encrypted.bin", "wb")
623
    f.write(embios.read(memaddr, len(datastr)))
624
    sys.stdout.write("Decrypting the data again...\n")
625
    embios.aesdecrypt(memaddr, len(datastr), 0)
626
    sys.stdout.write("Reading data back from device...\n")
627
    readdata = embios.read(memaddr, len(datastr))
628
    if readdata == datastr:
629
        sys.stdout.write("Data matches!")
630
    else:
631
        sys.stdout.write("Data does NOT match. Something got wrong")