From e74679711bb9051080e7f11e16fe474fb6b56e60 Mon Sep 17 00:00:00 2001 From: Arturs Artamonovs Date: Wed, 22 Mar 2023 22:55:37 +0000 Subject: airspyhf_waterfall shows first signs of working --- airspyhf/airspyhf.py | 31 ++++++- airspyhf_power.py | 0 airspyhf_rx.py | 2 +- airspyhf_shedule.py | 54 +++++++++++- airspyhf_waterfall.py | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 307 insertions(+), 6 deletions(-) create mode 100755 airspyhf_power.py create mode 100644 airspyhf_waterfall.py diff --git a/airspyhf/airspyhf.py b/airspyhf/airspyhf.py index 562d8e5..5a26fa3 100644 --- a/airspyhf/airspyhf.py +++ b/airspyhf/airspyhf.py @@ -5,6 +5,7 @@ class AirSpyHF: dev_p = airspyhf_device_t_p(None) sample_rates = [] initalized = False + cur_freq = 0 def __init__(self,): #self.dev_p = airspyhf_device_t_p(None) pass @@ -54,6 +55,7 @@ class AirSpyHF: def set_samplerate(self, samplerate:int): if not self.initalized: + print("airspy not initalized") return -1 if self.sample_rates == []: self.get_samplerates() @@ -70,42 +72,66 @@ class AirSpyHF: def set_hf_agc(self,flag): if not self.initalized: + print("airspy not initalized") return -1 ret = libairspyhf.airspyhf_set_hf_agc(self.dev_p, flag) return ret def set_hf_agc_threshold(self,flag): if not self.initalized: + print("airspy not initalized") return -1 ret = libairspyhf.airspyhf_set_hf_agc_threshold(self.dev_p, flag) return ret def set_hf_att(self, value): if not self.initalized: + print("airspy not initalized") return -1 ret = libairspyhf.airspyhf_set_hf_att(self.dev_p, value) return ret def set_hf_lna(self,flag): if not self.initalized: + print("airspy not initalized") return -1 ret = libairspyhf.airspyhf_set_hf_lna(self.dev_p, flag) return ret - def start(self, read_samples): + def set_frequency(self,freq:int): if not self.initalized: + print("airspy not initalized") return -1 - ret = libairspyhf.airspyhf_start(self.dev_p, airspyhf_sample_block_cb_fn(read_samples), None) + ret = libairspyhf.airspyhf_set_freq(self.dev_p, int(freq)) + if ret != 0: + return -1 + self.cur_freq = int(freq) + return 0 + + #def get_frequency(self,freq:int): + # return self.cur_freq + + def start(self, read_samples_cb): + if not self.initalized: + print("airspy not initalized") + return -1 + #read_samples() + #ret = libairspyhf.airspyhf_start(self.dev_p, airspyhf_sample_block_cb_fn(read_samples), None) + ret = libairspyhf.airspyhf_start(self.dev_p, read_samples_cb, None) if ret != 0: print(f"airspyhf_start ret={ret}") + return -1 + return 0 def is_streaming(self): if not self.initalized: + print("airspy not initalized") return -1 return libairspyhf.airspyhf_is_streaming(self.dev_p) def stop(self): if not self.initalized: + print("airspy not initalized") return -1 ret = libairspyhf.airspyhf_stop(self.dev_p) if ret != 0: @@ -115,6 +141,7 @@ class AirSpyHF: def close(self): if not self.initalized: + print("airspy not initalized") return -1 ret = libairspyhf.close(self.dev_p) if ret != 0: diff --git a/airspyhf_power.py b/airspyhf_power.py new file mode 100755 index 0000000..e69de29 diff --git a/airspyhf_rx.py b/airspyhf_rx.py index 2ae35f7..7d55c35 100755 --- a/airspyhf_rx.py +++ b/airspyhf_rx.py @@ -108,7 +108,7 @@ def read_samples(transfer): return 0 -read_samples_cb = airspyhf_sample_block_cb_fn(read_samples) +#read_samples_cb = airspyhf_sample_block_cb_fn(read_samples) ret = libairspyhf.airspyhf_start(dev_p, airspyhf_sample_block_cb_fn(read_samples), None) diff --git a/airspyhf_shedule.py b/airspyhf_shedule.py index 03139bc..a82b1b4 100755 --- a/airspyhf_shedule.py +++ b/airspyhf_shedule.py @@ -53,11 +53,59 @@ class Station: self.duration = time_in_sec if "day" in config: - self.day = config["day"] + self.day = [] + if config["day"] == "every": + self.day = [1,2,3,4,5,6,7] + else: + #Supported + # lowercase mon,tue,wen,thu,fri,sat,sun + days = config["day"].lower().split(",") + if "mon" in days: + self.day.append(1) + if "tur" in days: + self.day.append(2) + if "wen" in days: + self.day.append(3) + if "thu" in days: + self.day.append(4) + if "fri" in days: + self.day.append(5) + if "sat" in days: + self.day.append(6) + if "sun" in days: + self.day.append(7) if "month" in config: - self.month = config["month"] - + self.month = [] + #Supported + #jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec + month = config["month"].lower().split(",") + if "jan" in month: + self.month.append(1) + if "feb" in month: + self.month.append(2) + if "mar" in month: + self.month.append(3) + if "apr" in month: + self.month.append(4) + if "may" in month: + self.month.append(5) + if "jun" in month: + self.month.append(6) + if "jul" in month: + self.month.append(7) + if "aug" in month: + self.month.append(8) + if "sep" in month: + self.month.append(9) + if "oct" in month: + self.month.append(10) + if "nov" in month: + self.month.append(11) + if "dec" in month: + self.month.append(12) + def __str__(self): + return f"{self.name} freq:{self.frequency} time:{self.time} day:{self.day} month:{self.month}" class StationCollection: stations = [] diff --git a/airspyhf_waterfall.py b/airspyhf_waterfall.py new file mode 100644 index 0000000..fc1de56 --- /dev/null +++ b/airspyhf_waterfall.py @@ -0,0 +1,226 @@ +import os +import sys +import math + +import airspyhf + +import matplotlib +import numpy +import pylab +import time +import threading + +import pygame +from pygame import gfxdraw + +CENTER_FREQ = 101000000 +SAMPLE_RATE = 196e3 +SAMPLE_NUM = 2048 + +SCREEN_X = 1025 +SCREEN_Y = 320 + +MOVE_STEP = int(SAMPLE_RATE/2) + +sample_buf_lock = threading.Lock() + +# init AIRSPY and if no then go out +airspy = airspyhf.AirSpyHF() +if airspy.open(device_index=0) == -1: + print("Cant open airspyhf device") + sys.exit(1) + +# config rtlsdr device +airspy.set_samplerate(SAMPLE_RATE) +airspy.set_frequency(CENTER_FREQ) +airspy.set_hf_agc(1) +airspy.set_hf_agc_threshold(0) +airspy.set_hf_lna(1) + + +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 + 70) * 255 // 70) + 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) +sample_buffer = [] +def read_samples(transfer): + global sample_buffer + #print("callback") + #if sample_buf_lock.locked(): + # print("Buffer locked") + # return 0 + #sample_buf_lock.acquire() + #print("Python call back") + t = transfer.contents + bytes_to_write = t.sample_count * 4 * 2 + #print("Received %d samples"%(t.sample_count)) + rx_buffer = t.samples + #print(f"{bytes_to_write} bytes receieved") + #sample_buffer.append(rx_buffer) + for i in range(0,t.sample_count): + d_re = t.samples[i].re + d_im = t.samples[i].im + sample_buffer.append(math.sqrt(d_re*d_re+d_im*d_im)) + #data = struct.pack(" num: + # arr = [] + # times = len(samples)/num + # for i in range(0, num): + # avg = numpy.average(samples[times*num:times*num+times-1]) + # arr.append(avg) + # return arr + #else: + # print("Error in get_samples") + # return [] + return [] + +read_samples_cb = airspyhf.airspyhf_sample_block_cb_fn(read_samples) +airspy.start(read_samples_cb) + +run = True +line = 0 +while run and airspy.is_streaming(): + + print("Loop tick") + + # 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 + airspy.set_frequency(airspy.cur_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") + airspy.set_frequency(airspy.cur_freq + MOVE_STEP) + + width = SCREEN_X + height = SCREEN_Y + + samples = get_samples(SAMPLE_NUM) + if samples == []: + print("sample buffer is empty") + time.sleep(1) + continue + #print(samples) + spect = numpy.fft.fft(samples,n=SAMPLE_NUM) + + spect = spect[0:int((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() + + #print(spect_n) + + # total data size + spect_len = len(spect_n) + #print(spect_len) + # calculate amount spect points per pixel without rounding + pixel_width = int(spect_len / SCREEN_X + 1) + #print(pixel_width) + pixel_steps = int(spect_len / pixel_width) + #print(pixel_steps) + #print(spect_n) + 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 + if math.isinf(avg): + avg = -1000 + + # print avg + # gfxdraw.pixel( screen, step, line, color_normalise((100-abs(avg))/10)) + gfxdraw.pixel(screen, step, line, color_mapping(int(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 + time.sleep(0.1) + +pygame.quit() + +airspy.stop() +airspy.close() + -- cgit v1.2.3