From 4a489b2f306c179e303567908a26e7e79ef5c0dd Mon Sep 17 00:00:00 2001
From: Arturs Artamonovs <arturs.artamonovs@protonmail.com>
Date: Fri, 13 Dec 2024 10:19:13 +0000
Subject: AirSpy: receives valid samples

---
 PrySDR.xcodeproj/project.pbxproj | 106 ++++++++++++++++++++++++++++++++++++++-
 Radio/HW/AirSpy/AirSpy.swift     |  20 ++++++++
 Radio/Utils/AirSpyIQ/main.swift  |  65 ++++++++++++++++++++++--
 Radio/Utils/BladeRFIQ/main.swift |  14 ++++++
 4 files changed, 199 insertions(+), 6 deletions(-)
 create mode 100644 Radio/Utils/BladeRFIQ/main.swift

diff --git a/PrySDR.xcodeproj/project.pbxproj b/PrySDR.xcodeproj/project.pbxproj
index 415a2d0..05e4d16 100644
--- a/PrySDR.xcodeproj/project.pbxproj
+++ b/PrySDR.xcodeproj/project.pbxproj
@@ -62,6 +62,9 @@
 		8D8770AB2CD6B57E0082EC54 /* libbladerf.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D87709D2CD6B4BB0082EC54 /* libbladerf.a */; };
 		8D8771492CD7A69B0082EC54 /* libbladerf.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D87709D2CD6B4BB0082EC54 /* libbladerf.a */; };
 		8D87714A2CD7A6A40082EC54 /* libr820.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D5A5DB42CD4B70D0096CBD7 /* libr820.a */; };
+		8D9A334F2D0B0DD6009A4186 /* libusb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D5A5DDA2CD4B9100096CBD7 /* libusb.a */; };
+		8D9A33502D0B0DD8009A4186 /* libbladerf.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D87709D2CD6B4BB0082EC54 /* libbladerf.a */; };
+		8D9A33522D0B0DE5009A4186 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 8D9A33512D0B0DE5009A4186 /* ArgumentParser */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -271,6 +274,15 @@
 			);
 			runOnlyForDeploymentPostprocessing = 1;
 		};
+		8D9A33422D0B0D8D009A4186 /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = /usr/share/man/man1/;
+			dstSubfolderSpec = 0;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 1;
+		};
 		8DD98C3F2CC592540062D678 /* CopyFiles */ = {
 			isa = PBXCopyFilesBuildPhase;
 			buildActionMask = 2147483647;
@@ -298,6 +310,7 @@
 		8D876E772CD4DB8F0082EC54 /* test_airspyhf */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_airspyhf; sourceTree = BUILT_PRODUCTS_DIR; };
 		8D876FFD2CD4F1620082EC54 /* test_bladerf */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_bladerf; sourceTree = BUILT_PRODUCTS_DIR; };
 		8D87709D2CD6B4BB0082EC54 /* libbladerf.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libbladerf.a; sourceTree = BUILT_PRODUCTS_DIR; };
+		8D9A33442D0B0D8D009A4186 /* bladerf_iq */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = bladerf_iq; sourceTree = BUILT_PRODUCTS_DIR; };
 		8DD98C412CC592540062D678 /* prysdr */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = prysdr; sourceTree = BUILT_PRODUCTS_DIR; };
 		8DD98C722CC632040062D678 /* MatrixXT.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MatrixXT.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
@@ -331,6 +344,7 @@
 		8D40684F2CFDA6BD0064C96D /* Exceptions for "Radio" folder in "AirSpyIQ" target */ = {
 			isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
 			membershipExceptions = (
+				HW/AirSpy/AirSpy.swift,
 				Utils/AirSpyIQ/main.swift,
 			);
 			target = 8D4068442CFDA6B80064C96D /* AirSpyIQ */;
@@ -536,6 +550,7 @@
 				HW/RtlSdr/r820/src/tuner_r82xx.c,
 				Utils/AirSpyHFIQ/main.swift,
 				Utils/AirSpyIQ/main.swift,
+				Utils/BladeRFIQ/main.swift,
 				Utils/RtlSdrIQ/main.swift,
 				Utils/TestAirSpy/main.swift,
 				Utils/TestAirSpyHF/main.swift,
@@ -721,6 +736,14 @@
 			);
 			target = 8D87709C2CD6B4BB0082EC54 /* libbladerf */;
 		};
