summaryrefslogtreecommitdiff
path: root/pyserial/examples/tcp_serial_redirect.py
blob: e55d53adf8684593197c12f801ea8a086e1761ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/env python

#(C)2002-2003 Chris Liechti <cliechti@gmx.net>
#redirect data from a TCP/IP connection to a serial port and vice versa
#requires Python 2.2 'cause socket.sendall is used

"""USAGE: tcp_serial_redirect.py [options]
Simple Serial to Network (TCP/IP) redirector.

Options:
  -p, --port=PORT   serial port, a number, defualt = 0 or a device name
  -b, --baud=BAUD   baudrate, default 9600
  -r, --rtscts      enable RTS/CTS flow control (default off)
  -x, --xonxoff     enable software flow control (default off)
  -P, --localport   TCP/IP port on which to run the server (default 7777)

Note: no security measures are implemeted. Anyone can remotely connect
to this service over the network.
Only one connection at once is supported. If the connection is terminaed
it waits for the next connect.
"""

import sys, os, serial, threading, getopt, socket

try:
    True
except NameError:
    True = 1
    False = 0

class Redirector:
    def __init__(self, serial, socket):
        self.serial = serial
        self.socket = socket

    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(1)
        self.thread_read.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:
                    self.socket.sendall(data)           #send it over TCP
            except socket.error, msg:
                print msg
                #probably got disconnected
                break
        self.alive = False
    
    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(data)                 #get a bunch of bytes and send them
            except socket.error, msg:
                print 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__':
    ser = serial.Serial()
    
    #parse command line options
    try:
        opts, args = getopt.getopt(sys.argv[1:],
                "hp:b:rxP",
                ["help", "port=", "baud=", "rtscts", "xonxoff", "localport"])
    except getopt.GetoptError:
        # print help information and exit:
        print >>sys.stderr, __doc__
        sys.exit(2)
    
    ser.port    = 0
    ser.baudrate = 9600
    ser.rtscts  = False
    ser.xonxoff = False
    ser.timeout = 1     #required so that the reader thread can exit
    
    localport = 7777
    for o, a in opts:
        if o in ("-h", "--help"):   #help text
            usage()
            sys.exit()
        elif o in ("-p", "--port"):   #specified port
            try:
                ser.port = int(a)
            except ValueError:
                ser.port = a
        elif o in ("-b", "--baud"):   #specified baudrate
            try:
                ser.baudrate = int(a)
            except ValueError:
                raise ValueError, "Baudrate must be a integer number"
        elif o in ("-r", "--rtscts"):
            ser.rtscts = True
        elif o in ("-x", "--xonxoff"):
            ser.xonxoff = True
        elif o in ("-P", "--localport"):
            try:
                localport = int(a)
            except ValueError:
                raise ValueError, "Local port must be an integer number"

    print "--- TCP/IP to Serial redirector --- type Ctrl-C / BREAK to quit"

    try:
        ser.open()
    except serial.SerialException, e:
        print "Could not open serial port %s: %s" % (ser.portstr, e)
        sys.exit(1)

    srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    srv.bind( ('', localport) )
    srv.listen(1)
    while 1:
        try:
            print "Waiting for connection..."
            connection, addr = srv.accept()
            print 'Connected by', addr
            #enter console->serial loop
            r = Redirector(ser, connection)
            r.shortcut()
            print 'Disconnected'
            connection.close()
        except socket.error, msg:
            print msg

    print "\n--- exit ---"