Wrapper DLL RTL-SDR

Programmation d'applications complexes
Avatar de l’utilisateur
vertexview
Messages : 10
Inscription : mer. 24/janv./2024 16:02

Wrapper DLL RTL-SDR

Message par vertexview »

Bonjour,
J'essaie de réaliser un wrapper de librtlsdr.dll pour contrôler un récepteur radio de type dongle USB SDR (Software Defined Radio)
De nombreuses applications open source existent concernant l'utilisation de ce type de récepteur, mais pour le moment je n'en ai pas encore vu en Purebasic.

J'ai pu tester avec succès un récepteur ADSB (réception mode synchrone, type terminal) en Free Pascal, initialement développé en Delphi XE, après la conversion des fichiers dans l'IDE Lazarus 3.0.
Ce projet intègre un fichier wrapper relativement simple concernant la dll d'accès au matériel. Cette DLL principale, associée à deux autres dépendantes (libusb-1.0.dll, libwinpthread-1.dll), est utilisée pour la majorité des applications SDR utilisant des récepteurs de type RTL-SDR.
Je souhaite réaliser un wrapper similaire pour Purebasic.

. Information sur RTL-SDR: https://www.rtl-sdr.com/about-rtl-sdr/
. Projet Osmocom: https://osmocom.org/projects/rtl-sdr/wiki
. Github sources des drivers: https://github.com/osmocom/rtl-sdr
. Exemple de récepteur ADSB en DELPHI/PASCAL: https://sourceforge.net/projects/rtl-ad ... -xe8-port/
. Dernières versions de drivers pour Windows: https://ftp.osmocom.org/binaries/windows/rtl-sdr/

A partir de plusieurs posts, lus dans les forums français et anglais, j'ai pu réalisé un framework de wrapper, mais je bute principalement sur l'usage des pointeurs pour avoir un ensemble fonctionnel.
D'autre part, j'ai pu tester et utiliser un wrapper pour la DLL de VLC dans une application de player simplifié Purebasic, mais ma compréhension des fichiers sources reste problèmatique ...

Voici le développement actuel pour matériel SDR. Le wrapper compile sans anomalie, mais il ne permet de traiter que 2 fonctions de la DLL, un comptage des clefs RTL-SDR insérées sur ports USB et la récupération du nom de clef.
Je suis preneur de toute information pour avancer sur ce sujet afin de débloquer les fonctions principales de contrôle SDR (fréquence, bande passante, gain, buffer de données,...).

Source wrapper Libsdr.pbi

Code : Tout sélectionner

EnableExplicit

; -------  Structure for SDR device from C header rtlsdr.h
; struct rtlsdr_dev {
; 	libusb_context *ctx;
; 	struct libusb_device_handle *devh;
; 	uint32_t xfer_buf_num;
; 	uint32_t xfer_buf_len;
; 	struct libusb_transfer **xfer;
; 	unsigned char **xfer_buf;
; 	rtlsdr_read_async_cb_t cb;
; 	void *cb_ctx;
; 	enum rtlsdr_async_status async_status;
; 	int async_cancel;
; 	int use_zerocopy;
; 	/* rtl demod context */
; 	uint32_t rate; /* Hz */
; 	uint32_t rtl_xtal; /* Hz */
; 	int fir[FIR_LEN];
; 	int direct_sampling;
; 	/* tuner context */
; 	enum rtlsdr_tuner tuner_type;
; 	rtlsdr_tuner_iface_t *tuner;
; 	uint32_t tun_xtal; /* Hz */
; 	uint32_t freq; /* Hz */
; 	uint32_t bw;
; 	uint32_t offs_freq; /* Hz */
; 	int corr; /* ppm */
; 	int gain; /* tenth dB */
; 	struct e4k_state e4k_s;
; 	struct r82xx_config r82xx_c;
; 	struct r82xx_priv r82xx_p;
; 	/* status */
; 	int dev_lost;
; 	int driver_active;
; 	unsigned int xfer_errors;
; 	char manufact[256];
; 	char product[256];
; };

Structure rtlsdr_dev_t 
  ; content
EndStructure 

Structure rtlsdr_read_async_cb_t
  ; content
EndStructure

Enumeration rtlsdr_tuner_t
	#RTLSDR_TUNER_UNKNOWN = 0
	#RTLSDR_TUNER_E4000   = 1
	#RTLSDR_TUNER_FC0012  = 2
	#RTLSDR_TUNER_FC0013  = 3
	#RTLSDR_TUNER_FC2580  = 4
	#RTLSDR_TUNER_R820T   = 5
	#RTLSDR_TUNER_R828D   = 6
EndEnumeration 

; -------  Variable definitions
Global dev.rtlsdr_dev_t
Global *dev
Global cb.rtlsdr_read_async_cb_t
Global manufact.s
Global *manufact
Global product.s
Global *product
Global serial.s
Global *serial
Global *gains
Global *rtl_freq
Global *tuner_freq
Global *data
Global *ctx
Global index.l=0
Global freq.l=0
Global on.i=0
Global buf_num.l=0
Global buf_len.l=0
Global *data=0
Global offset.l=0
Global len.i=0
Global gpio.i=0
Global ppm.i=0
Global rate.l=0
Global bw.l=0
Global gain.i=0
Global manual.i=0
Global stage.i=0
Global rtl_freq.i=0
Global tuner_freq.i=0
Global n_read.i=0

; ------- Prototype parameters specifications
; RTLSDR_API int rtlsdr_cancel_async(rtlsdr_dev_t *dev);  
  Prototype.l proto_rtlsdr_cancel_async(*dev)
; RTLSDR_API int rtlsdr_close(rtlsdr_dev_t *dev);
  Prototype.l proto_rtlsdr_close(*dev)
; RTLSDR_API uint32_t rtlsdr_get_center_freq(rtlsdr_dev_t *dev);
  Prototype.l proto_rtlsdr_get_center_freq(*dev)
; RTLSDR_API uint32_t rtlsdr_get_device_count(void);
  Prototype.l proto_rtlsdr_get_device_count()
; RTLSDR_API const char* rtlsdr_get_device_name(uint32_t index);
  Prototype proto_rtlsdr_get_device_name(index.l)
; RTLSDR_API int rtlsdr_get_device_usb_strings(uint32_t index, char *manufact, char *product, char *serial);
  Prototype.l proto_rtlsdr_get_device_usb_strings(index.l, *manufact, *product, *serial)
; RTLSDR_API int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on);
  Prototype.l proto_rtlsdr_get_direct_sampling(*dev, on.i)
; RTLSDR_API int rtlsdr_get_freq_correction(rtlsdr_dev_t *dev);
  Prototype.l proto_rtlsdr_get_freq_correction(*dev)
; RTLSDR_API int rtlsdr_get_index_by_serial(const char *serial);
  Prototype.l proto_rtlsdr_get_index_by_serial(*serial)
; RTLSDR_API int rtlsdr_set_offset_tuning(rtlsdr_dev_t *dev, int on);
  Prototype.l proto_rtlsdr_get_offset_tuning(*dev, on.i)
; RTLSDR_API uint32_t rtlsdr_get_sample_rate(rtlsdr_dev_t *dev);
  Prototype.l proto_rtlsdr_get_sample_rate(*dev)
; RTLSDR_API int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev);
  Prototype.l proto_rtlsdr_get_tuner_gain(*dev)
; RTLSDR_API int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains);
  Prototype.l proto_rtlsdr_get_tuner_gains(*dev, *gains)
; RTLSDR_API enum rtlsdr_tuner rtlsdr_get_tuner_type(rtlsdr_dev_t *dev);
  Prototype proto_rtlsdr_get_tuner_type(*dev)
; RTLSDR_API int rtlsdr_get_usb_strings(rtlsdr_dev_t *dev, char *manufact, char *product, char *serial);
  Prototype.l proto_rtlsdr_get_usb_strings(*dev, *manufact, *product, *serial)
; RTLSDR_API int rtlsdr_get_xtal_freq(rtlsdr_dev_t *dev, uint32_t *rtl_freq, uint32_t *tuner_freq);
  Prototype.l proto_rtlsdr_get_xtal_freq(*dev, *rtl_freq, *tuner_freq)
; RTLSDR_API int rtlsdr_open(rtlsdr_dev_t **dev, uint32_t index);
  Prototype.l proto_rtlsdr_open(*dev, index.l)
; RTLSDR_API int rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx, uint32_t buf_num, uint32_t buf_len);
  Prototype.l proto_rtlsdr_read_async(*dev, cb, *ctx, buf_num.l, buf_len.i)
; RTLSDR_API int rtlsdr_read_eeprom(rtlsdr_dev_t *dev, uint8_t *data, uint8_t offset, uint16_t len);
  Prototype.l proto_rtlsdr_read_eeprom(*dev, *data, offset.l, len.i)
; RTLSDR_API int rtlsdr_read_sync(rtlsdr_dev_t *dev, void *buf, int len, int *n_read);
  Prototype.l proto_rtlsdr_read_sync(*dev, *buf, len.i, *n_read)
; RTLSDR_API int rtlsdr_reset_buffer(rtlsdr_dev_t *dev);
  Prototype.l proto_rtlsdr_reset_buffer(*dev)
; RTLSDR_API int rtlsdr_set_agc_mode(rtlsdr_dev_t *dev, int on);
  Prototype.l proto_rtlsdr_set_agc_mode(*dev, on.i)
; RTLSDR_API int rtlsdr_set_bias_tee(rtlsdr_dev_t *dev, int on);
  Prototype.l proto_rtlsdr_set_bias_tee(*dev, on.i)
