From 1e096e55ca30dc80c3faa8d1ea36de13bc90cc6a Mon Sep 17 00:00:00 2001 From: Arturs Artamonovs Date: Tue, 21 Jan 2025 09:24:13 +0000 Subject: iqconvert: initial implementation non-working --- IQ/IQ.swift | 2 + PrySDR.xcodeproj/project.pbxproj | 109 +++++++++++++++++++++++++++- Radio/Utils/WaterfallFile/NaiveFFT512.swift | 24 +----- Radio/Utils/WaterfallFile/main.swift | 2 + Radio/Utils/iqconvert/main.swift | 91 +++++++++++++++++++++++ Utils/Version.swift | 2 +- 6 files changed, 202 insertions(+), 28 deletions(-) create mode 100644 Radio/Utils/iqconvert/main.swift diff --git a/IQ/IQ.swift b/IQ/IQ.swift index 4725291..b816d77 100644 --- a/IQ/IQ.swift +++ b/IQ/IQ.swift @@ -9,7 +9,9 @@ /// Data type for raw binary digital data that comes from SDR devices. /// In range of 8 to 16bit RTLSDR is the lowest you can get 16bit is what you can max you can get for reasonable money struct IQ { + //how many bits of data var size:UInt8 + //total data size var bits:UInt8 var sign:Bool var complex:Bool diff --git a/PrySDR.xcodeproj/project.pbxproj b/PrySDR.xcodeproj/project.pbxproj index 817e90c..0dd3645 100644 --- a/PrySDR.xcodeproj/project.pbxproj +++ b/PrySDR.xcodeproj/project.pbxproj @@ -71,6 +71,7 @@ 8DBA9FA22D37C5C8008ECB92 /* libr820.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D5A5DB42CD4B70D0096CBD7 /* libr820.a */; }; 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 */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -340,6 +341,15 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + 8DBA9FAC2D3A68B5008ECB92 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; 8DD98C3F2CC592540062D678 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -375,6 +385,7 @@ 8DBA9F6F2D2C9796008ECB92 /* Waterfall_UI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Waterfall_UI.app; sourceTree = BUILT_PRODUCTS_DIR; }; 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; }; 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 */ @@ -615,6 +626,7 @@ Utils/AirSpyHFIQ/main.swift, Utils/AirSpyIQ/main.swift, Utils/BladeRFIQ/main.swift, + Utils/iqconvert/main.swift, Utils/RtlSdrIQ/main.swift, Utils/TestAirSpy/main.swift, Utils/TestAirSpyHF/main.swift, @@ -870,12 +882,22 @@ ); target = 8DBA9F6E2D2C9796008ECB92 /* Waterfall_UI */; }; - 8DD98C7C2CC6320C0062D678 /* Exceptions for "LA" folder in "PrySDR" target */ = { + 8DBA9FBC2D3A693D008ECB92 /* Exceptions for "Radio" folder in "iqconvert" target */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( - Test/MatrixXT/MatrixXT.swift, + Utils/iqconvert/main.swift, ); - target = 8DD98C402CC592540062D678 /* PrySDR */; + target = 8DBA9FAD2D3A68B5008ECB92 /* iqconvert */; + }; + 8DBA9FC02D3A71D2008ECB92 /* Exceptions for "Utils" folder in "iqconvert" target */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + FileReader.swift, + FileUtils.swift, + PathUtils.swift, + Version.swift, + ); + target = 8DBA9FAD2D3A68B5008ECB92 /* iqconvert */; }; 8DD98C7D2CC6320C0062D678 /* Exceptions for "LA" folder in "MatrixXT" target */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; @@ -936,7 +958,6 @@ 8DD98C502CC5935B0062D678 /* LA */ = { isa = PBXFileSystemSynchronizedRootGroup; exceptions = ( - 8DD98C7C2CC6320C0062D678 /* Exceptions for "LA" folder in "PrySDR" target */, 8DD98C7D2CC6320C0062D678 /* Exceptions for "LA" folder in "MatrixXT" target */, ); path = LA; @@ -962,6 +983,7 @@ 8DBA9F602D2928DE008ECB92 /* Exceptions for "Radio" folder in "WaterfallFile_UI" target */, 8D9A38812D196520009A4186 /* Exceptions for "Radio" folder in "WaterfallFile" target */, 8DBA9FA72D37CD92008ECB92 /* Exceptions for "Radio" folder in "Waterfall_UI" target */, + 8DBA9FBC2D3A693D008ECB92 /* Exceptions for "Radio" folder in "iqconvert" target */, ); path = Radio; sourceTree = ""; @@ -1023,6 +1045,7 @@ 8DBA9F652D2B5158008ECB92 /* Exceptions for "Utils" folder in "WaterfallFile_UI" target */, 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 */, ); path = Utils; sourceTree = ""; @@ -1199,6 +1222,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 8DBA9FAB2D3A68B5008ECB92 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DBA9FBE2D3A71A3008ECB92 /* ArgumentParser in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8DD98C3E2CC592540062D678 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1284,6 +1315,7 @@ 8DBA9F6F2D2C9796008ECB92 /* Waterfall_UI.app */, 8DBA9F812D2C979A008ECB92 /* Waterfall_UITests.xctest */, 8DBA9F8B2D2C979A008ECB92 /* Waterfall_UIUITests.xctest */, + 8DBA9FAE2D3A68B5008ECB92 /* iqconvert */, ); name = Products; sourceTree = ""; @@ -1760,6 +1792,26 @@ productReference = 8DBA9F8B2D2C979A008ECB92 /* Waterfall_UIUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; + 8DBA9FAD2D3A68B5008ECB92 /* iqconvert */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8DBA9FB22D3A68B5008ECB92 /* Build configuration list for PBXNativeTarget "iqconvert" */; + buildPhases = ( + 8DBA9FAA2D3A68B5008ECB92 /* Sources */, + 8DBA9FAB2D3A68B5008ECB92 /* Frameworks */, + 8DBA9FAC2D3A68B5008ECB92 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = iqconvert; + packageProductDependencies = ( + 8DBA9FBD2D3A71A3008ECB92 /* ArgumentParser */, + ); + productName = iqconvert; + productReference = 8DBA9FAE2D3A68B5008ECB92 /* iqconvert */; + productType = "com.apple.product-type.tool"; + }; 8DD98C402CC592540062D678 /* PrySDR */ = { isa = PBXNativeTarget; buildConfigurationList = 8DD98C482CC592540062D678 /* Build configuration list for PBXNativeTarget "PrySDR" */; @@ -1892,6 +1944,9 @@ CreatedOnToolsVersion = 16.2; TestTargetID = 8DBA9F6E2D2C9796008ECB92; }; + 8DBA9FAD2D3A68B5008ECB92 = { + CreatedOnToolsVersion = 16.2; + }; 8DD98C402CC592540062D678 = { CreatedOnToolsVersion = 16.0; }; @@ -1940,6 +1995,7 @@ 8DBA9F6E2D2C9796008ECB92 /* Waterfall_UI */, 8DBA9F802D2C979A008ECB92 /* Waterfall_UITests */, 8DBA9F8A2D2C979A008ECB92 /* Waterfall_UIUITests */, + 8DBA9FAD2D3A68B5008ECB92 /* iqconvert */, ); }; /* End PBXProject section */ @@ -2137,6 +2193,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 8DBA9FAA2D3A68B5008ECB92 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8DD98C3D2CC592540062D678 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -2930,6 +2993,30 @@ }; name = Release; }; + 8DBA9FB32D3A68B5008ECB92 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 53B26AJZ4Z; + ENABLE_HARDENED_RUNTIME = YES; + MACOSX_DEPLOYMENT_TARGET = 15.2; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 8DBA9FB42D3A68B5008ECB92 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 53B26AJZ4Z; + ENABLE_HARDENED_RUNTIME = YES; + MACOSX_DEPLOYMENT_TARGET = 15.2; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; 8DD98C462CC592540062D678 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3298,6 +3385,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 8DBA9FB22D3A68B5008ECB92 /* Build configuration list for PBXNativeTarget "iqconvert" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8DBA9FB32D3A68B5008ECB92 /* Debug */, + 8DBA9FB42D3A68B5008ECB92 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 8DD98C3C2CC592540062D678 /* Build configuration list for PBXProject "PrySDR" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -3374,6 +3470,11 @@ package = 8D0349232CF70E180026DA77 /* XCRemoteSwiftPackageReference "swift-argument-parser" */; productName = ArgumentParser; }; + 8DBA9FBD2D3A71A3008ECB92 /* ArgumentParser */ = { + isa = XCSwiftPackageProductDependency; + package = 8D0349232CF70E180026DA77 /* XCRemoteSwiftPackageReference "swift-argument-parser" */; + productName = ArgumentParser; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 8DD98C392CC592540062D678 /* Project object */; diff --git a/Radio/Utils/WaterfallFile/NaiveFFT512.swift b/Radio/Utils/WaterfallFile/NaiveFFT512.swift index 0e6373a..510d784 100644 --- a/Radio/Utils/WaterfallFile/NaiveFFT512.swift +++ b/Radio/Utils/WaterfallFile/NaiveFFT512.swift @@ -46,28 +46,6 @@ class NaiveFFT512 { return transform_result } - func computeLine1024(_ processingArray: [Int8]) -> [Float] { - - var dataFloat = [Float](repeating: 0.0, count: NaiveFFT512.sampleCount*2) - - if processingArray.count != NaiveFFT512.sampleCount*2 { - print("Not supporting arrays not equail to \(NaiveFFT512.sampleCount)") - return [] - } - - vDSP.convertElements(of: processingArray, to: &dataFloat) - //dataFloat = vDSP.add(127.0, dataFloat) - //print(dataFloat) - - //move from -127.0 to 128.0 range -1.0...1.0 - //var adjusted = vDSP.divide(dataFloat, Float(sampleCount)) - var adjusted = dataFloat - //print(adjusted) - - var transform_result = forwardDCT.transform(adjusted) - transform_result = vDSP.absolute(transform_result) - - return transform_result - } + } diff --git a/Radio/Utils/WaterfallFile/main.swift b/Radio/Utils/WaterfallFile/main.swift index 039be72..7717f1c 100644 --- a/Radio/Utils/WaterfallFile/main.swift +++ b/Radio/Utils/WaterfallFile/main.swift @@ -11,7 +11,9 @@ import ArgumentParser //set the command line arguments struct CommandLineArgs: ParsableCommand { + //input file format detected from file extension @Argument var inputFile:String = "" + //output file format detected from file extension @Argument var outputFile:String = "" } diff --git a/Radio/Utils/iqconvert/main.swift b/Radio/Utils/iqconvert/main.swift new file mode 100644 index 0000000..f619529 --- /dev/null +++ b/Radio/Utils/iqconvert/main.swift @@ -0,0 +1,91 @@ +// +// main.swift +// iqconvert +// +// Created by Jacky Jack on 17/01/2025. +// + +import Foundation +import ArgumentParser + +enum SDRInputFormat { + case FMT_NONE + case FMT_U8 + case FMT_F32 +} + +//set the command line arguments +struct CommandLineArgs: ParsableCommand { + @Argument var inputFile:String = "" + @Argument var outputFile:String = "" + @Flag(help:"Version \(software_version)") var version: Bool = false + @Flag(name: .shortAndLong) var verbose: Bool = false + @Flag(name: .shortAndLong) var listFormats: Bool = false +} + +let args = CommandLineArgs.parseOrExit() + +if args.listFormats { + print("Supported input:") + print(" u8: RTLSDR [not supported]") + print(" u16: AirSpyHF [not supported]") + print(" u16r: AirSpy [not supported]") + print(" i16: AirSpy [not supported]") + print(" i16r: AirSpy [not supported]") //int16 real 1 * 16bit per sample + 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(" wav: SDR# [not suppoprted]") +} + +//var inputFilePath:String +//check if input file exists as parameter is given +if !checkIfFileExists(args.inputFile) { + print("Error: Input file \(args.inputFile) does not exist") + exit(1) +} + +let fileReader = FileReader() +do { + try fileReader.open(filename: args.inputFile) +} catch { + print("ERROR: \(error) - Cant open file \(args.inputFile)") + exit(1) +} + +var inputFormat = SDRInputFormat.FMT_NONE +//file is open lets detect extension +if let dotIndex = args.inputFile.lastIndex(of: ".") { + let index = args.inputFile.index(dotIndex, offsetBy: 1) + let fileExtension = String(args.inputFile[index..