1
2 """SpecChannel module
3
4 This module defines the SpecChannel class
5 """
6
7 __author__ = 'Matias Guijarro'
8 __version__ = '1.0'
9
10 import SpecEventsDispatcher
11 import SpecWaitObject
12 import weakref
13 import types
14
15 (DOREG, DONTREG, WAITREG) = (0, 1, 2)
16
18 """SpecChannel class
19
20 Represent a channel in Spec
21
22 Signals:
23 valueChanged(channelValue, channelName) -- emitted when the channel gets updated
24 """
25 channel_aliases = {}
26
27 - def __init__(self, connection, channelName, registrationFlag = DOREG):
28 """Constructor
29
30 Arguments:
31 connection -- a SpecConnection object
32 channelName -- string representing a channel name, i.e. 'var/toto'
33
34 Keyword arguments:
35 registrationFlag -- defines how the channel is registered, possible
36 values are : SpecChannel.DOREG (default), SpecChannel.DONTREG
37 (do not register), SpecChannel.WAITREG (delayed registration until Spec is
38 reconnected)
39 """
40 self.connection = weakref.ref(connection)
41 self.name = channelName
42
43 if channelName.startswith("var/") and '/' in channelName[4:]:
44 l = channelName.split('/')
45 self.spec_chan_name = "/".join((l[0], l[1]))
46 if self.spec_chan_name in SpecChannel.channel_aliases:
47 SpecChannel.channel_aliases[self.spec_chan_name].append(self.name)
48 else:
49 SpecChannel.channel_aliases[self.spec_chan_name] = [self.name]
50
51 if len(l)==3:
52 self.access1=l[2]
53 self.access2=None
54 else:
55 self.access1=l[2]
56 self.access2=l[3]
57 else:
58 self.spec_chan_name = self.name
59 if not self.spec_chan_name in SpecChannel.channel_aliases:
60 SpecChannel.channel_aliases[self.spec_chan_name]=[self.name]
61 self.access1=None
62 self.access2=None
63 self.registrationFlag = registrationFlag
64 self.isdisconnected = True
65 self.registered = False
66 self.value = None
67
68 SpecEventsDispatcher.connect(connection, 'connected', self.connected)
69 SpecEventsDispatcher.connect(connection, 'disconnected', self.disconnected)
70
71 if connection.isSpecConnected():
72 self.connected()
73
74
76 """Do registration when Spec gets connected
77
78 If registration flag is WAITREG put the flag to DOREG if not yet connected,
79 and register if DOREG
80 """
81 if self.registrationFlag == WAITREG:
82 if self.isdisconnected:
83 self.registrationFlag = DOREG
84
85 self.isdisconnected = False
86
87 if self.registrationFlag == DOREG:
88 self.register()
89
90
92 """Reset channel object when Spec gets disconnected."""
93 self.value = None
94 self.isdisconnected = True
95
96
98 """Unregister channel."""
99 connection = self.connection()
100
101 if connection is not None:
102 connection.send_msg_unregister(self.spec_chan_name)
103 self.registered = False
104 self.value = None
105
106
108 """Register channel
109
110 Registering a channel means telling the server we want to receive
111 update events when a channel value changes on the server side.
112 """
113 connection = self.connection()
114
115 if connection is not None:
116 connection.send_msg_register(self.spec_chan_name)
117 self.registered = True
118
119
120 - def update(self, channelValue, deleted = False):
121 """Update channel's value and emit the 'valueChanged' signal."""
122 if type(channelValue) == types.DictType and self.access1 is not None:
123 if self.access1 in channelValue:
124 if deleted:
125 SpecEventsDispatcher.emit(self, 'valueChanged', (None, self.name, ))
126 else:
127 if self.access2 is None:
128 if self.value is None or self.value != channelValue[self.access1]:
129 self.value = channelValue[self.access1]
130 SpecEventsDispatcher.emit(self, 'valueChanged', (self.value, self.name, ))
131 else:
132 if self.access2 in channelValue[self.access1]:
133 if deleted:
134 SpecEventsDispatcher.emit(self, 'valueChanged', (None, self.name, ))
135 else:
136 if self.value is None or self.value != channelValue[self.access1][self.access2]:
137 self.value = channelValue[self.access1][self.access2]
138 SpecEventsDispatcher.emit(self, 'valueChanged', (self.value, self.name, ))
139 return
140
141 if type(self.value) == types.DictType and type(channelValue) == types.DictType:
142
143 if deleted:
144 for key,val in channelValue.iteritems():
145 if type(val) == types.DictType:
146 for k in val:
147 try:
148 del self.value[key][k]
149 except KeyError:
150 pass
151 if len(self.value[key])==1 and None in self.value[key]:
152 self.value[key]=self.value[key][None]
153 else:
154 try:
155 del self.value[key]
156 except KeyError:
157 pass
158 else:
159 for k1,v1 in channelValue.iteritems():
160 if type(v1)==types.DictType:
161 try:
162 self.value[k1].update(v1)
163 except KeyError:
164 self.value[k1]=v1
165 except AttributeError:
166 self.value[k1]={None: self.value[k1]}
167 self.value[k1].update(v1)
168 else:
169 if self.value.has_key(k1) and type(self.value[k1]) == types.DictType:
170 self.value[k1][None] = v1
171 else:
172 self.value[k1] = v1
173 value2emit=self.value.copy()
174 else:
175 if deleted:
176 self.value = None
177 else:
178 self.value = channelValue
179 value2emit=self.value
180
181 SpecEventsDispatcher.emit(self, 'valueChanged', (value2emit, self.name, ))
182
183
185 """Read the channel value
186
187 If channel is registered, just return the internal value,
188 else obtain the channel value and return it.
189 """
190 if self.registered and self.value is not None:
191
192
193
194
195
196 return self.value
197 else:
198 connection = self.connection()
199
200 if connection is not None:
201 w = SpecWaitObject.SpecWaitObject(connection)
202
203
204 w.waitConnection(timeout=500)
205 w.waitReply('send_msg_chan_read', (self.spec_chan_name, ))
206
207 self.update(w.value)
208
209 return self.value
210
211
213 """Write a channel value."""
214 connection = self.connection()
215
216 if connection is not None:
217 if self.access1 is not None:
218 if self.access2 is None:
219 value = { self.access1: value }
220 else:
221 value = { self.access1: { self.access2: value } }
222
223 connection.send_msg_chan_send(self.spec_chan_name, value)
224