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