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