changeset 69:7386f2888508

Make function more configurable
author Daniel O'Connor <doconnor@gsoft.com.au>
date Wed, 04 Aug 2021 16:07:44 +0930
parents f95db5ea2fe1
children 6ffa6fcf278e
files acqsweep.py logpps.py usb488.py
diffstat 3 files changed, 151 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/acqsweep.py	Tue Jan 19 17:32:57 2021 +1030
+++ b/acqsweep.py	Wed Aug 04 16:07:44 2021 +0930
@@ -25,6 +25,7 @@
 # SUCH DAMAGE.
 #
 
+import sys
 import usb
 import usb488
 
@@ -34,19 +35,16 @@
 
 def main():
     u = usb488.USB488Device()
-    print('Found device')
+    res = u.ask('*IDN?')
+    print('Found device ID: ' + res)
 
     setup(u)
 
 def freqsetup(u, swstart, swstop, swpoints, swoffset, swlevel):
     '''Setup a frequency sweep'''
 
-    res = u.ask('*IDN?')
-    print('Device ID: ' + res)
-
     # Output off
     wrcheck(u, ':OUTP:STATE', 'OFF')
-    # XXX: Most of these work with :SOUR prefixed but :SWE:POIN:TRIG:TYPE does not
     # Single sweep
     wrcheck(u, ':SWE:MODE', 'SING')
     # Frequency sweep
@@ -72,6 +70,42 @@
     wrcheck(u, ':SWE:STEP:STOP:LEV', '%fdBm' % (swlevel,))
     wrcheck(u, ':LEV', '%fdBm' % (swlevel,))
 
+def powersetup(u, swstart, swstop, swpoints, swfreq, swoffset):
+    '''Setup a power sweep'''
+
+    # Output off
+    wrcheck(u, ':OUTP:STATE', 'OFF')
+    # Single sweep
+    wrcheck(u, ':SWE:MODE', 'SING')
+    # Level sweep
+    wrcheck(u, ':SWE:STATE', ' LEV')
+    # Step (not list)
+    wrcheck(u, ':SWE:TYPE', 'STEP')
+    # In single sweep so it starts when SOU:SWE:EXE is sent
+    wrcheck(u, ':SWE:SWE:TRIG:TYPE', 'AUTO')
+    # Sweep a point every external trigger
+    wrcheck(u, ':SWE:POIN:TRIG:TYPE', 'EXT')
+    # Sweep up
+    wrcheck(u, ':SWE:DIR', 'FWD')
+    # Ramp (vs triangle)
+    wrcheck(u, ':SWE:STEP:SHAP', 'RAMP')
+    # Linear sweep
+    wrcheck(u, ':SWE:STEP:SPAC', 'LIN')
+    # Start/stop/points in sweep
+    wrcheck(u, ':LEV', '%fdBm' % (swstart,))
+    wrcheck(u, ':SWE:STEP:STAR:LEV', '%fdBm' % (swstart,))
+    wrcheck(u, ':SWE:STEP:STOP:LEV', '%fdBm' % (swstop,))
+    wrcheck(u, ':SWE:STEP:POIN', '%d' % (swpoints,))
+    # Output frequency
+    wrcheck(u, ':SWE:STEP:STAR:FREQ', '%fHz' % (swfreq + swoffset,))
+    wrcheck(u, ':SWE:STEP:STOP:FREQ', '%fHz' % (swfreq + swoffset,))
+    wrcheck(u, ':FREQ', '%fHz' % (swfreq,))
+    # Level sweep
+
+    # XXX: need to send this twice for some reason
+    # isn't needed for frequency sweep
+    wrcheck(u, ':SWE:STATE', ' LEV')
+
 def arm(u):
     # Output on
     wrcheck(u, ':OUTP:STATE', 'ON')
@@ -83,6 +117,7 @@
     u.chkcmd(name + ' ' + value)
     readval = u.ask(name + '?')
     print(name + ' -> ' + readval + ' (' + value + ')')
+    #sys.stdin.readline()
 
 if __name__ == '__main__':
     main()
