aio.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #!/usr/bin/env python3
  2. #
  3. # Python Serial Port Extension for Win32, Linux, BSD, Jython
  4. # module for serial IO for POSIX compatible systems, like Linux
  5. # see __init__.py
  6. #
  7. # (C) 2015 Chris Liechti <cliechti@gmx.net>
  8. #
  9. # SPDX-License-Identifier: BSD-3-Clause
  10. """\
  11. Support asyncio with serial ports. EXPERIMENTAL
  12. Posix platforms only, Python 3.4+ only.
  13. Windows event loops can not wait for serial ports with the current
  14. implementation. It should be possible to get that working though.
  15. """
  16. import asyncio
  17. import serial
  18. import logger
  19. class SerialTransport(asyncio.Transport):
  20. def __init__(self, loop, protocol, serial_instance):
  21. self._loop = loop
  22. self._protocol = protocol
  23. self.serial = serial_instance
  24. self._closing = False
  25. self._paused = False
  26. # XXX how to support url handlers too
  27. self.serial.timeout = 0
  28. self.serial.nonblocking()
  29. loop.call_soon(protocol.connection_made, self)
  30. # only start reading when connection_made() has been called
  31. loop.call_soon(loop.add_reader, self.serial.fd, self._read_ready)
  32. def __repr__(self):
  33. return '{self.__class__.__name__}({self._loop}, {self._protocol}, {self.serial})'.format(self=self)
  34. def close(self):
  35. if self._closing:
  36. return
  37. self._closing = True
  38. self._loop.remove_reader(self.serial.fd)
  39. self.serial.close()
  40. self._loop.call_soon(self._protocol.connection_lost, None)
  41. def _read_ready(self):
  42. data = self.serial.read(1024)
  43. if data:
  44. self._protocol.data_received(data)
  45. def write(self, data):
  46. self.serial.write(data)
  47. def can_write_eof(self):
  48. return False
  49. def pause_reading(self):
  50. if self._closing:
  51. raise RuntimeError('Cannot pause_reading() when closing')
  52. if self._paused:
  53. raise RuntimeError('Already paused')
  54. self._paused = True
  55. self._loop.remove_reader(self._sock_fd)
  56. if self._loop.get_debug():
  57. logger.debug("%r pauses reading", self)
  58. def resume_reading(self):
  59. if not self._paused:
  60. raise RuntimeError('Not paused')
  61. self._paused = False
  62. if self._closing:
  63. return
  64. self._loop.add_reader(self._sock_fd, self._read_ready)
  65. if self._loop.get_debug():
  66. logger.debug("%r resumes reading", self)
  67. #~ def set_write_buffer_limits(self, high=None, low=None):
  68. #~ def get_write_buffer_size(self):
  69. #~ def writelines(self, list_of_data):
  70. #~ def write_eof(self):
  71. #~ def abort(self):
  72. @asyncio.coroutine
  73. def create_serial_connection(loop, protocol_factory, *args, **kwargs):
  74. ser = serial.Serial(*args, **kwargs)
  75. protocol = protocol_factory()
  76. transport = SerialTransport(loop, protocol, ser)
  77. return (transport, protocol)
  78. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  79. # test
  80. if __name__ == '__main__':
  81. class Output(asyncio.Protocol):
  82. def connection_made(self, transport):
  83. self.transport = transport
  84. print('port opened', transport)
  85. transport.serial.rts = False
  86. transport.write(b'hello world\n')
  87. def data_received(self, data):
  88. print('data received', repr(data))
  89. self.transport.close()
  90. def connection_lost(self, exc):
  91. print('port closed')
  92. asyncio.get_event_loop().stop()
  93. loop = asyncio.get_event_loop()
  94. coro = create_serial_connection(loop, Output, '/dev/ttyUSB0', baudrate=115200)
  95. loop.run_until_complete(coro)
  96. loop.run_forever()
  97. loop.close()