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()
442 farthen 270
    def upload(self, data):
271
        """ Allocates memory of the size of 'data' and uploads 'data' to that memory region.
272
            Returns the address where 'data' is stored
273
        """
274
        addr = self.malloc(len(data))
275
        self.logger.debug("Uploading %d bytes to 0x%x\n" % (len(data), addr))
276
        self.write(addr, data)
277
        return addr
278
 
279
    @command()
173 farthen 280
    def readstring(self, addr, maxlength = 256):
281
        """ Reads a zero terminated string from memory 
282
            Reads only a maximum of 'maxlength' chars.
283
        """
343 farthen 284
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
173 farthen 285
        string = ""
286
        while (len(string) < maxlength or maxlength < 0):
178 farthen 287
            data = self._readmem(addr, min(maxlength - len(string), cin_maxsize))
173 farthen 288
            length = data.find("\0")
289
            if length >= 0:
290
                string += data[:length]
291
                break
292
            else:
293
                string += data
294
            addr += cin_maxsize
295
        return string
296
 
394 farthen 297
    @command()
171 farthen 298
    def i2cread(self, index, slaveaddr, startaddr, size):
299
        """ Reads data from an i2c slave """
236 farthen 300
        data = ""
301
        for i in range(size):
302
            resp = self.lib.monitorcommand(struct.pack("IBBBBII", 8, index, slaveaddr, startaddr + i, 1, 0, 0), "III1s", (None, None, None, "data"))
303
            data += resp.data
304
        return data
56 benedikt93 305
 
394 farthen 306
    @command()
171 farthen 307
    def i2cwrite(self, index, slaveaddr, startaddr, data):
308
        """ Writes data to an i2c slave """
176 farthen 309
        size = len(data)
310
        if size > 256 or size < 1:
341 farthen 311
            raise ArgumentError("Size must be a number between 1 and 256")
176 farthen 312
        if size == 256:
313
            size = 0
215 theseven 314
        return self.lib.monitorcommand(struct.pack("IBBBBII%ds" % size, 9, index, slaveaddr, startaddr, size, 0, 0, data), "III", (None, None, None))
56 benedikt93 315
 
394 farthen 316
    @command()
176 farthen 317
    def usbcread(self):
318
        """ Reads one packet with the maximal cin size """
343 farthen 319
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
176 farthen 320
        resp = self.lib.monitorcommand(struct.pack("IIII", 10, cin_maxsize, 0, 0), "III%ds" % cin_maxsize, ("validsize", "buffersize", "queuesize", "data"))
321
        resp.data = resp.data[:resp.validsize]
322
        resp.maxsize = cin_maxsize
323
        return resp
56 benedikt93 324
 
394 farthen 325
    @command()
171 farthen 326
    def usbcwrite(self, data):
327
        """ Writes data to the USB console """
343 farthen 328
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
176 farthen 329
        size = len(data)
330
        while len(data) > 0:
331
            writesize = min(cin_maxsize, len(data))
332
            resp = self.lib.monitorcommand(struct.pack("IIII%ds" % writesize, 11, writesize, 0, 0, data[:writesize]), "III", ("validsize", "buffersize", "freesize"))
333
            data = data[resp.validsize:]
334
        return size
56 benedikt93 335
 
394 farthen 336
    @command()
176 farthen 337
    def cread(self, bitmask=0x1):
338
        """ Reads one packet with the maximal cin size from the device consoles
171 farthen 339
            identified with the specified bitmask
340
        """
343 farthen 341
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
217 theseven 342
        resp = self.lib.monitorcommand(struct.pack("IIII", 13, bitmask, cin_maxsize, 0), "III%ds" % cin_maxsize, ("size", None, None))
176 farthen 343
        resp.data = resp.data[size:]
344
        resp.maxsize = cin_maxsize
345
        return resp
394 farthen 346
 
347
    @command()
176 farthen 348
    def cwrite(self, data, bitmask=0x1):
171 farthen 349
        """ Writes data to the device consoles 
350
            identified with the specified bitmask.
351
        """
343 farthen 352
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
176 farthen 353
        size = len(data)
354
        while len(data) > 0:
355
            writesize = min(cin_maxsize, len(data))
217 theseven 356
            resp = self.lib.monitorcommand(struct.pack("IIII%ds" % writesize, 12, bitmask, writesize, 0, data[:writesize]), "III", (None, None, None))
176 farthen 357
            data = data[writesize:]
358
        return size
56 benedikt93 359
 
394 farthen 360
    @command()
171 farthen 361
    def cflush(self, bitmask):
362
        """ Flushes the consoles specified with 'bitmask' """
363
        return self.lib.monitorcommand(struct.pack("IIII", 14, bitmask, 0, 0), "III", (None, None, None))
56 benedikt93 364
 
394 farthen 365
    @command()
173 farthen 366
    def getprocinfo(self):
171 farthen 367
        """ Gets current state of the scheduler """
343 farthen 368
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
173 farthen 369
        # Get the size
370
        schedulerstate = self.lockscheduler()
371
        resp = self.lib.monitorcommand(struct.pack("IIII", 15, 0, 0, 0), "III", ("structver", "tablesize", None))
372
        tablesize = resp.tablesize
373
        size = tablesize
374
        structver = resp.structver
375
        offset = 0
376
        data = ""
377
        while size > 0:
378
            if size > cin_maxsize:
379
                readsize = cin_maxsize
380
            else:
381
                readsize = size
382
            resp = self.lib.monitorcommand(struct.pack("IIII", 15, offset, readsize, 0), "III%ds" % readsize, ("structver", "tablesize", None, "data"))
383
            data += resp.data
384
            offset += readsize
385
            size -= readsize
386
        self.lockscheduler(schedulerstate)
