annotate vxi_11.py @ 75:576f112e0aba

Fix read timeout handling so it works over imperfect links.
author Daniel O'Connor <doconnor@gsoft.com.au>
date Fri, 27 Sep 2024 09:27:33 +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