44 @return: Time duration expressed in microsecond |
44 @return: Time duration expressed in microsecond |
45 """ |
45 """ |
46 return float(value.days * DAY + \ |
46 return float(value.days * DAY + \ |
47 value.seconds * SECOND + \ |
47 value.seconds * SECOND + \ |
48 value.microseconds) |
48 value.microseconds) |
49 return |
49 return |
50 |
50 |
51 def generate_time(value): |
51 def generate_time(value): |
52 """ |
52 """ |
53 Function converting time duration expressed in day, second and microseconds |
53 Function converting time duration expressed in day, second and microseconds |
54 into a IEC 61131 TIME literal |
54 into a IEC 61131 TIME literal |
55 @param value: Time duration to convert |
55 @param value: Time duration to convert |
56 @return: IEC 61131 TIME literal |
56 @return: IEC 61131 TIME literal |
57 """ |
57 """ |
58 microseconds = get_microseconds(value) |
58 microseconds = get_microseconds(value) |
59 |
59 |
60 # Get absolute microseconds value and save if it was negative |
60 # Get absolute microseconds value and save if it was negative |
61 negative = microseconds < 0 |
61 negative = microseconds < 0 |
62 microseconds = abs(microseconds) |
62 microseconds = abs(microseconds) |
63 |
63 |
64 # TIME literal prefix |
64 # TIME literal prefix |
65 data = "T#" |
65 data = "T#" |
66 if negative: |
66 if negative: |
67 data += "-" |
67 data += "-" |
68 |
68 |
69 # In TIME literal format, it isn't mandatory to indicate null values |
69 # In TIME literal format, it isn't mandatory to indicate null values |
70 # if no greater non-null values are available. This variable is used to |
70 # if no greater non-null values are available. This variable is used to |
71 # inhibit formatting until a non-null value is found |
71 # inhibit formatting until a non-null value is found |
72 not_null = False |
72 not_null = False |
73 |
73 |
74 for val, format in [ |
74 for val, format in [ |
75 (int(microseconds) / DAY, "%dd"), # Days |
75 (int(microseconds) / DAY, "%dd"), # Days |
76 ((int(microseconds) % DAY) / HOUR, "%dh"), # Hours |
76 ((int(microseconds) % DAY) / HOUR, "%dh"), # Hours |
77 ((int(microseconds) % HOUR) / MINUTE, "%dm"), # Minutes |
77 ((int(microseconds) % HOUR) / MINUTE, "%dm"), # Minutes |
78 ((int(microseconds) % MINUTE) / SECOND, "%ds")]: # Seconds |
78 ((int(microseconds) % MINUTE) / SECOND, "%ds")]: # Seconds |
79 |
79 |
80 # Add value to TIME literal if value is non-null or another non-null |
80 # Add value to TIME literal if value is non-null or another non-null |
81 # value have already be found |
81 # value have already be found |
82 if val > 0 or not_null: |
82 if val > 0 or not_null: |
83 data += format % val |
83 data += format % val |
84 |
84 |
85 # Update non-null variable |
85 # Update non-null variable |
86 not_null = True |
86 not_null = True |
87 |
87 |
88 # In any case microseconds have to be added to TIME literal |
88 # In any case microseconds have to be added to TIME literal |
89 data += "%gms" % (microseconds % SECOND / 1000.) |
89 data += "%gms" % (microseconds % SECOND / 1000.) |
90 |
90 |
91 return data |
91 return data |
92 |
92 |
93 def generate_date(value): |
93 def generate_date(value): |
94 """ |
94 """ |
95 Function converting time duration expressed in day, second and microseconds |
95 Function converting time duration expressed in day, second and microseconds |
114 into a IEC 61131 TIME_OF_DAY literal |
114 into a IEC 61131 TIME_OF_DAY literal |
115 @param value: Time duration to convert |
115 @param value: Time duration to convert |
116 @return: IEC 61131 TIME_OF_DAY literal |
116 @return: IEC 61131 TIME_OF_DAY literal |
117 """ |
117 """ |
118 microseconds = get_microseconds(value) |
118 microseconds = get_microseconds(value) |
119 |
119 |
120 # TIME_OF_DAY literal prefix |
120 # TIME_OF_DAY literal prefix |
121 data = "TOD#" |
121 data = "TOD#" |
122 |
122 |
123 for val, format in [ |
123 for val, format in [ |
124 (int(microseconds) / HOUR, "%2.2d:"), # Hours |
124 (int(microseconds) / HOUR, "%2.2d:"), # Hours |
125 ((int(microseconds) % HOUR) / MINUTE, "%2.2d:"), # Minutes |
125 ((int(microseconds) % HOUR) / MINUTE, "%2.2d:"), # Minutes |
126 ((int(microseconds) % MINUTE) / SECOND, "%2.2d."), # Seconds |
126 ((int(microseconds) % MINUTE) / SECOND, "%2.2d."), # Seconds |
127 (microseconds % SECOND, "%6.6d")]: # Microseconds |
127 (microseconds % SECOND, "%6.6d")]: # Microseconds |
128 |
128 |
129 # Add value to TIME_OF_DAY literal |
129 # Add value to TIME_OF_DAY literal |
130 data += format % val |
130 data += format % val |
131 |
131 |
132 return data |
132 return data |
133 |
133 |
134 # Dictionary of translation functions from value send by debugger to IEC |
134 # Dictionary of translation functions from value send by debugger to IEC |
135 # literal stored by type |
135 # literal stored by type |
136 TYPE_TRANSLATOR = { |
136 TYPE_TRANSLATOR = { |
137 "TIME": generate_time, |
137 "TIME": generate_time, |
138 "DATE": generate_date, |
138 "DATE": generate_date, |
139 "DT": generate_datetime, |
139 "DT": generate_datetime, |
152 Value update can be inhibited during the time the associated Debug Viewer is |
152 Value update can be inhibited during the time the associated Debug Viewer is |
153 refreshing |
153 refreshing |
154 """ |
154 """ |
155 |
155 |
156 class DebugDataConsumer: |
156 class DebugDataConsumer: |
157 |
157 |
158 def __init__(self): |
158 def __init__(self): |
159 """ |
159 """ |
160 Constructor |
160 Constructor |
161 """ |
161 """ |
162 # Debug value and forced flag |
162 # Debug value and forced flag |
163 self.Value = None |
163 self.Value = None |
164 self.Forced = False |
164 self.Forced = False |
165 |
165 |
166 # Store debug value and forced flag when value update is inhibited |
166 # Store debug value and forced flag when value update is inhibited |
167 self.LastValue = None |
167 self.LastValue = None |
168 self.LastForced = False |
168 self.LastForced = False |
169 |
169 |
170 # Value IEC data type |
170 # Value IEC data type |
171 self.DataType = None |
171 self.DataType = None |
172 |
172 |
173 # Flag that value update is inhibited |
173 # Flag that value update is inhibited |
174 self.Inhibited = False |
174 self.Inhibited = False |
175 |
175 |
176 def Inhibit(self, inhibit): |
176 def Inhibit(self, inhibit): |
177 """ |
177 """ |
178 Set flag to inhibit or activate value update |
178 Set flag to inhibit or activate value update |
179 @param inhibit: Inhibit flag |
179 @param inhibit: Inhibit flag |
180 """ |
180 """ |
181 # Save inhibit flag |
181 # Save inhibit flag |
182 self.Inhibited = inhibit |
182 self.Inhibited = inhibit |
183 |
183 |
184 # When reactivated update value and forced flag with stored values |
184 # When reactivated update value and forced flag with stored values |
185 if not inhibit and self.LastValue is not None: |
185 if not inhibit and self.LastValue is not None: |
186 self.SetForced(self.LastForced) |
186 self.SetForced(self.LastForced) |
187 self.SetValue(self.LastValue) |
187 self.SetValue(self.LastValue) |
188 |
188 |
189 # Reset stored values |
189 # Reset stored values |
190 self.LastValue = None |
190 self.LastValue = None |
191 self.LastForced = False |
191 self.LastForced = False |
192 |
192 |
193 def SetDataType(self, data_type): |
193 def SetDataType(self, data_type): |
194 """ |
194 """ |
195 Set value IEC data type |
195 Set value IEC data type |
196 @param data_type: Value IEC data type |
196 @param data_type: Value IEC data type |
197 """ |
197 """ |
198 self.DataType = data_type |
198 self.DataType = data_type |
199 |
199 |
200 def NewValues(self, tick, values, raw="BOOL"): |
200 def NewValues(self, tick, values, raw="BOOL"): |
201 """ |
201 """ |
202 Function called by debug thread when a new debug value is available |
202 Function called by debug thread when a new debug value is available |
203 @param tick: PLC tick when value was captured |
203 @param tick: PLC tick when value was captured |
204 @param value: Value captured |
204 @param value: Value captured |
205 @param forced: Forced flag, True if value is forced (default: False) |
205 @param forced: Forced flag, True if value is forced (default: False) |
206 @param raw: Data type of values not translated (default: 'BOOL') |
206 @param raw: Data type of values not translated (default: 'BOOL') |
207 """ |
207 """ |
208 value, forced = values |
208 value, forced = values |
209 |
209 |
210 # Translate value to IEC literal |
210 # Translate value to IEC literal |
211 if self.DataType != raw: |
211 if self.DataType != raw: |
212 value = TYPE_TRANSLATOR.get(self.DataType, str)(value) |
212 value = TYPE_TRANSLATOR.get(self.DataType, str)(value) |
213 |
213 |
214 # Store value and forced flag when value update is inhibited |
214 # Store value and forced flag when value update is inhibited |
215 if self.Inhibited: |
215 if self.Inhibited: |
216 self.LastValue = value |
216 self.LastValue = value |
217 self.LastForced = forced |
217 self.LastForced = forced |
218 |
218 |
219 # Update value and forced flag in any other case |
219 # Update value and forced flag in any other case |
220 else: |
220 else: |
221 self.SetForced(forced) |
221 self.SetForced(forced) |
222 self.SetValue(value) |
222 self.SetValue(value) |
223 |
223 |
224 def SetValue(self, value): |
224 def SetValue(self, value): |
225 """ |
225 """ |
226 Update value. |
226 Update value. |
227 May be overridden by inherited classes |
227 May be overridden by inherited classes |
228 @param value: New value |
228 @param value: New value |
229 """ |
229 """ |
230 self.Value = value |
230 self.Value = value |
231 |
231 |
232 def GetValue(self): |
232 def GetValue(self): |
233 """ |
233 """ |
234 Return current value |
234 Return current value |
235 @return: Current value |
235 @return: Current value |
236 """ |
236 """ |
237 return self.Value |
237 return self.Value |
238 |
238 |
239 def SetForced(self, forced): |
239 def SetForced(self, forced): |
240 """ |
240 """ |
241 Update Forced flag. |
241 Update Forced flag. |
242 May be overridden by inherited classes |
242 May be overridden by inherited classes |
243 @param forced: New forced flag |
243 @param forced: New forced flag |
244 """ |
244 """ |
245 self.Forced = forced |
245 self.Forced = forced |
246 |
246 |
247 def IsForced(self): |
247 def IsForced(self): |
248 """ |
248 """ |
249 Indicate if current value is forced |
249 Indicate if current value is forced |
250 @return: Current forced flag |
250 @return: Current forced flag |
251 """ |
251 """ |