blob: 43fc18560cbff49480342b8449b87dbdd7933d72 [file] [log] [blame]
Vadim Yanitskiy89fc14b2017-06-16 21:00:29 +07001#!/usr/bin/env python2
2# -*- coding: utf-8 -*-
3
4# GR-GSM based transceiver
5# Transceiver UDP interface
6#
7# (C) 2016-2017 by Vadim Yanitskiy <axilirator@gmail.com>
8#
9# All Rights Reserved
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation; either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License along
22# with this program; if not, write to the Free Software Foundation, Inc.,
23# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24
25import socket
26import select
27
28class UDPServer:
29 def __init__(self, remote_addr, remote_port, bind_port):
30 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
31 self.sock.bind(('0.0.0.0', bind_port))
32 self.sock.setblocking(0)
33
34 # Save remote info
35 self.remote_addr = remote_addr
36 self.remote_port = remote_port
37
38 def loop(self):
39 r_event, w_event, x_event = select.select([self.sock], [], [])
40
41 # Check for incoming data
42 if self.sock in r_event:
43 data, addr = self.sock.recvfrom(128)
44 self.handle_rx(data)
45
46 def shutdown(self):
47 self.sock.close();
48
49 def send(self, data):
50 self.sock.sendto(data, (self.remote_addr, self.remote_port))
51
52 def handle_rx(self, data):
53 raise NotImplementedError
54
55class CTRLInterface(UDPServer):
56 def __init__(self, remote_addr, remote_port, bind_port, radio_if):
57 print("[i] Init TRX CTRL interface")
58 UDPServer.__init__(self, remote_addr, remote_port, bind_port)
59 self.tb = radio_if
60
61 def shutdown(self):
62 print("[i] Shutdown TRX CTRL interface")
63 UDPServer.shutdown(self)
64
65 def handle_rx(self, data):
66 if self.verify_req(data):
67 request = self.prepare_req(data)
68 self.parse_cmd(request)
69 else:
70 print("[!] Wrong data on CTRL interface")
71
72 def verify_req(self, data):
73 # Verify command signature
74 return data.startswith("CMD")
75
76 def prepare_req(self, data):
77 # Strip signature, paddings and \0
78 request = data[4:].strip().strip("\0")
79 # Split into a command and arguments
80 request = request.split(" ")
81 # Now we have something like ["TXTUNE", "941600"]
82 return request
83
84 def verify_cmd(self, request, cmd, argc):
85 # Check if requested command matches
86 if request[0] != cmd:
87 return False
88
89 # And has enough arguments
90 if len(request) - 1 != argc:
91 return False
92
93 # Check if all arguments are numeric
94 for v in request[1:]:
95 if not v.isdigit():
96 return False
97
98 return True
99
100 def parse_cmd(self, request):
101 response_code = "0"
102
103 # Power control
104 if self.verify_cmd(request, "POWERON", 0):
105 print("[i] Recv POWERON cmd")
106 if not self.tb.trx_started:
107 if self.tb.check_available():
108 print("[i] Starting transceiver...")
109 self.tb.trx_started = True
110 self.tb.start()
111 else:
112 print("[!] Transceiver isn't ready to start")
113 response_code = "-1"
114 else:
115 print("[!] Transceiver already started!")
116 response_code = "-1"
117 elif self.verify_cmd(request, "POWEROFF", 0):
118 print("[i] Recv POWEROFF cmd")
119 print("[i] Stopping transceiver...")
120 self.tb.trx_started = False
121 # TODO: flush all buffers between blocks
122 self.tb.stop()
123 elif self.verify_cmd(request, "SETRXGAIN", 1):
124 print("[i] Recv SETRXGAIN cmd")
125 # TODO: check gain value
126 gain = int(request[1])
127 self.tb.set_gain(gain)
128
129 # Tuning Control
130 elif self.verify_cmd(request, "RXTUNE", 1):
131 print("[i] Recv RXTUNE cmd")
132 # TODO: check freq range
133 freq = int(request[1]) * 1000
134 self.tb.set_fc(freq)
135 elif self.verify_cmd(request, "TXTUNE", 1):
136 print("[i] Recv TXTUNE cmd")
137 # TODO: is not implemented yet
138
139 # Misc
140 elif self.verify_cmd(request, "ECHO", 0):
141 print("[i] Recv ECHO cmd")
142
143 # Wrong / unknown command
144 else:
145 print("[!] Wrong request on CTRL interface")
146 response_code = "-1"
147
148 # Anyway, we need to respond
149 self.send_response(request, response_code)
150
151 def send_response(self, request, response_code):
152 # Include status code, for example ["TXTUNE", "0", "941600"]
153 request.insert(1, response_code)
154 # Add the response signature, and join back to string
155 response = "RSP " + " ".join(request) + "\0"
156 # Now we have something like "RSP TXTUNE 0 941600"
157 self.send(response)