// // SDRSpectrum.swift // PrySDR // // Created by Jacky Jack on 10/01/2025. // // // FileSpectrum.swift // PrySDR // // Created by Jacky Jack on 01/01/2025. // import Accelerate import AppKit import Combine import CoreImage import libr820 class SDRSpectrum: NSObject, ObservableObject { static let default_width = 512 static let default_height = 512 static let defaultSleepTime:UInt32 = 1 var offset:Int=0 var allData:[Int8]? = nil var line_counter:Int = 0 //SDR default configs let device_idx: UInt32 = 0 let samplerate: Int = 2048000 let gain: Int = 0 let frequency: Int = 99500000 let nsamples: Int = default_width var device: R820Tuner? //fft drawing related let fft512 = NaiveFFT512() let sessionQueue = DispatchQueue(label: "sessionQueue", attributes: [], autoreleaseFrequency: .workItem) @Published var outputImage = emptyCGImage let simpleImage = SimpleImage(width: default_width, height: default_height) /// A 1x1 Core Graphics image. static var emptyCGImage: CGImage = { let buffer = vImage.PixelBuffer( pixelValues: [0], size: .init(width: 1, height: 1), pixelFormat: vImage.Planar8.self) let fmt = vImage_CGImageFormat( bitsPerComponent: 8, bitsPerPixel: 8 , colorSpace: CGColorSpaceCreateDeviceGray(), bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue), renderingIntent: .defaultIntent) return buffer.makeCGImage(cgImageFormat: fmt!)! }() func makeSpectrogramImage() -> NSImage { return NSImage(cgImage: SDRSpectrum.emptyCGImage, size: .zero) } //just get data time to time from databuffer and pretend to be realtime data func dataFileProcessor() { } func startRunning() { let buf_ptr = UnsafeMutableRawPointer.allocate(byteCount: nsamples, alignment: 1) var nbytes:Int32 = 0 //var total_bytes:Int32 = 0 //prepare sdr print("Prepare SDR") let count = getDeviceCount() print("Found \(count) devices") self.device = R820Tuner() sleep(1) if (self.device != nil) { self.device!.open(index:0) //prepare dongle to receive some data let _ = self.device!.setSampleRate(samplerate: UInt32(samplerate)) let _ = self.device!.setCenterFreq(freq: UInt32(frequency)) let _ = self.device!.setAgcMode(on: 1) let _ = self.device!.resetBuffer() } //run the task sessionQueue.async { print("lets start the task for spectrum analysis") for i in 0..<512 { if let dev = self.device { let ret = dev.readSync(buf: buf_ptr, len: Int32(self.nsamples), n_read: &nbytes) if ret<0 { print("data read sync returned <0 = \(ret)") sleep(1); continue; } } print("Got \(nbytes) bytes") /* let dataU8 = buf_ptr.bindMemory(to: UInt8.self, capacity: self.nsamples) let bufferU8 = UnsafeBufferPointer(start: dataU8, count: self.nsamples) let convertedData = Data(bufferU8) */ let dataI8 = buf_ptr.bindMemory(to: Int8.self, capacity: self.nsamples) let bufferI8 = UnsafeBufferPointer(start: dataI8, count: self.nsamples) let safeI8 = Array(bufferI8) let transform_result = self.fft512.computeLine(safeI8) print(transform_result) print("FFT result \(transform_result.count) points") //let drawSlice = transform_result[0...SDRSpectrum.default_width-1] //print("FFT result \(drawSlice.count) points") self.simpleImage.drawPalletLine(line: i, pixelLine: transform_result) self.outputImage = self.simpleImage.toCGImage()! print("Process the task line \(i)") sleep(1) } print("SDR loop done run") } } }