From 9eddeb320b6449825653f82435b16213475a739c Mon Sep 17 00:00:00 2001 From: Ramakrishnan Muthukrishnan Date: Sat, 7 Dec 2024 00:15:24 +0530 Subject: [PATCH] a simple demonstration of calling rust from C with cbindgen --- hpsdr_discovery.c | 16 + rust/Cargo.lock | 682 ++++++++++++++++++++++++++++++++ rust/Cargo.toml | 3 + rust/discovery/Cargo.toml | 17 + rust/discovery/build.rs | 14 + rust/discovery/cbindgen.toml | 8 + rust/discovery/src/discovery.rs | 88 +++++ rust/discovery/src/ffi.rs | 105 +++++ rust/discovery/src/lib.rs | 7 + rust/discovery/src/types.rs | 24 ++ 10 files changed, 964 insertions(+) create mode 100644 hpsdr_discovery.c create mode 100644 rust/Cargo.lock create mode 100644 rust/Cargo.toml create mode 100644 rust/discovery/Cargo.toml create mode 100644 rust/discovery/build.rs create mode 100644 rust/discovery/cbindgen.toml create mode 100644 rust/discovery/src/discovery.rs create mode 100644 rust/discovery/src/ffi.rs create mode 100644 rust/discovery/src/lib.rs create mode 100644 rust/discovery/src/types.rs diff --git a/hpsdr_discovery.c b/hpsdr_discovery.c new file mode 100644 index 0000000..cd87690 --- /dev/null +++ b/hpsdr_discovery.c @@ -0,0 +1,16 @@ +// main.c +#include "hpsdr_discovery.h" +#include + +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 index 0000000..3840937 --- /dev/null +++ b/rust/Cargo.lock @@ -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 index 0000000..0958446 --- /dev/null +++ b/rust/Cargo.toml @@ -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 index 0000000..a62ef72 --- /dev/null +++ b/rust/discovery/Cargo.toml @@ -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 index 0000000..0afc1b6 --- /dev/null +++ b/rust/discovery/build.rs @@ -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 index 0000000..6c87b68 --- /dev/null +++ b/rust/discovery/cbindgen.toml @@ -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 index 0000000..dd319ca --- /dev/null +++ b/rust/discovery/src/discovery.rs @@ -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 { + 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 { + 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 index 0000000..41ba735 --- /dev/null +++ b/rust/discovery/src/ffi.rs @@ -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 index 0000000..64f5b2c --- /dev/null +++ b/rust/discovery/src/lib.rs @@ -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 index 0000000..ed08914 --- /dev/null +++ b/rust/discovery/src/types.rs @@ -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, + pub interface_netmask: Option, + 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, +} -- 2.45.2