aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArturs Artamonovs <dos21h@gmail.com>2023-03-09 22:47:36 +0000
committerArturs Artamonovs <dos21h@gmail.com>2023-03-09 22:47:36 +0000
commit194f0c07ecbab61eb383c9d17c72fb73a4c9af80 (patch)
treea70fdd9a8e1235e1b35fbdd735ecaf9cdb7c0e41
parentc1ae0bcdb4eb27404d132b108f3d8da5ccdcf817 (diff)
parentfba22599d2ce386517c5c7f93403e0b3a4c92877 (diff)
downloadpyairspyhf-194f0c07ecbab61eb383c9d17c72fb73a4c9af80.tar.gz
pyairspyhf-194f0c07ecbab61eb383c9d17c72fb73a4c9af80.zip
Adding test for class. Implementeing main class. cleaning/fixing airspyhf_rx
-rw-r--r--.gitignore1
-rw-r--r--README.md39
-rw-r--r--airspy_waterfall.py153
-rw-r--r--airspyhf/airspyhf.py78
-rw-r--r--airspyhf/libairspyhf.py2
-rwxr-xr-xairspyhf_rx.py48
-rw-r--r--airspyhf_shedule.py8
-rwxr-xr-x[-rw-r--r--]test.py5
-rwxr-xr-xtest_class.py13
9 files changed, 322 insertions, 25 deletions
diff --git a/.gitignore b/.gitignore
index 77f5cbe..6342420 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
.idea
airspyhf/__pycache__/
+*.wav \ No newline at end of file
diff --git a/README.md b/README.md
index fd99dac..d555884 100644
--- a/README.md
+++ b/README.md
@@ -5,8 +5,9 @@ Python wrapper of airspyhf library
https://github.com/airspy/airspyhf.git
Project webpage main.lv
+main project page http://main.lv
+cgit source viewer http://git.main.lv/cgit.cgi/pyairspyhf.git
-http://git.main.lv/cgit.cgi/pyairspyhf.git
# Source code
@@ -14,6 +15,35 @@ http://git.main.lv/cgit.cgi/pyairspyhf.git
git clone https://git.main.lv/cgit/pyairspyhf.git
```
+# Install airspyhf
+
+Install all dependencies such as:
+```
+ cmake, libusb
+```
+
+Checked supported and tested version list
+
+To build the libairspyhf follow: https://github.com/airspy/airspyhf
+
+Workes localy
+```
+git clone https://github.com/airspy/airspyhf.git
+cd airspyhf
+cmake .
+make
+sudo make install
+```
+
+If there is issues with libusb header try to find libusb header locations
+```
+cmake -DLIBUSB_INCLUDE_DIR=/usr/include/libusb-1.0/ -DINSTALL_UDEV_RULES=ON
+```
+
+```commandline
+udevadm control --reload-rules
+```
+
# API
## libairspyhf
@@ -23,6 +53,13 @@ git clone https://git.main.lv/cgit/pyairspyhf.git
## airspyhf_rx.py
+## Supported and tested
+
+| --- | --- | --- | --- |
+| Python | libairspyhf | OS | Status |
+| --- |--- | --- | --- |
+| 3.9, 3.10 | 1.7.1 | ArchLinux, Ubuntu 20.04 | Supported and tested |
+
## Install
diff --git a/airspy_waterfall.py b/airspy_waterfall.py
new file mode 100644
index 0000000..255ecd5
--- /dev/null
+++ b/airspy_waterfall.py
@@ -0,0 +1,153 @@
+import os
+import sys
+import math
+
+import airspyhf
+
+import matplotlib
+import numpy
+import pylab
+
+import pygame
+from pygame import gfxdraw
+
+CENTER_FREQ = 4e6
+SAMPLE_RATE = 196e3
+SAMPLE_NUM = 2048
+GAIN = 'auto'
+
+SCREEN_X = 1025
+SCREEN_Y = 320
+
+MOVE_STEP = 0.1e6
+
+# init RTLSDR and if no then go out
+try:
+ pass
+except IOError:
+ print
+ "Probably RTLSDR device not attached"
+ sys.exit(0)
+
+# config rtlsdr device
+#rtl.sample_rate = SAMPLE_RATE
+#rtl.center_freq = CENTER_FREQ
+#rtl.gain = GAIN
+
+
+def iq_abs(c):
+ return (math.sqrt((c.real ** 2 + c.imag ** 2)))
+
+
+# point should be normalised to 0.0 ... 1.0
+def color_normalise(point):
+ ret = (255, 0, 0)
+ # blue
+ if (point < 0.3):
+ ret = (0, 0, int(point * 255 * 3.3))
+ # yello
+ elif (point < 0.7):
+ ret = (0, int((point - 0.3) * 255 * 2.5), 0)
+ # red
+ elif (point <= 1.0):
+ ret = (int((point - 0.7) * 255 * 3.3), 0, 0)
+ else:
+ # print "Color Error ", point
+ pass
+ return ret
+
+
+def color_mapping(x):
+ "assumes -50 to 0 range, returns color"
+ r = int((x + 50) * 255 // 50)
+ r = max(0, r)
+ r = min(255, r)
+ return (r, r, 100)
+
+
+# def draw_Hz( surface, x, y, hz ):
+
+
+arr = [[0 for i in range(0, SCREEN_X)] for j in range(0, SCREEN_Y)]
+
+# init all pygame modules audio,video and more
+pygame.init()
+
+# [NEW] creates screen surface using constants
+screen = pygame.display.set_mode((SCREEN_X, SCREEN_Y))
+
+#samples = rtl.read_samples(SAMPLE_NUM)
+samples = []
+
+run = True
+line = 0
+while run:
+
+ # print "update"
+
+ # check for all events that where ocure
+ for event in pygame.event.get():
+ # if some one clicked on close button
+ if event.type == pygame.QUIT:
+ # terminate programm
+ run = False
+ # don't waste your time by waiting while event loop will end
+ break
+ elif event.type == pygame.KEYDOWN:
+ if event.key == pygame.K_LEFT:
+ print
+ "Left"
+ rtl.center_freq -= MOVE_STEP
+ print
+ "Center freq: ", rtl.center_freq, " Hz"
+ elif event.key == pygame.K_RIGHT:
+ print
+ "Right"
+ rtl.center_freq += MOVE_STEP
+ print
+ "Center freq: ", rtl.center_freq, " Hz"
+
+ width = SCREEN_X
+ height = SCREEN_Y
+
+ samples = rtl.read_samples(SAMPLE_NUM)
+ spect = numpy.fft.fft(samples)
+ spect = spect[0:len(spect) / 2]
+
+ # (1/(Fs*N)) * abs(xdft).^2;
+ spect_n = [(1.0 / (SAMPLE_NUM * len(spect))) * iq_abs(x) ** 2 for x in spect]
+ spect_n = (10 * numpy.log10(spect_n)).tolist()
+
+ # total data size
+ spect_len = len(spect_n)
+
+ # calculate amount spect points per pixel without rounding
+ pixel_width = spect_len / SCREEN_X + 1
+ pixel_steps = spect_len / pixel_width
+
+ for step in range(0, pixel_steps):
+ avg = 0.0
+ for i in range(0, pixel_width):
+ avg += spect_n[step * pixel_width + i]
+ avg /= pixel_width
+
+ # print avg
+ # gfxdraw.pixel( screen, step, line, color_normalise((100-abs(avg))/10))
+ gfxdraw.pixel(screen, step, line, color_mapping(avg))
+
+ # draw central freq
+ font = pygame.font.Font(None, 20)
+ text = font.render(str(rtl.center_freq / 1e6), 1, (200, 30, 30), (0, 0, 0))
+ screen.blit(text, (SCREEN_X / 2, SCREEN_Y - 20))
+ text = font.render(str((rtl.center_freq + SAMPLE_RATE / 2) / 1e6), 1, (200, 30, 30), (0, 0, 0))
+ screen.blit(text, (SCREEN_X - 40, SCREEN_Y - 20))
+ text = font.render(str((rtl.center_freq - SAMPLE_RATE / 2) / 1e6), 1, (200, 30, 30), (0, 0, 0))
+ screen.blit(text, (20, SCREEN_Y - 20))
+
+ pygame.display.flip()
+ line += 1
+ if (line > SCREEN_Y):
+ line = 0
+
+pygame.quit
+
diff --git a/airspyhf/airspyhf.py b/airspyhf/airspyhf.py
index e13fada..4314c76 100644
--- a/airspyhf/airspyhf.py
+++ b/airspyhf/airspyhf.py
@@ -1,5 +1,77 @@
-from .libairspyhf import libairspyhf
+from .libairspyhf import *
+from ctypes import *
class AirSpyHF:
- def __init__(self):
- pass \ No newline at end of file
+ dev_p = airspyhf_device_t_p(None)
+ sample_rates = []
+ def __init__(self,):
+ self.dev_p = None
+
+ def open(self, device_index:int=None, serialnumber:int=None):
+ if serialnumber is not None:
+ ret = libairspyhf.airspyhf_open_sn(self.dev_p, serialnumber)
+ if ret != 0:
+ print("Cant open device by serial number")
+ return -1
+ elif device_index is not None:
+ ndev = libairspyhf.airspyhf_list_devices(None, 0)
+ if ndev < device_index+1:
+ print("Device index higher then device num")
+ return -1
+ serial = c_uint64(0)
+ libairspyhf.airspyhf_list_devices(byref(serial), device_index + 1)
+ return 0
+
+ def get_samplerates(self):
+ nsrates = c_uint32(0)
+ ret = libairspyhf.airspyhf_get_samplerates(self.dev_p, byref(nsrates), c_uint32(0))
+ if ret != 0:
+ print("Cant get number of avaliable sample rates")
+ return []
+ supported_samplerates = (c_uint32 * nsrates)(0)
+ ret = libairspyhf.airspyhf_get_samplerates(self.dev_p, supported_samplerates, nsrates)
+ if ret != 0:
+ print("Cant get avaliable sample rate list")
+ return []
+ self.sample_rates = list(supported_samplerates)
+ return self.sample_rates
+
+ def set_samplerate(self, samplerate:int):
+ if self.sample_rates == []:
+ self.get_samplerates()
+ if samplerate not in self.sample_rates:
+ print(f"Unknown sample rate. Avaliable samplerate {self.sample_rates}")
+ return -1
+
+ ret = libairspyhf.airspyhf_set_samplerate(self.dev_p, samplerate)
+ if ret != 0:
+ print("Cannot set samplerate")
+ return -1
+
+ return 0
+
+ def set_hf_agc(self,flag):
+ ret = libairspyhf.airspyhf_set_hf_agc(self.dev_p, flag)
+ return ret
+
+ def set_hf_agc_threshold(self,flag):
+ ret = libairspyhf.airspyhf_set_hf_agc_threshold(self.dev_p, flag)
+ return ret
+
+ def set_hf_att(self, value):
+ ret = libairspyhf.airspyhf_set_hf_att(dev_p, value)
+ return ret
+
+ def set_hf_lna(self,flag):
+ ret = libairspyhf.airspyhf_set_hf_lna(dev_p, 1)
+ return ret
+
+ def close(self):
+ ret = libairspyhf.close(self.dev_p)
+ if ret != 0:
+ print("Cant close device")
+
+
+
+
+
diff --git a/airspyhf/libairspyhf.py b/airspyhf/libairspyhf.py
index dada9f5..a287626 100644
--- a/airspyhf/libairspyhf.py
+++ b/airspyhf/libairspyhf.py
@@ -23,7 +23,7 @@ def load_libairspyhf():
driver = driver()
if driver is None:
continue
- print(driver)
+ #print("Search for driver named %s"%(driver))
try:
dll = CDLL(driver)
break
diff --git a/airspyhf_rx.py b/airspyhf_rx.py
index ac84856..a3b5634 100755
--- a/airspyhf_rx.py
+++ b/airspyhf_rx.py
@@ -1,3 +1,4 @@
+#!/usr/bin/python3
import os
from airspyhf import *
from ctypes import *
@@ -8,10 +9,10 @@ import struct
import argparse
parser = argparse.ArgumentParser()
-parser.add_argument("--frequency")
-parser.add_argument("--samplerate")
-parser.add_argument("--outputfile")
-parser.add_argument("--serial")
+parser.add_argument("-f","--frequency")
+parser.add_argument("-s","--samplerate")
+parser.add_argument("-o","--outputfile")
+parser.add_argument("-sn","--serial")
args = parser.parse_args()
print("Check airspyHF version")
@@ -38,7 +39,9 @@ if args.serial != None:
else:
serial = c_uint64(0)
libairspyhf.airspyhf_list_devices(byref(serial), 1)
- ret = libairspyhf.airspyhf_open_sn(dev_p, f"{hex(serial.value)}")
+ print(hex(serial.value))
+ print(type(serial.value))
+ ret = libairspyhf.airspyhf_open_sn(dev_p, serial.value)
print("open_sn: Returned %d"%(ret))
if (ret != 0):
print("airspyhf_open_sn returned != 0, error")
@@ -51,14 +54,21 @@ ret = libairspyhf.airspyhf_get_samplerates(dev_p,byref(nsrates),c_uint32(0))
print("ret %d"%ret)
print("sample rates %d"% nsrates.value)
-supportet_samplerates = (c_uint32*4)(0)
-ret = libairspyhf.airspyhf_get_samplerates(dev_p,supportet_samplerates,nsrates)
+supported_samplerates = (c_uint32*4)(0)
+ret = libairspyhf.airspyhf_get_samplerates(dev_p,supported_samplerates,nsrates)
print("ret %d"%ret)
+print("Sample rate list:")
for i in range(0,nsrates.value):
- print("Sample rates %d"% supportet_samplerates[i])
+ print(" %d s/sec"% supported_samplerates[i])
#try to get some samples
-ret = libairspyhf.airspyhf_set_samplerate(dev_p, supportet_samplerates[3])
+supported_samplerates = list(supported_samplerates)
+if int(args.samplerate) in supported_samplerates:
+ print("Setting sample rate to %s"%(args.samplerate))
+ ret = libairspyhf.airspyhf_set_samplerate(dev_p, int(args.samplerate))
+else:
+ print("Setting sample rate to %s"% (supported_samplerates[len(supported_samplerates)-1]))
+ ret = libairspyhf.airspyhf_set_samplerate(dev_p, supported_samplerates[len(supported_samplerates)-1])
print(f"airspyhf_set_samplerate ret={ret}")
ret = libairspyhf.airspyhf_set_hf_agc(dev_p, 1)
@@ -67,11 +77,17 @@ print(f"airspyhf_set_hf_agc ret={ret}")
ret = libairspyhf.airspyhf_set_hf_agc_threshold(dev_p, 0)
print(f"airspyhf_set_hf_agc_threshold ret={ret}")
+ret = libairspyhf.airspyhf_set_hf_lna(dev_p, 1)
+print(f"airspyhf_set_hf_lna ret={ret}")
+
sample_count = 0
-wave_file = wave.open("record.wav","w")
+RECORD_FILE_NAME="record.wav"
+if args.outputfile != None:
+ RECORD_FILE_NAME = args.outputfile
+wave_file = wave.open(RECORD_FILE_NAME,"w")
wave_file.setnchannels(2)
wave_file.setsampwidth(4)
-wave_file.setframerate(supportet_samplerates[1])
+wave_file.setframerate(supported_samplerates[1])
def read_samples(transfer):
global sample_count
global wave_file
@@ -98,11 +114,10 @@ read_samples_cb = airspyhf_sample_block_cb_fn(read_samples)
ret = libairspyhf.airspyhf_start(dev_p, airspyhf_sample_block_cb_fn(read_samples), None)
print(f"airspyhf_start ret={ret}")
-#ret = airspyhf.libairspyhf.py_cb_wrapper(dev_p)
-#print(f"airspyhf_start ret={ret}")
-
-
-ret = libairspyhf.airspyhf_set_freq(dev_p, 3865000)
+if args.frequency == None:
+ ret = libairspyhf.airspyhf_set_freq(dev_p, 3865000)
+else:
+ ret = libairspyhf.airspyhf_set_freq(dev_p, int(args.frequency))
print(f"airspyhf_set_freq ret={ret}")
count = 0
@@ -116,6 +131,7 @@ except:
ret = libairspyhf.airspyhf_stop(dev_p)
print(f"airspyhf_stop ret={ret}")
+time.sleep(1)
#Not close for now
ret = libairspyhf.close(dev_p)
diff --git a/airspyhf_shedule.py b/airspyhf_shedule.py
index e69de29..ad23e3d 100644
--- a/airspyhf_shedule.py
+++ b/airspyhf_shedule.py
@@ -0,0 +1,8 @@
+import os
+from airspyhf import *
+from ctypes import *
+import time
+import sys
+import wave
+import struct
+import argparse \ No newline at end of file
diff --git a/test.py b/test.py
index 8d17197..443b83f 100644..100755
--- a/test.py
+++ b/test.py
@@ -1,3 +1,4 @@
+#!/usr/bin/python3
import os
from airspyhf import *
from ctypes import *
@@ -110,10 +111,6 @@ print("closed: Returned %d"%(ret))
print(f"Total samples received {sample_count}")
-libairspyhf.py_test()
-
-libairspyhf.py_test_cb(read_samples_cb)
-
wave_file.close()
print("All is ok")
diff --git a/test_class.py b/test_class.py
new file mode 100755
index 0000000..35a6fd3
--- /dev/null
+++ b/test_class.py
@@ -0,0 +1,13 @@
+from airspyhf import *
+from ctypes import *
+import time
+import sys
+import wave
+import struct
+import argparse
+
+airspy = AirSpyHF()
+
+airspy.open(device_index=0)
+
+airspy.close() \ No newline at end of file