diff 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
line wrap: on
line diff
--- a/usb488.py	Fri Jan 08 14:10:24 2021 +1030
+++ b/usb488.py	Tue Jan 19 16:06:29 2021 +1030
@@ -35,6 +35,7 @@
 # http://sdpha2.ucsd.edu/Lab_Equip_Manuals/usbtmc_usb488_subclass_1_00.pdf
 #
 
+import time
 import usb
 from functools import reduce
 
@@ -89,6 +90,32 @@
 REQUEST_DEV_DEP_MSG_IN = 2
 DEV_DEP_MSG_IN = 2
 
+# USB TMC control requests
+INITIATE_ABORT_BULK_OUT = 1
+CHECK_ABORT_BULK_OUT_STATUS = 2
+INITIATE_ABORT_BULK_IN = 3
+CHECK_ABORT_BULK_IN_STATUS = 4
+INITIATE_CLEAR = 5
+CHECK_CLEAR_STATUS = 6
+GET_CAPABILITIES = 7
+INDICATOR_PULSE = 64
+
+# Interface capability bits
+IF_CAP_LISTEN_ONLY = 0x01
+IF_CAP_TALK_ONLY = 0x02
+IF_CAP_HAS_INDICATOR = 0x04
+
+# Device capability bits
+DEV_CAP_TERM_CHAR = 0x01
+
+# USBTMC status definitions
+STATUS_SUCCESS = 0x01
+STATUS_PENDING = 0x02
+STATUS_FAILED = 0x80
+STATUS_TRANSFER_NOT_IN_PROGRESS = 0x81
+STATUS_SPLIT_NOT_IN_PROGRESS = 0x82
+STATUS_SPLIT_IN_PROGRESS = 0x83
+
 class USB488Device(object):
     def __init__(self, vendor = None, product = None, serial = None, path = None):
         """Search for a USB488 class device, if specified vendor,
@@ -160,7 +187,7 @@
 
         # Determine the endpoints for each operation type
         self.intrep = self.bulkinep = self.bulkoutep = None
-    
+
         for ep in altif.endpoints:
             if ep.type == usb.ENDPOINT_TYPE_INTERRUPT and \
                    ep.address & usb.ENDPOINT_IN == usb.ENDPOINT_IN:
@@ -177,15 +204,16 @@
         if self.intrep == None:
             print("Can't find interrupt endpoint")
 
-        # Data from the scope (mandatory)
+        # Data from the device (mandatory)
         if self.bulkinep == None:
             raise BaseException("Can't find bulk-in endpoint")
 
-        # Data to the scope (mandatory)
+        # Data to the device (mandatory)
         if self.bulkoutep == None:
             raise BaseException("Can't find bulk-out endpoint")
 
         self.tag = 1
+        self.initiateClear()
 
     def __str__(self):
         rtn = "Mfg: %s Prod: %s" % (self.vendname, self.prodname)
@@ -228,7 +256,7 @@
             chunk = pkt[0:self.maxPacket]
             pkt = pkt[self.maxPacket:]
 
-            #print "Sending %s bytes of data: %s" % (len(chunk), chunk)
+            #print("Sending %s bytes of data: %s" % (len(chunk), chunk))
             wrote = self.handle.bulkWrite(self.bulkoutep, chunk)
             if wrote != len(chunk):
                 raise BaseException("Short write, got %d, expected %d" % (wrote, len(chunk)))
@@ -261,14 +289,14 @@
             self.incrtag()
 
             # Send it
-            #print "Sending " + str(pkt)
+            #print("Sending " + str(pkt))
             wrote = self.handle.bulkWrite(self.bulkoutep, pkt, _timeout)
             if wrote != len(pkt):
                 print("Short write, got %d, expected %d" % (wrote, len(pkt)))
 
-            #print "Reading.."
+            #print("Reading..")
             read = self.handle.bulkRead(self.bulkinep, datalen, _timeout)
-            #print "Read %s bytes: %s" % (len(read), str(read))
+            #print("Read %s bytes: %s" % (len(read), str(read)))
 
             if read[0] != DEV_DEP_MSG_IN:
                 raise BaseException("Unexpected Msg ID, got %s expected %d" % (read[0], DEV_DEP_MSG_IN))
@@ -278,10 +306,10 @@
                 raise BaseException("Unexpected tag inverse, got %d expected %d" % (read[1], ~exptag & 0xff))
 
             actualdata = read[4] | read[5] << 8 | read[6] << 16 | read[7] << 24
-            #print "Computed datalen is %d" % (actualdata)
+            #print("Computed datalen is %d" % (actualdata))
             data += read[12:12 + actualdata]
             if read[8] & 0x01:
-                #print "Breaking out due to EOM"
+                #print("Breaking out due to EOM")
                 break
 
         # Stringify result for easier consumption
@@ -307,4 +335,24 @@
             return False
 
         return True
-    
+
+    def getCapabilities(self):
+        '''Returns interface and device capability bytes (see IF_CAP_* and DEV_CAP_*)'''
+        res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, GET_CAPABILITIES, 0x18)
+        return res[4], res[5]
+
+    def indicatorPulse(self):
+        '''Send an indicator pulse request'''
+        res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, INDICATOR_PULSE, 0x01)
+
+    def initiateClear(self):
+        '''Send request to clear all transfers and wait until the device reports it is done and clear stalls'''
+        res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, INITIATE_CLEAR, 0x01)
+        if res[0] == STATUS_SUCCESS:
+            while True:
+                res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, CHECK_CLEAR_STATUS, 0x02)
+                if res[0] != STATUS_PENDING:
+                    break
+                time.sleep(0.1)
+        self.handle.clearHalt(usb.ENDPOINT_IN | self.bulkinep)
+        self.handle.clearHalt(usb.ENDPOINT_OUT | self.bulkoutep)