tools/litex_client/RemoteClient: add base_address parameter.
[litex.git] / litex / tools / litex_server.py
1 #!/usr/bin/env python3
2
3 # This file is Copyright (c) 2015-2019 Florent Kermarrec <florent@enjoy-digital.fr>
4 # This file is Copyright (c) 2019 Sean Cross <sean@xobs.io>
5 # This file is Copyright (c) 2018 Felix Held <felix-github@felixheld.de>
6 # License: BSD
7
8 import argparse
9
10 import sys
11 import socket
12 import time
13 import threading
14
15 from litex.tools.remote.etherbone import EtherbonePacket, EtherboneRecord, EtherboneWrites
16 from litex.tools.remote.etherbone import EtherboneIPC
17
18
19 class RemoteServer(EtherboneIPC):
20 def __init__(self, comm, bind_ip, bind_port=1234):
21 self.comm = comm
22 self.bind_ip = bind_ip
23 self.bind_port = bind_port
24 self.lock = False
25
26 def open(self):
27 if hasattr(self, "socket"):
28 return
29 socket_flags = 0
30 if hasattr(socket, "SO_REUSEADDR"):
31 socket_flags = socket_flags | socket.SO_REUSEADDR
32 if hasattr(socket, "SO_REUSEPORT"):
33 socket_flags = socket_flags | socket.SO_REUSEPORT
34 self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
35 self.socket.setsockopt(socket.SOL_SOCKET, socket_flags, 1)
36 self.socket.bind((self.bind_ip, self.bind_port))
37 print("tcp port: {:d}".format(self.bind_port))
38 self.socket.listen(1)
39 self.comm.open()
40
41 def close(self):
42 self.comm.close()
43 if not hasattr(self, "socket"):
44 return
45 self.socket.close()
46 del self.socket
47
48 def _serve_thread(self):
49 while True:
50 client_socket, addr = self.socket.accept()
51 print("Connected with " + addr[0] + ":" + str(addr[1]))
52 try:
53 while True:
54 try:
55 packet = self.receive_packet(client_socket)
56 if packet == 0:
57 break
58 except:
59 break
60 packet = EtherbonePacket(packet)
61 packet.decode()
62
63 record = packet.records.pop()
64
65 # wait for lock
66 while self.lock:
67 time.sleep(0.01)
68
69 # set lock
70 self.lock = True
71
72 # handle writes:
73 if record.writes != None:
74 self.comm.write(record.writes.base_addr, record.writes.get_datas())
75
76 # handle reads
77 if record.reads != None:
78 reads = []
79 for addr in record.reads.get_addrs():
80 reads.append(self.comm.read(addr))
81
82 record = EtherboneRecord()
83 record.writes = EtherboneWrites(datas=reads)
84 record.wcount = len(record.writes)
85
86 packet = EtherbonePacket()
87 packet.records = [record]
88 packet.encode()
89 self.send_packet(client_socket, packet)
90
91 # release lock
92 self.lock = False
93
94 finally:
95 print("Disconnect")
96 client_socket.close()
97
98 def start(self, nthreads):
99 for i in range(nthreads):
100 self.serve_thread = threading.Thread(target=self._serve_thread)
101 self.serve_thread.setDaemon(True)
102 self.serve_thread.start()
103
104
105 def main():
106 print("LiteX remote server")
107 parser = argparse.ArgumentParser()
108 # Common arguments
109 parser.add_argument("--bind-ip", default="localhost",
110 help="Host bind address")
111 parser.add_argument("--bind-port", default=1234,
112 help="Host bind port")
113
114 # UART arguments
115 parser.add_argument("--uart", action="store_true",
116 help="Select UART interface")
117 parser.add_argument("--uart-port", default=None,
118 help="Set UART port")
119 parser.add_argument("--uart-baudrate", default=115200,
120 help="Set UART baudrate")
121
122 # UDP arguments
123 parser.add_argument("--udp", action="store_true",
124 help="Select UDP interface")
125 parser.add_argument("--udp-ip", default="192.168.1.50",
126 help="Set UDP remote IP address")
127 parser.add_argument("--udp-port", default=1234,
128 help="Set UDP remote port")
129
130 # PCIe arguments
131 parser.add_argument("--pcie", action="store_true",
132 help="Select PCIe interface")
133 parser.add_argument("--pcie-bar", default=None,
134 help="Set PCIe BAR")
135
136 # USB arguments
137 parser.add_argument("--usb", action="store_true",
138 help="Select USB interface")
139 parser.add_argument("--usb-vid", default=None,
140 help="Set USB vendor ID")
141 parser.add_argument("--usb-pid", default=None,
142 help="Set USB product ID")
143 parser.add_argument("--usb-max-retries", default=10,
144 help="Number of times to try reconnecting to USB")
145 args = parser.parse_args()
146
147
148 if args.uart:
149 from litex.tools.remote.comm_uart import CommUART
150 if args.uart_port is None:
151 print("Need to specify --uart-port, exiting.")
152 exit()
153 uart_port = args.uart_port
154 uart_baudrate = int(float(args.uart_baudrate))
155 print("[CommUART] port: {} / baudrate: {} / ".format(uart_port, uart_baudrate), end="")
156 comm = CommUART(uart_port, uart_baudrate)
157 elif args.udp:
158 from litex.tools.remote.comm_udp import CommUDP
159 udp_ip = args.udp_ip
160 udp_port = int(args.udp_port)
161 print("[CommUDP] ip: {} / port: {} / ".format(udp_ip, udp_port), end="")
162 comm = CommUDP(udp_ip, udp_port)
163 elif args.pcie:
164 from litex.tools.remote.comm_pcie import CommPCIe
165 pcie_bar = args.pcie_bar
166 if args.pcie_bar is None:
167 print("Need to speficy --pcie-bar, exiting.")
168 exit()
169 print("[CommPCIe] bar: {} / ".format(args.pcie_bar), end="")
170 comm = CommPCIe(args.pcie_bar)
171 elif args.usb:
172 from litex.tools.remote.comm_usb import CommUSB
173 if args.usb_pid is None and args.usb_vid is None:
174 print("Need to speficy --usb-vid or --usb-pid, exiting.")
175 exit()
176 print("[CommUSB] vid: {} / pid: {} / ".format(args.usb_vid, args.usb_pid), end="")
177 pid = args.usb_pid
178 if pid is not None:
179 pid = int(pid, base=0)
180 vid = args.usb_vid
181 if vid is not None:
182 vid = int(vid, base=0)
183 comm = CommUSB(vid=vid, pid=pid, max_retries=args.usb_max_retries)
184 else:
185 parser.print_help()
186 exit()
187
188 server = RemoteServer(comm, args.bind_ip, int(args.bind_port))
189 server.open()
190 server.start(4)
191 try:
192 import time
193 while True: time.sleep(100)
194 except KeyboardInterrupt:
195 pass
196
197 if __name__ == "__main__":
198 main()