387
        threadstructsize = 120
388
        registersize = 32
389
        if len(data) % threadstructsize != 0:
390
            raise DeviceError("The thread struct is not a multiple of "+str(threadsturcsize)+"!")
391
        threadcount = len(data) / threadstructsize
392
        threads = []
393
        id = 0
394
        for thread in range(threadcount):
395
            offset = threadstructsize * thread
396
            threaddata = struct.unpack("<16IIIIIQIIIIIIIBBBB", data[offset:offset+threadstructsize])
397
            info = Bunch()
398
            info.id = id
399
            state = threaddata[17]
427 farthen 400
            info.state = libemcoredata.thread_state[state]
173 farthen 401
            if info.state == "THREAD_FREE":
402
                id += 1
403
                continue
404
            info.regs = Bunch()
405
            for register in range(16):
406
                info.regs["r"+str(register)] = threaddata[register]
407
            info.regs.cpsr = threaddata[16]
408
            info.nameptr = threaddata[18]
409
            if info.nameptr == 0:
410
                info.name = "Thread %d" % info.id
411
            else:
412
                info.name = self.readstring(info.nameptr)
413
            info.cputime_current = threaddata[19]
414
            info.cputime_total = threaddata[20]
415
            info.startusec = threaddata[21]
416
            info.queue_next_ptr = threaddata[22]
417
            info.timeout = threaddata[23]
418
            info.blocked_since = threaddata[24]
419
            info.blocked_by_ptr = threaddata[25]
420
            info.stackaddr = threaddata[26]
421
            info.err_no = threaddata[27]
427 farthen 422
            info.block_type = libemcoredata.thread_block[threaddata[28]]
423
            info.type = libemcoredata.thread_type[threaddata[29]]
173 farthen 424
            info.priority = threaddata[30]
425
            info.cpuload = threaddata[31]
426
            threads.append(info)
427
            id += 1
428
        return threads
56 benedikt93 429
 
394 farthen 430
    @command()
173 farthen 431
    def lockscheduler(self, freeze=True):
171 farthen 432
        """ Freezes/Unfreezes the scheduler """
173 farthen 433
        resp = self.lib.monitorcommand(struct.pack("IIII", 16, 1 if freeze else 0, 0, 0), "III", ("before", None, None))
434
        return True if resp.before == 1 else False
67 benedikt93 435
 
394 farthen 436
    @command()
173 farthen 437
    def unlockscheduler(self):
171 farthen 438
        """ Unfreezes the scheduler """
439
        return self.lib.monitorcommand(struct.pack("IIII", 16, 0, 0, 0), "III", ("before", None, None))
56 benedikt93 440
 
394 farthen 441
    @command()
171 farthen 442
    def suspendthread(self, id, suspend=True):
443
        """ Suspends the thread with the specified id """
173 farthen 444
        resp = self.lib.monitorcommand(struct.pack("IIII", 17, 1 if suspend else 0, id, 0), "III", ("before", None, None))
445
        return True if resp.before == 1 else False
56 benedikt93 446
 
394 farthen 447
    @command()
173 farthen 448
    def resumethread(self, id):
449
        """ Resumes the thread with the specified id """
171 farthen 450
        return self.lib.monitorcommand(struct.pack("IIII", 17, 0, id, 0), "III", ("before", None, None))
56 benedikt93 451
 
394 farthen 452
    @command()
171 farthen 453
    def killthread(self, id):
454
        """ Kills the thread with the specified id """
455
        return self.lib.monitorcommand(struct.pack("IIII", 18, id, 0, 0), "III", ("before", None, None))
56 benedikt93 456
 
394 farthen 457
    @command()
171 farthen 458
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
459
        """ Creates a thread with the specified attributes """
460
        if threadtype == "user":
461
            threadtype = 0
462
        elif threadtype == "system":
463
            threadtype = 1
464
        else:
341 farthen 465
            raise ArgumentError("Threadtype must be either 'system' or 'user'")
171 farthen 466
        if priority > 256 or priority < 0:
341 farthen 467
            raise ArgumentError("Priority must be a number between 0 and 256")
171 farthen 468
        if state == "ready":
469
            state = 0
470
        elif state == "suspended":
471
            state = 1
472
        else:
341 farthen 473
            raise ArgumentError("State must be either 'ready' or 'suspended'")
171 farthen 474
        resp = self.lib.monitorcommand(struct.pack("IIIIIIII", 19, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state), "III", (id, None, None))
475
        if resp.id < 0:
476
            raise DeviceError("The device returned the error code "+str(resp.id))
477
        return resp
56 benedikt93 478
 
394 farthen 479
    @command()
172 farthen 480
    def flushcaches(self):
171 farthen 481
        """ Flushes the CPU instruction and data cache """
482
        return self.lib.monitorcommand(struct.pack("IIII", 20, 0, 0, 0), "III", (None, None, None))
56 benedikt93 483
 
394 farthen 484
    @command()
172 farthen 485
    def execimage(self, addr):
427 farthen 486
        """ Runs the emCORE app at 'addr' """
452 theseven 487
        return self.lib.monitorcommand(struct.pack("IIII", 21, addr, 0, 0), "III", ("thread", None, None))
56 benedikt93 488
 
394 farthen 489
    @command()
238 farthen 490
    def run(self, app):
427 farthen 491
        """ Uploads and runs the emCORE app in the string 'app' """
452 theseven 492
        if app[:8] != "emCOexec":
427 farthen 493
            raise ArgumentError("The specified app is not an emCORE application")
452 theseven 494
        baseaddr = self.malloc(len(app))
238 farthen 495
        self.write(baseaddr, app)
452 theseven 496
        result = self.execimage(baseaddr)
