comparison usb488.py @ 69:7386f2888508

Make function more configurable
author Daniel O'Connor <doconnor@gsoft.com.au>
date Wed, 04 Aug 2021 16:07:44 +0930
parents 98b9258c75b6
children
comparison
equal deleted inserted replaced
68:f95db5ea2fe1 69:7386f2888508
97 CHECK_ABORT_BULK_IN_STATUS = 4 97 CHECK_ABORT_BULK_IN_STATUS = 4
98 INITIATE_CLEAR = 5 98 INITIATE_CLEAR = 5
99 CHECK_CLEAR_STATUS = 6 99 CHECK_CLEAR_STATUS = 6
100 GET_CAPABILITIES = 7 100 GET_CAPABILITIES = 7
101 INDICATOR_PULSE = 64 101 INDICATOR_PULSE = 64
102 # USB488
103 READ_STATUS_BYTE = 128
104 REN_CONTROL = 160
105 GO_TO_LOCAL = 161
106 LOCAL_LOCKOUT = 162
102 107
103 # Interface capability bits 108 # Interface capability bits
104 IF_CAP_LISTEN_ONLY = 0x01 109 IF_CAP_LISTEN_ONLY = 0x01
105 IF_CAP_TALK_ONLY = 0x02 110 IF_CAP_TALK_ONLY = 0x02
106 IF_CAP_HAS_INDICATOR = 0x04 111 IF_CAP_HAS_INDICATOR = 0x04
107 112
108 # Device capability bits 113 # Device capability bits
109 DEV_CAP_TERM_CHAR = 0x01 114 DEV_CAP_TERM_CHAR = 0x01
115
116 # USB488 interface capbility bits
117 USB488_IFCAP_TRIG = 0x01
118 USB488_IFCAP_GO_LOC = 0x02
119 USB488_IFCAP_488_2 = 0x04
120
121 # USB488 device capbility bits
122 USB488_DEVCAP_DT1 = 0x01
123 USB488_DEVCAP_RL1 = 0x02
124 USB488_DEVCAP_SR1 = 0x04
125 USB488_DEVCAP_SCPI = 0x08
110 126
111 # USBTMC status definitions 127 # USBTMC status definitions
112 STATUS_SUCCESS = 0x01 128 STATUS_SUCCESS = 0x01
113 STATUS_PENDING = 0x02 129 STATUS_PENDING = 0x02
114 STATUS_FAILED = 0x80 130 STATUS_FAILED = 0x80
214 # Data to the device (mandatory) 230 # Data to the device (mandatory)
215 if self.bulkoutep == None: 231 if self.bulkoutep == None:
216 raise BaseException("Can't find bulk-out endpoint") 232 raise BaseException("Can't find bulk-out endpoint")
217 233
218 self.tag = 1 234 self.tag = 1
219 235 #self.init()
236
237 def init(self):
220 # Flush out any pending data 238 # Flush out any pending data
221 self.initiateClear() 239 self.initiateClear()
222 # Perform dummy write/read otherwise the next read times out 240 # Perform dummy write/read otherwise the next read times out
223 try: 241 try:
224 self.ask('*STB?', timeout = 0.001) 242 self.ask('*STB?', timeout = 0.001)
237 if self.serial != "": 255 if self.serial != "":
238 rtn += " S/N: " + self.serial 256 rtn += " S/N: " + self.serial
239 257
240 return rtn 258 return rtn
241 259
242 def incrtag(self): 260 def gettag(self):
261 tag = self.tag
243 self.tag = (self.tag + 1) % 255 262 self.tag = (self.tag + 1) % 255
244 if self.tag == 0: 263 if self.tag == 0:
245 self.tag += 1 264 self.tag += 1
265 return tag
246 266
247 def write(self, data): 267 def write(self, data):
248 """Send data (string) to the instrument""" 268 """Send data (string) to the instrument"""
249 269
250 orddata = list(map(ord, data)) 270 orddata = list(map(ord, data))
252 if orddata[-1] != '\n': 272 if orddata[-1] != '\n':
253 orddata += [ord('\n')] 273 orddata += [ord('\n')]
254 datalen = len(orddata) 274 datalen = len(orddata)
255 275
256 # Build the packet 276 # Build the packet
257 pkt = [ DEV_DEP_MSG_OUT, self.tag, ~self.tag & 0xff, 0x00, 277 tag = self.gettag()
278 pkt = [ DEV_DEP_MSG_OUT, tag, ~tag & 0xff, 0x00,
258 datalen & 0xff, datalen >> 8 & 0xff, datalen >> 16 & 0xff, 279 datalen & 0xff, datalen >> 8 & 0xff, datalen >> 16 & 0xff,
259 datalen >> 24 & 0xff, 1, 0, 0, 0 ] 280 datalen >> 24 & 0xff, 1, 0, 0, 0 ]
260 281
261 # Add the data 282 # Add the data
262 pkt = pkt + orddata 283 pkt = pkt + orddata
263 284
264 # Align to 4 bytes 285 # Align to 4 bytes
265 alignlen = ((len(pkt) // 4) + 1) * 4 286 alignlen = ((len(pkt) // 4) + 1) * 4
266 pkt = pkt + [0] * (alignlen - len(pkt)) 287 pkt = pkt + [0] * (alignlen - len(pkt))
267 288
268 # Bump the tag
269 self.incrtag()
270
271 # Split it up into maxPacket sized chunks and send.. 289 # Split it up into maxPacket sized chunks and send..
290 # XXX; this is not correct, need a header for each one
272 while len(pkt) > 0: 291 while len(pkt) > 0:
273 chunk = pkt[0:self.maxPacket] 292 chunk = pkt[0:self.maxPacket]
274 pkt = pkt[self.maxPacket:] 293 pkt = pkt[self.maxPacket:]
275 294
276 #print("Sending %s bytes of data: %s" % (len(chunk), chunk)) 295 #print("Sending %d bytes of data: %s" % (len(chunk), chunk))
277 wrote = self.handle.bulkWrite(self.bulkoutep, chunk) 296 wrote = self.handle.bulkWrite(self.bulkoutep, chunk)
278 if wrote != len(chunk): 297 if wrote != len(chunk):
279 raise BaseException("Short write, got %d, expected %d" % (wrote, len(chunk))) 298 raise BaseException("Short write, got %d, expected %d" % (wrote, len(chunk)))
280 299
281 def read(self, timeout = None): 300 def read(self, timeout = None):
282 """Read data from the device, waits for up to timeout seconds for each USB transaction""" 301 """Read data from the device, waits for up to timeout seconds for each USB transaction"""
283 302
284 if timeout == None: 303 if timeout == None:
285 timeout = 0.5 304 timeout = 1
286 305
287 # Mangle into milliseconds 306 # Mangle into milliseconds
288 _timeout = int(timeout * 1000.0) 307 _timeout = int(timeout * 1000.0)
289 308
290 # Maximum we accept at once 309 # Maximum we accept at once
293 datalen = 10240 312 datalen = 10240
294 data = [] 313 data = []
295 314
296 while True: 315 while True:
297 # Ask the device to send us something 316 # Ask the device to send us something
298 pkt = [ REQUEST_DEV_DEP_MSG_IN, self.tag, ~self.tag & 0xff, 0x00, 317 tag = self.gettag()
318 pkt = [ REQUEST_DEV_DEP_MSG_IN, tag, ~tag & 0xff, 0x00,
299 datalen & 0xff, datalen >> 8 & 0xff, datalen >> 16 & 0xff, 319 datalen & 0xff, datalen >> 8 & 0xff, datalen >> 16 & 0xff,
300 datalen >> 24 & 0xff, 0, 0, 0, 0] 320 datalen >> 24 & 0xff, 0, 0, 0, 0]
301
302 # Expected tag
303 exptag = self.tag
304
305 # Bump tag
306 self.incrtag()
307 321
308 # Send it 322 # Send it
309 #print("Sending " + str(pkt)) 323 #print("Sending " + str(pkt))
310 wrote = self.handle.bulkWrite(self.bulkoutep, pkt, _timeout) 324 wrote = self.handle.bulkWrite(self.bulkoutep, pkt, _timeout)
311 if wrote != len(pkt): 325 if wrote != len(pkt):
315 read = self.handle.bulkRead(self.bulkinep, datalen, _timeout) 329 read = self.handle.bulkRead(self.bulkinep, datalen, _timeout)
316 #print("Read %s bytes: %s" % (len(read), str(read))) 330 #print("Read %s bytes: %s" % (len(read), str(read)))
317 331
318 if read[0] != DEV_DEP_MSG_IN: 332 if read[0] != DEV_DEP_MSG_IN:
319 raise BaseException("Unexpected Msg ID, got %s expected %d" % (read[0], DEV_DEP_MSG_IN)) 333 raise BaseException("Unexpected Msg ID, got %s expected %d" % (read[0], DEV_DEP_MSG_IN))
320 if read[1] != exptag: 334 if read[1] != tag:
321 raise BaseException("Unexpected tag, got %d expected %d" % (read[1], exptag)) 335 raise BaseException("Unexpected tag, got %d expected %d" % (read[1], tag))
322 if read[2] != ~exptag & 0xff: 336 if read[2] != ~tag & 0xff:
323 raise BaseException("Unexpected tag inverse, got %d expected %d" % (read[1], ~exptag & 0xff)) 337 raise BaseException("Unexpected tag inverse, got %d expected %d" % (read[1], ~tag & 0xff))
324 338
325 actualdata = read[4] | read[5] << 8 | read[6] << 16 | read[7] << 24 339 actualdata = read[4] | read[5] << 8 | read[6] << 16 | read[7] << 24
326 #print("Computed datalen is %d" % (actualdata)) 340 #print("Computed datalen is %d" % (actualdata))
327 data += read[12:12 + actualdata] 341 data += read[12:12 + actualdata]
328 if read[8] & 0x01: 342 if read[8] & 0x01:
360 return False 374 return False
361 375
362 return True 376 return True
363 377
364 def getCapabilities(self): 378 def getCapabilities(self):
365 '''Returns interface and device capability bytes (see IF_CAP_* and DEV_CAP_*)''' 379 '''Returns interface, device and USB488 capability bytes (see IF_CAP_*, DEV_CAP_*, USB488_IFCAP_* and USB488_DEVCAP_*)'''
366 res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, GET_CAPABILITIES, 0x18) 380 res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, GET_CAPABILITIES, 0x18)
367 return res[4], res[5] 381 return res[4], res[5], res[14], res[15]
368 382
369 def indicatorPulse(self): 383 def indicatorPulse(self):
370 '''Send an indicator pulse request''' 384 '''Send an indicator pulse request'''
371 res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, INDICATOR_PULSE, 0x01) 385 res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, INDICATOR_PULSE, 0x01)
372 386
377 while True: 391 while True:
378 res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, CHECK_CLEAR_STATUS, 0x02) 392 res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, CHECK_CLEAR_STATUS, 0x02)
379 if res[0] != STATUS_PENDING: 393 if res[0] != STATUS_PENDING:
380 break 394 break
381 time.sleep(0.1) 395 time.sleep(0.1)
382 self.handle.clearHalt(usb.ENDPOINT_IN | self.bulkinep) 396 else:
383 self.handle.clearHalt(usb.ENDPOINT_OUT | self.bulkoutep) 397 raise BaseException('INITIATE_CLEAR returned 0x%02x' % (res[0]))
398 self.handle.clearHalt(self.bulkinep)
399 self.handle.clearHalt(self.bulkoutep)
400
401 def renControl(self):
402 '''Send enable remote control message'''
403 res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, REN_CONTROL, 1, 0xff)
404 return res[0]
405
406 def getStatus(self):
407 '''Returns IEEE 488 status byte'''
408 tag = self.gettag()
409 res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, READ_STATUS_BYTE, 3, tag)
410 if res[1] != tag:
411 raise BaseException('Tag mismatch, got 0x%02x, expected 0x%02x' % (res[1], tag))
412 if res[0] != STATUS_SUCCESS:
413 raise BaseException('Unit returned invalid USBTMC status: %d' % (res[0],))
414 return res[2]
415
416 def abortIO(self, tag, isout):
417 if isout:
418 req = INITIATE_ABORT_BULK_OUT
419 chkreq = CHECK_ABORT_BULK_OUT_STATUS
420 ep = self.bulkoutep
421 name = 'out'
422 else:
423 req = INITIATE_ABORT_BULK_IN
424 chkreq = CHECK_ABORT_BULK_IN_STATUS
425 ep = self.bulkinep
426 name = 'in'
427 res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_ENDPOINT,
428 req, 2, value = tag, index = ep)
429 print('Initiate abort returned ' + str(res))
430 while True:
431 res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_ENDPOINT,
432 chkreq, 8, value = 0x00, index = ep)
433 print('Check abort returned ' + str(res))
434 if res[0] == STATUS_PENDING:
435 print('Status pending for %s abort' % (name,))
436 time.sleep(1)
437 elif res[0] == STATUS_SUCCESS or res[0] == STATUS_TRANSFER_NOT_IN_PROGRESS:
438 break
439 else:
440 raise BaseException('Invalid status reply to check abort %s 0x%02x' % (name, res[0]))