changeset 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 93b375e93fe1
files __init__.py
diffstat 1 files changed, 271 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/__init__.py	Sun Oct 28 11:08:38 2007 +1030
@@ -0,0 +1,271 @@
+import eg
+
+class PluginInfo(eg.PluginInfo):
+    name = "ZigBee"
+    author = "Darius"
+    version = "1.0.0"
+    description = "Listen for data from a Max Stream ZigBee module"
+
+
+    
+class Text:
+    port = "Port:"
+    baudrate = "Baudrate:"
+    bytesize = "Number of bits:"
+    parity = "Parity:"
+    parities = ['No parity', 'Odd', 'Even'] #, 'Mark', 'Space']
+    stopbits = "Stopbits:"
+    flowcontrol = "Flow control:"
+    handshakes = ['None', 'Xon / Xoff', 'Hardware']
+    generateEvents = "Generate events on incoming data"
+    eventPrefix = "Event prefix:"
+
+
+import wx
+import threading
+import win32event
+import win32file
+import struct
+
+class Serial(eg.RawReceiverPlugin):
+    canMultiLoad = True
+    text = Text
+    
+    def __init__(self):
+        eg.RawReceiverPlugin.__init__(self)
+        self.serial = None
+        self.buffer = []
+        self.state = 'init'
+
+    def __start__(
+        self, 
+        port, 
+        baudrate,
+        bytesize=8,
+        parity=0,
+        stopbits=0,
+        handshake=0,
+        generateEvents=False,
+        prefix="Serial",
+    ):
+        xonxoff = 0
+        rtscts = 0
+        if handshake == 1:
+            xonxoff = 1
+        elif handshake == 2:
+            rtscts = 1
+            
+        try:
+            self.serial = eg.SerialPort(
+                port, 
+                baudrate=baudrate, 
+                bytesize=(5, 6, 7, 8)[bytesize],
+                stopbits=(1, 2)[stopbits],
+                parity=('N', 'O', 'E')[parity],
+                xonxoff=xonxoff,
+                rtscts=rtscts,
+            )
+        except:
+            self.serial = None
+            raise eg.Exception("Can't open COM port.")
+        self.serial.timeout = 1.0
+        self.serial.setRTS()
+        self.info.eventPrefix = prefix
+        self.stopEvent = win32event.CreateEvent(None, 1, 0, None)
+        self.receiveThread = threading.Thread(target=self.ReceiveThread)
+        self.receiveThread.start()
+
+    def __stop__(self):
+        if self.serial is not None:
+            if self.receiveThread:
+                win32event.SetEvent(self.stopEvent)
+                self.receiveThread.join(1.0)
+            self.serial.close()
+            self.serial = None
+
+
+    def HandleChar(self, ch):
+	if (self.state == 'init'):
+	    if (ch != '\x7e'):
+                return
+
+	    self.state = 'sizemsb'
+            return
+        
+	elif (self.state == 'sizemsb'):
+            self.bufszmsb = struct.unpack('B', ch)[0]
+            self.state = 'sizelsb'
+	    return
+
+	elif (self.state == 'sizelsb'):
+	    self.bufszlsb = struct.unpack('B', ch)[0]
+	    self.dataleft = self.bufszmsb << 8 | self.bufszlsb
+	    
+	    self.state = 'data'
+            return
+        
+	elif (self.state == 'data'):
+	    self.buffer.append(struct.unpack('B', ch)[0])
+            self.dataleft = self.dataleft - 1
+            if (self.dataleft == 0):
+                self.state = 'cksum'
+            return
+         
+        elif (self.state == 'cksum'):
+            cksum = reduce(lambda x, y: x + y, self.buffer) & 0xff
+            rxcksum = struct.unpack('B', ch)[0]
+            if (cksum + rxcksum != 0xff):
+                self.PrintError("Bad checksum, got 0x%02x, expected 0x%02x" %
+                                cksum, 0xff - cksum)
+            else:
+                self.PrintError("Triggered event: " + str(self.buffer))
+                self.TriggerEvent(str(self.buffer))
+            self.buffer = []
+            self.state = 'init'
+            return
+        else:
+            self.PrintError("Internal error: bad state: " + str(self.state))
+            self.state = 'init'
+            
+    def ReceiveThread(self):
+        from win32event import (
+            ResetEvent, 
+            MsgWaitForMultipleObjects, 
+            QS_ALLINPUT, 
+            WAIT_OBJECT_0, 
+            WAIT_TIMEOUT,
+        )
+        from win32file import ReadFile, AllocateReadBuffer, GetOverlappedResult
+        from win32api import GetLastError
+
+        continueLoop = True
+        overlapped = self.serial._overlappedRead
+        hComPort = self.serial.hComPort
+        hEvent = overlapped.hEvent
+        stopEvent = self.stopEvent
+        n = 1
+        waitingOnRead = False
+        buf = AllocateReadBuffer(n)
+        while continueLoop:
+            if not waitingOnRead:
+                ResetEvent(hEvent)
+                hr, _ = ReadFile(hComPort, buf, overlapped)
+                if hr == 997:
+                    waitingOnRead = True
+                elif hr == 0:
+                    pass
+                    #n = GetOverlappedResult(hComPort, overlapped, 1)
+                    #self.HandleChar(str(buf))
+                else:
+                    self.PrintError("error")
+                    raise
+
+            rc = MsgWaitForMultipleObjects(
+                (hEvent, stopEvent),
+                0, 
+                1000, 
+                QS_ALLINPUT
+            )
+            if rc == WAIT_OBJECT_0:
+                n = GetOverlappedResult(hComPort, overlapped, 1)
+                if n:
+                    self.HandleChar(str(buf))
+                #else:
+                #    print "WAIT_OBJECT_0", n, str(buf[:n])
+                waitingOnRead = False
+            elif rc == WAIT_OBJECT_0+1:
+                continueLoop = False
+            elif rc == WAIT_TIMEOUT:
+                pass
+            else:
+                self.PrintError("unknown message")
+                
+            
+    def Configure(
+        self, 
+        port=0, 
+        baudrate=9600,
+        bytesize=8,
+        parity=0,
+        stopbits=0,
+        handshake=0,
+        generateEvents=False,
+        prefix="Serial",
+    ):
+        text = self.text
+        dialog = eg.ConfigurationDialog(self)
+        portCtrl = eg.SerialPortChoice(dialog, value=port)
+        
+        baudrateCtrl = wx.ComboBox(
+            dialog,
+            value=str(baudrate),
+            choices=[
+                        '110', '300', '600', '1200', '2400', '4800', '9600',
+                        '14400', '19200', '38400', '57600', '115200', 
+                        '128000', '256000'
+                    ],
+            style=wx.CB_DROPDOWN,
+            validator=eg.DigitOnlyValidator()
+        )
+        
+        bytesizeCtrl = wx.Choice(dialog, choices=['5', '6', '7', '8'])
+        bytesizeCtrl.SetSelection(8 - 5)
+        
+        parityCtrl = wx.Choice(dialog, choices=text.parities)
+        parityCtrl.SetSelection(parity)
+        
+        stopbitsCtrl = wx.Choice(dialog, choices=['1', '2'])
+        stopbitsCtrl.SetSelection(stopbits)
+        
+        handshakeCtrl = wx.Choice(dialog, choices=text.handshakes)
+        handshakeCtrl.SetSelection(handshake)
+        
+        generateEventsCtrl = wx.CheckBox(dialog, label=text.generateEvents)
+        generateEventsCtrl.SetValue(generateEvents)
+        
+        prefixCtrl = wx.TextCtrl(dialog)
+        prefixCtrl.SetValue(prefix)
+        prefixCtrl.Enable(generateEvents)
+        
+        def OnCheckBox(event):
+            flag = generateEventsCtrl.GetValue()
+            prefixCtrl.Enable(flag)
+        generateEventsCtrl.Bind(wx.EVT_CHECKBOX, OnCheckBox)
+        
+        flags = wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL
+        mySizer = wx.GridBagSizer(5, 5)
+        Add = mySizer.Add
+        Add(wx.StaticText(dialog, -1, text.port), (0, 0), flag=flags)
+        Add(portCtrl, (0, 1), flag=wx.EXPAND)
+        Add(wx.StaticText(dialog, -1, text.baudrate), (1, 0), flag=flags)
+        Add(baudrateCtrl, (1, 1), flag=wx.EXPAND)
+        Add(wx.StaticText(dialog, -1, text.bytesize), (2, 0), flag=flags)
+        Add(bytesizeCtrl, (2, 1), flag=wx.EXPAND)
+        Add(wx.StaticText(dialog, -1, text.parity), (3, 0), flag=flags)
+        Add(parityCtrl, (3, 1), flag=wx.EXPAND)
+        Add(wx.StaticText(dialog, -1, text.stopbits), (4, 0), flag=flags)
+        Add(stopbitsCtrl, (4, 1), flag=wx.EXPAND)
+        Add(wx.StaticText(dialog, -1, text.flowcontrol), (5, 0), flag=flags)
+        Add(handshakeCtrl, (5, 1), flag=wx.EXPAND)
+        
+        Add((5, 5), (6, 0), (1, 2), flag=flags)
+        Add(generateEventsCtrl, (7, 0), (1, 2), flag=flags)
+        Add(wx.StaticText(dialog, -1, text.eventPrefix), (9, 0), flag=flags)
+        Add(prefixCtrl, (9, 1), flag=wx.EXPAND)
+        dialog.sizer.Add(mySizer)
+
+        if dialog.AffirmedShowModal():
+            return (
+                portCtrl.GetValue(), 
+                int(baudrateCtrl.GetValue()),
+                bytesizeCtrl.GetSelection(),
+                parityCtrl.GetSelection(),
+                stopbitsCtrl.GetSelection(),
+                handshakeCtrl.GetSelection(),
+                generateEventsCtrl.GetValue(),
+                prefixCtrl.GetValue(),
+            )
+        
+        
+        
+