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