497
        return Bunch(thread=result.thread)
238 farthen 498
 
395 farthen 499
    @command(timeout = 5000)
171 farthen 500
    def bootflashread(self, memaddr, flashaddr, size):
501
        """ Copies the data in the bootflash at 'flashaddr' of the specified size
502
            to the memory at addr 'memaddr'
503
        """
174 farthen 504
        return self.lib.monitorcommand(struct.pack("IIII", 22, memaddr, flashaddr, size), "III", (None, None, None))
82 benedikt93 505
 
395 farthen 506
    @command(timeout = 30000)
171 farthen 507
    def bootflashwrite(self, memaddr, flashaddr, size):
508
        """ Copies the data in the memory at 'memaddr' of the specified size
509
            to the boot flash at addr 'flashaddr'
510
        """
174 farthen 511
        return self.lib.monitorcommand(struct.pack("IIII", 23, memaddr, flashaddr, size), "III", (None, None, None))
56 benedikt93 512
 
394 farthen 513
    @command()
442 farthen 514
    def execfirmware(self, targetaddr, addr, size):
515
        """ Moves the firmware at 'addr' with size 'size' to 'targetaddr' and passes all control to it. """
516
        self.logger.debug("Moving firmware at 0x%x with the size %d to 0x%x and executing it\n" % (addr, size, targetaddr))
517
        return self.lib.monitorcommand(struct.pack("IIII", 24, targetaddr, addr, size))
56 benedikt93 518
 
395 farthen 519
    @command(timeout = 30000)
171 farthen 520
    def aesencrypt(self, addr, size, keyindex):
521
        """ Encrypts the buffer at 'addr' with the specified size
522
            with the hardware AES key index 'keyindex'
523
        """
524
        return self.lib.monitorcommand(struct.pack("IBBHII", 25, 1, 0, keyindex, addr, size), "III", (None, None, None))
82 benedikt93 525
 
395 farthen 526
    @command(timeout = 30000)
171 farthen 527
    def aesdecrypt(self, addr, size, keyindex):
528
        """ Decrypts the buffer at 'addr' with the specified size
529
            with the hardware AES key index 'keyindex'
530
        """
531
        return self.lib.monitorcommand(struct.pack("IBBHII", 25, 0, 0, keyindex, addr, size), "III", (None, None, None))
82 benedikt93 532
 
395 farthen 533
    @command(timeout = 30000)
171 farthen 534
    def hmac_sha1(self, addr, size, destination):
535
        """ Generates a HMAC-SHA1 hash of the buffer and saves it to 'destination' """
536
        return self.lib.monitorcommand(struct.pack("IIII", 26, addr, size, destination), "III", (None, None, None))
56 benedikt93 537
 
398 farthen 538
    @command(target = 0x47324e49)
227 theseven 539
    def ipodnano2g_getnandinfo(self):
540
        """ Target-specific function: ipodnano2g
541
            Gathers some information about the NAND chip used
542
        """
543
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0001, 0, 0, 0), "IHHHH", ("type", "pagesperblock", "banks", "userblocks", "blocks"))
544
 
398 farthen 545
    @command(timeout = 30000, target = 0x47324e49)
227 theseven 546
    def ipodnano2g_nandread(self, addr, start, count, doecc, checkempty):
547
        """ Target-specific function: ipodnano2g
548
            Reads data from the NAND chip into memory
549
        """
404 farthen 550
        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 551
 
398 farthen 552
    @command(timeout = 30000, target = 0x47324e49)
227 theseven 553
    def ipodnano2g_nandwrite(self, addr, start, count, doecc):
554
        """ Target-specific function: ipodnano2g
555
            Writes data to the NAND chip
556
        """
404 farthen 557
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0003, addr | (0x80000000 if doecc else 0), start, count), "III", (None, None, None))
227 theseven 558
 
398 farthen 559
    @command(timeout = 30000, target = 0x47324e49)
227 theseven 560
    def ipodnano2g_nanderase(self, addr, start, count):
561
        """ Target-specific function: ipodnano2g
562
            Erases blocks on the NAND chip and stores the results to memory
563
        """
564
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0004, addr, start, count), "III", (None, None, None))
565
 
398 farthen 566
    @command(target = 0x4c435049)
346 theseven 567
    def ipodclassic_gethddinfo(self):
568
        """ Target-specific function: ipodclassic
569
            Gather information about the hard disk drive
570
        """
571
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0001, 0, 0, 0), "IQQII", ("identifyptr", "totalsectors", "virtualsectors", "bbtptr", "bbtsize"))
572
 
398 farthen 573
    @command(timeout = 30000, target = 0x4c435049)
346 theseven 574
    def ipodclassic_hddaccess(self, type, sector, count, addr):
575
        """ Target-specific function: ipodclassic
576
            Access the hard disk, type = 0 (read) / 1 (write)
577
        """
578
        rc = self.lib.monitorcommand(struct.pack("IIQIIII", 0xffff0002, type, sector, count, addr, 0, 0), "III", ("rc", None, None))
579
        if (rc > 0x80000000):
580
            raise DeviceError("HDD access (type=%d, sector=%d, count=%d, addr=0x%08X) failed with RC 0x%08X" % (type, sector, count, addr, rc))
581
 
398 farthen 582
    @command(target = 0x4c435049)
346 theseven 583
    def ipodclassic_writebbt(self, bbt, tempaddr):
584
        """ Target-specific function: ipodclassic
585
            Write hard drive bad block table
586
        """
587
        try:
588
            bbtheader = struct.unpack("<8s2024sQII512I", bbt[:4096])
589
        except struct.error:
427 farthen 590
            raise ArgumentError("The specified file is not an emCORE hard disk BBT")
346 theseven 591
        if bbtheader[0] != "emBIbbth":