; RTLSDR_API int rtlsdr_set_bias_tee_gpio(rtlsdr_dev_t *dev, int gpio, int on);
  Prototype.l proto_rtlsdr_set_bias_tee_gpio(*dev, gpio.i, on.i)
; RTLSDR_API int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq);
  Prototype.l proto_rtlsdr_set_center_freq(*dev, freq.l)
; RTLSDR_API int rtlsdr_get_direct_sampling(rtlsdr_dev_t *dev);
  Prototype.l proto_rtlsdr_set_direct_sampling(*dev)
; RTLSDR_API int rtlsdr_set_freq_correction(rtlsdr_dev_t *dev, int ppm);
  Prototype.l proto_rtlsdr_set_freq_correction(*dev, ppm.i)
; RTLSDR_API int rtlsdr_set_offset_tuning(rtlsdr_dev_t *dev, int on);
  Prototype.l proto_rtlsdr_set_offset_tuning(*dev, on.i)
; RTLSDR_API int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t rate);
  Prototype.l proto_rtlsdr_set_sample_rate(*dev, rate.l)
; RTLSDR_API int rtlsdr_set_testmode(rtlsdr_dev_t *dev, int on);
  Prototype.l proto_rtlsdr_set_testmode(*dev, on.i)
; RTLSDR_API int rtlsdr_set_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw);
  Prototype.l proto_rtlsdr_set_tuner_bandwidth(*dev, bw.l)
; RTLSDR_API int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain);
  Prototype.l proto_rtlsdr_set_tuner_gain(*dev, gain.i)
; RTLSDR_API int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int manual);
  Prototype.l proto_rtlsdr_set_tuner_gain_mode(*dev, manual.i)
; RTLSDR_API int rtlsdr_set_tuner_if_gain(rtlsdr_dev_t *dev, int stage, int gain);
  Prototype.l proto_rtlsdr_set_tuner_if_gain(*dev, stage.i, gain.i)
; RTLSDR_API int rtlsdr_set_xtal_freq(rtlsdr_dev_t *dev, uint32_t rtl_freq, uint32_t tuner_freq);
  Prototype.l proto_rtlsdr_set_xtal_freq(*dev, rtl_freq.l, tuner_freq.l)
; RTLSDR_API int rtlsdr_wait_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx);
  Prototype.l proto_rtlsdr_wait_async(*dev, cb, *ctx)
; RTLSDR_API int rtlsdr_write_eeprom(rtlsdr_dev_t *dev, uint8_t *data, uint8_t offset, uint16_t len);
  Prototype.l proto_rtlsdr_write_eeprom(*dev, *data, offset.l, len.i)
  
; ------- Function pointer declaration with prototype type specification  
Global rtlsdr_cancel_async.proto_rtlsdr_cancel_async
Global rtlsdr_close.proto_rtlsdr_close
Global rtlsdr_get_center_freq.proto_rtlsdr_get_center_freq
Global rtlsdr_get_device_count.proto_rtlsdr_get_device_count
Global rtlsdr_get_device_name.proto_rtlsdr_get_device_name
Global rtlsdr_get_device_usb_strings.proto_rtlsdr_get_device_usb_strings
Global rtlsdr_get_direct_sampling.proto_rtlsdr_get_direct_sampling
Global rtlsdr_get_freq_correction.proto_rtlsdr_get_freq_correction
Global rtlsdr_get_index_by_serial.proto_rtlsdr_get_index_by_serial
Global rtlsdr_get_offset_tuning.proto_rtlsdr_get_offset_tuning
Global rtlsdr_get_sample_rate.proto_rtlsdr_get_sample_rate
Global rtlsdr_get_tuner_gain.proto_rtlsdr_get_tuner_gain
Global rtlsdr_get_tuner_gains.proto_rtlsdr_get_tuner_gains
Global rtlsdr_get_tuner_type.proto_rtlsdr_get_tuner_type
Global rtlsdr_get_usb_strings.proto_rtlsdr_get_usb_strings
Global rtlsdr_get_xtal_freq.proto_rtlsdr_get_xtal_freq
Global rtlsdr_open.proto_rtlsdr_open
Global rtlsdr_read_async.proto_rtlsdr_read_async
Global rtlsdr_read_eeprom.proto_rtlsdr_read_eeprom
Global rtlsdr_read_sync.proto_rtlsdr_read_sync
Global rtlsdr_reset_buffer.proto_rtlsdr_reset_buffer
Global rtlsdr_set_agc_mode.proto_rtlsdr_set_agc_mode
Global rtlsdr_set_bias_tee.proto_rtlsdr_set_bias_tee
Global rtlsdr_set_bias_tee_gpio.proto_rtlsdr_set_bias_tee_gpio
Global rtlsdr_set_center_freq.proto_rtlsdr_set_center_freq
Global rtlsdr_set_direct_sampling.proto_rtlsdr_set_direct_sampling
Global rtlsdr_set_freq_correction.proto_rtlsdr_set_freq_correction
Global rtlsdr_set_offset_tuning.proto_rtlsdr_set_offset_tuning
Global rtlsdr_set_sample_rate.proto_rtlsdr_set_sample_rate
Global rtlsdr_set_testmode.proto_rtlsdr_set_testmode
Global rtlsdr_set_tuner_bandwidth.proto_rtlsdr_set_tuner_bandwidth
Global rtlsdr_set_tuner_gain.proto_rtlsdr_set_tuner_gain
Global rtlsdr_set_tuner_gain_mode.proto_rtlsdr_set_tuner_gain_mode
Global rtlsdr_set_tuner_if_gain.proto_rtlsdr_set_tuner_if_gain
Global rtlsdr_set_xtal_freq.proto_rtlsdr_set_xtal_freq
Global rtlsdr_wait_async.proto_rtlsdr_wait_async
Global rtlsdr_write_eeprom.proto_rtlsdr_write_eeprom