--- a/logpps.py	Tue Jan 19 17:32:57 2021 +1030
+++ b/logpps.py	Wed Aug 04 16:07:44 2021 +0930
@@ -28,7 +28,8 @@
 # CREATE TABLE ppslog (
 #   name TEXT,
 #   time TIMESTAMP WITH TIME ZONE,
-#   delta NUMERIC(15, 12)
+#   delta12 NUMERIC(15, 12),
+#   delta13 NUMERIC(15, 12)
 # );
 
 import datetime
@@ -49,11 +50,14 @@
     res = u.ask('*IDN?')
     print('IDN reports ' + res)
 
+    hostname = 'radartest1'
+    nchan = 2
     #dbh = sqlite3.connect('logpps.db')
     dbh = psycopg2.connect('host=vm11 user=ppslog dbname=ppslog')
-    test(u, dbh, 'ncu-iono2-tx')
+    #dbh = None
+    test(u, nchan, dbh, hostname)
 
-def test(u, dbh = None, name = None):
+def test(u, nchan, dbh = None, name = None):
     if dbh != None:
         cur = dbh.cursor()
 
@@ -63,11 +67,11 @@
     #u.write('DATA:ENC RIB')		# Big endian signed
     #u.write('DATA:WIDTH 2')		# 2 bytes wide
 
-    vscale1 = float(u.ask('CH1:SCALE?').split()[1])
-    print(('Channel 1 scale is %.2f volts/div' % (vscale1)))
-
-    vscale2 = float(u.ask('CH2:SCALE?').split()[1])
-    print(('Channel 2 scale is %.2f volts/div' % (vscale2)))
+    vscales = []
+    for i in range(nchan):
+        tmp = float(u.ask('CH%d:SCALE?' % (i + 1)).split()[1])
+        vscales.append(tmp)
+        print(('Channel %d scale is %.2f volts/div' % (i + 1, tmp)))
 
     hscale = float(u.ask('HOR:MAIN:SCALE?').split()[1])
     print(('Horizontal scale is %.5f nsec/div' % (hscale * 1e9)))
@@ -75,36 +79,44 @@
     acqwindow = hscale * 10.0
 
     while True:
-        ary1, ary2 = acquire(u, vscale1, vscale2)
-        #pylab.plot(ary1)
-        #pylab.plot(ary2)
+        arys = acquire(u, vscales)
+        #for a in arys:
+        #    pylab.plot(a)
         #pylab.show()
-        sampletime = acqwindow / len(ary1)
-        d = getpdiffedge(ary1, ary2) * sampletime
+        sampletime = acqwindow / len(arys[0])
+        deltas = []
+        for i in range(nchan - 1):
+            delta = getpdiffedge(arys[0], arys[i + 1]) * sampletime
+            deltas.append(delta)
+            print('Delta 1-%d is %.1f nsec' % (i + 2, delta * 1e9))
 
-        print('Delta is %.1f nsec' % (d * 1e9))
         if dbh != None:
             now = datetime.datetime.now()
-            cur.execute('INSERT INTO ppslog(name, time, delta) VALUES(%s, %s, %s)', (name, now, d))
+            d12 = deltas[0]
+            d13 = None
+            if nchan > 2:
+                d13 = deltas[1]
+            cur.execute('INSERT INTO ppslog(name, time, delta12, delta13) VALUES(%s, %s, %s, %s)', (name, now, d12, d13))
             dbh.commit()
 
 def getchannel(u, ch, vscale):
         u.write('DAT:SOU CH%d' % (ch))	# Set the curve source to desired channel
         result = u.ask('CURVE?', 1.0)	# Ask for the curve data
-        data1 = result[13:]		# Chop off the header (should verify this really..)
+        data1 = buffer(result[13:])		# Chop off the header (should verify this really..)
         ary = numpy.frombuffer(data1, dtype = '>h')
         ary = ary / 32768.0 * vscale # Scale to volts
         return ary
 
-def acquire(u, vscale1, vscale2):
+def acquire(u, vscales):
         u.write('ACQ:STATE 1')	# Do a single acquisition
         u.write('*OPC?')
         u.read(2.0)	# Wait for it to complete
 