427 farthen 592
            raise ArgumentError("The specified file is not an emCORE hard disk BBT")
346 theseven 593
        virtualsectors = bbtheader[2]
594
        bbtsectors = bbtheader[3]
595
        self.write(tempaddr, bbt)
596
        sector = 0
597
        count = 1
598
        offset = 0
599
        for i in range(bbtsectors):
600
            if bbtheader[4][i] == sector + count:
601
                count = count + 1
602
            else:
603
                self.ipodclassic_hddaccess(1, sector, count, tempaddr + offset)
604
                offset = offset + count * 4096
605
                sector = bbtheader[4][i]
606
                count = 1
607
        self.ipodclassic_hddaccess(1, sector, count, tempaddr + offset)
608
 
394 farthen 609
    @command()
379 theseven 610
    def storage_get_info(self, volume):
346 theseven 611
        """ Get information about a storage device """
379 theseven 612
        result = self.lib.monitorcommand(struct.pack("IIII", 27, volume, 0, 0), "IIIIIIII", ("version", None, None, "sectorsize", "numsectors", "vendorptr", "productptr", "revisionptr"))
346 theseven 613
        if result.version != 1:
614
            raise ValueError("Unknown version of storage_info struct: %d" % result.version)
379 theseven 615
        result.vendor = self.readstring(result.vendorptr)
616
        result.product = self.readstring(result.productptr)
617
        result.revision = self.readstring(result.revisionptr)
346 theseven 618
        return result
619
 
395 farthen 620
    @command(timeout = 50000)
475 farthen 621
    def storage_read_sectors_md(self, volume, sector, count, size = 0x100000, addr = None):
472 farthen 622
        """ Read sectors from as storage device. If addr is not given it allocates a buffer itself. """
623
        if addr is None:
624
            addr = self.malloc(size)
625
            malloc = True
626
        else:
627
            malloc = False
628
        try:
629
            result = self.lib.monitorcommand(struct.pack("IIQIIII", 28, volume, sector, count, addr, 0, 0), "III", ("rc", None, None))
630
        finally:
631
            if malloc == True:
632
                self.free(addr)
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
 
475 farthen 636
    def storage_write_sectors_md(self, volume, sector, count, size = 0x100000, addr = None):
472 farthen 637
        """ Read sectors from as storage device. If addr is not given it allocates a buffer itself. """
638
        if addr is None:
639
            addr = self.malloc(size)
640
            malloc = True
641
        else:
642
            malloc = False
643
        try:
644
            result = self.lib.monitorcommand(struct.pack("IIQIIII", 29, volume, sector, count, addr, 0, 0), "III", ("rc", None, None))
645
        finally:
646
            if malloc == True:
647
                self.free(addr)
346 theseven 648
        if result.rc > 0x80000000:
649
            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 650
 
395 farthen 651
    @command(timeout = 30000)
346 theseven 652
    def file_open(self, filename, mode):
653
        """ Opens a file and returns the handle """
654
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(filename), 30, mode, 0, 0, filename, 0), "III", ("fd", None, None))
655
        if result.fd > 0x80000000:
656
            raise DeviceError("file_open(filename=\"%s\", mode=0x%X) failed with RC=0x%08X, errno=%d" % (filename, mode, result.fd, self.errno()))
657
        return result.fd
658
 
395 farthen 659
    @command(timeout = 30000)
346 theseven 660
    def file_size(self, fd):
661
        """ Gets the size of a file referenced by a handle """
662
        result = self.lib.monitorcommand(struct.pack("IIII", 31, fd, 0, 0), "III", ("size", None, None))
663
        if result.size > 0x80000000:
664
            raise DeviceError("file_size(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.size, self.errno()))
665
        return result.size
394 farthen 666
 
395 farthen 667
    @command(timeout = 30000)
475 farthen 668
    def file_read(self, fd, size = 0x100000, addr = None):
472 farthen 669
        """ Reads data from a file referenced by a handle. If addr is not given it allocates a buffer itself. """
670
        if addr is None:
671
            addr = self.malloc(size)
672
            malloc = True
673
        else:
674
            malloc = False
675
        try:
676
            result = self.lib.monitorcommand(struct.pack("IIII", 32, fd, addr, size), "III", ("rc", None, None))
677
        finally:
678
            if malloc == True:
679
                self.free(addr)
346 theseven 680
        if result.rc > 0x80000000:
681
            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()))
682
        return result.rc
394 farthen 683
 
395 farthen 684
    @command(timeout = 30000)
475 farthen 685
    def file_write(self, fd, size = 0x100000, addr = None):
472 farthen 686
        """ Writes data from a file referenced by a handle. If addr is not given it allocates a buffer itself. """
687
        if addr is None:
688
            addr = self.malloc(size)
689
            malloc = True
690
        else:
691
            malloc = False
692
        try:
693
            result = self.lib.monitorcommand(struct.pack("IIII", 33, fd, addr, size), "III", ("rc", None, None))
694
        finally:
695
            if malloc == True:
696
                self.free(addr)
346 theseven 697
        if result.rc > 0x80000000:
698
            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()))
699
        return result.rc
700
 
395 farthen 701
    @command(timeout = 30000)
346 theseven 702
    def file_seek(self, fd, offset, whence):
703
        """ Seeks the file handle to the specified position in the file """
704
        result = self.lib.monitorcommand(struct.pack("IIII", 34, fd, offset, whence), "III", ("rc", None, None))
705
        if result.rc > 0x80000000:
706
            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()))
707
        return result.rc
708
 
395 farthen 709
    @command(timeout = 30000)
346 theseven 710
    def file_truncate(self, fd, length):
711
        """ Truncates a file referenced by a handle to a specified length """
