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