Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

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