712
        result = self.lib.monitorcommand(struct.pack("IIII", 35, fd, offset, 0), "III", ("rc", None, None))
713
        if result.rc > 0x80000000:
714
            raise DeviceError("file_truncate(fd=%d, length=0x%08X) failed with RC=0x%08X, errno=%d" % (fd, length, result.rc, self.errno()))
715
        return result.rc
716
 
395 farthen 717
    @command(timeout = 30000)
346 theseven 718
    def file_sync(self, fd):
719
        """ Flushes a file handles' buffers """
720
        result = self.lib.monitorcommand(struct.pack("IIII", 36, fd, 0, 0), "III", ("rc", None, None))
721
        if result.rc > 0x80000000:
722
            raise DeviceError("file_sync(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.rc, self.errno()))
723
        return result.rc
724
 
395 farthen 725
    @command(timeout = 30000)
346 theseven 726
    def file_close(self, fd):
727
        """ Closes a file handle """
728
        result = self.lib.monitorcommand(struct.pack("IIII", 37, fd, 0, 0), "III", ("rc", None, None))
729
        if result.rc > 0x80000000:
730
            raise DeviceError("file_close(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.rc, self.errno()))
731
        return result.rc
732
 
395 farthen 733
    @command(timeout = 30000)
346 theseven 734
    def file_close_all(self):
735
        """ Closes all file handles opened through the debugger """
736
        result = self.lib.monitorcommand(struct.pack("IIII", 38, 0, 0, 0), "III", ("rc", None, None))
737
        if result.rc > 0x80000000:
738
            raise DeviceError("file_close_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
739
        return result.rc
740
 
395 farthen 741
    @command(timeout = 30000)
346 theseven 742
    def file_kill_all(self):
743
        """ Kills all file handles (in the whole system) """
744
        result = self.lib.monitorcommand(struct.pack("IIII", 39, 0, 0, 0), "III", ("rc", None, None))
745
        if result.rc > 0x80000000:
746
            raise DeviceError("file_kill_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
747
        return result.rc
748
 
395 farthen 749
    @command(timeout = 30000)
346 theseven 750
    def file_unlink(self, filename):
751
        """ Removes a file """
752
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(filename), 40, 0, 0, 0, filename, 0), "III", ("rc", None, None))
753
        if result.rc > 0x80000000:
754
            raise DeviceError("file_unlink(filename=\"%s\") failed with RC=0x%08X, errno=%d" % (filename, result.rc, self.errno()))
755
        return result.rc
756
 
395 farthen 757
    @command(timeout = 30000)
346 theseven 758
    def file_rename(self, oldname, newname):
759
        """ Renames a file """
760
        result = self.lib.monitorcommand(struct.pack("IIII248s%dsB" % min(247, len(newname)), 41, 0, 0, 0, oldname, newname, 0), "III", ("rc", None, None))
761
        if result.rc > 0x80000000:
762
            raise DeviceError("file_rename(oldname=\"%s\", newname=\"%s\") failed with RC=0x%08X, errno=%d" % (oldname, newname, result.rc, self.errno()))
763
        return result.rc
764
 
395 farthen 765
    @command(timeout = 30000)
346 theseven 766
    def dir_open(self, dirname):
767
        """ Opens a directory and returns the handle """
768
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 42, 0, 0, 0, dirname, 0), "III", ("handle", None, None))
769
        if result.handle == 0:
770
            raise DeviceError("dir_open(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.handle, self.errno()))
771
        return result.handle
772
 
395 farthen 773
    @command(timeout = 30000)
346 theseven 774
    def dir_read(self, handle):
775
        """ Reads the next entry from a directory """
776
        result = self.lib.monitorcommand(struct.pack("IIII", 43, handle, 0, 0), "III", ("version", "maxpath", "ptr"))
777
        if result.ptr == 0:
778
            raise DeviceError("dir_read(handle=0x%08X) failed with RC=0x%08X, errno=%d" % (handle, result.ptr, self.errno()))
779
        if result.version != 1:
780
            raise ValueError("Unknown version of dirent struct: %d" % result.version)
781
        dirent = self.read(result.ptr, result.maxpath + 16)
782
        ret = Bunch()
783
        (ret.name, ret.attributes, ret.size, ret.startcluster, ret.wrtdate, ret.wrttime) = struct.unpack("%dsIIIHH" % result.maxpath, dirent)
784
        ret.name = ret.name[:ret.name.index('\x00')]
785
        return ret
786
 
395 farthen 787
    @command(timeout = 30000)
346 theseven 788
    def dir_close(self, handle):
789
        """ Closes a directory handle """
790
        result = self.lib.monitorcommand(struct.pack("IIII", 44, handle, 0, 0), "III", ("rc", None, None))
791
        if result.rc > 0x80000000:
792
            raise DeviceError("dir_close(handle=0x%08X) failed with RC=0x%08X, errno=%d" % (handle, result.rc, self.errno()))
793
        return result.rc
794
 
395 farthen 795
    @command(timeout = 30000)
346 theseven 796
    def dir_close_all(self):
797
        """ Closes all directory handles opened through the debugger """
798
        result = self.lib.monitorcommand(struct.pack("IIII", 45, 0, 0, 0), "III", ("rc", None, None))
799
        if result.rc > 0x80000000:
800
            raise DeviceError("dir_close_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
801
        return result.rc
802
 
395 farthen 803
    @command(timeout = 30000)
346 theseven 804
    def dir_kill_all(self):
805
        """ Kills all directory handles (in the whole system) """
806
        result = self.lib.monitorcommand(struct.pack("IIII", 46, 0, 0, 0), "III", ("rc", None, None))
807
        if result.rc > 0x80000000:
808
            raise DeviceError("dir_kill_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
809
        return result.rc
810
 
395 farthen 811
    @command(timeout = 30000)
346 theseven 812
    def dir_create(self, dirname):
813
        """ Creates a directory """
814
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 47, 0, 0, 0, dirname, 0), "III", ("rc", None, None))
815
        if result.rc > 0x80000000:
816
            raise DeviceError("dir_create(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.rc, self.errno()))
817
        return result.rc
818
 
395 farthen 819
    @command(timeout = 30000)
346 theseven 820
    def dir_remove(self, dirname):
821
        """ Removes an (empty) directory """
822
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 48, 0, 0, 0, dirname, 0), "III", ("rc", None, None))
823
        if result.rc > 0x80000000:
