annotate vxi_11.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 91b476ebc0f2
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1 "The basic infrastructure for maintaining a vxi-11 protocol connection to a remote device"
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
2 _rcsid="$Id: vxi_11.py 323 2011-04-06 19:10:03Z marcus $"
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
3
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
4 import rpc
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
5 from rpc import TCPClient, RawTCPClient
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
6 import exceptions
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
7 import struct
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
8 import traceback
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
9 import time
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
10 import weakref
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
11 import sys
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
12 import select
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
13
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
14 #try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
15 # import threading
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
16 # threads=1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
17 #except:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
18 # threads=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
19 threads=False
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
20
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
21 connection_dict={}
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
22
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
23 def close_all_connections():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
24 "disconnect and close out all vxi_11 connections created here, even if their object references have been lost"
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
25 for wobj in list(connection_dict.keys()):
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
26 name, wconn=connection_dict[wobj]
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
27 conn=wconn() #dereference weak ref
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
28 if conn is not None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
29 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
30 conn.disconnect()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
31 except:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
32 conn.log_exception("***vxi_11.close_all_connections exception: ")
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
33
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
34 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
35 del connection_dict[wobj] #how did this happen?
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
36
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
37 class Junk_OneWayAbortClient(RawTCPClient):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
38 """OneWayAbortClient allows one to handle the strange, one-way abort rpc from an Agilent E5810.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
39 Really, it doesn't even do a one-way transmission... it loses aborts, so this is history """
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
40
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
41 def do_call(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
42 call = self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
43 rpc.sendrecord(self.sock, call)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
44 self.unpacker.reset('\0\0\0\0') #put a valid return value into the unpacker
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
45
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
46 class VXI_11_Error(IOError):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
47 vxi_11_errors={
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
48 0:"No error", 1:"Syntax error", 3:"Device not accessible",
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
49 4:"Invalid link identifier", 5:"Parameter error", 6:"Channel not established",
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
50 8:"Operation not supported", 9:"Out of resources", 11:"Device locked by another link",
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
51 12:"No lock held by this link", 15:"IO Timeout", 17:"IO Error", 21:"Invalid Address",
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
52 23:"Abort", 29:"Channel already established" ,
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
53 "eof": "Cut off packet received in rpc.recvfrag()",
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
54 "sync":"stream sync lost",
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
55 "notconnected": "Device not connected"}
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
56
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
57 def identify_vxi_11_error(self, error):
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
58 if error in self.vxi_11_errors:
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
59 return repr(error)+": "+self.vxi_11_errors[error]
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
60 else:
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
61 return repr(error)+": Unknown error code"
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
62
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
63
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
64 def __init__(self, code, **other_info):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
65 IOError.__init__(self, self.identify_vxi_11_error(code))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
66 self.code=code
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
67 self.other_info=other_info
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
68
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
69 def __repr__(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
70 if self.other_info:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
71 return str(self)+": "+str(self.other_info)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
72 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
73 return str(self)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
74
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
75 class VXI_11_Device_Not_Connected(VXI_11_Error):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
76 def __init__(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
77 VXI_11_Error.__init__(self,'notconnected')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
78
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
79 class VXI_11_Device_Not_Locked(VXI_11_Error):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
80 pass
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
81
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
82 class VXI_11_Transient_Error(VXI_11_Error): #exceptions having to do with multiple use which might get better
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
83 pass
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
84
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
85 class VXI_11_Timeout(VXI_11_Transient_Error):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
86 pass
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
87
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
88 class VXI_11_Locked_Elsewhere(VXI_11_Transient_Error):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
89 pass
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
90
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
91 class VXI_11_Stream_Sync_Lost(VXI_11_Transient_Error):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
92 def __init__(self, code, bytes):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
93 VXI_11_Transient_Error.__init__(self, code)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
94 self.other_info="bytes vacuumed = %d" % bytes
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
95
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
96
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
97 class VXI_11_RPC_EOF(VXI_11_Transient_Error):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
98 pass
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
99
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
100 _VXI_11_enumerated_exceptions={ #common, correctable exceptions
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
101 15:VXI_11_Timeout,
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
102 11:VXI_11_Locked_Elsewhere,
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
103 12:VXI_11_Device_Not_Locked
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
104 }
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
105
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
106 class vxi_11_connection:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
107 """vxi_11_connection implements handling of devices compliant with vxi11.1-vxi11.3 protocols, with which
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
108 the user should have some familiarity"""
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
109
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
110 debug_info=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
111 debug_error=1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
112 debug_warning=2
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
113 debug_all=3
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
114
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
115 debug_level=debug_info
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
116
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
117 OneWayAbort=0 #by default, this class uses two-way aborts, per official vxi-11 standard
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
118
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
119 def _list_packer(self, args):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
120 l=map(None, self.pack_type_list, args) # combine lists
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
121 for packer, data in l:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
122 #print "packing " + str(data) + " with " + str(packer)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
123 packer(data)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
124
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
125 def _list_unpacker(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
126 res = []
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
127 for f in self.unpack_type_list:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
128 a = f()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
129 #print "Unpacked " + str(a) + " with " + str(f)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
130 res.append(a)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
131 return res
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
132 #return [func() for func in self.unpack_type_list]
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
133
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
134 def _link_xdr_defs(self, channel):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
135 "self.link_xdr_defs() creates dictionaries of functions for packing and unpacking the various data types"
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
136 p=channel.packer
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
137 u=channel.unpacker
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
138
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
139 xdr_packer_defs={
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
140 "write": (p.pack_int, p.pack_int, p.pack_int, p.pack_int, p.pack_opaque),
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
141 "read": (p.pack_int, p.pack_int, p.pack_int, p.pack_int, p.pack_int, p.pack_int),
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
142 "create_link": (p.pack_int, p.pack_bool, p.pack_uint, p.pack_string),
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
143 "generic": (p.pack_int, p.pack_int, p.pack_int, p.pack_int),
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
144 "lock": (p.pack_int, p.pack_int, p.pack_int),
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
145 "id": (p.pack_int,)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
146 }
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
147
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
148 xdr_unpacker_defs={
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
149 "write": (u.unpack_int, u.unpack_int),
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
150 "read": (u.unpack_int, u.unpack_int, u.unpack_opaque),
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
151 # *something* is transforming pack_int to pack_uint which (obviously) doesn't like getting negative numbers
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
152 # Since LID is basically opaque unpack it as a uint to paper over the vileness
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
153 "create_link": (u.unpack_uint, u.unpack_int, u.unpack_uint, u.unpack_uint),
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
154 "read_stb":(u.unpack_int, u.unpack_int),
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
155 "error": (u.unpack_int,)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
156 }
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
157
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
158 return xdr_packer_defs, xdr_unpacker_defs
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
159
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
160 def _setup_core_packing(self, pack, unpack):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
161 #print "setting up packing with " + pack
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
162 self.pack_type_list, self.unpack_type_list=self._core_packers[pack],self._core_unpackers[unpack]
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
163 #print "pack_type_list now " + str(self.pack_type_list)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
164 #print "unpack_type_list now " + str(self.unpack_type_list)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
165
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
166 def post_init(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
167 pass
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
168
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
169 def simple_log_error(self, message, level=debug_error, file=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
170 if level <= self.debug_level:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
171 if file is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
172 file=sys.stderr
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
173 print(self.device_name, message, file=file)
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
174
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
175 def fancy_log_error(self, message, level=debug_error, file=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
176 if level <= self.debug_level:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
177 message=str(message).strip()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
178 level_str=("**INFO*****", "**ERROR****", "**WARNING**", "**DEBUG****")[level]
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
179 if file is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
180 file=sys.stderr
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
181 print(time.asctime().strip(), '\t', level_str, '\t', self.shortname, '\t', \
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
182 message.replace('\n','\n\t** ').replace('\r','\n\t** '), file=file)
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
183
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
184 def log_error(self, message, level=debug_error, file=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
185 "override log_error() for sending messages to special places or formatting differently"
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
186 self.fancy_log_error(message, level, file)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
187
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
188 def log_traceback(self, main_message='', file=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
189 exlist=traceback.format_exception(*sys.exc_info())
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
190 s=main_message+'\n'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
191 for i in exlist:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
192 s=s+i
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
193
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
194 self.log_error(s, self.debug_error, file)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
195
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
196 def log_info(self, message, file=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
197 self.log_error(message, self.debug_info, file)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
198
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
199 def log_warning(self, message, file=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
200 self.log_error(message, self.debug_warning, file)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
201
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
202 def log_debug(self, message, file=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
203 self.log_error(message, self.debug_all, file)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
204
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
205 def log_exception(self, main_message='', file=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
206 self.log_error(main_message+traceback.format_exception_only(*(sys.exc_info()[:2]))[0], self.debug_error, file)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
207
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
208 def __init__(self, host='127.0.0.1', device="inst0", timeout=1000, raise_on_err=None, device_name="Network Device", shortname=None,
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
209 portmap_proxy_host=None, portmap_proxy_port=rpc.PMAP_PORT, use_vxi_locking=True):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
210
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
211 self.raise_on_err=raise_on_err
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
212 self.lid=None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
213 self.timeout=timeout
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
214 self.device_name=device_name
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
215 self.device_sicl_name=device
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
216 self.host=host
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
217 self.portmap_proxy_host=portmap_proxy_host
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
218 self.portmap_proxy_port=portmap_proxy_port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
219 self.core=None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
220 self.abortChannel=None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
221 self.mux=None #default is no multiplexer active
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
222 self.use_vxi_locking=use_vxi_locking
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
223
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
224 if shortname is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
225 self.shortname=device_name.strip().replace(' ','').replace('\t','')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
226 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
227 self.shortname=shortname.strip().replace(' ','').replace('\t','')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
228
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
229 if threads:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
230 self.threadlock=threading.RLock()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
231
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
232 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
233 self.reconnect()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
234
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
235 except VXI_11_Transient_Error:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
236 self.log_exception("Initial connect failed... retry later")
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
237
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
238 def setup_mux(self, mux=None, global_name=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
239 self.mux=mux
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
240 self.global_mux_name=global_name
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
241
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
242 def command(self, id, pack, unpack, arglist, ignore_connect=0):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
243 #print "command() id = " + str(id) + ", pack = " + pack
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
244 if not (ignore_connect or self.connected):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
245 raise VXI_11_Device_Not_Connected
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
246
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
247 #command has been made atomic, so that things like get_status_byte can be done
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
248 #in a multi-threaded environment without needed a full vxi-11 lock to make it safe
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
249 if threads:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
250 self.threadlock.acquire() #make this atomic
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
251
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
252 self._setup_core_packing(pack, unpack)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
253
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
254 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
255 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
256 result= self.core.make_call(id, arglist, self._list_packer, self._list_unpacker)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
257 except (RuntimeError, EOFError):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
258 #RuntimeError is thrown by recvfrag if the xid is off... it means we lost data in the pipe
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
259 #EOFError is thrown if the packet isn't full length, as usually happens when ther is garbage in the pipe read as a length
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
260 #so vacuum out the socket, and raise a transient error
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
261 rlist=1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
262 ntotal=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
263 while(rlist):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
264 rlist, wlist, xlist=select.select([self.core.sock],[],[], 1.0)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
265 if rlist:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
266 ntotal+=len(self.core.sock.recv(10000) )#get some data from it
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
267 raise VXI_11_Stream_Sync_Lost("sync", ntotal)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
268 finally:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
269 if threads:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
270 self.threadlock.release() #let go
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
271
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
272 err=result[0]
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
273
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
274 if err and self.raise_on_err:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
275 e=_VXI_11_enumerated_exceptions #common, correctable exceptions
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
276 if err in e:
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
277 raise e[err](err) #raise these exceptions explicitly
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
278 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
279 raise VXI_11_Error(err) #raise generic VXI_11 exception
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
280
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
281 return result
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
282
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
283 def do_timeouts(self, timeout, lock_timeout, channel=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
284
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
285 if channel is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
286 channel=self.core
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
287
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
288 flags=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
289 if timeout is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
290 timeout=self.timeout
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
291
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
292 if not lock_timeout and hasattr(self,"default_lock_timeout"):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
293 lock_timeout=self.default_lock_timeout
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
294
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
295 if lock_timeout:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
296 flags |= 1 # append waitlock bit
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
297
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
298 if channel:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
299 channel.select_timeout_seconds=0.5+1.5*max(timeout, lock_timeout)/1000.0 #convert ms to sec, and be generous on hard timeout
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
300
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
301 return flags, timeout, lock_timeout
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
302
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
303 def reconnect(self): #recreate a broken connection
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
304 """reconnect() creates or recreates our main connection. Useful in __init__ and in complete communications breakdowns.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
305 If it throws a VXI_11_Transient_Error, the connection exists, but the check_idn() handshake or post_init() failed."""
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
306
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
307 self.connected=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
308
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
309 if self.core:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
310 self.core.close() #if this is a reconnect, break old connection the hard way
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
311 if self.abortChannel:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
312 self.abortChannel.close()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
313
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
314 self.core=rpc.TCPClient(self.host, 395183, 1,
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
315 portmap_proxy_host=self.portmap_proxy_host,
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
316 portmap_proxy_port=self.portmap_proxy_port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
317
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
318 self._core_packers, self._core_unpackers=self._link_xdr_defs(self.core) #construct xdr data type definitions for the core
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
319 #print "_core_packers now " + str(self._core_packers)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
320
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
321 err, self.lid, self.abortPort, self.maxRecvSize=self.command(
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
322 10, "create_link","create_link", (0, 0, self.timeout, self.device_sicl_name), ignore_connect=1) #execute create_link
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
323 if err: #at this stage, we always raise exceptions since there isn't any way to bail out or retry reasonably
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
324 raise VXI_11_Error(err)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
325
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
326 self.maxRecvSize=min(self.maxRecvSize, 1048576) #never transfer more than 1MB at a shot
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
327
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
328 if self.OneWayAbort:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
329 #self.abort_channel=OneWayAbortClient(self.host, 395184, 1, self.abortPort)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
330 self.abort_channel=rpc.RawUDPClient(self.host, 395184, 1, self.abortPort)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
331 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
332 self.abort_channel=RawTCPClient(self.host, 395184, 1, self.abortPort)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
333
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
334 connection_dict[self.lid]=(self.device_name, weakref.ref(self))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
335
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
336 self.locklevel=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
337
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
338 self.connected=1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
339
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
340 self.check_idn()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
341 self.post_init()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
342
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
343
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
344 def abort(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
345
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
346 self.abort_channel.select_timeout_seconds=self.timeout/1000.0 #convert to seconds
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
347 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
348 err=self.abort_channel.make_call(1, self.lid, self.abort_channel.packer.pack_int, self.abort_channel.unpacker.unpack_int) #abort
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
349 except EOFError:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
350 raise VXI_11_RPC_EOF("eof")
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
351
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
352 if err and self.raise_on_err:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
353 raise VXI_11_Error( err)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
354 return err
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
355
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
356 def disconnect(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
357 if self.connected:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
358 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
359 err, =self.command(23, "id", "error", (self.lid,)) #execute destroy_link
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
360 except:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
361 self.log_traceback() #if we can't close nicely, we'll close anyway
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
362
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
363 self.connected=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
364 del connection_dict[self.lid]
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
365 self.lid=None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
366 self.core.close()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
367 self.abort_channel.close()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
368 del self.core, self.abort_channel
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
369 self.core=None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
370 self.abortChannel=None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
371
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
372 def __del__(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
373 if self.lid is not None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
374 self.raise_on_err=0 #no exceptions here from simple errors
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
375 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
376 self.abort()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
377 except VXI_11_Error:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
378 pass
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
379 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
380 self.disconnect()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
381 except VXI_11_Error:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
382 pass
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
383
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
384
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
385
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
386 def write(self, data, timeout=None, lock_timeout=0):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
387 """err, bytes_sent=write(data [, timeout] [,lock_timeout]) sends data to device. See do_timeouts() for
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
388 semantics of timeout and lock_timeout"""
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
389
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
390 flags, timeout, lock_timeout=self.do_timeouts(timeout, lock_timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
391 base=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
392 end=len(data)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
393 while base<end:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
394 n=end-base
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
395 if n>self.maxRecvSize:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
396 xfer=self.maxRecvSize
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
397 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
398 xfer=n
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
399 flags |= 8 #write end on last byte
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
400
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
401 err, count=self.command(11, "write", "write", (self.lid, timeout, lock_timeout, flags, data[base:base+xfer]))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
402 if err: break
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
403 base+=count
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
404 return err, base
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
405
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
406 def read(self, timeout=None, lock_timeout=0, count=None, termChar=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
407 """err, reason, result=read([timeout] [,lock_timeout] [,count] [,termChar]) reads up to count bytes from the device,
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
408 ending on count, EOI or termChar (if specified). See do_timeouts() for semantics of the timeouts. \n
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
409 the returned reason is an inclusive OR of 3 bits (per the VXI-11 specs section B.6.4.device_read):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
410 Bit 2 = END/EOI received,
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
411 bit 1 = Terminating Character received,
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
412 bit 0 = full requested byte count received.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
413 """
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
414 flags, timeout, lock_timeout=self.do_timeouts(timeout, lock_timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
415
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
416 if termChar is not None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
417 flags |= 128 # append termchrset bit
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
418 act_term=termChar
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
419 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
420 act_term=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
421
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
422 accumdata=""
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
423 reason=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
424 err=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
425 accumlen=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
426
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
427 while ( (not err) and (not (reason & 6) ) and
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
428 ( (count is None) or (accumlen < count)) ): #wait for END or CHR reason flag or count
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
429
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
430 readcount=self.maxRecvSize
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
431 if count is not None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
432 readcount=min(readcount, count-accumlen)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
433 err, reason, data = self.command(12, "read","read", (self.lid, readcount, timeout, lock_timeout, flags, act_term))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
434 accumdata+=data
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
435 accumlen+=len(data)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
436 #print err, reason, len(data), len(accumdata)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
437
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
438 return err, reason, accumdata
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
439
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
440 def generic(self, code, timeout, lock_timeout):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
441 flags, timeout, lock_timeout=self.do_timeouts(timeout, lock_timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
442
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
443 err, = self.command(code, "generic", "error", (self.lid, flags, timeout, lock_timeout))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
444
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
445 return err
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
446
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
447 def trigger(self, timeout=None, lock_timeout=0):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
448 return self.generic(14, timeout, lock_timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
449
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
450 def clear(self, timeout=None, lock_timeout=0):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
451 return self.generic(15, timeout, lock_timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
452
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
453 def remote(self, timeout=None, lock_timeout=0):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
454 return self.generic(16, timeout, lock_timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
455
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
456 def local(self, timeout=None, lock_timeout=0):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
457 return self.generic(17, timeout, lock_timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
458
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
459 def read_status_byte(self, timeout=None, lock_timeout=0):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
460 flags, timeout, lock_timeout=self.do_timeouts(timeout, lock_timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
461
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
462 err, status = self.command(13, "generic","read_stb", (self.lid, flags, timeout, lock_timeout))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
463
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
464 return err, status
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
465
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
466 def lock(self, lock_timeout=0):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
467 """lock() acquires a lock on a device and the threadlock. If it fails it leaves the connection cleanly unlocked.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
468 If self.use_vxi_locking is false, it acquires only a thread lock locally, and does not really lock the vxi-11 device.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
469 This is useful if only one process is talking to a given device, and saves time."""
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
470 err=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
471 if threads:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
472 self.threadlock.acquire()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
473
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
474 if self.use_vxi_locking and self.locklevel==0:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
475 flags, timeout, lock_timeout=self.do_timeouts(0, lock_timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
476 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
477 if self.mux: self.mux.lock_connection(self.global_mux_name)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
478 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
479 err, = self.command(18, "lock","error", (self.lid, flags, lock_timeout))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
480 except:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
481 if self.mux: self.mux.unlock_connection(self.global_mux_name)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
482 raise
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
483 except:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
484 if threads:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
485 self.threadlock.release()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
486 raise
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
487
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
488 if err:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
489 if threads:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
490 self.threadlock.release()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
491 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
492 self.locklevel+=1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
493 return err
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
494
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
495 def is_locked(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
496 return self.locklevel > 0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
497
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
498 def unlock(self, priority=0):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
499 """unlock(priority=0) unwinds one level of locking, and if the level is zero, really unlocks the device.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
500 Calls to lock() and unlock() should be matched. If there is a danger that they are not, due to bad
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
501 exception handling, unlock_completely() should be used as a final cleanup for a series of operations.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
502 Setting priority to non-zero will bias the apparent last-used time in a multiplexer (if one is used),
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
503 so setting priority to -10 will effectively mark this channel least-recently-used, while setting it to
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
504 +2 will post-date the last-used time 2 seconds, so for the next 2 seconds, the device will be hard to kick
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
505 out of the channel cache (but not impossible).
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
506 """
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
507
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
508 self.locklevel-=1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
509 assert self.locklevel>=0, "Too many unlocks on device: "+self.device_name
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
510
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
511 err=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
512 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
513 if self.use_vxi_locking and self.locklevel==0:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
514 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
515 err, = self.command(19, "id", "error", (self.lid, ))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
516 finally:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
517 if self.mux:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
518 self.mux.unlock_connection(self.global_mux_name, priority) #this cannot fail, no try needed (??)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
519 elif priority and self.mux:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
520 #even on a non-final unlock, a request for changed priority is always remembered
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
521 self.mux.adjust_priority(self.global_mux_name, priority)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
522 finally:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
523 if threads:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
524 self.threadlock.release()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
525
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
526 return err
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
527
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
528 def unlock_completely(self, priority=0):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
529 "unlock_completely() forces an unwind of any locks all the way back to zero for error cleanup. Only exceptions thrown are fatal."
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
530 if threads:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
531 self.threadlock.acquire() #make sure we have the threadlock before we try a (possibly failing) full lock
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
532 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
533 self.lock() #just to be safe, we should already hold one level of lock!
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
534 except VXI_11_Locked_Elsewhere:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
535 pass #this is often called on error cleanup when we don't already have a lock, and we don't really care if we can't get it
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
536 except VXI_11_Error:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
537 self.log_exception("Unexpected trouble locking in unlock_completely(): ")
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
538
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
539 if threads:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
540 self.threadlock._RLock__count += (1-self.threadlock._RLock__count)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
541 #unwind to single lock the fast way, and make sure this variable really existed, to shield against internal changes
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
542 self.locklevel=1 #unwind our own counter, too
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
543 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
544 self.unlock(priority)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
545 except VXI_11_Device_Not_Locked:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
546 pass #if we couldn't lock above, we will probably get another exception here, and don't care
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
547 except VXI_11_Transient_Error:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
548 self.log_exception("Unexpected trouble unlocking in unlock_completely(): ")
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
549 except VXI_11_Error:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
550 self.log_exception("Unexpected trouble unlocking in unlock_completely(): ")
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
551 raise
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
552
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
553 def transaction(self, data, count=None, lock_timeout=0):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
554 """err, reason, result=transaction(data, [, count] [,lock_timeout]) sends data and waits for a response.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
555 It is guaranteed to leave the lock level at its original value on exit,
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
556 unless KeyboardInterrupt breaks the normal flow. If count isn't provided, there is no limit to how much data will be accepted.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
557 See do_timeouts() for semantics on lock_timeout."""
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
558
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
559 self.lock(lock_timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
560 reason=None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
561 result=None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
562 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
563 err, write_count = self.write(data)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
564
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
565 if not err:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
566 err, reason, result = self.read(count=count)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
567 finally:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
568 self.unlock()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
569
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
570 return err, reason, result
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
571
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
572 def check_idn(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
573 'check_idn() executes "*idn?" and aborts if the result does not start with self.idn_head'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
574 if hasattr(self,"idn"):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
575 return #already done
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
576 if hasattr(self,"idn_head") and self.idn_head is not None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
577
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
578 self.lock()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
579 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
580 self.clear()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
581 err, reason, idn = self.transaction("*idn?")
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
582 finally:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
583 self.unlock()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
584
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
585 check=idn.find(self.idn_head)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
586 self.idn=idn.strip() #save for future reference info
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
587 if check:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
588 self.disconnect()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
589 assert check==0, "Wrong device type! expecting: "+self.idn_head+"... got: "+self.idn
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
590 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
591 self.idn="Device *idn? not checked!"
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
592
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
593 import copy
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
594
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
595 class device_thread:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
596
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
597 if threads:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
598 Thread=threading.Thread #by default, use canonical threads
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
599
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
600 def __init__(self, connection, main_sleep=1.0, name="Device"):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
601 self.running=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
602 self.main_sleep=main_sleep
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
603 self.__thread=None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
604 self.__name=copy.copy(name) #make a new copy to avoid a possible circular reference
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
605 self.__wait_event=threading.Event()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
606 self.set_connection(connection)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
607
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
608 def set_connection(self, connection):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
609 #keep only a weak reference, so the thread cannot prevent the device from being deleted
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
610 #such deletion creates an error when the thread tries to run, but that's OK
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
611 #this allows the device_thread to be used as a clean mix-in class to a vxi_11 connection
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
612 self.__weak_connection=weakref.ref(connection)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
613
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
614 def connection(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
615 return self.__weak_connection() #dereference weak reference
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
616
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
617 def handle_lock_error(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
618 "handle_lock_error can be overridden to count failures and do something if there are too many"
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
619 self.connection().log_exception(self.name+": Error while locking device")
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
620
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
621 def onepass(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
622 connection=self.connection()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
623
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
624 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
625 connection.lock()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
626 except VXI_11_Transient_Error:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
627 self.handle_lock_error()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
628 return
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
629
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
630 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
631 self.get_data()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
632 except:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
633 connection.log_traceback('Uncaught exception in get_data()')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
634 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
635 connection.clear()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
636 except:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
637 connection.log_exception('failed to clear connection after error')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
638 self.run=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
639
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
640 connection.unlock()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
641
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
642 def monitor(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
643 self.connection().log_info("Monitor loop entered")
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
644 while(self.run):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
645 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
646 self.onepass()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
647 self.__wait_event.wait(self.main_sleep) #wait until timeout or we are cancelled
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
648 except KeyboardInterrupt:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
649 self.connection().log_error("Keyboard Interrupt... terminating")
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
650 self.run=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
651 except:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
652 self.connection().log_traceback()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
653 self.run=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
654
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
655 self.running=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
656 self.connection().unlock_completely()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
657
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
658 def run_thread(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
659 if not self.running: #if it's already running, just keep it up.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
660 self.run=1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
661 self.__thread=self.Thread(target=self.monitor, name=self.__name)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
662 self.__wait_event.clear() #make sure we don't fall through immediately
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
663 self.__thread.start()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
664 self.running=1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
665
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
666 def get_monitor_thread(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
667 return self.__thread
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
668
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
669 def stop_thread(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
670 if self.running:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
671 self.run=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
672 self.__wait_event.set() #cancel any waiting