+		8D9A334E2D0B0D92009A4186 /* Exceptions for "Radio" folder in "BladeRFIQ" target */ = {
+			isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
+			membershipExceptions = (
+				HW/BladeRF/BladeRF.swift,
+				Utils/BladeRFIQ/main.swift,
+			);
+			target = 8D9A33432D0B0D8D009A4186 /* BladeRFIQ */;
+		};
 		8DD98C7C2CC6320C0062D678 /* Exceptions for "LA" folder in "PrySDR" target */ = {
 			isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
 			membershipExceptions = (
@@ -779,6 +802,7 @@
 				8D0349222CF70DD20026DA77 /* Exceptions for "Radio" folder in "RtlSdrIQ" target */,
 				8D4068402CFDA6A30064C96D /* Exceptions for "Radio" folder in "AirSpyHFIQ" target */,
 				8D40684F2CFDA6BD0064C96D /* Exceptions for "Radio" folder in "AirSpyIQ" target */,
+				8D9A334E2D0B0D92009A4186 /* Exceptions for "Radio" folder in "BladeRFIQ" target */,
 			);
 			path = Radio;
 			sourceTree = "<group>";
@@ -949,6 +973,16 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		8D9A33412D0B0D8D009A4186 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8D9A33522D0B0DE5009A4186 /* ArgumentParser in Frameworks */,
+				8D9A33502D0B0DD8009A4186 /* libbladerf.a in Frameworks */,
+				8D9A334F2D0B0DD6009A4186 /* libusb.a in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		8DD98C3E2CC592540062D678 /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
@@ -1020,6 +1054,7 @@
 				8D0349182CF70DCD0026DA77 /* rtlsdr_iq */,
 				8D4068362CFDA69C0064C96D /* airspyhf_iq */,
 				8D4068452CFDA6B80064C96D /* airspy_iq */,
+				8D9A33442D0B0D8D009A4186 /* bladerf_iq */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -1319,6 +1354,26 @@
 			productReference = 8D87709D2CD6B4BB0082EC54 /* libbladerf.a */;
 			productType = "com.apple.product-type.library.static";
 		};
+		8D9A33432D0B0D8D009A4186 /* BladeRFIQ */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 8D9A334A2D0B0D8D009A4186 /* Build configuration list for PBXNativeTarget "BladeRFIQ" */;
+			buildPhases = (
+				8D9A33402D0B0D8D009A4186 /* Sources */,
+				8D9A33412D0B0D8D009A4186 /* Frameworks */,
+				8D9A33422D0B0D8D009A4186 /* CopyFiles */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = BladeRFIQ;
+			packageProductDependencies = (
+				8D9A33512D0B0DE5009A4186 /* ArgumentParser */,
+			);
+			productName = BladeRFIQ;
+			productReference = 8D9A33442D0B0D8D009A4186 /* bladerf_iq */;
+			productType = "com.apple.product-type.tool";
+		};
 		8DD98C402CC592540062D678 /* PrySDR */ = {
 			isa = PBXNativeTarget;
 			buildConfigurationList = 8DD98C482CC592540062D678 /* Build configuration list for PBXNativeTarget "PrySDR" */;
@@ -1378,7 +1433,7 @@
 			isa = PBXProject;
 			attributes = {
 				BuildIndependentTargetsInParallel = 1;
-				LastSwiftUpdateCheck = 1610;
+				LastSwiftUpdateCheck = 1620;
 				LastUpgradeCheck = 1610;
 				TargetAttributes = {
 					8D0349172CF70DCD0026DA77 = {
@@ -1423,6 +1478,9 @@
 					8D87709C2CD6B4BB0082EC54 = {
 						CreatedOnToolsVersion = 16.1;
 					};
+					8D9A33432D0B0D8D009A4186 = {
+						CreatedOnToolsVersion = 16.2;
+					};
 					8DD98C402CC592540062D678 = {
 						CreatedOnToolsVersion = 16.0;
 					};
@@ -1463,6 +1521,7 @@
 				8D0349172CF70DCD0026DA77 /* RtlSdrIQ */,
 				8D4068352CFDA69C0064C96D /* AirSpyHFIQ */,
 				8D4068442CFDA6B80064C96D /* AirSpyIQ */,
+				8D9A33432D0B0D8D009A4186 /* BladeRFIQ */,
 			);
 		};
 /* End PBXProject section */
@@ -1562,6 +1621,13 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		8D9A33402D0B0D8D009A4186 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		8DD98C3D2CC592540062D678 /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
@@ -1997,6 +2063,30 @@
 			};
 			name = Release;
 		};
