1
1
import logging
2
2
import numpy as np
3
-
3
+ import collections
4
4
from p4p .client .thread import Context , Disconnected
5
5
from p4p .wrapper import Value
6
6
from .pva_codec import decompress
@@ -19,7 +19,6 @@ def __init__(self, channel: PyDMChannel, address: str,
19
19
protocol : Optional [str ] = None , parent : Optional [QObject ] = None ):
20
20
"""
21
21
Manages the connection to a channel using the P4P library. A given channel can have multiple listeners.
22
-
23
22
Parameters
24
23
----------
25
24
channel : PyDMChannel
@@ -33,7 +32,7 @@ def __init__(self, channel: PyDMChannel, address: str,
33
32
"""
34
33
super ().__init__ (channel , address , protocol , parent )
35
34
self ._connected = False
36
- self .monitor = P4PPlugin .context .monitor (name = address ,
35
+ self .monitor = P4PPlugin .context .monitor (name = self . address ,
37
36
cb = self .send_new_value ,
38
37
notify_disconnect = True )
39
38
self .add_listener (channel )
@@ -49,6 +48,7 @@ def __init__(self, channel: PyDMChannel, address: str,
49
48
self ._upper_warning_limit = None
50
49
self ._lower_warning_limit = None
51
50
self ._timestamp = None
51
+ self .nttable_data_location = PyDMPlugin .get_subfield (channel )
52
52
53
53
def clear_cache (self ) -> None :
54
54
""" Clear out all the stored values of this connection. """
@@ -65,6 +65,8 @@ def clear_cache(self) -> None:
65
65
self ._lower_warning_limit = None
66
66
self ._timestamp = None
67
67
68
+ self .nttable_data_location = None
69
+
68
70
def send_new_value (self , value : Value ) -> None :
69
71
""" Callback invoked whenever a new value is received by our monitor. Emits signals based on values changed. """
70
72
if isinstance (value , Disconnected ):
@@ -79,9 +81,45 @@ def send_new_value(self, value: Value) -> None:
79
81
self .write_access_signal .emit (True )
80
82
81
83
self ._value = value
84
+ has_value_changed_yet = False
82
85
for changed_value in value .changedSet ():
83
- if changed_value == 'value' :
84
- new_value = value .value
86
+ if changed_value == 'value' or changed_value .split ('.' )[0 ] == 'value' :
87
+ # NTTable has a changedSet item for each column that has changed
88
+ # Since we want to send an update on any table change, let's track
89
+ # if the value item has been updated yet
90
+ if has_value_changed_yet :
91
+ continue
92
+ else :
93
+ has_value_changed_yet = True
94
+
95
+ if 'NTTable' in value .getID ():
96
+ new_value = value .value .todict ()
97
+ else :
98
+ new_value = value .value
99
+
100
+ if self .nttable_data_location :
101
+ msg = f"Invalid channel... { self .nttable_data_location } "
102
+
103
+ for value in self .nttable_data_location :
104
+ if isinstance (new_value , collections .Container ) and not isinstance (new_value , str ):
105
+
106
+ if type (value ) == str :
107
+ try :
108
+ new_value = new_value [value ]
109
+ continue
110
+ except TypeError :
111
+ logger .debug ('Type Error when attempting to use the given key, code will next attempt to convert the key to an int' )
112
+ except KeyError :
113
+ logger .exception (msg )
114
+
115
+ try :
116
+ new_value = new_value [int (value )]
117
+ except ValueError :
118
+ logger .exception (msg , exc_info = True )
119
+ else :
120
+ logger .exception (msg , exc_info = True )
121
+ raise ValueError (msg )
122
+
85
123
if new_value is not None :
86
124
if isinstance (new_value , np .ndarray ):
87
125
if 'NTNDArray' in value .getID ():
@@ -95,6 +133,8 @@ def send_new_value(self, value: Value) -> None:
95
133
self .new_value_signal [int ].emit (new_value )
96
134
elif isinstance (new_value , str ):
97
135
self .new_value_signal [str ].emit (new_value )
136
+ elif isinstance (new_value , dict ):
137
+ self .new_value_signal [dict ].emit (new_value )
98
138
else :
99
139
raise ValueError (f'No matching signal for value: { new_value } with type: { type (new_value )} ' )
100
140
# Sometimes unchanged control variables appear to be returned with value changes, so checking against
@@ -149,7 +189,6 @@ def put_value(self, value):
149
189
def add_listener (self , channel : PyDMChannel ):
150
190
"""
151
191
Adds a listener to this connection, connecting the appropriate signals/slots to the input PyDMChannel.
152
-
153
192
Parameters
154
193
----------
155
194
channel : PyDMChannel
@@ -183,6 +222,10 @@ def add_listener(self, channel: PyDMChannel):
183
222
channel .value_signal [np .ndarray ].connect (self .put_value , Qt .QueuedConnection )
184
223
except KeyError :
185
224
pass
225
+ try :
226
+ channel .value_signal [dict ].connect (self .put_value , Qt .QueuedConnection )
227
+ except KeyError :
228
+ pass
186
229
187
230
def close (self ):
188
231
""" Closes out this connection. """
0 commit comments