Subversion Repositories freemyipod

Rev

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