view __init__.py @ 2:1e65aca0f39c

- Refactor use of struct.unpack() for greater clarity. - Fix logging of checksum errors.
author darius@midget.dons.net.au
date Mon, 29 Oct 2007 10:44:26 +1030
parents c978dbb7e4b8
children afd270964f5b
line wrap: on
line source

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):
        chint = struct.unpack('B', ch)[0]
	if (self.state == 'init'):
	    if (ch != '\x7e'):
                return

	    self.state = 'sizemsb'
            return
        
	elif (self.state == 'sizemsb'):
            self.bufszmsb = chint
            self.state = 'sizelsb'
	    return

	elif (self.state == 'sizelsb'):
	    self.bufszlsb = chint
	    self.dataleft = self.bufszmsb << 8 | self.bufszlsb
	    
	    self.state = 'data'
            return
        
	elif (self.state == 'data'):
	    self.buffer.append(chint)
            self.dataleft = self.dataleft - 1
            if (self.dataleft == 0):
                self.state = 'cksum'
            return
         
        elif (self.state == 'cksum'):
            pktsum = reduce(lambda x, y: x + y, self.buffer) & 0xff
            rxcksum = chint
            if (pktsum + rxcksum != 0xff):
                self.PrintError("Bad checksum, got 0x%02x, expected 0x%02x" %
                                rxcksum, 0xff - pktsum)
            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(),
            )