]> git.rkrishnan.org Git - pihpsdr.git/commitdiff
a simple demonstration of calling rust from C with cbindgen
authorRamakrishnan Muthukrishnan <ram@rkrishnan.org>
Fri, 6 Dec 2024 18:45:24 +0000 (00:15 +0530)
committerRamakrishnan Muthukrishnan <ram@rkrishnan.org>
Fri, 6 Dec 2024 18:45:24 +0000 (00:15 +0530)
hpsdr_discovery.c [new file with mode: 0644]
rust/Cargo.lock [new file with mode: 0644]
rust/Cargo.toml [new file with mode: 0644]
rust/discovery/Cargo.toml [new file with mode: 0644]
rust/discovery/build.rs [new file with mode: 0644]
rust/discovery/cbindgen.toml [new file with mode: 0644]
rust/discovery/src/discovery.rs [new file with mode: 0644]
rust/discovery/src/ffi.rs [new file with mode: 0644]
rust/discovery/src/lib.rs [new file with mode: 0644]
rust/discovery/src/types.rs [new file with mode: 0644]

diff --git a/hpsdr_discovery.c b/hpsdr_discovery.c
new file mode 100644 (file)
index 0000000..cd87690
--- /dev/null
@@ -0,0 +1,16 @@
+// main.c
+#include "hpsdr_discovery.h"
+#include <stdio.h>
+
+int main() {
+    struct CFfiDiscoveredDevice devices[16];
+    int count = discover_devices_ffi(devices, 16);
+    
+    for (int i = 0; i < count; i++) {
+        printf("Found device: %s\n", devices[i].name);
+    }
+
+    list_interfaces_ffi();
+
+    return 0;
+}
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
new file mode 100644 (file)
index 0000000..3840937
--- /dev/null
@@ -0,0 +1,682 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "addr2line"
+version = "0.24.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+
+[[package]]
+name = "anstream"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
+dependencies = [
+ "anstyle",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "backtrace"
+version = "0.3.74"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
+dependencies = [
+ "addr2line",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+ "windows-targets",
+]
+
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
+[[package]]
+name = "bytes"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
+
+[[package]]
+name = "cbindgen"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb"
+dependencies = [
+ "clap",
+ "heck",
+ "indexmap",
+ "log",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "syn",
+ "tempfile",
+ "toml",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
+name = "clap"
+version = "4.5.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
+dependencies = [
+ "clap_builder",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "errno"
+version = "0.3.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
+
+[[package]]
+name = "gimli"
+version = "0.31.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "hpsdr_discovery"
+version = "0.1.0"
+dependencies = [
+ "cbindgen",
+ "libc",
+ "nix",
+ "tokio",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "itoa"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
+
+[[package]]
+name = "libc"
+version = "0.2.167"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+
+[[package]]
+name = "lock_api"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
+name = "mio"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "nix"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+ "memoffset",
+]
+
+[[package]]
+name = "object"
+version = "0.36.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
+
+[[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",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+
+[[package]]
+name = "rustix"
+version = "0.38.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "serde"
+version = "1.0.215"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.215"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.133"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
+[[package]]
+name = "socket2"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "tokio"
+version = "1.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "libc",
+ "mio",
+ "parking_lot",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2",
+ "tokio-macros",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winnow"
+version = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+dependencies = [
+ "memchr",
+]
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
new file mode 100644 (file)
index 0000000..0958446
--- /dev/null
@@ -0,0 +1,3 @@
+[workspace]
+resolver = "2"
+members = [ "discovery" ]
diff --git a/rust/discovery/Cargo.toml b/rust/discovery/Cargo.toml
new file mode 100644 (file)
index 0000000..a62ef72
--- /dev/null
@@ -0,0 +1,17 @@
+[package]
+name = "hpsdr_discovery"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+name = "hpsdr_discovery"
+crate-type = ["cdylib", "rlib"]
+
+[dependencies]
+tokio = { version = "1.0", features = ["full"] }
+libc = "0.2"
+nix = { version = "0.29.0", features = ["net"] }
+
+[build-dependencies]
+cbindgen = "0.27.0"
+
diff --git a/rust/discovery/build.rs b/rust/discovery/build.rs
new file mode 100644 (file)
index 0000000..0afc1b6
--- /dev/null
@@ -0,0 +1,14 @@
+use std::env;
+
+fn main() {
+    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
+    let mut config: cbindgen::Config = cbindgen::Config::from_file("cbindgen.toml").unwrap();
+    config.language = cbindgen::Language::C;
+
+    cbindgen::Builder::new()
+        .with_crate(crate_dir)
+        .with_config(config)
+        .generate()
+        .expect("unable to generate bindings")
+        .write_to_file("hpsdr_discovery.h");
+}
diff --git a/rust/discovery/cbindgen.toml b/rust/discovery/cbindgen.toml
new file mode 100644 (file)
index 0000000..6c87b68
--- /dev/null
@@ -0,0 +1,8 @@
+language = "C"
+sys_includes = ["netinet/in.h"]
+
+
+# workaround for the bug: https://github.com/mozilla/cbindgen/issues/539
+[export.rename]
+"sockaddr_in" = "struct sockaddr_in"
+
diff --git a/rust/discovery/src/discovery.rs b/rust/discovery/src/discovery.rs
new file mode 100644 (file)
index 0000000..dd319ca
--- /dev/null
@@ -0,0 +1,88 @@
+use std::net::*;
+use tokio::time::Duration;
+use crate::types::*;
+use nix::ifaddrs;
+
+const DISCOVERY_PORT: u16 = 1024;
+
+pub async fn discover_devices() -> Vec<DiscoveredDevice> {
+    let socket = UdpSocket::bind("0.0.0.0:0").expect("Failed to bind socket");
+    socket.set_broadcast(true).expect("Failed to set broadcast");
+    let addrs = ifaddrs::getifaddrs().unwrap();
+    /* TODO */
+
+    let mut discovery_packet = [0u8; 63];
+    discovery_packet[0] = 0xEF;
+    discovery_packet[1] = 0xFE;
+    discovery_packet[2] = 0x02;
+
+    let broadcast_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::BROADCAST), DISCOVERY_PORT);
+    socket.send_to(&discovery_packet, broadcast_addr).expect("Failed to send discovery packet");
+
+    let mut devices = Vec::new();
+    let mut buf = [0u8; 2048];
+    socket.set_read_timeout(Some(Duration::from_secs(2))).expect("Failed to set timeout");
+
+    while let Ok((len, addr)) = socket.recv_from(&mut buf) {
+        if len >= 3 && buf[0] == 0xEF && buf[1] == 0xFE {
+            if let Some(device) = parse_discovery_response(&buf[..len], addr) {
+                devices.push(device);
+            }
+        }
+    }
+
+    devices
+}
+
+pub fn list_interfaces() {
+    let addrs = ifaddrs::getifaddrs().unwrap();
+    for ifaddr in addrs {
+        match ifaddr.address {
+            Some(iface_address) => {
+                println!("interface: {} address: {}", ifaddr.interface_name, iface_address);
+            },
+            None => {
+                println!("interface {} with unsupported address family",
+                         ifaddr.interface_name);
+            }
+        }
+    }
+}
+
+fn parse_discovery_response(data: &[u8], addr: SocketAddr) -> Option<DiscoveredDevice> {
+    if data.len() < 11 {
+        return None;
+    }
+
+    let device_type = data[10];
+    let (name, freq_min, freq_max) = match device_type {
+        0x00 => ("Metis", 0.0, 61440000.0),
+        0x01 => ("Hermes", 0.0, 61440000.0),
+        0x06 => ("HesmesLite2", 0.0, 30720000.0),
+        // Add other device types
+        _ => ("Unknown", 0.0, 61440000.0),
+    };
+
+    let mut mac_addr = [0u8; 6];
+    mac_addr.copy_from_slice(&data[3..9]);
+
+    Some(DiscoveredDevice {
+        protocol: 1,
+        device: device_type,
+        name: name.to_string(),
+        software_version: data[9],
+        status: data[2] as u32,
+        supported_receivers: 2,
+        frequency_min: freq_min,
+        frequency_max: freq_max,
+        network: NetworkInfo {
+            mac_address: mac_addr,
+            address: addr,
+            interface_address: None,
+            interface_netmask: None,
+            interface_name: String::new(),
+        },
+        use_tcp: false,
+    })
+}
+
diff --git a/rust/discovery/src/ffi.rs b/rust/discovery/src/ffi.rs
new file mode 100644 (file)
index 0000000..41ba735
--- /dev/null
@@ -0,0 +1,105 @@
+use std::ffi::CString;
+use libc::{c_char, c_int, sockaddr_in};
+use crate::{discover_devices, discovery::list_interfaces, DiscoveredDevice, NetworkInfo};
+use std::net::SocketAddr;
+
+#[repr(C)]
+pub struct CFfiNetworkInfo {
+    mac_address: [u8; 6],
+    address: sockaddr_in,
+    interface_address: sockaddr_in,
+    interface_netmask: sockaddr_in,
+    interface_name: [c_char; 64],
+}
+
+#[repr(C)]
+pub struct CFfiDiscoveredDevice {
+    protocol: u32,
+    device: u8,
+    name: [c_char; 32],
+    software_version: u8,
+    status: u32,
+    supported_receivers: u32,
+    frequency_min: f64,
+    frequency_max: f64,
+    network: CFfiNetworkInfo,
+    use_tcp: c_int,
+}
+
+#[no_mangle]
+pub extern "C" fn list_interfaces_ffi() {
+    list_interfaces();
+}
+
+#[no_mangle]
+pub extern "C" fn discover_devices_ffi(devices: *mut CFfiDiscoveredDevice, max_devices: c_int) -> c_int {
+    let rt = tokio::runtime::Runtime::new().unwrap();
+    
+    let rust_devices = rt.block_on(discover_devices());
+    let count = rust_devices.len().min(max_devices as usize);
+    
+    let devices_slice = unsafe { std::slice::from_raw_parts_mut(devices, count) };
+    
+    for (i, device) in rust_devices.iter().take(count).enumerate() {
+        devices_slice[i] = convert_to_c_device(device);
+    }
+    
+    count as c_int
+}
+
+fn convert_to_c_device(device: &DiscoveredDevice) -> CFfiDiscoveredDevice {
+    let name_c = CString::new(device.name.clone()).unwrap();
+    let mut name_arr = [0i8; 32];
+    for (i, &b) in name_c.as_bytes().iter().enumerate().take(31) {
+        name_arr[i] = b as i8;
+    }
+
+    CFfiDiscoveredDevice {
+        protocol: device.protocol,
+        device: device.device,
+        name: name_arr,
+        software_version: device.software_version,
+        status: device.status,
+        supported_receivers: device.supported_receivers,
+        frequency_min: device.frequency_min,
+        frequency_max: device.frequency_max,
+        network: convert_to_c_network(&device.network),
+        use_tcp: if device.use_tcp { 1 } else { 0 },
+    }
+}
+
+fn convert_to_c_network(network: &NetworkInfo) -> CFfiNetworkInfo {
+    let name_c = CString::new(network.interface_name.clone()).unwrap();
+    let mut name_arr = [0i8; 64];
+    for (i, &b) in name_c.as_bytes().iter().enumerate().take(63) {
+        name_arr[i] = b as i8;
+    }
+
+    CFfiNetworkInfo {
+        mac_address: network.mac_address,
+        address: socketaddr_to_sockaddr_in(&network.address),
+        interface_address: network.interface_address
+            .map(|addr| socketaddr_to_sockaddr_in(&addr))
+            .unwrap_or_else(|| unsafe { std::mem::zeroed() }),
+        interface_netmask: network.interface_netmask
+            .map(|addr| socketaddr_to_sockaddr_in(&addr))
+            .unwrap_or_else(|| unsafe { std::mem::zeroed() }),
+        interface_name: name_arr,
+    }
+}
+
+fn socketaddr_to_sockaddr_in(addr: &SocketAddr) -> sockaddr_in {
+    match addr {
+        SocketAddr::V4(addr) => unsafe {
+            let mut saddr: sockaddr_in = std::mem::zeroed();
+            saddr.sin_family = libc::AF_INET as u16;
+            saddr.sin_port = addr.port().to_be();
+            saddr.sin_addr = libc::in_addr {
+                s_addr: u32::from(*addr.ip()).to_be(),
+            };
+            saddr
+        },
+        _ => unsafe { std::mem::zeroed() },
+    }
+}
+
diff --git a/rust/discovery/src/lib.rs b/rust/discovery/src/lib.rs
new file mode 100644 (file)
index 0000000..64f5b2c
--- /dev/null
@@ -0,0 +1,7 @@
+mod discovery;
+mod ffi;
+mod types;
+
+pub use discovery::discover_devices;
+pub use types::*;
+
diff --git a/rust/discovery/src/types.rs b/rust/discovery/src/types.rs
new file mode 100644 (file)
index 0000000..ed08914
--- /dev/null
@@ -0,0 +1,24 @@
+use std::net::SocketAddr;
+
+#[derive(Debug, Clone)]
+pub struct NetworkInfo {
+    pub mac_address: [u8; 6],
+    pub address: SocketAddr,
+    pub interface_address: Option<SocketAddr>,
+    pub interface_netmask: Option<SocketAddr>,
+    pub interface_name: String,
+}
+
+#[derive(Debug, Clone)]
+pub struct DiscoveredDevice {
+    pub protocol: u32,
+    pub device: u8,
+    pub name: String,
+    pub software_version: u8,
+    pub status: u32,
+    pub supported_receivers: u32,
+    pub frequency_min: f64,
+    pub frequency_max: f64,
+    pub network: NetworkInfo,
+    pub use_tcp: bool,
+}