1# SPDX-FileCopyrightText: 2009-2015 Chris Liechti 2# SPDX-FileContributor: 2020-2024 Espressif Systems (Shanghai) CO LTD 3# SPDX-License-Identifier: BSD-3-Clause 4# 5# Redirect data from a TCP/IP connection to a serial port and vice versa using RFC 2217. 6 7################################################################################### 8# redirect data from a TCP/IP connection to a serial port and vice versa 9# using RFC 2217 10# 11# (C) 2009-2015 Chris Liechti <cliechti@gmx.net> 12# 13# SPDX-License-Identifier: BSD-3-Clause 14 15import logging 16import socket 17import sys 18import serial 19 20from esp_rfc2217_server.redirector import Redirector 21 22 23def main(): 24 import argparse 25 26 parser = argparse.ArgumentParser( 27 description="RFC 2217 Serial to Network (TCP/IP) redirector.", 28 epilog="NOTE: no security measures are implemented. " 29 "Anyone can remotely connect to this service over the network.\n" 30 "Only one connection at once is supported. " 31 "When the connection is terminated it waits for the next connect.", 32 ) 33 34 parser.add_argument("SERIALPORT") 35 36 parser.add_argument( 37 "-p", 38 "--localport", 39 type=int, 40 help="local TCP port, default: %(default)s", 41 metavar="TCPPORT", 42 default=2217, 43 ) 44 45 parser.add_argument( 46 "-v", 47 "--verbose", 48 dest="verbosity", 49 action="count", 50 help="print more diagnostic messages (option can be given multiple times)", 51 default=0, 52 ) 53 54 parser.add_argument( 55 "--r0", 56 help="Use delays necessary for ESP32 revision 0 chips", 57 action="store_true", 58 ) 59 60 args = parser.parse_args() 61 62 if args.verbosity > 3: 63 args.verbosity = 3 64 level = (logging.WARNING, logging.INFO, logging.DEBUG, logging.NOTSET)[ 65 args.verbosity 66 ] 67 logging.basicConfig(level=logging.INFO) 68 # logging.getLogger('root').setLevel(logging.INFO) 69 logging.getLogger("rfc2217").setLevel(level) 70 71 # connect to serial port 72 ser = serial.serial_for_url(args.SERIALPORT, do_not_open=True, exclusive=True) 73 ser.timeout = 3 # required so that the reader thread can exit 74 # reset control line as no _remote_ "terminal" has been connected yet 75 ser.dtr = False 76 ser.rts = False 77 78 logging.info(" RFC 2217 TCP/IP to Serial redirector - type Ctrl-C / BREAK to quit") 79 80 try: 81 ser.open() 82 except serial.SerialException as e: 83 logging.error(" Could not open serial port {}: {}".format(ser.name, e)) 84 sys.exit(1) 85 86 logging.info(" Serving serial port: {}".format(ser.name)) 87 settings = ser.get_settings() 88 89 srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 90 srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 91 srv.bind(("", args.localport)) 92 srv.listen(1) 93 logging.info(" TCP/IP port: {}".format(args.localport)) 94 while True: 95 try: 96 client_socket, addr = srv.accept() 97 logging.info("Connected by {}:{}".format(addr[0], addr[1])) 98 client_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) 99 ser.rts = True 100 ser.dtr = True 101 # enter network <-> serial loop 102 r = Redirector(ser, client_socket, args.verbosity > 0, args.r0) 103 try: 104 r.shortcircuit() 105 finally: 106 logging.info("Disconnected") 107 r.stop() 108 client_socket.close() 109 ser.dtr = False 110 ser.rts = False 111 # Restore port settings (may have been changed by RFC 2217 112 # capable client) 113 ser.apply_settings(settings) 114 except KeyboardInterrupt: 115 sys.stdout.write("\n") 116 break 117 except socket.error as msg: 118 logging.error(str(msg)) 119 120 logging.info("--- exit ---") 121 122 123if __name__ == "__main__": 124 main() 125