summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--IQ/IQUtils.swift88
-rw-r--r--LA/Test/MatrixXT/MatrixXT.swift12
-rw-r--r--PrySDR.xcodeproj/project.pbxproj151
-rw-r--r--PrySDR/main.swift14
-rw-r--r--PrySDR_Tests/PrySDR_Tests.swift79
-rw-r--r--Radio/Utils/iqconvert/main.swift50
-rw-r--r--Utils/Double+truncate.swift26
-rw-r--r--Utils/FileReader.swift2
-rw-r--r--Utils/FileWriter.swift91
-rw-r--r--Utils/Version.swift2
10 files changed, 505 insertions, 10 deletions
diff --git a/IQ/IQUtils.swift b/IQ/IQUtils.swift
new file mode 100644
index 0000000..9d1b048
--- /dev/null
+++ b/IQ/IQUtils.swift
@@ -0,0 +1,88 @@
+//
+// IQUtils.swift
+// PrySDR
+//
+// Created by Jacky Jack on 21/01/2025.
+//
+
+import Accelerate
+
+/// Convert from UInt8 to Float, naive implementation
+/// - Parameters:
+/// - arr: array of UInt8
+/// - Returns: Return floats -0.996...0.996
+///
+func cnvU8toFloat32(_ arr: [UInt8]) -> [Float32] {
+
+ //let iq = IQ(size: 8, bits: 8, sign: false, complex: true)
+
+ var out: [Float32] = .init(repeating: 0.0, count: arr.count)
+
+ // 0..255 -> -0.996 ... 0.996
+ // 0..127 -> -0.996 ... 0.0039
+ // 128...255 -> 0.0039 ... 0.996
+ for i in 0..<arr.count {
+ /*
+ if arr[i] >= 128 {
+ out[i] = Float(arr[i]-128)/128.0
+ } else { //
+ out[i] = Float(Int(arr[i])-128)/128.0
+ }*/
+ out[i] = (Float(arr[i])-127.5)/128.0
+ }
+
+ return out
+}
+
+/// Convert from UInt8 to Float, naive implementation rtlsdr specfic
+/// https://cgit.osmocom.org/gr-osmosdr/tree/lib/rtl/rtl_source_c.cc#n179
+/// - Parameters:
+/// - arr: array of UInt8
+/// - Returns: Return floats -0.996...0.996
+///
+func cnvU8toFloat32_rtlsdr(_ arr: [UInt8]) -> [Float32] {
+
+ //let iq = IQ(size: 8, bits: 8, sign: false, complex: true)
+
+ var out: [Float32] = .init(repeating: 0.0, count: arr.count)
+
+ // 0..255 -> -1.0 ... 1.0
+ for i in 0..<arr.count {
+ /*
+ if arr[i] >= 128 {
+ out[i] = Float(arr[i]-128)/128.0
+ } else { //
+ out[i] = Float(Int(arr[i])-128)/128.0
+ }*/
+ out[i] = (Float(arr[i])-127.4)/128.0
+ }
+
+ return out
+}
+
+
+/// Convert from UInt8 to Float, using Accel framework
+/// - Parameters:
+/// - arr: array of UInt8
+/// - Returns: Return floats -1.0...1.0
+///
+func cnvU8toFloat32_accel(_ arr: [UInt8]) -> [Float32] {
+ var out: [Float32] = .init(repeating: 0.0, count: arr.count)
+ vDSP.convertElements(of: arr, to: &out)
+ out = vDSP.add(-127.5, out)
+ out = vDSP.divide(out, 128)
+ return out
+}
+
+/// Convert from UInt8 to Float, using Accel framework specific to rtlsdr
+/// - Parameters:
+/// - arr: array of UInt8
+/// - Returns: Return floats -1.0...1.0
+///
+func cnvU8toFloat32_accel_rtlsdr(_ arr: [UInt8]) -> [Float32] {
+ var out: [Float32] = .init(repeating: 0.0, count: arr.count)
+ vDSP.convertElements(of: arr, to: &out)
+ out = vDSP.add(-127.4, out)
+ out = vDSP.divide(out, 128)
+ return out
+}
diff --git a/LA/Test/MatrixXT/MatrixXT.swift b/LA/Test/MatrixXT/MatrixXT.swift
index 55661be..a44887a 100644
--- a/LA/Test/MatrixXT/MatrixXT.swift
+++ b/LA/Test/MatrixXT/MatrixXT.swift
@@ -15,35 +15,35 @@ struct MatrixXT {
@Test func matrix_create_with_init() async throws {
do {
- let _ = try Matrix(row:-1,column: -1,val:0.0)
+ let _ = try Matrix(rows:-1,columns: -1,val:0.0)
Issue.record("Should fail")
} catch {
//should allway get here,
}
do {
- let _ = try Matrix(row: 0, column: 0, val: 0.0)
+ let _ = try Matrix(rows: 0, columns: 0, val: 0.0)
Issue.record("Should fail")
} catch {
//should allways get here
}
do {
- let _ = try Matrix(row: 1, column: 1, val: 0.0)
+ let _ = try Matrix(rows: 1, columns: 1, val: 0.0)
} catch {
Issue.record("Failed")
}
do {
- let _ = try Matrix(row: 2, column: 2, val: 0.0)
+ let _ = try Matrix(rows: 2, columns: 2, val: 0.0)
} catch {
Issue.record("Failed")
}
do {
- let _ = try Matrix(row: 3, column: 3, val: 0.0)
+ let _ = try Matrix(rows: 3, columns: 3, val: 0.0)
} catch {
Issue.record("Failed")
}
do {
- let _ = try Matrix(row:16, column: 16, val: 0.0)
+ let _ = try Matrix(rows:16, columns: 16, val: 0.0)
} catch {
Issue.record("Failed")
}
diff --git a/PrySDR.xcodeproj/project.pbxproj b/PrySDR.xcodeproj/project.pbxproj
index 0dd3645..ad6651e 100644
--- a/PrySDR.xcodeproj/project.pbxproj
+++ b/PrySDR.xcodeproj/project.pbxproj
@@ -72,6 +72,8 @@
8DBA9FA32D37C5CD008ECB92 /* libusb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D5A5DDA2CD4B9100096CBD7 /* libusb.a */; };
8DBA9FA52D37C5D1008ECB92 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 8DBA9FA42D37C5D1008ECB92 /* ArgumentParser */; };
8DBA9FBE2D3A71A3008ECB92 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 8DBA9FBD2D3A71A3008ECB92 /* ArgumentParser */; };
+ 8DBA9FC82D3FA346008ECB92 /* libusb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D5A5DDA2CD4B9100096CBD7 /* libusb.a */; };
+ 8DBA9FEC2D425776008ECB92 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 8DBA9FEB2D425776008ECB92 /* Numerics */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -386,6 +388,7 @@
8DBA9F812D2C979A008ECB92 /* Waterfall_UITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Waterfall_UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
8DBA9F8B2D2C979A008ECB92 /* Waterfall_UIUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Waterfall_UIUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
8DBA9FAE2D3A68B5008ECB92 /* iqconvert */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = iqconvert; sourceTree = BUILT_PRODUCTS_DIR; };
+ 8DBA9FD42D3FB893008ECB92 /* PrySDR_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PrySDR_Tests.xctest; 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 */
@@ -474,6 +477,7 @@
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
IQ.swift,
+ IQUtils.swift,
);
target = 8DD98C402CC592540062D678 /* PrySDR */;
};
@@ -615,7 +619,6 @@
HW/RtlSdr/libusb/os/threads_posix.c,
HW/RtlSdr/libusb/strerror.c,
HW/RtlSdr/libusb/sync.c,
- HW/RtlSdr/r820/r820.swift,
HW/RtlSdr/r820/src/librtlsdr.c,
HW/RtlSdr/r820/src/test.swift,
HW/RtlSdr/r820/src/tuner_e4k.c,
@@ -892,13 +895,43 @@
8DBA9FC02D3A71D2008ECB92 /* Exceptions for "Utils" folder in "iqconvert" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
+ "Double+truncate.swift",
FileReader.swift,
FileUtils.swift,
+ FileWriter.swift,
PathUtils.swift,
Version.swift,
);
target = 8DBA9FAD2D3A68B5008ECB92 /* iqconvert */;
};
+ 8DBA9FCA2D3FA381008ECB92 /* Exceptions for "LA" folder in "PrySDR" target */ = {
+ isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
+ membershipExceptions = (
+ Test/MatrixXT/MatrixXT.swift,
+ );
+ target = 8DD98C402CC592540062D678 /* PrySDR */;
+ };
+ 8DBA9FCF2D3FB1F4008ECB92 /* Exceptions for "IQ" folder in "iqconvert" target */ = {
+ isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
+ membershipExceptions = (
+ IQUtils.swift,
+ );
+ target = 8DBA9FAD2D3A68B5008ECB92 /* iqconvert */;
+ };
+ 8DBA9FDC2D3FBA2A008ECB92 /* Exceptions for "IQ" folder in "PrySDR_Tests" target */ = {
+ isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
+ membershipExceptions = (
+ IQUtils.swift,
+ );
+ target = 8DBA9FD32D3FB893008ECB92 /* PrySDR_Tests */;
+ };
+ 8DBA9FE12D425164008ECB92 /* Exceptions for "Utils" folder in "PrySDR_Tests" target */ = {
+ isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
+ membershipExceptions = (
+ "Double+truncate.swift",
+ );
+ target = 8DBA9FD32D3FB893008ECB92 /* PrySDR_Tests */;
+ };
8DD98C7D2CC6320C0062D678 /* Exceptions for "LA" folder in "MatrixXT" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
@@ -950,6 +983,11 @@
path = Waterfall_UIUITests;
sourceTree = "<group>";
};
+ 8DBA9FD52D3FB893008ECB92 /* PrySDR_Tests */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ path = PrySDR_Tests;
+ sourceTree = "<group>";
+ };
8DD98C432CC592540062D678 /* PrySDR */ = {
isa = PBXFileSystemSynchronizedRootGroup;
path = PrySDR;
@@ -958,6 +996,7 @@
8DD98C502CC5935B0062D678 /* LA */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
+ 8DBA9FCA2D3FA381008ECB92 /* Exceptions for "LA" folder in "PrySDR" target */,
8DD98C7D2CC6320C0062D678 /* Exceptions for "LA" folder in "MatrixXT" target */,
);
path = LA;
@@ -992,6 +1031,8 @@
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
8D5A5CFA2CCD95E90096CBD7 /* Exceptions for "IQ" folder in "PrySDR" target */,
+ 8DBA9FCF2D3FB1F4008ECB92 /* Exceptions for "IQ" folder in "iqconvert" target */,
+ 8DBA9FDC2D3FBA2A008ECB92 /* Exceptions for "IQ" folder in "PrySDR_Tests" target */,
);
path = IQ;
sourceTree = "<group>";
@@ -1046,6 +1087,7 @@
8D9A38832D19D277009A4186 /* Exceptions for "Utils" folder in "WaterfallFile" target */,
8DBA9F9E2D313168008ECB92 /* Exceptions for "Utils" folder in "Waterfall_UI" target */,
8DBA9FC02D3A71D2008ECB92 /* Exceptions for "Utils" folder in "iqconvert" target */,
+ 8DBA9FE12D425164008ECB92 /* Exceptions for "Utils" folder in "PrySDR_Tests" target */,
);
path = Utils;
sourceTree = "<group>";
@@ -1230,10 +1272,19 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 8DBA9FD12D3FB893008ECB92 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8DBA9FEC2D425776008ECB92 /* Numerics in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
8DD98C3E2CC592540062D678 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 8DBA9FC82D3FA346008ECB92 /* libusb.a in Frameworks */,
8D87714A2CD7A6A40082EC54 /* libr820.a in Frameworks */,
8D8771492CD7A69B0082EC54 /* libbladerf.a in Frameworks */,
8D5A5DAE2CD439DA0096CBD7 /* libairspyhf.a in Frameworks */,
@@ -1283,6 +1334,7 @@
8DBA9F702D2C9796008ECB92 /* Waterfall_UI */,
8DBA9F842D2C979A008ECB92 /* Waterfall_UITests */,
8DBA9F8E2D2C979A008ECB92 /* Waterfall_UIUITests */,
+ 8DBA9FD52D3FB893008ECB92 /* PrySDR_Tests */,
8DD98C422CC592540062D678 /* Products */,
8DD98C642CC599CA0062D678 /* Series */,
8DD98C7F2CC7852E0062D678 /* Images */,
@@ -1316,6 +1368,7 @@
8DBA9F812D2C979A008ECB92 /* Waterfall_UITests.xctest */,
8DBA9F8B2D2C979A008ECB92 /* Waterfall_UIUITests.xctest */,
8DBA9FAE2D3A68B5008ECB92 /* iqconvert */,
+ 8DBA9FD42D3FB893008ECB92 /* PrySDR_Tests.xctest */,
);
name = Products;
sourceTree = "<group>";
@@ -1812,6 +1865,29 @@
productReference = 8DBA9FAE2D3A68B5008ECB92 /* iqconvert */;
productType = "com.apple.product-type.tool";
};
+ 8DBA9FD32D3FB893008ECB92 /* PrySDR_Tests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 8DBA9FD82D3FB893008ECB92 /* Build configuration list for PBXNativeTarget "PrySDR_Tests" */;
+ buildPhases = (
+ 8DBA9FD02D3FB893008ECB92 /* Sources */,
+ 8DBA9FD12D3FB893008ECB92 /* Frameworks */,
+ 8DBA9FD22D3FB893008ECB92 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ fileSystemSynchronizedGroups = (
+ 8DBA9FD52D3FB893008ECB92 /* PrySDR_Tests */,
+ );
+ name = PrySDR_Tests;
+ packageProductDependencies = (
+ 8DBA9FEB2D425776008ECB92 /* Numerics */,
+ );
+ productName = PrySDR_Tests;
+ productReference = 8DBA9FD42D3FB893008ECB92 /* PrySDR_Tests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
8DD98C402CC592540062D678 /* PrySDR */ = {
isa = PBXNativeTarget;
buildConfigurationList = 8DD98C482CC592540062D678 /* Build configuration list for PBXNativeTarget "PrySDR" */;
@@ -1947,6 +2023,9 @@
8DBA9FAD2D3A68B5008ECB92 = {
CreatedOnToolsVersion = 16.2;
};
+ 8DBA9FD32D3FB893008ECB92 = {
+ CreatedOnToolsVersion = 16.2;
+ };
8DD98C402CC592540062D678 = {
CreatedOnToolsVersion = 16.0;
};
@@ -1966,6 +2045,7 @@
minimizedProjectReferenceProxies = 1;
packageReferences = (
8D0349232CF70E180026DA77 /* XCRemoteSwiftPackageReference "swift-argument-parser" */,
+ 8DBA9FE22D425453008ECB92 /* XCRemoteSwiftPackageReference "swift-numerics" */,
);
preferredProjectObjectVersion = 77;
productRefGroup = 8DD98C422CC592540062D678 /* Products */;
@@ -1996,6 +2076,7 @@
8DBA9F802D2C979A008ECB92 /* Waterfall_UITests */,
8DBA9F8A2D2C979A008ECB92 /* Waterfall_UIUITests */,
8DBA9FAD2D3A68B5008ECB92 /* iqconvert */,
+ 8DBA9FD32D3FB893008ECB92 /* PrySDR_Tests */,
);
};
/* End PBXProject section */
@@ -2043,6 +2124,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 8DBA9FD22D3FB893008ECB92 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
8DD98C702CC632040062D678 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -2200,6 +2288,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 8DBA9FD02D3FB893008ECB92 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
8DD98C3D2CC592540062D678 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -3017,6 +3112,38 @@
};
name = Release;
};
+ 8DBA9FD92D3FB893008ECB92 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 53B26AJZ4Z;
+ GENERATE_INFOPLIST_FILE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 15.2;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "RadioTeam.PrySDR-Tests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ SWIFT_VERSION = 5.0;
+ };
+ name = Debug;
+ };
+ 8DBA9FDA2D3FB893008ECB92 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 53B26AJZ4Z;
+ GENERATE_INFOPLIST_FILE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 15.2;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "RadioTeam.PrySDR-Tests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ SWIFT_VERSION = 5.0;
+ };
+ name = Release;
+ };
8DD98C462CC592540062D678 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -3394,6 +3521,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ 8DBA9FD82D3FB893008ECB92 /* Build configuration list for PBXNativeTarget "PrySDR_Tests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 8DBA9FD92D3FB893008ECB92 /* Debug */,
+ 8DBA9FDA2D3FB893008ECB92 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
8DD98C3C2CC592540062D678 /* Build configuration list for PBXProject "PrySDR" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -3432,6 +3568,14 @@
minimumVersion = 1.5.0;
};
};
+ 8DBA9FE22D425453008ECB92 /* XCRemoteSwiftPackageReference "swift-numerics" */ = {
+ isa = XCRemoteSwiftPackageReference;
+ repositoryURL = "https://github.com/apple/swift-numerics.git";
+ requirement = {
+ kind = upToNextMajorVersion;
+ minimumVersion = 1.0.2;
+ };
+ };
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
@@ -3475,6 +3619,11 @@
package = 8D0349232CF70E180026DA77 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
productName = ArgumentParser;
};
+ 8DBA9FEB2D425776008ECB92 /* Numerics */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 8DBA9FE22D425453008ECB92 /* XCRemoteSwiftPackageReference "swift-numerics" */;
+ productName = Numerics;
+ };
/* End XCSwiftPackageProductDependency section */
};
rootObject = 8DD98C392CC592540062D678 /* Project object */;
diff --git a/PrySDR/main.swift b/PrySDR/main.swift
index 74f3f67..c3b70d6 100644
--- a/PrySDR/main.swift
+++ b/PrySDR/main.swift
@@ -15,3 +15,17 @@ import libbladerf
print("PrySDR")
print("We will start soon on exploring things \(software_version)")
+print("Detect RtlSdr")
+let countRtlSdr = getDeviceCount()
+print("Found \(countRtlSdr) r820 devices")
+
+print("Detect AirSpy")
+
+print("Detect AirSpyHF")
+let countAirSpyHF = airspyhf_list_devices(nil, 0)
+print("Found \(countAirSpyHF) AirSpyHF devices")
+if countAirSpyHF < 0 {
+ exit(0)
+}
+
+print("Detect BladeRF")
diff --git a/PrySDR_Tests/PrySDR_Tests.swift b/PrySDR_Tests/PrySDR_Tests.swift
new file mode 100644
index 0000000..70b9828
--- /dev/null
+++ b/PrySDR_Tests/PrySDR_Tests.swift
@@ -0,0 +1,79 @@
+//
+// PrySDR_Tests.swift
+// PrySDR_Tests
+//
+// Created by Jacky Jack on 21/01/2025.
+//
+
+import Testing
+import Numerics
+
+struct IQConverter_Tests {
+
+ @Test func convertU8arrayToFloat32_accel_size1() async throws {
+ // Write your test here and use APIs like `#expect(...)` to check expected conditions.
+ let arr1:[UInt8] = [0]
+ let res1 = cnvU8toFloat32_accel(arr1)
+ #expect(res1[0].truncate(places: 3) == -0.997)
+ //#expect(res1[0].isApproximatelyEqual(to: -0.997, absoluteTolerance: 0.001))
+
+
+ let arr2:[UInt8] = [255]
+ let res2 = cnvU8toFloat32_accel(arr2)
+ #expect(res2[0].truncate(places: 3) == 0.996)
+
+ let arr3:[UInt8] = [127]
+ let res3 = cnvU8toFloat32_accel(arr3)
+ #expect(res3[0].truncate(places: 3) == -0.004)
+
+ let arr4:[UInt8] = [128]
+ let res4 = cnvU8toFloat32_accel(arr4)
+ #expect(res4[0].truncate(places: 3) == 0.003)
+ }
+ /*
+ @Test func cnvU8arrayToFloat32_size16() async throws {
+ // Write your test here and use APIs like `#expect(...)` to check expected conditions.
+ #expect(false)
+ }
+ */
+ /*
+ @Test func cnvU8arrayToFloat32_size1024() async throws {
+ // Write your test here and use APIs like `#expect(...)` to check expected conditions.
+ #expect(false)
+ }
+ */
+
+ @Test func cnvU8arrayToFloat32_naive_size1() async throws {
+ // Write your test here and use APIs like `#expect(...)` to check expected conditions.
+ let arr1:[UInt8] = [0]
+ let res1 = cnvU8toFloat32(arr1)
+ //minus truncates to "up"
+ #expect(res1[0].truncate(places: 3) == -0.997)
+
+ let arr2:[UInt8] = [255]
+ let res2 = cnvU8toFloat32(arr2)
+ #expect(res2[0].truncate(places: 3) == 0.996)
+
+ let arr3:[UInt8] = [127]
+ let res3 = cnvU8toFloat32(arr3)
+ //minus truncates to "up"
+ #expect(res3[0].truncate(places: 3) == -0.004)
+
+ let arr4:[UInt8] = [128]
+ let res4 = cnvU8toFloat32(arr4)
+ #expect(res4[0].truncate(places: 3) == 0.003)
+ }
+ /*
+ @Test func cnvU8arrayToFloat32_naive_size16() async throws {
+ // Write your test here and use APIs like `#expect(...)` to check expected conditions.
+ #expect(false)
+ }
+ */
+
+ /*
+ @Test func cnvU8arrayToFloat32_naive_size1024() async throws {
+ // Write your test here and use APIs like `#expect(...)` to check expected conditions.
+ #expect(false)
+ }
+ */
+}
diff --git a/Radio/Utils/iqconvert/main.swift b/Radio/Utils/iqconvert/main.swift
index f619529..49db280 100644
--- a/Radio/Utils/iqconvert/main.swift
+++ b/Radio/Utils/iqconvert/main.swift
@@ -35,7 +35,7 @@ if args.listFormats {
print(" sc16q11: BladeRF [not supported]")
print(" fc32r: AirSpy [not supported]") //float32 real 1 * 32bit per sampl
print("Supported output:")
- print(" fc32: inspectrum, sdr++ [not supported]")
+ print(" fc32: inspectrum, sdr++ ")
print(" wav: SDR# [not suppoprted]")
}
@@ -84,8 +84,54 @@ if let dotIndex = args.outputFile.lastIndex(of: ".") {
print("Input file format:\(inputFormat) output file format:\(outputFormat)")
+//read from file
+//if let data_u8:[UInt8] = fileReader.readAll() {
+var data_u8:[UInt8] = []
+do {
+ data_u8 = try fileReader.readAll()
+} catch {
+ print("Reading file: \(error)")
+ exit(1)
+}
-fileReader.close()
+//convert to output format
+var outdata_f32:[Float32] = []
+if data_u8.count > 0 {
+ outdata_f32 = cnvU8toFloat32(data_u8)
+} else {
+ print("No data in buffer")
+}
+// write to file
+let fileWrite = FileWriter()
+var file_ok = false
+if (checkIfFileExists(args.outputFile)) {
+ do {
+ print("try to delet file for write")
+ try fileWrite.deleteForWrite(filename: args.outputFile)
+ } catch {
+ print("cant delete file \(error)")
+ exit(1)
+ }
+} else {
+ do {
+ print("try to creating file")
+ try fileWrite.createForWrite(filename: args.outputFile)
+ } catch {
+ print("cant create file \(error)")
+ exit(1)
+ }
+}
+
+do {
+ try fileWrite.writeAll(outdata_f32)
+} catch {
+ print("Cant write to file \(error)")
+ exit(1)
+}
+
+
+fileReader.close()
+fileWrite.close()
diff --git a/Utils/Double+truncate.swift b/Utils/Double+truncate.swift
new file mode 100644
index 0000000..b86d51d
--- /dev/null
+++ b/Utils/Double+truncate.swift
@@ -0,0 +1,26 @@
+//
+// Double+truncate.swift
+// PrySDR
+//
+// Created by Jacky Jack on 23/01/2025.
+//
+
+import Foundation
+
+extension Double {
+ func truncate(places : Int)-> Double {
+ return Double(floor(Foundation.pow(10.0, Double(places)) * self)/Foundation.pow(10.0, Double(places)))
+ }
+}
+
+extension Float32 {
+ func truncate(places : Int)-> Float32 {
+ return Float32(floor(Foundation.pow(10.0, Float32(places)) * self)/Foundation.pow(10.0, Float32(places)))
+ }
+}
+
+extension Float32 {
+ var bytes: [UInt8] {
+ withUnsafeBytes(of: self, Array.init)
+ }
+}
diff --git a/Utils/FileReader.swift b/Utils/FileReader.swift
index d4be92d..1f9c561 100644
--- a/Utils/FileReader.swift
+++ b/Utils/FileReader.swift
@@ -143,6 +143,8 @@ class FileReader {
}
}
+
+
func close() {
fileHandle?.closeFile()
}
diff --git a/Utils/FileWriter.swift b/Utils/FileWriter.swift
new file mode 100644
index 0000000..6330342
--- /dev/null
+++ b/Utils/FileWriter.swift
@@ -0,0 +1,91 @@
+//
+// FileWriter.swift
+// PrySDR
+//
+// Created by Jacky Jack on 21/01/2025.
+//
+
+import Foundation
+
+enum FileWriterError: Error {
+ case noFile
+ case writeError
+ case createError
+}
+
+class FileWriter {
+ var filepath: String?
+ let filemgr = FileManager.default
+ var fileHandle: FileHandle?
+
+ init() {
+
+ }
+
+ func openForRead(filename: String) throws {
+ let dir = getCurrentExecutableDir()
+ self.filepath = dir+"/"+filename
+ print(dir+"/"+filename)
+ if !filemgr.fileExists(atPath: filename) {
+ print("Cant find file \(filename)")
+ throw FileReaderError.noFile
+ }
+
+ fileHandle = FileHandle(forReadingAtPath: dir+"/"+filename)
+ if (fileHandle == nil) {
+ print("FileHandler failed")
+ }
+ }
+
+ func createForWrite(filename: String) throws {
+ let dir = getCurrentExecutableDir()
+
+ self.filepath = dir+"/"+filename
+
+ if !filemgr.fileExists(atPath: filename) {
+ filemgr.createFile(atPath: dir+"/"+filename, contents: nil)
+ }
+ fileHandle = FileHandle(forUpdatingAtPath: dir+"/"+filename)
+ if (fileHandle == nil) {
+ print("FileHandler failed")
+ throw FileWriterError.createError
+ }
+ }
+
+ func deleteForWrite(filename: String) throws {
+ let dir = getCurrentExecutableDir()
+
+ self.filepath = dir+"/"+filename
+
+ if filemgr.fileExists(atPath: filename) {
+ do {
+ try filemgr.removeItem(atPath: filename)
+ filemgr.createFile(atPath: dir+"/"+filename, contents: nil)
+ } catch {
+ print("couldnt delete file to write: \(error)")
+ }
+ }
+ fileHandle = FileHandle(forWritingAtPath: dir+"/"+filename)
+ if (fileHandle == nil) {
+ print("FileHandler failed")
+ throw FileWriterError.createError
+ }
+ }
+
+ func writeAll(_ arr: [Float32]) throws {
+ //convert float to data
+ let databuf = arr.withUnsafeBytes { Data($0) }
+ do {
+ print("try to write \(databuf.count) bytes")
+ try fileHandle?.write(contentsOf: databuf)
+ } catch {
+ print("Cant write to file \(self.filepath) : \(error)")
+ throw FileWriterError.writeError
+ }
+ }
+
+ func close() {
+ fileHandle?.closeFile()
+ }
+
+}
diff --git a/Utils/Version.swift b/Utils/Version.swift
index e9283d3..accda99 100644
--- a/Utils/Version.swift
+++ b/Utils/Version.swift
@@ -5,4 +5,4 @@
// Created by Jacky Jack on 02/12/2024.
//
-public let software_version = "2025.1-1"
+public let software_version = "2025.2-1"