Posted:10/21/2015 4:00PM
Mike Mclain discusses how to use Python to Proxy RTL SDR Data From rtl_tcp.exe to permit multiple client connections simultaneously.
Over the last couple of years, I have been very interested in software defined radio (SDR) technology, and have routinely followed developments within the hobbyist (Realtek) RTL SDR (RTL2832U) community. Likewise, during this period of time, I have dabbled with a number of SDR projects (like GNU Radio, SDR Sharp, and SDR Console) along with other, more specific, RTL software tools (like rtl_tcp, and rtl_433).
Now, while such encounters are all --- well and good --- especially since most of the tools available are extremely flexible. Nevertheless, I have had a number of software snags over the years when it came to particular areas of interest (like decoding a whole Motorola type II trunking network simultaneously, or integrating a cheap Acurite thermometer into the Weather Underground accurately) because of innate limitations within the --- aforementioned --- software (with the connotation that specific problems typically merit specific solutions).
Conversely, while I have been working to develop my own software to implement my desired functionality (and learning DSP has been a fun adventure), I have also dabbled with cobbling together existing software solutions (like SDR Console and rtl_tcp) into something quickly functional (in the case of the Motorola type II trunking project) and have developed a Python script:
# A Simplistic Proxy Server to allow multiple clients to connect to the same rtl_tcp.exe instance
import sys
# Threaded Server Socket (TSsock) and Threaded Client Socket (TCsock)
# are wrapper classes I wrote to add additional features to the standard python socket class.
from TSsock import tssock
from TCsock import tcsock
# becuase we are streaming data we should also have thread suport
# this function also requires python threads
from threading import Thread
# all servers simply inherent the base threaded server socket class
class proxyserver(tssock,Thread):
# our class initialization
def __init__(self):
# setup the tssocket class
tssock.__init__(self)
# setup our inherented thread
Thread.__init__(self)
# Define the address and port of the rtl_tcp.exe instance
self.RTL_TCP_Host="127.0.0.1"
self.RTL_TCP_Port=1234
# Create a client connection to the rtl_tcp.exe instance
print "Setup RTLSDR"
self.device_info = None
self.rtlsdr = tcsock()
# The read buffer size is a rather tricky attribute given the data
# rate of the rtl_tcp.exe instance, this value works but your mileage may vary.
self.rtlsdr.set_read_buffer_size(1024*10)
# Startup connections to rtl_tcp.exe instance results additional device info
# being sent that must be processed differently than normal IQ traffic so we
# use a startup function here and swap over after this data is obtained.
self.rtlsdr.data_received_event=self.event_rtl_sdr_data_arrive_startup
self.rtlsdr.connect(self.RTL_TCP_Host,self.RTL_TCP_Port)
# rtl_tcp.exe will send 12 bytes of data with device info that we must buffer
# so do so
def event_rtl_sdr_data_arrive_startup(self,client,data):
if len(data)<12:
# we dont have all 12 bytes, so tell tcsock to keep the data we have so far
return 0
self.device_info = data[0:12]
print "Device Info Set To ",self.device_info
# once we have that info swap to the normal IQ processor
self.rtlsdr.data_received_event=self.event_rtl_sdr_data_arrive
# tell our tcsock to eat 12 bytes of data
return 12
# handle iq data from rtl_tcp.exe
def event_rtl_sdr_data_arrive(self,client,data):
# send this data to all connected clients
for index,aclient in enumerate(self.clients):
#print "write",index,len(data)
aclient.write(data)
# tell tcsock to eat the data len
return len(data)
# this event occurs when a client received data
def event_data_received(self,client,data):
self.rtlsdr.write(data)
#return len(data)
#return super(proxyserver, self).event_data_received(client,data)
# this event occurs when a client is connected to the server
def event_client_connected(self,client):
print "Client Connected"
if not self.device_info == None:
client.write(self.device_info)
# the default action is to ignore the event
pass
# this event occurs if the client connection is closed
def event_client_close(self,client,code):
print "Client Closed"
return super(proxyserver, self).event_client_close(client,code)
if __name__ == "__main__":
#setup SDR Proxy Server
# Connect via 127.0.0.1 on port 7000 rather than 127.0.0.1 on port 1234
Proxy_Server = proxyserver()
Proxy_Server.listen(7000)
while 1:
line = raw_input ("type q to quit> ")
if line == "q":
break
print "Stop RTL SDR Link"
Proxy_Server.rtlsdr.shutdown()
print "Stop Proxy Server"
Proxy_Server.shutdown()
to allow multiple SDR Console instances to obtain data from a single rtl_tcp instance.
While such notions might seem a little bit extreme (especially since SDR Console has 8 VFOs) and a RTL SDR dongle is bandwidth limited to around 1.5MHz; however, the ability to mirror information from the rtl_tcp application can be highly beneficial (especially during the development of other SDR applications) and I figured I would share my tools with the community at large (although I believe other projects similar to mine also exist)
Enjoy!
By Mike Mclain