blob: 2a93dc9adfc3774add87858282793c89098b1eba [file] [log] [blame]
Chris Liechtid07a9e72015-08-22 02:58:47 +02001#!/usr/bin/env python3
2#
Chris Liechti3e02f702015-12-16 23:06:04 +01003# Experimental implementation of asyncio support.
Chris Liechtid07a9e72015-08-22 02:58:47 +02004#
Chris Liechti3e02f702015-12-16 23:06:04 +01005# This file is part of pySerial. https://github.com/pyserial/pyserial
Chris Liechtid07a9e72015-08-22 02:58:47 +02006# (C) 2015 Chris Liechti <cliechti@gmx.net>
7#
8# SPDX-License-Identifier: BSD-3-Clause
9"""\
10Support asyncio with serial ports. EXPERIMENTAL
11
12Posix platforms only, Python 3.4+ only.
13
14Windows event loops can not wait for serial ports with the current
15implementation. It should be possible to get that working though.
16"""
17import asyncio
18import serial
Chris Liechtifc011102015-11-18 00:38:19 +010019import logging
Chris Liechti033f17c2015-08-30 21:28:04 +020020
Chris Liechtid07a9e72015-08-22 02:58:47 +020021
22class SerialTransport(asyncio.Transport):
23 def __init__(self, loop, protocol, serial_instance):
24 self._loop = loop
25 self._protocol = protocol
26 self.serial = serial_instance
27 self._closing = False
28 self._paused = False
29 # XXX how to support url handlers too
30 self.serial.timeout = 0
31 self.serial.nonblocking()
32 loop.call_soon(protocol.connection_made, self)
33 # only start reading when connection_made() has been called
34 loop.call_soon(loop.add_reader, self.serial.fd, self._read_ready)
35
36 def __repr__(self):
37 return '{self.__class__.__name__}({self._loop}, {self._protocol}, {self.serial})'.format(self=self)
38
39 def close(self):
40 if self._closing:
41 return
42 self._closing = True
43 self._loop.remove_reader(self.serial.fd)
44 self.serial.close()
45 self._loop.call_soon(self._protocol.connection_lost, None)
46
47 def _read_ready(self):
48 data = self.serial.read(1024)
49 if data:
50 self._protocol.data_received(data)
51
52 def write(self, data):
53 self.serial.write(data)
54
55 def can_write_eof(self):
56 return False
57
58 def pause_reading(self):
59 if self._closing:
60 raise RuntimeError('Cannot pause_reading() when closing')
61 if self._paused:
62 raise RuntimeError('Already paused')
63 self._paused = True
64 self._loop.remove_reader(self._sock_fd)
65 if self._loop.get_debug():
Chris Liechtifc011102015-11-18 00:38:19 +010066 logging.debug("%r pauses reading", self)
Chris Liechtid07a9e72015-08-22 02:58:47 +020067
68 def resume_reading(self):
69 if not self._paused:
70 raise RuntimeError('Not paused')
71 self._paused = False
72 if self._closing:
73 return
74 self._loop.add_reader(self._sock_fd, self._read_ready)
75 if self._loop.get_debug():
Chris Liechtifc011102015-11-18 00:38:19 +010076 logging.debug("%r resumes reading", self)
Chris Liechtid07a9e72015-08-22 02:58:47 +020077
78 #~ def set_write_buffer_limits(self, high=None, low=None):
79 #~ def get_write_buffer_size(self):
80 #~ def writelines(self, list_of_data):
81 #~ def write_eof(self):
82 #~ def abort(self):
83
Chris Liechti033f17c2015-08-30 21:28:04 +020084
Chris Liechtid07a9e72015-08-22 02:58:47 +020085@asyncio.coroutine
86def create_serial_connection(loop, protocol_factory, *args, **kwargs):
87 ser = serial.Serial(*args, **kwargs)
88 protocol = protocol_factory()
89 transport = SerialTransport(loop, protocol, ser)
90 return (transport, protocol)
91
92# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
93# test
94if __name__ == '__main__':
95 class Output(asyncio.Protocol):
96 def connection_made(self, transport):
97 self.transport = transport
98 print('port opened', transport)
Chris Liechti0cd7d072015-09-04 23:04:53 +020099 transport.serial.rts = False
Chris Liechtid07a9e72015-08-22 02:58:47 +0200100 transport.write(b'hello world\n')
101
102 def data_received(self, data):
103 print('data received', repr(data))
104 self.transport.close()
105
106 def connection_lost(self, exc):
107 print('port closed')
108 asyncio.get_event_loop().stop()
109
110 loop = asyncio.get_event_loop()
111 coro = create_serial_connection(loop, Output, '/dev/ttyUSB0', baudrate=115200)
112 loop.run_until_complete(coro)
113 loop.run_forever()
114 loop.close()