comparison usb488.py @ 65:29bcef559283

Add initiateClear and a few others and use it to clear buffers on setup.
author Daniel O'Connor <doconnor@gsoft.com.au>
date Tue, 19 Jan 2021 16:06:29 +1030
parents 4558e5ccd775
children bf411c7f5e78
comparison
equal deleted inserted replaced
64:4ca9fdf0795a 65:29bcef559283
33 # http://www.home.agilent.com/agilent/redirector.jspx?action=ref&cname=AGILENT_EDITORIAL&ckey=1189335&lc=eng&cc=US&nfr=-35560.0.00 33 # http://www.home.agilent.com/agilent/redirector.jspx?action=ref&cname=AGILENT_EDITORIAL&ckey=1189335&lc=eng&cc=US&nfr=-35560.0.00
34 # linux-2.6.29.3/drivers/usb/class/usbtmc.c 34 # linux-2.6.29.3/drivers/usb/class/usbtmc.c
35 # http://sdpha2.ucsd.edu/Lab_Equip_Manuals/usbtmc_usb488_subclass_1_00.pdf 35 # http://sdpha2.ucsd.edu/Lab_Equip_Manuals/usbtmc_usb488_subclass_1_00.pdf
36 # 36 #
37 37
38 import time
38 import usb 39 import usb
39 from functools import reduce 40 from functools import reduce
40 41
41 # 42 #
42 # The usual SCPI commands are wrapped before being sent. 43 # The usual SCPI commands are wrapped before being sent.
86 87
87 # USB488 message IDs 88 # USB488 message IDs
88 DEV_DEP_MSG_OUT = 1 89 DEV_DEP_MSG_OUT = 1
89 REQUEST_DEV_DEP_MSG_IN = 2 90 REQUEST_DEV_DEP_MSG_IN = 2
90 DEV_DEP_MSG_IN = 2 91 DEV_DEP_MSG_IN = 2
92
93 # USB TMC control requests
94 INITIATE_ABORT_BULK_OUT = 1
95 CHECK_ABORT_BULK_OUT_STATUS = 2
96 INITIATE_ABORT_BULK_IN = 3
97 CHECK_ABORT_BULK_IN_STATUS = 4
98 INITIATE_CLEAR = 5
99 CHECK_CLEAR_STATUS = 6
100 GET_CAPABILITIES = 7
101 INDICATOR_PULSE = 64
102
103 # Interface capability bits
104 IF_CAP_LISTEN_ONLY = 0x01
105 IF_CAP_TALK_ONLY = 0x02
106 IF_CAP_HAS_INDICATOR = 0x04
107
108 # Device capability bits
109 DEV_CAP_TERM_CHAR = 0x01
110
111 # USBTMC status definitions
112 STATUS_SUCCESS = 0x01
113 STATUS_PENDING = 0x02
114 STATUS_FAILED = 0x80
115 STATUS_TRANSFER_NOT_IN_PROGRESS = 0x81
116 STATUS_SPLIT_NOT_IN_PROGRESS = 0x82
117 STATUS_SPLIT_IN_PROGRESS = 0x83
91 118
92 class USB488Device(object): 119 class USB488Device(object):
93 def __init__(self, vendor = None, product = None, serial = None, path = None): 120 def __init__(self, vendor = None, product = None, serial = None, path = None):
94 """Search for a USB488 class device, if specified vendor, 121 """Search for a USB488 class device, if specified vendor,
95 product, serial and path will refine the search""" 122 product, serial and path will refine the search"""
158 except ValueError: 185 except ValueError:
159 self.serial = None 186 self.serial = None
160 187
161 # Determine the endpoints for each operation type 188 # Determine the endpoints for each operation type
162 self.intrep = self.bulkinep = self.bulkoutep = None 189 self.intrep = self.bulkinep = self.bulkoutep = None
163 190
164 for ep in altif.endpoints: 191 for ep in altif.endpoints:
165 if ep.type == usb.ENDPOINT_TYPE_INTERRUPT and \ 192 if ep.type == usb.ENDPOINT_TYPE_INTERRUPT and \
166 ep.address & usb.ENDPOINT_IN == usb.ENDPOINT_IN: 193 ep.address & usb.ENDPOINT_IN == usb.ENDPOINT_IN:
167 self.intrep = ep.address 194 self.intrep = ep.address
168 195
175 202
176 # Required for 488.2 devices, optional otherwise 203 # Required for 488.2 devices, optional otherwise
177 if self.intrep == None: 204 if self.intrep == None:
178 print("Can't find interrupt endpoint") 205 print("Can't find interrupt endpoint")
179 206
180 # Data from the scope (mandatory) 207 # Data from the device (mandatory)
181 if self.bulkinep == None: 208 if self.bulkinep == None:
182 raise BaseException("Can't find bulk-in endpoint") 209 raise BaseException("Can't find bulk-in endpoint")
183 210
184 # Data to the scope (mandatory) 211 # Data to the device (mandatory)
185 if self.bulkoutep == None: 212 if self.bulkoutep == None:
186 raise BaseException("Can't find bulk-out endpoint") 213 raise BaseException("Can't find bulk-out endpoint")
187 214
188 self.tag = 1 215 self.tag = 1
216 self.initiateClear()
189 217
190 def __str__(self): 218 def __str__(self):
191 rtn = "Mfg: %s Prod: %s" % (self.vendname, self.prodname) 219 rtn = "Mfg: %s Prod: %s" % (self.vendname, self.prodname)
192 if self.serial != "": 220 if self.serial != "":
193 rtn += " S/N: " + self.serial 221 rtn += " S/N: " + self.serial
226 # Split it up into maxPacket sized chunks and send.. 254 # Split it up into maxPacket sized chunks and send..
227 while len(pkt) > 0: 255 while len(pkt) > 0:
228 chunk = pkt[0:self.maxPacket] 256 chunk = pkt[0:self.maxPacket]
229 pkt = pkt[self.maxPacket:] 257 pkt = pkt[self.maxPacket:]
230 258
231 #print "Sending %s bytes of data: %s" % (len(chunk), chunk) 259 #print("Sending %s bytes of data: %s" % (len(chunk), chunk))
232 wrote = self.handle.bulkWrite(self.bulkoutep, chunk) 260 wrote = self.handle.bulkWrite(self.bulkoutep, chunk)
233 if wrote != len(chunk): 261 if wrote != len(chunk):
234 raise BaseException("Short write, got %d, expected %d" % (wrote, len(chunk))) 262 raise BaseException("Short write, got %d, expected %d" % (wrote, len(chunk)))
235 263
236 def read(self, timeout = None): 264 def read(self, timeout = None):
259 287
260 # Bump tag 288 # Bump tag
261 self.incrtag() 289 self.incrtag()
262 290
263 # Send it 291 # Send it
264 #print "Sending " + str(pkt) 292 #print("Sending " + str(pkt))
265 wrote = self.handle.bulkWrite(self.bulkoutep, pkt, _timeout) 293 wrote = self.handle.bulkWrite(self.bulkoutep, pkt, _timeout)
266 if wrote != len(pkt): 294 if wrote != len(pkt):
267 print("Short write, got %d, expected %d" % (wrote, len(pkt))) 295 print("Short write, got %d, expected %d" % (wrote, len(pkt)))
268 296
269 #print "Reading.." 297 #print("Reading..")
270 read = self.handle.bulkRead(self.bulkinep, datalen, _timeout) 298 read = self.handle.bulkRead(self.bulkinep, datalen, _timeout)
271 #print "Read %s bytes: %s" % (len(read), str(read)) 299 #print("Read %s bytes: %s" % (len(read), str(read)))
272 300
273 if read[0] != DEV_DEP_MSG_IN: 301 if read[0] != DEV_DEP_MSG_IN:
274 raise BaseException("Unexpected Msg ID, got %s expected %d" % (read[0], DEV_DEP_MSG_IN)) 302 raise BaseException("Unexpected Msg ID, got %s expected %d" % (read[0], DEV_DEP_MSG_IN))
275 if read[1] != exptag: 303 if read[1] != exptag:
276 raise BaseException("Unexpected tag, got %d expected %d" % (read[1], exptag)) 304 raise BaseException("Unexpected tag, got %d expected %d" % (read[1], exptag))
277 if read[2] != ~exptag & 0xff: 305 if read[2] != ~exptag & 0xff:
278 raise BaseException("Unexpected tag inverse, got %d expected %d" % (read[1], ~exptag & 0xff)) 306 raise BaseException("Unexpected tag inverse, got %d expected %d" % (read[1], ~exptag & 0xff))
279 307
280 actualdata = read[4] | read[5] << 8 | read[6] << 16 | read[7] << 24 308 actualdata = read[4] | read[5] << 8 | read[6] << 16 | read[7] << 24
281 #print "Computed datalen is %d" % (actualdata) 309 #print("Computed datalen is %d" % (actualdata))
282 data += read[12:12 + actualdata] 310 data += read[12:12 + actualdata]
283 if read[8] & 0x01: 311 if read[8] & 0x01:
284 #print "Breaking out due to EOM" 312 #print("Breaking out due to EOM")
285 break 313 break
286 314
287 # Stringify result for easier consumption 315 # Stringify result for easier consumption
288 result = reduce(lambda x, y: x+y, list(map(chr, data))) 316 result = reduce(lambda x, y: x+y, list(map(chr, data)))
289 # Trim off \n if present 317 # Trim off \n if present
305 self.handle.getString(self.dev.iManufacturer, 100) 333 self.handle.getString(self.dev.iManufacturer, 100)
306 except USBError as e: 334 except USBError as e:
307 return False 335 return False
308 336
309 return True 337 return True
310 338
339 def getCapabilities(self):
340 '''Returns interface and device capability bytes (see IF_CAP_* and DEV_CAP_*)'''
341 res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, GET_CAPABILITIES, 0x18)
342 return res[4], res[5]
343
344 def indicatorPulse(self):
345 '''Send an indicator pulse request'''
346 res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, INDICATOR_PULSE, 0x01)
347
348 def initiateClear(self):
349 '''Send request to clear all transfers and wait until the device reports it is done and clear stalls'''
350 res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, INITIATE_CLEAR, 0x01)
351 if res[0] == STATUS_SUCCESS:
352 while True:
353 res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, CHECK_CLEAR_STATUS, 0x02)
354 if res[0] != STATUS_PENDING:
355 break
356 time.sleep(0.1)
357 self.handle.clearHalt(usb.ENDPOINT_IN | self.bulkinep)
358 self.handle.clearHalt(usb.ENDPOINT_OUT | self.bulkoutep)