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
582 farthen 33
import base64
56 benedikt93 34
 
506 farthen 35
from libemcoredata import *
532 farthen 36
from misc import Logger, Bunch, Error, ArgumentError, gethwname
394 farthen 37
from functools import wraps
38
 
171 farthen 39
class DeviceNotFoundError(Error):
40
    pass
56 benedikt93 41
 
171 farthen 42
class DeviceError(Error):
43
    pass
56 benedikt93 44
 
171 farthen 45
class SendError(Error):
46
    pass
56 benedikt93 47
 
171 farthen 48
class ReceiveError(Error):
49
    pass
56 benedikt93 50
 
51
 
398 farthen 52
def command(timeout = None, target = None):
394 farthen 53
    """
54
        Decorator for all commands.
55
        It adds the "timeout" variable to all commands.
56
        It also provides the possibility to set the timeout directly in the decorator.
57
        It also includes some dirty hacks to not learn from.
58
    """
59
    time = timeout # dirty hack because otherwise it would raise a scoping problem.
60
                   # The reason is probably because I suck but I can't find any good explanation of this.
61
    def decorator(func):
62
        @wraps(func)
63
        def wrapper(*args, **kwargs):
398 farthen 64
            self = args[0] # little cheat as it expects self being always the first argument
394 farthen 65
            # precommand stuff
398 farthen 66
            if target is not None:
67
                if self.lib.dev.hwtypeid != target:
518 farthen 68
                    raise DeviceError("Wrong device for target-specific command. Expected \'%s\' but got \'%s\'" %
69
                                     (gethwname(target), 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
        """
548 farthen 137
        resp = self.lib.monitorcommand(struct.pack("<IIII", 4, addr, size, 0), "III%ds" % size, (None, None, None, "data"))
178 farthen 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
        """
548 farthen 145
        return self.lib.monitorcommand(struct.pack("<IIII%ds" % len(data), 5, addr, len(data), 0, data), "III", (None, None, None))
178 farthen 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
        """
548 farthen 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]
178 farthen 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
        """
548 farthen 160
        self.lib.monitorcommand(struct.pack("<IIII", 7, addr, len(data), 0), "III", (None, None, None))
178 farthen 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. """
548 farthen 166
        resp = self.lib.monitorcommand(struct.pack("<IIII", 1, 0, 0, 0), "IBBBBI", ("revision", "majorv", "minorv", "patchv", "swtypeid", "hwtypeid"))
342 farthen 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
518 farthen 171
        self.logger.debug("Device Software Type ID = 0x%X\n" % resp.swtypeid)
342 farthen 172
        self.lib.dev.swtypeid = resp.swtypeid
518 farthen 173
        self.logger.debug("Device Hardware Type ID = 0x%X\n" % resp.hwtypeid)
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
        """
548 farthen 182
        resp = self.lib.monitorcommand(struct.pack("<IIII", 1, 1, 0, 0), "HHII", ("coutmax", "cinmax", "doutmax", "dinmax"))
518 farthen 183
        self.logger.debug("Device cout packet size limit = %d\n" % resp.coutmax)
343 farthen 184
        self.lib.dev.packetsizelimit.cout = resp.coutmax
518 farthen 185
        self.logger.debug("Device cin packet size limit = %d\n" % resp.cinmax)
343 farthen 186
        self.lib.dev.packetsizelimit.cin = resp.cinmax
518 farthen 187
        self.logger.debug("Device din packet size limit = %d\n" % resp.doutmax)
343 farthen 188
        self.lib.dev.packetsizelimit.din = resp.dinmax
518 farthen 189
        self.logger.debug("Device dout packet size limit = %d\n" % resp.dinmax)
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. """
548 farthen 196
        resp = self.lib.monitorcommand(struct.pack("<IIII", 1, 2, 0, 0), "III", ("lower", "upper", None))
518 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:
548 farthen 206
            return self.lib.monitorcommand(struct.pack("<IIII", 2, 0, 0, 0))
171 farthen 207
        else:
548 farthen 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:
548 farthen 214
            return self.lib.monitorcommand(struct.pack("<IIII", 3, 0, 0, 0))
171 farthen 215
        else:
548 farthen 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
582 farthen 226
        data = b""
171 farthen 227
        (headsize, bodysize, tailsize) = self._alignsplit(addr, size, cin_maxsize, 16)
518 farthen 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)
518 farthen 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))
582 farthen 292
            length = data.find(b"\0")
173 farthen 293
            if length >= 0:
582 farthen 294
                string += data[:length].decode("latin_1")
173 farthen 295
                break
296
            else:
582 farthen 297
                string += data.decode("latin_1")
173 farthen 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 """
582 farthen 304
        data = b""
236 farthen 305
        for i in range(size):
548 farthen 306
            resp = self.lib.monitorcommand(struct.pack("<IBBBBII", 8, index, slaveaddr, startaddr + i, 1, 0, 0), "III1s", (None, None, None, "data"))
236 farthen 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
548 farthen 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):
582 farthen 322
        """ Reads one packet with the maximal cin size from the console """
343 farthen 323
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
548 farthen 324
        resp = self.lib.monitorcommand(struct.pack("<IIII", 10, cin_maxsize, 0, 0), "III%ds" % cin_maxsize, ("validsize", "buffersize", "queuesize", "data"))
582 farthen 325
        resp.data = resp.data[:resp.validsize].decode("latin_1")
176 farthen 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))
548 farthen 336
            resp = self.lib.monitorcommand(struct.pack("<IIII%ds" % writesize, 11, writesize, 0, 0, data[:writesize]), "III", ("validsize", "buffersize", "freesize"))