; ------- DLL Loading with functions pointers
Procedure.i rtlsdr_LoadDLL()
  Protected hDLL.i

  hDLL = OpenLibrary(#PB_Any, "librtlsdr.dll")
  If hDLL <> 0
    rtlsdr_cancel_async = GetFunction(hDLL, "rtlsdr_cancel_async")
    rtlsdr_close = GetFunction(hDLL, "rtlsdr_close")
    rtlsdr_get_center_freq = GetFunction(hDLL, "rtlsdr_get_center_freq")
    rtlsdr_get_device_count = GetFunction(hDLL, "rtlsdr_get_device_count")
    rtlsdr_get_device_name = GetFunction(hDLL, "rtlsdr_get_device_name")
    rtlsdr_get_device_usb_strings = GetFunction(hDLL, "rtlsdr_get_device_usb_strings")
    rtlsdr_get_direct_sampling = GetFunction(hDLL, "rtlsdr_get_direct_sampling")
    rtlsdr_get_freq_correction = GetFunction(hDLL, "rtlsdr_get_freq_correction")
    rtlsdr_get_index_by_serial = GetFunction(hDLL, "rtlsdr_get_index_by_serial")
    rtlsdr_get_offset_tuning = GetFunction(hDLL, "rtlsdr_get_offset_tuning")
    rtlsdr_get_sample_rate = GetFunction(hDLL, "rtlsdr_get_sample_rate")
    rtlsdr_get_tuner_gain = GetFunction(hDLL, "rtlsdr_get_tuner_gain")
    rtlsdr_get_tuner_gains = GetFunction(hDLL, "rtlsdr_get_tuner_gains")
    rtlsdr_get_tuner_type = GetFunction(hDLL, "rtlsdr_get_tuner_type")
    rtlsdr_get_usb_strings = GetFunction(hDLL, "rtlsdr_get_usb_strings")
    rtlsdr_get_xtal_freq = GetFunction(hDLL, "rtlsdr_get_xtal_freq")
    rtlsdr_open = GetFunction(hDLL, "rtlsdr_open")
    rtlsdr_read_async = GetFunction(hDLL, "rtlsdr_read_async")
    rtlsdr_read_eeprom = GetFunction(hDLL, "rtlsdr_read_eeprom")
    rtlsdr_read_sync = GetFunction(hDLL, "rtlsdr_read_sync")
    rtlsdr_reset_buffer = GetFunction(hDLL, "rtlsdr_reset_buffer")
    rtlsdr_set_agc_mode = GetFunction(hDLL, "rtlsdr_set_agc_mode")
    rtlsdr_set_bias_tee = GetFunction(hDLL, "rtlsdr_set_bias_tee")
    rtlsdr_set_bias_tee_gpio = GetFunction(hDLL, "rtlsdr_set_bias_tee_gpio")
    rtlsdr_set_center_freq = GetFunction(hDLL, "rtlsdr_set_center_freq")
    rtlsdr_set_direct_sampling = GetFunction(hDLL, "rtlsdr_set_direct_sampling")
    rtlsdr_set_freq_correction = GetFunction(hDLL, "rtlsdr_set_freq_correction")
    rtlsdr_set_offset_tuning = GetFunction(hDLL, "rtlsdr_set_offset_tuning")
    rtlsdr_set_sample_rate = GetFunction(hDLL, "rtlsdr_set_sample_rate")
    rtlsdr_set_testmode = GetFunction(hDLL, "rtlsdr_set_testmode")
    rtlsdr_set_tuner_bandwidth = GetFunction(hDLL, "rtlsdr_set_tuner_bandwidth")
    rtlsdr_set_tuner_gain = GetFunction(hDLL, "rtlsdr_set_tuner_gain")
    rtlsdr_set_tuner_gain_mode = GetFunction(hDLL, "rtlsdr_set_tuner_gain_mode")
    rtlsdr_set_tuner_if_gain = GetFunction(hDLL, "rtlsdr_set_tuner_if_gain")
    rtlsdr_set_xtal_freq = GetFunction(hDLL, "rtlsdr_set_xtal_freq")
    rtlsdr_wait_async = GetFunction(hDLL, "rtlsdr_wait_async")
    rtlsdr_write_eeprom = GetFunction(hDLL, "rtlsdr_write_eeprom")
    ProcedureReturn hDLL
  EndIf
  ProcedureReturn #False
EndProcedure
Programme de test: FunctionCall.pb

Code : Tout sélectionner

IncludeFile "libsdr.pbi"
EnableExplicit

CompilerIf #PB_Compiler_OS <> #PB_OS_Windows
    CompilerError "Windows only compilation"
  CompilerEndIf
  
; -------  Structures
  Structure info_tuner_t
    manufact.s
    Product.s
    serial.s
  EndStructure  
  
; -------  Variable definitions
  Global counter.l=0
  Global sdr_Name.s=""
  Global myfreq.l
  Global rtl_sdr_tuner.s
  Global mytuner.info_tuner_t
  Global tuner_type.l=0

; ------- Functions list inside DLL
; If OpenLibrary(1,"librtlsdr.dll")
;   ExamineLibraryFunctions(1)
;   While NextLibraryFunction()
;     Debug LibraryFunctionName()
;   Wend
; EndIf

; ------- SDR Helpers procedures
Procedure.s safePeekS(ps, len=-1)
	If ps:ProcedureReturn PeekS(ps, len, #PB_UTF8):EndIf
EndProcedure

Procedure.l open_sdr(index.l)
  rtlsdr_open(dev, index.l)
EndProcedure

Procedure.l get_device_count()
  counter.l=rtlsdr_get_device_count()
EndProcedure

Procedure.s get_device_name(index.l)
  sdr_name.s=safePeekS(rtlsdr_get_device_name(index.l), -1)
EndProcedure

Procedure.l get_tuner_type()
  tuner_type.l=rtlsdr_get_tuner_type(*dev)
EndProcedure

Procedure set_center_frequency(freq.l)
  rtlsdr_set_center_freq(*dev, freq.l)
EndProcedure

Procedure.l get_center_frequency()
  myfreq.l=rtlsdr_get_center_freq(*dev)
EndProcedure

Procedure close_sdr()
  rtlsdr_close(*dev)
EndProcedure

Procedure get_usb_strings(index.l)
  rtlsdr_get_device_usb_strings(index.l, *manufact, *product, *serial)
  manufact.s=safePeekS(*manufact, -1)
  product.s=safePeekS(*product, -1)
  serial.s=safePeekS(*serial, -1)
EndProcedure

; ------- SDR Tests access
  If rtlsdr_LoadDll()
    open_sdr(0)
    get_device_count()
    get_device_name(0)
    get_tuner_type()
    set_center_frequency(92200000)
    get_center_frequency()
    get_usb_strings(0)
    MessageRequester ("SDR Info", "SDR Count: "+ Str(counter.l) + Chr(10) + Chr(13) + "SDR Name: " + sdr_name.s, #PB_MessageRequester_Ok)
    MessageRequester ("SDR Info", "SDR Type: "+ tuner_type.l, #PB_MessageRequester_Ok)
    MessageRequester ("SDR Info", "Frequency: "+ myfreq.l +Chr(10) + Chr(13) + "Device: " + manufact.s + "/" + product.s + "/" + serial.s, #PB_MessageRequester_Ok)
    close_sdr()
  EndIf
 
End
Avatar de l’utilisateur
threedslider
Messages : 452
Inscription : dim. 01/juil./2018 22:38

Re: Wrapper DLL RTL-SDR

Message par threedslider »

Hello et bienvenu au forum de Purebasic :)

Bon je suis loin de compétence en matière radio, pour utiliser les pointeurs faut utiliser les structures dans Purebasic voici ses documentations : https://www.purebasic.com/french/docume ... tures.html et celui là aussi https://www.purebasic.com/french/docume ... emory.html et pour accéder au fichier DLL dans Purebasic c'est ici https://www.purebasic.com/french/docume ... types.html.

Effectivement tu peux construire aussi ta propre DLL : https://www.purebasic.com/french/docume ... e/dll.html

Voilà j'espère d'avoir aider un peu sur ton projet et bonne chance ;)
Avatar de l’utilisateur
vertexview
Messages : 10
Inscription : mer. 24/janv./2024 16:02

Re: Wrapper DLL RTL-SDR

Message par vertexview »

Merci threedslider.

Je me suis inscrit également sur le forum Purebasic anglais, et le code du wrapper évolue de manière significative avec l'aide importante d'infratec
https://www.purebasic.fr/english/viewtopic.php?t=83421

Pour le moment, les tests d'accès SDR réalisés sont simples, mais ils vont dans le bon sens :)
Avatar de l’utilisateur
vertexview
Messages : 10
Inscription : mer. 24/janv./2024 16:02

Re: Wrapper DLL RTL-SDR

Message par vertexview »

Bonjour,
Le wrapper de DLL pour RTL-SDR est pleinement opérationnel.
J'ai essayé avec succès de créer un décodeur ADSB simple avec ce wrapper Purebasic.
Le code SimpleADSB_sync.pb présenté ci-dessous est dérivé du source C original d'Osmocom (rtl_adsb.c) et de son portage en Delphi/Pascal (expérimentation Randall, partie rtl_syncread).

Le test a été réalisé pour exécuter une application console la plus simple possible, avec une lecture de type synchrone du buffer SDR I/Q.

Principales sources en C et Delphi :
https://github.com/osmocom/rtl-sdr/blob ... rtl_adsb.c
https://sourceforge.net/projects/rtl-ad ... port/files

Documentation du protocole ADSB :
https://github.com/junzis
https://mode-s.org/decode
Livre gratuit de Junzi Sun (PDF) : https://mode-s.org/decode/book-the_1090 ... zi_sun.pdf

Documentation sur le traitement de données I/Q
https://www.pe0sat.vgnet.nl/sdr/iq-data-explained
https://k3xec.com/packrat-processing-iq

Ce code a été réalisé à des fins éducatives.
SimpleADSB_sync.pb

Code : Tout sélectionner

EnableExplicit
IncludeFile "librtlsdr.pbi"

#SDR_SRATE		=2000000
#ADSB_FREQ		=1090000000
#SDR_GAIN     =439
#PREAMBLE_LEN =16
#LONG_FRAME   =112
#SHORT_FRAME  =56
#MESSAGEGO    =253
#OVERWRITE    =254
#BAD_SAMPLE   =255
#BUF_LENGTH	  =16*16384

Define.i i, r, n_read
Define.l dev_index
Define.i device_count
Define *dev.rtlsdr_dev_t
Define *buf
Define *n_read

Global length = 0
Global block_size.i=#BUF_LENGTH
Global StopReadingSamples.b=#False
Global Dim pythagore.a(128,128)
Global Dim adsb_frame.a(14)
Global Dim buffer.a(block_size)

Global allowed_errors.i = 5
Global quality.i = 20
Global short_output.i = 0
Global verbose_output.i = 1
Global lf_counter.i = 0
Global sf_counter.i = 0
Global show_stats.b = #False

Procedure.i abs8(x.i)
  If x >= 128
    ProcedureReturn x - 128
  Else  
    ProcedureReturn 128 - x
  EndIf  
EndProcedure

Procedure pythagore_precompute()
  Protected.i  x, y
  Protected.f  scale
  Protected.a  value

  scale = 1.408
  For x = 0 To 128
    For y = 0 To 128
      value=Round(scale * Sqr(x*x + y*y), #PB_Round_Nearest)
      pythagore.a(x, y) = value
    Next y  
  Next x
EndProcedure

Procedure magnitude(buf.a, len)
  Protected.i i,j
  Protected.a sq
  
  ; takes IQ samples. Changes in place with the magnitude value (Char/uint8_t) 
  For i=0 To len-1 Step 2
    sq.a = pythagore(abs8(buffer(i)), abs8(buffer(i + 1)))
    buffer(Int(i/2))=sq.a
  Next i
  
  ;returns new buffer length
  ProcedureReturn len/2
EndProcedure

Procedure.a single_manchester(a.a, b.a, c.a, d.a)
  Protected bit.a, bit_p.a
  
  ; takes 4 consecutive samples, return 0 or 1, #BADSAMPLE on error
  If a>b
    bit_p=1
  Else
    bit_p=0
  EndIf
  
  If c>d
    bit=1
  Else
    bit=0
  EndIf

  If quality=0
    ; no sanity check
    ProcedureReturn bit
  EndIf  

  If quality=5
    ; sanity check half-bit
    If ((bit=1) And (bit_p=1) And (b>c))
      ProcedureReturn #BAD_SAMPLE
    EndIf  
    If ((bit=0) And (bit_p=0) And (b<c))
      ProcedureReturn #BAD_SAMPLE
    EndIf  
    ProcedureReturn bit
  EndIf

  If quality=10
    ; sanity check one bit
    If ((bit=1) And (bit_p=1) And (c>b))
      ProcedureReturn 1
    EndIf
    If ((bit=1) And (bit_p=0) And (d<b))
      ProcedureReturn 1
    EndIf
    If ((bit=0) And (bit_p=1) And (d>b))
      ProcedureReturn 0
    EndIf
    If ((bit=0) And (bit_p=0) And (c<b))
      ProcedureReturn 0
    EndIf  
    ProcedureReturn #BAD_SAMPLE
  EndIf
  
  ; Sanity check two bits
  If ((bit=1) And (bit_p=1) And (c>b) And (d<a))
    ProcedureReturn 1
  EndIf  
  If ((bit=1) And (bit_p=0) And (c>a) And (d<b))
    ProcedureReturn 1
  EndIf  
  If ((bit=0) And (bit_p=1) And (c<a) And (d>b))
    ProcedureReturn 0
  EndIf
  If ((bit=0) And (bit_p=0) And (c<b) And (d>a))
    ProcedureReturn 0
  EndIf
  ProcedureReturn #BAD_SAMPLE
EndProcedure

Procedure preamble(buf.a, i.i)
  Protected i2.i
  Protected low.a, high.a
  
  low.a = 0
  high.a = 255
  ; Returns 0/1 for preamble at index i
  For i2 = 0 To #PREAMBLE_LEN-1
    Select i2 
      Case 0,2,7,9
        high = buffer(i+i2)
      Default
        low = buffer(i+i2)
    EndSelect

    If high <= low
      ProcedureReturn 0
    EndIf
  Next i2
  
  ; Preamble sequence found
  ProcedureReturn 1
EndProcedure

Procedure manchester(buf.a, len)
  Protected a.a, b.a, bit.a
  Protected i.i, i2.i, errors.i
  
  a = 0
  b = 0
  i = 0
  ; Overwrites magnitude buffer with valid bits (#BADSAMPLE on errors)
  While (i < len)
    ; Search a preamble sequence
    While i < len - #PREAMBLE_LEN
      If preamble(@buffer.a(), i) = 0
        i+1
        Continue
      EndIf
      
      ; preamble found at index i
      a = buffer(i)
      b = buffer(i + 1)
      For i2 = 0 To #PREAMBLE_LEN-1
        ; ovewrite buffer sequence with #MESSAGEGO
        buffer(i + i2) = #MESSAGEGO
      Next i2
      
      ; new index after preamble sequence
      i= i+#PREAMBLE_LEN
      Break
    Wend
    
    i2 = i
    errors = 0
    ; Mark bits until encoding breaks
    While (i < len)
      bit = single_manchester(a, b, buffer(i), buffer(i + 1))
      a = buffer(i)
      b = buffer(i + 1)
      If bit = #BAD_SAMPLE
        errors+1
        If errors > allowed_errors
          buffer(i2) = #BAD_SAMPLE
          Break
        Else
          If a>b
            bit = 1
          Else
            bit = 0
          EndIf  
          a = 0
          b = 255
        EndIf
      EndIf
      
      buffer(i) = #OVERWRITE
      buffer(i + 1) = #OVERWRITE
      buffer(i2) = bit
      i+2
      i2+1
    Wend
  Wend
  
EndProcedure

Procedure display(frame.a, len.i)
  Protected i.i
  Protected df.a, value.a, icao.i, pcode.i, tcode.a, stype.a
  Protected test.b
  
  If (short_output = 0) And (len <= #SHORT_FRAME)
    ProcedureReturn
  EndIf
  
  df = (adsb_frame(0) >> 3) & $1F

  If Quality=0 And Not ((df = 11) Or (df = 17) Or (df = 18) Or (df = 19))
    ProcedureReturn
  EndIf  
  
  Print("#")
  For i = 0 To (Int(len + 7)/8)-1
    Print(RSet(Hex(adsb_frame(i),#PB_Ascii),2,"0"))
  Next i  
  PrintN("")
  
  If verbose_output = 1
    PrintN(FormatDate(" %yyyy/%mm/%mm/%dd %hh:%ii:%ss", Date()))
    value=adsb_frame(0) & $07
    PrintN(" DF="+df+ " CA="+value)
    icao =(adsb_frame(1) << 16) | (adsb_frame(2) << 8) | adsb_frame(3)
    PrintN(" ICAO= "+RSet(Hex(icao),6,"0"))
  EndIf

  If len <= #SHORT_FRAME
    ProcedureReturn
  EndIf  

  If verbose_output = 1
    pcode=(adsb_frame(11) << 16) | (adsb_frame(12) << 8) | adsb_frame(13)
    tcode=(adsb_frame(4) >> 3) & $1F
    stype=adsb_frame(4) & $07
    ;PrintN(" PI_code= "+pcode)
    PrintN(" PI_code= 0x"+RSet(Hex(pcode),6,"0"))
    PrintN(" Type_code= "+tcode)
    PrintN(" S_type/ant= "+stype)
  EndIf

EndProcedure

Procedure outmessages(buf.a, len)
  Protected.i i, index
  Protected.a shift, frame_len, val_shift, data_i
  
  i =0
  lf_counter =0
  sf_counter =0
  
  While i< len
    If buffer(i) > 1
      i+1
      Continue
    EndIf
    
    frame_len = #LONG_FRAME
    data_i = 0
    For index = 0 To 13
      adsb_frame(index) = 0
    Next index  

    While (i < len) And (buffer(i) <= 1) And (data_i < frame_len)
      If buffer(i) = 1
        index = Int(data_i / 8)
        shift = 7 - (data_i % 8)
        val_shift = 1 << shift
        adsb_frame(index) = adsb_frame(index) | val_shift
      EndIf
      
      If data_i = 7
        If adsb_frame(0) = 0
          Break
        EndIf  
        
        If adsb_frame(0) & $80 <> 0
          frame_len = #LONG_FRAME
          lf_counter+1
        Else
          frame_len = #SHORT_FRAME
          sf_counter+1
        EndIf  
      EndIf

      i+1
      data_i+1
    Wend
    
    If data_i < frame_len-1
      i+1
      Continue
    EndIf
    
    display(adsb_frame.a(), frame_len)
    i+1
  Wend
  
EndProcedure

Procedure.i demodulation()
  lf_counter = 0
  sf_counter = 0
  
  length = magnitude(@buffer.a(), block_size)
  manchester(@buffer.a(), length)
  outmessages(@buffer.a(), length)
  
  If show_stats=#True
    PrintN("ADSB frames (Long/Short): "+Str(lf_counter)+"/"+Str(sf_counter))
  EndIf  
EndProcedure

; ------- Main -------

pythagore_precompute()
OpenConsole()

If UseLibrtlsdr()
  
  device_count = rtlsdr_get_device_count()
  If Not device_count
    PrintN("No supported devices found.")
    End 1
  EndIf
  
  PrintN("Found " + Str(device_count) + " device(s)")
  For i = 0 To device_count - 1
    PrintN("  " + Str(i) + ":  " + PeekS(rtlsdr_get_device_name(i), -1, #PB_UTF8))
  Next i
  PrintN("")
  PrintN("Using device " + Str(dev_index) + ": " + PeekS(rtlsdr_get_device_name(dev_index), -1, #PB_UTF8))
  
  r = rtlsdr_open(@*dev, dev_index)
  If r < 0
    PrintN("Failed to open rtlsdr device #" + Str(dev_index))
    End 1
  EndIf
  PrintN("")
  
  rtlsdr_set_center_freq(*dev, #ADSB_FREQ)
  rtlsdr_set_sample_rate(*dev, #SDR_SRATE)
  rtlsdr_set_tuner_gain(*dev, #SDR_GAIN) 
  rtlsdr_set_agc_mode(*dev, 1)
  PrintN("Tuned to "+ rtlsdr_get_center_freq(*dev) + " Hz")
  PrintN("Tuner gain: "+ rtlsdr_get_tuner_gain(*dev))
  
  r = rtlsdr_reset_buffer(*dev)
  If r < 0
    PrintN("Failed to reset buffer")
  EndIf
  
  PrintN("Reading samples in sync mode")
  PrintN("")
  
  While #True
    r = rtlsdr_read_sync(*dev, @buffer.a(), block_size, @n_read)
    
    If r < 0
      PrintN("Buffer Sync read failed\n")
    EndIf
    If n_read < block_size
      PrintN("Short read, samples lost\n" + n_read)
      Break
    EndIf
    If StopReadingSamples
      Break
    EndIf
    
    ; IQ Buffer data processing
    Demodulation()
  Wend
    
  rtlsdr_close(*dev)
  If r >= 0
    End r
  Else
    End -r
  EndIf
  
EndIf

CompilerIf #PB_Compiler_Debugger
  Input()
CompilerEndIf

CloseConsole()
Avatar de l’utilisateur
Ar-S
Messages : 9539
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: Wrapper DLL RTL-SDR

Message par Ar-S »

Bravo à toi. Je n'ai pas de quoi le tester mais tu as l'air de t'éclater. ça fait plaisir.
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Avatar de l’utilisateur
threedslider
Messages : 452
Inscription : dim. 01/juil./2018 22:38

Re: Wrapper DLL RTL-SDR

Message par threedslider »

Super cool de ton avancement ! :D

Par contre pour la tester faut ton fichier Librtlsdr.pbi... pourrais tu nous le fournir si possible afin de tester ton programme ?

Merci et bravo à toi :wink:
Avatar de l’utilisateur
vertexview
Messages : 10
Inscription : mer. 24/janv./2024 16:02

Re: Wrapper DLL RTL-SDR

Message par vertexview »

Bonsoir,
Voici le code du wrapper de DLL.
Les échanges concernant sa mise au point, avec l'aide décisive d'infratec, sont disponibles sur le forum anglais Purebasic.
https://www.purebasic.fr/english/viewtopic.php?t=83421

A noter également, dans cette partie du forum, une version de l'application Osmocom rtl_eeprom. La conversion du source C en Purebasic a été réalisée par infratec. J'ai pu tester cette version qui se comporte de manière identique à l'utilitaire rtl_eeprom.exe fourni dans le pack driver rtl-sdr Osmocom.
Source d'origine: https://github.com/osmocom/rtl-sdr/blob ... l_eeprom.c.

librtlsdr.pbi

Code : Tout sélectionner

;
; Osmocom project: https://osmocom.org/projects/rtl-sdr/wiki
; Github driver sources: https://github.com/osmocom/rtl-sdr
; Last Windows drivers builds: https://ftp.osmocom.org/binaries/windows/rtl-sdr/
;

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf

Enumeration e4k_band
  #E4K_BAND_VHF2
  #E4K_BAND_VHF3
  #E4K_BAND_UHF
  #E4K_BAND_L
EndEnumeration
Macro e4k_band
  i
EndMacro

#NUM_REGS	= 30

Enumeration r82xx_chip
  #CHIP_R820T
  #CHIP_R620D
  #CHIP_R828D
  #CHIP_R828
  #CHIP_R828S
  #CHIP_R820C
EndEnumeration
Macro r82xx_chip
  i
EndMacro

Enumeration r82xx_xtal_cap_value
  #XTAL_LOW_CAP_30P
  #XTAL_LOW_CAP_20P
  #XTAL_LOW_CAP_10P
  #XTAL_LOW_CAP_0P
  #XTAL_HIGH_CAP_0P
EndEnumeration
Macro r82xx_xtal_cap_value
  i
EndMacro

Enumeration r82xx_tuner_type
  #TUNER_RADIO = 1
  #TUNER_ANALOG_TV
  #TUNER_DIGITAL_TV
EndEnumeration
Macro r82xx_tuner_type
  i
EndMacro

Enumeration rtlsdr_tuner
  #RTLSDR_TUNER_UNKNOWN
  #RTLSDR_TUNER_E4000
  #RTLSDR_TUNER_FC0012
  #RTLSDR_TUNER_FC0013
  #RTLSDR_TUNER_FC2580
  #RTLSDR_TUNER_R820T
  #RTLSDR_TUNER_R828D
EndEnumeration
Macro rtlsdr_tuner_t
  i
EndMacro

Enumeration rtlsdr_async_status
  #RTLSDR_INACTIVE
  #RTLSDR_CANCELING
  #RTLSDR_RUNNING
EndEnumeration
Macro rtlsdr_async_status
  i
EndMacro

#FIR_LEN = 16

PrototypeC.l Prototype_init()
PrototypeC.l Prototype_exit()
PrototypeC.l Prototype_set_freq(*p, freq.l)
PrototypeC.l Prototype_set_bw(*p, bw.l)
PrototypeC.l Prototype_set_gain(*p, gain.l)
PrototypeC.l Prototype_set_if_gain(*p, stage.l, gain.l)
PrototypeC.l Prototype_set_gain_mode(*p, manual.l)

Structure rtlsdr_tuner_iface Align #PB_Structure_AlignC
  ; tuner Interface
  init.Prototype_init
  exit.Prototype_exit
  set_freq.Prototype_set_freq
  set_bw.Prototype_set_bw
  set_gain.Prototype_set_gain
  set_if_gain.Prototype_set_if_gain
  set_gain_mode.Prototype_set_gain_mode
EndStructure
Macro rtlsdr_tuner_iface_t
  rtlsdr_tuner_iface
EndMacro

Structure e4k_pll_params Align #PB_Structure_AlignC
  fosc.l
  intended_flo.l
  flo.l
  x.u
  z.a
  r.a
  r_idx.a
  threephase.a
EndStructure

Structure e4k_state Align #PB_Structure_AlignC
  *i2c_dev
  i2c_addr.a
  band.e4k_band
  vco.e4k_pll_params
  *rtl_dev
EndStructure

Structure r82xx_config Align #PB_Structure_AlignC
  i2c_addr.a
  xtal.l
  rafael_chip.r82xx_chip
  max_i2c_msg_len.l
  use_predetect.l
EndStructure

Structure r82xx_priv Align #PB_Structure_AlignC
  *cfg.r82xx_config
  
  regs.a[#NUM_REGS]
  buf.a[#NUM_REGS + 1]
  xtal_cap_sel.r82xx_xtal_cap_value
  pll.u           ;	kHz
  int_freq.l
  fil_cal_code.a
  input.a
  has_lock.l
  init_done.l
  
  ; Store current mode
  delsys.l
  type.r82xx_tuner_type
  
  bw.l  ;	in MHz
  
  *rtl_dev
EndStructure

PrototypeC rtlsdr_read_async_cb_t(*buf, len.l, *ctx)

Structure rtlsdr_dev Align #PB_Structure_AlignC
  *ctx
  *devh
  xfer_buf_num.l
  xfer_buf_len.l
  *xfer
  *xfer_buf
  cb.rtlsdr_read_async_cb_t
  *cb_ctx
  async_status.rtlsdr_async_status
  async_cancel.l
  use_zerocopy.l
  ; rtl demod context
  rate.l      ; Hz
  rtl_xtal.l  ; Hz
  fir.l[#FIR_LEN]
  direct_sampling.l
  ; tuner context
  tuner_type.rtlsdr_tuner_t
  *tuner.rtlsdr_tuner_iface_t
  tun_xtal.l  ; Hz
  freq.l      ; Hz
  bw.l
  offs_freq.l ; Hz
  corr.l      ; ppm
  gain.l      ; tenth dB
  e4k_s.e4k_state
  r82xx_c.r82xx_config
  r82xx_p.r82xx_priv
  ; status
  dev_lost.l
  driver_active.l
  xfer_errors.l
  manufact.a[256]
  product.a[256]
EndStructure 
Macro rtlsdr_dev_t
  rtlsdr_dev
EndMacro


; ------- Prototype parameters specifications
PrototypeC.l proto_rtlsdr_cancel_async(*dev.rtlsdr_dev_t)
PrototypeC.l proto_rtlsdr_close(*dev.rtlsdr_dev_t)
PrototypeC.l proto_rtlsdr_get_center_freq(*dev.rtlsdr_dev_t)
PrototypeC.l proto_rtlsdr_get_device_count()
PrototypeC proto_rtlsdr_get_device_name(index.l)
PrototypeC.l proto_rtlsdr_get_device_usb_strings(index.l, *manufact, *product, *serial)
PrototypeC.l proto_rtlsdr_get_direct_sampling(*dev.rtlsdr_dev_t, on.l)
PrototypeC.l proto_rtlsdr_get_freq_correction(*dev.rtlsdr_dev_t)
PrototypeC.l proto_rtlsdr_get_index_by_serial(serial.p-utf8)
PrototypeC.l proto_rtlsdr_get_offset_tuning(*dev.rtlsdr_dev_t, on.l)
PrototypeC.l proto_rtlsdr_get_sample_rate(*dev.rtlsdr_dev_t)
PrototypeC.l proto_rtlsdr_get_tuner_gain(*dev.rtlsdr_dev_t)
PrototypeC.l proto_rtlsdr_get_tuner_gains(*dev.rtlsdr_dev_t, *gains)
PrototypeC proto_rtlsdr_get_tuner_type(*dev.rtlsdr_dev_t)
PrototypeC.l proto_rtlsdr_get_usb_strings(*dev.rtlsdr_dev_t, *manufact, *product, *serial)
PrototypeC.l proto_rtlsdr_get_xtal_freq(*dev.rtlsdr_dev_t, *rtl_freq, *tuner_freq)
PrototypeC.l proto_rtlsdr_open(*pdev, index.l)
PrototypeC.l proto_rtlsdr_read_async(*dev.rtlsdr_dev_t, cb.rtlsdr_read_async_cb_t, *ctx, buf_num.l, buf_len.l)
PrototypeC.l proto_rtlsdr_read_eeprom(*dev.rtlsdr_dev_t, *data, offset.a, len.l)
PrototypeC.l proto_rtlsdr_read_sync(*dev.rtlsdr_dev_t, *buf, len.l, *n_read)
PrototypeC.l proto_rtlsdr_reset_buffer(*dev.rtlsdr_dev_t)
PrototypeC.l proto_rtlsdr_set_agc_mode(*dev.rtlsdr_dev_t, on.l)
PrototypeC.l proto_rtlsdr_set_bias_tee(*dev.rtlsdr_dev_t, on.l)
PrototypeC.l proto_rtlsdr_set_bias_tee_gpio(*dev.rtlsdr_dev_t, gpio.l, on.l)
PrototypeC.l proto_rtlsdr_set_center_freq(*dev.rtlsdr_dev_t, freq.l)
PrototypeC.l proto_rtlsdr_set_direct_sampling(*dev.rtlsdr_dev_t)
PrototypeC.l proto_rtlsdr_set_freq_correction(*dev.rtlsdr_dev_t, ppm.l)
PrototypeC.l proto_rtlsdr_set_offset_tuning(*dev.rtlsdr_dev_t, on.l)
PrototypeC.l proto_rtlsdr_set_sample_rate(*dev.rtlsdr_dev_t, rate.l)
PrototypeC.l proto_rtlsdr_set_testmode(*dev.rtlsdr_dev_t, on.l)
PrototypeC.l proto_rtlsdr_set_tuner_bandwidth(*dev.rtlsdr_dev_t, bw.l)
PrototypeC.l proto_rtlsdr_set_tuner_gain(*dev.rtlsdr_dev_t, gain.l)
PrototypeC.l proto_rtlsdr_set_tuner_gain_mode(*dev.rtlsdr_dev_t, manual.l)
PrototypeC.l proto_rtlsdr_set_tuner_if_gain(*dev.rtlsdr_dev_t, stage.l, gain.l)
PrototypeC.l proto_rtlsdr_set_xtal_freq(*dev.rtlsdr_dev_t, rtl_freq.l, tuner_freq.l)
PrototypeC.l proto_rtlsdr_wait_async(*dev.rtlsdr_dev_t, cb.rtlsdr_read_async_cb_t, *ctx)
PrototypeC.l proto_rtlsdr_write_eeprom(*dev.rtlsdr_dev_t, *data, offset.a, len.u)

; ------- Function pointer declaration with prototype type specification  
Global rtlsdr_cancel_async.proto_rtlsdr_cancel_async
Global rtlsdr_close.proto_rtlsdr_close
Global rtlsdr_get_center_freq.proto_rtlsdr_get_center_freq
Global rtlsdr_get_device_count.proto_rtlsdr_get_device_count
Global rtlsdr_get_device_name.proto_rtlsdr_get_device_name
Global rtlsdr_get_device_usb_strings.proto_rtlsdr_get_device_usb_strings
Global rtlsdr_get_direct_sampling.proto_rtlsdr_get_direct_sampling
Global rtlsdr_get_freq_correction.proto_rtlsdr_get_freq_correction
Global rtlsdr_get_index_by_serial.proto_rtlsdr_get_index_by_serial
Global rtlsdr_get_offset_tuning.proto_rtlsdr_get_offset_tuning
Global rtlsdr_get_sample_rate.proto_rtlsdr_get_sample_rate
Global rtlsdr_get_tuner_gain.proto_rtlsdr_get_tuner_gain
Global rtlsdr_get_tuner_gains.proto_rtlsdr_get_tuner_gains
Global rtlsdr_get_tuner_type.proto_rtlsdr_get_tuner_type
Global rtlsdr_get_usb_strings.proto_rtlsdr_get_usb_strings
Global rtlsdr_get_xtal_freq.proto_rtlsdr_get_xtal_freq
Global rtlsdr_open.proto_rtlsdr_open
Global rtlsdr_read_async.proto_rtlsdr_read_async
Global rtlsdr_read_eeprom.proto_rtlsdr_read_eeprom
Global rtlsdr_read_sync.proto_rtlsdr_read_sync
Global rtlsdr_reset_buffer.proto_rtlsdr_reset_buffer
Global rtlsdr_set_agc_mode.proto_rtlsdr_set_agc_mode
Global rtlsdr_set_bias_tee.proto_rtlsdr_set_bias_tee
Global rtlsdr_set_bias_tee_gpio.proto_rtlsdr_set_bias_tee_gpio
Global rtlsdr_set_center_freq.proto_rtlsdr_set_center_freq
Global rtlsdr_set_direct_sampling.proto_rtlsdr_set_direct_sampling
Global rtlsdr_set_freq_correction.proto_rtlsdr_set_freq_correction
Global rtlsdr_set_offset_tuning.proto_rtlsdr_set_offset_tuning
Global rtlsdr_set_sample_rate.proto_rtlsdr_set_sample_rate
Global rtlsdr_set_testmode.proto_rtlsdr_set_testmode
Global rtlsdr_set_tuner_bandwidth.proto_rtlsdr_set_tuner_bandwidth
Global rtlsdr_set_tuner_gain.proto_rtlsdr_set_tuner_gain
Global rtlsdr_set_tuner_gain_mode.proto_rtlsdr_set_tuner_gain_mode
Global rtlsdr_set_tuner_if_gain.proto_rtlsdr_set_tuner_if_gain
Global rtlsdr_set_xtal_freq.proto_rtlsdr_set_xtal_freq
Global rtlsdr_wait_async.proto_rtlsdr_wait_async
Global rtlsdr_write_eeprom.proto_rtlsdr_write_eeprom

Global librtlsdr.i

; ------- DLL Loading with functions pointers
Procedure.i UseLibrtlsdr()
  
  If Not IsLibrary(librtlsdr)
    
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        librtlsdr = OpenLibrary(#PB_Any, "librtlsdr.dll")
      CompilerCase #PB_OS_Linux
        librtlsdr = OpenLibrary(#PB_Any, "librtlsdr.so")
      CompilerCase #PB_OS_MacOS
        librtlsdr = OpenLibrary(#PB_Any, "librtlsdr.dylib")
    CompilerEndSelect
    If librtlsdr <> 0
      rtlsdr_cancel_async = GetFunction(librtlsdr, "rtlsdr_cancel_async")
      rtlsdr_close = GetFunction(librtlsdr, "rtlsdr_close")
      rtlsdr_get_center_freq = GetFunction(librtlsdr, "rtlsdr_get_center_freq")
      rtlsdr_get_device_count = GetFunction(librtlsdr, "rtlsdr_get_device_count")
      rtlsdr_get_device_name = GetFunction(librtlsdr, "rtlsdr_get_device_name")
      rtlsdr_get_device_usb_strings = GetFunction(librtlsdr, "rtlsdr_get_device_usb_strings")
      rtlsdr_get_direct_sampling = GetFunction(librtlsdr, "rtlsdr_get_direct_sampling")
      rtlsdr_get_freq_correction = GetFunction(librtlsdr, "rtlsdr_get_freq_correction")
      rtlsdr_get_index_by_serial = GetFunction(librtlsdr, "rtlsdr_get_index_by_serial")
      rtlsdr_get_offset_tuning = GetFunction(librtlsdr, "rtlsdr_get_offset_tuning")
      rtlsdr_get_sample_rate = GetFunction(librtlsdr, "rtlsdr_get_sample_rate")
      rtlsdr_get_tuner_gain = GetFunction(librtlsdr, "rtlsdr_get_tuner_gain")
      rtlsdr_get_tuner_gains = GetFunction(librtlsdr, "rtlsdr_get_tuner_gains")
      rtlsdr_get_tuner_type = GetFunction(librtlsdr, "rtlsdr_get_tuner_type")
      rtlsdr_get_usb_strings = GetFunction(librtlsdr, "rtlsdr_get_usb_strings")
      rtlsdr_get_xtal_freq = GetFunction(librtlsdr, "rtlsdr_get_xtal_freq")
      rtlsdr_open = GetFunction(librtlsdr, "rtlsdr_open")
      rtlsdr_read_async = GetFunction(librtlsdr, "rtlsdr_read_async")
      rtlsdr_read_eeprom = GetFunction(librtlsdr, "rtlsdr_read_eeprom")
      rtlsdr_read_sync = GetFunction(librtlsdr, "rtlsdr_read_sync")
      rtlsdr_reset_buffer = GetFunction(librtlsdr, "rtlsdr_reset_buffer")
      rtlsdr_set_agc_mode = GetFunction(librtlsdr, "rtlsdr_set_agc_mode")
      rtlsdr_set_bias_tee = GetFunction(librtlsdr, "rtlsdr_set_bias_tee")
      rtlsdr_set_bias_tee_gpio = GetFunction(librtlsdr, "rtlsdr_set_bias_tee_gpio")
      rtlsdr_set_center_freq = GetFunction(librtlsdr, "rtlsdr_set_center_freq")
      rtlsdr_set_direct_sampling = GetFunction(librtlsdr, "rtlsdr_set_direct_sampling")
      rtlsdr_set_freq_correction = GetFunction(librtlsdr, "rtlsdr_set_freq_correction")
      rtlsdr_set_offset_tuning = GetFunction(librtlsdr, "rtlsdr_set_offset_tuning")
      rtlsdr_set_sample_rate = GetFunction(librtlsdr, "rtlsdr_set_sample_rate")
      rtlsdr_set_testmode = GetFunction(librtlsdr, "rtlsdr_set_testmode")
      rtlsdr_set_tuner_bandwidth = GetFunction(librtlsdr, "rtlsdr_set_tuner_bandwidth")
      rtlsdr_set_tuner_gain = GetFunction(librtlsdr, "rtlsdr_set_tuner_gain")
      rtlsdr_set_tuner_gain_mode = GetFunction(librtlsdr, "rtlsdr_set_tuner_gain_mode")
      rtlsdr_set_tuner_if_gain = GetFunction(librtlsdr, "rtlsdr_set_tuner_if_gain")
      rtlsdr_set_xtal_freq = GetFunction(librtlsdr, "rtlsdr_set_xtal_freq")
      rtlsdr_wait_async = GetFunction(librtlsdr, "rtlsdr_wait_async")
      rtlsdr_write_eeprom = GetFunction(librtlsdr, "rtlsdr_write_eeprom")
    EndIf
    
  EndIf
  
  ProcedureReturn librtlsdr
  
EndProcedure

Procedure.l verbose_device_search(s.s="")
  
  Protected.l i, device_count, device, offset
  Protected Dim vendor.a(256)
  Protected Dim product.a(256)
  Protected Dim serial.a(256)
  
  device = -1
  
  device_count = rtlsdr_get_device_count()
  If device_count = 0
    Debug "No supported devices found."
    ProcedureReturn -1
  EndIf
  
  Debug "Found " + Str(device_count) + " device(s):"
  For i = 0 To device_count - 1
    rtlsdr_get_device_usb_strings(i, @vendor(0), @product(0), @serial(0))
    Debug "  " + Str(i) + ":  " + PeekS(@vendor(0), -1, #PB_UTF8) + ", " + PeekS(@product(0), -1, #PB_UTF8) + ", " + PeekS(@serial(0), -1, #PB_UTF8)
  Next i
  Debug ""
  
  If s <> ""
    ; does string look like raw id number
    device = Val(s)
    If Len(s) = Len(Str(device)) And device >= 0 And device < device_count
      Debug "Using device " + Str(device) + ": " + PeekS(rtlsdr_get_device_name(device), -1, #PB_UTF8)
    EndIf
  EndIf
  
  If device = -1
    ; does string exact match a serial
    For i = 0 To device_count - 1
      rtlsdr_get_device_usb_strings(i, @vendor(0), @product(0), @serial(0))
      If s <> PeekS(@serial(0), -1, #PB_UTF8)
        Continue
      EndIf
      device = i
      Debug "Using device " + Str(device) + ": " + PeekS(rtlsdr_get_device_name(device), -1, #PB_UTF8)
    Next i
  EndIf
  
  If device = -1
    ; does string prefix match a serial
    For i = 0 To device_count - 1
      rtlsdr_get_device_usb_strings(i, @vendor(0), @product(0), @serial(0))
      If FindString(PeekS(@serial(0), -1, #PB_UTF8), s) = 0
        Continue
      EndIf
      device = i
      Debug "Using device " + Str(device) + ": " + PeekS(rtlsdr_get_device_name(device), -1, #PB_UTF8)
      ProcedureReturn device
    Next i
  EndIf
  
  If device = -1
    Debug "No matching devices found."
  EndIf
  
  ProcedureReturn device
  
EndProcedure
Avatar de l’utilisateur
vertexview
Messages : 10
Inscription : mer. 24/janv./2024 16:02

Re: Wrapper DLL RTL-SDR

Message par vertexview »

Bonjour,
Voici le résultat de mes derniers échanges avec infratec, sur le forum anglais, concernant l'utilisation du wrapper RTL-SDR.

Il s'agit d'une application ADSB de type Form windows s'ajoutant à la version console qui utilisait un mode d'échange synchrone (rtlsdr_read_sync).
Les points principaux concernant cette version sont:
. Utilisation stable du mode de lecture asynchrone (rtlsdr_read_async) des données du dongle RTL-SDR
. Mise en oeuvre de threads, semaphore, buffers multiples, ProcedureC
. Les données ADSB sont affichées dans un gadget ListIcon
. La signification des trames longues a été ajoutée dans une colonne du gadget ListIcon.
. Le statut du dongle RTL-SDR est affiché dans un gadget StatusBar

Code : Tout sélectionner

EnableExplicit

XIncludeFile "librtlsdr.pbi"

#SDR_SRATE		  = 2000000
#ADSB_FREQ		  = 1090000000
#SDR_GAIN       = 372
#PREAMBLE_LEN   = 16
#LONG_FRAME     = 112
#SHORT_FRAME    = 56
#MESSAGEGO      = 253
#OVERWRITE      = 254
#BAD_SAMPLE     = 255
#BUF_LENGTH     = 16*16384
#ALLOWED_ERRORS = 5

Enumeration FormWindow
  #Window_Main
EndEnumeration

Enumeration FormGadget
  #ListIcon_Frames
EndEnumeration

Structure ByteArray_Structure
  a.a[0]
EndStructure

Structure ThreadParameter_Structure
  Thread.i
  Exit.i
EndStructure

Global *dev.rtlsdr_dev_t
Global *buf
Global ThreadParameter.ThreadParameter_Structure
Global hSem.i

Global Dim pythagore.a(128, 128)
Global Dim adsb_frame.a(13)
Global Dim buf.a(#BUF_LENGTH)
Global Dim thread_buf.a(#BUF_LENGTH)

Global font.i
Global lineCounter.i
Global lineMax.i = 300
Global framesCounter.i
Global ShowLongOnly.b = #False

Procedure pythagore_precompute()
  
  Protected.i x, y
  Protected.d scale
  
  scale = 1.408
  For x = 0 To 128
    For y = 0 To 128
      pythagore(x, y) = Round(scale * Sqr(x*x + y*y), #PB_Round_Nearest)
    Next y  
  Next x
  
EndProcedure

Procedure.a abs8(x.a)
  
  If x >= 128
    ProcedureReturn x - 128
  Else  
    ProcedureReturn 128 - x
  EndIf
  
EndProcedure

Procedure.i magnitude(*buf.ByteArray_Structure, len.i)
  
  Protected.i i
  
  ; takes IQ samples. Changes in place with the magnitude value (Char/uint8_t) 
  While i < len
    *buf\a[i / 2] = pythagore(abs8(*buf\a[i]), abs8(*buf\a[i + 1]))
    i + 2
  Wend
  
  ;returns new buffer length
  ProcedureReturn len / 2
  
EndProcedure

Procedure.i single_manchester(a.i, b.i, c.i, d.i)
  
  Protected.i bit, bit_p
  
  ; takes 4 consecutive samples, return 0 or 1, #BADSAMPLE on error
  If a > b
    bit_p = 1
  Else
    bit_p = 0
  EndIf
  
  If c > d
    bit = 1
  Else
    bit = 0
  EndIf

  ; Sanity check two bits
  If ((bit = 1) And (bit_p = 1) And (c > b) And (d < a))
    ProcedureReturn 1
  EndIf
  
  If ((bit = 1) And (bit_p = 0) And (c > a) And (d < b))
    ProcedureReturn 1
  EndIf
  
  If ((bit = 0) And (bit_p = 1) And (c < a) And (d > b))
    ProcedureReturn 0
  EndIf
  
  If ((bit = 0) And (bit_p = 0) And (c < b) And (d > a))
    ProcedureReturn 0
  EndIf
  
  ProcedureReturn #BAD_SAMPLE
  
EndProcedure

Procedure.i preamble(*buf.ByteArray_Structure, len.i, i.i)
  
  Protected.i i2
  Protected.a low, high
  
  low.a = 0
  high.a = 255
  ; Sequence Check. Returns 0/1 for preamble at index i
  For i2 = 0 To #PREAMBLE_LEN - 1
    Select i2
      Case 0,2,7,9
        high = *buf\a[i + i2]
      Default
        low = *buf\a[i + i2]
    EndSelect

    If high <= low
      ; No preamble sequence identified
      ProcedureReturn 0
    EndIf
    
  Next i2
  
  ; Preamble sequence found
  ProcedureReturn 1
  
EndProcedure

Procedure manchester(*buf.ByteArray_Structure, len.i)
  
  Protected a.a, b.a, bit.a
  Protected i.i, i2.i, errors.i
  
  ; Overwrites magnitude buffer with valid bits (#BADSAMPLE on errors)
  While (i < len)
    ; Find preamble sequence
    While i < len - #PREAMBLE_LEN
      If preamble(*buf, len, i) = 0
        i + 1
        Continue
      EndIf
      
      a = *buf\a[i]
      b = *buf\a[i + 1]
      For i2 = 0 To #PREAMBLE_LEN - 1
        *buf\a[i + i2] = #MESSAGEGO
      Next i2
      
      i = i + #PREAMBLE_LEN
      Break
      
      i + 1
    Wend
    
    i2 = i
    errors = 0
    ; Mark bits until encoding breaks
    While i < len
      bit = single_manchester(a, b, *buf\a[i], *buf\a[i + 1])
      a = *buf\a[i]
      b = *buf\a[i + 1]
      If bit = #BAD_SAMPLE
        errors + 1
        If errors > #ALLOWED_ERRORS
          *buf\a[i2] = #BAD_SAMPLE
          Break
        Else
          If a > b
            bit = 1
          Else
            bit = 0
          EndIf
          a = 0
          b = 255
        EndIf
      EndIf
      
      *buf\a[i] = #OVERWRITE
      *buf\a[i + 1] = #OVERWRITE
      *buf\a[i2] = bit
      i + 2
      i2 + 1
    Wend
  Wend
  
EndProcedure

Procedure display(*frame.ByteArray_Structure, len.i)
  
  Protected.i i, df, tc
  Protected.s timeStamp, hexFrame, DFs, CA, AA, ICAO, PI, TCs, ST, Comment
  Protected.s gadgetLine
  
  ; Downlink Format
  df = (*frame\a[0] >> 3) & $1F

  ; All-call Reply (DF11) or Extended Squitter frames (DF17, DF18, DF19)
  If Not ((df = 11) Or (df = 17) Or (df = 18) Or (df = 19))
    ProcedureReturn
  EndIf  
  
  timeStamp=FormatDate(" %yy/%mm/%dd %hh:%ii:%ss", Date())
  For i = 0 To ((len + 7) / 8) - 1
    hexFrame=hexFrame+RSet(Hex(adsb_frame(i),#PB_Ascii),2,"0")
  Next i
  DFs=Str(df)
  ; Mode S Transpondeur. CApability
  CA=Str(*frame\a[0] & $07)
  gadgetLine=timeStamp+Chr(10)+hexFrame+Chr(10)+DFs+Chr(10)+CA+Chr(10)
  
  If df=11
    ; Short frame. All-call Reply
    ; Anounced Adress
    AA=RSet(Hex(*frame\a[1] << 16 | (*frame\a[2] << 8) | *frame\a[3]), 6, "0")
    ; Parity/Interogator ID for short frame
    PI=RSet(Hex(*frame\a[4] << 16 | (*frame\a[5] << 8) | *frame\a[5]), 6, "0")
    
    gadgetLine=gadgetLine+AA+Chr(10)+PI
    If ShowLongOnly= #False
      AddGadgetItem(#ListIcon_Frames, -1, gadgetLine)
      lineCounter+1
    EndIf  
  Else
    ; Extended Squitter long frame (DF17, DF18, DF19)
    ; Aircraft Adress
    ICAO=RSet(Hex(*frame\a[1] << 16 | (*frame\a[2] << 8) | *frame\a[3]), 6, "0")
    ; Parity/Interogator ID for long frame
    PI=RSet(Hex(*frame\a[11] << 16 | (*frame\a[12] << 8) | *frame\a[13]), 6, "0")
    ; Type Code. Data frame content
    tc=(*frame\a[4] >> 3) & $1F
    TCs=Str(tc)
    ; SubType code
    ST=Str(*frame\a[4] & $07)
    ; Comment - From Type Code value
    Select tc
      Case 1, 2, 3, 4
        Comment="Aircraft identification"
      Case 5, 6, 7, 8
        Comment="Surface position"
      Case 9, 10, 11, 12, 13, 14, 15, 16, 17, 18
        Comment="Airborne position - Barometric altitude"
      Case 19
        Comment="Airborne velocities"
      Case 20, 21, 22
        Comment="Airborne position - GNSS altitude"
      Case 23, 24, 25, 26, 27
        Comment="Reserved"
      Case 28
        Comment="Aircraft status"
      Case 29
        Comment="Target state and status"
      Case 31
        Comment="Aircraft operation status"
    EndSelect
    
    gadgetLine=gadgetLine+ICAO+Chr(10)+PI+Chr(10)+TCs+Chr(10)+ST+Chr(10)+Comment
    AddGadgetItem(#ListIcon_Frames, -1, gadgetLine)
    lineCounter+1
  EndIf  

  framesCounter+1
  StatusBarText(0, 2, " Frames Counter (Short + Long):  "+Str(framesCounter+1))
  
  ; Windows API call. Automatic ListIcon gadget scrolling  
  SendMessage_(GadgetID(#ListIcon_Frames), #LVM_ENSUREVISIBLE, lineCounter-1, #True)
  If lineCounter=lineMax
    ClearGadgetItems(#ListIcon_Frames)
    lineCounter=0
  EndIf
  
EndProcedure

Procedure outmessages(*buf.ByteArray_Structure, len.i)
  
  Protected.i i, data_i, index, shift, frame_len
  Protected.a val_shift
  
  While i < len
    If *buf\a[i] > 1
      i + 1
      Continue
    EndIf
    frame_len = #LONG_FRAME
    data_i = 0
    
    For index = 0 To 13
      adsb_frame(index) = 0
    Next index

    While (i < len) And (*buf\a[i] <= 1) And (data_i < frame_len)
      If *buf\a[i] = 1
        index = data_i / 8
        shift = 7 - (data_i % 8)
        adsb_frame(index) = adsb_frame(index) | 1 << shift
      EndIf
      
      If data_i = 7
        If adsb_frame(0) = 0
          Break
        EndIf  
        
        If adsb_frame(0) & $80 <> 0
          frame_len = #LONG_FRAME
        Else
          frame_len = #SHORT_FRAME
        EndIf  
      EndIf

      i + 1
      data_i + 1
    Wend
    
    If data_i < frame_len - 1
      i + 1
      Continue
    EndIf
    display(@adsb_frame(0), frame_len)
    
    i + 1
  Wend
  
EndProcedure

Procedure initSDR()

  Protected.i i, r, device_count
  Protected.l dev_index
  Protected.s notification
  
  If UseLibrtlsdr()
  
    ; RTL-SDR System dll must be in application directory
    device_count = rtlsdr_get_device_count()
    
    If device_count = 0
      notification="No SDR device found. Application shutdown"
      StatusBarText(0, 3, notification)
      MessageRequester("PlaneTracker", notification, #PB_MessageRequester_Warning)
      Delay(3000)
      End 1
    EndIf
    
    notification="Found " + Str(device_count) + " device(s)"
    StatusBarText(0, 3, notification)
    
    For i = 0 To device_count - 1
      Debug("SDR Scan. "+Str(i) + ": " + PeekS(rtlsdr_get_device_name(i), -1, #PB_UTF8))
    Next i
    
    notification="SDR ID used " + Str(dev_index) + ": " + PeekS(rtlsdr_get_device_name(dev_index), -1, #PB_UTF8)
    StatusBarText(0, 0, " "+notification)
    
    r = rtlsdr_open(@*dev, dev_index)
    If r < 0
      notification="Failed to open SDR device #" + Str(dev_index)
      StatusBarText(0, 3, notification)
      Delay(3000)
      End 1
    EndIf
    
    rtlsdr_set_center_freq(*dev, #ADSB_FREQ)
    rtlsdr_set_sample_rate(*dev, #SDR_SRATE)
    rtlsdr_set_tuner_gain(*dev, #SDR_GAIN) 
    rtlsdr_set_agc_mode(*dev, 0)
   
    r = rtlsdr_reset_buffer(*dev)
    If r < 0
      notification="Failed to reset buffer"
      StatusBarText(0, 3, notification)
      Delay(3000)
    EndIf
    
  EndIf
  
EndProcedure

ProcedureC ReadBuffer(*buffer, size.l, *ctx)
  
  CopyMemory(*buffer, @buf(0), size)
  
  If IsThread(ThreadParameter\Thread)
    SignalSemaphore(hSem)
  EndIf  
  
EndProcedure


Procedure ThreadProc(*Parameter.ThreadParameter_Structure)
  
  Protected len.i
  
  Repeat
    
    WaitSemaphore(hSem)
    
    If Not *Parameter\Exit
      
      CopyMemory(@buf(0), @thread_buf(0), #BUF_LENGTH)
      ; ADSB data processing
      len = magnitude(@thread_buf(0), #BUF_LENGTH)
      manchester(@thread_buf(0), len)
      outmessages(@thread_buf(0), len)

    EndIf
    
  Until *Parameter\Exit
  
EndProcedure

Procedure ReadAsyncThread(*Dummy)
  
  Protected r.i
  
  r = rtlsdr_read_async(*dev, @ReadBuffer(), 0, 32, #BUF_LENGTH)
  
EndProcedure

Define.i event, ReadThread

; Main code with thread/semaphore creation 

OpenWindow(#Window_Main, 0, 0, 1024, 600, "ADSB SDR Async Reading", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

font=LoadFont(#PB_Any, "Consolas", 10)

CreateStatusBar(0, WindowID(#Window_Main))
AddStatusBarField(240)
StatusBarText(0, 0, "SDR Status")
AddStatusBarField(240)
StatusBarText(0, 1, "General information")
AddStatusBarField(240)
StatusBarText(0, 2, "Counter information")
AddStatusBarField(300)
StatusBarText(0, 3, "Status Detail")

ListIconGadget(#ListIcon_Frames, 2, 6, 1020, 566, "Time Stamp", 150)
AddGadgetColumn(#ListIcon_Frames, 1, "ADSB Frame", 220)
AddGadgetColumn(#ListIcon_Frames, 2, "DF", 30)
AddGadgetColumn(#ListIcon_Frames, 3, "CA", 30)
AddGadgetColumn(#ListIcon_Frames, 4, "AA-ICAO", 70)
AddGadgetColumn(#ListIcon_Frames, 5, "PI", 60)
AddGadgetColumn(#ListIcon_Frames, 6, "TC", 30)
AddGadgetColumn(#ListIcon_Frames, 7, "ST", 30)
AddGadgetColumn(#ListIcon_Frames, 8, "Comment", 300)
SetGadgetColor(#ListIcon_Frames, #PB_Gadget_FrontColor,RGB(0,64,128))
SetGadgetColor(#ListIcon_Frames, #PB_Gadget_BackColor,RGB(248,248,248))
SetGadgetFont(#ListIcon_Frames, FontID(font))

; SDR environment initialization
initSDR()
pythagore_precompute()

; Thread and semaphore creation
hSem = CreateSemaphore()
ThreadParameter\Thread = CreateThread(@ThreadProc(), @ThreadParameter)
ReadThread = CreateThread(@ReadAsyncThread(), #Null)

; Window loop event management
Repeat
  Event = WaitWindowEvent()
  
  Select Event
    Case #PB_Event_Gadget
      Select EventGadget()
        ; Gadget event
      EndSelect
  EndSelect    
      
Until Event = #PB_Event_CloseWindow

; Cancel Async reading
rtlsdr_cancel_async(*dev)
If WaitThread(ReadThread, 3000) = 0
  KillThread(ReadThread)
EndIf

; Cleaning ressources after shutdown
ThreadParameter\Exit = #True

If IsThread(ThreadParameter\Thread)
  SignalSemaphore(hSem)
EndIf

If WaitThread(ThreadParameter\Thread, 1000) = 0
  KillThread(ThreadParameter\Thread)
  Debug ("ThreadProc killed")
EndIf

If hSem
  FreeSemaphore(hSem)
EndIf

rtlsdr_close(*dev)
Debug ("Ressources cleaned and rtlsdr closed")

End
Lien vers le sujet sur le forum anglais:
https://www.purebasic.fr/english/viewtopic.php?t=83421

Téléchargement des dll nécessaires (versions de driver RTL-SDR)
https://ftp.osmocom.org/binaries/windows/rtl-sdr/
Répondre