diff options
author | cliechti <cliechti@f19166aa-fa4f-0410-85c2-fa1106f25c8a> | 2009-08-07 18:22:49 +0000 |
---|---|---|
committer | cliechti <cliechti@f19166aa-fa4f-0410-85c2-fa1106f25c8a> | 2009-08-07 18:22:49 +0000 |
commit | 82b30aadd0d7f693fe3f2a882b18e5ac2f0517bd (patch) | |
tree | 9b0e6be17f3224bca42073ba77674455cb4b2929 /examples | |
parent | 93bfe4f43975cf7f6af788b863a1fec7c2379f32 (diff) | |
download | pyserial-82b30aadd0d7f693fe3f2a882b18e5ac2f0517bd.tar.gz |
add a simplified single port RFC 2217 server
git-svn-id: http://svn.code.sf.net/p/pyserial/code/trunk/pyserial@320 f19166aa-fa4f-0410-85c2-fa1106f25c8a
Diffstat (limited to 'examples')
-rw-r--r-- | examples/rfc2217_server.py | 159 | ||||
-rw-r--r-- | examples/setup-rfc2217_server-py2exe.py | 24 |
2 files changed, 183 insertions, 0 deletions
diff --git a/examples/rfc2217_server.py b/examples/rfc2217_server.py new file mode 100644 index 0000000..151d3c3 --- /dev/null +++ b/examples/rfc2217_server.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python + +# (C) 2009 Chris Liechti <cliechti@gmx.net> +# redirect data from a TCP/IP connection to a serial port and vice versa +# using RFC 2217 + + +import sys +import os +import threading +import time +import socket +import serial +import serial.rfc2217 + +class Redirector: + def __init__(self, serial_instance, socket): + self.serial = serial_instance + self.socket = socket + self._write_lock = threading.Lock() + self.rfc2217 = serial.rfc2217.PortManager(self.serial, self, debug_output=False) + + def statusline_poller(self): + while self.alive: + time.sleep(1) + self.rfc2217.check_modem_lines() + + def shortcut(self): + """connect the serial port to the TCP port by copying everything + from one side to the other""" + self.alive = True + self.thread_read = threading.Thread(target=self.reader) + self.thread_read.setDaemon(True) + self.thread_read.setName('serial->socket') + self.thread_read.start() + self.thread_poll = threading.Thread(target=self.statusline_poller) + self.thread_poll.setDaemon(True) + self.thread_poll.setName('status line poll') + self.thread_poll.start() + self.writer() + + def reader(self): + """loop forever and copy serial->socket""" + while self.alive: + try: + data = self.serial.read(1) # read one, blocking + n = self.serial.inWaiting() # look if there is more + if n: + data = data + self.serial.read(n) # and get as much as possible + if data: + # escape outgoing data when needed (Telnet IAC (0xff) character) + data = serial.to_bytes(self.rfc2217.escape(data)) + self._write_lock.acquire() + try: + self.socket.sendall(data) # send it over TCP + finally: + self._write_lock.release() + except socket.error, msg: + sys.stderr.write('ERROR: %s\n' % msg) + # probably got disconnected + break + self.alive = False + + def write(self, data): + """thread safe socket write with no data escaping. used to send telnet stuff""" + self._write_lock.acquire() + try: + self.socket.sendall(data) + finally: + self._write_lock.release() + + def writer(self): + """loop forever and copy socket->serial""" + while self.alive: + try: + data = self.socket.recv(1024) + if not data: + break + self.serial.write(serial.to_bytes(self.rfc2217.filter(data))) + except socket.error, msg: + sys.stderr.write('ERROR: %s\n' % msg) + # probably got disconnected + break + self.alive = False + self.thread_read.join() + + def stop(self): + """Stop copying""" + if self.alive: + self.alive = False + self.thread_read.join() + + +if __name__ == '__main__': + import optparse + + parser = optparse.OptionParser( + usage = "%prog [options] [port [baudrate]]", + description = "RFC 2217 Serial to Network (TCP/IP) redirector.", + epilog = """\ +NOTE: no security measures are implemented. Anyone can remotely connect +to this service over the network. + +Only one connection at once is supported. When the connection is terminated +it waits for the next connect. +""") + + parser.add_option("-p", "--localport", + dest = "local_port", + action = "store", + type = 'int', + help = "local TCP port", + default = 2217 + ) + + (options, args) = parser.parse_args() + + if len(args) != 1: + parser.error('serial port name required as argument') + + # connect to serial port + ser = serial.Serial() + ser.port = args[0] + ser.timeout = 1 # required so that the reader thread can exit + + sys.stderr.write("--- RFC 2217 TCP/IP to Serial redirector --- type Ctrl-C / BREAK to quit\n") + + try: + ser.open() + except serial.SerialException, e: + sys.stderr.write("Could not open serial port %s: %s\n" % (ser.portstr, e)) + sys.exit(1) + + sys.stderr.write("--- Serving serial port: %s\n" % (ser.portstr,)) + + srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + srv.bind( ('', options.local_port) ) + srv.listen(1) + sys.stderr.write("--- TCP/IP port: %s\n" % (options.local_port,)) + while True: + try: + connection, addr = srv.accept() + sys.stderr.write('Connected by %s\n' % (addr,)) + # enter console->serial loop + r = Redirector( + ser, + connection, + ) + r.shortcut() + sys.stderr.write('Disconnected\n') + connection.close() + except KeyboardInterrupt: + break + except socket.error, msg: + sys.stderr.write('ERROR: %s\n' % msg) + + sys.stderr.write('\n--- exit ---\n') + diff --git a/examples/setup-rfc2217_server-py2exe.py b/examples/setup-rfc2217_server-py2exe.py new file mode 100644 index 0000000..020427e --- /dev/null +++ b/examples/setup-rfc2217_server-py2exe.py @@ -0,0 +1,24 @@ +# setup script for py2exe to create the miniterm.exe +# $Id$ + +from distutils.core import setup +import glob, sys, py2exe, os + +sys.path.append('..') + +sys.argv.extend("py2exe --bundle 1".split()) + +setup( + name='rfc2217_server', + zipfile=None, + options = {"py2exe": + { + 'dist_dir': 'bin', + 'excludes': ['javax.comm'], + 'compressed': 1, + } + }, + console = [ + "rfc2217_server.py", + ], +) |