Mercurial > ~darius > hgwebdir.cgi > EG-ZigBee
comparison __init__.py @ 0:c978dbb7e4b8
Commit first version of plugin to parse events from MaxStream ZigBee modules.
At the moment it is not very configurable and only listens for evens from
remote modules set up to send IO events.
author | darius@inchoate.localdomain |
---|---|
date | Sun, 28 Oct 2007 11:08:38 +1030 |
parents | |
children | 1e65aca0f39c |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c978dbb7e4b8 |
---|---|
1 import eg | |
2 | |
3 class PluginInfo(eg.PluginInfo): | |
4 name = "ZigBee" | |
5 author = "Darius" | |
6 version = "1.0.0" | |
7 description = "Listen for data from a Max Stream ZigBee module" | |
8 | |
9 | |
10 | |
11 class Text: | |
12 port = "Port:" | |
13 baudrate = "Baudrate:" | |
14 bytesize = "Number of bits:" | |
15 parity = "Parity:" | |
16 parities = ['No parity', 'Odd', 'Even'] #, 'Mark', 'Space'] | |
17 stopbits = "Stopbits:" | |
18 flowcontrol = "Flow control:" | |
19 handshakes = ['None', 'Xon / Xoff', 'Hardware'] | |
20 generateEvents = "Generate events on incoming data" | |
21 eventPrefix = "Event prefix:" | |
22 | |
23 | |
24 import wx | |
25 import threading | |
26 import win32event | |
27 import win32file | |
28 import struct | |
29 | |
30 class Serial(eg.RawReceiverPlugin): | |
31 canMultiLoad = True | |
32 text = Text | |
33 | |
34 def __init__(self): | |
35 eg.RawReceiverPlugin.__init__(self) | |
36 self.serial = None | |
37 self.buffer = [] | |
38 self.state = 'init' | |
39 | |
40 def __start__( | |
41 self, | |
42 port, | |
43 baudrate, | |
44 bytesize=8, | |
45 parity=0, | |
46 stopbits=0, | |
47 handshake=0, | |
48 generateEvents=False, | |
49 prefix="Serial", | |
50 ): | |
51 xonxoff = 0 | |
52 rtscts = 0 | |
53 if handshake == 1: | |
54 xonxoff = 1 | |
55 elif handshake == 2: | |
56 rtscts = 1 | |
57 | |
58 try: | |
59 self.serial = eg.SerialPort( | |
60 port, | |
61 baudrate=baudrate, | |
62 bytesize=(5, 6, 7, 8)[bytesize], | |
63 stopbits=(1, 2)[stopbits], | |
64 parity=('N', 'O', 'E')[parity], | |
65 xonxoff=xonxoff, | |
66 rtscts=rtscts, | |
67 ) | |
68 except: | |
69 self.serial = None | |
70 raise eg.Exception("Can't open COM port.") | |
71 self.serial.timeout = 1.0 | |
72 self.serial.setRTS() | |
73 self.info.eventPrefix = prefix | |
74 self.stopEvent = win32event.CreateEvent(None, 1, 0, None) | |
75 self.receiveThread = threading.Thread(target=self.ReceiveThread) | |
76 self.receiveThread.start() | |
77 | |
78 def __stop__(self): | |
79 if self.serial is not None: | |
80 if self.receiveThread: | |
81 win32event.SetEvent(self.stopEvent) | |
82 self.receiveThread.join(1.0) | |
83 self.serial.close() | |
84 self.serial = None | |
85 | |
86 | |
87 def HandleChar(self, ch): | |
88 if (self.state == 'init'): | |
89 if (ch != '\x7e'): | |
90 return | |
91 | |
92 self.state = 'sizemsb' | |
93 return | |
94 | |
95 elif (self.state == 'sizemsb'): | |
96 self.bufszmsb = struct.unpack('B', ch)[0] | |
97 self.state = 'sizelsb' | |
98 return | |
99 | |
100 elif (self.state == 'sizelsb'): | |
101 self.bufszlsb = struct.unpack('B', ch)[0] | |
102 self.dataleft = self.bufszmsb << 8 | self.bufszlsb | |
103 | |
104 self.state = 'data' | |
105 return | |
106 | |
107 elif (self.state == 'data'): | |
108 self.buffer.append(struct.unpack('B', ch)[0]) | |
109 self.dataleft = self.dataleft - 1 | |
110 if (self.dataleft == 0): | |
111 self.state = 'cksum' | |
112 return | |
113 | |
114 elif (self.state == 'cksum'): | |
115 cksum = reduce(lambda x, y: x + y, self.buffer) & 0xff | |
116 rxcksum = struct.unpack('B', ch)[0] | |
117 if (cksum + rxcksum != 0xff): | |
118 self.PrintError("Bad checksum, got 0x%02x, expected 0x%02x" % | |
119 cksum, 0xff - cksum) | |
120 else: | |
121 self.PrintError("Triggered event: " + str(self.buffer)) | |
122 self.TriggerEvent(str(self.buffer)) | |
123 self.buffer = [] | |
124 self.state = 'init' | |
125 return | |
126 else: | |
127 self.PrintError("Internal error: bad state: " + str(self.state)) | |
128 self.state = 'init' | |
129 | |
130 def ReceiveThread(self): | |
131 from win32event import ( | |
132 ResetEvent, | |
133 MsgWaitForMultipleObjects, | |
134 QS_ALLINPUT, | |
135 WAIT_OBJECT_0, | |
136 WAIT_TIMEOUT, | |
137 ) | |
138 from win32file import ReadFile, AllocateReadBuffer, GetOverlappedResult | |
139 from win32api import GetLastError | |
140 | |
141 continueLoop = True | |
142 overlapped = self.serial._overlappedRead | |
143 hComPort = self.serial.hComPort | |
144 hEvent = overlapped.hEvent | |
145 stopEvent = self.stopEvent | |
146 n = 1 | |
147 waitingOnRead = False | |
148 buf = AllocateReadBuffer(n) | |
149 while continueLoop: | |
150 if not waitingOnRead: | |
151 ResetEvent(hEvent) | |
152 hr, _ = ReadFile(hComPort, buf, overlapped) | |
153 if hr == 997: | |
154 waitingOnRead = True | |
155 elif hr == 0: | |
156 pass | |
157 #n = GetOverlappedResult(hComPort, overlapped, 1) | |
158 #self.HandleChar(str(buf)) | |
159 else: | |
160 self.PrintError("error") | |
161 raise | |
162 | |
163 rc = MsgWaitForMultipleObjects( | |
164 (hEvent, stopEvent), | |
165 0, | |
166 1000, | |
167 QS_ALLINPUT | |
168 ) | |
169 if rc == WAIT_OBJECT_0: | |
170 n = GetOverlappedResult(hComPort, overlapped, 1) | |
171 if n: | |
172 self.HandleChar(str(buf)) | |
173 #else: | |
174 # print "WAIT_OBJECT_0", n, str(buf[:n]) | |
175 waitingOnRead = False | |
176 elif rc == WAIT_OBJECT_0+1: | |
177 continueLoop = False | |
178 elif rc == WAIT_TIMEOUT: | |
179 pass | |
180 else: | |
181 self.PrintError("unknown message") | |
182 | |
183 | |
184 def Configure( | |
185 self, | |
186 port=0, | |
187 baudrate=9600, | |
188 bytesize=8, | |
189 parity=0, | |
190 stopbits=0, | |
191 handshake=0, | |
192 generateEvents=False, | |
193 prefix="Serial", | |
194 ): | |
195 text = self.text | |
196 dialog = eg.ConfigurationDialog(self) | |
197 portCtrl = eg.SerialPortChoice(dialog, value=port) | |
198 | |
199 baudrateCtrl = wx.ComboBox( | |
200 dialog, | |
201 value=str(baudrate), | |
202 choices=[ | |
203 '110', '300', '600', '1200', '2400', '4800', '9600', | |
204 '14400', '19200', '38400', '57600', '115200', | |
205 '128000', '256000' | |
206 ], | |
207 style=wx.CB_DROPDOWN, | |
208 validator=eg.DigitOnlyValidator() | |
209 ) | |
210 | |
211 bytesizeCtrl = wx.Choice(dialog, choices=['5', '6', '7', '8']) | |
212 bytesizeCtrl.SetSelection(8 - 5) | |
213 | |
214 parityCtrl = wx.Choice(dialog, choices=text.parities) | |
215 parityCtrl.SetSelection(parity) | |
216 | |
217 stopbitsCtrl = wx.Choice(dialog, choices=['1', '2']) | |
218 stopbitsCtrl.SetSelection(stopbits) | |
219 | |
220 handshakeCtrl = wx.Choice(dialog, choices=text.handshakes) | |
221 handshakeCtrl.SetSelection(handshake) | |
222 | |
223 generateEventsCtrl = wx.CheckBox(dialog, label=text.generateEvents) | |
224 generateEventsCtrl.SetValue(generateEvents) | |
225 | |
226 prefixCtrl = wx.TextCtrl(dialog) | |
227 prefixCtrl.SetValue(prefix) | |
228 prefixCtrl.Enable(generateEvents) | |
229 | |
230 def OnCheckBox(event): | |
231 flag = generateEventsCtrl.GetValue() | |
232 prefixCtrl.Enable(flag) | |
233 generateEventsCtrl.Bind(wx.EVT_CHECKBOX, OnCheckBox) | |
234 | |
235 flags = wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL | |
236 mySizer = wx.GridBagSizer(5, 5) | |
237 Add = mySizer.Add | |
238 Add(wx.StaticText(dialog, -1, text.port), (0, 0), flag=flags) | |
239 Add(portCtrl, (0, 1), flag=wx.EXPAND) | |
240 Add(wx.StaticText(dialog, -1, text.baudrate), (1, 0), flag=flags) | |
241 Add(baudrateCtrl, (1, 1), flag=wx.EXPAND) | |
242 Add(wx.StaticText(dialog, -1, text.bytesize), (2, 0), flag=flags) | |
243 Add(bytesizeCtrl, (2, 1), flag=wx.EXPAND) | |
244 Add(wx.StaticText(dialog, -1, text.parity), (3, 0), flag=flags) | |
245 Add(parityCtrl, (3, 1), flag=wx.EXPAND) | |
246 Add(wx.StaticText(dialog, -1, text.stopbits), (4, 0), flag=flags) | |
247 Add(stopbitsCtrl, (4, 1), flag=wx.EXPAND) | |
248 Add(wx.StaticText(dialog, -1, text.flowcontrol), (5, 0), flag=flags) | |
249 Add(handshakeCtrl, (5, 1), flag=wx.EXPAND) | |
250 | |
251 Add((5, 5), (6, 0), (1, 2), flag=flags) | |
252 Add(generateEventsCtrl, (7, 0), (1, 2), flag=flags) | |
253 Add(wx.StaticText(dialog, -1, text.eventPrefix), (9, 0), flag=flags) | |
254 Add(prefixCtrl, (9, 1), flag=wx.EXPAND) | |
255 dialog.sizer.Add(mySizer) | |
256 | |
257 if dialog.AffirmedShowModal(): | |
258 return ( | |
259 portCtrl.GetValue(), | |
260 int(baudrateCtrl.GetValue()), | |
261 bytesizeCtrl.GetSelection(), | |
262 parityCtrl.GetSelection(), | |
263 stopbitsCtrl.GetSelection(), | |
264 handshakeCtrl.GetSelection(), | |
265 generateEventsCtrl.GetValue(), | |
266 prefixCtrl.GetValue(), | |
267 ) | |
268 | |
269 | |
270 | |
271 |