| 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()
|
| 176 |
farthen |
106 |
self.getpacketsizeinfo()
|
| 343 |
farthen |
107 |
self.getusermemrange()
|
| 56 |
benedikt93 |
108 |
|
| 171 |
farthen |
109 |
@staticmethod
|
|
|
110 |
def _alignsplit(addr, size, blksize, align):
|
| 177 |
farthen |
111 |
if size <= blksize: return (size, 0, 0)
|
| 171 |
farthen |
112 |
end = addr + size
|
|
|
113 |
if addr & (align - 1):
|
|
|
114 |
bodyaddr = (addr + min(size, blksize)) & ~(align - 1)
|
|
|
115 |
else: bodyaddr = addr
|
|
|
116 |
headsize = bodyaddr - addr
|
|
|
117 |
if (size - headsize) & (align - 1):
|
|
|
118 |
tailaddr = (end - min(end - bodyaddr, blksize) + align - 1) & ~(align - 1)
|
|
|
119 |
else: tailaddr = end
|
|
|
120 |
tailsize = end - tailaddr
|
|
|
121 |
return (headsize, tailaddr - bodyaddr, tailsize)
|
| 56 |
benedikt93 |
122 |
|
| 394 |
farthen |
123 |
@command()
|
| 178 |
farthen |
124 |
def _readmem(self, addr, size):
|
|
|
125 |
""" Reads the memory from location 'addr' with size 'size'
|
|
|
126 |
from the device.
|
|
|
127 |
"""
|
|
|
128 |
resp = self.lib.monitorcommand(struct.pack("IIII", 4, addr, size, 0), "III%ds" % size, (None, None, None, "data"))
|
|
|
129 |
return resp.data
|
| 394 |
farthen |
130 |
|
|
|
131 |
@command()
|
| 178 |
farthen |
132 |
def _writemem(self, addr, data):
|
|
|
133 |
""" Writes the data in 'data' to the location 'addr'
|
|
|
134 |
in the memory of the device.
|
|
|
135 |
"""
|
|
|
136 |
return self.lib.monitorcommand(struct.pack("IIII%ds" % len(data), 5, addr, len(data), 0, data), "III", (None, None, None))
|
|
|
137 |
|
| 394 |
farthen |
138 |
@command()
|
| 178 |
farthen |
139 |
def _readdma(self, addr, size):
|
|
|
140 |
""" Reads the memory from location 'addr' with size 'size'
|
|
|
141 |
from the device. This uses DMA and the data in endpoint.
|
|
|
142 |
"""
|
|
|
143 |
self.lib.monitorcommand(struct.pack("IIII", 6, addr, size, 0), "III", (None, None, None))
|
|
|
144 |
return struct.unpack("%ds" % size, self.lib.dev.din(size))[0]
|
|
|
145 |
|
| 394 |
farthen |
146 |
@command()
|
| 178 |
farthen |
147 |
def _writedma(self, addr, data):
|
|
|
148 |
""" Writes the data in 'data' to the location 'addr'
|
|
|
149 |
in the memory of the device. This uses DMA and the data out endpoint.
|
|
|
150 |
"""
|
|
|
151 |
self.lib.monitorcommand(struct.pack("IIII", 7, addr, len(data), 0), "III", (None, None, None))
|
|
|
152 |
return self.lib.dev.dout(data)
|
|
|
153 |
|
| 394 |
farthen |
154 |
@command()
|
| 171 |
farthen |
155 |
def getversioninfo(self):
|
| 427 |
farthen |
156 |
""" This returns the emCORE version and device information. """
|
| 342 |
farthen |
157 |
resp = self.lib.monitorcommand(struct.pack("IIII", 1, 0, 0, 0), "IBBBBI", ("revision", "majorv", "minorv", "patchv", "swtypeid", "hwtypeid"))
|
|
|
158 |
self.lib.dev.version.revision = resp.revision
|
|
|
159 |
self.lib.dev.version.majorv = resp.majorv
|
|
|
160 |
self.lib.dev.version.minorv = resp.minorv
|
|
|
161 |
self.lib.dev.version.patchv = resp.patchv
|
| 401 |
farthen |
162 |
self.logger.debug("Device Software Type ID = " + str(resp.swtypeid) + "\n")
|
| 342 |
farthen |
163 |
self.lib.dev.swtypeid = resp.swtypeid
|
| 401 |
farthen |
164 |
self.logger.debug("Device Hardware Type ID = " + str(resp.hwtypeid) + "\n")
|
| 342 |
farthen |
165 |
self.lib.dev.hwtypeid = resp.hwtypeid
|
|
|
166 |
return resp
|
| 56 |
benedikt93 |
167 |
|
| 394 |
farthen |
168 |
@command()
|
| 171 |
farthen |
169 |
def getpacketsizeinfo(self):
|
| 427 |
farthen |
170 |
""" This returns the emCORE max packet size information.
|
| 171 |
farthen |
171 |
It also sets the properties of the device object accordingly.
|
|
|
172 |
"""
|
|
|
173 |
resp = self.lib.monitorcommand(struct.pack("IIII", 1, 1, 0, 0), "HHII", ("coutmax", "cinmax", "doutmax", "dinmax"))
|
| 401 |
farthen |
174 |
self.logger.debug("Device cout packet size limit = " + str(resp.coutmax) + "\n")
|
| 343 |
farthen |
175 |
self.lib.dev.packetsizelimit.cout = resp.coutmax
|
| 401 |
farthen |
176 |
self.logger.debug("Device cin packet size limit = " + str(resp.cinmax) + "\n")
|
| 343 |
farthen |
177 |
self.lib.dev.packetsizelimit.cin = resp.cinmax
|
| 401 |
farthen |
178 |
self.logger.debug("Device din packet size limit = " + str(resp.doutmax) + "\n")
|
| 343 |
farthen |
179 |
self.lib.dev.packetsizelimit.din = resp.dinmax
|
| 401 |
farthen |
180 |
self.logger.debug("Device dout packet size limit = " + str(resp.dinmax) + "\n")
|
| 343 |
farthen |
181 |
self.lib.dev.packetsizelimit.dout = resp.doutmax
|
| 171 |
farthen |
182 |
return resp
|
| 56 |
benedikt93 |
183 |
|
| 394 |
farthen |
184 |
@command()
|
| 171 |
farthen |
185 |
def getusermemrange(self):
|
|
|
186 |
""" This returns the memory range the user has access to. """
|
| 342 |
farthen |
187 |
resp = self.lib.monitorcommand(struct.pack("IIII", 1, 2, 0, 0), "III", ("lower", "upper", None))
|
| 401 |
farthen |
188 |
self.logger.debug("Device user memory = 0x%x - 0x%x\n" % (resp.lower, resp.upper))
|
| 342 |
farthen |
189 |
self.lib.dev.usermem.lower = resp.lower
|
|
|
190 |
self.lib.dev.usermem.upper = resp.upper
|
|
|
191 |
return resp
|
| 56 |
benedikt93 |
192 |
|
| 394 |
farthen |
193 |
@command()
|
| 171 |
farthen |
194 |
def reset(self, force=False):
|
|
|
195 |
""" Reboot the device """
|
|
|
196 |
if force:
|
|
|
197 |
return self.lib.monitorcommand(struct.pack("IIII", 2, 0, 0, 0))
|
|
|
198 |
else:
|
|
|
199 |
return self.lib.monitorcommand(struct.pack("IIII", 2, 1, 0, 0), "III", (None, None, None))
|
| 56 |
benedikt93 |
200 |
|
| 394 |
farthen |
201 |
@command()
|
| 171 |
farthen |
202 |
def poweroff(self, force=False):
|
|
|
203 |
""" Powers the device off. """
|
|
|
204 |
if force:
|
|
|
205 |
return self.lib.monitorcommand(struct.pack("IIII", 3, 0, 0, 0))
|
|
|
206 |
else:
|
|
|
207 |
return self.lib.monitorcommand(struct.pack("IIII", 3, 1, 0, 0), "III", (None, None, None))
|
| 56 |
benedikt93 |
208 |
|
| 394 |
farthen |
209 |
@command()
|
| 171 |
farthen |
210 |
def read(self, addr, size):
|
|
|
211 |
""" Reads the memory from location 'addr' with size 'size'
|
|
|
212 |
from the device. This cares about too long packages
|
|
|
213 |
and decides whether to use DMA or not.
|
|
|
214 |
"""
|
| 343 |
farthen |
215 |
cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
|
|
|
216 |
din_maxsize = self.lib.dev.packetsizelimit.din
|
| 171 |
farthen |
217 |
data = ""
|
|
|
218 |
(headsize, bodysize, tailsize) = self._alignsplit(addr, size, cin_maxsize, 16)
|
|
|
219 |
if headsize != 0:
|
| 178 |
farthen |
220 |
data += self._readmem(addr, headsize)
|
| 171 |
farthen |
221 |
addr += headsize
|
|
|
222 |
while bodysize > 0:
|
|
|
223 |
if bodysize >= 2 * cin_maxsize:
|
|
|
224 |
readsize = min(bodysize, din_maxsize)
|
| 178 |
farthen |
225 |
data += self._readdma(addr, readsize)
|
| 171 |
farthen |
226 |
else:
|
|
|
227 |
readsize = min(bodysize, cin_maxsize)
|
| 178 |
farthen |
228 |
data += self._readmem(addr, readsize)
|
| 171 |
farthen |
229 |
addr += readsize
|
|
|
230 |
bodysize -= readsize
|
|
|
231 |
if tailsize != 0:
|
| 178 |
farthen |
232 |
data += self._readmem(addr, tailsize)
|
| 171 |
farthen |
233 |
return data
|
| 56 |
benedikt93 |
234 |
|
| 394 |
farthen |
235 |
@command()
|
| 171 |
farthen |
236 |
def write(self, addr, data):
|
|
|
237 |
""" Writes the data in 'data' to the location 'addr'
|
|
|
238 |
in the memory of the device. This cares about too long packages
|
|
|
239 |
and decides whether to use DMA or not.
|
|
|
240 |
"""
|
| 343 |
farthen |
241 |
cout_maxsize = self.lib.dev.packetsizelimit.cout - self.lib.headersize
|
|
|
242 |
dout_maxsize = self.lib.dev.packetsizelimit.dout
|
| 171 |
farthen |
243 |
(headsize, bodysize, tailsize) = self._alignsplit(addr, len(data), cout_maxsize, 16)
|
|
|
244 |
offset = 0
|
|
|
245 |
if headsize != 0:
|
| 178 |
farthen |
246 |
self._writemem(addr, data[offset:offset+headsize])
|
| 171 |
farthen |
247 |
offset += headsize
|
|
|
248 |
addr += headsize
|
|
|
249 |
while bodysize > 0:
|
|
|
250 |
if bodysize >= 2 * cout_maxsize:
|
|
|
251 |
writesize = min(bodysize, dout_maxsize)
|
| 178 |
farthen |
252 |
self._writedma(addr, data[offset:offset+writesize])
|
| 171 |
farthen |
253 |
else:
|
|
|
254 |
writesize = min(bodysize, cout_maxsize)
|
| 178 |
farthen |
255 |
self._writemem(addr, data[offset:offset+writesize])
|
| 171 |
farthen |
256 |
offset += writesize
|
|
|
257 |
addr += writesize
|
|
|
258 |
bodysize -= writesize
|
|
|
259 |
if tailsize != 0:
|
| 178 |
farthen |
260 |
self._writemem(addr, data[offset:offset+tailsize])
|
| 171 |
farthen |
261 |
return data
|
| 56 |
benedikt93 |
262 |
|
| 394 |
farthen |
263 |
@command()
|
| 173 |
farthen |
264 |
def readstring(self, addr, maxlength = 256):
|
|
|
265 |
""" Reads a zero terminated string from memory
|
|
|
266 |
Reads only a maximum of 'maxlength' chars.
|
|
|
267 |
"""
|
| 343 |
farthen |
268 |
cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
|
| 173 |
farthen |
269 |
string = ""
|
|
|
270 |
while (len(string) < maxlength or maxlength < 0):
|
| 178 |
farthen |
271 |
data = self._readmem(addr, min(maxlength - len(string), cin_maxsize))
|
| 173 |
farthen |
272 |
length = data.find("\0")
|
|
|
273 |
if length >= 0:
|
|
|
274 |
string += data[:length]
|
|
|
275 |
break
|
|
|
276 |
else:
|
|
|
277 |
string += data
|
|
|
278 |
addr += cin_maxsize
|
|
|
279 |
return string
|
|
|
280 |
|
| 394 |
farthen |
281 |
@command()
|
| 171 |
farthen |
282 |
def i2cread(self, index, slaveaddr, startaddr, size):
|
|
|
283 |
""" Reads data from an i2c slave """
|
| 236 |
farthen |
284 |
data = ""
|
|
|
285 |
for i in range(size):
|
|
|
286 |
resp = self.lib.monitorcommand(struct.pack("IBBBBII", 8, index, slaveaddr, startaddr + i, 1, 0, 0), "III1s", (None, None, None, "data"))
|
|
|
287 |
data += resp.data
|
|
|
288 |
return data
|
| 56 |
benedikt93 |
289 |
|
| 394 |
farthen |
290 |
@command()
|
| 171 |
farthen |
291 |
def i2cwrite(self, index, slaveaddr, startaddr, data):
|
|
|
292 |
""" Writes data to an i2c slave """
|
| 176 |
farthen |
293 |
size = len(data)
|
|
|
294 |
if size > 256 or size < 1:
|
| 341 |
farthen |
295 |
raise ArgumentError("Size must be a number between 1 and 256")
|
| 176 |
farthen |
296 |
if size == 256:
|
|
|
297 |
size = 0
|
| 215 |
theseven |
298 |
return self.lib.monitorcommand(struct.pack("IBBBBII%ds" % size, 9, index, slaveaddr, startaddr, size, 0, 0, data), "III", (None, None, None))
|
| 56 |
benedikt93 |
299 |
|
| 394 |
farthen |
300 |
@command()
|
| 176 |
farthen |
301 |
def usbcread(self):
|
|
|
302 |
""" Reads one packet with the maximal cin size """
|
| 343 |
farthen |
303 |
cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
|
| 176 |
farthen |
304 |
resp = self.lib.monitorcommand(struct.pack("IIII", 10, cin_maxsize, 0, 0), "III%ds" % cin_maxsize, ("validsize", "buffersize", "queuesize", "data"))
|
|
|
305 |
resp.data = resp.data[:resp.validsize]
|
|
|
306 |
resp.maxsize = cin_maxsize
|
|
|
307 |
return resp
|
| 56 |
benedikt93 |
308 |
|
| 394 |
farthen |
309 |
@command()
|
| 171 |
farthen |
310 |
def usbcwrite(self, data):
|
|
|
311 |
""" Writes data to the USB console """
|
| 343 |
farthen |
312 |
cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
|
| 176 |
farthen |
313 |
size = len(data)
|
|
|
314 |
while len(data) > 0:
|
|
|
315 |
writesize = min(cin_maxsize, len(data))
|
|
|
316 |
resp = self.lib.monitorcommand(struct.pack("IIII%ds" % writesize, 11, writesize, 0, 0, data[:writesize]), "III", ("validsize", "buffersize", "freesize"))
|
|
|
317 |
data = data[resp.validsize:]
|
|
|
318 |
return size
|
| 56 |
benedikt93 |
319 |
|
| 394 |
farthen |
320 |
@command()
|
| 176 |
farthen |
321 |
def cread(self, bitmask=0x1):
|
|
|
322 |
""" Reads one packet with the maximal cin size from the device consoles
|
| 171 |
farthen |
323 |
identified with the specified bitmask
|
|
|
324 |
"""
|
| 343 |
farthen |
325 |
cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
|
| 217 |
theseven |
326 |
resp = self.lib.monitorcommand(struct.pack("IIII", 13, bitmask, cin_maxsize, 0), "III%ds" % cin_maxsize, ("size", None, None))
|
| 176 |
farthen |
327 |
resp.data = resp.data[size:]
|
|
|
328 |
resp.maxsize = cin_maxsize
|
|
|
329 |
return resp
|
| 394 |
farthen |
330 |
|
|
|
331 |
@command()
|
| 176 |
farthen |
332 |
def cwrite(self, data, bitmask=0x1):
|
| 171 |
farthen |
333 |
""" Writes data to the device consoles
|
|
|
334 |
identified with the specified bitmask.
|
|
|
335 |
"""
|
| 343 |
farthen |
336 |
cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
|
| 176 |
farthen |
337 |
size = len(data)
|
|
|
338 |
while len(data) > 0:
|
|
|
339 |
writesize = min(cin_maxsize, len(data))
|
| 217 |
theseven |
340 |
resp = self.lib.monitorcommand(struct.pack("IIII%ds" % writesize, 12, bitmask, writesize, 0, data[:writesize]), "III", (None, None, None))
|
| 176 |
farthen |
341 |
data = data[writesize:]
|
|
|
342 |
return size
|
| 56 |
benedikt93 |
343 |
|
| 394 |
farthen |
344 |
@command()
|
| 171 |
farthen |
345 |
def cflush(self, bitmask):
|
|
|
346 |
""" Flushes the consoles specified with 'bitmask' """
|
|
|
347 |
return self.lib.monitorcommand(struct.pack("IIII", 14, bitmask, 0, 0), "III", (None, None, None))
|
| 56 |
benedikt93 |
348 |
|
| 394 |
farthen |
349 |
@command()
|
| 173 |
farthen |
350 |
def getprocinfo(self):
|
| 171 |
farthen |
351 |
""" Gets current state of the scheduler """
|
| 343 |
farthen |
352 |
cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
|
| 173 |
farthen |
353 |
# Get the size
|
|
|
354 |
schedulerstate = self.lockscheduler()
|
|
|
355 |
resp = self.lib.monitorcommand(struct.pack("IIII", 15, 0, 0, 0), "III", ("structver", "tablesize", None))
|
|
|
356 |
tablesize = resp.tablesize
|
|
|
357 |
size = tablesize
|
|
|
358 |
structver = resp.structver
|
|
|
359 |
offset = 0
|
|
|
360 |
data = ""
|
|
|
361 |
while size > 0:
|
|
|
362 |
if size > cin_maxsize:
|
|
|
363 |
readsize = cin_maxsize
|
|
|
364 |
else:
|
|
|
365 |
readsize = size
|
|
|
366 |
resp = self.lib.monitorcommand(struct.pack("IIII", 15, offset, readsize, 0), "III%ds" % readsize, ("structver", "tablesize", None, "data"))
|
|
|
367 |
data += resp.data
|
|
|
368 |
offset += readsize
|
|
|
369 |
size -= readsize
|
|
|
370 |
self.lockscheduler(schedulerstate)
|
|
|
371 |
threadstructsize = 120
|
|
|
372 |
registersize = 32
|
|
|
373 |
if len(data) % threadstructsize != 0:
|
|
|
374 |
raise DeviceError("The thread struct is not a multiple of "+str(threadsturcsize)+"!")
|
|
|
375 |
threadcount = len(data) / threadstructsize
|
|
|
376 |
threads = []
|
|
|
377 |
id = 0
|
|
|
378 |
for thread in range(threadcount):
|
|
|
379 |
offset = threadstructsize * thread
|
|
|
380 |
threaddata = struct.unpack("<16IIIIIQIIIIIIIBBBB", data[offset:offset+threadstructsize])
|
|
|
381 |
info = Bunch()
|
|
|
382 |
info.id = id
|
|
|
383 |
state = threaddata[17]
|
| 427 |
farthen |
384 |
info.state = libemcoredata.thread_state[state]
|
| 173 |
farthen |
385 |
if info.state == "THREAD_FREE":
|
|
|
386 |
id += 1
|
|
|
387 |
continue
|
|
|
388 |
info.regs = Bunch()
|
|
|
389 |
for register in range(16):
|
|
|
390 |
info.regs["r"+str(register)] = threaddata[register]
|
|
|
391 |
info.regs.cpsr = threaddata[16]
|
|
|
392 |
info.nameptr = threaddata[18]
|
|
|
393 |
if info.nameptr == 0:
|
|
|
394 |
info.name = "Thread %d" % info.id
|
|
|
395 |
else:
|
|
|
396 |
info.name = self.readstring(info.nameptr)
|
|
|
397 |
info.cputime_current = threaddata[19]
|
|
|
398 |
info.cputime_total = threaddata[20]
|
|
|
399 |
info.startusec = threaddata[21]
|
|
|
400 |
info.queue_next_ptr = threaddata[22]
|
|
|
401 |
info.timeout = threaddata[23]
|
|
|
402 |
info.blocked_since = threaddata[24]
|
|
|
403 |
info.blocked_by_ptr = threaddata[25]
|
|
|
404 |
info.stackaddr = threaddata[26]
|
|
|
405 |
info.err_no = threaddata[27]
|
| 427 |
farthen |
406 |
info.block_type = libemcoredata.thread_block[threaddata[28]]
|
|
|
407 |
info.type = libemcoredata.thread_type[threaddata[29]]
|
| 173 |
farthen |
408 |
info.priority = threaddata[30]
|
|
|
409 |
info.cpuload = threaddata[31]
|
|
|
410 |
threads.append(info)
|
|
|
411 |
id += 1
|
|
|
412 |
return threads
|
| 56 |
benedikt93 |
413 |
|
| 394 |
farthen |
414 |
@command()
|
| 173 |
farthen |
415 |
def lockscheduler(self, freeze=True):
|
| 171 |
farthen |
416 |
""" Freezes/Unfreezes the scheduler """
|
| 173 |
farthen |
417 |
resp = self.lib.monitorcommand(struct.pack("IIII", 16, 1 if freeze else 0, 0, 0), "III", ("before", None, None))
|
|
|
418 |
return True if resp.before == 1 else False
|
| 67 |
benedikt93 |
419 |
|
| 394 |
farthen |
420 |
@command()
|
| 173 |
farthen |
421 |
def unlockscheduler(self):
|
| 171 |
farthen |
422 |
""" Unfreezes the scheduler """
|
|
|
423 |
return self.lib.monitorcommand(struct.pack("IIII", 16, 0, 0, 0), "III", ("before", None, None))
|
| 56 |
benedikt93 |
424 |
|
| 394 |
farthen |
425 |
@command()
|
| 171 |
farthen |
426 |
def suspendthread(self, id, suspend=True):
|
|
|
427 |
""" Suspends the thread with the specified id """
|
| 173 |
farthen |
428 |
resp = self.lib.monitorcommand(struct.pack("IIII", 17, 1 if suspend else 0, id, 0), "III", ("before", None, None))
|
|
|
429 |
return True if resp.before == 1 else False
|
| 56 |
benedikt93 |
430 |
|
| 394 |
farthen |
431 |
@command()
|
| 173 |
farthen |
432 |
def resumethread(self, id):
|
|
|
433 |
""" Resumes the thread with the specified id """
|
| 171 |
farthen |
434 |
return self.lib.monitorcommand(struct.pack("IIII", 17, 0, id, 0), "III", ("before", None, None))
|
| 56 |
benedikt93 |
435 |
|
| 394 |
farthen |
436 |
@command()
|
| 171 |
farthen |
437 |
def killthread(self, id):
|
|
|
438 |
""" Kills the thread with the specified id """
|
|
|
439 |
return self.lib.monitorcommand(struct.pack("IIII", 18, id, 0, 0), "III", ("before", None, None))
|
| 56 |
benedikt93 |
440 |
|
| 394 |
farthen |
441 |
@command()
|
| 171 |
farthen |
442 |
def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
|
|
|
443 |
""" Creates a thread with the specified attributes """
|
|
|
444 |
if threadtype == "user":
|
|
|
445 |
threadtype = 0
|
|
|
446 |
elif threadtype == "system":
|
|
|
447 |
threadtype = 1
|
|
|
448 |
else:
|
| 341 |
farthen |
449 |
raise ArgumentError("Threadtype must be either 'system' or 'user'")
|
| 171 |
farthen |
450 |
if priority > 256 or priority < 0:
|
| 341 |
farthen |
451 |
raise ArgumentError("Priority must be a number between 0 and 256")
|
| 171 |
farthen |
452 |
if state == "ready":
|
|
|
453 |
state = 0
|
|
|
454 |
elif state == "suspended":
|
|
|
455 |
state = 1
|
|
|
456 |
else:
|
| 341 |
farthen |
457 |
raise ArgumentError("State must be either 'ready' or 'suspended'")
|
| 171 |
farthen |
458 |
resp = self.lib.monitorcommand(struct.pack("IIIIIIII", 19, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state), "III", (id, None, None))
|
|
|
459 |
if resp.id < 0:
|
|
|
460 |
raise DeviceError("The device returned the error code "+str(resp.id))
|
|
|
461 |
return resp
|
| 56 |
benedikt93 |
462 |
|
| 394 |
farthen |
463 |
@command()
|
| 172 |
farthen |
464 |
def flushcaches(self):
|
| 171 |
farthen |
465 |
""" Flushes the CPU instruction and data cache """
|
|
|
466 |
return self.lib.monitorcommand(struct.pack("IIII", 20, 0, 0, 0), "III", (None, None, None))
|
| 56 |
benedikt93 |
467 |
|
| 394 |
farthen |
468 |
@command()
|
| 172 |
farthen |
469 |
def execimage(self, addr):
|
| 427 |
farthen |
470 |
""" Runs the emCORE app at 'addr' """
|
| 346 |
theseven |
471 |
return self.lib.monitorcommand(struct.pack("IIII", 21, addr, 0, 0), "III", ("rc", None, None))
|
| 56 |
benedikt93 |
472 |
|
| 394 |
farthen |
473 |
@command()
|
| 238 |
farthen |
474 |
def run(self, app):
|
| 427 |
farthen |
475 |
""" Uploads and runs the emCORE app in the string 'app' """
|
| 238 |
farthen |
476 |
try:
|
|
|
477 |
appheader = struct.unpack("<8sIIIIIIIIII", app[:48])
|
|
|
478 |
except struct.error:
|
| 427 |
farthen |
479 |
raise ArgumentError("The specified app is not an emCORE application")
|
| 238 |
farthen |
480 |
header = appheader[0]
|
|
|
481 |
if header != "emBIexec":
|
| 427 |
farthen |
482 |
raise ArgumentError("The specified app is not an emCORE application")
|
| 238 |
farthen |
483 |
baseaddr = appheader[2]
|
|
|
484 |
threadnameptr = appheader[8]
|
|
|
485 |
nameptr = threadnameptr - baseaddr
|
|
|
486 |
name = ""
|
|
|
487 |
while True:
|
|
|
488 |
char = app[nameptr:nameptr+1]
|
|
|
489 |
try:
|
|
|
490 |
if ord(char) == 0:
|
|
|
491 |
break
|
|
|
492 |
except TypeError:
|
| 427 |
farthen |
493 |
raise ArgumentError("The specified app is not an emCORE application")
|
| 238 |
farthen |
494 |
name += char
|
|
|
495 |
nameptr += 1
|
|
|
496 |
usermem = self.getusermemrange()
|
|
|
497 |
if usermem.lower > baseaddr or usermem.upper < baseaddr + len(app):
|
| 427 |
farthen |
498 |
raise ArgumentError("The baseaddress of the specified emCORE application is out of range of the user memory range on the device. Are you sure that this application is compatible with your device?")
|
| 238 |
farthen |
499 |
self.write(baseaddr, app)
|
|
|
500 |
self.execimage(baseaddr)
|
|
|
501 |
return Bunch(baseaddr=baseaddr, name=name)
|
|
|
502 |
|
| 395 |
farthen |
503 |
@command(timeout = 5000)
|
| 171 |
farthen |
504 |
def bootflashread(self, memaddr, flashaddr, size):
|
|
|
505 |
""" Copies the data in the bootflash at 'flashaddr' of the specified size
|
|
|
506 |
to the memory at addr 'memaddr'
|
|
|
507 |
"""
|
| 174 |
farthen |
508 |
return self.lib.monitorcommand(struct.pack("IIII", 22, memaddr, flashaddr, size), "III", (None, None, None))
|
| 82 |
benedikt93 |
509 |
|
| 395 |
farthen |
510 |
@command(timeout = 30000)
|
| 171 |
farthen |
511 |
def bootflashwrite(self, memaddr, flashaddr, size):
|
|
|
512 |
""" Copies the data in the memory at 'memaddr' of the specified size
|
|
|
513 |
to the boot flash at addr 'flashaddr'
|
|
|
514 |
"""
|
| 174 |
farthen |
515 |
return self.lib.monitorcommand(struct.pack("IIII", 23, memaddr, flashaddr, size), "III", (None, None, None))
|
| 56 |
benedikt93 |
516 |
|
| 394 |
farthen |
517 |
@command()
|
| 171 |
farthen |
518 |
def execfirmware(self, addr):
|
|
|
519 |
""" Executes the firmware at 'addr' and passes all control to it. """
|
| 269 |
farthen |
520 |
return self.lib.monitorcommand(struct.pack("IIII", 24, addr, 0, 0))
|
| 56 |
benedikt93 |
521 |
|
| 395 |
farthen |
522 |
@command(timeout = 30000)
|
| 171 |
farthen |
523 |
def aesencrypt(self, addr, size, keyindex):
|
|
|
524 |
""" Encrypts the buffer at 'addr' with the specified size
|
|
|
525 |
with the hardware AES key index 'keyindex'
|
|
|
526 |
"""
|
|
|
527 |
return self.lib.monitorcommand(struct.pack("IBBHII", 25, 1, 0, keyindex, addr, size), "III", (None, None, None))
|
| 82 |
benedikt93 |
528 |
|
| 395 |
farthen |
529 |
@command(timeout = 30000)
|
| 171 |
farthen |
530 |
def aesdecrypt(self, addr, size, keyindex):
|
|
|
531 |
""" Decrypts the buffer at 'addr' with the specified size
|
|
|
532 |
with the hardware AES key index 'keyindex'
|
|
|
533 |
"""
|
|
|
534 |
return self.lib.monitorcommand(struct.pack("IBBHII", 25, 0, 0, keyindex, addr, size), "III", (None, None, None))
|
| 82 |
benedikt93 |
535 |
|
| 395 |
farthen |
536 |
@command(timeout = 30000)
|
| 171 |
farthen |
537 |
def hmac_sha1(self, addr, size, destination):
|
|
|
538 |
""" Generates a HMAC-SHA1 hash of the buffer and saves it to 'destination' """
|
|
|
539 |
return self.lib.monitorcommand(struct.pack("IIII", 26, addr, size, destination), "III", (None, None, None))
|
| 56 |
benedikt93 |
540 |
|
| 398 |
farthen |
541 |
@command(target = 0x47324e49)
|
| 227 |
theseven |
542 |
def ipodnano2g_getnandinfo(self):
|
|
|
543 |
""" Target-specific function: ipodnano2g
|
|
|
544 |
Gathers some information about the NAND chip used
|
|
|
545 |
"""
|
|
|
546 |
return self.lib.monitorcommand(struct.pack("IIII", 0xffff0001, 0, 0, 0), "IHHHH", ("type", "pagesperblock", "banks", "userblocks", "blocks"))
|
|
|
547 |
|
| 398 |
farthen |
548 |
@command(timeout = 30000, target = 0x47324e49)
|
| 227 |
theseven |
549 |
def ipodnano2g_nandread(self, addr, start, count, doecc, checkempty):
|
|
|
550 |
""" Target-specific function: ipodnano2g
|
|
|
551 |
Reads data from the NAND chip into memory
|
|
|
552 |
"""
|
| 404 |
farthen |
553 |
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 |
554 |
|
| 398 |
farthen |
555 |
@command(timeout = 30000, target = 0x47324e49)
|
| 227 |
theseven |
556 |
def ipodnano2g_nandwrite(self, addr, start, count, doecc):
|
|
|
557 |
""" Target-specific function: ipodnano2g
|
|
|
558 |
Writes data to the NAND chip
|
|
|
559 |
"""
|
| 404 |
farthen |
560 |
return self.lib.monitorcommand(struct.pack("IIII", 0xffff0003, addr | (0x80000000 if doecc else 0), start, count), "III", (None, None, None))
|
| 227 |
theseven |
561 |
|
| 398 |
farthen |
562 |
@command(timeout = 30000, target = 0x47324e49)
|
| 227 |
theseven |
563 |
def ipodnano2g_nanderase(self, addr, start, count):
|
|
|
564 |
""" Target-specific function: ipodnano2g
|
|
|
565 |
Erases blocks on the NAND chip and stores the results to memory
|
|
|
566 |
"""
|
|
|
567 |
return self.lib.monitorcommand(struct.pack("IIII", 0xffff0004, addr, start, count), "III", (None, None, None))
|
|
|
568 |
|
| 398 |
farthen |
569 |
@command(target = 0x4c435049)
|
| 346 |
theseven |
570 |
def ipodclassic_gethddinfo(self):
|
|
|
571 |
""" Target-specific function: ipodclassic
|
|
|
572 |
Gather information about the hard disk drive
|
|
|
573 |
"""
|
|
|
574 |
return self.lib.monitorcommand(struct.pack("IIII", 0xffff0001, 0, 0, 0), "IQQII", ("identifyptr", "totalsectors", "virtualsectors", "bbtptr", "bbtsize"))
|
|
|
575 |
|
| 398 |
farthen |
576 |
@command(timeout = 30000, target = 0x4c435049)
|
| 346 |
theseven |
577 |
def ipodclassic_hddaccess(self, type, sector, count, addr):
|
|
|
578 |
""" Target-specific function: ipodclassic
|
|
|
579 |
Access the hard disk, type = 0 (read) / 1 (write)
|
|
|
580 |
"""
|
|
|
581 |
rc = self.lib.monitorcommand(struct.pack("IIQIIII", 0xffff0002, type, sector, count, addr, 0, 0), "III", ("rc", None, None))
|
|
|
582 |
if (rc > 0x80000000):
|
|
|
583 |
raise DeviceError("HDD access (type=%d, sector=%d, count=%d, addr=0x%08X) failed with RC 0x%08X" % (type, sector, count, addr, rc))
|
|
|
584 |
|
| 398 |
farthen |
585 |
@command(target = 0x4c435049)
|
| 346 |
theseven |
586 |
def ipodclassic_writebbt(self, bbt, tempaddr):
|
|
|
587 |
""" Target-specific function: ipodclassic
|
|
|
588 |
Write hard drive bad block table
|
|
|
589 |
"""
|
|
|
590 |
try:
|
|
|
591 |
bbtheader = struct.unpack("<8s2024sQII512I", bbt[:4096])
|
|
|
592 |
except struct.error:
|
| 427 |
farthen |
593 |
raise ArgumentError("The specified file is not an emCORE hard disk BBT")
|
| 346 |
theseven |
594 |
if bbtheader[0] != "emBIbbth":
|
| 427 |
farthen |
595 |
raise ArgumentError("The specified file is not an emCORE hard disk BBT")
|
| 346 |
theseven |
596 |
virtualsectors = bbtheader[2]
|
|
|
597 |
bbtsectors = bbtheader[3]
|
|
|
598 |
self.write(tempaddr, bbt)
|
|
|
599 |
sector = 0
|
|
|
600 |
count = 1
|
|
|
601 |
offset = 0
|
|
|
602 |
for i in range(bbtsectors):
|
|
|
603 |
if bbtheader[4][i] == sector + count:
|
|
|
604 |
count = count + 1
|
|
|
605 |
else:
|
|
|
606 |
self.ipodclassic_hddaccess(1, sector, count, tempaddr + offset)
|
|
|
607 |
offset = offset + count * 4096
|
|
|
608 |
sector = bbtheader[4][i]
|
|
|
609 |
count = 1
|
|
|
610 |
self.ipodclassic_hddaccess(1, sector, count, tempaddr + offset)
|
|
|
611 |
|
| 394 |
farthen |
612 |
@command()
|
| 379 |
theseven |
613 |
def storage_get_info(self, volume):
|
| 346 |
theseven |
614 |
""" Get information about a storage device """
|
| 379 |
theseven |
615 |
result = self.lib.monitorcommand(struct.pack("IIII", 27, volume, 0, 0), "IIIIIIII", ("version", None, None, "sectorsize", "numsectors", "vendorptr", "productptr", "revisionptr"))
|
| 346 |
theseven |
616 |
if result.version != 1:
|
|
|
617 |
raise ValueError("Unknown version of storage_info struct: %d" % result.version)
|
| 379 |
theseven |
618 |
result.vendor = self.readstring(result.vendorptr)
|
|
|
619 |
result.product = self.readstring(result.productptr)
|
|
|
620 |
result.revision = self.readstring(result.revisionptr)
|
| 346 |
theseven |
621 |
return result
|
|
|
622 |
|
| 395 |
farthen |
623 |
@command(timeout = 50000)
|
| 346 |
theseven |
624 |
def storage_read_sectors_md(self, volume, sector, count, addr):
|
|
|
625 |
""" Read sectors from as storage device """
|
| 399 |
farthen |
626 |
result = self.lib.monitorcommand(struct.pack("IIQIIII", 28, volume, sector, count, addr, 0, 0), "III", ("rc", None, None))
|
| 346 |
theseven |
627 |
if result.rc > 0x80000000:
|
|
|
628 |
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))
|
| 394 |
farthen |
629 |
|
| 395 |
farthen |
630 |
@command(timeout = 50000)
|
| 346 |
theseven |
631 |
def storage_write_sectors_md(self, volume, sector, count, addr):
|
|
|
632 |
""" Read sectors from as storage device """
|
| 399 |
farthen |
633 |
result = self.lib.monitorcommand(struct.pack("IIQIIII", 29, volume, sector, count, addr, 0, 0), "III", ("rc", None, None))
|
| 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))
|
| 394 |
farthen |
636 |
|
| 395 |
farthen |
637 |
@command(timeout = 30000)
|
| 346 |
theseven |
638 |
def file_open(self, filename, mode):
|
|
|
639 |
""" Opens a file and returns the handle """
|
|
|
640 |
result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(filename), 30, mode, 0, 0, filename, 0), "III", ("fd", None, None))
|
|
|
641 |
if result.fd > 0x80000000:
|
|
|
642 |
raise DeviceError("file_open(filename=\"%s\", mode=0x%X) failed with RC=0x%08X, errno=%d" % (filename, mode, result.fd, self.errno()))
|
|
|
643 |
return result.fd
|
|
|
644 |
|
| 395 |
farthen |
645 |
@command(timeout = 30000)
|
| 346 |
theseven |
646 |
def file_size(self, fd):
|
|
|
647 |
""" Gets the size of a file referenced by a handle """
|
|
|
648 |
result = self.lib.monitorcommand(struct.pack("IIII", 31, fd, 0, 0), "III", ("size", None, None))
|
|
|
649 |
if result.size > 0x80000000:
|
|
|
650 |
raise DeviceError("file_size(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.size, self.errno()))
|
|
|
651 |
return result.size
|
| 394 |
farthen |
652 |
|
| 395 |
farthen |
653 |
@command(timeout = 30000)
|
| 346 |
theseven |
654 |
def file_read(self, fd, addr, size):
|
|
|
655 |
""" Reads data from a file referenced by a handle """
|
|
|
656 |
result = self.lib.monitorcommand(struct.pack("IIII", 32, fd, addr, size), "III", ("rc", None, None))
|
|
|
657 |
if result.rc > 0x80000000:
|
|
|
658 |
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()))
|
|
|
659 |
return result.rc
|
| 394 |
farthen |
660 |
|
| 395 |
farthen |
661 |
@command(timeout = 30000)
|
| 346 |
theseven |
662 |
def file_write(self, fd, addr, size):
|
|
|
663 |
""" Writes data from a file referenced by a handle """
|
|
|
664 |
result = self.lib.monitorcommand(struct.pack("IIII", 33, fd, addr, size), "III", ("rc", None, None))
|
|
|
665 |
if result.rc > 0x80000000:
|
|
|
666 |
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()))
|
|
|
667 |
return result.rc
|
|
|
668 |
|
| 395 |
farthen |
669 |
@command(timeout = 30000)
|
| 346 |
theseven |
670 |
def file_seek(self, fd, offset, whence):
|
|
|
671 |
""" Seeks the file handle to the specified position in the file """
|
|
|
672 |
result = self.lib.monitorcommand(struct.pack("IIII", 34, fd, offset, whence), "III", ("rc", None, None))
|
|
|
673 |
if result.rc > 0x80000000:
|
|
|
674 |
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()))
|
|
|
675 |
return result.rc
|
|
|
676 |
|
| 395 |
farthen |
677 |
@command(timeout = 30000)
|
| 346 |
theseven |
678 |
def file_truncate(self, fd, length):
|
|
|
679 |
""" Truncates a file referenced by a handle to a specified length """
|
|
|
680 |
result = self.lib.monitorcommand(struct.pack("IIII", 35, fd, offset, 0), "III", ("rc", None, None))
|
|
|
681 |
if result.rc > 0x80000000:
|
|
|
682 |
raise DeviceError("file_truncate(fd=%d, length=0x%08X) failed with RC=0x%08X, errno=%d" % (fd, length, result.rc, self.errno()))
|
|
|
683 |
return result.rc
|
|
|
684 |
|
| 395 |
farthen |
685 |
@command(timeout = 30000)
|
| 346 |
theseven |
686 |
def file_sync(self, fd):
|
|
|
687 |
""" Flushes a file handles' buffers """
|
|
|
688 |
result = self.lib.monitorcommand(struct.pack("IIII", 36, fd, 0, 0), "III", ("rc", None, None))
|
|
|
689 |
if result.rc > 0x80000000:
|
|
|
690 |
raise DeviceError("file_sync(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.rc, self.errno()))
|
|
|
691 |
return result.rc
|
|
|
692 |
|
| 395 |
farthen |
693 |
@command(timeout = 30000)
|
| 346 |
theseven |
694 |
def file_close(self, fd):
|
|
|
695 |
""" Closes a file handle """
|
|
|
696 |
result = self.lib.monitorcommand(struct.pack("IIII", 37, fd, 0, 0), "III", ("rc", None, None))
|
|
|
697 |
if result.rc > 0x80000000:
|
|
|
698 |
raise DeviceError("file_close(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.rc, self.errno()))
|
|
|
699 |
return result.rc
|
|
|
700 |
|
| 395 |
farthen |
701 |
@command(timeout = 30000)
|
| 346 |
theseven |
702 |
def file_close_all(self):
|
|
|
703 |
""" Closes all file handles opened through the debugger """
|
|
|
704 |
result = self.lib.monitorcommand(struct.pack("IIII", 38, 0, 0, 0), "III", ("rc", None, None))
|
|
|
705 |
if result.rc > 0x80000000:
|
|
|
706 |
raise DeviceError("file_close_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
|
|
|
707 |
return result.rc
|
|
|
708 |
|
| 395 |
farthen |
709 |
@command(timeout = 30000)
|
| 346 |
theseven |
710 |
def file_kill_all(self):
|
|
|
711 |
""" Kills all file handles (in the whole system) """
|
|
|
712 |
result = self.lib.monitorcommand(struct.pack("IIII", 39, 0, 0, 0), "III", ("rc", None, None))
|
|
|
713 |
if result.rc > 0x80000000:
|
|
|
714 |
raise DeviceError("file_kill_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
|
|
|
715 |
return result.rc
|
|
|
716 |
|
| 395 |
farthen |
717 |
@command(timeout = 30000)
|
| 346 |
theseven |
718 |
def file_unlink(self, filename):
|
|
|
719 |
""" Removes a file """
|
|
|
720 |
result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(filename), 40, 0, 0, 0, filename, 0), "III", ("rc", None, None))
|
|
|
721 |
if result.rc > 0x80000000:
|
|
|
722 |
raise DeviceError("file_unlink(filename=\"%s\") failed with RC=0x%08X, errno=%d" % (filename, result.rc, self.errno()))
|
|
|
723 |
return result.rc
|
|
|
724 |
|
| 395 |
farthen |
725 |
@command(timeout = 30000)
|
| 346 |
theseven |
726 |
def file_rename(self, oldname, newname):
|
|
|
727 |
""" Renames a file """
|
|
|
728 |
result = self.lib.monitorcommand(struct.pack("IIII248s%dsB" % min(247, len(newname)), 41, 0, 0, 0, oldname, newname, 0), "III", ("rc", None, None))
|
|
|
729 |
if result.rc > 0x80000000:
|
|
|
730 |
raise DeviceError("file_rename(oldname=\"%s\", newname=\"%s\") failed with RC=0x%08X, errno=%d" % (oldname, newname, result.rc, self.errno()))
|
|
|
731 |
return result.rc
|
|
|
732 |
|
| 395 |
farthen |
733 |
@command(timeout = 30000)
|
| 346 |
theseven |
734 |
def dir_open(self, dirname):
|
|
|
735 |
""" Opens a directory and returns the handle """
|
|
|
736 |
result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 42, 0, 0, 0, dirname, 0), "III", ("handle", None, None))
|
|
|
737 |
if result.handle == 0:
|
|
|
738 |
raise DeviceError("dir_open(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.handle, self.errno()))
|
|
|
739 |
return result.handle
|
|
|
740 |
|
| 395 |
farthen |
741 |
@command(timeout = 30000)
|
| 346 |
theseven |
742 |
def dir_read(self, handle):
|
|
|
743 |
""" Reads the next entry from a directory """
|
|
|
744 |
result = self.lib.monitorcommand(struct.pack("IIII", 43, handle, 0, 0), "III", ("version", "maxpath", "ptr"))
|
|
|
745 |
if result.ptr == 0:
|
|
|
746 |
raise DeviceError("dir_read(handle=0x%08X) failed with RC=0x%08X, errno=%d" % (handle, result.ptr, self.errno()))
|
|
|
747 |
if result.version != 1:
|
|
|
748 |
raise ValueError("Unknown version of dirent struct: %d" % result.version)
|
|
|
749 |
dirent = self.read(result.ptr, result.maxpath + 16)
|
|
|
750 |
ret = Bunch()
|
|
|
751 |
(ret.name, ret.attributes, ret.size, ret.startcluster, ret.wrtdate, ret.wrttime) = struct.unpack("%dsIIIHH" % result.maxpath, dirent)
|
|
|
752 |
ret.name = ret.name[:ret.name.index('\x00')]
|
|
|
753 |
return ret
|
|
|
754 |
|
| 395 |
farthen |
755 |
@command(timeout = 30000)
|
| 346 |
theseven |
756 |
def dir_close(self, handle):
|
|
|
757 |
""" Closes a directory handle """
|
|
|
758 |
result = self.lib.monitorcommand(struct.pack("IIII", 44, handle, 0, 0), "III", ("rc", None, None))
|
|
|
759 |
if result.rc > 0x80000000:
|
|
|
760 |
raise DeviceError("dir_close(handle=0x%08X) failed with RC=0x%08X, errno=%d" % (handle, result.rc, self.errno()))
|
|
|
761 |
return result.rc
|
|
|
762 |
|
| 395 |
farthen |
763 |
@command(timeout = 30000)
|
| 346 |
theseven |
764 |
def dir_close_all(self):
|
|
|
765 |
""" Closes all directory handles opened through the debugger """
|
|
|
766 |
result = self.lib.monitorcommand(struct.pack("IIII", 45, 0, 0, 0), "III", ("rc", None, None))
|
|
|
767 |
if result.rc > 0x80000000:
|
|
|
768 |
raise DeviceError("dir_close_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
|
|
|
769 |
return result.rc
|
|
|
770 |
|
| 395 |
farthen |
771 |
@command(timeout = 30000)
|
| 346 |
theseven |
772 |
def dir_kill_all(self):
|
|
|
773 |
""" Kills all directory handles (in the whole system) """
|
|
|
774 |
result = self.lib.monitorcommand(struct.pack("IIII", 46, 0, 0, 0), "III", ("rc", None, None))
|
|
|
775 |
if result.rc > 0x80000000:
|
|
|
776 |
raise DeviceError("dir_kill_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
|
|
|
777 |
return result.rc
|
|
|
778 |
|
| 395 |
farthen |
779 |
@command(timeout = 30000)
|
| 346 |
theseven |
780 |
def dir_create(self, dirname):
|
|
|
781 |
""" Creates a directory """
|
|
|
782 |
result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 47, 0, 0, 0, dirname, 0), "III", ("rc", None, None))
|
|
|
783 |
if result.rc > 0x80000000:
|
|
|
784 |
raise DeviceError("dir_create(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.rc, self.errno()))
|
|
|
785 |
return result.rc
|
|
|
786 |
|
| 395 |
farthen |
787 |
@command(timeout = 30000)
|
| 346 |
theseven |
788 |
def dir_remove(self, dirname):
|
|
|
789 |
""" Removes an (empty) directory """
|
|
|
790 |
result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 48, 0, 0, 0, dirname, 0), "III", ("rc", None, None))
|
|
|
791 |
if result.rc > 0x80000000:
|
|
|
792 |
raise DeviceError("dir_remove(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.rc, self.errno()))
|
|
|
793 |
return result.rc
|
|
|
794 |
|
| 394 |
farthen |
795 |
@command()
|
| 346 |
theseven |
796 |
def errno(self):
|
|
|
797 |
""" Returns the number of the last error that happened """
|
|
|
798 |
result = self.lib.monitorcommand(struct.pack("IIII", 49, 0, 0, 0), "III", ("errno", None, None))
|
|
|
799 |
return result.errno
|
|
|
800 |
|
| 394 |
farthen |
801 |
@command()
|
| 346 |
theseven |
802 |
def disk_mount(self, volume):
|
|
|
803 |
""" Mounts a volume """
|
|
|
804 |
result = self.lib.monitorcommand(struct.pack("IIII", 50, volume, 0, 0), "III", ("rc", None, None))
|
|
|
805 |
if result.rc > 0x80000000:
|
|
|
806 |
raise DeviceError("disk_mount(volume=%d) failed with RC=0x%08X, errno=%d" % (volume, result.rc, self.errno()))
|
|
|
807 |
return result.rc
|
|
|
808 |
|
| 394 |
farthen |
809 |
@command()
|
| 346 |
theseven |
810 |
def disk_unmount(self, volume):
|
|
|
811 |
""" Unmounts a volume """
|
|
|
812 |
result = self.lib.monitorcommand(struct.pack("IIII", 51, volume, 0, 0), "III", ("rc", None, None))
|
|
|
813 |
if result.rc > 0x80000000:
|
|
|
814 |
raise DeviceError("disk_unmount(volume=%d) failed with RC=0x%08X, errno=%d" % (volume, result.rc, self.errno()))
|
|
|
815 |
return result.rc
|
|
|
816 |
|
|
|
817 |
|
| 171 |
farthen |
818 |
class Lib(object):
|
| 401 |
farthen |
819 |
def __init__(self, logger):
|
|
|
820 |
self.logger = logger
|
|
|
821 |
self.logger.debug("Initializing Lib object\n")
|
| 171 |
farthen |
822 |
self.idVendor = 0xFFFF
|
|
|
823 |
self.idProduct = 0xE000
|
| 176 |
farthen |
824 |
|
|
|
825 |
self.headersize = 0x10
|
|
|
826 |
|
|
|
827 |
self.connect()
|
| 56 |
benedikt93 |
828 |
|
| 171 |
farthen |
829 |
def connect(self):
|
| 401 |
farthen |
830 |
self.dev = Dev(self.idVendor, self.idProduct, self.logger)
|
| 171 |
farthen |
831 |
self.connected = True
|
| 56 |
benedikt93 |
832 |
|
| 171 |
farthen |
833 |
def monitorcommand(self, cmd, rcvdatatypes=None, rcvstruct=None):
|
| 401 |
farthen |
834 |
self.logger.debug("Sending monitorcommand\n")
|
| 269 |
farthen |
835 |
writelen = self.dev.cout(cmd)
|
| 171 |
farthen |
836 |
if rcvdatatypes:
|
|
|
837 |
rcvdatatypes = "I" + rcvdatatypes # add the response
|
|
|
838 |
data = self.dev.cin(struct.calcsize(rcvdatatypes))
|
|
|
839 |
data = struct.unpack(rcvdatatypes, data)
|
|
|
840 |
response = data[0]
|
| 427 |
farthen |
841 |
if libemcoredata.responsecodes[response] == "ok":
|
| 401 |
farthen |
842 |
self.logger.debug("Response: OK\n")
|
| 171 |
farthen |
843 |
if rcvstruct:
|
|
|
844 |
datadict = Bunch()
|
|
|
845 |
counter = 1 # start with 1, 0 is the id
|
|
|
846 |
for item in rcvstruct:
|
|
|
847 |
if item != None: # else the data is undefined
|
|
|
848 |
datadict[item] = data[counter]
|
|
|
849 |
counter += 1
|
|
|
850 |
return datadict
|
|
|
851 |
else:
|
|
|
852 |
return data
|
| 427 |
farthen |
853 |
elif libemcoredata.responsecodes[response] == "unsupported":
|
| 401 |
farthen |
854 |
self.logger.debug("Response: UNSUPPORTED\n")
|
| 171 |
farthen |
855 |
raise DeviceError("The device does not support this command.")
|
| 427 |
farthen |
856 |
elif libemcoredata.responsecodes[response] == "invalid":
|
| 401 |
farthen |
857 |
self.logger.debug("Response: INVALID\n")
|
| 171 |
farthen |
858 |
raise DeviceError("Invalid command! This should NOT happen!")
|
| 427 |
farthen |
859 |
elif libemcoredata.responsecodes[response] == "busy":
|
| 401 |
farthen |
860 |
self.logger.debug("Response: BUSY\n")
|
| 171 |
farthen |
861 |
raise DeviceError("Device busy")
|
| 401 |
farthen |
862 |
else:
|
|
|
863 |
self.logger.debug("Response: UNKOWN\n")
|
|
|
864 |
raise DeviceError("Invalid response! This should NOT happen!")
|
| 269 |
farthen |
865 |
else:
|
|
|
866 |
return writelen
|
| 56 |
benedikt93 |
867 |
|
|
|
868 |
|
| 171 |
farthen |
869 |
class Dev(object):
|
| 401 |
farthen |
870 |
def __init__(self, idVendor, idProduct, logger):
|
| 171 |
farthen |
871 |
self.idVendor = idVendor
|
|
|
872 |
self.idProduct = idProduct
|
| 67 |
benedikt93 |
873 |
|
| 401 |
farthen |
874 |
self.logger = logger
|
|
|
875 |
self.logger.debug("Initializing Dev object\n")
|
|
|
876 |
|
| 171 |
farthen |
877 |
self.interface = 0
|
|
|
878 |
self.timeout = 100
|
| 176 |
farthen |
879 |
|
| 171 |
farthen |
880 |
self.connect()
|
|
|
881 |
self.findEndpoints()
|
|
|
882 |
|
| 401 |
farthen |
883 |
self.logger.debug("Successfully connected to device\n")
|
| 342 |
farthen |
884 |
|
|
|
885 |
# Device properties
|
| 343 |
farthen |
886 |
self.packetsizelimit = Bunch()
|
|
|
887 |
self.packetsizelimit.cout = None
|
|
|
888 |
self.packetsizelimit.cin = None
|
|
|
889 |
self.packetsizelimit.dout = None
|
|
|
890 |
self.packetsizelimit.din = None
|
| 342 |
farthen |
891 |
|
| 343 |
farthen |
892 |
self.version = Bunch()
|
| 342 |
farthen |
893 |
self.version.revision = None
|
|
|
894 |
self.version.majorv = None
|
|
|
895 |
self.version.minorv = None
|
|
|
896 |
self.version.patchv = None
|
|
|
897 |
self.swtypeid = None
|
|
|
898 |
self.hwtypeid = None
|
|
|
899 |
|
| 343 |
farthen |
900 |
self.usermem = Bunch()
|
| 342 |
farthen |
901 |
self.usermem.lower = None
|
|
|
902 |
self.usermem.upper = None
|
| 56 |
benedikt93 |
903 |
|
| 171 |
farthen |
904 |
def __del__(self):
|
|
|
905 |
self.disconnect()
|
| 56 |
benedikt93 |
906 |
|
| 171 |
farthen |
907 |
def findEndpoints(self):
|
| 401 |
farthen |
908 |
self.logger.debug("Searching for device endpoints:\n")
|
| 171 |
farthen |
909 |
epcounter = 0
|
| 343 |
farthen |
910 |
self.endpoint = Bunch()
|
| 171 |
farthen |
911 |
for cfg in self.dev:
|
|
|
912 |
for intf in cfg:
|
|
|
913 |
for ep in intf:
|
|
|
914 |
if epcounter == 0:
|
| 401 |
farthen |
915 |
self.logger.debug("Found cout endpoint at 0x%x\n" % ep.bEndpointAddress)
|
| 343 |
farthen |
916 |
self.endpoint.cout = ep.bEndpointAddress
|
| 171 |
farthen |
917 |
elif epcounter == 1:
|
| 401 |
farthen |
918 |
self.logger.debug("Found cin endpoint at 0x%x\n" % ep.bEndpointAddress)
|
| 343 |
farthen |
919 |
self.endpoint.cin = ep.bEndpointAddress
|
| 171 |
farthen |
920 |
elif epcounter == 2:
|
| 401 |
farthen |
921 |
self.logger.debug("Found dout endpoint at 0x%x\n" % ep.bEndpointAddress)
|
| 343 |
farthen |
922 |
self.endpoint.dout = ep.bEndpointAddress
|
| 171 |
farthen |
923 |
elif epcounter == 3:
|
| 401 |
farthen |
924 |
self.logger.debug("Found din endpoint at 0x%x\n" % ep.bEndpointAddress)
|
| 343 |
farthen |
925 |
self.endpoint.din = ep.bEndpointAddress
|
| 171 |
farthen |
926 |
epcounter += 1
|
|
|
927 |
if epcounter <= 3:
|
|
|
928 |
raise DeviceError("Not all endpoints found in the descriptor. Only "+str(epcounter)+" found, we need 4")
|
| 56 |
benedikt93 |
929 |
|
| 171 |
farthen |
930 |
def connect(self):
|
| 427 |
farthen |
931 |
self.logger.debug("Looking for emCORE device\n")
|
| 171 |
farthen |
932 |
self.dev = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
|
|
|
933 |
if self.dev is None:
|
|
|
934 |
raise DeviceNotFoundError()
|
| 401 |
farthen |
935 |
self.logger.debug("Device Found!\n")
|
|
|
936 |
self.logger.debug("Setting first configuration\n")
|
| 171 |
farthen |
937 |
self.dev.set_configuration()
|
| 56 |
benedikt93 |
938 |
|
| 171 |
farthen |
939 |
def disconnect(self):
|
|
|
940 |
pass
|
| 102 |
benedikt93 |
941 |
|
| 171 |
farthen |
942 |
def send(self, endpoint, data):
|
|
|
943 |
size = self.dev.write(endpoint, data, self.interface, self.timeout)
|
|
|
944 |
if size != len(data):
|
| 176 |
farthen |
945 |
raise SendError("Not all data was written!")
|
| 171 |
farthen |
946 |
return len
|
| 102 |
benedikt93 |
947 |
|
| 171 |
farthen |
948 |
def receive(self, endpoint, size):
|
|
|
949 |
read = self.dev.read(endpoint, size, self.interface, self.timeout)
|
|
|
950 |
if len(read) != size:
|
| 176 |
farthen |
951 |
raise ReceiveError("Requested size and read size don't match!")
|
| 171 |
farthen |
952 |
return read
|
| 56 |
benedikt93 |
953 |
|
| 171 |
farthen |
954 |
def cout(self, data):
|
| 401 |
farthen |
955 |
self.logger.debug("Sending data to cout endpoint with the size " + str(len(data)) + "\n")
|
| 343 |
farthen |
956 |
if self.packetsizelimit.cout and len(data) > self.packetsizelimit.cout:
|
| 171 |
farthen |
957 |
raise SendError("Packet too big")
|
| 343 |
farthen |
958 |
return self.send(self.endpoint.cout, data)
|
| 94 |
benedikt93 |
959 |
|
| 171 |
farthen |
960 |
def cin(self, size):
|
| 401 |
farthen |
961 |
self.logger.debug("Receiving data on the cin endpoint with the size " + str(size) + "\n")
|
| 343 |
farthen |
962 |
if self.packetsizelimit.cin and size > self.packetsizelimit.cin:
|
| 171 |
farthen |
963 |
raise ReceiveError("Packet too big")
|
| 343 |
farthen |
964 |
return self.receive(self.endpoint.cin, size)
|
| 94 |
benedikt93 |
965 |
|
| 171 |
farthen |
966 |
def dout(self, data):
|
| 401 |
farthen |
967 |
self.logger.debug("Sending data to cout endpoint with the size " + str(len(data)) + "\n")
|
| 343 |
farthen |
968 |
if self.packetsizelimit.dout and len(data) > self.packetsizelimit.dout:
|
| 171 |
farthen |
969 |
raise SendError("Packet too big")
|
| 343 |
farthen |
970 |
return self.send(self.endpoint.dout, data)
|
| 94 |
benedikt93 |
971 |
|
| 171 |
farthen |
972 |
def din(self, size):
|
| 401 |
farthen |
973 |
self.logger.debug("Receiving data on the din endpoint with the size " + str(size) + "\n")
|
| 343 |
farthen |
974 |
if self.packetsizelimit.din and size > self.packetsizelimit.din:
|
| 171 |
farthen |
975 |
raise ReceiveError("Packet too big")
|
| 343 |
farthen |
976 |
return self.receive(self.endpoint.din, size)
|
| 56 |
benedikt93 |
977 |
|
| 96 |
benedikt93 |
978 |
|
| 171 |
farthen |
979 |
if __name__ == "__main__":
|
| 396 |
farthen |
980 |
from misc import Logger
|
|
|
981 |
logger = Logger()
|
|
|
982 |
if sys.argv[1] == "test":
|
|
|
983 |
# Some tests
|
|
|
984 |
import sys
|
| 427 |
farthen |
985 |
emcore = Emcore()
|
|
|
986 |
resp = emcore.getversioninfo()
|
|
|
987 |
logger.log("Emcore device version information: " + libemcoredata.swtypes[resp.swtypeid] + " v" + str(resp.majorv) + "." + str(resp.minorv) +
|
|
|
988 |
"." + str(resp.patchv) + " r" + str(resp.revision) + " running on " + libemcoredata.hwtypes[resp.hwtypeid] + "\n")
|
|
|
989 |
resp = emcore.getusermemrange()
|
| 396 |
farthen |
990 |
logger.log("Usermemrange: "+hex(resp.lower)+" - "+hex(resp.upper)+"\n")
|
|
|
991 |
memaddr = resp.lower
|
|
|
992 |
maxlen = resp.upper - resp.lower
|
| 427 |
farthen |
993 |
f = open("./emcore.py", "rb")
|
|
|
994 |
logger.log("Loading test file (emcore.py) to send over USB...\n")
|
| 396 |
farthen |
995 |
datastr = f.read()[:maxlen]
|
|
|
996 |
logger.log("Sending data...\n")
|
| 427 |
farthen |
997 |
emcore.write(memaddr, datastr)
|
| 396 |
farthen |
998 |
logger.log("Encrypting data with the hardware key...\n")
|
| 427 |
farthen |
999 |
emcore.aesencrypt(memaddr, len(datastr), 0)
|
|
|
1000 |
logger.log("Reading data back and saving it to 'libemcore-test-encrypted.bin'...\n")
|
|
|
1001 |
f = open("./libemcore-test-encrypted.bin", "wb")
|
|
|
1002 |
f.write(emcore.read(memaddr, len(datastr)))
|
| 396 |
farthen |
1003 |
logger.log("Decrypting the data again...\n")
|
| 427 |
farthen |
1004 |
emcore.aesdecrypt(memaddr, len(datastr), 0)
|
| 396 |
farthen |
1005 |
logger.log("Reading data back from device...\n")
|
| 427 |
farthen |
1006 |
readdata = emcore.read(memaddr, len(datastr))
|
| 396 |
farthen |
1007 |
if readdata == datastr:
|
|
|
1008 |
logger.log("Data matches!")
|
|
|
1009 |
else:
|
|
|
1010 |
logger.log("Data does NOT match. Something went wrong")
|
|
|
1011 |
|
|
|
1012 |
elif sys.argv[1] == "gendoc":
|
|
|
1013 |
# Generates Documentation
|
|
|
1014 |
from misc import gendoc
|
|
|
1015 |
logger.log("Generating documentation\n")
|
|
|
1016 |
cmddict = {}
|
| 427 |
farthen |
1017 |
for attr, value in Emcore.__dict__.iteritems():
|
| 396 |
farthen |
1018 |
if getattr(value, 'func', False):
|
|
|
1019 |
if getattr(value.func, '_command', False):
|
|
|
1020 |
cmddict[value.func.__name__] = value
|
|
|
1021 |
logger.log(gendoc(cmddict))
|