-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Matthias Puech
committed
Nov 19, 2015
1 parent
af6aa3e
commit c104c61
Showing
31 changed files
with
7,394 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
#!/usr/bin/env python | ||
# | ||
# portable serial port access with python | ||
# this is a wrapper module for different platform implementations | ||
# | ||
# (C) 2001-2015 Chris Liechti <[email protected]> | ||
# | ||
# SPDX-License-Identifier: BSD-3-Clause | ||
|
||
import importlib | ||
import sys | ||
|
||
from serial.serialutil import * | ||
#~ SerialBase, SerialException, to_bytes, iterbytes | ||
|
||
VERSION = '3.0b1' | ||
|
||
if sys.platform == 'cli': | ||
from serial.serialcli import Serial | ||
else: | ||
import os | ||
# chose an implementation, depending on os | ||
if os.name == 'nt': # sys.platform == 'win32': | ||
from serial.serialwin32 import Serial | ||
elif os.name == 'posix': | ||
from serial.serialposix import Serial, PosixPollSerial, VTIMESerial | ||
elif os.name == 'java': | ||
from serial.serialjava import Serial | ||
else: | ||
raise ImportError("Sorry: no implementation for your platform ('%s') available" % (os.name,)) | ||
|
||
|
||
protocol_handler_packages = [ | ||
'serial.urlhandler', | ||
] | ||
|
||
|
||
def serial_for_url(url, *args, **kwargs): | ||
"""\ | ||
Get an instance of the Serial class, depending on port/url. The port is not | ||
opened when the keyword parameter 'do_not_open' is true, by default it | ||
is. All other parameters are directly passed to the __init__ method when | ||
the port is instantiated. | ||
The list of package names that is searched for protocol handlers is kept in | ||
``protocol_handler_packages``. | ||
e.g. we want to support a URL ``foobar://``. A module | ||
``my_handlers.protocol_foobar`` is provided by the user. Then | ||
``protocol_handler_packages.append("my_handlers")`` would extend the search | ||
path so that ``serial_for_url("foobar://"))`` would work. | ||
""" | ||
# check and remove extra parameter to not confuse the Serial class | ||
do_open = not kwargs.pop('do_not_open', False) | ||
# the default is to use the native implementation | ||
klass = Serial | ||
try: | ||
url_lowercase = url.lower() | ||
except AttributeError: | ||
# it's not a string, use default | ||
pass | ||
else: | ||
# if it is an URL, try to import the handler module from the list of possible packages | ||
if '://' in url_lowercase: | ||
protocol = url_lowercase.split('://', 1)[0] | ||
module_name = '.protocol_%s' % (protocol,) | ||
for package_name in protocol_handler_packages: | ||
try: | ||
package = importlib.import_module(package_name) | ||
handler_module = importlib.import_module(module_name, package_name) | ||
except ImportError: | ||
continue | ||
else: | ||
if hasattr(handler_module, 'serial_class_for_url'): | ||
url, klass = handler_module.serial_class_for_url(url) | ||
else: | ||
klass = handler_module.Serial | ||
break | ||
else: | ||
raise ValueError('invalid URL, protocol %r not known' % (protocol,)) | ||
# instantiate and open when desired | ||
instance = klass(None, *args, **kwargs) | ||
instance.port = url | ||
if do_open: | ||
instance.open() | ||
return instance |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# Python Serial Port Extension for Win32, Linux, BSD, Jython | ||
# module for serial IO for POSIX compatible systems, like Linux | ||
# see __init__.py | ||
# | ||
# (C) 2015 Chris Liechti <[email protected]> | ||
# | ||
# SPDX-License-Identifier: BSD-3-Clause | ||
"""\ | ||
Support asyncio with serial ports. EXPERIMENTAL | ||
Posix platforms only, Python 3.4+ only. | ||
Windows event loops can not wait for serial ports with the current | ||
implementation. It should be possible to get that working though. | ||
""" | ||
import asyncio | ||
import serial | ||
import logger | ||
|
||
|
||
class SerialTransport(asyncio.Transport): | ||
def __init__(self, loop, protocol, serial_instance): | ||
self._loop = loop | ||
self._protocol = protocol | ||
self.serial = serial_instance | ||
self._closing = False | ||
self._paused = False | ||
# XXX how to support url handlers too | ||
self.serial.timeout = 0 | ||
self.serial.nonblocking() | ||
loop.call_soon(protocol.connection_made, self) | ||
# only start reading when connection_made() has been called | ||
loop.call_soon(loop.add_reader, self.serial.fd, self._read_ready) | ||
|
||
def __repr__(self): | ||
return '{self.__class__.__name__}({self._loop}, {self._protocol}, {self.serial})'.format(self=self) | ||
|
||
def close(self): | ||
if self._closing: | ||
return | ||
self._closing = True | ||
self._loop.remove_reader(self.serial.fd) | ||
self.serial.close() | ||
self._loop.call_soon(self._protocol.connection_lost, None) | ||
|
||
def _read_ready(self): | ||
data = self.serial.read(1024) | ||
if data: | ||
self._protocol.data_received(data) | ||
|
||
def write(self, data): | ||
self.serial.write(data) | ||
|
||
def can_write_eof(self): | ||
return False | ||
|
||
def pause_reading(self): | ||
if self._closing: | ||
raise RuntimeError('Cannot pause_reading() when closing') | ||
if self._paused: | ||
raise RuntimeError('Already paused') | ||
self._paused = True | ||
self._loop.remove_reader(self._sock_fd) | ||
if self._loop.get_debug(): | ||
logger.debug("%r pauses reading", self) | ||
|
||
def resume_reading(self): | ||
if not self._paused: | ||
raise RuntimeError('Not paused') | ||
self._paused = False | ||
if self._closing: | ||
return | ||
self._loop.add_reader(self._sock_fd, self._read_ready) | ||
if self._loop.get_debug(): | ||
logger.debug("%r resumes reading", self) | ||
|
||
#~ def set_write_buffer_limits(self, high=None, low=None): | ||
#~ def get_write_buffer_size(self): | ||
#~ def writelines(self, list_of_data): | ||
#~ def write_eof(self): | ||
#~ def abort(self): | ||
|
||
|
||
@asyncio.coroutine | ||
def create_serial_connection(loop, protocol_factory, *args, **kwargs): | ||
ser = serial.Serial(*args, **kwargs) | ||
protocol = protocol_factory() | ||
transport = SerialTransport(loop, protocol, ser) | ||
return (transport, protocol) | ||
|
||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
# test | ||
if __name__ == '__main__': | ||
class Output(asyncio.Protocol): | ||
def connection_made(self, transport): | ||
self.transport = transport | ||
print('port opened', transport) | ||
transport.serial.rts = False | ||
transport.write(b'hello world\n') | ||
|
||
def data_received(self, data): | ||
print('data received', repr(data)) | ||
self.transport.close() | ||
|
||
def connection_lost(self, exc): | ||
print('port closed') | ||
asyncio.get_event_loop().stop() | ||
|
||
loop = asyncio.get_event_loop() | ||
coro = create_serial_connection(loop, Output, '/dev/ttyUSB0', baudrate=115200) | ||
loop.run_until_complete(coro) | ||
loop.run_forever() | ||
loop.close() |
Oops, something went wrong.