824
            raise DeviceError("dir_remove(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.rc, self.errno()))
825
        return result.rc
826
 
394 farthen 827
    @command()
346 theseven 828
    def errno(self):
829
        """ Returns the number of the last error that happened """
830
        result = self.lib.monitorcommand(struct.pack("IIII", 49, 0, 0, 0), "III", ("errno", None, None))
831
        return result.errno
832
 
394 farthen 833
    @command()
346 theseven 834
    def disk_mount(self, volume):
835
        """ Mounts a volume """
836
        result = self.lib.monitorcommand(struct.pack("IIII", 50, volume, 0, 0), "III", ("rc", None, None))
837
        if result.rc > 0x80000000:
838
            raise DeviceError("disk_mount(volume=%d) failed with RC=0x%08X, errno=%d" % (volume, result.rc, self.errno()))
839
        return result.rc
840
 
394 farthen 841
    @command()
346 theseven 842
    def disk_unmount(self, volume):
843
        """ Unmounts a volume """
844
        result = self.lib.monitorcommand(struct.pack("IIII", 51, volume, 0, 0), "III", ("rc", None, None))
845
        if result.rc > 0x80000000:
846
            raise DeviceError("disk_unmount(volume=%d) failed with RC=0x%08X, errno=%d" % (volume, result.rc, self.errno()))
847
        return result.rc
848
 
441 farthen 849
    @command()
850
    def malloc(self, size):
851
        """ Allocates 'size' bytes and returns a pointer to the allocated memory """
442 farthen 852
        self.logger.debug("Allocating %d bytes of memory\n" % size)
441 farthen 853
        result = self.lib.monitorcommand(struct.pack("IIII", 52, size, 0, 0), "III", ("ptr", None, None))
442 farthen 854
        self.logger.debug("Allocated %d bytes of memory at 0x%x\n" % (size, result.ptr))
441 farthen 855
        return result.ptr
856
 
857
    @command()
858
    def memalign(self, align, size):
859
        """ Allocates 'size' bytes aligned to 'align' and returns a pointer to the allocated memory """
442 farthen 860
        self.logger.debug("Allocating %d bytes of memory aligned to 0x%x\n" % (size, align))
441 farthen 861
        result = self.lib.monitorcommand(struct.pack("IIII", 53, align, size, 0), "III", ("ptr", None, None))
442 farthen 862
        self.logger.debug("Allocated %d bytes of memory at 0x%x\n" % (size, result.ptr))
441 farthen 863
        return result.ptr
864
 
865
    @command()
866
    def realloc(self, ptr, size):
867
        """ The size of the memory block pointed to by 'ptr' is changed to the 'size' bytes,
868
            expanding or reducing the amount of memory available in the block.
869
            Returns a pointer to the reallocated memory.
870
        """
442 farthen 871
        self.logger.debug("Reallocating 0x%x to have the new size %d\n" % (ptr, size))
441 farthen 872
        result = self.lib.monitorcommand(struct.pack("IIII", 54, ptr, size, 0), "III", ("ptr", None, None))
442 farthen 873
        self.logger.debug("Reallocated memory at 0x%x to 0x%x with the new size %d\n" % (ptr, result.ptr, size))
441 farthen 874
        return result.ptr
875
 
876
    @command()
877
    def reownalloc(self, ptr, owner):
878
        """ Changes the owner of the memory allocation 'ptr' to the thread struct at addr 'owner' """
442 farthen 879
        self.logger.debug("Changing owner of the memory region 0x%x to 0x%x" % (ptr, owner))
441 farthen 880
        return self.lib.monitorcommand(struct.pack("IIII", 55, ptr, owner, 0), "III", (None, None, None))
881
 
882
    @command()
883
    def free(self, ptr):
884
        """ Frees the memory space pointed to by 'ptr' """
442 farthen 885
        self.logger.debug("Freeing the memory region at 0x%x\n" % ptr)
473 farthen 886
        return self.lib.monitorcommand(struct.pack("IIII", 56, ptr, 0, 0), "III", (None, None, None))
441 farthen 887
 
473 farthen 888
    @command()
889
    def free_all(self):
890
        """ Frees all memory allocations created by the monitor thread """
891
        self.logger.debug("Freeing all memory allocations created by the monitor thread\n")
892
        return self.lib.monitorcommand(struct.pack("IIII", 57, 0, 0, 0), "III", (None, None, None))
893
 
346 theseven 894
 
171 farthen 895
class Lib(object):
401 farthen 896
    def __init__(self, logger):
897
        self.logger = logger
898
        self.logger.debug("Initializing Lib object\n")
171 farthen 899
        self.idVendor = 0xFFFF
900
        self.idProduct = 0xE000
176 farthen 901
 
902
        self.headersize = 0x10
903
 
904
        self.connect()
56 benedikt93 905
 
171 farthen 906
    def connect(self):
401 farthen 907
        self.dev = Dev(self.idVendor, self.idProduct, self.logger)
171 farthen 908
        self.connected = True
56 benedikt93 909
 
171 farthen 910
    def monitorcommand(self, cmd, rcvdatatypes=None, rcvstruct=None):
442 farthen 911
        self.logger.debug("Sending monitorcommand [0x%s]\n" % cmd[3::-1].encode("hex"))
269 farthen 912
        writelen = self.dev.cout(cmd)
171 farthen 913
        if rcvdatatypes:
914
            rcvdatatypes = "I" + rcvdatatypes # add the response
915
            data = self.dev.cin(struct.calcsize(rcvdatatypes))
916
            data = struct.unpack(rcvdatatypes, data)
917
            response = data[0]
427 farthen 918
            if libemcoredata.responsecodes[response] == "ok":
401 farthen 919
                self.logger.debug("Response: OK\n")
171 farthen 920
                if rcvstruct:
921
                    datadict = Bunch()
922
                    counter = 1 # start with 1, 0 is the id
923
                    for item in rcvstruct:
924
                        if item != None: # else the data is undefined
925
                            datadict[item] = data[counter]
926
                        counter += 1
927
                    return datadict
928
                else:
929
                    return data
427 farthen 930
            elif libemcoredata.responsecodes[response] == "unsupported":
401 farthen 931
                self.logger.debug("Response: UNSUPPORTED\n")
171 farthen 932
                raise DeviceError("The device does not support this command.")
427 farthen 933
            elif libemcoredata.responsecodes[response] == "invalid":
401 farthen 934
                self.logger.debug("Response: INVALID\n")
171 farthen 935
                raise DeviceError("Invalid command! This should NOT happen!")
427 farthen 936
            elif libemcoredata.responsecodes[response] == "busy":
401 farthen 937
                self.logger.debug("Response: BUSY\n")
171 farthen 938
                raise DeviceError("Device busy")
401 farthen 939
            else:
940
                self.logger.debug("Response: UNKOWN\n")
941
                raise DeviceError("Invalid response! This should NOT happen!")
269 farthen 942
        else:
943
            return writelen
56 benedikt93 944
 
945
 
171 farthen 946
class Dev(object):
401 farthen 947
    def __init__(self, idVendor, idProduct, logger):
171 farthen 948
        self.idVendor = idVendor
949
        self.idProduct = idProduct
67 benedikt93 950
 
401 farthen 951
        self.logger = logger
952
        self.logger.debug("Initializing Dev object\n")
953
 
171 farthen 954
        self.interface = 0
955
        self.timeout = 100
176 farthen 956
 
171 farthen 957
        self.connect()
958
        self.findEndpoints()
959
 
401 farthen 960
        self.logger.debug("Successfully connected to device\n")
342 farthen 961
 
962
        # Device properties
343 farthen 963
        self.packetsizelimit = Bunch()
964
        self.packetsizelimit.cout = None
965
        self.packetsizelimit.cin = None
966
        self.packetsizelimit.dout = None
967
        self.packetsizelimit.din = None
342 farthen 968
 
343 farthen 969
        self.version = Bunch()
342 farthen 970
        self.version.revision = None
971
        self.version.majorv = None
972
        self.version.minorv = None
973
        self.version.patchv = None
974
        self.swtypeid = None
975
        self.hwtypeid = None
976
 
343 farthen 977
        self.usermem = Bunch()
342 farthen 978
        self.usermem.lower = None
979
        self.usermem.upper = None
56 benedikt93 980
 
171 farthen 981
    def __del__(self):
982
        self.disconnect()
56 benedikt93 983
 
171 farthen 984
    def findEndpoints(self):
401 farthen 985
        self.logger.debug("Searching for device endpoints:\n")
171 farthen 986
        epcounter = 0
343 farthen 987
        self.endpoint = Bunch()
171 farthen 988
        for cfg in self.dev:
989
            for intf in cfg:
990
                for ep in intf:
991
                    if epcounter == 0:
401 farthen 992
                        self.logger.debug("Found cout endpoint at 0x%x\n" % ep.bEndpointAddress)
343 farthen 993
                        self.endpoint.cout = ep.bEndpointAddress
171 farthen 994
                    elif epcounter == 1:
401 farthen 995
                        self.logger.debug("Found cin endpoint at 0x%x\n" % ep.bEndpointAddress)
343 farthen 996
                        self.endpoint.cin = ep.bEndpointAddress
171 farthen 997
                    elif epcounter == 2:
401 farthen 998
                        self.logger.debug("Found dout endpoint at 0x%x\n" % ep.bEndpointAddress)
343 farthen 999
                        self.endpoint.dout = ep.bEndpointAddress
171 farthen 1000
                    elif epcounter == 3:
401 farthen 1001
                        self.logger.debug("Found din endpoint at 0x%x\n" % ep.bEndpointAddress)
343 farthen 1002
                        self.endpoint.din = ep.bEndpointAddress
171 farthen 1003
                    epcounter += 1
1004
        if epcounter <= 3:
1005
            raise DeviceError("Not all endpoints found in the descriptor. Only "+str(epcounter)+" found, we need 4")
56 benedikt93 1006
 
171 farthen 1007
    def connect(self):
427 farthen 1008
        self.logger.debug("Looking for emCORE device\n")
171 farthen 1009
        self.dev = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
1010
        if self.dev is None:
1011
            raise DeviceNotFoundError()
401 farthen 1012
        self.logger.debug("Device Found!\n")
1013
        self.logger.debug("Setting first configuration\n")
171 farthen 1014
        self.dev.set_configuration()
56 benedikt93 1015
 
171 farthen 1016
    def disconnect(self):
1017
        pass
102 benedikt93 1018
 
171 farthen 1019
    def send(self, endpoint, data):
1020
        size = self.dev.write(endpoint, data, self.interface, self.timeout)
1021
        if size != len(data):
176 farthen 1022
            raise SendError("Not all data was written!")
171 farthen 1023
        return len
102 benedikt93 1024
 
171 farthen 1025
    def receive(self, endpoint, size):
1026
        read = self.dev.read(endpoint, size, self.interface, self.timeout)
1027
        if len(read) != size:
176 farthen 1028
            raise ReceiveError("Requested size and read size don't match!")
171 farthen 1029
        return read
56 benedikt93 1030
 
171 farthen 1031
    def cout(self, data):
401 farthen 1032
        self.logger.debug("Sending data to cout endpoint with the size " + str(len(data)) + "\n")
343 farthen 1033
        if self.packetsizelimit.cout and len(data) > self.packetsizelimit.cout:
171 farthen 1034
            raise SendError("Packet too big")
343 farthen 1035
        return self.send(self.endpoint.cout, data)
94 benedikt93 1036
 
171 farthen 1037
    def cin(self, size):
401 farthen 1038
        self.logger.debug("Receiving data on the cin endpoint with the size " + str(size) + "\n")
343 farthen 1039
        if self.packetsizelimit.cin and size > self.packetsizelimit.cin:
171 farthen 1040
            raise ReceiveError("Packet too big")
343 farthen 1041
        return self.receive(self.endpoint.cin, size)
94 benedikt93 1042
 
171 farthen 1043
    def dout(self, data):
401 farthen 1044
        self.logger.debug("Sending data to cout endpoint with the size " + str(len(data)) + "\n")
343 farthen 1045
        if self.packetsizelimit.dout and len(data) > self.packetsizelimit.dout:
171 farthen 1046
            raise SendError("Packet too big")
343 farthen 1047
        return self.send(self.endpoint.dout, data)
94 benedikt93 1048
 
171 farthen 1049
    def din(self, size):
401 farthen 1050
        self.logger.debug("Receiving data on the din endpoint with the size " + str(size) + "\n")
343 farthen 1051
        if self.packetsizelimit.din and size > self.packetsizelimit.din:
171 farthen 1052
            raise ReceiveError("Packet too big")
343 farthen 1053
        return self.receive(self.endpoint.din, size)
56 benedikt93 1054
 
96 benedikt93 1055
 
171 farthen 1056
if __name__ == "__main__":
396 farthen 1057
    from misc import Logger
1058
    logger = Logger()
1059
    if sys.argv[1] == "test":
1060
        # Some tests
1061
        import sys
427 farthen 1062
        emcore = Emcore()
1063
        resp = emcore.getversioninfo()
1064
        logger.log("Emcore device version information: " + libemcoredata.swtypes[resp.swtypeid] + " v" + str(resp.majorv) + "." + str(resp.minorv) + 
1065
                         "." + str(resp.patchv) + " r" + str(resp.revision) + " running on " + libemcoredata.hwtypes[resp.hwtypeid] + "\n")
1066
        resp = emcore.getusermemrange()
396 farthen 1067
        logger.log("Usermemrange: "+hex(resp.lower)+" - "+hex(resp.upper)+"\n")
1068
        memaddr = resp.lower
1069
        maxlen = resp.upper - resp.lower
427 farthen 1070
        f = open("./emcore.py", "rb")
1071
        logger.log("Loading test file (emcore.py) to send over USB...\n")
396 farthen 1072
        datastr = f.read()[:maxlen]
1073
        logger.log("Sending data...\n")
427 farthen 1074
        emcore.write(memaddr, datastr)
396 farthen 1075
        logger.log("Encrypting data with the hardware key...\n")
427 farthen 1076
        emcore.aesencrypt(memaddr, len(datastr), 0)
1077
        logger.log("Reading data back and saving it to 'libemcore-test-encrypted.bin'...\n")
1078
        f = open("./libemcore-test-encrypted.bin", "wb")
1079
        f.write(emcore.read(memaddr, len(datastr)))
396 farthen 1080
        logger.log("Decrypting the data again...\n")
427 farthen 1081
        emcore.aesdecrypt(memaddr, len(datastr), 0)
396 farthen 1082
        logger.log("Reading data back from device...\n")
427 farthen 1083
        readdata = emcore.read(memaddr, len(datastr))
396 farthen 1084
        if readdata == datastr:
1085
            logger.log("Data matches!")
1086
        else:
1087
            logger.log("Data does NOT match. Something went wrong")
1088
 
1089
    elif sys.argv[1] == "gendoc":
1090
        # Generates Documentation
1091
        from misc import gendoc
1092
        logger.log("Generating documentation\n")
1093
        cmddict = {}
427 farthen 1094
        for attr, value in Emcore.__dict__.iteritems():
396 farthen 1095
            if getattr(value, 'func', False):
1096
                if getattr(value.func, '_command', False):
1097
                    cmddict[value.func.__name__] = value
441 farthen 1098
        logger.log(gendoc(cmddict))
1099
 
1100
    elif sys.argv[1] == "malloctest":
1101
        emcore = Emcore()
1102
        logger.log("Allocating 200 bytes of memory: ")
1103
        addr = emcore.malloc(200)
1104
        logger.log("0x%x\n" % addr)
1105
        logger.log("Reallocating to 2000 bytes: ")
1106
        addr = emcore.realloc(addr, 2000)
1107
        logger.log("0x%x\n" % addr)
1108
        logger.log("Freeing 0x%x\n" % addr)
1109
        emcore.free(addr)
1110
        logger.log("Allocating 1000 bytes of memory aligned to 100 bytes: ")
1111
        addr = emcore.memalign(100, 1000)
1112
        logger.log("0x%x\n" % addr)
1113
        logger.log("Freeing 0x%x\n" % addr)
1114
        emcore.free(addr)