Re: DLL wrapper for RTL-SDR
Posted: Sat Jan 27, 2024 7:19 pm
I modified the listing above.
http://www.purebasic.com
https://www.purebasic.fr/english/
Code: Select all
H:\Projets\Purebasic\SDR>rtl_eeprom -w dumpv4p.dat
Found 1device(s):
0: Generic RTL2832U OEM
Using device 0: Generic RTL2832U OEM
Found Rafael Micro R828D tuner
RTL-SDR Blog V4 Detected
Current configuration:
__________________________________________
Vendor ID: $0BDA
Product ID: $2838
Manufacturer: RTLSDRBlog
Product: Blog V4
Serial number: 00000012
Serial number enabled: yes
IR endpoint enabled: yes
Remote wakeup enabled: no
__________________________________________
New configuration:
__________________________________________
Vendor ID: $0BDA
Product ID: $2838
Manufacturer: RTLSDRBlog
Product: Blog V4
Serial number: 00000011
Serial number enabled: yes
IR endpoint enabled: yes
Remote wakeup enabled: no
__________________________________________
Write new configuration to device [y/n]?
Configuration successfully written.
Please replug the device For changes to take effect.
H:\Projets\Purebasic\SDR>rtl_eeprom
Found 1device(s):
0: Generic RTL2832U OEM
Using device 0: Generic RTL2832U OEM
Found Rafael Micro R828D tuner
RTL-SDR Blog V4 Detected
Current configuration:
__________________________________________
Vendor ID: $0BDA
Product ID: $2838
Manufacturer: RTLSDRBlog
Product: Blog V4
Serial number: 00000011
Serial number enabled: yes
IR endpoint enabled: yes
Remote wakeup enabled: no
__________________________________________
H:\Projets\Purebasic\SDR>rtl_eeprom -d 0
Found 2device(s):
0: Generic RTL2832U OEM
1: Generic RTL2832U OEM
Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Current configuration:
__________________________________________
Vendor ID: $0BDA
Product ID: $2838
Manufacturer: Realtek
Product: RTL2838UHIDIR
Serial number: 00000001
Serial number enabled: yes
IR endpoint enabled: yes
Remote wakeup enabled: no
__________________________________________
H:\Projets\Purebasic\SDR>rtl_eeprom -d 1
Found 2device(s):
0: Generic RTL2832U OEM
1: Generic RTL2832U OEM
Using device 1: Generic RTL2832U OEM
Found Rafael Micro R828D tuner
RTL-SDR Blog V4 Detected
Current configuration:
__________________________________________
Vendor ID: $0BDA
Product ID: $2838
Manufacturer: RTLSDRBlog
Product: Blog V4
Serial number: 00000011
Serial number enabled: yes
IR endpoint enabled: yes
Remote wakeup enabled: no
__________________________________________
H:\Projets\Purebasic\SDR>
Code: Select all
;-Demo
CompilerIf #PB_Compiler_IsMainFile
; ------- Variable definitions
Define.l counter, my_freq, my_gain, my_srate, my_fcor, tuner_type, dev_index, status, idx
Define sdr_Name.s
Define *dev.rtlsdr_dev_t
Define Dim manufact.a(256)
Define Dim product.a(256)
Define Dim serial.a(256)
; ------- SDR Tests access
If UseLibrtlsdr()
;dev_index = verbose_device_search("00000053")
dev_index=1
counter = rtlsdr_get_device_count()
idx = rtlsdr_get_index_by_serial("00000054")
Debug "SDR connected: " + counter + #LF$ + "Test get device Idx by serial With 00000054: "+ idx
rtlsdr_get_device_usb_strings(dev_index, @manufact(0), @product(0), @serial(0))
Debug "Check USB Strings for index = " + Str(dev_index) + " - Result: " + PeekS(@manufact(0), -1, #PB_UTF8) + ", " + PeekS(@product(0), -1, #PB_UTF8) + ", " + PeekS(@serial(0), -1, #PB_UTF8)
status= rtlsdr_open(@*dev, dev_index)
Debug "rtlsdr_open function return value: " + status
If status = 0
sdr_name = PeekS(rtlsdr_get_device_name(dev_index), -1, #PB_UTF8)
tuner_type = rtlsdr_get_tuner_type(*dev)
Debug "Device opened index: " + dev_index + #LF$ + "SDR Name: " + sdr_name + #LF$ + "SDR Type: "+ Str(tuner_type)
rtlsdr_set_center_freq(*dev, 92200000)
rtlsdr_set_tuner_gain(*dev, 372)
rtlsdr_set_sample_rate(*dev, 2048000)
rtlsdr_set_freq_correction(*dev, 2)
rtlsdr_set_bias_tee(*dev, 1)
my_freq = rtlsdr_get_center_freq(*dev)
my_gain = rtlsdr_get_tuner_gain(*dev)
my_srate = rtlsdr_get_sample_rate(*dev)
my_fcor= rtlsdr_get_freq_correction(*dev)
Debug "Get frequency (Hz): " + Str(my_freq) + #LF$ + "Get gain (tenths of dB): " + Str(my_gain) + #LF$ + "SDR Bias-tee ON" + #LF$ + "Get sample rate (bps): "+ Str(my_srate)+ #LF$ + "Get frequency correction (ppm): "+ Str(my_fcor)
; RTL-SDR Blog v4 Led indicator activated if bias-tee ON
Delay (5000)
rtlsdr_set_bias_tee(*dev, 0)
Debug "SDR Bias-tee OFF"
status=rtlsdr_close(*dev)
Debug "rtlsdr_close function return value: " + status
Else
Debug "Was not able to open a device"
EndIf
EndIf
CompilerEndIf
Code: Select all
rtlsdr_open()
Code: Select all
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()
Code: Select all
var
thread_buf: array [0 .. DEFAULT_BUF_LENGTH] of Byte;
ThreadHandle: integer;
ThreadID: DWORD;
hSem: THandle = 0;
function Read(buffer: PAnsiChar; size: integer; ctx: Pointer): LongWord;
begin
if ctx = nil then
Exit(0);
// 262144 bytes in buffer
// Move(buf, ctx, size);
CopyMemory(@buf[0], ctx, size);
hSem := CreateSemaphore(nil, 1, 1, nil);
Result := 1;
end;
procedure ThreadProc;
var
len: integer;
WaitReturn: integer;
begin
while (True) do
begin
WaitReturn := WaitForSingleObject(hSem, INFINITE);
if WaitReturn = WAIT_OBJECT_0 then
begin
// writeln('thread on');
CopyMemory(@thread_buf, @buf, DEFAULT_BUF_LENGTH);
len := magnitute(thread_buf, DEFAULT_BUF_LENGTH);
manchester(thread_buf, len);
outmessages(thread_buf, len);
ReleaseSemaphore(hSem, 1, nil);
CloseHandle(hSem);
// writeln('thread off');
end;
end;
rtlsdr_cancel_async(dev);
end;
## Specific part in the Main Delphi code ##
ThreadHandle := CreateThread(nil, 0, @ThreadProc, nil, 0, ThreadID);
r := rtlsdr_read_async(dev, @read, nil, 32, DEFAULT_BUF_LENGTH);
Code: Select all
Global Dim thread_buf.a(block_size)
Global hThread.l
Global hSem.l
Procedure ReadBufffer(*buf, len.l, *ctx)
If *ctx=0
ProcedureReturn 0
EndIf
; CopyMemory in Delphi (Destination: Pointer; Source: Pointer; Length: DWORD)
; CopyMemory in Purebasic (*Source, *Destination, Size)
CopyMemory(*buf, @buffer.a(), len.l)
; handle semaphore
hSem=CreateSemaphore()
MessageRequester("Info","Copy realized and semaphore created", 0)
ProcedureReturn 1
EndProcedure
Procedure ThreadProc(value)
Protected len.i
Protected WaitReturn.i
Repeat
;WaitReturn=WaitSemaphore(hSem)
;If WaitReturn=0
; CopyMemory (source, destination, taille)
CopyMemory(@buffer.a(), @thread_buf.a(), block_size)
len = magnitude(@thread_buf.a(), block_size)
manchester(@thread_buf.a(), len)
outmessages(@thread_buf.a(), len)
; FreeSemaphore(hSem)
;EndIf
ForEver
;rtlsdr_cancel_async(*dev)
EndProcedure
## Specific part in the Main Purebasic code ##
hThread=CreateThread(@ThreadProc(), 0)
r = rtlsdr_read_async(*dev, ReadBuffer, 0, 32, block_size)
Code: Select all
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
Define ReadBuffer
Define cb.rtlsdr_read_async_cb_t
Global length.i = 0
Global buf_num.i = 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 buf.a(block_size)
Global Dim buffer.a(block_size)
Global Dim thread_buf.a(block_size)
Global hThread.l
Global hSem.l
Global allowed_errors.i = 5
Global quality.i = 20
Global short_output.i = 0
Global verbose_output.i = 0
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)
; Find preamble sequence
While i < len - #PREAMBLE_LEN
If preamble(@buffer.a(), i) = 0
i+1
Continue
EndIf
a = buffer(i)
b = buffer(i + 1)
For i2 = 0 To #PREAMBLE_LEN-1
buffer(i + i2) = #MESSAGEGO
Next i2
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.a, pcode.a, 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= "+icao)
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(" 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
Procedure ReadBufffer(*buf, len.l, *ctx)
If *ctx=0
ProcedureReturn 0
EndIf
; CopyMemory in Delphi (Destination: Pointer; Source: Pointer; Length: DWORD)
; CopyMemory in Purebasic (*Source, *Destination, Size)
CopyMemory(*buf, @buffer.a(), len.l)
; handle semaphore
hSem=CreateSemaphore()
MessageRequester("Info","Copy realized and semaphore created", 0)
ProcedureReturn 1
EndProcedure
Procedure ThreadProc(value)
Protected len.i
Protected WaitReturn.i
Repeat
;WaitReturn=WaitSemaphore(hSem)
;If WaitReturn=0
; CopyMemory (source, destination, taille)
CopyMemory(@buffer.a(), @thread_buf.a(), block_size)
len = magnitude(@thread_buf.a(), block_size)
manchester(@thread_buf.a(), len)
outmessages(@thread_buf.a(), len)
; FreeSemaphore(hSem)
;EndIf
ForEver
;rtlsdr_cancel_async(*dev)
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 Async mode")
PrintN("")
hThread=CreateThread(@ThreadProc(), 0)
MessageRequester("Info","ThreadProc running", 0)
r = rtlsdr_read_async(*dev, ReadBuffer, 0, 32, block_size)
If r < 0
PrintN("Buffer Async read failed\n")
EndIf
; Can't reach this point after rtlsdr_read_async
rtlsdr_close(*dev)
If r >= 0
End r
Else
End -r
EndIf
EndIf
CompilerIf #PB_Compiler_Debugger
Input()
CompilerEndIf
CloseConsole()
Code: Select all
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
#DEFAULT_BUF_LENGTH = 16 * 16384
Structure ThreadParameter_Structure
Thread.i
Exit.i
EndStructure
Define.i i, r
Define.l dev_index
Define.i device_count
Define *dev.rtlsdr_dev_t
Define *buf
Global length.i
Global buf_num.i
Global StopReadingSamples.i
Global Dim pythagore.a(128, 128)
Global Dim adsb_frame.a(13)
Global Dim buf.a(#DEFAULT_BUF_LENGTH)
Global Dim thread_buf.a(#DEFAULT_BUF_LENGTH)
Global hThread.i
Global hSem.i
Global allowed_errors.i = 5
Global quality.i = 20
Global short_output.i
Global verbose_output.i
Global show_stats.i
ProcedureC ReadBuffer(*buffer, size.l, *ctx)
Debug "ReadBuffer size: " + Str(size)
; CopyMemory in Delphi (Destination: Pointer; Source: Pointer; Length: DWORD)
; CopyMemory in Purebasic (*Source, *Destination, Size)
CopyMemory(*buffer, @buf(0), size)
SignalSemaphore(hSem)
EndProcedure
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
Structure ByteArray_Structure
a.a[0]
EndStructure
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 bit.i, bit_p.i
; 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.0
; no sanity check
ProcedureReturn bit
EndIf
If quality = 0.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 = 1.0
; 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.i preamble(*buf.ByteArray_Structure, len.i, 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 = *buf\a[i + i2]
Default
low = *buf\a[i + i2]
EndSelect
If high <= low
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.i
Protected value.a, icao.a, pcode.a, tcode.a, stype.a
Protected test.b
If (short_output = 0) And (len <= #SHORT_FRAME)
ProcedureReturn
EndIf
df = (*frame\a[0] >> 3) & $1F
If Quality = 0.0 And Not ((df = 11) Or (df = 17) Or (df = 18) Or (df = 19))
ProcedureReturn
EndIf
Print("*")
For i = 0 To ((len + 7) / 8) - 1
Print(RSet(Hex(*frame\a[i], #PB_Ascii), 2, "0"))
Next i
PrintN("")
If verbose_output = 1
PrintN(FormatDate(" %yyyy/%mm/%mm/%dd %hh:%ii:%ss", Date()))
Print(" DF=" + Str(df) + " CA=" + Str(*frame\a[0] & $07))
PrintN(", ICAO=" + RSet(Hex(*frame\a[1] << 16 | (*frame\a[2] << 8) | *frame\a[3]), 6, "0"))
EndIf
If len <= #SHORT_FRAME
ProcedureReturn
EndIf
If verbose_output = 1
PrintN(" PI_code=" + RSet(Hex(*frame\a[11] << 16 | (*frame\a[12] << 8) | *frame\a[13]), 6, "0"))
PrintN(" Type_code=" + Str((*frame\a[4] >> 3) & $1F) + " S_type/ant=" + Str(*frame\a[4] & $07))
PrintN("")
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 ThreadProc(*Parameter.ThreadParameter_Structure)
Protected len.i
Protected WaitReturn.i
Repeat
WaitSemaphore(hSem)
If Not *Parameter\Exit
; CopyMemory (source, destination, taille)
CopyMemory(@buf(0), @thread_buf(0), #DEFAULT_BUF_LENGTH)
len = magnitude(@thread_buf(0), #DEFAULT_BUF_LENGTH)
manchester(@thread_buf(0), len)
outmessages(@thread_buf(0), len)
EndIf
Until *Parameter\Exit
;rtlsdr_cancel_async(*dev)
EndProcedure
; ------- Main -------
Define ThreadParameter.ThreadParameter_Structure
OpenConsole()
If UseLibrtlsdr()
; handle semaphore
hSem = CreateSemaphore()
pythagore_precompute()
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 Async mode")
PrintN("")
ThreadParameter\Thread = CreateThread(@ThreadProc(), @ThreadParameter)
;MessageRequester("Info","ThreadProc running")
r = rtlsdr_read_async(*dev, @ReadBuffer(), #Null, 32, #DEFAULT_BUF_LENGTH)
If r < 0
PrintN("Buffer Async read failed\n")
EndIf
; Can't reach this point after rtlsdr_read_async
rtlsdr_close(*dev)
ThreadParameter\Exit = #True
SignalSemaphore(hSem)
If WaitThread(ThreadParameter\Thread, 1000) = 0
KillThread(ThreadParameter\Thread)
EndIf
If hSem
FreeSemaphore(hSem)
EndIf
If r >= 0
End r
Else
End -r
EndIf
EndIf
CompilerIf #PB_Compiler_Debugger
Input()
CompilerEndIf
CloseConsole()
Code: Select all
Procedure ThreadProc(*Dummy)
Protected len.i
Protected WaitReturn.i
While #True
If hSem
WaitSemaphore(hSem)
; CopyMemory (source, destination, taille)
CopyMemory(@buf(0), @thread_buf(0), #DEFAULT_BUF_LENGTH)
len = magnitude(@thread_buf(0), #DEFAULT_BUF_LENGTH)
manchester(@thread_buf(0), len)
outmessages(@thread_buf(0), len)
FreeSemaphore(hSem)
EndIf
Wend
;rtlsdr_cancel_async(*dev)
EndProcedure
Code: Select all
r = rtlsdr_read_async(*dev, @ReadBuffer(), 0, 32, #DEFAULT_BUF_LENGTH)
Code: Select all
Procedure.i ReadBuffer(*buffer, size.i, *ctx)
Debug("ReadBuffer procedure called")
If *ctx = #Null
ProcedureReturn 0
EndIf
; CopyMemory in Delphi (Destination: Pointer; Source: Pointer; Length: DWORD)
; CopyMemory in Purebasic (*Source, *Destination, Size)
CopyMemory(*ctx, @buf(0), size)
; handle semaphore
hSem = CreateSemaphore()
Debug("MemCopy done and Semaphore created")
ProcedureReturn 1
EndProcedure
Code: Select all
Procedure.i ReadBuffer(*buffer, size.i, *ctx)
Debug("ReadBuffer procedure called")
If *ctx = #Null
Debug("ProcedureReturn 0 debug")
ProcedureReturn 0
EndIf
; CopyMemory in Delphi (Destination: Pointer; Source: Pointer; Length: DWORD)
; CopyMemory in Purebasic (*Source, *Destination, Size)
CopyMemory(*ctx, @buf(0), size)
; handle semaphore
hSem = CreateSemaphore()
Debug("MemCopy done and Semaphore created")
ProcedureReturn 1
EndProcedure