/circuits/io/serial.py

https://bitbucket.org/prologic/circuits/ · Python · 168 lines · 122 code · 38 blank · 8 comment · 31 complexity · 273e3b058bbaff14552caad7e3029f0f MD5 · raw file

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