+		8D9A33482D0B0D8D009A4186 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				DEVELOPMENT_TEAM = 53B26AJZ4Z;
+				ENABLE_HARDENED_RUNTIME = YES;
+				MACOSX_DEPLOYMENT_TARGET = 15.1;
+				PRODUCT_NAME = bladerf_iq;
+				SWIFT_VERSION = 5.0;
+			};
+			name = Debug;
+		};
+		8D9A33492D0B0D8D009A4186 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				DEVELOPMENT_TEAM = 53B26AJZ4Z;
+				ENABLE_HARDENED_RUNTIME = YES;
+				MACOSX_DEPLOYMENT_TARGET = 15.1;
+				PRODUCT_NAME = bladerf_iq;
+				SWIFT_VERSION = 5.0;
+			};
+			name = Release;
+		};
 		8DD98C462CC592540062D678 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
@@ -2287,6 +2377,15 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
+		8D9A334A2D0B0D8D009A4186 /* Build configuration list for PBXNativeTarget "BladeRFIQ" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				8D9A33482D0B0D8D009A4186 /* Debug */,
+				8D9A33492D0B0D8D009A4186 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
 		8DD98C3C2CC592540062D678 /* Build configuration list for PBXProject "PrySDR" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
@@ -2348,6 +2447,11 @@
 			package = 8D0349232CF70E180026DA77 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
 			productName = ArgumentParser;
 		};
+		8D9A33512D0B0DE5009A4186 /* ArgumentParser */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = 8D0349232CF70E180026DA77 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
+			productName = ArgumentParser;
+		};
 /* End XCSwiftPackageProductDependency section */
 	};
 	rootObject = 8DD98C392CC592540062D678 /* Project object */;
diff --git a/Radio/HW/AirSpy/AirSpy.swift b/Radio/HW/AirSpy/AirSpy.swift
index d7916b2..25f5b0b 100644
--- a/Radio/HW/AirSpy/AirSpy.swift
+++ b/Radio/HW/AirSpy/AirSpy.swift
@@ -54,10 +54,30 @@ class AirSpy {
         return airspy_set_samplerate(dev, samplerate)
     }
     
+    func rfBias(_ rfbias: UInt8) -> Int32 {
+        return airspy_set_rf_bias(dev, rfbias)
+    }
+    
+    func VGAGain(_ vgagain: UInt8) -> Int32 {
+        return airspy_set_vga_gain(dev, vgagain)
+    }
+    
+    func mixerGain(_ gain: UInt8) -> Int32 {
+        return airspy_set_mixer_gain(dev, gain)
+    }
+    
+    func lnaGain(_ gain: UInt8) -> Int32 {
+        return airspy_set_lna_gain(dev, gain)
+    }
+    
     func startRx(_ callback: airspy_sample_block_cb_fn) -> Int32 {
         return airspy_start_rx(dev, callback, nil)
     }
     
+    func stopRx() -> Int32 {
+        return airspy_stop_rx(dev)
+    }
+    
     func setFrequency(_ freq: UInt32) -> Int32 {
         return airspy_set_freq(dev, freq)
     }
diff --git a/Radio/Utils/AirSpyIQ/main.swift b/Radio/Utils/AirSpyIQ/main.swift
index 7fea329..a643d5f 100644
--- a/Radio/Utils/AirSpyIQ/main.swift
+++ b/Radio/Utils/AirSpyIQ/main.swift
@@ -12,11 +12,11 @@ import libairspy
 //set the command line arguments
 struct CommandLineArgs: ParsableCommand {
     @Argument var file:String = ""
-    @Option(name:.shortAndLong) var serialno: UInt64 = 0
+    @Option() var serial: UInt64 = 0
     @Option(name:.shortAndLong) var samplerate: Int = 3000000
     @Option(name:.shortAndLong) var gain: Int = 0
     @Option(name:.shortAndLong) var frequency: Int = 100000000
-    @Option(name:.shortAndLong) var nsamples: Int = 1024
+    @Option(name:.shortAndLong) var nsamples: Int = 65536
     @Flag(help:"Version \(software_version)") var version: Bool = false
     @Flag(name: .shortAndLong) var verbose: Bool = false
 }
