3 # Copyright 2006 Free Software Foundation, Inc.
5 # This file is part of GNU Radio
7 # GNU Radio is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3, or (at your option)
12 # GNU Radio is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with GNU Radio; see the file COPYING. If not, write to
19 # the Free Software Foundation, Inc., 51 Franklin Street,
20 # Boston, MA 02110-1301, USA.
29 from gnuradio.eng_option import eng_option
30 import gnuradio.gr.gr_threading as _threading
33 BROADCAST_ADDR = '255.255.255.255'
35 BROADCAST_PORT = 27010 # UDP
36 CONTROL_PORT = 27011 # TCP
38 PKT_HEADER_SIZE = 4 # 32-bit int
43 (len,) = struct.unpack('!i', s)
47 return struct.pack('!i', len)
50 class control_port_listener(asyncore.dispatcher):
51 def __init__(self, port=CONTROL_PORT, udp_socket=None, verbose=False):
53 @param port: TCP port to listen on.
56 asyncore.dispatcher.__init__(self)
58 self._verbose = verbose
59 self._udp_socket = udp_socket
61 host = '' # symbolic name for localhost
62 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
66 self.bind((host, port))
67 except socket.error, err:
68 sys.stderr.write('Failed to bind to %s: %s\n' %
69 ((host, port), os.strerror (err.args[0]),))
74 def handle_accept(self):
75 socket, addr = self.accept()
76 sys.stderr.write("handle_accept: %r\n" % (addr,))
77 if not(socket is None):
78 # instantiate a server
79 s = control_server(socket, addr, self._udp_socket, self._verbose)
82 class gr_dispatcher(asyncore.dispatcher):
83 def __init__(self, sock=None, map=None):
84 asyncore.dispatcher.__init__(self, sock=sock, map=map)
86 def read_packet(self):
88 Returns None or packet
90 s = self.recvall(PKT_HEADER_SIZE)
94 (payload_len,) = unpack_header(s)
96 payload_len = int(payload_len)
101 payload = self.recvall(payload_len)
102 if len(payload) != payload_len:
103 sys.stderr.write ('short recv, expected %d bytes, got %d\n' % (
104 payload_len, len(payload)))
105 raise RuntimeError, "short recv"
109 def recvall(self, buffer_size):
111 while len(result) < buffer_size:
112 data = self.recv(buffer_size - len(result))
119 class pkt_receiver_thread(_threading.Thread):
120 def __init__(self, socket):
121 _threading.Thread.__init__(self)
124 self.keep_running = True
128 while self.keep_running:
129 pkt, sender = self.socket.recvfrom(10000)
132 t = struct.unpack('!H', pkt[0:2])
137 logfile.write('RCVD seqno %4d len %4d from %s\n' % (seqno, len(pkt), sender))
141 class control_server(gr_dispatcher):
142 def __init__(self, socket, addr, udp_socket, verbose=False):
143 gr_dispatcher.__init__(self, sock=socket)
145 self._udp_socket = udp_socket
146 self.verbose = verbose
152 def handle_read(self):
153 pkt = self.read_packet()
155 annotate = 'ANNOTATE'
156 if pkt.startswith(annotate):
157 logfile.write(pkt[len(annotate)+1:])
160 elif pkt.startswith('SEND'):
165 npkts = int(tokens[1])
166 size = int(tokens[2])
167 power = float(tokens[3])
168 send_test_packets(self._udp_socket, npkts, size, power)
172 def handle_close(self):
176 def invalid_packet(pkt):
177 sys.stderr.write('received unrecognized packet: %s\n' % (pkt,))
180 def make_random_payload(size):
183 for i in range(size):
184 p[i] = chr(random.randint(0, 255))
186 for i in range(size):
191 def send_test_packets(udp_socket, npkts, size, power):
192 # we ignore power for now...
194 payload = make_random_payload(size - 2)
195 for n in range(npkts):
196 pkt = struct.pack('!H', n) + payload
197 udp_socket.sendto(pkt, (BROADCAST_ADDR, BROADCAST_PORT))
198 #udp_socket.sendall(pkt)
201 def open_udp_broadcast_socket(gr0_host_ip, port):
202 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
203 # s.bind((gr0_host_ip, port))
205 s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
206 # s.connect((BROADCAST_ADDR, port))
213 usage = 'usage: %prog [options] gr0-ip-addr'
214 parser = optparse.OptionParser (option_class=eng_option, usage=usage)
215 parser.add_option('-l', '--logfile', type='string', default=None,
216 help="specify log file name [default=<stdout>]")
217 parser.add_option('-v', '--verbose', action="store_true", default=False,
218 help="enable verbose diagnostics")
220 (options, args) = parser.parse_args ()
225 gr0_ip_addr = args[0]
226 if options.logfile is None:
229 logfile = file(options.logfile, 'w')
231 udp_socket = open_udp_broadcast_socket(gr0_ip_addr, BROADCAST_PORT)
232 R = pkt_receiver_thread(udp_socket)
233 L = control_port_listener(CONTROL_PORT, udp_socket=udp_socket, verbose=options.verbose)
234 asyncore.loop(LOOP_TIMEOUT)
237 if __name__ == '__main__':
240 except KeyboardInterrupt: