PageRenderTime 34ms CodeModel.GetById 2ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 0ms

/circuits/io/serial.py

https://bitbucket.org/prologic/circuits/
Python | 168 lines | 122 code | 38 blank | 8 comment | 29 complexity | 273e3b058bbaff14552caad7e3029f0f MD5 | raw file
  1# Module:   serial
  2# Date:     4th August 2004
  3# Author:   James Mills <prologic@shortcircuit.net.au>
  4
  5"""Serial I/O
  6
  7This module implements basic Serial (RS232) I/O.
  8"""
  9
 10import os
 11import select
 12from collections import deque
 13
 14from circuits.core import Component, handler, Event
 15from circuits.core.pollers import BasePoller, Poller
 16from circuits.core.utils import findcmp
 17from circuits.tools import tryimport
 18from circuits.six import binary_type, string_types
 19
 20from .events import closed, error, opened, read, ready, close
 21
 22serial = tryimport("serial")
 23
 24TIMEOUT = 0.2
 25BUFSIZE = 4096
 26
 27
 28class _open(Event):
 29    """_open Event"""
 30
 31
 32class Serial(Component):
 33
 34    channel = "serial"
 35
 36    def __init__(self, port, baudrate=115200, bufsize=BUFSIZE,
 37                 timeout=TIMEOUT, channel=channel):
 38        super(Serial, self).__init__(channel=channel)
 39
 40        if serial is None:
 41            raise RuntimeError("No serial support available")
 42
 43        self._port = port
 44        self._baudrate = baudrate
 45        self._bufsize = bufsize
 46
 47        self._serial = None
 48        self._poller = None
 49        self._buffer = deque()
 50        self._closeflag = False
 51
 52    @handler("ready")
 53    def _on_ready(self, component):
 54        self.fire(_open(), self.channel)
 55
 56    @handler("_open")
 57    def _on_open(self, port=None, baudrate=None, bufsize=None):
 58        self._port = port or self._port
 59        self._baudrate = baudrate or self._baudrate
 60        self._bufsize = bufsize or self._bufsize
 61
 62        self._serial = serial.Serial(port=self._port, baudrate=self._baudrate, timeout=0)
 63        self._fd = self._serial.fileno()  # not portable!
 64
 65        self._poller.addReader(self, self._fd)
 66
 67        self.fire(opened(self._port, self._baudrate))
 68
 69    @handler("registered", "started", channel="*")
 70    def _on_registered_or_started(self, component, manager=None):
 71        if self._poller is None:
 72            if isinstance(component, BasePoller):
 73                self._poller = component
 74                self.fire(ready(self))
 75            else:
 76                if component is not self:
 77                    return
 78                component = findcmp(self.root, BasePoller)
 79                if component is not None:
 80                    self._poller = component
 81                    self.fire(ready(self))
 82                else:
 83                    self._poller = Poller().register(self)
 84                    self.fire(ready(self))
 85
 86    @handler("stopped", channel="*")
 87    def _on_stopped(self, component):
 88        self.fire(close())
 89
 90    @handler("prepare_unregister", channel="*")
 91    def _on_prepare_unregister(self, event, c):
 92        if event.in_subtree(self):
 93            self._close()
 94
 95    def _close(self):
 96        if self._closeflag:
 97            return
 98
 99        self._poller.discard(self._fd)
100
101        self._buffer.clear()
102        self._closeflag = False
103        self._connected = False
104
105        try:
106            self._serial.close()
107        except:
108            pass
109
110        self.fire(closed())
111
112    def close(self):
113        if not self._buffer:
114            self._close()
115        elif not self._closeflag:
116            self._closeflag = True
117
118    def _read(self):
119        try:
120            data = self._serial.read(self._bufsize)
121            if not isinstance(data, binary_type):
122                data = data.encode(self._encoding)
123
124            if data:
125                self.fire(read(data)).notify = True
126        except (OSError, IOError) as e:
127            self.fire(error(e))
128            self._close()
129
130    def _write(self, data):
131        try:
132            if not isinstance(data, binary_type):
133                data = data.encode(self._encoding)
134
135            try:
136                nbytes = self._serial.write(data)
137            except (serial.SerialTimeoutException) as e:
138                nbytes = 0
139            if nbytes < len(data):
140                self._buffer.appendleft(data[nbytes:])
141        except (OSError, IOError) as e:
142            self.fire(error(e))
143            self._close()
144
145    def write(self, data):
146        if self._poller is not None and not self._poller.isWriting(self._fd):
147            self._poller.addWriter(self, self._fd)
148        self._buffer.append(data)
149
150    @handler("_disconnect")
151    def __on_disconnect(self, sock):
152        self._close()
153
154    @handler("_read")
155    def __on_read(self, sock):
156        self._read()
157
158    @handler("_write")
159    def __on_write(self, sock):
160        if self._buffer:
161            data = self._buffer.popleft()
162            self._write(data)
163
164        if not self._buffer:
165            if self._closeflag:
166                self._close()
167            elif self._poller.isWriting(self._fd):
168                self._poller.removeWriter(self._fd)