@@ -43,6 +43,28 @@ if (ret != AIRSPY_SUCCESS.rawValue) {
     exit(1)
 }
 
+//prepare file descriptor if args specify that
+let currentExePath = Process().currentDirectoryPath
+var fileDescriptor = FileManager.default
+var fileArgUrl:URL?
+var fileHandle:FileHandle?
+if (args.file != "") {
+    fileArgUrl = URL(fileURLWithFileSystemRepresentation: args.file, isDirectory: false, relativeTo: nil)
+    if (checkIfFileExists(args.file)) {
+        //remove file
+        do {
+            try fileDescriptor.removeItem(atPath: fileArgUrl!.path())
+        } catch {
+            print("Couldn't delete file that exists \(fileArgUrl!.path())")
+        }
+    }
+    
+    //create file
+    fileDescriptor.createFile(atPath: fileArgUrl!.path(), contents: nil)
+    try fileHandle = FileHandle(forWritingTo: fileArgUrl!)
+    try fileHandle?.seekToEnd()
+}
+
 var device:AirSpy?
 do {
     device = try AirSpy()
@@ -53,14 +75,45 @@ do {
 let sample_rates = device?.getSampleRates()
 
 let _ = device?.setSampleRate(sample_rates![0])
+print("sample rate \(sample_rates![0])")
 
-print("Here 5")
+var sdr_run = true
+var total_samples:Int32=0
 func rf_callback(_ transffer: UnsafeMutablePointer<airspy_transfer_t>?) -> Int32 {
     let t = transffer!.pointee
-    print("Got \(t.sample_count) samples")
+    let rx_bufffer = t.samples
+    let sample_count = t.sample_count
+    //default value
+    
+    if (t.sample_type != AIRSPY_SAMPLE_FLOAT32_IQ) {
+        print("Unsupported sample type to write")
+    }
+    let bytes_to_write = sample_count*2*4 //IQ*float
+    
+    total_samples += sample_count
+    if total_samples > args.nsamples {
+        sdr_run = false
+        return 0
+    }
+    
+    if let file = fileHandle {
+        let convertedData = Data(bytes: rx_bufffer!, count: Int(bytes_to_write))
+        do {
+            try file.write(contentsOf: convertedData)
+        } catch {
+            print("Cant dump data to file")
+        }
+    }
+    
+    print("Got \(sample_count) samples")
+    
     return 0
 }
 
+let _ = device?.VGAGain(5)
+let _ = device?.mixerGain(5)
+let _ = device?.lnaGain(1)
+
 let _ = device?.startRx(rf_callback)
 
 let _ = device?.setFrequency(UInt32(args.frequency))
@@ -68,12 +121,14 @@ let _ = device?.setFrequency(UInt32(args.frequency))
 sleep(1)
 var count = 10
 while ((device?.isStreaming() != AIRSPY_TRUE.rawValue)
-&& (count>0)) {
+&& (count>0) && (sdr_run)) {
     print("Streaming")
     sleep(1)
     count -= 1
 }
 
+let _ = device?.stopRx()
+
 let _ = device?.close()
 
 airspy_exit()
diff --git a/Radio/Utils/BladeRFIQ/main.swift b/Radio/Utils/BladeRFIQ/main.swift
new file mode 100644
index 0000000..a4f2ffe
--- /dev/null
+++ b/Radio/Utils/BladeRFIQ/main.swift
@@ -0,0 +1,14 @@
+//
+//  main.swift
+//  BladeRFIQ
+//
+//  Created by Jacky Jack on 12/12/2024.
+//
+
+import Foundation
+import ArgumentParser
+import libbladerf
+
+print("Hello, World!")
+
+
-- 
cgit v1.2.3