176 farthen 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
548 farthen 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))
548 farthen 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' """
548 farthen 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 """
173 farthen 372
        schedulerstate = self.lockscheduler()
548 farthen 373
        resp = self.lib.monitorcommand(struct.pack("<IIII", 15, 0, 0, 0), "III", ("structver", "structptr", None))
506 farthen 374
        if resp.structver != 2:
375
            raise DeviceError("Unsupported thread struct version!")
376
 
173 farthen 377
        threads = []
506 farthen 378
        structptr = resp.structptr
173 farthen 379
        id = 0
506 farthen 380
        while structptr != 0:
381
            threadstruct = scheduler_thread()
518 farthen 382
            self.logger.debug("Reading thread struct of thread at 0x%X\n" % structptr)
506 farthen 383
            threaddata = self.read(structptr, ctypes.sizeof(scheduler_thread))
384
            threadstruct._from_string(threaddata)
385
            threadstruct = threadstruct._to_bunch()
386
            threadstruct.id = id # only for the purpose of detecting the idle thread as it is always the first one
387
            threadstruct.addr = structptr
587 theseven 388
	    if threadstruct.name != 0:
389
	        threadstruct.name = self.readstring(threadstruct.name)
390
            else: threadstruct.name = "[Thread %08X]" % structptr
506 farthen 391
            threadstruct.state = thread_state(threadstruct.state)
392
            threads.append(threadstruct)
173 farthen 393
            id += 1
506 farthen 394
            structptr = threadstruct.thread_next
508 farthen 395
        self.lockscheduler(schedulerstate)
173 farthen 396
        return threads
56 benedikt93 397
 
394 farthen 398
    @command()
173 farthen 399
    def lockscheduler(self, freeze=True):
171 farthen 400
        """ Freezes/Unfreezes the scheduler """
548 farthen 401
        resp = self.lib.monitorcommand(struct.pack("<IIII", 16, 1 if freeze else 0, 0, 0), "III", ("before", None, None))
173 farthen 402
        return True if resp.before == 1 else False
67 benedikt93 403
 
394 farthen 404
    @command()
173 farthen 405
    def unlockscheduler(self):
171 farthen 406
        """ Unfreezes the scheduler """
548 farthen 407
        return self.lib.monitorcommand(struct.pack("<IIII", 16, 0, 0, 0), "III", ("before", None, None))
56 benedikt93 408
 
394 farthen 409
    @command()
171 farthen 410
    def suspendthread(self, id, suspend=True):
411
        """ Suspends the thread with the specified id """
548 farthen 412
        resp = self.lib.monitorcommand(struct.pack("<IIII", 17, 1 if suspend else 0, id, 0), "III", ("before", None, None))
173 farthen 413
        return True if resp.before == 1 else False
56 benedikt93 414
 
394 farthen 415
    @command()
173 farthen 416
    def resumethread(self, id):
417
        """ Resumes the thread with the specified id """
548 farthen 418
        return self.lib.monitorcommand(struct.pack("<IIII", 17, 0, id, 0), "III", ("before", None, None))
56 benedikt93 419
 
394 farthen 420
    @command()
171 farthen 421
    def killthread(self, id):
422
        """ Kills the thread with the specified id """
548 farthen 423
        return self.lib.monitorcommand(struct.pack("<IIII", 18, id, 0, 0), "III", ("before", None, None))
56 benedikt93 424
 
394 farthen 425
    @command()
171 farthen 426
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
427
        """ Creates a thread with the specified attributes """
428
        if threadtype == "user":
429
            threadtype = 0
430
        elif threadtype == "system":
431
            threadtype = 1
432
        else:
341 farthen 433
            raise ArgumentError("Threadtype must be either 'system' or 'user'")
171 farthen 434
        if priority > 256 or priority < 0:
341 farthen 435
            raise ArgumentError("Priority must be a number between 0 and 256")
171 farthen 436
        if state == "ready":
437
            state = 0
438
        elif state == "suspended":
439
            state = 1
440
        else:
341 farthen 441
            raise ArgumentError("State must be either 'ready' or 'suspended'")
548 farthen 442
        resp = self.lib.monitorcommand(struct.pack("<IIIIIIII", 19, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state), "III", ("threadptr", None, None))
516 farthen 443
        if resp.threadptr < 0:
518 farthen 444
            raise DeviceError("The device returned the error code %d" % resp.threadptr)
171 farthen 445
        return resp
56 benedikt93 446
 
394 farthen 447
    @command()
172 farthen 448
    def flushcaches(self):
171 farthen 449
        """ Flushes the CPU instruction and data cache """
548 farthen 450
        return self.lib.monitorcommand(struct.pack("<IIII", 20, 0, 0, 0), "III", (None, None, None))
56 benedikt93 451
 
394 farthen 452
    @command()
172 farthen 453
    def execimage(self, addr):
427 farthen 454
        """ Runs the emCORE app at 'addr' """
548 farthen 455
        return self.lib.monitorcommand(struct.pack("<IIII", 21, addr, 0, 0), "III", ("thread", None, None))
56 benedikt93 456
 
394 farthen 457
    @command()
238 farthen 458
    def run(self, app):
427 farthen 459
        """ Uploads and runs the emCORE app in the string 'app' """
583 farthen 460
        if app[:8].decode("ascii") != "emCOexec":
427 farthen 461
            raise ArgumentError("The specified app is not an emCORE application")
452 theseven 462
        baseaddr = self.malloc(len(app))
238 farthen 463
        self.write(baseaddr, app)
452 theseven 464
        result = self.execimage(baseaddr)
465
        return Bunch(thread=result.thread)
238 farthen 466
 
395 farthen 467
    @command(timeout = 5000)
171 farthen 468
    def bootflashread(self, memaddr, flashaddr, size):
469
        """ Copies the data in the bootflash at 'flashaddr' of the specified size
470
            to the memory at addr 'memaddr'
471
        """
548 farthen 472
        return self.lib.monitorcommand(struct.pack("<IIII", 22, memaddr, flashaddr, size), "III", (None, None, None))
82 benedikt93 473
 
395 farthen 474
    @command(timeout = 30000)
171 farthen 475
    def bootflashwrite(self, memaddr, flashaddr, size):
476
        """ Copies the data in the memory at 'memaddr' of the specified size
477
            to the boot flash at addr 'flashaddr'
478
        """
548 farthen 479
        return self.lib.monitorcommand(struct.pack("<IIII", 23, memaddr, flashaddr, size), "III", (None, None, None))
56 benedikt93 480
 
394 farthen 481
    @command()
442 farthen 482
    def execfirmware(self, targetaddr, addr, size):
483
        """ Moves the firmware at 'addr' with size 'size' to 'targetaddr' and passes all control to it. """
518 farthen 484
        self.logger.debug("Moving firmware at 0x%X with the size %d to 0x%X and executing it\n" % (addr, size, targetaddr))
548 farthen 485
        return self.lib.monitorcommand(struct.pack("<IIII", 24, targetaddr, addr, size))
56 benedikt93 486
 
395 farthen 487
    @command(timeout = 30000)
171 farthen 488
    def aesencrypt(self, addr, size, keyindex):
489
        """ Encrypts the buffer at 'addr' with the specified size
490
            with the hardware AES key index 'keyindex'
