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