AI HackRF на Windows: работа через DLL и создание Python-библиотеки

AI

Редактор
Регистрация
23 Август 2023
Сообщения
2 819
Лучшие ответы
0
Реакции
0
Баллы
51
Offline
#1


Небольшая статья для начала работы на питоне с приемником HackRF One под Windows. Когда мне захотелось работать с приемником HackRF напрямую из Python, я обнаружил, что существующая библиотека pyhackrf работает только на Linux. Это подтолкнуло меня к доработке подхода для работы под Windows через прямое взаимодействие с DLL. Возможно, мой опыт кому-то пригодится.

Почему напрямую через DLL?


  • pyhackrf изначально заточен под Linux и использует libhackrf.so


  • На Windows libhackrf.so заменяется на hackrf.dll


  • Прямой вызов DLL через Python позволяет полностью контролировать устройство


  • Минимальные зависимости и прозрачность работы


  • Полная свобода в реализации нужного функционала

    Создание Python-библиотеки для HackRF

Код hackrf_dll.py

from ctypes import *
import os
import numpy as np

# Путь к DLL
dll_path = os.path.join(os.path.dirname(__file__), "hackrf.dll")
lib = CDLL(dll_path)

p_hackrf_device = c_void_p

# Настройка функций DLL
lib.hackrf_init.restype = c_int
lib.hackrf_exit.restype = c_int

lib.hackrf_open.argtypes = [POINTER(p_hackrf_device)]
lib.hackrf_open.restype = c_int

lib.hackrf_close.argtypes = [p_hackrf_device]
lib.hackrf_close.restype = c_int

lib.hackrf_set_freq.argtypes = [p_hackrf_device, c_uint64]
lib.hackrf_set_freq.restype = c_int

lib.hackrf_set_sample_rate.argtypes = [p_hackrf_device, c_double]
lib.hackrf_set_sample_rate.restype = c_int

lib.hackrf_set_lna_gain.argtypes = [p_hackrf_device, c_uint32]
lib.hackrf_set_lna_gain.restype = c_int

lib.hackrf_set_vga_gain.argtypes = [p_hackrf_device, c_uint32]
lib.hackrf_set_vga_gain.restype = c_int

lib.hackrf_set_amp_enable.argtypes = [p_hackrf_device, c_uint8]
lib.hackrf_set_amp_enable.restype = c_int

# RX callback тип
HackRFRxCallback = CFUNCTYPE(c_int, POINTER(c_byte), c_int, c_void_p)
# TX callback тип
HackRFTxCallback = CFUNCTYPE(c_int, POINTER(c_byte), c_int, c_void_p)

lib.hackrf_start_rx.argtypes = [p_hackrf_device, HackRFRxCallback, c_void_p]
lib.hackrf_start_rx.restype = c_int

lib.hackrf_stop_rx.argtypes = [p_hackrf_device]
lib.hackrf_stop_rx.restype = c_int

lib.hackrf_start_tx.argtypes = [p_hackrf_device, HackRFTxCallback, c_void_p]
lib.hackrf_start_tx.restype = c_int

lib.hackrf_stop_tx.argtypes = [p_hackrf_device]
lib.hackrf_stop_tx.restype = c_int


class HackRF:
def __init__(self):
self.dev = p_hackrf_device(None)
if lib.hackrf_init() != 0:
raise RuntimeError("HackRF init error")
if lib.hackrf_open(pointer(self.dev)) != 0:
raise RuntimeError("HackRF open error")
print("HackRF открыт!")

def set_freq(self, freq_hz):
if lib.hackrf_set_freq(self.dev, int(freq_hz)) != 0:
raise RuntimeError("HackRF set_freq error")
self._freq = freq_hz
print(f"Частота установлена на {freq_hz} Hz")

def set_sample_rate(self, rate_hz):
if lib.hackrf_set_sample_rate(self.dev, float(rate_hz)) != 0:
raise RuntimeError("HackRF set_sample_rate error")
self._sample_rate = rate_hz
print(f"Частота дискретизации установлена на {rate_hz} Hz")

def set_lna_gain(self, gain):
if lib.hackrf_set_lna_gain(self.dev, int(gain)) != 0:
raise RuntimeError("HackRF set_lna_gain error")

def set_vga_gain(self, gain):
if lib.hackrf_set_vga_gain(self.dev, int(gain)) != 0:
raise RuntimeError("HackRF set_vga_gain error")

def enable_amp(self):
if lib.hackrf_set_amp_enable(self.dev, 1) != 0:
raise RuntimeError("HackRF enable_amp error")

def disable_amp(self):
if lib.hackrf_set_amp_enable(self.dev, 0) != 0:
raise RuntimeError("HackRF disable_amp error")

# ---------------- RX -----------------
def start_rx(self, callback):
if not callable(callback):
raise ValueError("callback must be callable")

def rx_cb(buf_ptr, length, ctx):
raw = np.ctypeslib.as_array(buf_ptr, shape=(length,))
iq = raw.astype(np.int8).view(np.complex64) / 127.0
callback(iq)
return 0

self._rx_cb = HackRFRxCallback(rx_cb)
res = lib.hackrf_start_rx(self.dev, self._rx_cb, None)
if res != 0:
raise RuntimeError(f"HackRF start_rx error: {res}")
print("Начало приёма RX")

def stop_rx(self):
res = lib.hackrf_stop_rx(self.dev)
if res != 0:
raise RuntimeError(f"HackRF stop_rx error: {res}")
print("Остановка приёма RX")

# ---------------- TX -----------------
def start_tx(self, callback):
if not callable(callback):
raise ValueError("callback must be callable")

def tx_cb(buf_ptr, length, ctx):
raw_buf = np.ctypeslib.as_array(buf_ptr, shape=(length,))
iq = callback(length)
# Проверяем размер
if len(iq)*8 > length:
raise RuntimeError("TX buffer overflow")
# Преобразуем IQ в int8 и копируем в буфер
raw_buf[:len(iq)*2] = np.frombuffer((iq*127).astype(np.int8).tobytes(), dtype=np.int8)
return 0

self._tx_cb = HackRFTxCallback(tx_cb)
res = lib.hackrf_start_tx(self.dev, self._tx_cb, None)
if res != 0:
raise RuntimeError(f"HackRF start_tx error: {res}")
print("Начало передачи TX")

def stop_tx(self):
res = lib.hackrf_stop_tx(self.dev)
if res != 0:
raise RuntimeError(f"HackRF stop_tx error: {res}")
print("Остановка передачи TX")

# ---------------- General -----------------
def close(self):
lib.hackrf_close(self.dev)
lib.hackrf_exit()
print("HackRF закрыт!")

def __enter__(self):
return self

def __exit__(self, *args):
self.close()


Пример использования библиотеки

from hackrf_dll import HackRF
import time

# Работа с HackRF через контекстный менеджер
with HackRF() as hackrf:
hackrf.set_freq(433_920_000) # Частота для радиоуправления RC
hackrf.set_lna_gain(16)
hackrf.set_vga_gain(16)
hackrf.enable_amp()

# Простейшая "тестовая передача" — пауза
time.sleep(2)

Итоги


  • Работа напрямую с hackrf_dll даёт полный контроль и кроссплатформенную совместимость в Windows.


  • Мини-библиотека позволяет управлять частотой, усилением и включением передатчика, оставаясь лёгкой и прозрачной.

Полните что включать на передачу без антенны можно спалить передатчик. Так же антенна должна быть правильная для той частоты которую выбрали.
 

Похожие темы

Сверху Снизу