491
        """
548 farthen 492
        return self.lib.monitorcommand(struct.pack("<IBBHII", 25, 1, 0, keyindex, addr, size), "III", (None, None, None))
82 benedikt93 493
 
395 farthen 494
    @command(timeout = 30000)
171 farthen 495
    def aesdecrypt(self, addr, size, keyindex):
496
        """ Decrypts the buffer at 'addr' with the specified size
497
            with the hardware AES key index 'keyindex'
498
        """
548 farthen 499
        return self.lib.monitorcommand(struct.pack("<IBBHII", 25, 0, 0, keyindex, addr, size), "III", (None, None, None))
82 benedikt93 500
 
395 farthen 501
    @command(timeout = 30000)
171 farthen 502
    def hmac_sha1(self, addr, size, destination):
503
        """ Generates a HMAC-SHA1 hash of the buffer and saves it to 'destination' """
548 farthen 504
        return self.lib.monitorcommand(struct.pack("<IIII", 26, addr, size, destination), "III", (None, None, None))
56 benedikt93 505
 
398 farthen 506
    @command(target = 0x47324e49)
227 theseven 507
    def ipodnano2g_getnandinfo(self):
508
        """ Target-specific function: ipodnano2g
509
            Gathers some information about the NAND chip used
510
        """
548 farthen 511
        return self.lib.monitorcommand(struct.pack("<IIII", 0xffff0001, 0, 0, 0), "IHHHH", ("type", "pagesperblock", "banks", "userblocks", "blocks"))
227 theseven 512
 
398 farthen 513
    @command(timeout = 30000, target = 0x47324e49)
227 theseven 514
    def ipodnano2g_nandread(self, addr, start, count, doecc, checkempty):
515
        """ Target-specific function: ipodnano2g
516
            Reads data from the NAND chip into memory
517
        """
548 farthen 518
        return self.lib.monitorcommand(struct.pack("<IIII", 0xffff0002, addr | (0x80000000 if doecc else 0) | (0x40000000 if checkempty else 0), start, count), "III", (None, None, None))
227 theseven 519
 
398 farthen 520
    @command(timeout = 30000, target = 0x47324e49)
227 theseven 521
    def ipodnano2g_nandwrite(self, addr, start, count, doecc):
522
        """ Target-specific function: ipodnano2g
523
            Writes data to the NAND chip
524
        """
548 farthen 525
        return self.lib.monitorcommand(struct.pack("<IIII", 0xffff0003, addr | (0x80000000 if doecc else 0), start, count), "III", (None, None, None))
227 theseven 526
 
398 farthen 527
    @command(timeout = 30000, target = 0x47324e49)
227 theseven 528
    def ipodnano2g_nanderase(self, addr, start, count):
529
        """ Target-specific function: ipodnano2g
530
            Erases blocks on the NAND chip and stores the results to memory
531
        """
548 farthen 532
        return self.lib.monitorcommand(struct.pack("<IIII", 0xffff0004, addr, start, count), "III", (None, None, None))
227 theseven 533
 
398 farthen 534
    @command(target = 0x4c435049)
346 theseven 535
    def ipodclassic_gethddinfo(self):
536
        """ Target-specific function: ipodclassic
537
            Gather information about the hard disk drive
538
        """
548 farthen 539
        return self.lib.monitorcommand(struct.pack("<IIII", 0xffff0001, 0, 0, 0), "IQQII", ("identifyptr", "totalsectors", "virtualsectors", "bbtptr", "bbtsize"))
346 theseven 540
 
398 farthen 541
    @command(timeout = 30000, target = 0x4c435049)
346 theseven 542
    def ipodclassic_hddaccess(self, type, sector, count, addr):
543
        """ Target-specific function: ipodclassic
544
            Access the hard disk, type = 0 (read) / 1 (write)
545
        """
548 farthen 546
        rc = self.lib.monitorcommand(struct.pack("<IIQIIII", 0xffff0002, type, sector, count, addr, 0, 0), "III", ("rc", None, None))
585 theseven 547
        if (rc.rc > 0x80000000):
548
            raise DeviceError("HDD access (type=%d, sector=%d, count=%d, addr=0x%08X) failed with RC 0x%08X" % (type, sector, count, addr, rc.rc))
346 theseven 549
 
398 farthen 550
    @command(target = 0x4c435049)
585 theseven 551
    def ipodclassic_writebbt(self, bbt, tempaddr = None):
346 theseven 552
        """ Target-specific function: ipodclassic
553
            Write hard drive bad block table
