15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#!/usr/bin/env python
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# portable serial port access with python
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# this is a wrapper module for different platform implementations
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# (C) 2001-2010 Chris Liechti <cliechti@gmx.net>
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# this is distributed under a free software license, see license.txt
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VERSION = '2.7'
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import sys
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)if sys.platform == 'cli':
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    from serial.serialcli import *
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)else:
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    import os
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # chose an implementation, depending on os
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if os.name == 'nt': #sys.platform == 'win32':
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        from serial.serialwin32 import *
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    elif os.name == 'posix':
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        from serial.serialposix import *
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    elif os.name == 'java':
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        from serial.serialjava import *
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else:
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        raise ImportError("Sorry: no implementation for your platform ('%s') available" % (os.name,))
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)protocol_handler_packages = [
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'serial.urlhandler',
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ]
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def serial_for_url(url, *args, **kwargs):
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """\
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Get an instance of the Serial class, depending on port/url. The port is not
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    opened when the keyword parameter 'do_not_open' is true, by default it
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    is. All other parameters are directly passed to the __init__ method when
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    the port is instantiated.
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    The list of package names that is searched for protocol handlers is kept in
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ``protocol_handler_packages``.
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    e.g. we want to support a URL ``foobar://``. A module
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ``my_handlers.protocol_foobar`` is provided by the user. Then
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ``protocol_handler_packages.append("my_handlers")`` would extend the search
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    path so that ``serial_for_url("foobar://"))`` would work.
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # check remove extra parameter to not confuse the Serial class
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    do_open = 'do_not_open' not in kwargs or not kwargs['do_not_open']
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if 'do_not_open' in kwargs: del kwargs['do_not_open']
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # the default is to use the native version
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    klass = Serial   # 'native' implementation
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # check port type and get class
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    try:
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        url_nocase = url.lower()
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    except AttributeError:
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # it's not a string, use default
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        pass
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else:
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if '://' in url_nocase:
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            protocol = url_nocase.split('://', 1)[0]
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            for package_name in protocol_handler_packages:
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                module_name = '%s.protocol_%s' % (package_name, protocol,)
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                try:
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    handler_module = __import__(module_name)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                except ImportError:
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    pass
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                else:
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    klass = sys.modules[module_name].Serial
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    break
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            else:
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                raise ValueError('invalid URL, protocol %r not known' % (protocol,))
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        else:
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            klass = Serial   # 'native' implementation
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # instantiate and open when desired
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    instance = klass(None, *args, **kwargs)
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    instance.port = url
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if do_open:
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        instance.open()
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return instance
80