annotate scpi.py @ 79:84f96c5fe791

Use different message ID that does not result in "Query UNTERMINATE" messages in the error log. Fix testsrq. Rename queryrsb to querystb as that matches the operating manual.
author Daniel O'Connor <doconnor@gsoft.com.au>
date Fri, 27 Sep 2024 16:53:43 +0930
parents ca5a822c550a
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
15
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1 #!/usr/bin/env python
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
2
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
3 # Copyright (c) 2011
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
4 # Daniel O'Connor <darius@dons.net.au>. All rights reserved.
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
5 #
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
6 # Redistribution and use in source and binary forms, with or without
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
7 # modification, are permitted provided that the following conditions
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
8 # are met:
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
9 # 1. Redistributions of source code must retain the above copyright
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
10 # notice, this list of conditions and the following disclaimer.
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
11 # 2. Redistributions in binary form must reproduce the above copyright
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
12 # notice, this list of conditions and the following disclaimer in the
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
13 # documentation and/or other materials provided with the distribution.
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
14 #
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
15 # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
17 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
18 # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
19 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
20 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
21 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
22 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
23 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
24 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
25 # SUCH DAMAGE.
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
26 #
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
27
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
28 import numpy
17
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
29 import re
15
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
30
73
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
31 headerre = re.compile(b'^(:[A-Z:]+ ).*')
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
32 insturlre = re.compile(b'([a-zA-Z0-9]+)://(([^:]+)?(:([^/]+)@))?([^:]+)(:(.+))?')
27
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
33
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
34 def query(d, q, timeout = None):
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
35 d.write(q)
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
36 return d.read(timeout)
17
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
37
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
38 def clean(data):
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
39 # The instrument might return some header before the data (TEK 2024B does this)
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
40 m = headerre.match(data)
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
41 if m == None:
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
42 return data
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
43 else:
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
44 hlen = len(m.groups()[0])
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
45 return(data[hlen:])
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
46
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
47 def getdata(data, dtype = float):
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
48 '''Get a single data item'''
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
49 data = clean(data)
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
50 return dtype(data)
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
51
73
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
52 def getbin(data):
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
53 '''Fetch binary blob, strips ASCII length header and checks'''
17
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
54 data = clean(data)
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
55
73
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
56 if data[0] != ord('#'):
71
00800345fbae Python3ise RSIB code
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 27
diff changeset
57 raise ValueError('data length header incorrect')
73
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
58 dlenlen = int(chr(data[1]))
27
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
59 if dlenlen == 0:
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
60 return numpy.array([])
73
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
61
17
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
62 dlen = int(data[2:dlenlen + 2])
27
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
63 if dlen == 0:
73
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
64 return b''
27
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
65
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
66 wanted = dlen + 2 + dlenlen
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
67 # Chop off the trailing \n if necessary
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
68 if len(data) == wanted + 1 and data[-1] == '\n':
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
69 data = data[0:-1]
73
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
70
27
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
71 if len(data) != wanted:
71
00800345fbae Python3ise RSIB code
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 27
diff changeset
72 raise ValueError('length mismatch, header says %d, actually got %d bytes' % (wanted, len(data)))
73
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
73
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
74 return data[2 + dlenlen:]
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
75
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
76 def bindecode(data, dtype = numpy.float32):
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
77 '''Decode binary data, returns numpy array'''
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
78
ca5a822c550a Fix for Python 3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 71
diff changeset
79 return numpy.frombuffer(getbin(data), dtype = dtype)
15
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
80
20
a124aa7067e7 Make ascdecode smarter so it can handle Anritsu ASCII.
Daniel O'Connor <darius@dons.net.au>
parents: 17
diff changeset
81 def ascdecode(data, dtype = numpy.float32, sep = None):
15
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
82 '''Decode ASCII data, returns numpy array'''
17
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
83
20df02be818a Work out the header using an RE and scrub it automatically.
Daniel O'Connor <darius@dons.net.au>
parents: 15
diff changeset
84 data = clean(data)
20
a124aa7067e7 Make ascdecode smarter so it can handle Anritsu ASCII.
Daniel O'Connor <darius@dons.net.au>
parents: 17
diff changeset
85
a124aa7067e7 Make ascdecode smarter so it can handle Anritsu ASCII.
Daniel O'Connor <darius@dons.net.au>
parents: 17
diff changeset
86 # Strip length off if present as we don't need it
a124aa7067e7 Make ascdecode smarter so it can handle Anritsu ASCII.
Daniel O'Connor <darius@dons.net.au>
parents: 17
diff changeset
87 if data[0] == '#':
a124aa7067e7 Make ascdecode smarter so it can handle Anritsu ASCII.
Daniel O'Connor <darius@dons.net.au>
parents: 17
diff changeset
88 l = int(data[1])
a124aa7067e7 Make ascdecode smarter so it can handle Anritsu ASCII.
Daniel O'Connor <darius@dons.net.au>
parents: 17
diff changeset
89 data = data[l + 2:]
a124aa7067e7 Make ascdecode smarter so it can handle Anritsu ASCII.
Daniel O'Connor <darius@dons.net.au>
parents: 17
diff changeset
90
a124aa7067e7 Make ascdecode smarter so it can handle Anritsu ASCII.
Daniel O'Connor <darius@dons.net.au>
parents: 17
diff changeset
91 # Take a guess at the separator
a124aa7067e7 Make ascdecode smarter so it can handle Anritsu ASCII.
Daniel O'Connor <darius@dons.net.au>
parents: 17
diff changeset
92 if sep == None:
a124aa7067e7 Make ascdecode smarter so it can handle Anritsu ASCII.
Daniel O'Connor <darius@dons.net.au>
parents: 17
diff changeset
93 if data.find(',', 0, 20) != -1:
a124aa7067e7 Make ascdecode smarter so it can handle Anritsu ASCII.
Daniel O'Connor <darius@dons.net.au>
parents: 17
diff changeset
94 sep = ','
a124aa7067e7 Make ascdecode smarter so it can handle Anritsu ASCII.
Daniel O'Connor <darius@dons.net.au>
parents: 17
diff changeset
95 else:
a124aa7067e7 Make ascdecode smarter so it can handle Anritsu ASCII.
Daniel O'Connor <darius@dons.net.au>
parents: 17
diff changeset
96 sep = ' '
a124aa7067e7 Make ascdecode smarter so it can handle Anritsu ASCII.
Daniel O'Connor <darius@dons.net.au>
parents: 17
diff changeset
97 return numpy.fromstring(data, dtype = dtype, sep = sep)
15
37d6ceb4850f Add helper functions for SCPI.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
98
27
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
99
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
100 def instURL(url):
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
101 m = insturlre.match(url)
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
102 if m == None:
71
00800345fbae Python3ise RSIB code
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 27
diff changeset
103 raise ValueError('Unable to parse URL')
27
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
104 proto, xxx, user, xxx, pwd, address, xxx, port = m.groups()
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
105 if proto == 'rsib':
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
106 import rsib
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
107 return rsib.RSIBDevice(address, port)
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
108 elif proto == 'usb':
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
109 import usb488
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
110 return usb488.USB488Device()
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
111 elif proto == 'vxi':
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
112 import vxi
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
113 if port == None:
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
114 port = 'inst0'
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
115 return vxi.VXIDevice(address, device = port)
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
116 elif proto == 'scpi':
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
117 import scpisock
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
118 return scpisock.SCPISockDevice(address, port)
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
119 else:
71
00800345fbae Python3ise RSIB code
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 27
diff changeset
120 raise NotImplementedError("unknown protocol " + proto)
27
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
121
e2833d081413 - Handle zero length data from the instrument.
Daniel O'Connor <darius@dons.net.au>
parents: 20
diff changeset
122