diff --git a/.github/scripts/desktop.rs b/.github/scripts/desktop.sh similarity index 100% rename from .github/scripts/desktop.rs rename to .github/scripts/desktop.sh diff --git a/.github/scripts/jni.rs b/.github/scripts/jni.sh similarity index 59% rename from .github/scripts/jni.rs rename to .github/scripts/jni.sh index edfd4755..e7afcedd 100755 --- a/.github/scripts/jni.rs +++ b/.github/scripts/jni.sh @@ -3,7 +3,5 @@ cd FoxhunterJNI/foxhunterjni-rs cargo ndk -t armeabi-v7a -t arm64-v8a build -# Ensure check on the native platform works (check for breakage between cargo ndk and rust-analyzer) -cargo check cargo fmt -- --check cargo ndk -t armeabi-v7a -t arm64-v8a clippy diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 884b39a6..8018df97 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,7 +1,7 @@ name: rust on: [push] jobs: - build_jni: + android: runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -9,9 +9,9 @@ jobs: - uses: cachix/install-nix-action@v27 with: nix_path: nixpkgs=channel:nixos-unstable - - run: "nix develop .#jni_ci --command bash ./.github/scripts/jni.rs" + - run: "nix develop .#android --command bash ./.github/scripts/jni.sh" - test_rust: + desktop: runs-on: ubuntu-latest timeout-minutes: 5 steps: @@ -19,5 +19,5 @@ jobs: - uses: cachix/install-nix-action@v27 with: nix_path: nixpkgs=channel:nixos-unstable - - run: "nix develop .#ci --command bash ./.github/scripts/desktop.rs" + - run: "nix develop .#desktop --command bash ./.github/scripts/desktop.sh" diff --git a/.gitignore b/.gitignore index e24521c3..dddbfcee 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,9 @@ local.properties **/.androidsdk /data + +peda-session-*.txt +.gdb_history + +# Allow putting firmware files in working dir for easy bladerf-cli debugging with autoloading of FPGA image +hostedx*.rbf diff --git a/Cargo.lock b/Cargo.lock index 45793ce8..898d1e1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,13 +19,14 @@ checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" -version = "0.7.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ - "getrandom", + "cfg-if", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -37,6 +38,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" + [[package]] name = "alsa" version = "0.9.1" @@ -71,18 +78,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937" -[[package]] -name = "android_logger" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c494134f746c14dc653a35a4ea5aca24ac368529da5370ecf41fe0341c35772f" -dependencies = [ - "android_log-sys", - "env_logger", - "log", - "once_cell", -] - [[package]] name = "android_logger" version = "0.14.1" @@ -105,9 +100,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" + +[[package]] +name = "arraydeque" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" [[package]] name = "arrayvec" @@ -146,32 +147,20 @@ checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.1.1", - "futures-lite 2.3.0", + "fastrand", + "futures-lite", "slab", ] -[[package]] -name = "async-fs" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "blocking", - "futures-lite 1.13.0", -] - [[package]] name = "async-fs" version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" dependencies = [ - "async-lock 3.4.0", + "async-lock", "blocking", - "futures-lite 2.3.0", + "futures-lite", ] [[package]] @@ -182,61 +171,32 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.3.1", "async-executor", - "async-io 2.3.4", - "async-lock 3.4.0", + "async-io", + "async-lock", "blocking", - "futures-lite 2.3.0", + "futures-lite", "once_cell", ] [[package]] name = "async-io" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" -dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.27", - "slab", - "socket2 0.4.10", - "waker-fn", -] - -[[package]] -name = "async-io" -version = "2.3.4" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" dependencies = [ - "async-lock 3.4.0", + "async-lock", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.3.0", + "futures-lite", "parking", - "polling 3.7.3", - "rustix 0.38.37", + "polling", + "rustix", "slab", "tracing", "windows-sys 0.59.0", ] -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - [[package]] name = "async-lock" version = "3.4.0" @@ -248,26 +208,15 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "async-net" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0434b1ed18ce1cf5769b8ac540e33f01fa9471058b5e89da9e06f3c882a8c12f" -dependencies = [ - "async-io 1.13.0", - "blocking", - "futures-lite 1.13.0", -] - [[package]] name = "async-net" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" dependencies = [ - "async-io 2.3.4", + "async-io", "blocking", - "futures-lite 2.3.0", + "futures-lite", ] [[package]] @@ -278,14 +227,14 @@ checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" dependencies = [ "async-channel 1.9.0", "async-global-executor", - "async-io 2.3.4", - "async-lock 3.4.0", + "async-io", + "async-lock", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite 2.3.0", - "gloo-timers 0.3.0", + "futures-lite", + "gloo-timers", "kv-log-macro", "log", "memchr", @@ -310,20 +259,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", -] - -[[package]] -name = "async-tungstenite" -version = "0.22.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce01ac37fdc85f10a43c43bc582cbd566720357011578a935761075f898baf58" -dependencies = [ - "futures-io", - "futures-util", - "log", - "pin-project-lite", - "tungstenite 0.19.0", + "syn 2.0.87", ] [[package]] @@ -336,7 +272,7 @@ dependencies = [ "futures-util", "log", "pin-project-lite", - "tungstenite 0.23.0", + "tungstenite", ] [[package]] @@ -345,55 +281,12 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "atomic_enum" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e1aca718ea7b89985790c94aad72d77533063fe00bc497bb79a7c2dae6a661" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.79", -] - [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core 0.3.4", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.30", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper 0.1.2", - "tokio", - "tower 0.4.13", - "tower-layer", - "tower-service", -] - [[package]] name = "axum" version = "0.7.7" @@ -401,13 +294,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", - "axum-core 0.4.5", + "axum-core", "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-util", "itoa", "matchit", @@ -422,29 +315,12 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 1.0.1", "tokio", - "tower 0.5.1", + "tower", "tower-layer", "tower-service", "tracing", ] -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - [[package]] name = "axum-core" version = "0.4.5" @@ -454,8 +330,8 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", "mime", "pin-project-lite", @@ -481,12 +357,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -509,12 +379,14 @@ dependencies = [ "cexpr", "clang-sys", "itertools", + "log", + "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -532,6 +404,20 @@ dependencies = [ "serde", ] +[[package]] +name = "bladerf" +version = "0.1.0" +dependencies = [ + "bytemuck", + "enum-map", + "libbladerf-sys", + "log", + "num-complex", + "parking_lot", + "strum", + "thiserror", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -550,10 +436,16 @@ dependencies = [ "async-channel 2.3.1", "async-task", "futures-io", - "futures-lite 2.3.0", + "futures-lite", "piper", ] +[[package]] +name = "build-target" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "832133bbabbbaa9fbdba793456a2827627a7d2b8fb96032fa1e7666d7895832b" + [[package]] name = "bumpalo" version = "3.16.0" @@ -562,9 +454,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" [[package]] name = "byteorder" @@ -574,15 +466,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "cc" -version = "1.1.28" +version = "1.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" +checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" dependencies = [ "jobserver", "libc", @@ -655,51 +547,21 @@ dependencies = [ [[package]] name = "config" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23738e11972c7643e4ec947840fc463b6a571afcd3e735bdfce7d03c7a784aca" -dependencies = [ - "async-trait", - "json5", - "lazy_static", - "nom", - "pathdiff", - "ron 0.7.1", - "rust-ini 0.18.0", - "serde", - "serde_json", - "toml 0.5.11", - "yaml-rust", -] - -[[package]] -name = "config" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" +checksum = "68578f196d2a33ff61b27fae256c3164f65e36382648e30666dde05b8cc9dfdf" dependencies = [ "async-trait", "convert_case", "json5", - "lazy_static", "nom", "pathdiff", - "ron 0.8.1", - "rust-ini 0.19.0", + "ron", + "rust-ini", "serde", "serde_json", - "toml 0.8.19", - "yaml-rust", -] - -[[package]] -name = "console_log" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" -dependencies = [ - "log", - "web-sys", + "toml", + "yaml-rust2", ] [[package]] @@ -803,9 +665,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" dependencies = [ "libc", ] @@ -853,7 +715,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -864,7 +726,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -883,7 +745,7 @@ checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" name = "data-gen" version = "0.1.0" dependencies = [ - "futuresdr 0.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "futuresdr", "tracing", "tracing-subscriber", "zigbee", @@ -930,12 +792,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "dlv-list" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" - [[package]] name = "dlv-list" version = "0.5.2" @@ -951,7 +807,7 @@ version = "0.1.0" dependencies = [ "anyhow", "foxhunter-profile", - "futuresdr 0.0.37 (git+https://github.com/MerchGuardian/FutureSDr.git?branch=android-fd)", + "futuresdr", "log", "serde", "serde_json", @@ -962,9 +818,11 @@ dependencies = [ name = "dsp-runner" version = "0.1.0" dependencies = [ + "anyhow", "dsp", - "futuresdr 0.0.37 (git+https://github.com/MerchGuardian/FutureSDr.git?branch=android-fd)", - "hackrfone", + "futuresdr", + "log", + "nusb", "pretty_env_logger", "tracy-client", ] @@ -983,13 +841,33 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] +[[package]] +name = "enum-map" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" +dependencies = [ + "enum-map-derive", +] + +[[package]] +name = "enum-map-derive" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "env_filter" version = "0.1.2" @@ -1064,18 +942,9 @@ checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365" [[package]] name = "fastrand" -version = "1.9.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fastrand" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fnv" @@ -1104,19 +973,6 @@ dependencies = [ [[package]] name = "futuredsp" version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f7672eb033261d8a9cff356d0373c831e853ea11dbeeb9100ffb6bea7a49189" -dependencies = [ - "log", - "num-complex", - "num-traits", - "rustc_version", -] - -[[package]] -name = "futuredsp" -version = "0.0.6" -source = "git+https://github.com/MerchGuardian/FutureSDr.git?branch=android-fd#4c31826b61fd3f69ca526cda520ad9b412a1b06a" dependencies = [ "num-complex", "num-traits", @@ -1174,26 +1030,11 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-lite" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" dependencies = [ - "fastrand 2.1.1", + "fastrand", "futures-core", "futures-io", "parking", @@ -1208,7 +1049,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1244,91 +1085,34 @@ dependencies = [ [[package]] name = "futuresdr" version = "0.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5511cab460817af5fa469aaec84148193d694e8ecaa4dc73b029a89667599805" dependencies = [ - "android_logger 0.13.3", + "android_logger", "anyhow", "async-executor", - "async-fs 1.6.0", - "async-io 1.13.0", - "async-lock 2.8.0", - "async-net 1.8.0", - "async-task", - "async-trait", - "async-tungstenite 0.22.2", - "axum 0.6.20", - "blocking", - "concurrent-queue", - "config 0.13.4", - "console_log", - "core_affinity", - "dirs", - "dyn-clone", - "futuredsp 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures", - "futures-lite 1.13.0", - "futuresdr-macros 0.0.5", - "futuresdr-types 0.0.11", - "getrandom", - "gloo-net 0.2.6", - "gloo-timers 0.2.6", - "js-sys", - "libc", - "log", - "num-complex", - "num-integer", - "num_cpus", - "once_cell", - "rand", - "rustc_version", - "rustfft", - "serde", - "serde-wasm-bindgen 0.5.0", - "serde_json", - "slab", - "spin", - "thiserror", - "tokio", - "tower-http 0.4.4", - "vmcircbuffer", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "futuresdr" -version = "0.0.37" -source = "git+https://github.com/MerchGuardian/FutureSDr.git?branch=android-fd#4c31826b61fd3f69ca526cda520ad9b412a1b06a" -dependencies = [ - "android_logger 0.14.1", - "anyhow", - "async-executor", - "async-fs 2.1.2", - "async-io 2.3.4", - "async-lock 3.4.0", - "async-net 2.0.0", + "async-fs", + "async-io", + "async-lock", + "async-net", "async-std", "async-task", "async-trait", - "async-tungstenite 0.27.0", - "axum 0.7.7", + "async-tungstenite", + "axum", "blocking", "concurrent-queue", - "config 0.14.0", + "config", "core_affinity", "cpal", "dirs", "dyn-clone", - "futuredsp 0.0.6 (git+https://github.com/MerchGuardian/FutureSDr.git?branch=android-fd)", + "futuredsp", "futures", - "futures-lite 2.3.0", - "futuresdr-macros 0.0.6", - "futuresdr-types 0.0.12", + "futures-lite", + "futuresdr-macros", + "futuresdr-types", "getrandom", - "gloo-net 0.6.0", - "gloo-timers 0.3.0", + "gloo-net", + "gloo-timers", "hound", "js-sys", "libc", @@ -1342,13 +1126,13 @@ dependencies = [ "rustfft", "seify", "serde", - "serde-wasm-bindgen 0.6.5", + "serde-wasm-bindgen", "serde_json", "slab", "spin", "thiserror", "tokio", - "tower-http 0.5.2", + "tower-http", "tracing", "tracing-subscriber", "tracing-wasm", @@ -1359,45 +1143,19 @@ dependencies = [ "web-time", ] -[[package]] -name = "futuresdr-macros" -version = "0.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78636147bb403c28d9aa4f046e9ee101efd6b253f73387bfcfa47936921dbcbf" -dependencies = [ - "indexmap 1.9.3", - "proc-macro2", - "quote", - "syn 2.0.79", -] - [[package]] name = "futuresdr-macros" version = "0.0.6" -source = "git+https://github.com/MerchGuardian/FutureSDr.git?branch=android-fd#4c31826b61fd3f69ca526cda520ad9b412a1b06a" dependencies = [ "indexmap 2.6.0", "proc-macro2", "quote", - "syn 2.0.79", -] - -[[package]] -name = "futuresdr-types" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da62a7641c097c98851f6d83deb8f75fae779c663e064ccf6dd49e5fb31b5d41" -dependencies = [ - "dyn-clone", - "serde", - "serde_json", - "thiserror", + "syn 2.0.87", ] [[package]] name = "futuresdr-types" version = "0.0.12" -source = "git+https://github.com/MerchGuardian/FutureSDr.git?branch=android-fd#4c31826b61fd3f69ca526cda520ad9b412a1b06a" dependencies = [ "dyn-clone", "num-complex", @@ -1454,26 +1212,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" -[[package]] -name = "gloo-net" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10" -dependencies = [ - "futures-channel", - "futures-core", - "futures-sink", - "gloo-utils 0.1.7", - "js-sys", - "pin-project", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "gloo-net" version = "0.6.0" @@ -1483,8 +1221,8 @@ dependencies = [ "futures-channel", "futures-core", "futures-sink", - "gloo-utils 0.2.0", - "http 1.1.0", + "gloo-utils", + "http", "js-sys", "pin-project", "serde", @@ -1495,18 +1233,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - [[package]] name = "gloo-timers" version = "0.3.0" @@ -1519,19 +1245,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "gloo-utils" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" -dependencies = [ - "js-sys", - "serde", - "serde_json", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "gloo-utils" version = "0.2.0" @@ -1545,36 +1258,42 @@ dependencies = [ "web-sys", ] -[[package]] -name = "hackrfone" -version = "0.1.0" -dependencies = [ - "foxhunter-profile", - "num-complex", - "rusb", - "tracy-client", -] - [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", + "allocator-api2", ] [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" [[package]] -name = "hashbrown" -version = "0.15.0" +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -1600,17 +1319,6 @@ version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f" -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.1.0" @@ -1622,17 +1330,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -1640,7 +1337,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http", ] [[package]] @@ -1651,17 +1348,11 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] -[[package]] -name = "http-range-header" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" - [[package]] name = "http-range-header" version = "0.4.1" @@ -1688,38 +1379,15 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.5.7", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "httparse", "httpdate", "itoa", @@ -1730,15 +1398,15 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "hyper 1.4.1", + "http", + "http-body", + "hyper", "pin-project-lite", "tokio", "tower-service", @@ -1773,16 +1441,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "indexmap" version = "1.9.3" @@ -1801,19 +1459,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "serde", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - [[package]] name = "io-kit-sys" version = "0.4.1" @@ -1824,17 +1473,6 @@ dependencies = [ "mach2", ] -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "is-terminal" version = "0.4.13" @@ -1927,11 +1565,20 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "libbladerf-sys" +version = "0.1.0" +dependencies = [ + "anyhow", + "bindgen", + "build-target", +] + [[package]] name = "libc" -version = "0.2.159" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "libloading" @@ -1940,41 +1587,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.6", -] - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.6.0", - "libc", -] - -[[package]] -name = "libusb1-sys" -version = "0.7.0" -source = "git+https://github.com/MerchGuardian/rusb#66a1ce99c84e74ceb82fff68d0b6d78df808c54d" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + "windows-targets 0.52.6", +] [[package]] -name = "linux-raw-sys" -version = "0.3.8" +name = "libredox" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] [[package]] name = "linux-raw-sys" @@ -2160,7 +1784,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2209,13 +1833,14 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "nusb" -version = "0.1.10" -source = "git+https://github.com/kevinmehall/nusb.git?rev=809228038f43de2d7a636825d17439b445f612b7#809228038f43de2d7a636825d17439b445f612b7" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58c5baaf1902712d1c7ef734165376bf1e05f0ebfd00755fd4c4762c06b0c1a" dependencies = [ "atomic-waker", "core-foundation", @@ -2225,7 +1850,7 @@ dependencies = [ "libc", "log", "once_cell", - "rustix 0.38.37", + "rustix", "slab", "windows-sys 0.48.0", ] @@ -2276,22 +1901,12 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "ordered-multimap" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" -dependencies = [ - "dlv-list 0.3.0", - "hashbrown 0.12.3", -] - -[[package]] -name = "ordered-multimap" -version = "0.6.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" dependencies = [ - "dlv-list 0.5.2", - "hashbrown 0.13.2", + "dlv-list", + "hashbrown 0.14.5", ] [[package]] @@ -2306,11 +1921,34 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" [[package]] name = "percent-encoding" @@ -2320,9 +1958,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", "thiserror", @@ -2331,9 +1969,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" dependencies = [ "pest", "pest_generator", @@ -2341,22 +1979,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "pest_meta" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" dependencies = [ "once_cell", "pest", @@ -2365,29 +2003,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -2402,7 +2040,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.1.1", + "fastrand", "futures-io", ] @@ -2414,31 +2052,15 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polling" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" -dependencies = [ - "autocfg", - "bitflags 1.3.2", - "cfg-if", - "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - -[[package]] -name = "polling" -version = "3.7.3" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.37", + "rustix", "tracing", "windows-sys 0.59.0", ] @@ -2468,6 +2090,16 @@ dependencies = [ "log", ] +[[package]] +name = "prettyplease" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +dependencies = [ + "proc-macro2", + "syn 2.0.87", +] + [[package]] name = "primal-check" version = "0.3.4" @@ -2488,9 +2120,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -2534,6 +2166,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "redox_users" version = "0.4.6" @@ -2547,13 +2188,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -2568,9 +2209,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -2600,17 +2241,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "ron" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" -dependencies = [ - "base64 0.13.1", - "bitflags 1.3.2", - "serde", -] - [[package]] name = "ron" version = "0.8.1" @@ -2623,33 +2253,14 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "rusb" -version = "0.9.4" -source = "git+https://github.com/MerchGuardian/rusb#66a1ce99c84e74ceb82fff68d0b6d78df808c54d" -dependencies = [ - "libc", - "libusb1-sys", -] - -[[package]] -name = "rust-ini" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" -dependencies = [ - "cfg-if", - "ordered-multimap 0.4.3", -] - [[package]] name = "rust-ini" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091" +checksum = "3e0698206bcb8882bf2a9ecb4c1e7785db57ff052297085a6efd4fe42302068a" dependencies = [ "cfg-if", - "ordered-multimap 0.6.0", + "ordered-multimap", ] [[package]] @@ -2690,36 +2301,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.37" +version = "0.38.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" dependencies = [ "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.14", + "linux-raw-sys", "windows-sys 0.52.0", ] [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -2751,32 +2348,19 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "seify" version = "0.13.0" -source = "git+https://github.com/MerchGuardian/seify.git?rev=1c5df71f96327fbc726071163ad227cc0e9de670#1c5df71f96327fbc726071163ad227cc0e9de670" dependencies = [ + "bladerf", "futures", "log", "nom", "num-complex", "once_cell", - "seify-hackrfone", "serde", "serde_json", "serde_with", "thiserror", ] -[[package]] -name = "seify-hackrfone" -version = "0.1.0" -source = "git+https://github.com/MerchGuardian/seify.git?rev=1c5df71f96327fbc726071163ad227cc0e9de670#1c5df71f96327fbc726071163ad227cc0e9de670" -dependencies = [ - "atomic_enum", - "futures-lite 2.3.0", - "log", - "nusb", - "thiserror", -] - [[package]] name = "semver" version = "1.0.23" @@ -2785,24 +2369,13 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] -[[package]] -name = "serde-wasm-bindgen" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - [[package]] name = "serde-wasm-bindgen" version = "0.6.5" @@ -2816,20 +2389,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -2895,7 +2468,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2950,16 +2523,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.7" @@ -2991,6 +2554,28 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.87", +] + [[package]] name = "symphonia" version = "0.5.4" @@ -3149,9 +2734,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -3181,22 +2766,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3249,33 +2834,18 @@ dependencies = [ "crunchy", ] -[[package]] -name = "tinyvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" -version = "1.40.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", "libc", "mio", "pin-project-lite", - "socket2 0.5.7", + "socket2", "tokio-macros", "windows-sys 0.52.0", ] @@ -3288,7 +2858,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3304,15 +2874,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - [[package]] name = "toml" version = "0.8.19" @@ -3347,22 +2908,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "tower" version = "0.5.1" @@ -3379,31 +2924,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tower-http" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" -dependencies = [ - "bitflags 2.6.0", - "bytes", - "futures-core", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "http-range-header 0.3.1", - "httpdate", - "mime", - "mime_guess", - "percent-encoding", - "pin-project-lite", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "tower-http" version = "0.5.2" @@ -3413,10 +2933,10 @@ dependencies = [ "bitflags 2.6.0", "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", - "http-range-header 0.4.1", + "http-range-header", "httpdate", "mime", "mime_guess", @@ -3461,7 +2981,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3544,31 +3064,6 @@ dependencies = [ "strength_reduce", ] -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "tungstenite" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15fba1a6d6bb030745759a9a2a588bfe8490fc8b4751a277db3a0be1c9ebbf67" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 0.2.12", - "httparse", - "log", - "rand", - "sha1", - "thiserror", - "url", - "utf-8", -] - [[package]] name = "tungstenite" version = "0.23.0" @@ -3578,7 +3073,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.1.0", + "http", "httparse", "log", "rand", @@ -3601,18 +3096,9 @@ checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.17" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-ident" @@ -3620,32 +3106,12 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-segmentation" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" -[[package]] -name = "url" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - [[package]] name = "utf-8" version = "0.7.6" @@ -3660,15 +3126,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" - -[[package]] -name = "vcpkg" -version = "0.2.15" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" [[package]] name = "version_check" @@ -3690,12 +3150,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - [[package]] name = "walkdir" version = "2.5.0" @@ -3706,15 +3160,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -3743,7 +3188,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "wasm-bindgen-shared", ] @@ -3777,7 +3222,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3790,9 +3235,9 @@ checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -3899,7 +3344,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3910,7 +3355,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -4165,12 +3610,14 @@ dependencies = [ ] [[package]] -name = "yaml-rust" -version = "0.4.5" +name = "yaml-rust2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +checksum = "8902160c4e6f2fb145dbe9d6760a75e3c9522d8bf796ed7047c85919ac7115f8" dependencies = [ - "linked-hash-map", + "arraydeque", + "encoding_rs", + "hashlink", ] [[package]] @@ -4191,13 +3638,13 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "zigbee" version = "0.0.1" dependencies = [ - "futuresdr 0.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "futuresdr", "tracing", ] diff --git a/Cargo.toml b/Cargo.toml index 0474dc82..dc9923eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,5 @@ [workspace] members = [ - "hackrfone", "dsp", "dsp-runner", "foxhunter-profile", @@ -18,7 +17,8 @@ exclude = [ resolver = "2" [workspace.dependencies] -rusb = { git = "https://github.com/MerchGuardian/rusb", features = ["vendored"] } +# futuresdr = { git = "https://github.com/MerchGuardian/FutureSDr.git", branch = "android-fd", default-features = false, features = ["bladerf", "audio"] } +futuresdr = { path = "../FutureSDR", default-features = false, features = ["bladerf", "audio"] } [workspace.dependencies.tracy-client] # Force v0.17.0 since we our GUI is on v0.10 diff --git a/FoxhunterJNI/build.gradle.kts b/FoxhunterJNI/build.gradle.kts index d568c54a..05599cdb 100644 --- a/FoxhunterJNI/build.gradle.kts +++ b/FoxhunterJNI/build.gradle.kts @@ -6,7 +6,7 @@ plugins { tasks.register("buildRustNatives") { workingDir("./foxhunterjni-rs/") - commandLine("nix", "develop", "--command", "./build.sh") + commandLine("nix", "develop", ".#android", "--command", "./build.sh") outputs.upToDateWhen { false } } @@ -55,4 +55,5 @@ dependencies { androidTestImplementation(libs.androidx.espresso.core) implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") + implementation(kotlin("reflect")) } diff --git a/FoxhunterJNI/foxhunterjni-rs/Cargo.lock b/FoxhunterJNI/foxhunterjni-rs/Cargo.lock index f7c558fc..a935bb0e 100644 --- a/FoxhunterJNI/foxhunterjni-rs/Cargo.lock +++ b/FoxhunterJNI/foxhunterjni-rs/Cargo.lock @@ -17,6 +17,18 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -26,6 +38,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" + [[package]] name = "alsa" version = "0.9.1" @@ -82,9 +100,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" + +[[package]] +name = "arraydeque" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" [[package]] name = "arrayvec" @@ -156,9 +180,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.4" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" dependencies = [ "async-lock", "cfg-if", @@ -235,7 +259,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -257,17 +281,6 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "atomic_enum" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e1aca718ea7b89985790c94aad72d77533063fe00bc497bb79a7c2dae6a661" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.79", -] - [[package]] name = "autocfg" version = "1.4.0" @@ -366,12 +379,14 @@ dependencies = [ "cexpr", "clang-sys", "itertools", + "log", + "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -389,6 +404,20 @@ dependencies = [ "serde", ] +[[package]] +name = "bladerf" +version = "0.1.0" +dependencies = [ + "bytemuck", + "enum-map", + "libbladerf-sys", + "log", + "num-complex", + "parking_lot", + "strum", + "thiserror", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -411,6 +440,12 @@ dependencies = [ "piper", ] +[[package]] +name = "build-target" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "832133bbabbbaa9fbdba793456a2827627a7d2b8fb96032fa1e7666d7895832b" + [[package]] name = "bumpalo" version = "3.16.0" @@ -419,9 +454,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" [[package]] name = "byteorder" @@ -431,15 +466,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "cc" -version = "1.1.28" +version = "1.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" +checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" dependencies = [ "jobserver", "libc", @@ -512,14 +547,13 @@ dependencies = [ [[package]] name = "config" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" +checksum = "68578f196d2a33ff61b27fae256c3164f65e36382648e30666dde05b8cc9dfdf" dependencies = [ "async-trait", "convert_case", "json5", - "lazy_static", "nom", "pathdiff", "ron", @@ -527,7 +561,7 @@ dependencies = [ "serde", "serde_json", "toml", - "yaml-rust", + "yaml-rust2", ] [[package]] @@ -559,16 +593,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -631,9 +655,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" dependencies = [ "libc", ] @@ -681,7 +705,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -692,7 +716,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -784,13 +808,33 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] +[[package]] +name = "enum-map" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" +dependencies = [ + "enum-map-derive", +] + +[[package]] +name = "enum-map-derive" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "env_filter" version = "0.1.2" @@ -852,9 +896,9 @@ checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365" [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fnv" @@ -900,7 +944,6 @@ dependencies = [ [[package]] name = "futuredsp" version = "0.0.6" -source = "git+https://github.com/MerchGuardian/FutureSDr.git?branch=android-fd#4c31826b61fd3f69ca526cda520ad9b412a1b06a" dependencies = [ "num-complex", "num-traits", @@ -958,9 +1001,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" dependencies = [ "fastrand", "futures-core", @@ -977,7 +1020,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1013,7 +1056,6 @@ dependencies = [ [[package]] name = "futuresdr" version = "0.0.37" -source = "git+https://github.com/MerchGuardian/FutureSDr.git?branch=android-fd#4c31826b61fd3f69ca526cda520ad9b412a1b06a" dependencies = [ "android_logger", "anyhow", @@ -1075,18 +1117,16 @@ dependencies = [ [[package]] name = "futuresdr-macros" version = "0.0.6" -source = "git+https://github.com/MerchGuardian/FutureSDr.git?branch=android-fd#4c31826b61fd3f69ca526cda520ad9b412a1b06a" dependencies = [ "indexmap 2.6.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "futuresdr-types" version = "0.0.12" -source = "git+https://github.com/MerchGuardian/FutureSDr.git?branch=android-fd#4c31826b61fd3f69ca526cda520ad9b412a1b06a" dependencies = [ "dyn-clone", "num-complex", @@ -1197,15 +1237,34 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -1285,9 +1344,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", @@ -1304,9 +1363,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-util", @@ -1365,20 +1424,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "serde", ] -[[package]] -name = "io-kit-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b" -dependencies = [ - "core-foundation-sys", - "mach2", -] - [[package]] name = "itertools" version = "0.13.0" @@ -1460,11 +1509,20 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "libbladerf-sys" +version = "0.1.0" +dependencies = [ + "anyhow", + "bindgen", + "build-target", +] + [[package]] name = "libc" -version = "0.2.159" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "libloading" @@ -1486,12 +1544,6 @@ dependencies = [ "libc", ] -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -1676,7 +1728,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1725,25 +1777,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.79", -] - -[[package]] -name = "nusb" -version = "0.1.10" -source = "git+https://github.com/kevinmehall/nusb.git?rev=809228038f43de2d7a636825d17439b445f612b7#809228038f43de2d7a636825d17439b445f612b7" -dependencies = [ - "atomic-waker", - "core-foundation", - "core-foundation-sys", - "futures-core", - "io-kit-sys", - "libc", - "log", - "once_cell", - "rustix", - "slab", - "windows-sys 0.48.0", + "syn 2.0.87", ] [[package]] @@ -1792,12 +1826,12 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "ordered-multimap" -version = "0.6.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" dependencies = [ "dlv-list", - "hashbrown 0.13.2", + "hashbrown 0.14.5", ] [[package]] @@ -1812,11 +1846,34 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" [[package]] name = "percent-encoding" @@ -1826,9 +1883,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", "thiserror", @@ -1837,9 +1894,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" dependencies = [ "pest", "pest_generator", @@ -1847,22 +1904,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "pest_meta" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" dependencies = [ "once_cell", "pest", @@ -1871,29 +1928,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -1920,9 +1977,9 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polling" -version = "3.7.3" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", @@ -1948,6 +2005,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +dependencies = [ + "proc-macro2", + "syn 2.0.87", +] + [[package]] name = "primal-check" version = "0.3.4" @@ -1968,9 +2035,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -2014,6 +2081,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "redox_users" version = "0.4.6" @@ -2027,13 +2103,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -2048,9 +2124,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -2094,9 +2170,9 @@ dependencies = [ [[package]] name = "rust-ini" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091" +checksum = "3e0698206bcb8882bf2a9ecb4c1e7785db57ff052297085a6efd4fe42302068a" dependencies = [ "cfg-if", "ordered-multimap", @@ -2140,9 +2216,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" dependencies = [ "bitflags 2.6.0", "errno", @@ -2153,9 +2229,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -2187,32 +2263,19 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "seify" version = "0.13.0" -source = "git+https://github.com/MerchGuardian/seify.git?rev=1c5df71f96327fbc726071163ad227cc0e9de670#1c5df71f96327fbc726071163ad227cc0e9de670" dependencies = [ + "bladerf", "futures", "log", "nom", "num-complex", "once_cell", - "seify-hackrfone", "serde", "serde_json", "serde_with", "thiserror", ] -[[package]] -name = "seify-hackrfone" -version = "0.1.0" -source = "git+https://github.com/MerchGuardian/seify.git?rev=1c5df71f96327fbc726071163ad227cc0e9de670#1c5df71f96327fbc726071163ad227cc0e9de670" -dependencies = [ - "atomic_enum", - "futures-lite", - "log", - "nusb", - "thiserror", -] - [[package]] name = "semver" version = "1.0.23" @@ -2221,9 +2284,9 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] @@ -2241,20 +2304,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -2320,7 +2383,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2406,6 +2469,28 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.87", +] + [[package]] name = "symphonia" version = "0.5.4" @@ -2564,9 +2649,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -2587,22 +2672,22 @@ checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2657,9 +2742,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.40.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", @@ -2679,7 +2764,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2802,7 +2887,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2917,12 +3002,9 @@ checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-ident" @@ -2950,9 +3032,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" +checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" [[package]] name = "version_check" @@ -3012,7 +3094,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "wasm-bindgen-shared", ] @@ -3046,7 +3128,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3168,7 +3250,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3179,7 +3261,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3434,12 +3516,14 @@ dependencies = [ ] [[package]] -name = "yaml-rust" -version = "0.4.5" +name = "yaml-rust2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +checksum = "8902160c4e6f2fb145dbe9d6760a75e3c9522d8bf796ed7047c85919ac7115f8" dependencies = [ - "linked-hash-map", + "arraydeque", + "encoding_rs", + "hashlink", ] [[package]] @@ -3460,5 +3544,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] diff --git a/FoxhunterJNI/foxhunterjni-rs/Cargo.toml b/FoxhunterJNI/foxhunterjni-rs/Cargo.toml index e0176a00..983ab790 100644 --- a/FoxhunterJNI/foxhunterjni-rs/Cargo.toml +++ b/FoxhunterJNI/foxhunterjni-rs/Cargo.toml @@ -11,7 +11,8 @@ jni = "0.21.1" lazy_static = "1.5.0" log = "0.4" ndk-context = "0.1.1" -futuresdr = { git = "https://github.com/MerchGuardian/FutureSDr.git", branch = "android-fd", default-features = false, features = ["hackrfone", "audio"] } +# futuresdr = { git = "https://github.com/MerchGuardian/FutureSDr.git", branch = "android-fd", default-features = false, features = ["bladerf", "audio"] } +futuresdr = { path = "../../../FutureSDR", default-features = false, features = ["bladerf", "audio"] } backtrace = "0.3.74" serde = "1.0.210" serde_json = "1.0.128" @@ -22,3 +23,6 @@ crate-type=["cdylib"] [profile.release-with-debug] inherits = "release" debug = true + +[build-dependencies] +anyhow = "1.0.86" diff --git a/FoxhunterJNI/foxhunterjni-rs/build.rs b/FoxhunterJNI/foxhunterjni-rs/build.rs index 957e7b4d..9e019735 100644 --- a/FoxhunterJNI/foxhunterjni-rs/build.rs +++ b/FoxhunterJNI/foxhunterjni-rs/build.rs @@ -1,34 +1,82 @@ use std::{ env, + os::unix::fs::PermissionsExt, path::{Path, PathBuf}, }; +use anyhow::{Context, Result}; + fn main() { if env::var("CARGO_CFG_TARGET_OS").unwrap() == "android" { - android(); + android().expect("Failed to copy android libs"); } } -// Copy c++_shared dylib from ndk, to satisfy cpal's dep. +// Copy c++_shared dylib from ndk, to satisfy cpal's dep + libbladeRF dylib. // See: https://github.com/RustAudio/cpal/tree/master?tab=readme-ov-file#feature-flags-for-audio-backends -fn android() { +fn android() -> Result<()> { println!("cargo:rustc-link-lib=c++_shared"); - if let Ok(output_path) = env::var("CARGO_NDK_OUTPUT_PATH") { - let sysroot_libs_path = PathBuf::from(env::var_os("CARGO_NDK_SYSROOT_LIBS_PATH").unwrap()); - let src = sysroot_libs_path.join("libc++_shared.so"); + println!("cargo:rerun-if-env-changed=CARGO_NDK_OUTPUT_PATH"); + println!("cargo:rerun-if-env-changed=CARGO_NDK_ANDROID_TARGET"); + + if let Some(output_root) = env::var("CARGO_NDK_OUTPUT_PATH").ok() { + println!("cargo:rerun-if-changed={output_root}"); - let dst = Path::new(&output_path) - .join(env::var("CARGO_NDK_ANDROID_TARGET").unwrap()) - .join("libc++_shared.so"); + let target = env::var("CARGO_NDK_ANDROID_TARGET") + .context("Failed to read env var CARGO_NDK_ANDROID_TARGET")?; - let _ = std::fs::create_dir_all(dst.parent().unwrap()); + let output_path = Path::new(&output_root).join(target); + copy_from_env_path( + &output_path, + "CARGO_NDK_SYSROOT_LIBS_PATH", + "libc++_shared.so", + None, + ) + .context("Failed to copy libc++_shared.so")?; - std::fs::copy(&src, &dst).unwrap(); - // Likely copied from nix store, so need to remove readonly flag - let mut perms = std::fs::metadata(&src).unwrap().permissions(); - perms.set_readonly(false); + copy_from_env_path(&output_path, "BLADERF_LIB_PATH", "libbladeRF.so", None) + .context("Failed to copy libbladeRF.so")?; - std::fs::set_permissions(&dst, perms).unwrap(); + // NOTE: bindgen expects `libusb1.0.so` (without the dash) + copy_from_env_path( + &output_path, + "LIBUSB_LIB_PATH", + "libusb-1.0.so", + Some("libusb1.0.so"), + ) + .context("Failed to copy libusb-1.0.so")?; } + + Ok(()) +} + +fn copy_from_env_path( + output_path: &Path, + var_name: &str, + lib_name: &str, + dst_name: Option<&str>, +) -> Result<()> { + println!("cargo:rerun-if-env-changed={var_name}"); + + let sysroot_libs_path = PathBuf::from(env::var_os(var_name).unwrap()); + let src = sysroot_libs_path.join(lib_name); + + let dst_name = dst_name.unwrap_or(lib_name); + let dst = Path::new(&output_path).join(dst_name); + + let _ = std::fs::create_dir_all(dst.parent().context("Failed to get parent of dst file")?); + + std::fs::copy(&src, &dst).with_context(|| format!("Failed to copy {src:?} to {dst:?}"))?; + + // Likely copied from nix store, so need to remove readonly flag + let mut perms = std::fs::metadata(&src) + .with_context(|| format!("Failed to read permissions of file {src:?}"))? + .permissions(); + perms.set_mode(0o644); + + std::fs::set_permissions(&dst, perms) + .context("Failed to change output permissions of output lib")?; + + Ok(()) } diff --git a/FoxhunterJNI/foxhunterjni-rs/src/jni_entry.rs b/FoxhunterJNI/foxhunterjni-rs/src/jni_entry.rs index 3249b9a3..bfe32e56 100644 --- a/FoxhunterJNI/foxhunterjni-rs/src/jni_entry.rs +++ b/FoxhunterJNI/foxhunterjni-rs/src/jni_entry.rs @@ -6,28 +6,41 @@ use jni::objects::{JClass, JObject, JString}; use jni::sys::{jint, jlong, jstring}; use jni::JNIEnv; use log::{info, warn}; +use std::panic::AssertUnwindSafe; use std::sync::Mutex; static HANDLE: Mutex>> = Mutex::new(None); #[no_mangle] pub extern "C" fn JNI_OnLoad(vm: jni::JavaVM, res: *mut std::os::raw::c_void) -> jni::sys::jint { - crate::logger::init(log::LevelFilter::Info); - let vm = vm.get_java_vm_pointer() as *mut std::ffi::c_void; - info!("Java VM pointer: {vm:?}"); unsafe { // Set android context for cpal audio natives ndk_context::initialize_android_context(vm, res); } - info!("Initialized ndk context!"); - info!("Returning from JNI_OnLoad"); jni::JNIVersion::V6.into() } +#[no_mangle] +pub unsafe extern "C" fn Java_ai_foxhunter_foxhunterjni_Foxhunter_initLogging( + env: JNIEnv, + _: JClass, + on_log_class: JClass, +) -> jstring { + map_result(env, |env| { + crate::logger::init( + env.get_java_vm().expect("Failed to get java VM"), + on_log_class, + log::LevelFilter::Info, + )?; + info!("Native logging initialized"); + Ok(()) + }) +} + #[no_mangle] pub unsafe extern "C" fn Java_ai_foxhunter_foxhunterjni_Foxhunter_setLogLevel0( - _: JNIEnv, + _env: JNIEnv, _: JClass, level: jint, ) { @@ -62,57 +75,58 @@ pub unsafe extern "C" fn Java_ai_foxhunter_foxhunterjni_Foxhunter_init0( ptr as jlong } -/// Opens fd as a hack rf device and stores the info in state for later usage. +/// Opens fd as a seify device and stores the info in state for later usage. /// # Safety /// Expects a valid call from JNI (java env pointers etc.) #[no_mangle] pub unsafe extern "C" fn Java_ai_foxhunter_foxhunterjni_Foxhunter_startTask0( - mut env: JNIEnv, + env: JNIEnv, _: JClass, handle: jlong, fd: jint, name: JString, parameters_json: JString, ) -> jstring { - let res = with_handle(handle, |state| { - ensure!( - fd >= 0, - "startTask received negitive file descriptor. Wrong value or usb device closed?" - ); - - let name = env.get_string(&name)?; - let name = name - .to_str() - .context("Failed to convert task name to rust str")?; - let parameters_json = env.get_string(¶meters_json)?; - let parameters_json = parameters_json - .to_str() - .context("Failed to convert parameters json to rust str")?; - state.start_task(fd, name, parameters_json) - }); - map_result(&mut env, res) + map_result(env, |env| { + with_handle(handle, |state| { + ensure!( + fd >= 0, + "startTask received negitive file descriptor. Wrong value or usb device closed?" + ); + + let name = env.get_string(&name)?; + let name = name + .to_str() + .context("Failed to convert task name to rust str")?; + let parameters_json = env.get_string(¶meters_json)?; + let parameters_json = parameters_json + .to_str() + .context("Failed to convert parameters json to rust str")?; + state.start_task(fd, name, parameters_json) + }) + }) } -/// Opens fd as a hack rf device and stores the info in state for later usage. +/// Stops the currently running task started by `startTask0` (if any). +/// /// # Safety /// Expects a valid call from JNI (java env pointers etc.) #[no_mangle] pub unsafe extern "C" fn Java_ai_foxhunter_foxhunterjni_Foxhunter_stopTask0( - mut env: JNIEnv, + env: JNIEnv, _: JClass, handle: jlong, ) -> jstring { - let res = with_handle(handle, |state| state.stop_task()); - map_result(&mut env, res) + map_result(env, |_| with_handle(handle, |state| state.stop_task())) } #[no_mangle] pub unsafe extern "C" fn Java_ai_foxhunter_foxhunterjni_Foxhunter_shutdown0( - mut env: JNIEnv, + env: JNIEnv, _: JClass, _handle: jlong, ) -> jstring { - let shutdown_fn = || -> Result<()> { + map_result(env, |_| -> Result<()> { let mut inner = HANDLE.try_lock().map_err(|_| { anyhow!( "handle already aliased. jni function called on separate threads or recursively?" @@ -123,21 +137,34 @@ pub unsafe extern "C" fn Java_ai_foxhunter_foxhunterjni_Foxhunter_shutdown0( let _ = inner.take(); Ok(()) - }; - map_result(&mut env, shutdown_fn()) + }) } -fn map_result(env: &mut JNIEnv, result: Result<()>) -> jstring { - match result { - Ok(()) => JObject::null().into_raw(), - Err(e) => { - let msg = format!("{e:?}"); - // TODO(troy): handle string encoding failure. How do we return an error string when we - // cant make a string? - let jstring = env.new_string(msg).expect("Failed to encode java string"); - jstring.into_raw() +fn map_result(mut env: JNIEnv, fun: impl FnOnce(&mut JNIEnv) -> Result<()>) -> jstring { + let err_msg = match std::panic::catch_unwind(AssertUnwindSafe(|| fun(&mut env))) { + Ok(Ok(())) => return JObject::null().into_raw(), + Ok(Err(e)) => { + format!("{e:?}") } - } + Err(payload) => { + let msg = match payload.downcast_ref::<&'static str>() { + Some(s) => *s, + None => match payload.downcast_ref::() { + Some(s) => &s[..], + None => "Box", + }, + }; + + // Paniced + format!("foxhunterjni PANICKED across jni function: {msg}") + } + }; + + // TODO(troy): handle string encoding failure. How do we return an error string when we + // cant make a string? + env.new_string(err_msg) + .expect("Failed to encode java string") + .into_raw() } fn with_handle(handle: jlong, f: F) -> Result diff --git a/FoxhunterJNI/foxhunterjni-rs/src/lib.rs b/FoxhunterJNI/foxhunterjni-rs/src/lib.rs index bac1ef04..c91d7316 100644 --- a/FoxhunterJNI/foxhunterjni-rs/src/lib.rs +++ b/FoxhunterJNI/foxhunterjni-rs/src/lib.rs @@ -4,11 +4,10 @@ mod jni_entry; mod logger; use anyhow::{bail, Context, Result}; -use dsp::FmDemodConfig; +use dsp::fm_demod::Config; use futuresdr::runtime::FlowgraphHandle; -use futuresdr::seify; -use log::debug; +use futuresdr::seify::{self, Args}; #[derive(Default)] pub struct FoxhunterState { @@ -21,16 +20,24 @@ impl FoxhunterState { } fn start_task(&mut self, fd: i32, name: &str, parameters_json: &str) -> Result<()> { - debug!("Starting FM demod task with fd={fd}"); - let device = - seify::Device::from_args(format!("fd={fd}")).context("Failed to open seify device")?; + log::info!("Starting FM demod task with fd={fd}"); + + let mut args = Args::new(); + args.set("fd", fd.to_string()); + args.set("bladerf_use_default_fpga_bitstream", true.to_string()); + args.set("bladerf_log_level", "debug"); + + // Currently freezes when opening device + let device = seify::Device::from_args(args).context("Failed to open seify device")?; + + log::info!("Opened seify device, starting task {name}"); self.handle = Some(match name { "fm_demod" => { - let config: FmDemodConfig = serde_json::from_str(parameters_json) - .context("Failed to parse fm parameters")?; + let config: Config = serde_json::from_str(parameters_json) + .context("Failed to parse fm demod parameters")?; - dsp::rx_and_play_radio(device, &config)? + dsp::fm_demod::start(device, &config)? } _ => bail!("Unknown native task `{name}`"), }); @@ -63,7 +70,6 @@ impl FoxhunterState { // // foxhunterjni PANICKED: called `Result::unwrap()` on an `Err` value: Canceled, at /home/troy/foxhunter/FutureSDR/src/runtime/scheduler/smol.rs:81 - // Strangely if we call `connection.close()` (in kotlin) right after starting the // flowgraph (we dont hear anything of course, but) the crash doesnt happen. // Maybe something to do with raudio not initializing since no samples get through? diff --git a/FoxhunterJNI/foxhunterjni-rs/src/logger.rs b/FoxhunterJNI/foxhunterjni-rs/src/logger.rs index be2b3e4b..ef45dc09 100644 --- a/FoxhunterJNI/foxhunterjni-rs/src/logger.rs +++ b/FoxhunterJNI/foxhunterjni-rs/src/logger.rs @@ -1,24 +1,75 @@ use android_log_sys::LogPriority; +use anyhow::Context; +use jni::objects::{GlobalRef, JClass, JObject, JStaticMethodID, JString, JValueGen}; +use jni::signature::{Primitive, ReturnType}; +use jni::JavaVM; use log::{Level, Log, Metadata, Record}; use std::ffi::{CStr, CString}; use std::fmt; use std::io::Write; -pub struct AndroidLogger; - lazy_static::lazy_static! { static ref TAG: CString = CString::new("foxhunter_log_jni").unwrap(); } +pub struct AndroidLogger { + vm: JavaVM, + log_class: GlobalRef, + on_log: JStaticMethodID, +} + +impl AndroidLogger { + /// Creates a new logger which will forward [`log`] events to `log_class`. + /// + /// This function will return `Err(..)` if `log_class` doesn't contain a static `onLog` method + /// which takes a string and an int level and returns void. + /// This function will be called to redirect native logs to Java/Kotlin. + pub fn new(vm: JavaVM, log_class: JClass<'_>) -> anyhow::Result { + let mut env = vm.get_env().context("Failed to get jni env from vm")?; + + let sig = "(Ljava/lang/String;I)V"; + let name = "onLog"; + + let on_log = env + .get_static_method_id(&log_class, name, sig) + .with_context(|| { + env.exception_clear().ok(); + + let class_name = env + .call_method(&log_class, "getName", "()Ljava/lang/String;", &[]) + .map(|r| r.l().expect("Class::getName did not return object")) + .map(|o| { + let s: &JString = (&o).into(); + env.get_string(s).expect("Non UTF-8 class name").into() + }) + .unwrap_or_else(|_| { + env.exception_clear().ok(); + "".to_string() + }); + format!("Failed to find method `{name}` with signature {sig} in {class_name}") + })?; + + let log_class = env + .new_global_ref(&log_class) + .context("Failed to create global ref to log class")?; + + Ok(Self { + vm, + log_class, + on_log, + }) + } +} + /// Initalizes [`log`]'s global logger as the android logger, and sets the panic hook to also /// prin to the android log -pub fn init(min_level: log::LevelFilter) { - let logger = AndroidLogger; +pub fn init(vm: JavaVM, log_class: JClass<'_>, min_level: log::LevelFilter) -> anyhow::Result<()> { + let logger = AndroidLogger::new(vm, log_class)?; log::set_max_level(min_level); let logger = Box::leak(Box::new(logger)); - log::set_logger(logger).expect("global logger already set"); + log::set_logger(logger).context("global logger already set")?; // std::env::set_var("RUST_BACKTRACE", "full"); @@ -41,10 +92,12 @@ pub fn init(min_level: log::LevelFilter) { write_inner( LogPriority::FATAL, - format_args!("foxhunterjni PANICKED: {msg}, at {file}:{line}"), + format_args!("(panic hook) foxhunterjni PANICKED: {msg}, at {file}:{line}"), ); write_inner(LogPriority::FATAL, format_args!("")); + log::error!("(panic hook) foxhunterjni PANICKED: {msg}, at {file}:{line}"); + // Doesnt seem to work... // Trying to debug flowgraph exit segfault backtrace::trace(|frame| { @@ -87,6 +140,8 @@ pub fn init(min_level: log::LevelFilter) { })); log::info!("Rust natives initialized with min level {min_level:?}"); + + Ok(()) } impl Log for AndroidLogger { @@ -114,12 +169,60 @@ impl Log for AndroidLogger { Level::Trace => LogPriority::DEBUG, }; + let mut buf = std::io::Cursor::new([0u8; 4096]); // TOOD(troy): add extra context like line info etc. // Maybe take a page out of env_logger's playbook and use their formatting style - write_inner( - priority, - format_args!("{}:{} - {}", record.level(), record.target(), record.args()), - ) + let _ = buf.write_fmt(format_args!( + "{}:{} - {}", + record.level(), + record.target(), + record.args() + )); + + // Append null terminator or terminate at end of buffer + let null_index = std::cmp::min(buf.position() as usize, buf.get_ref().len() - 1); + buf.get_mut()[null_index] = 0x00; + + // SAFETY: just wrote the null byte at `null_index`. + let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(&buf.get_ref()[..null_index + 1]) }; + raw_log(priority, cstr); + + let msg = std::str::from_utf8(&buf.get_ref()[..null_index]) + .expect("Rust formatting produced non UTF-8 string"); + + if let Ok(mut env) = self.vm.get_env() { + env.with_local_frame(32, move |env| { + match env.new_string(msg) { + Ok(j_string) => { + let s: &JObject<'_> = &j_string; + let level = record.level() as usize; + // TODO: clear exception? + + // SAFETY: Existence of `on_log` with correct parameters method was checked at init. + let _ = unsafe { + env.call_static_method_unchecked( + &self.log_class, + &self.on_log, + ReturnType::Primitive(Primitive::Void), + &[ + JValueGen::Object(s).as_jni(), + JValueGen::::Int(level as i32).as_jni(), + ], + ) + }; + } + Err(e) => { + write_inner( + LogPriority::FATAL, + format_args!("Failed to create jstring: {e:?}",), + ); + } + } + // + jni::errors::Result::Ok(()) + }) + .expect("Local frame count exceeded"); + } } fn flush(&self) { @@ -128,14 +231,19 @@ impl Log for AndroidLogger { } fn write_inner(priority: LogPriority, args: fmt::Arguments) { - let mut buf = std::io::Cursor::new([0u8; 4096]); - let _ = write!(&mut buf, "{args}"); + let mut buf = std::io::Cursor::new([0u8; 1024]); + let _ = buf.write_fmt(args); + // Append null terminator or terminate at end of buffer let null_index = std::cmp::min(buf.position() as usize, buf.get_ref().len() - 1); buf.get_mut()[null_index] = 0x00; - // SAFETY: just wrote the null byte at the end - let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(&buf.get_ref()[..null_index + 1]) }; + raw_log( + priority, + CStr::from_bytes_with_nul(&buf.get_ref()[..null_index + 1]).unwrap(), + ); +} +fn raw_log(priority: LogPriority, cstr: &CStr) { unsafe { android_log_sys::__android_log_write(priority as i32, TAG.as_ptr(), cstr.as_ptr()) }; } diff --git a/FoxhunterJNI/proguard-rules.pro b/FoxhunterJNI/proguard-rules.pro index 481bb434..cfde5155 100644 --- a/FoxhunterJNI/proguard-rules.pro +++ b/FoxhunterJNI/proguard-rules.pro @@ -18,4 +18,5 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile +-keepclassmembers class ai.foxhunter.foxhunterjni.Foxhunter$NativeLogWrapper { *; } \ No newline at end of file diff --git a/FoxhunterJNI/src/main/java/ai/foxhunter/foxhunterjni/ALog.kt b/FoxhunterJNI/src/main/java/ai/foxhunter/foxhunterjni/ALog.kt index b830f4d7..9afc3c2e 100644 --- a/FoxhunterJNI/src/main/java/ai/foxhunter/foxhunterjni/ALog.kt +++ b/FoxhunterJNI/src/main/java/ai/foxhunter/foxhunterjni/ALog.kt @@ -1,25 +1,65 @@ package ai.foxhunter.foxhunterjni import android.util.Log +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow -const val TAG = "foxhunter-log" +const val TAG = "foxhunter_log" + +private const val MAX_LOG_ENTRIES = 1000 + +data class LogEntry(val level: LogLevel, val message: String) + +enum class LogLevel { + DEBUG, INFO, WARN, ERROR +} class ALog { companion object { - fun debug(s: String) { - Log.d(TAG, s) + private val logBuffer = ArrayDeque(MAX_LOG_ENTRIES) + private val _logBufferFlow = MutableStateFlow(logBuffer.toList()) + val logBufferFlow: StateFlow> = _logBufferFlow + + private fun addToBuffer(level: LogLevel, message: String) { + synchronized(logBuffer) { + if (logBuffer.size >= MAX_LOG_ENTRIES) { + logBuffer.removeFirst() + } + logBuffer.addLast(LogEntry(level, message)) + _logBufferFlow.value = logBuffer.toList() // Emit updated log list + } + } + + fun debug(s: String, print: Boolean = true) { + if (print) { + Log.d(TAG, s) + } + addToBuffer(LogLevel.DEBUG, s) + } + + fun info(s: String, print: Boolean = true) { + if (print) { + Log.i(TAG, s) + } + addToBuffer(LogLevel.INFO, s) } - fun info(s: String) { - Log.i(TAG, s) + fun warn(s: String, print: Boolean = true) { + if (print) { + Log.w(TAG, s) + } + addToBuffer(LogLevel.WARN, s) } - fun warn(s: String) { - Log.w(TAG, s) + fun error(s: String, print: Boolean = true) { + if (print) { + Log.e(TAG, s) + } + addToBuffer(LogLevel.ERROR, s) } - fun error(s: String) { - Log.e(TAG, s) + fun getLogs(): List { + return synchronized(logBuffer) { logBuffer.toList() } } } } \ No newline at end of file diff --git a/FoxhunterJNI/src/main/java/ai/foxhunter/foxhunterjni/Foxhunter.kt b/FoxhunterJNI/src/main/java/ai/foxhunter/foxhunterjni/Foxhunter.kt index df9807d0..6edf01c8 100644 --- a/FoxhunterJNI/src/main/java/ai/foxhunter/foxhunterjni/Foxhunter.kt +++ b/FoxhunterJNI/src/main/java/ai/foxhunter/foxhunterjni/Foxhunter.kt @@ -1,6 +1,5 @@ package ai.foxhunter.foxhunterjni -import android.util.Log import kotlinx.serialization.* import kotlinx.serialization.json.* import kotlin.jvm.Throws @@ -12,7 +11,12 @@ class Foxhunter { if (handle == 0L) { throw RuntimeException("Failed to initialize foxhunterjni") } - ALog.info("Initialized natives successfully") + val err = initLogging(NativeLogWrapper::class.java) + if (err != null) { + ALog.error("Failed to initialize native logging: $err") + } else { + ALog.info("Initialized natives successfully") + } } enum class NativeLogLevel { @@ -40,6 +44,21 @@ class Foxhunter { setLogLevel0(intLevel) } + class NativeLogWrapper { + companion object { + @JvmStatic + fun onLog(msg: String, level: Int) { + when (level) { + 1 -> ALog.error(msg, print = false) + 2 -> ALog.warn(msg, print = false) + 3 -> ALog.info(msg, print = false) + 4 -> ALog.debug(msg, print = false) + 5 -> ALog.debug(msg, print = false) + } + } + } + } + @Serializable data class FmDemodParameters( @SerialName("frequency_hz") val frequencyHz: Double, @@ -59,9 +78,7 @@ class Foxhunter { if (err == null) { ALog.info( "Started task successfully") } else { - ALog.error(err) - // Extract just the first line (cause) not the full anyhow chain which might be too long for a toast. - throw RuntimeException(err.split("\n", limit = 1).getOrNull(0)) + throw RuntimeException(err) } } @@ -84,6 +101,7 @@ class Foxhunter { companion object { @JvmStatic external fun init0(): Long + @JvmStatic external fun initLogging(clazz: Class): String? @JvmStatic external fun setLogLevel0(level: Int) @JvmStatic external fun startTask0(handle: Long, fd: Int, name: String, parametersJson: String): String? @JvmStatic external fun stopTask0(handle: Long): String? diff --git a/FoxhunterStandaloneAndroid/app/build.gradle.kts b/FoxhunterStandaloneAndroid/app/build.gradle.kts index 36afce37..a9518d5f 100644 --- a/FoxhunterStandaloneAndroid/app/build.gradle.kts +++ b/FoxhunterStandaloneAndroid/app/build.gradle.kts @@ -69,6 +69,7 @@ dependencies { implementation(libs.androidx.ui) implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.navigation.compose) implementation(libs.androidx.material3) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) diff --git a/FoxhunterStandaloneAndroid/app/src/main/java/ai/foxhunter/standalone/MainActivity.kt b/FoxhunterStandaloneAndroid/app/src/main/java/ai/foxhunter/standalone/MainActivity.kt index 7f5511c1..55265b94 100644 --- a/FoxhunterStandaloneAndroid/app/src/main/java/ai/foxhunter/standalone/MainActivity.kt +++ b/FoxhunterStandaloneAndroid/app/src/main/java/ai/foxhunter/standalone/MainActivity.kt @@ -2,6 +2,8 @@ package ai.foxhunter.standalone import ai.foxhunter.foxhunterjni.ALog import ai.foxhunter.foxhunterjni.Foxhunter +import ai.foxhunter.standalone.ui.ErrorDialog +import ai.foxhunter.standalone.ui.LogViewerScreen import ai.foxhunter.standalone.ui.theme.FoxhunterPrototypeTheme import android.annotation.SuppressLint import android.app.PendingIntent @@ -26,14 +28,22 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController class MainActivity: ComponentActivity() { val natives: Foxhunter = Foxhunter() init { - natives.setLogLevel(Foxhunter.NativeLogLevel.Info) + natives.setLogLevel(Foxhunter.NativeLogLevel.Debug) } override fun onNewIntent(intent: Intent) { @@ -42,6 +52,8 @@ class MainActivity: ComponentActivity() { } private lateinit var usbManager: UsbManager + var showDialog by mutableStateOf(false) + var errorMessage by mutableStateOf("") fun requestUsbPermissions() { val usbReceiver = object : BroadcastReceiver() { @@ -68,7 +80,8 @@ class MainActivity: ComponentActivity() { try { natives.startFmDemodTask(connection.fileDescriptor, parameters) } catch (e: Exception) { - Toast.makeText(context, "${e.message}", LENGTH_LONG).show() + errorMessage = e.message ?: "Unknown error" + showDialog = true } } } else { @@ -135,21 +148,41 @@ class MainActivity: ComponentActivity() { enableEdgeToEdge() setContent { FoxhunterPrototypeTheme { - Scaffold(modifier = Modifier.fillMaxSize()) { _ -> - Column { - Spacer(Modifier.height(20.dp)) - Text("Foxhunter radio prototype", modifier = Modifier.padding(5.dp)) - Text("Connect a hackrf to run the demo", modifier = Modifier.padding(5.dp)) - Button( - onClick = { - stopTask() - }, - content = { - Text("Stop task") - } - ) + val navController = rememberNavController() + + if (showDialog) { + ErrorDialog(errorMessage = errorMessage) { + showDialog = false } } + + NavHost(navController, startDestination = "main") { + composable("main") { MainScreen(navController, this@MainActivity) } + composable("logs") { LogViewerScreen() } + } + } + } + } +} + +@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") +@Composable +fun MainScreen(navController: NavController, mainActivity: MainActivity) { + Scaffold(modifier = Modifier.fillMaxSize()) { + Column { + Spacer(Modifier.height(20.dp)) + Text("Foxhunter radio prototype", modifier = Modifier.padding(5.dp)) + Text("Connect a radio to run the demo", modifier = Modifier.padding(5.dp)) + Button( + onClick = { + mainActivity.stopTask() + }, + content = { + Text("Stop task") + } + ) + Button(onClick = { navController.navigate("logs") }) { + Text("View Logs") } } } diff --git a/FoxhunterStandaloneAndroid/app/src/main/java/ai/foxhunter/standalone/ui/ErrorDialog.kt b/FoxhunterStandaloneAndroid/app/src/main/java/ai/foxhunter/standalone/ui/ErrorDialog.kt new file mode 100644 index 00000000..c0ec19ab --- /dev/null +++ b/FoxhunterStandaloneAndroid/app/src/main/java/ai/foxhunter/standalone/ui/ErrorDialog.kt @@ -0,0 +1,26 @@ +package ai.foxhunter.standalone.ui + +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.style.TextAlign + +@Composable +fun ErrorDialog(errorMessage: String, onDismiss: () -> Unit) { + AlertDialog( + onDismissRequest = onDismiss, + title = { Text(text = "Error") }, + text = { + Text( + text = errorMessage, + textAlign = TextAlign.Start + ) + }, + confirmButton = { + Button(onClick = onDismiss) { + Text("OK") + } + } + ) +} diff --git a/FoxhunterStandaloneAndroid/app/src/main/java/ai/foxhunter/standalone/ui/LogViewerScreen.kt b/FoxhunterStandaloneAndroid/app/src/main/java/ai/foxhunter/standalone/ui/LogViewerScreen.kt new file mode 100644 index 00000000..0bd6dd7f --- /dev/null +++ b/FoxhunterStandaloneAndroid/app/src/main/java/ai/foxhunter/standalone/ui/LogViewerScreen.kt @@ -0,0 +1,56 @@ +package ai.foxhunter.standalone.ui + +import ai.foxhunter.foxhunterjni.ALog +import ai.foxhunter.foxhunterjni.LogEntry +import ai.foxhunter.foxhunterjni.LogLevel +import android.annotation.SuppressLint +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.Checkbox +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") +@Composable +fun LogViewerScreen() { + var followLogs by remember { mutableStateOf(true) } + val logs by ALog.logBufferFlow.collectAsState() + + Scaffold( + modifier = Modifier.fillMaxSize().padding(10.dp) + ) { + Column { + Row(verticalAlignment = androidx.compose.ui.Alignment.CenterVertically) { + Text("Follow Logs", modifier = Modifier.padding(end = 8.dp)) + Checkbox( + checked = followLogs, + onCheckedChange = { followLogs = it } + ) + } + + Spacer(modifier = Modifier.height(10.dp)) + + LazyColumn( + modifier = Modifier.fillMaxSize().padding(8.dp), + ) { + items(logs.size) { logEntry -> + LogRow(logs[logEntry]) + } + } + } + } +} + +@Composable +fun LogRow(logEntry: LogEntry) { + val color = when (logEntry.level) { + LogLevel.DEBUG -> androidx.compose.ui.graphics.Color.Gray + LogLevel.INFO -> androidx.compose.ui.graphics.Color.Blue + LogLevel.WARN -> androidx.compose.ui.graphics.Color(255, 165, 0) + LogLevel.ERROR -> androidx.compose.ui.graphics.Color.Red + } + Text(text = "[${logEntry.level}] ${logEntry.message}", color = color) +} diff --git a/FoxhunterStandaloneAndroid/gradle/libs.versions.toml b/FoxhunterStandaloneAndroid/gradle/libs.versions.toml index 1d77cf2c..ab7c2b65 100644 --- a/FoxhunterStandaloneAndroid/gradle/libs.versions.toml +++ b/FoxhunterStandaloneAndroid/gradle/libs.versions.toml @@ -10,6 +10,7 @@ activityCompose = "1.9.0" composeBom = "2024.04.01" appcompat = "1.7.0" material = "1.12.0" +navigation = "2.8.1" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -25,6 +26,7 @@ androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } +androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } material = { group = "com.google.android.material", name = "material", version.ref = "material" } diff --git a/README.md b/README.md index 42335b49..d922d7a4 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ │   └── foxhunterjni-rs (rust bindings to JNI, calls into dsp/) ├── FoxhunterStandaloneAndroid (Standalone android app for Foxhunter, uses FoxhunterJNI to call into dsp/) ├── dsp-runner (Desktop-version of FoxhunterStandaloneAndroid. Calls into dsp/) -└── hackrfone (rusb/libusb driver code for Foxhunter) ``` ## Profiling diff --git a/data-gen/data-gen/Cargo.toml b/data-gen/data-gen/Cargo.toml index 09da5036..cc7fb3cb 100644 --- a/data-gen/data-gen/Cargo.toml +++ b/data-gen/data-gen/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -futuresdr = "0.0.37" +futuresdr = { workspace = true } tracing = "0.1.40" tracing-subscriber = "0.3.18" zigbee = { path = "../zigbee" } diff --git a/data-gen/zigbee/Cargo.toml b/data-gen/zigbee/Cargo.toml index c7926019..0b1f5931 100644 --- a/data-gen/zigbee/Cargo.toml +++ b/data-gen/zigbee/Cargo.toml @@ -3,8 +3,6 @@ name = "zigbee" version = "0.0.1" edition = "2021" -[features] - [dependencies] -futuresdr = "0.0.37" +futuresdr = { workspace = true } tracing = "0.1.40" diff --git a/dsp-runner/Cargo.toml b/dsp-runner/Cargo.toml index 45e81263..bfd5cd77 100644 --- a/dsp-runner/Cargo.toml +++ b/dsp-runner/Cargo.toml @@ -2,12 +2,15 @@ name = "dsp-runner" version = "0.1.0" edition = "2021" +description = "Entry point for foxhunter on desktop" [dependencies] -hackrfone = { path = "../hackrfone" } +anyhow = "1.0.93" dsp = { path = "../dsp" } +futuresdr = { workspace = true } +log = "0.4.22" +nusb = "0.1.11" pretty_env_logger = "0.5.0" -futuresdr = { git = "https://github.com/MerchGuardian/FutureSDr.git", branch = "android-fd", default-features = false, features = ["hackrfone", "audio"] } [target.'cfg(profile)'.dependencies] tracy-client = { workspace = true } diff --git a/dsp-runner/src/bin/fm_demod.rs b/dsp-runner/src/bin/fm_demod.rs new file mode 100644 index 00000000..c246a5a5 --- /dev/null +++ b/dsp-runner/src/bin/fm_demod.rs @@ -0,0 +1,57 @@ +#![deny(unsafe_code)] + +use std::os::fd::AsRawFd; + +use anyhow::Context; +use futuresdr::seify::{self, Args}; +use log::debug; + +fn main() -> anyhow::Result<()> { + let bladerf = nusb::list_devices() + .unwrap() + .find(|dev| dev.vendor_id() == 0x2cf0 && dev.product_id() == 0x5250) + .expect("bladerf not connected"); + + let dev_path = format!( + "/dev/bus/usb/{:03}/{:03}", + bladerf.bus_number(), + bladerf.device_address() + ); + + pretty_env_logger::init(); + debug!("Opening {dev_path}"); + + let file = std::fs::OpenOptions::new() + .read(true) + .write(true) + .open(dev_path) + .context("Failed to open device file")?; + + let fd = file.as_raw_fd(); + let mut args = Args::new(); + args.set("fd", fd.to_string()); + args.set("bladerf_log_level", "verbose"); + let dev = seify::Device::from_args(args).context("Failed to open radio")?; + + let config = dsp::fm_demod::Config { + gain: None, + // Mountain View Indian radio: https://bolly923fm.com/ + frequency_hz: 92_300_000.0, + sample_rate_hz: 2_000_000.0, + bandwidth_hz: Some(2_000_000.0), + audio_mult: None, + audio_rate: None, + }; + let mut handle = dsp::fm_demod::start(dev, &config).unwrap(); + + let mut line = String::new(); + std::io::stdin() + .read_line(&mut line) + .expect("Failed to read from stdin"); + + println!("Press enter to stop"); + futuresdr::async_io::block_on(handle.terminate_and_wait()) + .context("Failed to shutdown flowgraph")?; + + Ok(()) +} diff --git a/dsp-runner/src/bin/main.rs b/dsp-runner/src/bin/main.rs deleted file mode 100644 index 63b9a7d5..00000000 --- a/dsp-runner/src/bin/main.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![deny(unsafe_code)] -//! Analogous to `foxhunter-jni`, opens hackrf on using desktop libusb1 library, then calls into [`dsp`]. - -use futuresdr::seify; - -fn main() { - pretty_env_logger::init(); - let dev = seify::Device::new().expect("Failed to find hackrf"); - - let config = dsp::FmDemodConfig { - gain: 24.0, - frequency_hz: 90_100_000.0, - sample_rate_hz: 2_500_000.0, - audio_mult: None, - audio_rate: None, - }; - let mut handle = dsp::rx_and_play_radio(dev, &config).unwrap(); - - let mut line = String::new(); - std::io::stdin() - .read_line(&mut line) - .expect("Failed to read from stdin"); - - println!("Press enter to stop"); - futuresdr::async_io::block_on(handle.terminate_and_wait()) - .expect("Failed to shutdown flowgraph"); -} diff --git a/dsp/Cargo.toml b/dsp/Cargo.toml index 7558ba5f..e426de98 100644 --- a/dsp/Cargo.toml +++ b/dsp/Cargo.toml @@ -2,11 +2,12 @@ name = "dsp" version = "0.1.0" edition = "2021" +description = "Main crate for foxhunter" [dependencies] anyhow = "1.0.86" foxhunter-profile = { path = "../foxhunter-profile" } -futuresdr = { git = "https://github.com/MerchGuardian/FutureSDr.git", branch = "android-fd", default-features = false, features = ["hackrfone"] } +futuresdr = { workspace = true } log = "0.4.22" serde = "1.0.210" serde_json = "1.0.128" diff --git a/dsp/src/fm_demod.rs b/dsp/src/fm_demod.rs new file mode 100644 index 00000000..4fa4608b --- /dev/null +++ b/dsp/src/fm_demod.rs @@ -0,0 +1,185 @@ +#![deny(unsafe_code)] + +//! Invoked via foxhunter-jni` on android or `dsp-runner` on desktop. + +use anyhow::Result; +use futuresdr::runtime::FlowgraphHandle; +use futuresdr::seify::Device; +use futuresdr::seify::DeviceTrait; +use log::info; +use serde::{Deserialize, Serialize}; + +#[cfg(profile)] +#[global_allocator] +static GLOBAL: tracy_client::ProfiledAllocator = + tracy_client::ProfiledAllocator::new(std::alloc::System, 32); + +use futuresdr::blocks::audio::AudioSink; +use futuresdr::blocks::seify::SourceBuilder; +use futuresdr::blocks::Apply; +use futuresdr::blocks::FirBuilder; +use futuresdr::futuredsp::firdes; +use futuresdr::macros::connect; +use futuresdr::num_complex::Complex32; +use futuresdr::num_integer::gcd; +use futuresdr::runtime::Flowgraph; +use futuresdr::runtime::Runtime; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Config { + /// Gain to apply to the seify source. Uses AGC if unset and supported by the radio + pub gain: Option, + /// Center frequency + pub frequency_hz: f64, + pub bandwidth_hz: Option, + /// Sample rate + pub sample_rate_hz: f64, + /// Multiplier for intermedia sample rate + pub audio_mult: Option, + /// Audio Rate + pub audio_rate: Option, +} + +pub fn start( + device: Device, + c: &Config, +) -> Result { + info!( + "Using device: {:?}, driver: {:?}", + device.info()?, + device.driver() + ); + + // A simple FM receiver that you can tune to nearby radio stations + // + // When you run the example, it will build a flowgraph consisting of the following blocks: + // * SeifySource: Gets data from your SDR + // * Demodulator: Demodulates the FM signal + // * AudioSink: Plays the demodulated signal on your device + // + // After giving it some time to start up the SDR, it enters a loop where you will + // be periodically asked to enter a new frequency that the SDR will be tuned to. + // **Watch out** though: Some frequencies (very high or very low) might be unsupported + // by your SDR and may cause a crash. + + let sample_rate = c.sample_rate_hz as u32; + let freq_offset = c.sample_rate_hz / 4.0; + info!("Frequency Offset {freq_offset:?}"); + + let audio_rate = if let Some(r) = c.audio_rate { + r + } else { + let mut audio_rates = AudioSink::supported_sample_rates(); + assert!(!audio_rates.is_empty()); + audio_rates.sort_by_key(|a| std::cmp::Reverse(gcd(*a, sample_rate))); + info!("Supported Audio Rates {audio_rates:?}"); + audio_rates[0] + }; + info!("Selected Audio Rate {audio_rate:?}"); + + let audio_mult = if let Some(m) = c.audio_mult { + m + } else { + let mut m = 5; + while (m * audio_rate) as f64 > freq_offset + 100e3 { + m -= 1; + } + m + }; + info!("Audio Mult {audio_mult:?}"); + + // Create the `Flowgraph` where the `Block`s will be added later on + let mut fg = Flowgraph::new(); + + info!("Frequency {}", c.frequency_hz); + + // Create a new Seify SDR block with the given parameters + let mut builder = SourceBuilder::new() + .device(device) + .frequency(c.frequency_hz + freq_offset) + .sample_rate(c.sample_rate_hz); + + builder = match c.gain { + Some(gain) => { + info!("Setting manual gain to {gain}"); + builder.gain(gain) + } + None => { + info!("Enabling automatic gain control"); + builder.enable_agc() + } + }; + + if let Some(bandwidth_hz) = c.bandwidth_hz { + builder = builder.bandwidth(bandwidth_hz); + } + + let src = builder.build().expect("failed to create seify device"); + + // Store the `freq` port ID for later use + let _freq_port_id = src + .message_input_name_to_id("freq") + .expect("No freq port found!"); + + // Downsample before demodulation + let interp = (audio_rate * audio_mult) as usize; + let decim = sample_rate as usize; + info!("interp {interp} decim {decim}"); + let resamp1 = FirBuilder::resampling::(interp, decim); + + // Demodulation block using the conjugate delay method + // See https://en.wikipedia.org/wiki/Detector_(radio)#Quadrature_detector + let mut last = Complex32::new(0.0, 0.0); // store sample x[n-1] + let demod = Apply::new(move |v: &Complex32| -> f32 { + let arg = (v * last.conj()).arg(); // Obtain phase of x[n] * conj(x[n-1]) + last = *v; + arg + }); + + let mut last = Complex32::new(1.0, 0.0); + let add = Complex32::from_polar( + 1.0, + (2.0 * std::f64::consts::PI * freq_offset / c.sample_rate_hz) as f32, + ); + let shift = Apply::new(move |v: &Complex32| -> Complex32 { + last *= add; + last * v + }); + + // Design filter for the audio and decimate by 'audio_mult' + let cutoff = 2_000.0 / (audio_rate * audio_mult) as f64; + let transition = 10_000.0 / (audio_rate * audio_mult) as f64; + info!("cutoff {} transition {}", cutoff, transition); + + let audio_filter_taps = firdes::kaiser::lowpass::(cutoff, transition, 0.1); + let resamp2 = + FirBuilder::resampling_with_taps::(1, audio_mult as usize, audio_filter_taps); + + // Compute the de-emphasis filter coefficient + let rc = 75e-6; // De-emphasis time constant in seconds + let sample_rate_f32 = audio_rate as f32; // Convert audio rate to f32 + let alpha = 1.0 / (rc * sample_rate_f32 + 1.0); + info!("De-emphasis alpha {}", alpha); + + // Create the de-emphasis filter block + let mut y_prev = 0.0f32; + let deemph = Apply::new(move |x: &f32| -> f32 { + let y = (1.0 - alpha) * y_prev + alpha * (*x); + y_prev = y; + y + }); + + // Single-channel `AudioSink` with the downsampled rate (e.g., 48_000 Hz) + let snk = AudioSink::new(audio_rate, 1); + info!("Created AudioSink"); + + // Add all the blocks to the `Flowgraph` and connect them + connect!(fg, src > shift > resamp1 > demod > resamp2 > deemph > snk.in;); + + // Start the flowgraph and save the handle + let rt = Runtime::new(); + let (_res, handle) = rt.start_sync(fg); + info!("started flowgraph"); + + Ok(handle) +} diff --git a/dsp/src/lib.rs b/dsp/src/lib.rs index 725b25a5..b07a4d80 100644 --- a/dsp/src/lib.rs +++ b/dsp/src/lib.rs @@ -1,158 +1 @@ -#![deny(unsafe_code)] - -//! Main crate for foxhunter. -//! Invoked via foxhunter-jni` on android or `dsp-runner` on desktop. - -use anyhow::Result; -use futuresdr::runtime::FlowgraphHandle; -use futuresdr::seify::Device; -use futuresdr::seify::DeviceTrait; -use log::info; -use serde::{Deserialize, Serialize}; - -#[cfg(profile)] -#[global_allocator] -static GLOBAL: tracy_client::ProfiledAllocator = - tracy_client::ProfiledAllocator::new(std::alloc::System, 32); - -use futuresdr::blocks::audio::AudioSink; -use futuresdr::blocks::seify::SourceBuilder; -use futuresdr::blocks::Apply; -use futuresdr::blocks::FirBuilder; -use futuresdr::futuredsp::firdes; -use futuresdr::macros::connect; -use futuresdr::num_complex::Complex32; -use futuresdr::num_integer::gcd; -use futuresdr::runtime::Flowgraph; -use futuresdr::runtime::Runtime; - -#[derive(Debug, Serialize, Deserialize)] -pub struct FmDemodConfig { - /// Gain to apply to the seify source - pub gain: f64, - /// Center frequency - pub frequency_hz: f64, - /// Sample rate - pub sample_rate_hz: f64, - /// Multiplier for intermedia sample rate - pub audio_mult: Option, - /// Audio Rate - pub audio_rate: Option, -} - -pub fn rx_and_play_radio( - device: Device, - c: &FmDemodConfig, -) -> Result { - info!( - "Using device: {:?}, driver: {:?}", - device.info()?, - device.driver() - ); - - // A simple FM receiver that you can tune to nearby radio stations - // - // When you run the example, it will build a flowgraph consisting of the following blocks: - // * SeifySource: Gets data from your SDR - // * Demodulator: Demodulates the FM signal - // * AudioSink: Plays the demodulated signal on your device - // - // After giving it some time to start up the SDR, it enters a loop where you will - // be periodically asked to enter a new frequency that the SDR will be tuned to. - // **Watch out** though: Some frequencies (very high or very low) might be unsupported - // by your SDR and may cause a crash. - - let sample_rate = c.sample_rate_hz as u32; - let freq_offset = c.sample_rate_hz / 4.0; - info!("Frequency Offset {freq_offset:?}"); - - let audio_rate = if let Some(r) = c.audio_rate { - r - } else { - let mut audio_rates = AudioSink::supported_sample_rates(); - assert!(!audio_rates.is_empty()); - audio_rates.sort_by_key(|a| std::cmp::Reverse(gcd(*a, sample_rate))); - info!("Supported Audio Rates {audio_rates:?}"); - audio_rates[0] - }; - info!("Selected Audio Rate {audio_rate:?}"); - - let audio_mult = if let Some(m) = c.audio_mult { - m - } else { - let mut m = 5; - while (m * audio_rate) as f64 > freq_offset + 100e3 { - m -= 1; - } - m - }; - info!("Audio Mult {audio_mult:?}"); - - // Create the `Flowgraph` where the `Block`s will be added later on - let mut fg = Flowgraph::new(); - - info!("Frequency {}", c.frequency_hz); - - // Create a new Seify SDR block with the given parameters - let src = SourceBuilder::new() - .device(device) - .frequency(c.frequency_hz + freq_offset) - .sample_rate(c.sample_rate_hz) - .gain(c.gain) - .build() - .expect("failed to create seify device"); - - // Store the `freq` port ID for later use - let _freq_port_id = src - .message_input_name_to_id("freq") - .expect("No freq port found!"); - - // Downsample before demodulation - let interp = (audio_rate * audio_mult) as usize; - let decim = sample_rate as usize; - info!("interp {interp} decim {decim}"); - let resamp1 = FirBuilder::resampling::(interp, decim); - - // Demodulation block using the conjugate delay method - // See https://en.wikipedia.org/wiki/Detector_(radio)#Quadrature_detector - let mut last = Complex32::new(0.0, 0.0); // store sample x[n-1] - let demod = Apply::new(move |v: &Complex32| -> f32 { - let arg = (v * last.conj()).arg(); // Obtain phase of x[n] * conj(x[n-1]) - last = *v; - arg - }); - - let mut last = Complex32::new(1.0, 0.0); - let add = Complex32::from_polar( - 1.0, - (2.0 * std::f64::consts::PI * freq_offset / c.sample_rate_hz) as f32, - ); - let shift = Apply::new(move |v: &Complex32| -> Complex32 { - last *= add; - last * v - }); - - // Design filter for the audio and decimate by 5. - // Ideally, this should be a FM de-emphasis filter, but the following works. - let cutoff = 2_000.0 / (audio_rate * audio_mult) as f64; - let transition = 10_000.0 / (audio_rate * audio_mult) as f64; - info!("cutoff {cutoff} transition {transition}"); - - let audio_filter_taps = firdes::kaiser::lowpass::(cutoff, transition, 0.1); - let resamp2 = - FirBuilder::resampling_with_taps::(1, audio_mult as usize, audio_filter_taps); - - // Single-channel `AudioSink` with the downsampled rate (sample_rate / (8*5) = 48_000) - let snk = AudioSink::new(audio_rate, 1); - info!("Created AudioSink"); - - // Add all the blocks to the `Flowgraph`... - connect!(fg, src > shift > resamp1 > demod > resamp2 > snk.in;); - - // Start the flowgraph and save the handle - let rt = Runtime::new(); - let (_res, handle) = rt.start_sync(fg); - info!("started flowgraph"); - - Ok(handle) -} +pub mod fm_demod; diff --git a/flake.lock b/flake.lock index 3525bc3f..27821164 100644 --- a/flake.lock +++ b/flake.lock @@ -1,9 +1,70 @@ { "nodes": { + "bladerf": { + "inputs": { + "bladerf-src": "bladerf-src", + "flake-utils": "flake-utils_2", + "nixpkgs": [ + "nixpkgs" + ], + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1731782317, + "narHash": "sha256-HuUP67zBPRZjUIPUKAFOBXPSvvCU3RzR3TSw2Db9uu4=", + "path": "/Users/troyneubauer/foxhunter/seify-bladerf/", + "type": "path" + }, + "original": { + "path": "/Users/troyneubauer/foxhunter/seify-bladerf/", + "type": "path" + } + }, + "bladerf-src": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "bladerf", + "nixpkgs" + ] + }, + "locked": { + "dirtyRev": "e96269ebfef4138697b7283019f725ab63aa68ce-dirty", + "dirtyShortRev": "e96269eb-dirty", + "lastModified": 1731679544, + "narHash": "sha256-5NWQQg6Bo9jG+lReYsW3tMmZ1qvO6VolM8NsSK49wCs=", + "submodules": true, + "type": "git", + "url": "file:/home/troy/foxhunter/seify-bladerf/bladeRF" + }, + "original": { + "submodules": true, + "type": "git", + "url": "file:/home/troy/foxhunter/seify-bladerf/bladeRF" + } + }, "flake-utils": { "inputs": { "systems": "systems" }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, "locked": { "lastModified": 1710146030, "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", @@ -18,34 +79,36 @@ "type": "github" } }, - "nixpkgs": { + "flake-utils_3": { + "inputs": { + "systems": "systems_3" + }, "locked": { - "lastModified": 1725826545, - "narHash": "sha256-L64N1rpLlXdc94H+F6scnrbuEu+utC03cDDVvvJGOME=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "f4c846aee8e1e29062aa8514d5e0ab270f4ec2f9", + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "type": "github" }, "original": { - "owner": "NixOS", - "ref": "nixos-24.05", - "repo": "nixpkgs", + "owner": "numtide", + "repo": "flake-utils", "type": "github" } }, - "nixpkgs-unstable": { + "nixpkgs": { "locked": { - "lastModified": 1725634671, - "narHash": "sha256-v3rIhsJBOMLR8e/RNWxr828tB+WywYIoajrZKFM+0Gg=", - "owner": "nixos", + "lastModified": 1725826545, + "narHash": "sha256-L64N1rpLlXdc94H+F6scnrbuEu+utC03cDDVvvJGOME=", + "owner": "NixOS", "repo": "nixpkgs", - "rev": "574d1eac1c200690e27b8eb4e24887f8df7ac27c", + "rev": "f4c846aee8e1e29062aa8514d5e0ab270f4ec2f9", "type": "github" }, "original": { - "owner": "nixos", - "ref": "nixos-unstable", + "owner": "NixOS", + "ref": "nixos-24.05", "repo": "nixpkgs", "type": "github" } @@ -68,13 +131,35 @@ }, "root": { "inputs": { - "flake-utils": "flake-utils", + "bladerf": "bladerf", + "flake-utils": "flake-utils_3", "nixpkgs": "nixpkgs", "nixpkgs-unstable": "nixpkgs-unstable", - "rust-overlay": "rust-overlay" + "rust-overlay": "rust-overlay_2" } }, "rust-overlay": { + "inputs": { + "nixpkgs": [ + "bladerf", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1728095260, + "narHash": "sha256-X62hA5ivYLY5G5+mXI6l9eUDkgi6Wu/7QUrwXhJ09oo=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "d1d2532ab267cfe6e40dff73fbaf34436c406d26", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "rust-overlay_2": { "inputs": { "nixpkgs": [ "nixpkgs" @@ -108,6 +193,36 @@ "repo": "default", "type": "github" } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index cf9c72a5..9f36fe5a 100644 --- a/flake.nix +++ b/flake.nix @@ -4,6 +4,12 @@ nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable"; + bladerf = { + # url = "github:MerchGuardian/seify-bladerf?ref=master"; + url = "path:/Users/troyneubauer/foxhunter/seify-bladerf/"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + flake-utils.url = "github:numtide/flake-utils"; rust-overlay = { @@ -31,7 +37,7 @@ }; rust-pkgs = pkgs.rust-bin.stable.latest.default.override { extensions = [ "rust-analyzer" "rust-src" ]; - targets = [ "aarch64-linux-android" "armv7-linux-androideabi" ]; + targets = [ "aarch64-linux-android" ]; }; ndk-version = "25.1.8937393"; android = pkgs.androidenv.composeAndroidPackages { @@ -39,25 +45,22 @@ includeNDK = true; includeSources = true; ndkVersions = [ ndk-version ]; - cmakeVersions = [ "3.22.1" ]; platformVersions = [ "34" ]; - abiVersions = [ "armeabi-v7a" "arm64-v8a" ]; + abiVersions = [ "arm64-v8a" ]; }; android-sdk = android.androidsdk; - base-deps = [ + deps = [ rust-pkgs + pkgs.cargo-show-asm + pkgs.fish + pkgs.tree ] ++ pkgs.lib.optionals pkgs.stdenv.isLinux ([ - # fm-receiver example deps + # fm-demod example deps pkgs.alsa-lib pkgs.pkg-config - ]); - jdk = pkgs.jdk17; - dev-deps = with pkgs; [ - fish - tree - cargo-show-asm - ] ++ pkgs.lib.optionals pkgs.stdenv.isDarwin ( - # fm-receiver example deps + pkgs.gdb + ]) ++ pkgs.lib.optionals pkgs.stdenv.isDarwin ( + # fm-demod example deps with pkgs.darwin.apple_sdk.frameworks; [ Foundation AudioUnit @@ -67,35 +70,51 @@ pkgs.cargo-ndk android-sdk pkgs.gradle_8 - jdk + pkgs.jdk17 ]; + bladerf = { + inherit (inputs.bladerf.packages.${system}) xa4-bitstream fx3-firmware libbladerf libbladerf-android libusb-android; + }; src-path = ./.; - shell = jni: profiling: ci: gradle-build: pkgs.mkShell { + shell = android: profiling: pkgs.mkShell { CARGO_NET_GIT_FETCH_WITH_CLI = "true"; RUSTFLAGS = if profiling then "--cfg profile" else ""; - packages = base-deps - ++ (if jni then android-deps else []) - ++ (if profiling then [ pkgs.tracy ] else []) - ++ (if ci then [] else dev-deps); + packages = deps + ++ (if android then android-deps else []) + ++ (if profiling then [ pkgs.tracy ] else []); + + shellHook = + '' + export LIBCLANG_PATH="${pkgs.llvmPackages_14.clang.cc.lib}/lib"; + '' + (if android then '' + export ANDROID_SDK_ROOT=${android-sdk}/libexec/android-sdk; + export ANDROID_HOME=${android-sdk}/libexec/android-sdk; + export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/${ndk-version}/; + rm -f .androidsdk && ln -s $ANDROID_HOME .androidsdk - shellHook = '' - # - '' + (if jni then '' - export ANDROID_SDK_ROOT=${android-sdk}/libexec/android-sdk; - export ANDROID_HOME=${android-sdk}/libexec/android-sdk; - export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/${ndk-version}/; - rm -f .androidsdk && ln -s $ANDROID_HOME .androidsdk - '' else "" - ); + export BLADERF_INCLUDE_PATH="${bladerf.libbladerf-android}/include"; + export BLADERF_RS_FPGA_BITSTREAM_PATH="${bladerf.xa4-bitstream}"; + export BLADERF_LIB_PATH="${bladerf.libbladerf-android}/lib"; + export LIBUSB_LIB_PATH="${bladerf.libusb-android}/lib"; + export RUSTFLAGS="-L ${bladerf.libbladerf-android}/lib"; + '' else '' + # Desktop + export BLADERF_INCLUDE_PATH="${bladerf.libbladerf}/include"; + export BLADERF_RS_FPGA_BITSTREAM_PATH="${bladerf.xa4-bitstream}"; + export BLADERF_RS_FX3_FIRMWARE_PATH="${bladerf.fx3-firmware}"; + + export PATH="${bladerf.libbladerf}/bin:$PATH"; + export RUSTFLAGS="-L ${bladerf.libbladerf}/lib $RUSTFLAGS"; + ''); }; in { devShells = rec { - default = shell true false false false; - gradle-build = shell true false false true; - profile = shell false true false false; - ci = shell false false true false; - jni_ci = shell true true true false; + default = pkgs.mkShell { + shellHook = "echo 'ERROR: You must select a shell variant\nTry `nix develop .#android` or `nix develop .#desktop`'; exit 1"; + }; + android = shell true false; + desktop = shell false false; }; }); } diff --git a/hackrfone/Cargo.toml b/hackrfone/Cargo.toml deleted file mode 100644 index c11bc041..00000000 --- a/hackrfone/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "hackrfone" -version = "0.1.0" -edition = "2021" - -[dependencies] -rusb = { workspace = true } -num-complex = "0.4" -foxhunter-profile = { path = "../foxhunter-profile" } - -[target.'cfg(profile)'.dependencies] -tracy-client = { workspace = true } diff --git a/hackrfone/examples/info.rs b/hackrfone/examples/info.rs deleted file mode 100644 index fec2a151..00000000 --- a/hackrfone/examples/info.rs +++ /dev/null @@ -1,10 +0,0 @@ -use hackrfone::{HackRfOne, UnknownMode}; - -fn main() { - let radio: HackRfOne = - HackRfOne::new(rusb::Context::new().expect("Failed to create rusb Context")) - .expect("Failed to open HackRF One"); - println!("Board ID: {:?}", radio.board_id()); - println!("Version: {:?}", radio.version()); - println!("Device version: {:?}", radio.device_version()); -} diff --git a/hackrfone/examples/rx.rs b/hackrfone/examples/rx.rs deleted file mode 100644 index 4f29948b..00000000 --- a/hackrfone/examples/rx.rs +++ /dev/null @@ -1,98 +0,0 @@ -use hackrfone::{num_complex::Complex32, HackRfOne, RxConfig, RxMode, UnknownMode}; -use std::{ - sync::mpsc::{self, TryRecvError}, - thread, -}; - -fn main() { - let mut radio: HackRfOne = - HackRfOne::new(rusb::Context::new().expect("Failed to create Hackrf Context")) - .expect("Failed to open HackRF One"); - - println!("Opened Hackrf"); - println!(" Board ID: {:?}", radio.board_id()); - println!(" Version: {:?}", radio.version()); - println!(" Device version: {:?}", radio.device_version()); - - const FC: u64 = 2_410_000_000; - - radio.set_freq(FC).expect("Failed to set frequency"); - radio - .set_amp_enable(true) - .expect("Failed to disable amplifier"); - radio - .set_antenna_enable(0) - .expect("Failed to disable antenna"); - - let mut radio: HackRfOne = radio - .into_rx_mode(RxConfig::default()) - .expect("Failed to enter RX mode"); - - let (data_tx, data_rx) = mpsc::channel(); - let (exit_tx, exit_rx) = mpsc::channel(); - - let sample_thread = thread::Builder::new() - .name("sample".to_string()) - .spawn(move || -> Result<(), hackrfone::Error> { - println!("Spawned sample thread"); - - const MTU: usize = 128 * 1024; - loop { - let mut buf = vec![0u8; MTU]; - let n = radio.rx(&mut buf)?; - assert_eq!(n, buf.len()); - data_tx - .send(buf) - .expect("Failed to send buffer from sample thread"); - - match exit_rx.try_recv() { - Ok(_) => { - println!("Got shutdown request"); - radio.stop_rx()?; - return Ok(()); - } - Err(TryRecvError::Disconnected) => { - println!("Main thread disconnected"); - return Ok(()); - } - Err(TryRecvError::Empty) => {} - } - } - }) - .expect("Failed to spawn sample thread"); - - const NUM_SAMPLES: usize = 1024 * 1024; - let mut capture_buf: Vec = Vec::with_capacity(NUM_SAMPLES); - - loop { - match data_rx.try_recv() { - Ok(buf) => buf.chunks_exact(2).for_each(|iq| { - capture_buf.push(num_complex::Complex::new( - iq[0] as i8 as f32, - iq[1] as i8 as f32, - )); - }), - Err(TryRecvError::Disconnected) => { - println!("Sample thread disconnected"); - break; - } - Err(TryRecvError::Empty) => {} - } - - if capture_buf.len() >= NUM_SAMPLES { - println!("GOT {:#?} samples", &capture_buf[..1000]); - break; - } - } - - println!("Shutting down sample thread"); - - if let Err(e) = exit_tx.send(()) { - println!("Failed to send exit event (receiver disconnected): {}", e); - } - - sample_thread - .join() - .expect("Failed to join sample thread") - .expect("Sample thread returned an error"); -} diff --git a/hackrfone/src/lib.rs b/hackrfone/src/lib.rs deleted file mode 100644 index 6cd97698..00000000 --- a/hackrfone/src/lib.rs +++ /dev/null @@ -1,782 +0,0 @@ -#![deny(unsafe_code)] - -//! HackRF One API. -//! -//! To get started take a look at [`HackRfOne::new`]. -#![cfg_attr(docsrs, feature(doc_cfg), feature(doc_auto_cfg))] -#![warn(missing_docs)] - -pub use rusb; - -use foxhunter_profile::profile; -use rusb::{request_type, Context, Direction, Recipient, RequestType, UsbContext, Version}; -use std::time::Duration; - -pub use num_complex; - -/// HackRF USB vendor ID. -const HACKRF_USB_VID: u16 = 0x1D50; -/// HackRF One USB product ID. -const HACKRF_ONE_USB_PID: u16 = 0x6089; - -#[allow(dead_code)] -#[repr(u8)] -enum Request { - SetTransceiverMode = 1, - Max2837Write = 2, - Max2837Read = 3, - Si5351CWrite = 4, - Si5351CRead = 5, - SampleRateSet = 6, - BasebandFilterBandwidthSet = 7, - Rffc5071Write = 8, - Rffc5071Read = 9, - SpiflashErase = 10, - SpiflashWrite = 11, - SpiflashRead = 12, - BoardIdRead = 14, - VersionStringRead = 15, - SetFreq = 16, - AmpEnable = 17, - BoardPartidSerialnoRead = 18, - SetLnaGain = 19, - SetVgaGain = 20, - SetTxvgaGain = 21, - AntennaEnable = 23, - SetFreqExplicit = 24, - UsbWcidVendorReq = 25, - InitSweep = 26, - OperacakeGetBoards = 27, - OperacakeSetPorts = 28, - SetHwSyncMode = 29, - Reset = 30, - OperacakeSetRanges = 31, - ClkoutEnable = 32, - SpiflashStatus = 33, - SpiflashClearStatus = 34, - OperacakeGpioTest = 35, - CpldChecksum = 36, - UiEnable = 37, -} - -impl From for u8 { - fn from(r: Request) -> Self { - r as u8 - } -} - -#[allow(dead_code)] -#[repr(u8)] -enum TranscieverMode { - Off = 0, - Receive = 1, - Transmit = 2, - Ss = 3, - CpldUpdate = 4, - RxSweep = 5, -} - -impl From for u8 { - fn from(tm: TranscieverMode) -> Self { - tm as u8 - } -} - -impl From for u16 { - fn from(tm: TranscieverMode) -> Self { - tm as u16 - } -} - -/// HackRF One errors. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum Error { - /// USB error. - Usb(rusb::Error), - /// Failed to transfer all bytes in a control transfer. - CtrlTransfer { - /// Control transfer direction. - dir: Direction, - /// Actual amount of bytes transferred. - actual: usize, - /// Excepted number of bytes transferred. - expected: usize, - }, - /// An API call is not supported by your hardware. - /// - /// Try updating the firmware on your device. - Version { - /// Current device version. - device: Version, - /// Minimum version required. - min: Version, - }, - /// A provided argument was out of range. - Argument, -} - -impl From for Error { - fn from(e: rusb::Error) -> Self { - Error::Usb(e) - } -} - -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl std::error::Error for Error {} - -/// Typestate for TX mode. -#[derive(Debug)] -pub struct TxMode; - -/// Typestate for RX mode. -#[derive(Debug)] -pub struct RxMode; - -/// Typestate for an unknown mode. -#[derive(Debug)] -pub struct UnknownMode; - -/// Configuration for TX gain settings -/// The LNA is always turned off for TX operations -#[derive(Debug)] -pub struct TxConfig { - /// Baseband gain, 0-62dB in 2dB increments - pub vga_db: u16, - - /// 0 - 47 dB in 1dB increments - pub txvga_db: u16, - - /// RF amplifier (on/off) - pub amp_enable: bool, - - /// Antenna power port control. Suspected range 0-1 (off-on) - pub antenna_enable: u8, - - /// Frequency in hz - pub frequency_hz: u64, -} - -impl Default for TxConfig { - fn default() -> Self { - Self { - vga_db: 16, - txvga_db: 40, - amp_enable: true, - antenna_enable: 1, - // set within ITU americas 900mhz ISM - // as punishment for calling ::default() - frequency_hz: 908_000_000, - } - } -} - -/// Configuration for RX gain settings -/// The TXVGA is always turned off for RX operations -#[derive(Debug)] -pub struct RxConfig { - /// Baseband gain, 0-62dB in 2dB increments - pub vga_db: u16, - - /// Low-noise amplifier gain, in 0-40dB in 8dB increments - pub lna_db: u16, - - /// RF amplifier (on/off) - pub amp_enable: bool, - - /// Antenna power port control. Suspected range 0-1 (off-on) - pub antenna_enable: u8, - - /// Frequency in hz - pub frequency_hz: u64, -} - -impl Default for RxConfig { - fn default() -> Self { - Self { - vga_db: 8, - lna_db: 16, - amp_enable: true, - antenna_enable: 1, - // set within global 900mhz ISM band to avoid sending our engineers to foreign prisons - // as punishment for calling ::default() - frequency_hz: 908_000_000, - } - } -} - -/// HackRF One software defined radio. -pub struct HackRfOne { - dh: rusb::DeviceHandle, - desc: rusb::DeviceDescriptor, - #[allow(dead_code)] - mode: MODE, - to: Duration, -} - -impl HackRfOne { - /// Open a new HackRF One. - /// - /// # Example - /// - /// ```no_run - /// use hackrfone::{HackRfOne, UnknownMode}; - /// - /// let mut radio: HackRfOne = HackRfOne::new(rusb::Context::new().unwrap()).unwrap(); - /// ``` - pub fn new(ctx: Context) -> Option> { - let devices = match ctx.devices() { - Ok(d) => d, - Err(_) => return None, - }; - - for device in devices.iter() { - let desc = match device.device_descriptor() { - Ok(d) => d, - Err(_) => continue, - }; - - if desc.vendor_id() == HACKRF_USB_VID && desc.product_id() == HACKRF_ONE_USB_PID { - match device.open() { - Ok(handle) => { - return Some(HackRfOne { - dh: handle, - desc, - mode: UnknownMode, - to: Duration::from_secs(1), - }) - } - Err(_) => continue, - } - } - } - - None - } - - /** - * Wraps an rusb device for use on Android etc. - */ - pub fn wrap( - handle: rusb::DeviceHandle, - desc: rusb::DeviceDescriptor, - ) -> HackRfOne { - HackRfOne { - dh: handle, - desc, - mode: UnknownMode, - to: Duration::from_secs(1), - } - } -} - -impl HackRfOne { - fn read_control( - &self, - request: Request, - value: u16, - index: u16, - ) -> Result<[u8; N], Error> { - let mut buf: [u8; N] = [0; N]; - let n: usize = self.dh.read_control( - request_type(Direction::In, RequestType::Vendor, Recipient::Device), - request.into(), - value, - index, - &mut buf, - self.to, - )?; - if n != buf.len() { - Err(Error::CtrlTransfer { - dir: Direction::In, - actual: n, - expected: buf.len(), - }) - } else { - Ok(buf) - } - } - - fn write_control( - &mut self, - request: Request, - value: u16, - index: u16, - buf: &[u8], - ) -> Result<(), Error> { - let n: usize = self.dh.write_control( - request_type(Direction::Out, RequestType::Vendor, Recipient::Device), - request.into(), - value, - index, - buf, - self.to, - )?; - if n != buf.len() { - Err(Error::CtrlTransfer { - dir: Direction::Out, - actual: n, - expected: buf.len(), - }) - } else { - Ok(()) - } - } - - fn check_api_version(&self, min: Version) -> Result<(), Error> { - fn version_to_u32(v: Version) -> u32 { - ((v.major() as u32) << 16) | ((v.minor() as u32) << 8) | (v.sub_minor() as u32) - } - - let v: Version = self.device_version(); - let v_cmp: u32 = version_to_u32(v); - let min_cmp: u32 = version_to_u32(min); - - if v_cmp >= min_cmp { - Ok(()) - } else { - Err(Error::Version { device: v, min }) - } - } - - /// Get the device version from the USB descriptor. - /// - /// The HackRF C API calls the equivalent of this function - /// `hackrf_usb_api_version_read`. - /// - /// # Example - /// - /// ```no_run - /// use hackrfone::{rusb, HackRfOne, UnknownMode}; - /// - /// let mut radio: HackRfOne = HackRfOne::new(rusb::Context::new().unwrap()).unwrap(); - /// assert_eq!(radio.device_version(), rusb::Version(1, 0, 4)); - /// ``` - pub fn device_version(&self) -> Version { - self.desc.device_version() - } - - /// Set the timeout for USB transfers. - /// - /// # Example - /// - /// Set a 100ms timeout. - /// - /// ```no_run - /// use hackrfone::{HackRfOne, UnknownMode}; - /// use std::time::Duration; - /// - /// let mut radio: HackRfOne = HackRfOne::new(rusb::Context::new().unwrap()).unwrap(); - /// radio.set_timeout(Duration::from_millis(100)) - /// ``` - pub fn set_timeout(&mut self, duration: Duration) { - self.to = duration; - } - - /// Read the board ID. - /// - /// # Example - /// - /// ```no_run - /// use hackrfone::{HackRfOne, UnknownMode}; - /// - /// let mut radio: HackRfOne = HackRfOne::new(rusb::Context::new().unwrap()).unwrap(); - /// assert_eq!(radio.board_id()?, 0x02); - /// # Ok::<(), hackrfone::Error>(()) - /// ``` - pub fn board_id(&self) -> Result { - let data: [u8; 1] = self.read_control(Request::BoardIdRead, 0, 0)?; - Ok(data[0]) - } - - /// Read the firmware version. - pub fn version(&self) -> Result { - let mut buf: [u8; 16] = [0; 16]; - let n: usize = self.dh.read_control( - request_type(Direction::In, RequestType::Vendor, Recipient::Device), - Request::VersionStringRead.into(), - 0, - 0, - &mut buf, - self.to, - )?; - Ok(String::from_utf8_lossy(&buf[0..n]).into()) - } - - /// Set the center frequency. - /// - /// # Example - /// - /// Set the frequency to 915MHz. - /// - /// ```no_run - /// use hackrfone::{HackRfOne, UnknownMode}; - /// - /// let mut radio: HackRfOne = HackRfOne::new(rusb::Context::new().unwrap()).unwrap(); - /// radio.set_freq(915_000_000)?; - /// # Ok::<(), hackrfone::Error>(()) - /// ``` - pub fn set_freq(&mut self, hz: u64) -> Result<(), Error> { - let buf: [u8; 8] = freq_params(hz); - self.write_control(Request::SetFreq, 0, 0, &buf) - } - - /// Enable the RX/TX RF amplifier. - /// - /// In GNU radio this is used as the RF gain, where a value of 0 dB is off, - /// and a value of 14 dB is on. - /// - /// # Example - /// - /// Disable the amplifier. - /// - /// ```no_run - /// use hackrfone::{HackRfOne, UnknownMode}; - /// - /// let mut radio: HackRfOne = HackRfOne::new(rusb::Context::new().unwrap()).unwrap(); - /// radio.set_amp_enable(false)?; - /// # Ok::<(), hackrfone::Error>(()) - /// ``` - pub fn set_amp_enable(&mut self, enable: bool) -> Result<(), Error> { - self.write_control(Request::AmpEnable, enable.into(), 0, &[]) - } - - /// Set the baseband filter bandwidth. - /// - /// This is automatically set when the sample rate is changed with - /// [`set_sample_rate`]. - /// - /// # Example - /// - /// Set the filter bandwidth to 70% of the sample rate. - /// - /// ```no_run - /// use hackrfone::{HackRfOne, UnknownMode}; - /// - /// const SAMPLE_HZ: u32 = 20_000_000; - /// const SAMPLE_DIV: u32 = 2; - /// const FILTER_BW: u32 = (0.7 * (SAMPLE_HZ as f32) / (SAMPLE_DIV as f32)) as u32; - /// - /// let mut radio: HackRfOne = HackRfOne::new(rusb::Context::new().unwrap()).unwrap(); - /// radio.set_sample_rate(SAMPLE_HZ, SAMPLE_DIV)?; - /// radio.set_baseband_filter_bandwidth(FILTER_BW)?; - /// # Ok::<(), hackrfone::Error>(()) - /// ``` - /// - /// [`set_sample_rate`]: crate::HackRfOne::set_sample_rate - pub fn set_baseband_filter_bandwidth(&mut self, hz: u32) -> Result<(), Error> { - self.write_control( - Request::BasebandFilterBandwidthSet, - (hz & 0xFFFF) as u16, - (hz >> 16) as u16, - &[], - ) - } - - /// Set the sample rate. - /// - /// For anti-aliasing, the baseband filter bandwidth is automatically set to - /// the widest available setting that is no more than 75% of the sample rate. - /// This happens every time the sample rate is set. - /// If you want to override the baseband filter selection, you must do so - /// after setting the sample rate. - /// - /// Limits are 8MHz - 20MHz. - /// Preferred rates are 8, 10, 12.5, 16, 20MHz due to less jitter. - /// - /// # Example - /// - /// Set the sample rate to 10 MHz. - /// - /// ```no_run - /// use hackrfone::{HackRfOne, UnknownMode}; - /// - /// let mut radio: HackRfOne = HackRfOne::new(rusb::Context::new().unwrap()).unwrap(); - /// radio.set_sample_rate(20_000_000, 2)?; - /// # Ok::<(), hackrfone::Error>(()) - /// ``` - pub fn set_sample_rate(&mut self, hz: u32, div: u32) -> Result<(), Error> { - let hz: u32 = hz.to_le(); - let div: u32 = div.to_le(); - let buf: [u8; 8] = [ - (hz & 0xFF) as u8, - ((hz >> 8) & 0xFF) as u8, - ((hz >> 16) & 0xFF) as u8, - ((hz >> 24) & 0xFF) as u8, - (div & 0xFF) as u8, - ((div >> 8) & 0xFF) as u8, - ((div >> 16) & 0xFF) as u8, - ((div >> 24) & 0xFF) as u8, - ]; - self.write_control(Request::SampleRateSet, 0, 0, &buf)?; - self.set_baseband_filter_bandwidth((0.75 * (hz as f32) / (div as f32)) as u32) - } - - /// Set the LNA (low noise amplifier) gain. - /// - /// Range 0 to 40dB in 8dB steps. - /// - /// This is also known as the IF gain. - /// - /// # Example - /// - /// Set the LNA gain to 16 dB (generally a reasonable gain to start with). - /// - /// ```no_run - /// use hackrfone::{HackRfOne, UnknownMode}; - /// - /// let mut radio: HackRfOne = HackRfOne::new(rusb::Context::new().unwrap()).unwrap(); - /// radio.set_lna_gain(16)?; - /// # Ok::<(), hackrfone::Error>(()) - /// ``` - pub fn set_lna_gain(&mut self, gain: u16) -> Result<(), Error> { - if gain > 40 { - Err(Error::Argument) - } else { - let buf: [u8; 1] = self.read_control(Request::SetLnaGain, 0, gain & !0x07)?; - if buf[0] == 0 { - Err(Error::Argument) - } else { - Ok(()) - } - } - } - - /// Set the VGA (variable gain amplifier) gain. - /// - /// Range 0 to 62dB in 2dB steps. - /// - /// This is also known as the baseband (BB) gain. - /// - /// # Example - /// - /// Set the VGA gain to 16 dB (generally a reasonable gain to start with). - /// - /// - /// ```no_run - /// use hackrfone::{HackRfOne, UnknownMode}; - /// - /// let mut radio: HackRfOne = HackRfOne::new(rusb::Context::new().unwrap()).unwrap(); - /// radio.set_vga_gain(16)?; - /// # Ok::<(), hackrfone::Error>(()) - /// ``` - pub fn set_vga_gain(&mut self, gain: u16) -> Result<(), Error> { - if gain > 62 || gain % 2 == 1 { - Err(Error::Argument) - } else { - let buf: [u8; 1] = self.read_control(Request::SetVgaGain, 0, gain & !0b1)?; - if buf[0] == 0 { - Err(Error::Argument) - } else { - Ok(()) - } - } - } - - /// Set the transmit VGA gain. - /// - /// Range 0 to 47dB in 1db steps. - pub fn set_txvga_gain(&mut self, gain: u16) -> Result<(), Error> { - if gain > 47 { - Err(Error::Argument) - } else { - let buf: [u8; 1] = self.read_control(Request::SetTxvgaGain, 0, gain)?; - if buf[0] == 0 { - Err(Error::Argument) - } else { - Ok(()) - } - } - } - - /// Antenna power port control. Dhruv's guess: is this DC bias? - /// - /// The source docs are a little lacking in terms of explanations here. - pub fn set_antenna_enable(&mut self, value: u8) -> Result<(), Error> { - self.write_control(Request::AntennaEnable, value.into(), 0, &[]) - } - - /// CLKOUT enable. - /// - /// The source docs are a little lacking in terms of explanations here. - pub fn set_clkout_enable(&mut self, en: bool) -> Result<(), Error> { - self.check_api_version(Version::from_bcd(0x0103))?; - self.write_control(Request::ClkoutEnable, en.into(), 0, &[]) - } - - /// Reset the HackRF radio. - /// - /// # Example - /// - /// ```no_run - /// use hackrfone::{HackRfOne, UnknownMode}; - /// - /// let mut radio: HackRfOne = HackRfOne::new(rusb::Context::new().unwrap()).unwrap(); - /// let mut radio: HackRfOne = radio.reset()?; - /// # Ok::<(), hackrfone::Error>(()) - /// ``` - pub fn reset(mut self) -> Result, Error> { - self.check_api_version(Version::from_bcd(0x0102))?; - self.write_control(Request::Reset, 0, 0, &[])?; - Ok(HackRfOne { - dh: self.dh, - desc: self.desc, - mode: UnknownMode, - to: self.to, - }) - } - - fn set_transceiver_mode(&mut self, mode: TranscieverMode) -> Result<(), Error> { - self.write_control(Request::SetTransceiverMode, mode.into(), 0, &[]) - } - - /// Change the radio mode to RX. - pub fn into_rx_mode(mut self, config: RxConfig) -> Result, Error> { - self.set_freq(config.frequency_hz)?; - self.set_vga_gain(config.vga_db)?; - self.set_txvga_gain(0)?; - self.set_amp_enable(config.amp_enable)?; - self.set_antenna_enable(config.antenna_enable)?; - - self.set_transceiver_mode(TranscieverMode::Receive)?; - self.dh.claim_interface(0)?; - Ok(HackRfOne { - dh: self.dh, - desc: self.desc, - mode: RxMode, - to: self.to, - }) - } - - /// Changes the radio mode to TX - pub fn into_tx_mode(mut self, config: TxConfig) -> Result, Error> { - self.set_lna_gain(0)?; - self.set_vga_gain(config.vga_db)?; - self.set_txvga_gain(config.txvga_db)?; - self.set_freq(config.frequency_hz)?; - self.set_amp_enable(config.amp_enable)?; - self.set_antenna_enable(config.antenna_enable)?; - - self.set_transceiver_mode(TranscieverMode::Transmit)?; - self.dh.claim_interface(0)?; //released when devh goes out of scope. may pose an issue when - //switching between rx and tx - Ok(HackRfOne { - dh: self.dh, - desc: self.desc, - mode: TxMode, - to: self.to, - }) - } -} - -impl HackRfOne { - /// Transmit samples - /// - /// Set gain, frequency and sample rate before calling - /// - /// Samples are interleaved 8 bit I&Q samples - /// - /// # Panics - /// This function will panic if samples is not a multiple of 512 in length - #[profile] - pub fn tx(&mut self, samples: &[u8]) -> Result { - const ENDPOINT: u8 = 0x02; - - if samples.len() % 512 != 0 { - panic!("samples must be a multiple of 512"); - } - - self.dh - .write_bulk(ENDPOINT, samples, Duration::from_millis(1)) - .map_err(Error::Usb) - } - - /// Stop Transmitting. - pub fn stop_tx(mut self) -> Result, Error> { - self.dh.release_interface(0)?; - self.set_transceiver_mode(TranscieverMode::Off)?; - Ok(HackRfOne { - dh: self.dh, - desc: self.desc, - mode: UnknownMode, - to: self.to, - }) - } -} - -impl HackRfOne { - /// Receive data from the radio. - /// - /// This uses a bulk transfer to get one MTU (maximum transmission unit) - /// of data in a single shot. The data format is pairs of signed 8-bit IQ. - /// - /// Unlike `libhackrf` this does not spawn a sampling thread. - #[profile] - pub fn rx(&mut self, buf: &mut [u8]) -> Result { - const ENDPOINT: u8 = 0x81; - let n = self.dh.read_bulk(ENDPOINT, buf, self.to)?; - Ok(n) - } - - /// Stop receiving. - pub fn stop_rx(mut self) -> Result, Error> { - self.dh.release_interface(0)?; - self.set_transceiver_mode(TranscieverMode::Off)?; - Ok(HackRfOne { - dh: self.dh, - desc: self.desc, - mode: UnknownMode, - to: self.to, - }) - } -} - -// Helper for set_freq -fn freq_params(hz: u64) -> [u8; 8] { - const MHZ: u64 = 1_000_000; - - let l_freq_mhz: u32 = u32::try_from(hz / MHZ).unwrap_or(u32::MAX).to_le(); - let l_freq_hz: u32 = u32::try_from(hz - u64::from(l_freq_mhz) * MHZ) - .unwrap_or(u32::MAX) - .to_le(); - - [ - (l_freq_mhz & 0xFF) as u8, - ((l_freq_mhz >> 8) & 0xFF) as u8, - ((l_freq_mhz >> 16) & 0xFF) as u8, - ((l_freq_mhz >> 24) & 0xFF) as u8, - (l_freq_hz & 0xFF) as u8, - ((l_freq_hz >> 8) & 0xFF) as u8, - ((l_freq_hz >> 16) & 0xFF) as u8, - ((l_freq_hz >> 24) & 0xFF) as u8, - ] -} - -#[cfg(test)] -mod test { - use super::freq_params; - - #[test] - fn nominal() { - assert_eq!(freq_params(915_000_000), [0x93, 0x03, 0, 0, 0, 0, 0, 0]); - assert_eq!(freq_params(915_000_001), [0x93, 0x03, 0, 0, 1, 0, 0, 0]); - assert_eq!( - freq_params(123456789), - [0x7B, 0, 0, 0, 0x55, 0xF8, 0x06, 0x00] - ); - } - - #[test] - fn min() { - assert_eq!(freq_params(0), [0; 8]); - } - - #[test] - fn max() { - assert_eq!(freq_params(u64::MAX), [0xFF; 8]); - } -}