Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

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