-        ary1 = getchannel(u, 1, vscale1)
-        ary2 = getchannel(u, 2, vscale2)
+        arys = []
+        for i in range(len(vscales)):
+            arys.append(getchannel(u, i + 1, vscales[i]))
 
-        return ary1, ary2
+        return arys
 
 def getpdiffedge(ary1, ary2):
     '''Return phase difference in samples between two signals by edge detection'''
--- a/usb488.py	Tue Jan 19 17:32:57 2021 +1030
+++ b/usb488.py	Wed Aug 04 16:07:44 2021 +0930
@@ -99,6 +99,11 @@
 CHECK_CLEAR_STATUS = 6
 GET_CAPABILITIES = 7
 INDICATOR_PULSE = 64
+# USB488
+READ_STATUS_BYTE = 128
+REN_CONTROL = 160
+GO_TO_LOCAL = 161
+LOCAL_LOCKOUT = 162
 
 # Interface capability bits
 IF_CAP_LISTEN_ONLY = 0x01
@@ -108,6 +113,17 @@
 # Device capability bits
 DEV_CAP_TERM_CHAR = 0x01
 
+# USB488 interface capbility bits
+USB488_IFCAP_TRIG = 0x01
+USB488_IFCAP_GO_LOC = 0x02
+USB488_IFCAP_488_2 = 0x04
+
+# USB488 device capbility bits
+USB488_DEVCAP_DT1 = 0x01
+USB488_DEVCAP_RL1 = 0x02
+USB488_DEVCAP_SR1 = 0x04
+USB488_DEVCAP_SCPI = 0x08
+
 # USBTMC status definitions
 STATUS_SUCCESS = 0x01
 STATUS_PENDING = 0x02
@@ -216,7 +232,9 @@
             raise BaseException("Can't find bulk-out endpoint")
 
         self.tag = 1
+        #self.init()
 
+    def init(self):
         # Flush out any pending data
         self.initiateClear()
         # Perform dummy write/read otherwise the next read times out
@@ -239,10 +257,12 @@
 
         return rtn
 
-    def incrtag(self):
+    def gettag(self):
+        tag = self.tag
         self.tag = (self.tag + 1) % 255
         if self.tag == 0:
             self.tag += 1
+        return tag
 
     def write(self, data):
         """Send data (string) to the instrument"""
@@ -254,7 +274,8 @@
         datalen = len(orddata)
 
         # Build the packet
