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