554
        """
555
        try:
556
            bbtheader = struct.unpack("<8s2024sQII512I", bbt[:4096])
557
        except struct.error:
427 farthen 558
            raise ArgumentError("The specified file is not an emCORE hard disk BBT")
346 theseven 559
        if bbtheader[0] != "emBIbbth":
427 farthen 560
            raise ArgumentError("The specified file is not an emCORE hard disk BBT")
346 theseven 561
        virtualsectors = bbtheader[2]
562
        bbtsectors = bbtheader[3]
585 theseven 563
        if tempaddr is None:
564
            tempaddr = self.malloc(len(bbt))
565
            malloc = True
566
        else:
567
            malloc = False
568
        try:
569
            self.write(tempaddr, bbt)
570
            sector = 0
571
            count = 1
572
            offset = 0
573
            for i in range(bbtsectors):
574
                if bbtheader[4][i] == sector + count:
575
                    count = count + 1
576
                else:
577
                    self.ipodclassic_hddaccess(1, sector, count, tempaddr + offset)
578
                    offset = offset + count * 4096
579
                    sector = bbtheader[4][i]
580
                    count = 1
581
            self.ipodclassic_hddaccess(1, sector, count, tempaddr + offset)
582
        except:
583
            if malloc == True:
584
                self.free(tempaddr)
585
            raise
346 theseven 586
 
394 farthen 587
    @command()
379 theseven 588
    def storage_get_info(self, volume):
346 theseven 589
        """ Get information about a storage device """
484 theseven 590
        self.logger.debug("Getting storage information\n")
548 farthen 591
        result = self.lib.monitorcommand(struct.pack("<IIII", 27, volume, 0, 0), "IIIIIIII", ("version", None, None, "sectorsize", "numsectors", "vendorptr", "productptr", "revisionptr"))
346 theseven 592
        if result.version != 1:
593
            raise ValueError("Unknown version of storage_info struct: %d" % result.version)
379 theseven 594
        result.vendor = self.readstring(result.vendorptr)
595
        result.product = self.readstring(result.productptr)
596
        result.revision = self.readstring(result.revisionptr)
484 theseven 597
        self.logger.debug("Got storage information:\n")
598
        self.logger.debug("Vendor: %s\n" % result.vendor)
599
        self.logger.debug("Product: %s\n" % result.product)
600
        self.logger.debug("Revision: %s\n" % result.revision)
601
        self.logger.debug("Sector size: %d\n" % result.sectorsize)
602
        self.logger.debug("Number of sectors: %d\n" % result.numsectors)
346 theseven 603
        return result
604
 
395 farthen 605
    @command(timeout = 50000)
479 theseven 606
    def storage_read_sectors_md(self, volume, sector, count, addr):
607
        """ Read sectors from as storage device """
518 farthen 608
        self.logger.debug("Reading %d sectors from disk at volume %d, sector %d to memory at 0x%X\n" % (count, volume, sector, addr))
548 farthen 609
        result = self.lib.monitorcommand(struct.pack("<IIQIIII", 28, volume, sector, count, addr, 0, 0), "III", ("rc", None, None))
518 farthen 610
        self.logger.debug("Read sectors, result: 0x%X\n" % result.rc)
346 theseven 611
        if result.rc > 0x80000000:
612
            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 613
 
614
    @command(timeout = 50000)
615
    def storage_write_sectors_md(self, volume, sector, count, addr):
616
        """ Read sectors from as storage device """
518 farthen 617
        self.logger.debug("Writing %d sectors from memory at 0x%X to disk at volume %d, sector %d\n" % (count, addr, volume, sector))
548 farthen 618
        result = self.lib.monitorcommand(struct.pack("<IIQIIII", 29, volume, sector, count, addr, 0, 0), "III", ("rc", None, None))
518 farthen 619
        self.logger.debug("Wrote sectors, result: 0x%X\n" % result.rc)
346 theseven 620
        if result.rc > 0x80000000:
479 theseven 621
            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 622
 
395 farthen 623
    @command(timeout = 30000)
479 theseven 624
    def fat_enable_flushing(self, state):
625
        """ Enables/disables flushing the FAT cache after every transaction """
484 theseven 626
        if state != 0: self.logger.debug("Enabling FAT flushing\n")
627
        else: self.logger.debug("Disabling FAT flushing\n")
548 farthen 628
        self.lib.monitorcommand(struct.pack("<IIII", 58, state, 0, 0), "III", (None, None, None))
484 theseven 629
        if state != 0: self.logger.debug("Enabled FAT flushing\n")
630
        else: self.logger.debug("Disabled FAT flushing\n")
517 farthen 631
 
479 theseven 632
    @command(timeout = 30000)
346 theseven 633
    def file_open(self, filename, mode):
634
        """ Opens a file and returns the handle """
487 theseven 635
        self.logger.debug("Opening remote file %s with mode %d\n" % (filename, mode))
548 farthen 636
        result = self.lib.monitorcommand(struct.pack("<IIII%dsB" % len(filename), 30, mode, 0, 0, filename, 0), "III", ("fd", None, None))
346 theseven 637
        if result.fd > 0x80000000:
638
            raise DeviceError("file_open(filename=\"%s\", mode=0x%X) failed with RC=0x%08X, errno=%d" % (filename, mode, result.fd, self.errno()))
518 farthen 639
        self.logger.debug("Opened file as handle 0x%X\n" % result.fd)
346 theseven 640
        return result.fd
641
 
395 farthen 642
    @command(timeout = 30000)
346 theseven 643
    def file_size(self, fd):
644
        """ Gets the size of a file referenced by a handle """
518 farthen 645
        self.logger.debug("Getting file size of handle 0x%X\n" % fd)
548 farthen 646
        result = self.lib.monitorcommand(struct.pack("<IIII", 31, fd, 0, 0), "III", ("size", None, None))
346 theseven 647
        if result.size > 0x80000000:
648
            raise DeviceError("file_size(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.size, self.errno()))
484 theseven 649
        self.logger.debug("Got file size: %d bytes\n" % result.size)
346 theseven 650
        return result.size
394 farthen 651
 
395 farthen 652
    @command(timeout = 30000)
480 theseven 653
    def file_read(self, fd, size, addr = None):
472 farthen 654
        """ Reads data from a file referenced by a handle. If addr is not given it allocates a buffer itself. """
655
        if addr is None:
656
            addr = self.malloc(size)
657
            malloc = True
658
        else:
659
            malloc = False
518 farthen 660
        self.logger.debug("Reading %d bytes from file handle 0x%X to 0x%X\n" % (size, fd, addr))
472 farthen 661
        try:
548 farthen 662
            result = self.lib.monitorcommand(struct.pack("<IIII", 32, fd, addr, size), "III", ("rc", None, None))
479 theseven 663
            if result.rc > 0x80000000:
664
                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()))
665
        except:
472 farthen 666
            if malloc == True:
667
                self.free(addr)
479 theseven 668
            raise
518 farthen 669
        self.logger.debug("File read result: 0x%X\n" % result.rc)
479 theseven 670
        return Bunch(rc = result.rc, addr = addr)
394 farthen 671
 
395 farthen 672
    @command(timeout = 30000)
479 theseven 673
    def file_write(self, fd, size, addr):
674
        """ Writes data from a file referenced by a handle. """
518 farthen 675
        self.logger.debug("Writing %d bytes from 0x%X to file handle 0x%X\n" % (size, addr, fd))
548 farthen 676
        result = self.lib.monitorcommand(struct.pack("<IIII", 33, fd, addr, size), "III", ("rc", None, None))
346 theseven 677
        if result.rc > 0x80000000:
678
            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 679
        self.logger.debug("File write result: 0x%X\n" % result.rc)
346 theseven 680
        return result.rc
681
 
395 farthen 682
    @command(timeout = 30000)
346 theseven 683
    def file_seek(self, fd, offset, whence):
684
        """ Seeks the file handle to the specified position in the file """
518 farthen 685
        self.logger.debug("Seeking file handle 0x%X to whence=%d, offset=0x%X\n" % (fd, whence, offset))
548 farthen 686
        result = self.lib.monitorcommand(struct.pack("<IIII", 34, fd, offset, whence), "III", ("rc", None, None))
346 theseven 687
        if result.rc > 0x80000000:
688
            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 689
        self.logger.debug("File seek result: 0x%X\n" % (result.rc))
346 theseven 690
        return result.rc
691
 
395 farthen 692
    @command(timeout = 30000)
346 theseven 693
    def file_truncate(self, fd, length):
694
        """ Truncates a file referenced by a handle to a specified length """
518 farthen 695
        self.logger.debug("Truncating file with handle 0x%X to 0x%X bytes\n" % (fd, length))
548 farthen 696
        result = self.lib.monitorcommand(struct.pack("<IIII", 35, fd, offset, 0), "III", ("rc", None, None))
346 theseven 697
        if result.rc > 0x80000000:
698
            raise DeviceError("file_truncate(fd=%d, length=0x%08X) failed with RC=0x%08X, errno=%d" % (fd, length, result.rc, self.errno()))
518 farthen 699
        self.logger.debug("File truncate result: 0x%X\n" % (result.rc))
346 theseven 700
        return result.rc
701
 
395 farthen 702
    @command(timeout = 30000)
346 theseven 703
    def file_sync(self, fd):
704
        """ Flushes a file handles' buffers """
