Skip to content

Commit

Permalink
example script for using the live streaming servers
Browse files Browse the repository at this point in the history
  • Loading branch information
jankae committed Jun 21, 2024
1 parent ee1adc0 commit 253e2d3
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 0 deletions.
57 changes: 57 additions & 0 deletions Documentation/UserManual/SCPI_Examples/capture_live_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env python3

import time
from libreVNA import libreVNA

# Create the control instance
vna = libreVNA('localhost', 19542)

# Quick connection check (should print "LibreVNA-GUI")
print(vna.query("*IDN?"))

# Make sure we are connecting to a device (just to be sure, with default settings the LibreVNA-GUI auto-connects)
vna.cmd(":DEV:CONN")
dev = vna.query(":DEV:CONN?")
if dev == "Not connected":
print("Not connected to any device, aborting")
exit(-1)
else:
print("Connected to "+dev)

# Capture live data as it is coming in. Stop acquisition for now
vna.cmd(":VNA:ACQ:STOP")

# switch to VNA mode, set up the sweep parameters
print("Setting up the sweep...")
vna.cmd(":DEV:MODE VNA")
vna.cmd(":VNA:SWEEP FREQUENCY")
vna.cmd(":VNA:STIM:LVL -10")
vna.cmd(":VNA:ACQ:IFBW 100")
vna.cmd(":VNA:ACQ:AVG 1")
vna.cmd(":VNA:ACQ:POINTS 501")
vna.cmd(":VNA:FREQuency:START 10000000")
vna.cmd(":VNA:FREQuency:STOP 6000000000")

sweepComplete = False


def callback(data):
global sweepComplete
print(data)
if data["pointNum"] == 500:
# this was the last point
vna.remove_live_callback(19000, callback)
sweepComplete = True


# Set up the connection for the live data
vna.add_live_callback(19000, callback)
print("Starting the sweep...")
vna.cmd(":VNA:ACQ:RUN")

while not sweepComplete:
time.sleep(0.1)

print("Sweep complete")


59 changes: 59 additions & 0 deletions Documentation/UserManual/SCPI_Examples/libreVNA.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import socket
from asyncio import IncompleteReadError # only import the exception class
import time
import threading
import json

class SocketStreamReader:
def __init__(self, sock: socket.socket, default_timeout=1):
Expand Down Expand Up @@ -72,13 +74,16 @@ class libreVNA:
def __init__(self, host='localhost', port=19542,
check_cmds=True, timeout=1):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.host = host
try:
self.sock.connect((host, port))
except:
raise Exception("Unable to connect to LibreVNA-GUI. Make sure it is running and the TCP server is enabled.")
self.reader = SocketStreamReader(self.sock,
default_timeout=timeout)
self.default_check_cmds = check_cmds
self.live_threads = {}
self.live_callbacks = {}

def __del__(self):
self.sock.close()
Expand Down Expand Up @@ -117,6 +122,60 @@ def get_status(self, timeout=None):
if status < 0 or status > 255:
raise Exception(f"*ESR? returned invalid value {status}.")
return status

def add_live_callback(self, port, callback):
# check if we already have a thread handling this connection
if not port in self.live_threads:
# needs to create the connection and thread first
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((self.host, port))
except:
raise Exception("Unable to connect to streaming server at port {}. Make sure it is enabled.".format(port))

self.live_callbacks[port] = [callback]
self.live_threads[port] = threading.Thread(target=self.__live_thread, args=(sock, port))
self.live_threads[port].start()
else:
# thread already existed, simply add to list
self.live_callbacks[port].append(callback)

def remove_live_callback(self, port, callback):
if port in self.live_callbacks:
# remove all matching callbacks from the list
self.live_callbacks[port] = [cb for cb in self.live_callbacks[port] if cb != callback]
# if the list is now empty, the thread will exit
if len(self.live_callbacks) == 0:
self.live_threads[port].join()
del self.live_threads[port]

def __live_thread(self, sock, port):
reader = SocketStreamReader(sock, default_timeout=0.1)
while len(self.live_callbacks[port]) > 0:
try:
line = reader.readline().decode().rstrip()
# determine whether this is data from the VNA or spectrum analyzer
data = json.loads(line)
if "Z0" in data:
# This is VNA data which has the imag/real parts of the S-parameters split into two float values.
# This was necessary because json does not support complex number. But python does -> convert back
# to complex
measurements = {}
for meas in data["measurements"].keys():
if meas.endswith("_imag"):
# ignore
continue
name = meas.removesuffix("_real")
real = data["measurements"][meas]
imag = data["measurements"][name+"_imag"]
measurements[name] = complex(real, imag)
data["measurements"] = measurements
for cb in self.live_callbacks[port]:
cb(data)
except:
# ignore timeouts
pass


@staticmethod
def parse_VNA_trace_data(data):
Expand Down

0 comments on commit 253e2d3

Please sign in to comment.