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