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