Imports System
Imports System.Collections.Generic
Imports System.Runtime.InteropServices
Imports System.IO
Imports System.Net.Sockets
Imports System.math
Imports System.buffer
Imports System.windows.Forms.Application
Imports System.Threading.Thread
Imports FFTWSharp
Imports SDRPlay2RSS.RSS
Imports Microsoft.VisualBasic
''' Interfaces the SDRPlay receiver to Radio Sky Spectrograph (radiosky.com).
''' Uses FTTW package: fttw.org.
Public Class SDRPlay
Shared percent As Double = 100
Shared MHz As Double = 1000000.0
Public frequency As Double
Public rfBW As mir_sdr_Bw_MHzT
Public SampleRate As Double
Public ifBW As mir_sdr_If_kHzT = mir_sdr_If_kHzT.mir_sdr_IF_Zero
Public N As Integer ' fourier frame size
Private N2 As Integer
Public r As mir_sdr_ErrT ' last error
Public recordindexstart As Integer
Public recordindexend As Integer
Public k As Integer = 1 ' filter frame count; k==1 means no pfb
Public samplesperpacket As Integer
Public datasink As DataSinkType ' where the data are going
Public Offset As Double = 0.1
Public RSSScale As Double = 1
Public TrigThreshold As Single = 0
Public backgroundaveragecount As Integer = 10
Public StreamingDuration As Long = 40000
Public LogScale As Boolean = False
' number of bits to RSS and to .sps files
Const c As ColorRes = ColorRes.twelvebit
Dim spec As SpectralProcessing
Private windowflag As Boolean
Public statuscallback As changecontroltextdelegate
Public hwver As Byte
Dim SwitchedAntennas As Boolean
Public switchedpausesamples As Integer = 150000 ' samples
Public retries As Integer = 1
Const rsp1aver As Byte = 255
Public Sub New( _
ByVal frequencyin As Double, ByVal bw As mir_sdr_Bw_MHzT, _
ByVal samplerateval As Double, ByVal framesize As Integer, _
ByRef devconfig As SDRPlay.rspConfig, _
Optional ByVal sa As Boolean = False, _
Optional ByVal scb As changecontroltextdelegate = Nothing)
SwitchedAntennas = sa
' set the antenna
Antenna = devconfig.antennaSelect
' Mirics API version
Dim vers As Single
Dim merr As mir_sdr_ErrT = mir_sdr_ApiVersion(vers)
Debug.Print("API version " & vers.ToString)
frequency = frequencyin
rfBW = bw
SampleRate = samplerateval
statuscallback = scb
' uninitializes the API
r = mir_sdr_Uninit()
If r <> mir_sdr_ErrT.mir_sdr_Success Then
'Throw (New ArgumentException(sprintf("SDRPlay.constructor - mir_sdr_UInit error %s", r.ToString)))
Debug.Print(sprintf("SDRPlay.constructor - mir_sdr_UInit error %s", r.ToString))
End If
N = framesize
N2 = N << 1
SampleRate = samplerateval
' first init; open with safe values
r = mir_sdr_Init(GainReduction, 5000000.0 / MHz, frequency / MHz, mir_sdr_Bw_MHzT.mir_sdr_BW_1_536, ifBW, samplesperpacket)
If r <> mir_sdr_ErrT.mir_sdr_Success Then
Debug.Print("mir_sdr_Init failed: " & r.ToString)
Throw (New ArgumentException(sprintf("SDRPlay.constructor - Failed to open SDRplay RSP device, %s.", r.ToString)))
End If
' hardware version, rsp1: 1, rsp2: 2, rsp1a: rsp1aver
Try
If mir_sdr_GetHwVersion(hwver) <> mir_sdr_ErrT.mir_sdr_Success Then
Throw (New ArgumentException("SDRPlay.constructor - error reading hardware version."))
Else
Debug.Print("hwver - " & mir_sdr_GetHwVersion(hwver).ToString & ": " & hwver.ToString)
End If
Catch ex As EntryPointNotFoundException
' early api version
hwver = 1
End Try
' set bias T
BiasT = devconfig.biasT
' set rsp2 notch filter
notchfilter = devconfig.rsp2notchEnable
' set rsp1a filters
dabNotchFilter = devconfig.rsp1adabnotchEnable
bcastNotchFilter = devconfig.rsp1abroadcastnotchEnable
' uninitialize the API
If mir_sdr_Uninit() <> mir_sdr_ErrT.mir_sdr_Success Then
Throw (New ArgumentException(sprintf("SDRPlay.constructor - mir_sdr_UInit error %s", r.ToString)))
End If
' set gain map (must be applied before _init)
GainMap = GainMapSettings.newset
' enable LNA (note: only works if gain map = new)
LNA = EnableDisable.disable
' enable debug output
r = mir_sdr_DebugEnable(1)
If r <> mir_sdr_ErrT.mir_sdr_Success Then
Throw (New ArgumentException(sprintf("SDRPlay.constructor - mir_sdr_DebugEnable error %s", r.ToString)))
End If
Debug.Print("antenna " & merr.ToString & r.ToString)
' check the sample rate
Dim minfs, maxfs As Double
Select Case hwver
Case 1
minfs = 1000000.0
maxfs = 12000000.0
Case 2
minfs = 2000000.0
maxfs = 10000000.0
Case rsp1aver
minfs = 2000000.0
maxfs = 10000000.0
End Select
If samplerateval < minfs OrElse samplerateval > maxfs Then
'Throw (New ArgumentException("SDRPlay.constructor - sample rate is out of range: " & (samplerateval / MHz).ToString & " MHz"))
Throw (New ArgumentException(sprintf("SDRPlay.constructor - sample rate is out of range: %4.1f MHz (%4.1f MHz < fs < %4.1f MHz)", samplerateval / MHz, minfs / MHz, maxfs / MHz)))
End If
' check the bandwidth
If CDbl(bw) * 1000 > SampleRate Then
Throw (New ArgumentException("SDRPlay.constructor - bandwidth > sample rate"))
End If
'open the device again
r = mir_sdr_Init(GainReduction, SampleRate / MHz, frequency / MHz, bw, ifBW, samplesperpacket)
If r <> mir_sdr_ErrT.mir_sdr_Success Then
Throw (New ArgumentException("SDRPlay.run - Failed to open SDRplay RSP device."))
End If
mir_sdr_SetDcMode(DCOffsetCorrectionMode.oneshot, EnableDisable.disable)
mir_sdr_SetDcTrackTime(63)
End Sub
Public Sub Streaming(ByRef do_exit As Boolean, _
ByVal recordfreqstart As Double, ByVal recordfreqend As Double, _
ByVal ds As DataSinkType, _
ByVal statuscontrol As ToolStripStatusLabel, _
ByVal obs As ObservatoryData.observatory, _
Optional ByVal filepath As String = Nothing)
Dim recordindexstart As Integer = CInt((recordfreqstart - (frequency - SampleRate / 2)) / SampleRate * N) ' unaliased spectral channel
Dim recordindexend As Integer = CInt((recordfreqend - (frequency - SampleRate / 2)) / SampleRate * N) ' unaliased spectral channel
Dim recordcount As Integer = recordindexend - recordindexstart + 1
Dim freq1 As Double = recordindexstart * SampleRate / N + frequency - SampleRate / 2
Dim freq2 As Double = recordindexend * SampleRate / N + frequency - SampleRate / 2
' write buffer
Dim writebuf(8 * recordcount - 1) As Byte
Dim swap(N - 1) As Single
' moving average
Dim ma As Single
' fft
Dim s1(N2 - 1), s2(N2 - 1) As Single
Dim hs1 As GCHandle = GCHandle.Alloc(s1, GCHandleType.Pinned)
Dim hs2 As GCHandle = GCHandle.Alloc(s2, GCHandleType.Pinned)
Dim fftwplan As IntPtr = fftwf.dft_1d(N, _
hs1.AddrOfPinnedObject(), hs2.AddrOfPinnedObject(), _
fftw_direction.Forward, fftw_flags.Measure)
' I and Q values:
Dim ibuf(samplesperpacket - 1) As Short
Dim qbuf(samplesperpacket - 1) As Short
Dim n_read As Integer = samplesperpacket * 2
Dim bytes_to_read As UInteger = 0
Dim SampleNum As UInteger = 0
Dim SampleNumPrev As UInteger
Dim grChanged As Integer = 0
Dim rfChanged As Integer = 0
Dim fsChanged As Integer = 0
' window function
Dim wf As New WindowFunctions(N, WindowFunctions.wfType.Blackman)
statuscontrol.Text = sprintf("Samples per packet %d. Starting ...", samplesperpacket)
Dim spsfile As SPSWriter = Nothing
Dim file As FileStream = Nothing
Dim binWriter As BinaryWriter = Nothing
Try
Do
Dim spswritebuf() As Single = Nothing
Select Case ds
Case DataSinkType.File
' output file
Dim filename As String
If String.IsNullOrEmpty(filepath) Then
filename = DateTime.UtcNow.ToString("yyyyMMddTHHmmss") & ".dat"
Else
filename = My.Computer.FileSystem.CombinePath(filepath, DateTime.UtcNow.ToString("yyyyMMddTHHmmss") & ".dat")
End If
file = New FileStream(filename, FileMode.Create)
binWriter = New BinaryWriter(file)
' write the header
binWriter.Write(("SDRPlay receiver").ToCharArray) ' 16 bytes
binWriter.Write(frequency) ' double
binWriter.Write(rfBW) ' integer
binWriter.Write(SampleRate) ' double
binWriter.Write(ifBW) ' integer
binWriter.Write(N) ' integer
binWriter.Write(recordcount) ' integer
binWriter.Write(recordindexstart) ' integer
binWriter.Write(recordindexend) ' integer
binWriter.Write(freq1) ' double
binWriter.Write(freq2) ' double
Case DataSinkType.SPS
' sps file
spsfile = New SPSWriter(StreamingDuration, recordcount, False, c)
With spsfile
.freqcent = frequency
.freqspan = freq2 - freq1
.dateobs = DateTime.UtcNow
ReDim spswritebuf(recordcount - 1)
End With
Case Else
Throw (New ArgumentException(sprintf("%s.Streaming - data-sink option %s is not allowed.", Me.GetType.Name, ds.ToString)))
End Select
' update gain reduction
GainReduction = GainReduction
Dim filerestartflag As Boolean = False
Dim starttime As DateTime = DateTime.UtcNow
Dim readcount As Long = 0
Dim currentbuffer As Integer = 0
' loop over reads
Dim s1posn As Integer = 0
Dim scale As Single = 1.0 / 32768.0
Dim trigcounter As Long = 0
Dim droppedsamplescounter As Integer = 0
Dim sc As Single = 1 / N
Do
' fetch the data
SampleNumPrev = SampleNum
r = mir_sdr_ReadPacket(ibuf, qbuf, SampleNum, grChanged, rfChanged, fsChanged)
If r <> mir_sdr_ErrT.mir_sdr_Success Then
hs1.Free()
hs2.Free()
fftw.destroy_plan(fftwplan)
Select Case ds
Case DataSinkType.File
file.Flush()
file.Close()
binWriter.Close()
Case DataSinkType.SPS
spsfile.close()
Case Else
Throw (New ArgumentException(sprintf("%s.Streaming - data-sink option %s is not allowed.", Me.GetType.Name, ds.ToString)))
End Select
mir_sdr_Uninit()
Throw (New ArgumentException("SDRPlay.run - WARNING: ReadPacket failed."))
ElseIf SampleNum > samplesperpacket + SampleNumPrev AndAlso SampleNumPrev > 0 AndAlso statuscallback IsNot Nothing Then
Dim s As String = sprintf("SDRPlay.Streaming - samples dropped: %d (%d)", SampleNum - SampleNumPrev - samplesperpacket, droppedsamplescounter)
statuscallback(s)
droppedsamplescounter += 1
End If
readcount += 1
If ds = DataSinkType.File Then
' undecimated TD samples
' interleave I an Q samples
Static binbuf1(2 * samplesperpacket - 1) As Short
For i As Integer = 0 To samplesperpacket - 1
Dim i2 As Integer = i >> 1
binbuf1(i2) = ibuf(i)
binbuf1(i2 Or 1) = qbuf(i)
Next
' copy to a byte buffer
Static binbuf2(4 * samplesperpacket - 1) As Byte
BlockCopy(binbuf1, 0, binbuf2, 0, 4 * samplesperpacket)
' write to the file
binWriter.Write(binbuf2)
' decimation of saved samples
'Dim avgcount2 As Integer
'For i As Integer = 0 To s1.Length - 2 Step 2
' s2(avgcount2) += s1(i)
' s2(avgcount2 + 1) += s1(i + 1)
'Next
'avgcount2 += 2
'If avgcount2 = N2 Then
' BlockCopy(s2, 0, binbuf, 0, 8 * N)
' binWriter.Write(binbuf)
' avgcount2 = 0
'End If
Else
' interleave I and Q parts
Dim IQposn As Integer = 0
Do While IQposn < samplesperpacket
Do While s1posn < N2 AndAlso IQposn < samplesperpacket
Dim a, b As Single
a = scale * CSng(ibuf(IQposn))
s1(s1posn) = a ' I part
b = a * a
s1posn += 1
a = scale * CSng(qbuf(IQposn))
s1(s1posn) = a ' Q part
b += a * a
s1posn += 1
IQposn += 1
ma += b
Loop
If s1posn = N2 Then
' write td data to binary file, interleaved I and Q
Select Case ds
Case DataSinkType.File
Case DataSinkType.SPS
ma *= 1000 / N
If trigcounter = 0 AndAlso ma >= TrigThreshold Then
trigcounter += 1
If TrigThreshold > 0.0 Then statuscontrol.Text = sprintf("Triggered %s, level %5.2f/%5.2f", DateTime.UtcNow.ToString("s"), ma, TrigThreshold)
End If
' reset trigger
ma = 0
' process if counter is nonzero
If trigcounter > 0 Then
' apply window function to the TD frame
If windowflag Then wf.mult2(s1)
' fourier transform
fftw.execute(fftwplan)
' fix the zeroth channel
s2(0) = 0.5 * (s2(1) + s2(s2.Length - 1))
' swap halves
Array.Copy(s2, 0, swap, 0, N)
Array.Copy(s2, N, s2, 0, N)
Array.Copy(swap, 0, s2, N, N)
' catch transients
Dim ok As Boolean = True
For i As Integer = 0 To s2.Length - 1
ok = s2(i) < 1.0E+15!
If Not ok Then Exit For
Next
If ok Then
Array.Clear(spswritebuf, 0, spswritebuf.Length)
For i As Integer = 0 To recordcount - 1
Dim i2 As Integer = 2 * (i + recordindexstart)
Dim b As Single = 0
Dim a As Single = s2(i2)
b += a * a
a = s2(i2 + 1)
b += a * a
spswritebuf(i) = b * sc
Next
End If
' log scale?
If LogScale Then
' convert to decibels
For i As Integer = 0 To recordcount - 1
spswritebuf(i) = SPSWriter.dB(spswritebuf(i))
Next
End If
' write to the file
spsfile.spectrum(CSng(Offset), CSng(RSSScale)) = spswritebuf
If spsfile.isfull Then
' closing date
spsfile.dateend = DateTime.UtcNow
' write the file
spsfile.export(obs, Nothing, filepath) ' standard file name in the working directory
spsfile = Nothing ' dispose
' start a new spectrogram
spsfile = New SPSWriter(StreamingDuration, recordcount, False, c)
With spsfile
.freqcent = frequency
.freqspan = freq2 - freq1
.dateobs = DateTime.UtcNow
End With
End If
trigcounter = (trigcounter + 1) Mod StreamingDuration
End If
End Select
s1posn = 0
End If
Loop
End If
DoEvents() ' for stopping
Loop Until filerestartflag OrElse do_exit
Dim time As Double = DateTime.UtcNow.Subtract(starttime).TotalSeconds
Dim frac As Double = CDbl(CLng(samplesperpacket) * readcount) / (time * SampleRate)
printf("%d reads, time %5.2f, fs = %5.3f MHz, per read %5.1f us (%5.1f\p)", _
readcount, time, SampleRate / MHz, time / readcount * MHz, frac * percent)
Loop Until do_exit
Catch ex As IndexOutOfRangeException
log(ex)
Throw (ex)
Catch ex As OverflowException
log(ex)
Throw (ex)
Catch ex As Exception
log(ex)
Throw (ex)
Finally
' maximum time for fft threads to finish
Dim waittime As Integer = CInt((2 * N / SampleRate + 0.1) * 1000)
' write the sps file if exists
If spsfile IsNot Nothing AndAlso ds = DataSinkType.SPS Then
' mark the time of the last spectrum
spsfile.dateend = DateTime.UtcNow
' write the file
spsfile.export(obs, Nothing, filepath) ' standard file name in the working directory
spsfile = Nothing ' dispose
End If
If ds = DataSinkType.File Then
file.Flush()
file.Close()
binWriter.Close()
End If
' wait for fft threads to finish
Sleep(waittime)
' cleanup
hs1.Free()
hs2.Free()
fftw.destroy_plan(fftwplan)
statuscontrol.Text &= sprintf(" Done.", samplesperpacket)
do_exit = False
End Try
End Sub
Public Sub Integrating(ByVal integrationtime As Double, _
ByVal recordfreqstart As Double, ByVal recordfreqend As Double, _
ByRef devconfig As rspConfig, _
ByVal triggeredduration As Double, _
ByVal obs As ObservatoryData, _
Optional ByVal datasink As DataSinkType = DataSinkType.RSS, _
Optional ByVal retries As Integer = 0, _
Optional ByVal filepath As String = Nothing, _
Optional ByVal tapspath As String = Nothing, _
Optional ByVal integrationblocksize As Double = 0.2)
Dim SwAnt As Boolean = hwver = 2 AndAlso SwitchedAntennas
' set the antenna
Antenna = devconfig.antennaSelect
' intblocksize in seconds
' frequency range
Dim flow As Double = frequency - SampleRate / 2
recordindexstart = CInt((recordfreqstart - flow) / SampleRate * N) ' unaliased spectral channel
recordindexend = CInt((recordfreqend - flow) / SampleRate * N) ' unaliased spectral channel
recordindexend = Min(recordindexend, recordindexstart + N - 1) ' cannot be larger than frame size
Dim recordcount As Integer = recordindexend - recordindexstart + 1
Dim rssfreq1 As Double = recordindexstart * SampleRate / N + flow
Dim rssfreq2 As Double = recordindexend * SampleRate / N + flow
' partitions and blocks
Dim blocks As Integer ' total number of blocks
Dim partitions As Integer ' number of partitions
Dim blockspartitioned As Integer ' blocks per partition
If integrationtime <= 0 Then
blocks = 1
partitions = 1
blockspartitioned = blocks
Else
' estimated block count
partitions = Max(1, Ceiling(integrationtime / integrationblocksize))
blockspartitioned = CInt(integrationtime * SampleRate / N) \ partitions
blocks = blockspartitioned * partitions
End If
Debug.Print("blocks " & blocks.ToString & ", partitions " & partitions.ToString & ", blockspartitioned " & blockspartitioned.ToString)
' exact integration time
integrationtime = blocks * N / SampleRate
' integration time per partition
Dim integrationtimepartitioned As Double = blockspartitioned * N / SampleRate
' array for sum over partitions
Dim s4() As Double = Nothing
Dim s5() As Double = Nothing
Dim s4counter As Long
Dim Nslash2 As Integer = N \ 2
Dim samples As Integer = N * blocks
Dim samples2 As Integer = 2 * samples
' number of samples per partition
Dim samplespartitioned As Integer = N * blockspartitioned
' twice the number of samples per partition
Dim samples2partitioned As Integer = 2 * samplespartitioned
If recordfreqstart < frequency - SampleRate / 2 OrElse recordfreqend >= frequency + SampleRate / 2 Then
recordfreqstart = frequency - SampleRate / 2
recordfreqend = frequency + SampleRate / 2 - SampleRate / N
End If
' SDRPlay read-packet variables
Dim n_read As Integer = samplesperpacket * 2
Dim bytes_to_read As UInteger = 0
Dim SampleNum As UInteger = 0
Dim SampleNumPrev As UInteger = 0
Dim grChanged As Integer = 0
Dim rfChanged As Integer = 0
Dim fsChanged As Integer = 0
Dim segmentposition As Integer = 0
' I and Q values:
Dim ibuf(samplesperpacket - 1) As Short
Dim qbuf(samplesperpacket - 1) As Short
' spectral processing initialization
Dim kernels As Integer = 5
If devconfig.pfb Then k = 4 Else k = 1
spec = New SpectralProcessing(N, kernels, integrationtimepartitioned, k, , tapspath)
spec.pollinterval = 1 + blockspartitioned \ 100
Debug.Print("threads " & spec.threadcount.ToString)
Dim s1(kernels - 1)(), s2(kernels - 1)() As Double
For i As Integer = 0 To kernels - 1
ReDim s1(i)(2 * samplespartitioned - 1)
ReDim s2(i)(N - 1)
Next
Dim writebuf() As Byte = Nothing
' background subtraction array with distinct arrays for switched mode
Dim background()() As Double = Nothing
Dim bgsum()() As Double = Nothing
' temporary buffer pointer for swap
Dim bgtmp() As Double = Nothing
' set windowing
winflag = winflag
' loop over connections
Do
' data sink
Dim client As RSSServer = Nothing
Dim spssink As SPSWriter = Nothing
Dim file As FileStream = Nothing
Dim sidclient As SID = Nothing
Dim binwriter As BinaryWriter = Nothing
Dim wrapmask As Integer = N - 1
Dim s3() As Double = Nothing
ReDim s4(recordcount - 1)
If SwAnt Then
ReDim s5(2 * recordcount - 1)
End If
s4counter = 0
Dim swap(Nslash2 - 1) As Double
Select Case datasink
Case DataSinkType.File
' TD output to a binary file
ReDim writebuf(8 * N - 1)
Dim filename As String = DateTime.UtcNow.ToString("yyyyMMddTHHmmss") & ".dat"
file = New FileStream(filename, FileMode.Create)
binwriter = New BinaryWriter(file)
Case DataSinkType.SPS
' FD output to a .sps file
Dim reccount As Integer
If SwAnt Then reccount = 2 Else reccount = 1
spssink = New SPSWriter(Min(1000000, CInt(triggeredduration / integrationtime)), recordcount, False, c, reccount)
spssink.freqcent = 0.5 * (rssfreq2 + rssfreq1)
spssink.freqspan = rssfreq2 - rssfreq1
spssink.dateobs = DateTime.UtcNow
If Not devconfig.do_exit Then ReDim s3(recordcount - 1)
Case DataSinkType.RSS
' FD output to an RSS device server
Dim rectype As ReceiverType
If SwAnt Then
rectype = ReceiverType.FSX12bitSwitching
Else
rectype = ReceiverType.RTLDongle
End If
client = New RSSServer(8888, recordcount, SampleRate / N, 0.5 * (rssfreq1 + rssfreq2), 0, rectype, ColorRes.twelvebit)
Debug.Print("sdrplay.integrating client.waitforconnection")
client.WaitForConnection(devconfig.do_exit) ' wait for a connection from RSS
Debug.Print("sdrplay.integrating client.waitforconnection done")
' buffer
If Not devconfig.do_exit Then ReDim s3(recordcount - 1)
Case DataSinkType.SID
' Data to a SID file
sidclient = New SID(rssfreq1, rssfreq2, recordcount, filepath, integrationtime, obs)
If Not devconfig.do_exit Then ReDim s3(recordcount - 1)
End Select
' periodically updating gain reduction fixes fading problem
GainReduction = GainReduction
' record the time of the first spectrum
Dim starttime As DateTime = DateTime.UtcNow
' number of hardware reads
Dim readcount As Long = 0
Try
If Not devconfig.do_exit Then
printf("Packet size %d; Starting ...", samplesperpacket)
Dim currentbuffer As Integer = 0
' loop over reads
Dim fftindex As Integer = 0
Dim s1posn As Integer = 0
Dim backgroundcount As Integer = 0
Dim droppedsamplescounter As Integer = 0
Dim scale As Double = 1.0 / 32768.0
Dim currentAntennaB As Boolean = False
Dim pausecounter As Integer = 0
Dim c1(1) As Integer
' for dividing by the number of partitions (below)
Dim s4scale As Double = 1.0 / partitions
' loop over packet reads from the hardware
Dim specctr As Long = 0
Do Until devconfig.do_exit
' fetch the data
For i As Integer = 0 To retries
r = mir_sdr_ReadPacket(ibuf, qbuf, SampleNum, grChanged, rfChanged, fsChanged)
If r = mir_sdr_ErrT.mir_sdr_Success Then
If SampleNum > samplesperpacket + SampleNumPrev AndAlso statuscallback IsNot Nothing AndAlso SampleNumPrev > 0 Then
' samples were dropped
Dim s As String = sprintf("SDRPlay.Integrating - samples dropped: %d (%d)", SampleNum - SampleNumPrev - samplesperpacket, droppedsamplescounter)
statuscallback(s)
droppedsamplescounter += 1
End If
Exit For
ElseIf r = mir_sdr_ErrT.mir_sdr_HwError Then
Continue For
ElseIf r <> mir_sdr_ErrT.mir_sdr_Success Then
Select Case datasink
Case DataSinkType.File : file.Flush() : file.Close()
Case DataSinkType.SPS : spssink.close()
Case DataSinkType.RSS : client.stopall()
Case DataSinkType.SID : sidclient = Nothing
End Select
mir_sdr_Uninit()
Throw (New ArgumentException(sprintf("%s.run - WARNING: ReadPacket failed, %s.", Me.GetType.Name, r.ToString)))
End If
Next
If r = mir_sdr_ErrT.mir_sdr_HwError Then
Throw (New ArgumentException(sprintf("%s.integrating - ReadPacket failed %d times, %s.", Me.GetType.Name, retries + 1, r.ToString)))
End If
SampleNumPrev = SampleNum
readcount += 1
' pause counter pauses processing for a time after the active antenna port is switched
If pausecounter > 0 Then
pausecounter -= 1
Continue Do
ElseIf pausecounter = 0 Then
pausecounter -= 1
End If
' interleave I and Q parts
Dim IQposn As Integer = 0
' loop to fill the blocks processing buffer
Do While IQposn < samplesperpacket
Dim s1temp() As Double = s1(fftindex)
' interleave I and Q parts; stop when either the buffer is filled, or run out of data
Do While s1posn < samples2partitioned AndAlso IQposn < samplesperpacket
s1temp(s1posn) = scale * CDbl(ibuf(IQposn))
s1posn += 1
s1temp(s1posn) = scale * CDbl(qbuf(IQposn))
s1posn += 1
IQposn += 1
Loop
' when buffer is filled
If s1posn = samples2partitioned Then
' counts the partitions processed
s4counter = s4counter + 1
' all partitions processed
If SwAnt And s4counter Mod partitions = 0 Then
' switch antennas
currentAntennaB = Not currentAntennaB
If currentAntennaB Then
Antenna = mir_sdr_RSPII_AntennaSelectT.mir_sdr_RSPII_ANTENNA_A
Else
Antenna = mir_sdr_RSPII_AntennaSelectT.mir_sdr_RSPII_ANTENNA_B
End If
pausecounter = switchedpausesamples \ samplesperpacket
End If
' fourier transform
spec.run(s1temp, s2(fftindex))
' switch to next fft buffer, which processing is presumed finished
fftindex = (fftindex + 1) Mod kernels
Dim s2temp() As Double = s2(fftindex)
' look for glitch
Dim ok As Boolean = True
' fix the zeroth channel
s2temp(0) = 0.5 * (s2temp(1) + s2temp(s2temp.Length - 1))
' swap halves
Array.Copy(s2temp, 0, swap, 0, Nslash2)
Array.Copy(s2temp, Nslash2, s2temp, 0, Nslash2)
Array.Copy(swap, 0, s2temp, Nslash2, Nslash2)
Array.Copy(s2temp, recordindexstart, s3, 0, recordcount)
' accumulate over partitions
If partitions > 1 Then
For i As Integer = 0 To recordcount - 1
s4(i) += s3(i)
Next
Else
Array.Copy(s3, s4, s4.Length)
End If
If (s4counter - spec.threadcount + 1) Mod partitions = 0 Then
' divide by the number of partitions
For i As Integer = 0 To recordcount - 1
s4(i) *= s4scale
Next
' logarithmic scale
If LogScale Then
' convert to decibels
For i As Integer = 0 To recordcount - 1
s4(i) = SPSWriter.dB(s4(i))
Next
End If
' write to the file
Select Case datasink
Case DataSinkType.File
If ok Then BlockCopy(s4, 0, writebuf, 0, writebuf.Length)
binwriter.Write(writebuf)
Case DataSinkType.SPS
If SwAnt Then
' switched antennas
If currentAntennaB Then
' fill the first half of the buffer
Array.Copy(s4, s5, recordcount)
Else
' fill the second half of the buffer and send to RSS
Array.Copy(s4, 0, s5, recordcount, recordcount)
spssink.spectrum(Offset, RSSScale) = s5
End If
Else
' write the buffer to the sps file
spssink.spectrum(Offset, RSSScale) = s4
End If
' if full, then write the file and create a new one
If spssink.isfull Then
' save
spssink.dateend = DateTime.UtcNow
spssink.export(obs.data, Nothing, filepath)
Dim spssinktemp As SPSWriter = spssink
' new file
spssink = New SPSWriter(Min(100000, CInt(triggeredduration / integrationtime)), recordcount, False, c)
spssink.freqcent = spssinktemp.freqcent
spssink.freqspan = spssinktemp.freqspan
spssink.dateobs = DateTime.UtcNow
spssinktemp = Nothing ' release the old spswriter
End If
Case DataSinkType.RSS
If ok Then
' switched antenna channel, when active, is tied to the current antenna
Dim swchancount, swantchan As Integer
If SwAnt AndAlso currentAntennaB Then swantchan = 1 Else swantchan = 0
' for background subtraction, there are two buffers for each receiver channel processed
' the first contains the active spectrum currently being subtracted from from the data stream
' the second is available for simultaneously accumulating new background spectra
' when accumulation is done, the buffers, active and accumulated, are swapped
' and the accumulating buffer is cleared for the next accumulating
' check if background subtraction is in effect
If devconfig.backgroundsubtraction OrElse c1(swantchan) = backgroundaveragecount Then
' check if there are background arrays
If background Is Nothing Then
' set the number of spectral channels whose background is being subtracted
If SwAnt Then swchancount = 2 Else swchancount = 1
' dimension the arrays
ReDim background(swchancount - 1)
' array being summed
ReDim bgsum(swchancount - 1)
End If
If background(swantchan) Is Nothing OrElse background(swantchan).Length <> recordcount Then
' create new background arrays
ReDim background(swantchan)(recordcount - 1) ' currently active background
ReDim bgsum(swantchan)(recordcount - 1) ' background to be or being accumulated
End If
' general-purpose pointer
Dim buf0() As Double
If c1(swantchan) < backgroundaveragecount Then
' set a pointer to the sum array
buf0 = bgsum(swantchan)
' accumulate background spectra
For i As Integer = 0 To recordcount - 1
buf0(i) += s4(i)
Next
' increment the number of spectra summed
c1(swantchan) += 1
' number of spectra summed is the max:
If c1(swantchan) = backgroundaveragecount Then
' divide the array
Dim x As Double = 1.0 / CDbl(c1(swantchan))
For i As Integer = 0 To recordcount - 1
buf0(i) *= x
Next
' swap active background array with the array for summing
buf0 = background(swantchan)
background(swantchan) = bgsum(swantchan)
bgsum(swantchan) = buf0
' clear the sum array for the next time background is activated
Array.Clear(bgsum(swantchan), 0, recordcount)
End If
End If
' current background buffers
buf0 = background(swantchan)
' subtract the background
For i As Integer = 0 To recordcount - 1
s4(i) -= buf0(i)
Next
' clear the sum count
If Not devconfig.backgroundsubtraction Then
For i As Integer = 0 To swchancount - 1
c1(i) = 0
Next
End If
Else
For i As Integer = 0 To swchancount - 1
c1(i) = 0
Next
End If
End If
If SwAnt Then
' switched antennas
If currentAntennaB Then
' fill the first half of the buffer
Array.Copy(s4, s5, recordcount)
Else
' fill the first half of the buffer
Array.Copy(s4, 0, s5, recordcount, recordcount)
client.spectrum(Offset, RSSScale, True) = s5
End If
Else
client.spectrum(Offset, RSSScale, True) = s4
End If
Case DataSinkType.SID
sidclient.spectrum = s4
End Select
' reset the accumulator and counter
Array.Clear(s4, 0, recordcount)
' set again gain reduction to stop fading
specctr += 1
If specctr Mod 100 = 0 Then
GainReduction(lnaoptions.currentsetting) = gr
End If
End If
segmentposition = 0
s1posn = 0
End If
Loop ' loop to fill the blocks processing buffer
' needed because of fading problem
'If readcount Mod CLng(100000) = 0 Then GainReduction = GainReduction
' for the stop flag
DoEvents()
Loop ' loop over packet reads from the hardware
devconfig.backgroundsubtraction = False
Dim time As Double = DateTime.UtcNow.Subtract(starttime).TotalSeconds
Dim frac As Double = CDbl(CLng(samplesperpacket) * readcount) / (time * SampleRate)
printf("%d reads, time %5.2f, fs = %5.3f MHz, per read %5.1f us (%5.1f\p)", _
readcount, time, SampleRate / MHz, time / readcount * MHz, frac * 100)
End If
Catch ex As SocketException
printf(ex.Message)
log(ex)
Catch ex As Exception
' maximum time for fft threads to finish
spec.close()
log(ex)
Throw (ex)
Finally
' cleanup
Select Case datasink
Case DataSinkType.File : file.Flush() : file.Close() : binwriter = Nothing
Case DataSinkType.SPS
spssink.dateend = DateTime.UtcNow ' end date
spssink.export(obs.data, Nothing, filepath) ' write the file and close
spssink = Nothing
Case DataSinkType.RSS
client.stopall()
client = Nothing
End Select
End Try
Loop Until devconfig.do_exit
devconfig.backgroundsubtraction = False
spec.close()
spec = Nothing
devconfig.do_exit = False
End Sub
Delegate Sub elog(ByVal a As String, ByVal b As String, ByVal c As Boolean, ByVal d As System.Text.Encoding)
''' Write exception information to a log file.
''' The exception to be logged.
Public Shared Sub log(ByVal ex As Exception, Optional ByVal filename As String = "SDRPlay.log")
Static e As elog = AddressOf My.Computer.FileSystem.WriteAllText
Static a As System.Text.Encoding = Text.Encoding.ASCII
e(filename, Now.ToString("s") & " ============================= " & ex.GetType.Name & vbNewLine, True, a)
e(filename, ex.Message & vbNewLine, True, a)
e(filename, ex.StackTrace & vbNewLine, True, a)
If ex.InnerException IsNot Nothing Then
e(filename, "= = = = = = = = = = = = = = = = = = = = =" & vbNewLine, True, a)
e(filename, ex.InnerException.StackTrace & vbNewLine, True, a)
End If
End Sub
Public Overloads Sub finalize()
mir_sdr_Uninit()
MyBase.Finalize()
End Sub
Public dcc As EnableDisable = EnableDisable.disable
Public Property DCCorrection() As EnableDisable
Get
Return dcc
End Get
Set(ByVal value As EnableDisable)
Select Case value
Case 0, 1
dcc = value
r = mir_sdr_SetParam(102, value)
If r <> mir_sdr_ErrT.mir_sdr_Success Then
Throw (New ArgumentException(sprintf("%s.%s - error %s", Me.GetType.Name, "DCCorrection", r.ToString)))
End If
Case 2
r = mir_sdr_SetParam(104, 0)
If r <> mir_sdr_ErrT.mir_sdr_Success Then
Throw (New ArgumentException(sprintf("%s.%s - error %s", Me.GetType.Name, "DCCorrection", r.ToString)))
End If
End Select
End Set
End Property
Public iqc As EnableDisable = EnableDisable.disable
Public Property IQCorrection() As EnableDisable
Get
Return iqc
End Get
Set(ByVal value As EnableDisable)
Select Case value
Case 0, 1
iqc = value
r = mir_sdr_SetParam(105, value)
If r <> mir_sdr_ErrT.mir_sdr_Success Then
Throw (New ArgumentException(sprintf("%s.%s - error %s", Me.GetType.Name, "IQCorrection", r.ToString)))
End If
Case 2
r = mir_sdr_SetParam(106, 0)
If r <> mir_sdr_ErrT.mir_sdr_Success Then
Throw (New ArgumentException(sprintf("%s.%s - error %s", Me.GetType.Name, "IQCorrection", r.ToString)))
End If
End Select
End Set
End Property
Dim gm As GainMapSettings = GainMapSettings.defaultset
Public Property GainMap() As GainMapSettings
Get
Return gm
End Get
Set(ByVal value As GainMapSettings)
gm = value
r = mir_sdr_SetParam(201, value)
If r <> mir_sdr_ErrT.mir_sdr_Success Then
Throw (New ArgumentException(sprintf("%s.%s - error %s", Me.GetType.Name, "GainMap", r.ToString)))
End If
End Set
End Property
''' Sets port-B bias T
Public WriteOnly Property BiasT() As Boolean
Set(ByVal value As Boolean)
Select Case hwver
Case 2
If value Then
mir_sdr_RSPII_BiasTControl(1)
Else
mir_sdr_RSPII_BiasTControl(0)
End If
Case rsp1aver
If value Then
mir_sdr_rsp1a_BiasT(1)
Else
mir_sdr_rsp1a_BiasT(0)
End If
Case Else
' nothing for rsp1
End Select
End Set
End Property
''' select the antenna port
''' Programmed to the rsp2 spec: select am port while uninitialized;
''' A and B port whether initialized or not, but takes effect after initialization.
''' But doesn't seem to work that way.
Public WriteOnly Property Antenna() As mir_sdr_RSPII_AntennaSelectT
Set(ByVal value As mir_sdr_RSPII_AntennaSelectT)
Select Case hwver
Case 2
' initialized rsp2
If value <> mir_sdr_RSPII_AntennaSelectT.mir_sdr_RSPII_HiZ Then
' antenna A or B
mir_sdr_RSPII_AntennaControl(value)
Else
Exit Select
End If
Exit Select
Case rsp1aver
' RSP1a
Case Else
' not initialized
If value = mir_sdr_RSPII_AntennaSelectT.mir_sdr_RSPII_HiZ Then
' hi-z port
Debug.Print(mir_sdr_AmPortSelect(1).ToString)
Exit Select
Else
Debug.Print(mir_sdr_AmPortSelect(0).ToString)
Debug.Print(mir_sdr_RSPII_AntennaControl(value).ToString)
End If
End Select
End Set
End Property
Dim lnavar As EnableDisable
Public Property LNA() As EnableDisable
Get
Return lnavar
End Get
Set(ByVal value As EnableDisable)
If hwver = 2 Then
If gm = GainMapSettings.newset Then
lnavar = value
r = mir_sdr_SetParam(202, value)
If r <> mir_sdr_ErrT.mir_sdr_Success Then
Throw (New ArgumentException(sprintf("%s.%s - error %s", Me.GetType.Name, "LNA", r.ToString)))
End If
Else
Throw (New ArgumentException(sprintf("%s.%s - GainMap must be set to 'new'.", Me.GetType.Name, "LNA")))
End If
End If
End Set
End Property
Public Enum DataSinkType
None
File
RSS
SPS
FITS
SID ' sudden ionospheric disturband
End Enum
Enum lnaoptions
onsetting
offsetting
currentsetting
End Enum
Private gr As Integer = 40
Private lnasetting As lnaoptions = lnaoptions.offsetting
Public Property GainReduction(Optional ByVal lna As lnaoptions = lnaoptions.currentsetting) As Integer
Get
Return gr
End Get
Set(ByVal value As Integer)
Dim mir_lna As Integer
Select Case lna
Case lnaoptions.onsetting
mir_lna = 1
Case lnaoptions.offsetting
mir_lna = 0
Case lnaoptions.currentsetting
Select Case lnasetting
Case lnaoptions.onsetting
mir_lna = 1
Case lnaoptions.offsetting
mir_lna = 0
End Select
End Select
Dim overallgrreturn As Integer
Dim seterror As mir_sdr_ErrT
seterror = mir_sdr_SetGrAltMode(value, mir_lna, overallgrreturn, 1, 0)
If seterror <> mir_sdr_ErrT.mir_sdr_Success Then
Debug.Print("SDRPlay.GainReduction - " & seterror.ToString)
Select Case seterror
Case mir_sdr_ErrT.mir_sdr_NotInitialised
Case mir_sdr_ErrT.mir_sdr_GainUpdateError
Case mir_sdr_ErrT.mir_sdr_InvalidParam
Case mir_sdr_ErrT.mir_sdr_OutOfRange
Case mir_sdr_ErrT.mir_sdr_HwError
End Select
Else
Debug.Print("SDRPlay.GainReduction - before " & gr.ToString & " set " & value.ToString & " actual" & overallgrreturn.ToString)
gr = value 'overallgrreturn
Select Case lna
Case lnaoptions.onsetting, lnaoptions.offsetting
lnasetting = lna
End Select
End If
End Set
End Property
Public Enum GRRelAbs
relative = 0
absolute = 1
End Enum
Public Enum GRUpdate
immediate = 0
synchronous = 1
End Enum
Public Shared Function bandwidth(ByVal x As mir_sdr_Bw_MHzT) As Double
Return x * 1000.0
End Function
''' Set or returns whether the Fourier computation is windowed.
Public Property winflag() As Boolean
Get
Return windowflag
End Get
Set(ByVal value As Boolean)
windowflag = value
If spec IsNot Nothing Then spec.WindowFlag = windowflag
End Set
End Property
Delegate Sub changecontroltextdelegate(ByVal text As String)
Public Shared Function mirVersion() As Single
Dim ver As Single
Dim errval As mir_sdr_ErrT = mir_sdr_ApiVersion(ver)
If errval = mir_sdr_ErrT.mir_sdr_InvalidParam Then
Throw New ArgumentException("SDRPlay.mirVersion - error reading API version.")
End If
Return ver
End Function
Public WriteOnly Property notchfilter() As Boolean
Set(ByVal value As Boolean)
Dim res As mir_sdr_ErrT
If hwver = 2 Then
If value Then
res = mir_sdr_RSPII_RfNotchEnable(1)
Else
res = mir_sdr_RSPII_RfNotchEnable(0)
End If
Else
Debug.Print("SDRPlay.notchfilter.Set - invalid device")
End If
End Set
End Property
Dim dabvar As Boolean
Public Property dabNotchFilter() As Boolean
Get
Return dabvar
End Get
Set(ByVal value As Boolean)
If hwver = rsp1aver Then
dabvar = value
If dabvar Then
mir_sdr_rsp1a_DabNotch(1)
Else
mir_sdr_rsp1a_DabNotch(0)
End If
Else
Debug.Print("SDRPlay.dabNotchFilter.Set - wrong h/w version")
End If
End Set
End Property
Dim bcastvar As Boolean
Public Property bcastNotchFilter() As Boolean
Get
Return bcastvar
End Get
Set(ByVal value As Boolean)
If hwver = rsp1aver Then
bcastvar = value
If bcastvar Then
mir_sdr_rsp1a_BroadcastNotch(1)
Else
mir_sdr_rsp1a_BroadcastNotch(0)
End If
Else
Debug.Print("SDRPlay.bcastNotchFilter.Set - wrong h/w version")
End If
End Set
End Property
#Region "SDRPlay dll enumerations"
Enum GainMapSettings
defaultset = 0
newset = 1
End Enum
Enum EnableDisable
disable = 0
enable = 1
reset = 2
End Enum
Enum mir_sdr_ErrT
mir_sdr_Success = 0
mir_sdr_Fail = 1
mir_sdr_InvalidParam = 2
mir_sdr_OutOfRange = 3
mir_sdr_GainUpdateError = 4
mir_sdr_RfUpdateError = 5
mir_sdr_FsUpdateError = 6
mir_sdr_HwError = 7
mir_sdr_AliasingError = 8
mir_sdr_AlreadyInitialised = 9
mir_sdr_NotInitialised = 10
mir_sdr_NotEnabled = 11
mir_sdr_HwVerError = 12
mir_sdr_OutOfMemError = 13
End Enum
Enum mir_sdr_Bw_MHzT
mir_sdr_BW_0_200 = 200
mir_sdr_BW_0_300 = 300
mir_sdr_BW_0_600 = 600
mir_sdr_BW_1_536 = 1536
mir_sdr_BW_5_000 = 5000
mir_sdr_BW_6_000 = 6000
mir_sdr_BW_7_000 = 7000
mir_sdr_BW_8_000 = 8000
End Enum
Enum mir_sdr_If_kHzT
mir_sdr_IF_Zero = 0
mir_sdr_IF_0_450 = 450
mir_sdr_IF_1_620 = 1620
mir_sdr_IF_2_048 = 2048
End Enum
Enum mir_sdr_TransferModeT
mir_sdr_ISOCH = 0
mir_sdr_BULK = 1
End Enum
Enum mir_sdr_JavaReqT
mir_sdr_GetFd = 0
mir_sdr_FreeFd = 1
mir_sdr_DevNotFound = 2
mir_sdr_DevRemoved = 3
End Enum
Enum DCOffsetCorrectionMode
staticmode
periodic6ms
periodic12ms
periodic24ms
oneshot
continuous
End Enum
Enum mir_sdr_RSPII_AntennaSelectT
mir_sdr_RSPII_ANTENNA_A = 5
mir_sdr_RSPII_ANTENNA_B = 6
mir_sdr_RSPII_HiZ = 7
End Enum
Enum mir_sdr_ReasonForReinitT
mir_sdr_CHANGE_NONE = &H0
mir_sdr_CHANGE_GR = &H1
mir_sdr_CHANGE_FS_FREQ = &H2
mir_sdr_CHANGE_RF_FREQ = &H4
mir_sdr_CHANGE_BW_TYPE = &H8
mir_sdr_CHANGE_IF_TYPE = &H10
mir_sdr_CHANGE_LO_MODE = &H20
mir_sdr_CHANGE_AM_PORT = &H40
End Enum
Enum mir_sdr_LoModeT
mir_sdr_LO_Undefined = 0
mir_sdr_LO_Auto = 1 ' 1st LO is automatically selected to provide appropriate coverage
' across all tuner frequency ranges
mir_sdr_LO_120MHz = 2 ' 1st LO is set to 120MHz (coverage gap between 370MHZ and 420MHz)
mir_sdr_LO_144MHz = 3 ' 1st LO is set to 144MHz (coverage gap between 250MHZ and 255MHz
' and between 400MHz and 420MHz)
mir_sdr_LO_168MHz = 4 ' 1st LO is set to 168MHz (coverage gap between 250MHZ and 265MHz)
End Enum
Enum mir_sdr_BandT
mir_sdr_BAND_AM_LO = 0 ' 0 <= Freq < 12 MHz
mir_sdr_BAND_AM_MID = 1 ' 12 <= Freq < 30 MHz
mir_sdr_BAND_AM_HI = 2 ' 30 <= Freq < 60 MHz
mir_sdr_BAND_VHF = 3 ' 60 <= Freq < 120 MHz
mir_sdr_BAND_3 = 4 ' 120 <= Freq < 250 MHz
mir_sdr_BAND_X = 5 ' 250 <= Freq < 420 MHz
mir_sdr_BAND_4_5 = 6 ' 420 <= Freq < 1000 MHz
mir_sdr_BAND_L = 7 ' 1000 <= Freq < 2000 MHz
End Enum
Enum mir_sdr_SetGrModeT
mir_sdr_USE_SET_GR = 0
mir_sdr_USE_SET_GR_ALT_MODE = 1
mir_sdr_USE_RSP_SET_GR = 2
End Enum
Enum mir_sdr_RSPII_BandT
mir_sdr_RSPII_BAND_UNKNOWN = 0
mir_sdr_RSPII_BAND_AM_LO = 1
mir_sdr_RSPII_BAND_AM_MID = 2
mir_sdr_RSPII_BAND_AM_HI = 3
mir_sdr_RSPII_BAND_VHF = 4
mir_sdr_RSPII_BAND_3 = 5
mir_sdr_RSPII_BAND_X_LO = 6
mir_sdr_RSPII_BAND_X_MID = 7
mir_sdr_RSPII_BAND_X_HI = 8
mir_sdr_RSPII_BAND_4_5 = 9
mir_sdr_RSPII_BAND_L = 10
End Enum
Enum mir_sdr_AgcControlT
mir_sdr_AGC_DISABLE = 0
mir_sdr_AGC_100HZ = 1
mir_sdr_AGC_50HZ = 2
mir_sdr_AGC_5HZ = 3
End Enum
Enum mir_sdr_GainMessageIdT
mir_sdr_GAIN_MESSAGE_START_ID = &H80000000
mir_sdr_ADC_OVERLOAD_DETECTED = mir_sdr_GAIN_MESSAGE_START_ID + 1
mir_sdr_ADC_OVERLOAD_CORRECTED = mir_sdr_GAIN_MESSAGE_START_ID + 2
End Enum
Enum mir_sdr_MinGainReductionT
mir_sdr_EXTENDED_MIN_GR = 0 ' 0 to 59
mir_sdr_NORMAL_MIN_GR = 20 ' 20 to 59
End Enum
Structure mir_sdr_DeviceT
Dim SerNo() As Char
Dim DevNm() As Char
Dim hwVer As Byte
Dim devAvail As Byte
End Structure
Structure mir_sdr_GainValuesT
Dim curr As Single
Dim max As Single
Dim min As Single
End Structure
Public Structure rspConfig
Dim biasT As Boolean
Dim rsp2notchEnable As Boolean
Dim rsp1adabnotchEnable As Boolean
Dim rsp1abroadcastnotchEnable As Boolean
Dim antennaSelect As mir_sdr_RSPII_AntennaSelectT
Dim do_exit As Boolean
Dim backgroundsubtraction As Boolean
Dim pfb As Boolean
End Structure
#End Region
#Region "SDRPlay dll function declarations"
' mir_sdr_ErrT mir_sdr_SetGrAltMode(int *gRidx, int LNAstate, int *gRdBsystem, int abs, int syncUpdate)
Declare Auto Function mir_sdr_SetGrAltMode Lib "mir_sdr_api.dll" (ByRef gRidx As Integer, ByVal LNAstate As Integer, ByRef gRdBsystem As Integer, ByVal grDbsystem As Integer, ByVal syncUpdate As Integer) As mir_sdr_ErrT
Declare Auto Function mir_sdr_ApiVersion Lib "mir_sdr_api.dll" (ByRef version As Single) As mir_sdr_ErrT
Declare Auto Function mir_sdr_DebugEnable Lib "mir_sdr_api.dll" (ByVal enable As UInteger) As mir_sdr_ErrT
Declare Auto Function mir_sdr_GetHwVersion Lib "mir_sdr_api.dll" (ByRef ver As Byte) As mir_sdr_ErrT
Declare Auto Function mir_sdr_AmPortSelect Lib "mir_sdr_api.dll" (ByVal port As Integer) As mir_sdr_ErrT
Declare Auto Function mir_sdr_RSPII_BiasTControl Lib "mir_sdr_api.dll" (ByVal enable As UInteger) As mir_sdr_ErrT
' mir_sdr_ErrT mir_sdr_rsp1a_DabNotch(int enable);
Declare Auto Function mir_sdr_rsp1a_DabNotch Lib "mir_sdr_api.dll" (ByVal enable As UInteger) As mir_sdr_ErrT
' mir_sdr_ErrT mir_sdr_RSPII_RfNotchEnable(unsigned int enable);
Declare Auto Function mir_sdr_RSPII_RfNotchEnable Lib "mir_sdr_api.dll" (ByVal en As UInteger) As mir_sdr_ErrT
Declare Auto Function mir_sdr_rsp1a_BroadcastNotch Lib "mir_sdr_api.dll" (ByVal enable As UInteger) As mir_sdr_ErrT
' _MIR_SDR_QUALIFIER mir_sdr_ErrT mir_sdr_rsp1a_BiasT(int enable);
Declare Auto Function mir_sdr_rsp1a_BiasT Lib "mir_sdr_api.dll" (ByVal enable As UInteger) As mir_sdr_ErrT
'[DllImport(APIDLL)]
'mir_sdr_ErrT mir_sdr_RSPII_AntennaControl(mir_sdr_RSPII_AntennaSelectT select);
Declare Auto Function mir_sdr_RSPII_AntennaControl Lib "mir_sdr_api.dll" (ByVal selectx As mir_sdr_RSPII_AntennaSelectT) As mir_sdr_ErrT
'[DllImport("mir_sdr_api.dll")]
'private shared extern mir_sdr_ErrT mir_sdr_SetParam(ParamterId as integer, value as integer);
Declare Auto Function mir_sdr_SetParam Lib "mir_sdr_api.dll" (ByVal ParameterId As Integer, ByVal value As Integer) As mir_sdr_ErrT
'[DllImport("mir_sdr_api.dll")]
'private shared extern mir_sdr_ErrT mir_sdr_Init(int gRdB, double fsMHz, double rfMHz, mir_sdr_Bw_MHzT bwType, _
' mir_sdr_If_kHzT ifType, ref int samplesPerPacket);
Declare Auto Function mir_sdr_Init Lib "mir_sdr_api.dll" (ByVal gRdB As Integer, ByVal fsMHz As Double, ByVal rfMHz As Double, ByVal bwType As mir_sdr_Bw_MHzT, _
ByVal ifType As mir_sdr_If_kHzT, ByRef samplesPerPacket As Integer) As mir_sdr_ErrT
'[DllImport("mir_sdr_api.dll")]
'private shared extern mir_sdr_ErrT mir_sdr_SetDcMode(int dcCal, int speedUp);
Declare Auto Function mir_sdr_SetDcMode Lib "mir_sdr_api.dll" (ByVal dcCal As DCOffsetCorrectionMode, ByVal speedup As EnableDisable) As mir_sdr_ErrT
'[DllImport("mir_sdr_api.dll")]
'private shared extern mir_sdr_ErrT mir_sdr_SetDcTrackTime(int trackTime);
Declare Auto Function mir_sdr_SetDcTrackTime Lib "mir_sdr_api.dll" (ByVal trackTime As Integer) As mir_sdr_ErrT
'[DllImport("mir_sdr_api.dll")]
'private shared extern mir_sdr_ErrT mir_sdr_ReadPacket( short[] xi, short [] xq, ref uint firstSampleNum, _
' ref int grChanged, ref int rfChanged, ref int fsChanged);
Declare Auto Function mir_sdr_ReadPacket Lib "mir_sdr_api.dll" (ByVal xi() As Short, ByVal xq() As Short, ByRef firstSampleNum As UInteger, _
ByRef grChanged As Integer, ByRef rfChanged As Integer, ByRef fsChanged As Integer) As mir_sdr_ErrT
'[DllImport("mir_sdr_api.dll")]
'private shared extern mir_sdr_ErrT mir_sdr_Uninit();
Declare Auto Function mir_sdr_Uninit Lib "mir_sdr_api.dll" () As mir_sdr_ErrT
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_SetRf(double drfHz, int abs, int syncUpdate);
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_SetFs(double dfsHz, int abs, int syncUpdate, int reCal);
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_SetGr(int gRdB, int abs, int syncUpdate);
Declare Auto Function mir_sdr_SetGr Lib "mir_sdr_api.dll" (ByVal gRdb As Integer, ByVal abs As GRRelAbs, ByVal syncUpdate As GRUpdate) As mir_sdr_ErrT
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_SetGrParams(int minimumGr, int lnaGrThreshold);
'const string APIDLL = "mir_sdr_api.dll";
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_Init(int gRdB, double fsMHz, double rfMHz, SDRplayIO.mir_sdr_Bw_MHzT bwType, SDRplayIO.mir_sdr_If_kHzT ifType, out int samplesPerPacket);
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_Uninit();
'[DllImport(APIDLL)]
'public unsafe static extern SDRplayIO.mir_sdr_ErrT mir_sdr_ReadPacket(short* xi, short* xq, out uint firstSampleNum, out int grChanged, out int rfChanged, out int fsChanged);
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_SetRf(double drfHz, int abs, int syncUpdate);
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_SetFs(double dfsHz, int abs, int syncUpdate, int reCal);
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_SetGr(int gRdB, int abs, int syncUpdate);
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_SetGrParams(int minimumGr, int lnaGrThreshold);
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_SetDcMode(int dcCal, int speedUp);
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_SetDcTrackTime(int trackTime);
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_SetSyncUpdateSampleNum(uint sampleNum);
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_SetSyncUpdatePeriod(uint period);
'[DllImport(APIDLL)]
'public unsafe static extern SDRplayIO.mir_sdr_ErrT mir_sdr_DownConvert(short* xin, short* xi, short* xq, uint SamplesPerPacket, SDRplayIO.mir_sdr_If_kHzT ifType, uint Decimation, uint Preset);
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_SetParam(int ParameterId, int Value);
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_ResetUpdateFlags(int ResetGainUpdate, int ResetRFUpdate, int ResetFsUpdate);
'[DllImport(APIDLL)]
'public static extern SDRplayIO.mir_sdr_ErrT mir_sdr_ApiVersion(out float version); // Called by application to retrieve version of API used to create Dll
'using System;
'using System.Collections.Generic;
'using System.Runtime.InteropServices;
'using System.IO;
'namespace RSPSample1
'{
' Class Program
' {
' Enum mir_sdr_ErrT
' {
' mir_sdr_Success = 0,
' mir_sdr_Fail = 1,
' mir_sdr_InvalidParam = 2,
' mir_sdr_OutOfRange = 3,
' mir_sdr_GainUpdateError = 4,
' mir_sdr_RfUpdateError = 5,
' mir_sdr_FsUpdateError = 6,
' mir_sdr_HwError = 7,
' mir_sdr_AliasingError = 8,
' mir_sdr_AlreadyInitialised = 9,
' mir_sdr_NotInitialised = 10
' }
' Private Enum mir_sdr_Bw_MHzT
' {
' mir_sdr_BW_0_200 = 200,
' mir_sdr_BW_0_300 = 300,
' mir_sdr_BW_0_600 = 600,
' mir_sdr_BW_1_536 = 1536,
' mir_sdr_BW_5_000 = 5000,
' mir_sdr_BW_6_000 = 6000,
' mir_sdr_BW_7_000 = 7000,
' mir_sdr_BW_8_000 = 8000
' }
' Private Enum mir_sdr_If_kHzT
' {
' mir_sdr_IF_Zero = 0,
' mir_sdr_IF_0_450 = 450,
' mir_sdr_IF_1_620 = 1620,
' mir_sdr_IF_2_048 = 2048
' }
' static void Main(string[] args)
' {
' const int DEFAULT_SAMPLE_RATE = 2048000;
' const int DEFAULT_BUF_LENGTH = (336 * 2);
' bool do_exit = false;
' uint bytes_to_read = 0;
' // I and Q values:
' short[] ibuf;
' short[] qbuf;
' uint firstSample = 0;
' int samplesPerPacket = 0, grChanged = 0, fsChanged = 0, rfChanged = 0;
' string filename = "filename1.raw"; // output file, containing raw IQ samples
' int n_read;
' mir_sdr_ErrT r;
' int gain = 50;
' FileStream file = new FileStream(filename,FileMode.Create);
' BinaryWriter binWriter = new BinaryWriter(file);
' byte[] buffer = new byte[DEFAULT_BUF_LENGTH];
' uint frequency = 87900000; // frequency: 87.9 MHZ (a local FM station)
' uint samp_rate = DEFAULT_SAMPLE_RATE;
' int i, j;
' r = mir_sdr_Init(40, 2.0, 100.00, mir_sdr_Bw_MHzT.mir_sdr_BW_1_536, mir_sdr_If_kHzT.mir_sdr_IF_Zero,
' ref samplesPerPacket);
' if (r != mir_sdr_ErrT.mir_sdr_Success)
' {
' Console.WriteLine("Failed to open SDRplay RSP device.");
' return;
' }
' mir_sdr_Uninit();
' mir_sdr_SetParam(201, 1);
' mir_sdr_SetParam(202, 0);
' r = mir_sdr_Init(gain, (samp_rate / 1e6), (frequency / 1e6),
' mir_sdr_Bw_MHzT.mir_sdr_BW_1_536, mir_sdr_If_kHzT.mir_sdr_IF_Zero, ref samplesPerPacket);
' if (r != mir_sdr_ErrT.mir_sdr_Success)
' {
' Console.WriteLine("Failed to open SDRplay RSP device.");
' return;
' }
' mir_sdr_SetDcMode(4, 0);
' mir_sdr_SetDcTrackTime(63);
' ibuf = new short[samplesPerPacket];
' qbuf = new short[samplesPerPacket];
' Console.WriteLine("Writing samples...");
' while (!do_exit)
' {
' r = mir_sdr_ReadPacket( ibuf, qbuf, ref firstSample, ref grChanged, ref rfChanged,
' ref fsChanged);
' if (r != mir_sdr_ErrT.mir_sdr_Success)
' {
' Console.WriteLine("WARNING: ReadPacket failed.");
' break;
' }
' j = 0;
' for (i = 0; i < samplesPerPacket; i++)
' {
' // I and Q values are 16-bits values; here we convert them to 8-bits to be compatible with RTL-SDR format.
' buffer[j++] = (byte) (ibuf[i] >> 8);
' buffer[j++] = (byte) (qbuf[i] >> 8);
' }
' n_read = (samplesPerPacket * 2);
' if ((bytes_to_read > 0) && (bytes_to_read <= (uint)n_read))
' {
' n_read = (int)bytes_to_read;
' do_exit = true;
' }
' binWriter.Write(buffer);
' if (bytes_to_read > 0)
' bytes_to_read -= (uint)n_read;
' }
' file.Flush();
' file.Close();
' mir_sdr_Uninit();
' }
' }
'}
#End Region
End Class