-        pkt = [ DEV_DEP_MSG_OUT, self.tag, ~self.tag & 0xff, 0x00,
+        tag = self.gettag()
+        pkt = [ DEV_DEP_MSG_OUT, tag, ~tag & 0xff, 0x00,
                 datalen & 0xff, datalen >> 8 & 0xff, datalen >> 16 & 0xff,
                 datalen >> 24 & 0xff, 1, 0, 0, 0 ]
 
@@ -265,15 +286,13 @@
         alignlen = ((len(pkt) // 4) + 1) * 4
         pkt = pkt + [0] * (alignlen - len(pkt))
 
-        # Bump the tag
-        self.incrtag()
-
         # Split it up into maxPacket sized chunks and send..
+        # XXX; this is not correct, need a header for each one
         while len(pkt) > 0:
             chunk = pkt[0:self.maxPacket]
             pkt = pkt[self.maxPacket:]
 
-            #print("Sending %s bytes of data: %s" % (len(chunk), chunk))
+            #print("Sending %d 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)))
@@ -282,7 +301,7 @@
         """Read data from the device, waits for up to timeout seconds for each USB transaction"""
 
         if timeout == None:
-            timeout = 0.5
+            timeout = 1
 
         # Mangle into milliseconds
         _timeout = int(timeout * 1000.0)
@@ -295,16 +314,11 @@
         
         while True:
             # Ask the device to send us something
-            pkt = [ REQUEST_DEV_DEP_MSG_IN, self.tag, ~self.tag & 0xff, 0x00,
+            tag = self.gettag()
+            pkt = [ REQUEST_DEV_DEP_MSG_IN, tag, ~tag & 0xff, 0x00,
                     datalen & 0xff, datalen >> 8 & 0xff, datalen >> 16 & 0xff,
                     datalen >> 24 & 0xff, 0, 0, 0, 0]
 
-            # Expected tag
-            exptag = self.tag
-            
-            # Bump tag
-            self.incrtag()
-
             # Send it
             #print("Sending " + str(pkt))
             wrote = self.handle.bulkWrite(self.bulkoutep, pkt, _timeout)
@@ -317,10 +331,10 @@
 
             if read[0] != DEV_DEP_MSG_IN:
                 raise BaseException("Unexpected Msg ID, got %s expected %d" % (read[0], DEV_DEP_MSG_IN))
-            if read[1] != exptag:
-                raise BaseException("Unexpected tag, got %d expected %d" % (read[1], exptag))
-            if read[2] != ~exptag & 0xff:
-                raise BaseException("Unexpected tag inverse, got %d expected %d" % (read[1], ~exptag & 0xff))
+            if read[1] != tag:
+                raise BaseException("Unexpected tag, got %d expected %d" % (read[1], tag))
+            if read[2] != ~tag & 0xff:
+                raise BaseException("Unexpected tag inverse, got %d expected %d" % (read[1], ~tag & 0xff))
 
             actualdata = read[4] | read[5] << 8 | read[6] << 16 | read[7] << 24
             #print("Computed datalen is %d" % (actualdata))
@@ -362,9 +376,9 @@
         return True
 
     def getCapabilities(self):
-        '''Returns interface and device capability bytes (see IF_CAP_* and DEV_CAP_*)'''
+        '''Returns interface, device and USB488 capability bytes (see IF_CAP_*, DEV_CAP_*, USB488_IFCAP_* and USB488_DEVCAP_*)'''
         res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, GET_CAPABILITIES, 0x18)
-        return res[4], res[5]
+        return res[4], res[5], res[14], res[15]
 
     def indicatorPulse(self):
         '''Send an indicator pulse request'''
@@ -379,5 +393,48 @@
                 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)
+        else:
+            raise BaseException('INITIATE_CLEAR returned 0x%02x' % (res[0]))
+        self.handle.clearHalt(self.bulkinep)
+        self.handle.clearHalt(self.bulkoutep)
+
+    def renControl(self):
+        '''Send enable remote control message'''
+        res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, REN_CONTROL, 1, 0xff)
+        return res[0]
+
+    def getStatus(self):
+        '''Returns IEEE 488 status byte'''
+        tag = self.gettag()
+        res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE, READ_STATUS_BYTE, 3, tag)
+        if res[1] != tag:
+            raise BaseException('Tag mismatch, got 0x%02x, expected 0x%02x' % (res[1], tag))
+        if res[0] != STATUS_SUCCESS:
+            raise BaseException('Unit returned invalid USBTMC status: %d' % (res[0],))
+        return res[2]
+
+    def abortIO(self, tag, isout):
+        if isout:
+            req = INITIATE_ABORT_BULK_OUT
+            chkreq = CHECK_ABORT_BULK_OUT_STATUS
+            ep = self.bulkoutep
+            name = 'out'
+        else:
+            req = INITIATE_ABORT_BULK_IN
+            chkreq = CHECK_ABORT_BULK_IN_STATUS
+            ep = self.bulkinep
+            name = 'in'
+        res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_ENDPOINT,
+                                req, 2, value = tag, index = ep)
+        print('Initiate abort returned ' + str(res))
+        while True:
+            res = self.handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_ENDPOINT,
+                                         chkreq, 8, value = 0x00, index = ep)
+            print('Check abort returned ' + str(res))
+            if res[0] == STATUS_PENDING:
+                print('Status pending for %s abort' % (name,))
+                time.sleep(1)
+            elif res[0] == STATUS_SUCCESS or res[0] == STATUS_TRANSFER_NOT_IN_PROGRESS:
+                break
+            else:
+                raise BaseException('Invalid status reply to check abort %s 0x%02x' % (name, res[0]))