1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
//
// 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")
}
}
}
|