# HG changeset patch # User Daniel O'Connor # Date 1628059064 -34200 # Node ID 7386f288850840c5046948f07fb165b272873b31 # Parent f95db5ea2fe1b096c298b87e618fc5a2f0cb5522 Make function more configurable diff -r f95db5ea2fe1 -r 7386f2888508 acqsweep.py --- 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() diff -r f95db5ea2fe1 -r 7386f2888508 logpps.py --- 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''' diff -r f95db5ea2fe1 -r 7386f2888508 usb488.py --- 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]))