diff --git a/Cargo.lock b/Cargo.lock index 557c7c5..8804c45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,48 @@ version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +[[package]] +name = "api" +version = "0.1.0" +source = "git+https://gitea.sergeysav.com/sergeysav/telemetry_visualization.git?rev=458c94c2ad362b1a6c31c2b1ee606a9f40605e06#458c94c2ad362b1a6c31c2b1ee606a9f40605e06" +dependencies = [ + "api-core", + "api-proc-macro", + "chrono", + "derive_more", + "futures-util", + "log", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-tungstenite", + "tokio-util", + "uuid", +] + +[[package]] +name = "api-core" +version = "0.1.0" +source = "git+https://gitea.sergeysav.com/sergeysav/telemetry_visualization.git?rev=458c94c2ad362b1a6c31c2b1ee606a9f40605e06#458c94c2ad362b1a6c31c2b1ee606a9f40605e06" +dependencies = [ + "chrono", + "derive_more", + "serde", + "thiserror", +] + +[[package]] +name = "api-proc-macro" +version = "0.1.0" +source = "git+https://gitea.sergeysav.com/sergeysav/telemetry_visualization.git?rev=458c94c2ad362b1a6c31c2b1ee606a9f40605e06#458c94c2ad362b1a6c31c2b1ee606a9f40605e06" +dependencies = [ + "api-core", + "proc-macro-error", + "quote", + "syn 2.0.112", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -29,12 +71,27 @@ version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +[[package]] +name = "bytes" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + [[package]] name = "cc" version = "1.2.17" @@ -89,6 +146,25 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -96,10 +172,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "crc" -version = "3.3.0" +name = "cpufeatures" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] @@ -116,6 +201,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "ctrlc" version = "3.5.0" @@ -127,12 +222,57 @@ dependencies = [ "windows-sys 0.61.1", ] +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.112", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dispatch" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "embedded-hal" version = "0.2.7" @@ -215,10 +355,142 @@ dependencies = [ ] [[package]] -name = "hex" -version = "0.4.3" +name = "futures" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.112", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "iana-time-zone" @@ -244,6 +516,21 @@ dependencies = [ "cc", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + [[package]] name = "js-sys" version = "0.3.77" @@ -262,15 +549,32 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.1", +] [[package]] name = "nautilus_common" @@ -279,11 +583,14 @@ dependencies = [ "anyhow", "chrono", "ctrlc", + "derive_more", "fern", "log", "postcard", "serde", "thiserror", + "tokio", + "tokio-util", ] [[package]] @@ -296,7 +603,6 @@ dependencies = [ "embedded-hal 1.0.0", "embedded-hal-bus", "embedded-hal-mock", - "hex", "log", "nautilus_common", "postcard", @@ -308,12 +614,15 @@ name = "nautilus_ground" version = "0.1.0" dependencies = [ "anyhow", + "api", "chrono", - "hex", + "futures", + "itertools", "log", "nautilus_common", "postcard", - "serde", + "tokio", + "tokio-util", ] [[package]] @@ -411,6 +720,24 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "openssl-probe" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "postcard" version = "1.1.3" @@ -423,6 +750,39 @@ dependencies = [ "serde", ] +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.94" @@ -434,13 +794,62 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rpi-pal" version = "0.22.2" @@ -456,12 +865,104 @@ dependencies = [ "void", ] +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustls" +version = "0.23.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.1", +] + +[[package]] +name = "security-framework" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -489,7 +990,31 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", +] + +[[package]] +name = "serde_json" +version = "1.0.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", ] [[package]] @@ -498,6 +1023,22 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + [[package]] name = "spin_sleep" version = "1.3.1" @@ -508,10 +1049,26 @@ dependencies = [ ] [[package]] -name = "syn" -version = "2.0.100" +name = "subtle" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.112" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21f182278bf2d2bcb3c88b1b08a37df029d71ce3d3ae26168e3c653b213b99d4" dependencies = [ "proc-macro2", "quote", @@ -535,21 +1092,168 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", ] +[[package]] +name = "tokio" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.61.1", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.112", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" +dependencies = [ + "futures-util", + "log", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand", + "rustls", + "rustls-pki-types", + "sha1", + "thiserror", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uuid" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -572,7 +1276,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 2.0.112", "wasm-bindgen-shared", ] @@ -594,7 +1298,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.112", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -614,7 +1318,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -623,13 +1327,31 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.4", ] [[package]] @@ -647,14 +1369,31 @@ 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", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -663,44 +1402,130 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[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_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[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_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[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_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[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_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "zerocopy" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.112", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zmij" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac060176f7020d62c3bcc1cdbcec619d54f48b07ad1963a3f80ce7a0c17755f" diff --git a/Cargo.toml b/Cargo.toml index 0b7682b..6076e01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,10 +4,23 @@ members = ["common", "ground", "flight"] [workspace.dependencies] anyhow = "1.0.100" -fern = { version = "0.7.1", features = ["colored"] } -log = { version = "0.4.28" } +api = { git = "https://gitea.sergeysav.com/sergeysav/telemetry_visualization.git", rev = "458c94c2ad362b1a6c31c2b1ee606a9f40605e06" } chrono = { version = "0.4.42", features = ["serde"] } +crc = "3.4.0" ctrlc = "3.5.0" -serde = { version = "1.0.228", features = ["derive"], default-features = false } +derive_more = "2.1.1" +embedded-hal = "1.0.0" +embedded-hal-bus = "0.3.0" +embedded-hal-mock = "0.11.1" +fern = { version = "0.7.1", features = ["colored"] } +futures = "0.3.31" +itertools = "0.14.0" +log = { version = "0.4.29" } +nautilus_common = { path = "./common" } postcard = { version = "1.1.3", default-features = false, features = ["alloc"] } +rpi-pal = "0.22.2" +serde = { version = "1.0.228", features = ["derive"], default-features = false } thiserror = "2.0.17" +tokio = { version = "1.48.0" } +tokio-util = "0.7.17" + diff --git a/common/Cargo.toml b/common/Cargo.toml index 28e7ff7..9b3dbd6 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -5,10 +5,16 @@ edition = "2024" [dependencies] anyhow = { workspace = true } -fern = { workspace = true } -log = { workspace = true } chrono = { workspace = true } ctrlc = { workspace = true } -serde = { workspace = true } +derive_more = {workspace = true, features = ["display"]} +fern = { workspace = true } +log = { workspace = true } postcard = { workspace = true } +serde = { workspace = true } thiserror = { workspace = true } +tokio = { workspace = true, optional = true, features = ["net"] } +tokio-util = {workspace = true, optional = true} + +[features] +async = [ "dep:tokio", "dep:tokio-util" ] diff --git a/common/src/command/mod.rs b/common/src/command/mod.rs index f32205a..1af6274 100644 --- a/common/src/command/mod.rs +++ b/common/src/command/mod.rs @@ -50,6 +50,12 @@ pub struct CommandHeader<'a> { pub data: &'a [u8], } +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct OwnedCommandHeader { + pub name: String, + pub data: Vec, +} + pub trait Command: Serialize + DeserializeOwned {} impl Command for () {} diff --git a/common/src/lib.rs b/common/src/lib.rs index b4cb991..4978fc9 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,10 +1,9 @@ #![warn(clippy::all, clippy::pedantic)] use log::info; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; pub mod command; pub mod logger; +pub mod on_drop; pub mod telemetry; pub mod udp; @@ -12,10 +11,25 @@ pub mod udp; /// /// # Errors /// If a system error occurred while trying to set the ctrl-c handler -pub fn add_ctrlc_handler(flag: Arc) -> anyhow::Result<()> { +pub fn add_ctrlc_handler_arc( + flag: std::sync::Arc, +) -> anyhow::Result<()> { ctrlc::set_handler(move || { info!("Shutdown Requested"); - flag.store(false, Ordering::Relaxed); + flag.store(false, std::sync::atomic::Ordering::Relaxed); + })?; + Ok(()) +} + +/// Add a ctrl-c handler which will set an atomic flag to `false` when ctrl-c is detected +/// +/// # Errors +/// If a system error occurred while trying to set the ctrl-c handler +#[cfg(feature = "async")] +pub fn add_ctrlc_handler_cancel(cancel: tokio_util::sync::CancellationToken) -> anyhow::Result<()> { + ctrlc::set_handler(move || { + info!("Shutdown Requested"); + cancel.cancel(); })?; Ok(()) } diff --git a/common/src/logger.rs b/common/src/logger.rs index aa43845..e7af5bd 100644 --- a/common/src/logger.rs +++ b/common/src/logger.rs @@ -1,6 +1,6 @@ use anyhow::Result; use fern::colors::{Color, ColoredLevelConfig}; -use log::debug; +use log::{LevelFilter, debug}; use std::fs::create_dir_all; use std::str::FromStr; use std::{env, thread}; @@ -46,6 +46,9 @@ pub fn setup_logger(package_name: &'static str) -> Result<()> { .chain( fern::Dispatch::new() .level(log_level) + .level_for("tungstenite", LevelFilter::Warn) + .level_for("tokio_tungstenite", LevelFilter::Warn) + .level_for("api", LevelFilter::Info) .chain(std::io::stdout()), ) .chain(fern::log_file(log_file.clone())?) diff --git a/flight/src/on_drop.rs b/common/src/on_drop.rs similarity index 100% rename from flight/src/on_drop.rs rename to common/src/on_drop.rs diff --git a/common/src/telemetry/mod.rs b/common/src/telemetry/mod.rs index c770c92..554c860 100644 --- a/common/src/telemetry/mod.rs +++ b/common/src/telemetry/mod.rs @@ -1,5 +1,6 @@ use chrono::serde::ts_nanoseconds; use chrono::{DateTime, Utc}; +use derive_more::Display; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Serialize, Deserialize)] @@ -9,7 +10,7 @@ pub struct Telemetry { pub message: TelemetryMessage, } -#[derive(Copy, Clone, Debug, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, Display, Serialize, Deserialize)] pub enum SwitchBank { A, B, diff --git a/common/src/udp.rs b/common/src/udp.rs index fe1fb11..1236a9b 100644 --- a/common/src/udp.rs +++ b/common/src/udp.rs @@ -1,7 +1,6 @@ use crate::command::{Command, CommandHeader}; use crate::udp::UdpRecvPostcardError::ExtraData; use crate::udp::UdpSendPostcardError::LengthMismatch; -use log::error; use serde::{Deserialize, Serialize}; use std::io::ErrorKind; use std::net::{SocketAddr, ToSocketAddrs, UdpSocket}; @@ -30,7 +29,7 @@ pub enum UdpSendPostcardError { } pub trait UdpSocketExt { - /// Receive a CBOR encoded message from this UDP Socket + /// Receive a Postcard encoded message from this UDP Socket /// /// # Errors /// An error that could have occurred while trying to receive this message. @@ -63,26 +62,51 @@ pub trait UdpSocketExt { ) -> Result<(), UdpSendPostcardError>; } +fn recv_postcard_inner<'de, T: Deserialize<'de>>( + result: std::io::Result<(usize, SocketAddr)>, + buffer: &'de mut [u8], +) -> Result<(T, SocketAddr), UdpRecvPostcardError> { + match result { + Ok((size, addr)) => match postcard::take_from_bytes::(&buffer[..size]) { + Ok((res, rem)) => { + if !rem.is_empty() { + return Err(ExtraData { amount: rem.len() }); + } + Ok((res, addr)) + } + Err(err) => Err(err.into()), + }, + Err(err) => match err.kind() { + ErrorKind::WouldBlock | ErrorKind::TimedOut => Err(UdpRecvPostcardError::NoData), + _ => Err(err.into()), + }, + } +} + +fn send_inner( + send_result: Result, + expected_size: usize, +) -> Result<(), UdpSendPostcardError> { + match send_result { + Ok(size_sent) => { + if expected_size != size_sent { + return Err(LengthMismatch { + expected: expected_size, + actual: size_sent, + }); + } + Ok(()) + } + Err(e) => Err(e.into()), + } +} + impl UdpSocketExt for UdpSocket { fn recv_postcard<'de, T: Deserialize<'de>>( &self, buffer: &'de mut [u8], ) -> Result<(T, SocketAddr), UdpRecvPostcardError> { - match self.recv_from(buffer) { - Ok((size, addr)) => match postcard::take_from_bytes::(&buffer[..size]) { - Ok((res, rem)) => { - if !rem.is_empty() { - return Err(ExtraData { amount: rem.len() }); - } - Ok((res, addr)) - } - Err(err) => Err(err.into()), - }, - Err(err) => match err.kind() { - ErrorKind::WouldBlock | ErrorKind::TimedOut => Err(UdpRecvPostcardError::NoData), - _ => Err(err.into()), - }, - } + recv_postcard_inner(self.recv_from(buffer), buffer) } fn send_postcard( @@ -91,24 +115,9 @@ impl UdpSocketExt for UdpSocket { buffer: &mut [u8], addr: A, ) -> Result<(), UdpSendPostcardError> { - match postcard::to_slice(data, buffer) { - Ok(result) => { - let size_encoded = result.len(); - match self.send_to(result, addr) { - Ok(size_sent) => { - if size_encoded != size_sent { - return Err(LengthMismatch { - expected: size_encoded, - actual: size_sent, - }); - } - Ok(()) - } - Err(e) => Err(e.into()), - } - } - Err(e) => Err(e.into()), - } + let result = postcard::to_slice(data, buffer)?; + let size_encoded = result.len(); + send_inner(self.send_to(result, addr), size_encoded) } fn send_command( @@ -120,21 +129,97 @@ impl UdpSocketExt for UdpSocket { let mut inner_buffer = [0u8; 512]; let inner_buffer = postcard::to_slice(data, &mut inner_buffer)?; let mut buffer = [0u8; 512]; - let buffer = postcard::to_slice( + self.send_postcard( &CommandHeader { name, data: inner_buffer, }, &mut buffer, - )?; - let size_encoded = buffer.len(); - let size_sent = self.send_to(buffer, addr)?; - if size_encoded != size_sent { - return Err(LengthMismatch { - expected: size_encoded, - actual: size_sent, - }); - } - Ok(()) + addr, + ) + } +} + +#[cfg(feature = "async")] +pub mod tokio { + use super::{ + Command, CommandHeader, Deserialize, Serialize, SocketAddr, UdpRecvPostcardError, + UdpSendPostcardError, recv_postcard_inner, send_inner, + }; + use ::tokio::net::ToSocketAddrs; + use ::tokio::net::UdpSocket; + + pub trait AsyncUdpSocketExt { + /// Receive a Postcard encoded message from this UDP Socket + /// + /// # Errors + /// An error that could have occurred while trying to receive this message. + /// If no data was received a `UdpRecvCborError::NoData` error would be returned. + fn recv_postcard<'de, T: Deserialize<'de>>( + &self, + buffer: &'de mut [u8], + ) -> impl Future>; + + /// Send a CBOR encoded message to an address using this socket + /// + /// # Errors + /// An error that could have occurred while trying to send this message + fn send_postcard( + &self, + data: &T, + buffer: &mut [u8], + addr: A, + ) -> impl Future>; + + /// Send a command message to an address using this socket + /// + /// # Errors + /// An error that could have occurred while trying to send this message + fn send_command( + &self, + name: &str, + data: &T, + addr: A, + ) -> impl Future>; + } + + impl AsyncUdpSocketExt for UdpSocket { + async fn recv_postcard<'de, T: Deserialize<'de>>( + &self, + buffer: &'de mut [u8], + ) -> Result<(T, SocketAddr), UdpRecvPostcardError> { + recv_postcard_inner(self.recv_from(buffer).await, buffer) + } + + async fn send_postcard( + &self, + data: &T, + buffer: &mut [u8], + addr: A, + ) -> Result<(), UdpSendPostcardError> { + let result = postcard::to_slice(data, buffer)?; + let size_encoded = result.len(); + send_inner(self.send_to(result, addr).await, size_encoded) + } + + async fn send_command( + &self, + name: &str, + data: &T, + addr: A, + ) -> Result<(), UdpSendPostcardError> { + let mut inner_buffer = [0u8; 512]; + let inner_buffer = postcard::to_slice(data, &mut inner_buffer)?; + let mut buffer = [0u8; 512]; + self.send_postcard( + &CommandHeader { + name, + data: inner_buffer, + }, + &mut buffer, + addr, + ) + .await + } } } diff --git a/flight/Cargo.toml b/flight/Cargo.toml index 7b4fcce..c28e211 100644 --- a/flight/Cargo.toml +++ b/flight/Cargo.toml @@ -5,19 +5,18 @@ edition = "2024" [dependencies] anyhow = { workspace = true } -log = { workspace = true, features = ["max_level_trace", "release_max_level_debug"] } chrono = { workspace = true } -embedded-hal = "1.0.0" -embedded-hal-bus = { version = "0.3.0", features = ["std"] } -embedded-hal-mock = { version = "0.11.1", optional = true } -rpi-pal = { version = "0.22.2", features = ["hal"], optional = true } -hex = "0.4.3" -crc = "3.3.0" -nautilus_common = { path = "../common" } +crc = {workspace = true} +embedded-hal = {workspace = true} +embedded-hal-bus = { workspace = true, features = ["std"] } +embedded-hal-mock = { workspace = true, optional = true } +log = { workspace = true, features = ["max_level_trace", "release_max_level_debug"] } +nautilus_common = { workspace = true } postcard = { workspace = true } +rpi-pal = { workspace = true, features = ["hal"], optional = true } [dev-dependencies] -embedded-hal-mock = { version = "0.11.1" } +embedded-hal-mock = { workspace = true } [features] raspi = ["dep:rpi-pal"] diff --git a/flight/src/lib.rs b/flight/src/lib.rs index 57bc15a..1030681 100644 --- a/flight/src/lib.rs +++ b/flight/src/lib.rs @@ -10,12 +10,12 @@ use crate::state_vector::StateVector; use anyhow::Result; use embedded_hal::pwm::SetDutyCycle; use log::info; -use nautilus_common::add_ctrlc_handler; use nautilus_common::telemetry::{SwitchBank, TelemetryMessage}; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::thread::sleep; use std::time::Duration; +use nautilus_common::add_ctrlc_handler_arc; mod hardware; @@ -35,7 +35,7 @@ pub fn run() -> Result<()> { ); let running = Arc::new(AtomicBool::new(true)); - add_ctrlc_handler(running.clone())?; + add_ctrlc_handler_arc(running.clone())?; let state_vector = StateVector::new(); @@ -92,7 +92,7 @@ pub fn run() -> Result<()> { }); }); }, - 1, + 10, )?; info!("Starting Main Loop"); @@ -119,7 +119,6 @@ pub fn run() -> Result<()> { mod comms; mod data; -mod on_drop; mod rcs; mod scheduler; mod state_vector; diff --git a/flight/src/scheduler/mod.rs b/flight/src/scheduler/mod.rs index ea1ebd7..12386af 100644 --- a/flight/src/scheduler/mod.rs +++ b/flight/src/scheduler/mod.rs @@ -1,6 +1,6 @@ -use crate::on_drop::on_drop; use anyhow::Result; use log::trace; +use nautilus_common::on_drop::on_drop; use std::any::type_name; use std::fmt::Debug; use std::ops::Deref; diff --git a/ground/Cargo.toml b/ground/Cargo.toml index 99eba98..a09658b 100644 --- a/ground/Cargo.toml +++ b/ground/Cargo.toml @@ -5,9 +5,12 @@ edition = "2024" [dependencies] anyhow = { workspace = true } -nautilus_common = { path = "../common" } -log = { workspace = true } +api = { workspace = true } chrono = { workspace = true } +futures = {workspace = true} +itertools = { workspace = true } +log = { workspace = true } +nautilus_common = { workspace = true, features = ["async"] } postcard = { workspace = true } -hex = "0.4.3" -serde = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread", "rt", "macros", "net"]} +tokio-util = { workspace = true } diff --git a/ground/src/command.rs b/ground/src/command.rs new file mode 100644 index 0000000..a28eec5 --- /dev/null +++ b/ground/src/command.rs @@ -0,0 +1,121 @@ +use api::client::Client; +use api::client::command::CommandRegistry; +use api::macros::IntoCommandDefinition; +use chrono::TimeDelta; +use itertools::Itertools; +use log::{error, trace}; +use nautilus_common::command::{Command, OwnedCommandHeader, SetPin, ValidPriorityCommand}; +use nautilus_common::udp::tokio::AsyncUdpSocketExt; +use std::fmt::Debug; +use std::net::SocketAddr; +use std::sync::Arc; +use tokio::net::UdpSocket; +use tokio::select; +use tokio::sync::RwLock; +use tokio::sync::mpsc::{Sender, channel}; +use tokio_util::sync::CancellationToken; + +pub struct CommandHandler<'a> { + cmd: CommandRegistry, + flight_addr: &'a RwLock, + udp: &'a UdpSocket, + cancel: CancellationToken, +} + +#[derive(IntoCommandDefinition)] +struct SetPinCommand { + state: bool, +} + +impl<'a> CommandHandler<'a> { + pub fn new( + client: Arc, + flight_addr: &'a RwLock, + udp: &'a UdpSocket, + cancel: CancellationToken, + ) -> Self { + Self { + cmd: CommandRegistry::new(client), + flight_addr, + udp, + cancel, + } + } + + pub fn run(self) -> anyhow::Result<()> { + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build()?; + + runtime.block_on(async move { + let (outgoing_commands_tx, mut outgoing_commands_rx) = channel::(16); + + let commands = ["a", "b"].iter().cartesian_product(0..16) + .map(|(bank, i)| { + let command_name = format!("/mcp23017{bank}/set"); + let outgoing_commands_tx = outgoing_commands_tx.clone(); + self.cmd.register_handler( + format!("switch.{bank}.{i}.set"), + move |header, cmd: SetPinCommand| -> anyhow::Result<_> { + trace!("Setting Switch {bank} {i}"); + + outgoing_commands_tx.try_send_command( + &command_name, + &ValidPriorityCommand { + inner: SetPin { + pin: i, + value: cmd.state, + }, + valid_until: header.timestamp + TimeDelta::seconds(5), + priority: 0, + } + )?; + + Ok("Command Executed Successfully".to_string()) + } + ) + }) + .collect::>(); + + let mut buffer = [0u8; 512]; + while !self.cancel.is_cancelled() { + select! { + () = self.cancel.cancelled() => { break; } + outgoing = outgoing_commands_rx.recv() => { + match outgoing { + None => break, + Some(outgoing) => { + match self.udp.send_postcard(&outgoing, &mut buffer, *self.flight_addr.read().await).await { + Ok(()) => {}, + Err(err) => error!("Failed to Send Outgoing {err}"), + } + } + } + } + } + } + + // Explicit Drops + drop(commands); + drop(self); + }); + + Ok(()) + } +} + +trait SenderExt { + fn try_send_command(&self, name: &str, data: &T) -> anyhow::Result<()>; +} + +impl SenderExt for Sender { + fn try_send_command(&self, name: &str, data: &T) -> anyhow::Result<()> { + trace!("{data:?}"); + let inner_buffer = postcard::to_allocvec(data)?; + self.try_send(OwnedCommandHeader { + name: name.to_string(), + data: inner_buffer, + })?; + Ok(()) + } +} diff --git a/ground/src/lib.rs b/ground/src/lib.rs index bd00a63..f9331fd 100644 --- a/ground/src/lib.rs +++ b/ground/src/lib.rs @@ -1,15 +1,24 @@ #![warn(clippy::all, clippy::pedantic)] -use anyhow::Result; -use chrono::{TimeDelta, Utc}; -use log::{error, info}; -use nautilus_common::add_ctrlc_handler; -use nautilus_common::command::{SetPin, ValidPriorityCommand}; -use nautilus_common::telemetry::Telemetry; -use nautilus_common::udp::{UdpRecvPostcardError, UdpSocketExt}; -use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket}; + +use nautilus_common::udp::tokio::AsyncUdpSocketExt; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +mod command; +mod telemetry; + +use crate::command::CommandHandler; +use crate::telemetry::TelemetryHandler; +use anyhow::{Result, anyhow, bail}; +use api::client::Client; +use futures::executor::block_on; +use futures::future::{Either, select}; +use log::{info, warn}; +use nautilus_common::add_ctrlc_handler_cancel; use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::time::Duration; +use std::thread::{Builder, scope}; +use tokio::net::UdpSocket; +use tokio::pin; +use tokio::sync::RwLock; +use tokio_util::sync::CancellationToken; /// Run the Ground Software /// @@ -21,86 +30,78 @@ pub fn run() -> Result<()> { env!("CARGO_PKG_VERSION") ); - let running = Arc::new(AtomicBool::new(true)); + let udp_shutdown = CancellationToken::new(); + let cancel = udp_shutdown.child_token(); + add_ctrlc_handler_cancel(cancel.clone())?; - add_ctrlc_handler(running.clone())?; + let (udp_thread, udp) = { + let udp_shutdown = udp_shutdown.clone(); + let (udp_tx, udp) = tokio::sync::oneshot::channel(); - let mut flight_addr = None; - let bind_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 14000); - let udp = UdpSocket::bind(bind_addr)?; - udp.set_read_timeout(Some(Duration::from_millis(100)))?; + let udp_thread = Builder::new() + .name("flight-udp-connection-handler".to_string()) + .spawn(move || { + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build()?; - let mut buffer = [0u8; 512]; + runtime.block_on(async { + let udp = UdpSocket::bind("0.0.0.0:14000").await?; + udp_tx + .send(udp) + .map_err(|_| anyhow!("Couldn't complete UDP establish"))?; + Ok(()) as Result<()> + })?; - let mut do_once = true; + runtime.block_on(udp_shutdown.cancelled()); - while running.load(Ordering::Relaxed) { - match udp.recv_postcard::(&mut buffer) { - Ok((tlm, addr)) => { - flight_addr = Some(addr); - info!("{tlm:?}"); + Ok(()) as Result<()> + })?; - if do_once { - do_once = false; - udp.send_command( - "/mcp23017a/set", - &ValidPriorityCommand { - inner: SetPin { - pin: 0, - value: true, - }, - valid_until: Utc::now() + TimeDelta::seconds(5), - priority: 0, - }, - addr, - )?; - } - } - Err(UdpRecvPostcardError::NoData) => { - // NoOp - } - Err(err) => { - error!("Rx error: {err}"); - } - } + let f1 = cancel.cancelled(); + pin!(f1); + let udp = block_on(async { + let f2 = udp; + select(f1, f2).await + }); + let udp = match udp { + Either::Left(_) => bail!("Cancelled Before UDP established"), + Either::Right(x) => x.0?, + }; + (udp_thread, udp) + }; + + let flight_addr = RwLock::new(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)); + let lock = flight_addr.blocking_write(); + + scope(|scope| { + let client = Arc::new(Client::connect("ws://localhost:8080/backend")?); + + let tlm = TelemetryHandler::new(client.clone(), &flight_addr, lock, &udp, cancel.clone()); + let cmd = CommandHandler::new(client, &flight_addr, &udp, cancel.clone()); + + let tlm_thread = Builder::new() + .name("telemetry-handler".to_string()) + .spawn_scoped(scope, move || tlm.run())?; // move to take ownership (drop when exited) + + let cmd_thread = Builder::new() + .name("command-handler".to_string()) + .spawn_scoped(scope, move || cmd.run())?; + + // Force the thread panics into anyhow errors + tlm_thread.join().map_err(|e| anyhow!("{e:?}"))??; + cmd_thread.join().map_err(|e| anyhow!("{e:?}"))??; + Ok(()) as Result<()> + })?; + + info!("Sending Shutdown Command"); + + if let Ok(flight_addr) = flight_addr.try_read() { + block_on(async { udp.send_command("/shutdown", &(), *flight_addr).await })?; } - if let Some(flight_addr) = flight_addr { - udp.send_command("/shutdown", &(), flight_addr)?; - - // let cmd_data = CommandData::Shutdown; - // udp.send_postcard(&cmd_data, &mut buffer, flight_addr)?; - - // let cmd_data = SetPin { - // pin: 4, - // value: true, - // valid_until: Utc::now(), - // priority: 120, - // }; - // let cmd_data = postcard::to_allocvec(&cmd_data)?; - // - // let cmd = CommandHeader { - // name: "/shutdown", - // data: &cmd_data, - // }; - // - // let encoded = postcard::to_allocvec(&cmd)?; - // println!("{}", hex::encode(&encoded)); - // - // let decoded = postcard::from_bytes::(&encoded)?; - // println!("{decoded:?}"); - // - // let (decoded, remainder) = postcard::take_from_bytes::(decoded.data)?; - // ensure!(remainder.is_empty(), "Not all command bytes consumed"); - // println!("{decoded:?}"); - - // let mut another_buffer = Cursor::new([0u8; 512]); - // // ciborium::into_writer(&cmd, &mut another_buffer)?; - // let _ = Serializer::writer(&cmd, &mut another_buffer)?; - // let size_encoded = usize::try_from(another_buffer.position())?; - - // let _ = test(&another_buffer.get_ref()[0..size_encoded])?; - } + udp_shutdown.cancel(); + udp_thread.join().map_err(|e| anyhow!("{e:?}"))??; Ok(()) } diff --git a/ground/src/telemetry.rs b/ground/src/telemetry.rs new file mode 100644 index 0000000..86b756a --- /dev/null +++ b/ground/src/telemetry.rs @@ -0,0 +1,142 @@ +use api::client::Client; +use api::client::telemetry::{TelemetryHandle, TelemetryRegistry}; +use futures::TryFutureExt; +use futures::future::join_all; +use log::{error, trace}; +use nautilus_common::on_drop::on_drop; +use nautilus_common::telemetry::{SwitchBank, Telemetry, TelemetryMessage}; +use nautilus_common::udp::UdpRecvPostcardError; +use nautilus_common::udp::tokio::AsyncUdpSocketExt; +use std::net::SocketAddr; +use std::sync::Arc; +use tokio::net::UdpSocket; +use tokio::sync::{RwLock, RwLockWriteGuard}; +use tokio::task::yield_now; +use tokio::{join, pin, select}; +use tokio_util::sync::CancellationToken; + +pub struct TelemetryHandler<'a> { + tlm: TelemetryRegistry, + flight_addr: &'a RwLock, + lock: Option>, + udp: &'a UdpSocket, + cancel: CancellationToken, +} + +impl<'a> TelemetryHandler<'a> { + pub fn new( + client: Arc, + flight_addr: &'a RwLock, + lock: RwLockWriteGuard<'a, SocketAddr>, + udp: &'a UdpSocket, + cancel: CancellationToken, + ) -> Self { + Self { + tlm: TelemetryRegistry::new(client), + flight_addr, + lock: Some(lock), + udp, + cancel, + } + } + + /// Run this telemetry handler. + /// Note: this method is expected to block so should run in its own thread + pub fn run(mut self) -> anyhow::Result<()> { + let cancel = self.cancel.clone(); + // Trigger a shutdown if we exit the telemetry process for some reason (including panic) + let _shutdown_when_closed = on_drop(move || cancel.cancel()); + + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build()?; + + runtime.block_on(async { + let mut context = TelemetryContext::new(&self).await; + + let mut buffer = [0u8; 512]; + + while !self.cancel.is_cancelled() { + select! { + () = self.cancel.cancelled() => {}, + incoming = self.udp.recv_postcard::(&mut buffer) => { + match incoming { + Ok((tlm, addr)) => { + trace!("{tlm:?}"); + + let flight_addr_update = async { + // The first time around we will use the lock given to us + // Other times we will grab a new lock + // self.re + let mut lock = match self.lock.take() { + None => self.flight_addr.write().await, + Some(lock) => lock, + }; + // Update the value in the lock + *lock = addr; + }; + pin!(flight_addr_update); + + // We can do these two operations concurrently + join!( + flight_addr_update, + context.step(tlm), + ); + }, + Err(UdpRecvPostcardError::NoData) => { + // This shouldn't be possible when using a tokio socket I don't think + // But let's just yield our time anyways + yield_now().await; + }, + Err(err) => { + error!("Rx error: {err}"); + }, + } + } + } + } + + // Explicit Drop + drop(self); + + Ok(()) + }) + } +} + +struct TelemetryContext { + bank_a: Vec>, + bank_b: Vec>, +} + +impl TelemetryContext { + async fn new(tlm: &TelemetryHandler<'_>) -> Self { + let bank_a = + join_all((0..16).map(|i| tlm.tlm.register::(format!("switch.bank_a.{i}")))).await; + let bank_b = + join_all((0..16).map(|i| tlm.tlm.register::(format!("switch.bank_b.{i}")))).await; + + Self { bank_a, bank_b } + } + + async fn step(&mut self, tlm: Telemetry) { + match tlm.message { + TelemetryMessage::SwitchState { bank, switches } => { + let bank_handles = match bank { + SwitchBank::A => &self.bank_a, + SwitchBank::B => &self.bank_b, + }; + assert!(bank_handles.len() >= switches.iter().len()); + join_all(switches.into_iter().enumerate().map(|(i, state)| { + bank_handles[i] + .publish(state, tlm.timestamp) + .unwrap_or_else(move |err| { + // We don't need to bubble this error up, just report it + error!("Failed to publish telemetry for switch {bank} {i}: {err}"); + }) + })) + .await; + } + } + } +}