518 farthen 705
        self.logger.debug("Flushing buffers of file with handle 0x%X\n" % (fd))
548 farthen 706
        result = self.lib.monitorcommand(struct.pack("<IIII", 36, fd, 0, 0), "III", ("rc", None, None))
346 theseven 707
        if result.rc > 0x80000000:
708
            raise DeviceError("file_sync(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.rc, self.errno()))
518 farthen 709
        self.logger.debug("File flush result: 0x%X\n" % (result.rc))
346 theseven 710
        return result.rc
711
 
395 farthen 712
    @command(timeout = 30000)
346 theseven 713
    def file_close(self, fd):
714
        """ Closes a file handle """
518 farthen 715
        self.logger.debug("Closing file handle 0x%X\n" % (fd))
548 farthen 716
        result = self.lib.monitorcommand(struct.pack("<IIII", 37, fd, 0, 0), "III", ("rc", None, None))
346 theseven 717
        if result.rc > 0x80000000:
718
            raise DeviceError("file_close(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.rc, self.errno()))
518 farthen 719
        self.logger.debug("File close result: 0x%X\n" % (result.rc))
346 theseven 720
        return result.rc
721
 
395 farthen 722
    @command(timeout = 30000)
346 theseven 723
    def file_close_all(self):
724
        """ Closes all file handles opened through the debugger """
484 theseven 725
        self.logger.debug("Closing all files that were opened via USB\n")
548 farthen 726
        result = self.lib.monitorcommand(struct.pack("<IIII", 38, 0, 0, 0), "III", ("rc", None, None))
346 theseven 727
        if result.rc > 0x80000000:
728
            raise DeviceError("file_close_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
484 theseven 729
        self.logger.debug("Closed %d files\n" % (result.rc))
346 theseven 730
        return result.rc
731
 
395 farthen 732
    @command(timeout = 30000)
484 theseven 733
    def file_kill_all(self, volume):
734
        """ Kills all file handles of a volume (in the whole system) """
735
        self.logger.debug("Killing all file handles of volume %d\n" % (volume))
548 farthen 736
        result = self.lib.monitorcommand(struct.pack("<IIII", 39, volume, 0, 0), "III", ("rc", None, None))
346 theseven 737
        if result.rc > 0x80000000:
738
            raise DeviceError("file_kill_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
484 theseven 739
        self.logger.debug("Closed %d files\n" % (result.rc))
346 theseven 740
        return result.rc
741
 
395 farthen 742
    @command(timeout = 30000)
346 theseven 743
    def file_unlink(self, filename):
744
        """ Removes a file """
484 theseven 745
        self.logger.debug("Deleting file %s\n" % (filename))
548 farthen 746
        result = self.lib.monitorcommand(struct.pack("<IIII%dsB" % len(filename), 40, 0, 0, 0, filename, 0), "III", ("rc", None, None))
346 theseven 747
        if result.rc > 0x80000000:
748
            raise DeviceError("file_unlink(filename=\"%s\") failed with RC=0x%08X, errno=%d" % (filename, result.rc, self.errno()))
518 farthen 749
        self.logger.debug("Delete file result: 0x%X\n" % (result.rc))
346 theseven 750
        return result.rc
751
 
395 farthen 752
    @command(timeout = 30000)
346 theseven 753
    def file_rename(self, oldname, newname):
754
        """ Renames a file """
484 theseven 755
        self.logger.debug("Renaming file %s to %s\n" % (oldname, newname))
548 farthen 756
        result = self.lib.monitorcommand(struct.pack("<IIII248s%dsB" % min(247, len(newname)), 41, 0, 0, 0, oldname, newname, 0), "III", ("rc", None, None))
346 theseven 757
        if result.rc > 0x80000000:
758
            raise DeviceError("file_rename(oldname=\"%s\", newname=\"%s\") failed with RC=0x%08X, errno=%d" % (oldname, newname, result.rc, self.errno()))
518 farthen 759
        self.logger.debug("Rename file result: 0x%X\n" % (result.rc))
346 theseven 760
        return result.rc
761
 
395 farthen 762
    @command(timeout = 30000)
346 theseven 763
    def dir_open(self, dirname):
764
        """ Opens a directory and returns the handle """
484 theseven 765
        self.logger.debug("Opening directory %s\n" % (dirname))
548 farthen 766
        result = self.lib.monitorcommand(struct.pack("<IIII%dsB" % len(dirname), 42, 0, 0, 0, dirname, 0), "III", ("handle", None, None))
346 theseven 767
        if result.handle == 0:
768
            raise DeviceError("dir_open(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.handle, self.errno()))
518 farthen 769
        self.logger.debug("Opened directory as handle 0x%X\n" % (result.handle))
346 theseven 770
        return result.handle
771
 
395 farthen 772
    @command(timeout = 30000)
346 theseven 773
    def dir_read(self, handle):
774
        """ Reads the next entry from a directory """
518 farthen 775
        self.logger.debug("Reading next entry of directory handle 0x%X\n" % (handle))
548 farthen 776
        result = self.lib.monitorcommand(struct.pack("<IIII", 43, handle, 0, 0), "III", ("version", "maxpath", "ptr"))
346 theseven 777
        if result.ptr == 0:
778
            raise DeviceError("dir_read(handle=0x%08X) failed with RC=0x%08X, errno=%d" % (handle, result.ptr, self.errno()))
779
        if result.version != 1:
780
            raise ValueError("Unknown version of dirent struct: %d" % result.version)
781
        dirent = self.read(result.ptr, result.maxpath + 16)
782
        ret = Bunch()
548 farthen 783
        (ret.name, ret.attributes, ret.size, ret.startcluster, ret.wrtdate, ret.wrttime) = struct.unpack("<%dsIIIHH" % result.maxpath, dirent)
346 theseven 784
        ret.name = ret.name[:ret.name.index('\x00')]
484 theseven 785
        self.logger.debug("Read directory entry:\n")
786
        self.logger.debug("Name: %s\n" % ret.name)
518 farthen 787
        self.logger.debug("Attributes: 0x%X\n" % ret.attributes)
484 theseven 788
        self.logger.debug("Size: %d\n" % ret.size)
789
        self.logger.debug("Start cluster: %d\n" % ret.startcluster)
518 farthen 790
        self.logger.debug("Last written date: 0x%X\n" % ret.wrtdate)
791
        self.logger.debug("Last written time: 0x%X\n" % ret.wrttime)
346 theseven 792
        return ret
793
 
395 farthen 794
    @command(timeout = 30000)
346 theseven 795
    def dir_close(self, handle):
796
        """ Closes a directory handle """
518 farthen 797
        self.logger.debug("Closing directory handle 0x%X\n" % (handle))
548 farthen 798
        result = self.lib.monitorcommand(struct.pack("<IIII", 44, handle, 0, 0), "III", ("rc", None, None))
346 theseven 799
        if result.rc > 0x80000000:
800
            raise DeviceError("dir_close(handle=0x%08X) failed with RC=0x%08X, errno=%d" % (handle, result.rc, self.errno()))
518 farthen 801
        self.logger.debug("Close directory result: 0x%X\n" % (result.rc))
346 theseven 802
        return result.rc
803
 
395 farthen 804
    @command(timeout = 30000)
346 theseven 805
    def dir_close_all(self):
806
        """ Closes all directory handles opened through the debugger """
484 theseven 807
        self.logger.debug("Closing all directories that were opened via USB\n")
548 farthen 808
        result = self.lib.monitorcommand(struct.pack("<IIII", 45, 0, 0, 0), "III", ("rc", None, None))
346 theseven 809
        if result.rc > 0x80000000:
810
            raise DeviceError("dir_close_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
484 theseven 811
        self.logger.debug("Closed %d directories\n" % (result.rc))
346 theseven 812
        return result.rc
813
 
395 farthen 814
    @command(timeout = 30000)
484 theseven 815
    def dir_kill_all(self, volume):
816
        """ Kills all directory handles of a volume (in the whole system) """
817
        self.logger.debug("Closing all directories of volume %d\n" % (volume))
548 farthen 818
        result = self.lib.monitorcommand(struct.pack("<IIII", 46, volume, 0, 0), "III", ("rc", None, None))
346 theseven 819
        if result.rc > 0x80000000:
820
            raise DeviceError("dir_kill_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
484 theseven 821
        self.logger.debug("Closed %d directories\n" % (result.rc))
346 theseven 822
        return result.rc
823
 
395 farthen 824
    @command(timeout = 30000)
346 theseven 825
    def dir_create(self, dirname):
826
        """ Creates a directory """
484 theseven 827
        self.logger.debug("Creating directory %s\n" % (dirname))
548 farthen 828
        result = self.lib.monitorcommand(struct.pack("<IIII%dsB" % len(dirname), 47, 0, 0, 0, dirname, 0), "III", ("rc", None, None))
346 theseven 829
        if result.rc > 0x80000000:
830
            raise DeviceError("dir_create(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.rc, self.errno()))
518 farthen 831
        self.logger.debug("Create directory result: 0x%X\n" % (result.rc))
346 theseven 832
        return result.rc
833
 
395 farthen 834
    @command(timeout = 30000)
346 theseven 835
    def dir_remove(self, dirname):
836
        """ Removes an (empty) directory """
484 theseven 837
        self.logger.debug("Removing directory %s\n" % (dirname))
548 farthen 838
        result = self.lib.monitorcommand(struct.pack("<IIII%dsB" % len(dirname), 48, 0, 0, 0, dirname, 0), "III", ("rc", None, None))
346 theseven 839
        if result.rc > 0x80000000:
840
            raise DeviceError("dir_remove(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.rc, self.errno()))
518 farthen 841
        self.logger.debug("Remove directory result: 0x%X\n" % (result.rc))
346 theseven 842
        return result.rc
843
 
394 farthen 844
    @command()
346 theseven 845
    def errno(self):
846
        """ Returns the number of the last error that happened """
484 theseven 847
        self.logger.debug("Getting last error number\n")
548 farthen 848
        result = self.lib.monitorcommand(struct.pack("<IIII", 49, 0, 0, 0), "III", ("errno", None, None))
518 farthen 849
        self.logger.debug("Last error: 0x%X\n" % (result.errno))
346 theseven 850
        return result.errno
851
 
394 farthen 852
    @command()
346 theseven 853
    def disk_mount(self, volume):
854
        """ Mounts a volume """
484 theseven 855
        self.logger.debug("Mounting volume %d\n" % (volume))
548 farthen 856
        result = self.lib.monitorcommand(struct.pack("<IIII", 50, volume, 0, 0), "III", ("rc", None, None))
346 theseven 857
        if result.rc > 0x80000000:
858
            raise DeviceError("disk_mount(volume=%d) failed with RC=0x%08X, errno=%d" % (volume, result.rc, self.errno()))
518 farthen 859
        self.logger.debug("Mount volume result: 0x%X\n" % (result.rc))
346 theseven 860
        return result.rc
861
 
394 farthen 862
    @command()
346 theseven 863
    def disk_unmount(self, volume):
864
        """ Unmounts a volume """
484 theseven 865
        self.logger.debug("Unmounting volume %d\n" % (volume))
548 farthen 866
        result = self.lib.monitorcommand(struct.pack("<IIII", 51, volume, 0, 0), "III", ("rc", None, None))
346 theseven 867
        if result.rc > 0x80000000:
868
            raise DeviceError("disk_unmount(volume=%d) failed with RC=0x%08X, errno=%d" % (volume, result.rc, self.errno()))
518 farthen 869
        self.logger.debug("Unmount volume result: 0x%X\n" % (result.rc))
346 theseven 870
        return result.rc
871
 
441 farthen 872
    @command()
873
    def malloc(self, size):
874
        """ Allocates 'size' bytes and returns a pointer to the allocated memory """
442 farthen 875
        self.logger.debug("Allocating %d bytes of memory\n" % size)
548 farthen 876
        result = self.lib.monitorcommand(struct.pack("<IIII", 52, size, 0, 0), "III", ("ptr", None, None))
518 farthen 877
        self.logger.debug("Allocated %d bytes of memory at 0x%X\n" % (size, result.ptr))
441 farthen 878
        return result.ptr
879
 
880
    @command()
881
    def memalign(self, align, size):
882
        """ Allocates 'size' bytes aligned to 'align' and returns a pointer to the allocated memory """
518 farthen 883
        self.logger.debug("Allocating %d bytes of memory aligned to 0x%X\n" % (size, align))
548 farthen 884
        result = self.lib.monitorcommand(struct.pack("<IIII", 53, align, size, 0), "III", ("ptr", None, None))
518 farthen 885
        self.logger.debug("Allocated %d bytes of memory at 0x%X\n" % (size, result.ptr))
441 farthen 886
        return result.ptr
887
 
888
    @command()
889
    def realloc(self, ptr, size):
890
        """ The size of the memory block pointed to by 'ptr' is changed to the 'size' bytes,
891
            expanding or reducing the amount of memory available in the block.
892
            Returns a pointer to the reallocated memory.
893
        """
518 farthen 894
        self.logger.debug("Reallocating 0x%X to have the new size %d\n" % (ptr, size))
548 farthen 895
        result = self.lib.monitorcommand(struct.pack("<IIII", 54, ptr, size, 0), "III", ("ptr", None, None))
518 farthen 896
        self.logger.debug("Reallocated memory at 0x%X to 0x%X with the new size %d\n" % (ptr, result.ptr, size))
441 farthen 897
        return result.ptr
898
 
899
    @command()
900
    def reownalloc(self, ptr, owner):
901
        """ Changes the owner of the memory allocation 'ptr' to the thread struct at addr 'owner' """
518 farthen 902
        self.logger.debug("Changing owner of the memory region 0x%X to 0x%X\n" % (ptr, owner))
548 farthen 903
        return self.lib.monitorcommand(struct.pack("<IIII", 55, ptr, owner, 0), "III", (None, None, None))
441 farthen 904
 
905
    @command()
906
    def free(self, ptr):
907
        """ Frees the memory space pointed to by 'ptr' """
518 farthen 908
        self.logger.debug("Freeing the memory region at 0x%X\n" % ptr)
548 farthen 909
        return self.lib.monitorcommand(struct.pack("<IIII", 56, ptr, 0, 0), "III", (None, None, None))
441 farthen 910
 
473 farthen 911
    @command()
912
    def free_all(self):
913
        """ Frees all memory allocations created by the monitor thread """
914
        self.logger.debug("Freeing all memory allocations created by the monitor thread\n")
548 farthen 915
        return self.lib.monitorcommand(struct.pack("<IIII", 57, 0, 0, 0), "III", (None, None, None))
346 theseven 916
 
517 farthen 917
 
171 farthen 918
class Lib(object):
401 farthen 919
    def __init__(self, logger):
920
        self.logger = logger
921
        self.logger.debug("Initializing Lib object\n")
171 farthen 922
        self.idVendor = 0xFFFF
923
        self.idProduct = 0xE000
176 farthen 924
 
925
        self.headersize = 0x10
926
 
927
        self.connect()
56 benedikt93 928
 
171 farthen 929
    def connect(self):
401 farthen 930
        self.dev = Dev(self.idVendor, self.idProduct, self.logger)
171 farthen 931
        self.connected = True
56 benedikt93 932
 
171 farthen 933
    def monitorcommand(self, cmd, rcvdatatypes=None, rcvstruct=None):
582 farthen 934
        self.logger.debug("Sending monitorcommand [0x%s]\n" % base64.b16encode(cmd[3::-1]).decode("ascii"))
269 farthen 935
        writelen = self.dev.cout(cmd)
171 farthen 936
        if rcvdatatypes:
937
            rcvdatatypes = "I" + rcvdatatypes # add the response
938
            data = self.dev.cin(struct.calcsize(rcvdatatypes))
939
            data = struct.unpack(rcvdatatypes, data)
506 farthen 940
            try:
941
                response = responsecode(data[0])
942
            except IndexError:
943
                self.logger.debug("Response: UNKOWN\n")
944
                raise DeviceError("Invalid response! This should NOT happen!")
945
            if response == "OK":
401 farthen 946
                self.logger.debug("Response: OK\n")
171 farthen 947
                if rcvstruct:
948
                    datadict = Bunch()
949
                    counter = 1 # start with 1, 0 is the id
950
                    for item in rcvstruct:
951
                        if item != None: # else the data is undefined
952
                            datadict[item] = data[counter]
953
                        counter += 1
954
                    return datadict
955
                else:
956
                    return data
506 farthen 957
            elif response == "UNSUPPORTED":
401 farthen 958
                self.logger.debug("Response: UNSUPPORTED\n")
171 farthen 959
                raise DeviceError("The device does not support this command.")
506 farthen 960
            elif response == "INVALID":
401 farthen 961
                self.logger.debug("Response: INVALID\n")
171 farthen 962
                raise DeviceError("Invalid command! This should NOT happen!")
506 farthen 963
            elif response == "BUSY":
401 farthen 964
                self.logger.debug("Response: BUSY\n")
171 farthen 965
                raise DeviceError("Device busy")
269 farthen 966
        else:
967
            return writelen
56 benedikt93 968
 
969
 
171 farthen 970
class Dev(object):
401 farthen 971
    def __init__(self, idVendor, idProduct, logger):
171 farthen 972
        self.idVendor = idVendor
973
        self.idProduct = idProduct
67 benedikt93 974
 
401 farthen 975
        self.logger = logger
976
        self.logger.debug("Initializing Dev object\n")
977
 
171 farthen 978
        self.interface = 0
979
        self.timeout = 100
517 farthen 980
 
171 farthen 981
        self.connect()
982
        self.findEndpoints()
983
 
401 farthen 984
        self.logger.debug("Successfully connected to device\n")
342 farthen 985
 
986
        # Device properties
343 farthen 987
        self.packetsizelimit = Bunch()
988
        self.packetsizelimit.cout = None
989
        self.packetsizelimit.cin = None
990
        self.packetsizelimit.dout = None
991
        self.packetsizelimit.din = None
342 farthen 992
 
343 farthen 993
        self.version = Bunch()
342 farthen 994
        self.version.revision = None
995
        self.version.majorv = None
996
        self.version.minorv = None
997
        self.version.patchv = None
998
        self.swtypeid = None
999
        self.hwtypeid = None
1000
 
343 farthen 1001
        self.usermem = Bunch()
342 farthen 1002
        self.usermem.lower = None
1003
        self.usermem.upper = None
56 benedikt93 1004
 
171 farthen 1005
    def __del__(self):
1006
        self.disconnect()
56 benedikt93 1007
 
171 farthen 1008
    def findEndpoints(self):
401 farthen 1009
        self.logger.debug("Searching for device endpoints:\n")
171 farthen 1010
        epcounter = 0
343 farthen 1011
        self.endpoint = Bunch()
171 farthen 1012
        for cfg in self.dev:
1013
            for intf in cfg:
1014
                for ep in intf:
1015
                    if epcounter == 0:
518 farthen 1016
                        self.logger.debug("Found cout endpoint at 0x%X\n" % ep.bEndpointAddress)
343 farthen 1017
                        self.endpoint.cout = ep.bEndpointAddress
171 farthen 1018
                    elif epcounter == 1:
518 farthen 1019
                        self.logger.debug("Found cin endpoint at 0x%X\n" % ep.bEndpointAddress)
343 farthen 1020
                        self.endpoint.cin = ep.bEndpointAddress
171 farthen 1021
                    elif epcounter == 2:
518 farthen 1022
                        self.logger.debug("Found dout endpoint at 0x%X\n" % ep.bEndpointAddress)
343 farthen 1023
                        self.endpoint.dout = ep.bEndpointAddress
171 farthen 1024
                    elif epcounter == 3:
518 farthen 1025
                        self.logger.debug("Found din endpoint at 0x%X\n" % ep.bEndpointAddress)
343 farthen 1026
                        self.endpoint.din = ep.bEndpointAddress
171 farthen 1027
                    epcounter += 1
1028
        if epcounter <= 3:
518 farthen 1029
            raise DeviceError("Not all endpoints found in the descriptor. Only %d endpoints found, at least 4 endpoints were expeceted" % epcounter)
56 benedikt93 1030
 
171 farthen 1031
    def connect(self):
427 farthen 1032
        self.logger.debug("Looking for emCORE device\n")
171 farthen 1033
        self.dev = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
1034
        if self.dev is None:
1035
            raise DeviceNotFoundError()
401 farthen 1036
        self.logger.debug("Device Found!\n")
1037
        self.logger.debug("Setting first configuration\n")
171 farthen 1038
        self.dev.set_configuration()
56 benedikt93 1039
 
171 farthen 1040
    def disconnect(self):
1041
        pass
102 benedikt93 1042
 
171 farthen 1043
    def send(self, endpoint, data):
1044
        size = self.dev.write(endpoint, data, self.interface, self.timeout)
1045
        if size != len(data):
176 farthen 1046
            raise SendError("Not all data was written!")
171 farthen 1047
        return len
102 benedikt93 1048
 
171 farthen 1049
    def receive(self, endpoint, size):
1050
        read = self.dev.read(endpoint, size, self.interface, self.timeout)
1051
        if len(read) != size:
176 farthen 1052
            raise ReceiveError("Requested size and read size don't match!")
171 farthen 1053
        return read
56 benedikt93 1054
 
171 farthen 1055
    def cout(self, data):
518 farthen 1056
        self.logger.debug("Sending data to cout endpoint with the size %d\n" % len(data))
343 farthen 1057
        if self.packetsizelimit.cout and len(data) > self.packetsizelimit.cout:
171 farthen 1058
            raise SendError("Packet too big")
343 farthen 1059
        return self.send(self.endpoint.cout, data)
94 benedikt93 1060
 
171 farthen 1061
    def cin(self, size):
518 farthen 1062
        self.logger.debug("Receiving data on the cin endpoint with the size %d\n" % size)
343 farthen 1063
        if self.packetsizelimit.cin and size > self.packetsizelimit.cin:
171 farthen 1064
            raise ReceiveError("Packet too big")
343 farthen 1065
        return self.receive(self.endpoint.cin, size)
94 benedikt93 1066
 
171 farthen 1067
    def dout(self, data):
518 farthen 1068
        self.logger.debug("Sending data to cout endpoint with the size %d\n" % len(data))
343 farthen 1069
        if self.packetsizelimit.dout and len(data) > self.packetsizelimit.dout:
171 farthen 1070
            raise SendError("Packet too big")
343 farthen 1071
        return self.send(self.endpoint.dout, data)
94 benedikt93 1072
 
171 farthen 1073
    def din(self, size):
518 farthen 1074
        self.logger.debug("Receiving data on the din endpoint with the size %d\n" % size)
343 farthen 1075
        if self.packetsizelimit.din and size > self.packetsizelimit.din:
171 farthen 1076
            raise ReceiveError("Packet too big")
343 farthen 1077
        return self.receive(self.endpoint.din, size)
56 benedikt93 1078
 
96 benedikt93 1079
 
171 farthen 1080
if __name__ == "__main__":
396 farthen 1081
    from misc import Logger
1082
    logger = Logger()
1083
 
500 farthen 1084
    if sys.argv[1] == "gendoc":
396 farthen 1085
        # Generates Documentation
1086
        from misc import gendoc
501 farthen 1087
        logger.write("Generating documentation\n")
396 farthen 1088
        cmddict = {}
582 farthen 1089
        for attr, value in Emcore.__dict__.items():
396 farthen 1090
            if getattr(value, 'func', False):
1091
                if getattr(value.func, '_command', False):
1092
                    cmddict[value.func.__name__] = value
501 farthen 1093
        logger.write(gendoc(cmddict))
441 farthen 1094
 
1095
    elif sys.argv[1] == "malloctest":
1096
        emcore = Emcore()
501 farthen 1097
        logger.write("Allocating 200 bytes of memory: ")
441 farthen 1098
        addr = emcore.malloc(200)
518 farthen 1099
        logger.write("0x%X\n" % addr)
501 farthen 1100
        logger.write("Reallocating to 2000 bytes: ")
441 farthen 1101
        addr = emcore.realloc(addr, 2000)
518 farthen 1102
        logger.write("0x%X\n" % addr)
1103
        logger.write("Freeing 0x%X\n" % addr)
441 farthen 1104
        emcore.free(addr)
501 farthen 1105
        logger.write("Allocating 1000 bytes of memory aligned to 100 bytes: ")
441 farthen 1106
        addr = emcore.memalign(100, 1000)
518 farthen 1107
        logger.write("0x%X\n" % addr)
1108
        logger.write("Freeing 0x%X\n" % addr)
441 farthen 1109
        emcore.free(addr)