diff --git a/.DS_Store b/.DS_Store index 0409a9b..254e579 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Cargo.lock b/Cargo.lock index 257b035..b5f20f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,18 +17,27 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] -name = "anstream" -version = "0.6.19" +name = "android_system_properties" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -41,44 +50,44 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.9" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "bitflags" @@ -88,9 +97,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "castaway" @@ -102,16 +117,39 @@ dependencies = [ ] [[package]] -name = "cfg-if" -version = "1.0.1" +name = "cc" +version = "1.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] [[package]] name = "clap" -version = "4.5.41" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", @@ -119,9 +157,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.41" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", @@ -131,9 +169,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.41" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", "proc-macro2", @@ -143,21 +181,21 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.5" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "colorchoice" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "compact_str" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" +checksum = "7fd622ebbb56a5b2ccb651b32b911cdeb2a9b4b11776b2473bf26a26a286244e" dependencies = [ "castaway", "cfg-if", @@ -169,12 +207,12 @@ dependencies = [ [[package]] name = "config_lib" -version = "0.1.0" +version = "0.1.1" dependencies = [ "env_logger", "log", "rand", - "toml_edit 0.23.2", + "toml_edit 0.23.10+spec-1.0.0", ] [[package]] @@ -195,18 +233,18 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "crc" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] [[package]] name = "crc-catalog" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" [[package]] name = "crossbeam-channel" @@ -245,9 +283,9 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.12.1", "crossterm_winapi", - "mio 1.0.4", + "mio 1.2.1", "parking_lot", "rustix", "signal-hook", @@ -352,19 +390,13 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", ] -[[package]] -name = "embedded-hal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" - [[package]] name = "enum-map" version = "2.7.3" @@ -387,18 +419,18 @@ dependencies = [ [[package]] name = "enumset" -version = "1.1.10" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b07a8dfbbbfc0064c0a6bdf9edcf966de6b1c33ce344bdeca3b41615452634" +checksum = "839c4174b41e75c8f7306110b2c51996a293b8d1d850edd529011841d9fede7d" dependencies = [ "enumset_derive", ] [[package]] name = "enumset_derive" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43e744e4ea338060faee68ed933e46e722fb7f3617e722a5772d7e856d8b3ce" +checksum = "4bd536557b58c682b217b8fb199afdff47cd3eff260623f19e77074eb073d63a" dependencies = [ "darling", "proc-macro2", @@ -408,9 +440,9 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.3" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" dependencies = [ "log", "regex", @@ -418,9 +450,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.8" +version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" dependencies = [ "anstream", "anstyle", @@ -437,14 +469,20 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "fnv" version = "1.0.7" @@ -452,55 +490,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "getrandom" -version = "0.3.3" +name = "futures-core" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[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", - "wasi 0.14.2+wasi-0.2.4", -] - -[[package]] -name = "gpiocdev" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ae5319702c7dc34334b9f5e2b73d4ffedb0544675b5931af61b3b13a13f928e" -dependencies = [ - "gpiocdev-uapi", - "thiserror", -] - -[[package]] -name = "gpiocdev-embedded-hal" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af983262d31a1acaec17c949a0bb2a7df7fbdd7ab89c9a6bf6f98a38b25bd690" -dependencies = [ - "embedded-hal", - "gpiocdev", - "thiserror", -] - -[[package]] -name = "gpiocdev-uapi" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbb160ed63d4235176759e49b7e26aa063603ec4547e458ab1ea98483040028c" -dependencies = [ - "bitflags 2.9.1", - "ioctl-sys", - "libc", - "thiserror", + "wasip2", ] [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "heck" @@ -508,6 +537,30 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -516,9 +569,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indexmap" -version = "2.10.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown", @@ -534,48 +587,54 @@ dependencies = [ "mach2", ] -[[package]] -name = "ioctl-sys" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd11f3a29434026f5ff98c730b668ba74b1033637b8817940b54d040696133c" - [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" -version = "0.2.15" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102" dependencies = [ "jiff-static", "log", "portable-atomic", "portable-atomic-util", - "serde", + "serde_core", ] [[package]] name = "jiff-static" -version = "0.2.15" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "js-sys" +version = "0.3.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -584,9 +643,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.174" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "linux-raw-sys" @@ -596,19 +655,31 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "113b30b4cd05f7c06868fdb2854f66a7b9fece9a48425351cd532e810d74024f" + +[[package]] +name = "logger" +version = "0.1.0" +dependencies = [ + "chrono", + "config_lib", + "env_logger", + "log", + "protocol_lib", + "serialport", + "signal-hook", +] [[package]] name = "mach2" @@ -621,13 +692,22 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] [[package]] name = "menu_tui" -version = "0.2.0" +version = "0.2.2" dependencies = [ "clap", "config_lib", @@ -645,20 +725,33 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "windows-sys 0.48.0", ] [[package]] name = "mio" -version = "1.0.4" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "log", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "nix" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" +dependencies = [ + "bitflags 1.3.2", + "cc", + "cfg-if", + "libc", + "memoffset", ] [[package]] @@ -696,9 +789,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-integer" @@ -750,21 +843,21 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -772,28 +865,34 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] -name = "portable-atomic" -version = "1.11.1" +name = "pin-project-lite" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.4" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" dependencies = [ "portable-atomic", ] @@ -815,9 +914,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -833,9 +932,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -848,9 +947,9 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha", "rand_core", @@ -868,27 +967,27 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom", ] [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.12.1", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -898,9 +997,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -909,13 +1008,25 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rk_nku_menu" +version = "0.1.1" +dependencies = [ + "config_lib", + "env_logger", + "log", + "menu_tui", + "sysfs_gpio", + "thiserror", +] [[package]] name = "rk_nku_sync" -version = "0.1.0" +version = "0.1.1" dependencies = [ "clap", "config_lib", @@ -924,26 +1035,13 @@ dependencies = [ "protocol_lib", ] -[[package]] -name = "rk_smart_menu" -version = "0.1.0" -dependencies = [ - "config_lib", - "env_logger", - "gpiocdev", - "gpiocdev-embedded-hal", - "log", - "menu_tui", - "thiserror", -] - [[package]] name = "rustix" version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.12.1", "errno", "libc", "linux-raw-sys", @@ -958,9 +1056,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "scopeguard" @@ -970,18 +1068,27 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -990,14 +1097,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] @@ -1011,22 +1119,28 @@ dependencies = [ [[package]] name = "serialport" -version = "4.7.2" +version = "4.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb0bc984f6af6ef8bab54e6cf2071579ee75b9286aa9f2319a0d220c28b0a2b" +checksum = "a4d91116f97173694f1642263b2ff837f80d933aa837e2314969f6728f661df3" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.12.1", "cfg-if", "core-foundation", "core-foundation-sys", "io-kit-sys", "mach2", - "nix", + "nix 0.26.4", "scopeguard", "unescaper", - "winapi", + "windows-sys 0.52.0", ] +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + [[package]] name = "signal-hook" version = "0.3.18" @@ -1039,25 +1153,32 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" dependencies = [ "libc", "mio 0.8.11", - "mio 1.0.4", + "mio 1.2.1", "signal-hook", ] [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + [[package]] name = "smallvec" version = "1.15.1" @@ -1078,9 +1199,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.104" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1088,19 +1209,28 @@ dependencies = [ ] [[package]] -name = "thiserror" -version = "2.0.12" +name = "sysfs_gpio" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "e8808c55bc926565c62ef7838bcaa8add51585236803e2bdfa1472e3a3ab5e17" +dependencies = [ + "nix 0.23.2", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -1109,9 +1239,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.44" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", @@ -1119,22 +1249,22 @@ dependencies = [ "num-conv", "num_threads", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", @@ -1163,11 +1293,11 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.0" +version = "0.7.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -1181,29 +1311,29 @@ dependencies = [ "serde_spanned", "toml_datetime 0.6.11", "toml_write", - "winnow", + "winnow 0.7.15", ] [[package]] name = "toml_edit" -version = "0.23.2" +version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1dee9dc43ac2aaf7d3b774e2fba5148212bf2bd9374f4e50152ebe9afd03d42" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ "indexmap", - "toml_datetime 0.7.0", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "toml_writer", - "winnow", + "winnow 0.7.15", ] [[package]] name = "toml_parser" -version = "1.0.1" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow", + "winnow 1.0.3", ] [[package]] @@ -1214,30 +1344,30 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "toml_writer" -version = "1.0.2" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] name = "unescaper" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c01d12e3a56a4432a8b436f293c25f4808bdf9e9f9f98f9260bba1f1bc5a1f26" +checksum = "4064ed685c487dbc25bd3f0e9548f2e34bab9d18cefc700f9ec2dba74ba1138e" dependencies = [ "thiserror", ] [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-width" @@ -1264,12 +1394,57 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" +dependencies = [ + "unicode-ident", ] [[package]] @@ -1294,6 +1469,65 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -1303,6 +1537,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[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" @@ -1314,11 +1557,11 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.60.2" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-targets 0.53.2", + "windows-link", ] [[package]] @@ -1345,29 +1588,13 @@ dependencies = [ "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_gnullvm", "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.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -1380,12 +1607,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -1398,12 +1619,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -1416,24 +1631,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[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.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -1446,12 +1649,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -1464,12 +1661,6 @@ 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.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -1482,12 +1673,6 @@ 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.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -1500,29 +1685,26 @@ 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.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" dependencies = [ "memchr", ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "winnow" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.1", -] +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "xi-unicode" @@ -1532,20 +1714,26 @@ checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 98fb026..a226c4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ members = [ "menu_tui", "protocol_lib", "rk_nku_sync", - "rk_nku_menu", + "rk_nku_menu", "logger", ] [workspace.package] diff --git a/Cross.toml b/Cross.toml index be65704..9b152cb 100644 --- a/Cross.toml +++ b/Cross.toml @@ -5,3 +5,8 @@ default-target = "aarch64-unknown-linux-gnu" [build.zig] enable = true # Сборка с участием линковщика Zig version = "2.31" # Версия glibc, установленная на RK3399-ROC-PC-PRO + +# [target.aarch64-unknown-linux-gnu] +# pre-build = [ +# "apt-get update && apt-get install --assume-yes libxkbcommon" +# ] \ No newline at end of file diff --git a/config_lib/.DS_Store b/config_lib/.DS_Store index 5008ddf..6486560 100644 Binary files a/config_lib/.DS_Store and b/config_lib/.DS_Store differ diff --git a/config_lib/Cargo.toml b/config_lib/Cargo.toml index 0253944..2003596 100644 --- a/config_lib/Cargo.toml +++ b/config_lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "config_lib" -version = "0.1.0" +version = "0.1.1" edition = "2024" authors.workspace = true diff --git a/config_lib/src/device_config.rs b/config_lib/src/device_config.rs index 028412e..5e5cc59 100644 --- a/config_lib/src/device_config.rs +++ b/config_lib/src/device_config.rs @@ -26,12 +26,24 @@ impl DeviceConfig { debug!("Parameter list: {:#?}", parameter_list); let mut parameter_map = HashMap::new(); - for parameter in parameter_list { + 'mapify: for parameter in parameter_list { + // Пропускаем параметры, которые не требуют синхронизации с внешним MCU + // Актуально для {protocol_name}_scheme.toml + if let Ok(should_sync) = toml_config.get_string_value(¶meter, "should_sync") { + match should_sync.as_str() { + "false" => { + continue 'mapify; + } + _ => (), + } + } + let device_parameter = Parameter { description: toml_config.get_string_value(¶meter, "name")?, value: toml_config.get_string_value(¶meter, "current")?, possible_values: toml_config.get_array_value(¶meter, "possible_values")?, }; + parameter_map.insert(parameter, device_parameter); } @@ -44,6 +56,7 @@ impl DeviceConfig { } /// ## Сохранение текущих значений параметров в TOML-файл `self.schema_path` + /// TODO: параметры с `should_sync = false` не сохраняются??? pub fn save_parameters_values(&self) -> Result<(), String> { let mut toml_config = TomlScheme::new(&self.scheme.get_path_to_scheme_file()).map_err(|e| e.to_string())?; diff --git a/config_lib/src/lib.rs b/config_lib/src/lib.rs index e184bc4..c833f71 100644 --- a/config_lib/src/lib.rs +++ b/config_lib/src/lib.rs @@ -1,2 +1,3 @@ pub mod device_config; +pub mod serial_config; mod toml_parser; diff --git a/config_lib/src/serial_config.rs b/config_lib/src/serial_config.rs new file mode 100644 index 0000000..152d397 --- /dev/null +++ b/config_lib/src/serial_config.rs @@ -0,0 +1,38 @@ +use crate::device_config::DeviceConfig; +use log::debug; + +pub struct SerialPortConfig { + serial_name: String, + serial_baudrate: u32, +} + +impl SerialPortConfig { + /// Чтение параметров последовательного порта из файла-схемы TOML + pub fn new(path_to_scheme: &str) -> Result { + let smart_serial_parameters = DeviceConfig::create_parameter_list(path_to_scheme)?; + + let serial_name = smart_serial_parameters.get_parameter_value("device")?; + let serial_baudrate = smart_serial_parameters + .get_parameter_value("baudrate")? + .parse::() + .map_err(|e: std::num::ParseIntError| e.to_string())?; + + debug!("serial port_name: {}", serial_name); + debug!("serial baudrate: {}", serial_baudrate); + + Ok(SerialPortConfig { + serial_name, + serial_baudrate, + }) + } + + /// Чтение имени последовательного порта из конфига + pub fn get_serial_name(&self) -> String { + self.serial_name.clone() + } + + /// Чтение скорости последовательного порта из конфига + pub fn get_serial_baudrate(&self) -> u32 { + self.serial_baudrate + } +} diff --git a/docs/build'n'deploy/README.md b/docs/build'n'deploy/README.md deleted file mode 100644 index c6b5583..0000000 --- a/docs/build'n'deploy/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Настройка рабочего окружения - -## Кросскомпиляция - -- [cargo-zigbuild](https://github.com/rust-cross/cargo-zigbuild) -- [cross-rs](https://github.com/cross-rs/cross) - -### Сборка - -> Важно: необходимо использовать версию линковщика, совпадающую с версией, установленной на целевом устройстве - -- cross-rs: `cross build --target=arm-unknown-linux-gnueabihf --bin --release` - -- zigbuild: `cargo zigbuild --target=arm-unknown-linux-gnueabihf.[версия линкера на целевом устройстве] --bin --release` - -> Для кросскомпиляции `serialport` (libudev не поддерживается на MacOS & WIN64) указать фича-флаг `default-features = false` - -## Загрузка на целевое устройство - -`scp -P [port_number] [path/to/bin] [hostname]@[ip_address]:/home/[user-name]` diff --git a/docs/vscode/Install.md b/docs/vscode/Install.md deleted file mode 100644 index 728d9ed..0000000 --- a/docs/vscode/Install.md +++ /dev/null @@ -1,5 +0,0 @@ -# Установка необходимых расширений - -```bash -cat vs_code_extensions_list.txt | xargs -n 1 code --install-extension -``` diff --git a/docs/vscode/vs_code_extensions_list.txt b/docs/vscode/vs_code_extensions_list.txt deleted file mode 100644 index 95f6692..0000000 Binary files a/docs/vscode/vs_code_extensions_list.txt and /dev/null differ diff --git a/logger/Cargo.toml b/logger/Cargo.toml new file mode 100644 index 0000000..43b9af5 --- /dev/null +++ b/logger/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "logger" +version = "0.1.0" +edition = "2024" +authors.workspace = true + +[dependencies] +chrono = "0.4" +protocol_lib = { path = "../protocol_lib" } +config_lib = { path = "../config_lib" } +log = { workspace = true } +env_logger = { workspace = true } +serialport = { workspace = true } +signal-hook = "0.3" \ No newline at end of file diff --git a/logger/src/logger.rs b/logger/src/logger.rs new file mode 100644 index 0000000..b21ced0 --- /dev/null +++ b/logger/src/logger.rs @@ -0,0 +1,179 @@ +/// ### Модуль логгирования в файл +/// - Предоставляет функционал для записи логов в файл с временными метками +/// - Каждые сутки создает новый файл для записи +/// - Предоставляет статистику: количество корректных сообщений, количество ошибок, количество созданных файлов +use chrono::{Local, NaiveDate}; +use log::{trace, warn}; +use protocol_lib::mu_frame::MUFrame; +use std::fs::{File, OpenOptions}; +use std::io::{self, BufWriter, Write}; +pub struct RollingFileLogger { + /// Директория для хранения логов + log_dir: String, + /// Текущее время с начала старта + current_date: NaiveDate, + /// Текущий файл, в который ведётся запись + current_file: Option>, + /// Буфер для промежуточного хранения логов + buffer: Vec, + /// Емкость буфера (хранит логи перед записью в файл) + max_buffer_size: usize, + /// Статистика логгера + stats: LoggerStats, +} + +#[derive(Debug, Clone, Default)] +/// Статистика текущей сессии логгирования +pub struct LoggerStats { + /// Корректно принятые, распакованные сообщения + pub total_messages: u64, + /// Количество возникших ошибок (парсинг, таймаут приема) + pub total_errors: u64, + /// Количество созданных файлов + pub files_rotated: u64, +} + +impl RollingFileLogger { + pub fn new(log_dir: &str, max_buffer_size: usize) -> io::Result { + std::fs::create_dir_all(log_dir)?; + + let logger = Self { + log_dir: log_dir.to_string(), + current_date: Local::now().date_naive(), + current_file: None, + buffer: Vec::new(), + max_buffer_size, + stats: LoggerStats::default(), + }; + + Ok(logger) + } + + /// Логгирование распакованного сообщения + pub fn log_frame(&mut self, opcode: u8, payload: &[u8]) -> io::Result<()> { + let payload_str = String::from_utf8_lossy(payload); + let message = format!( + "СООБЩЕНИЕ | ТИП: {} | ДАННЫЕ: {}", + MUFrame::get_opcode_description(opcode), + payload_str + ); + + trace!("{}", message); + + self.log(message)?; + self.stats.total_messages += 1; + + Ok(()) + } + + /// Логгирование ошибки + pub fn log_error(&mut self, error: &str) -> io::Result<()> { + let message = format!("ОШИБКА | {}", error); + self.log(message)?; + self.stats.total_errors += 1; + + Ok(()) + } + + fn log(&mut self, message: String) -> io::Result<()> { + let now = Local::now(); + let new_date = now.date_naive(); + + // Прошли сутки - создаем новый файл для записи + if new_date != self.current_date { + self.flush()?; + self.current_file = None; + self.current_date = new_date; + self.stats.files_rotated += 1; + + warn!("[LOG] Date changed, new log file created: {}", new_date); + } + if self.current_file.is_none() { + let file = self.open_log_file()?; + self.current_file = Some(BufWriter::new(file)); + } + + let timestamped = format!("[{}] {}", now.format("%Y-%m-%d %H:%M:%S%.3f"), message); + + self.buffer.push(timestamped); + + // Запись в файл после заполнения буфера + if self.buffer.len() >= self.max_buffer_size { + self.flush()?; + } + + Ok(()) + } + + /// **Открытие файла для записи** + /// > Файл будет создан, если он не существует + fn open_log_file(&self) -> io::Result { + let filename = format!( + "{}/uart_log_{}.txt", + self.log_dir, + self.current_date.format("%Y-%m-%d") + ); + + OpenOptions::new().create(true).append(true).open(&filename) + } + + pub fn flush(&mut self) -> io::Result<()> { + if let Some(ref mut file) = self.current_file { + for line in self.buffer.drain(..) { + writeln!(file, "{}", line)?; + } + file.flush()?; + } + Ok(()) + } + + /// Получение статистики текущей сессии логгирования + pub fn stats(&self) -> &LoggerStats { + &self.stats + } + + /// Получение имени файла, в который в данный момент ведётся запись + pub fn current_log_file(&self) -> String { + format!( + "{}/uart_log_{}.txt", + self.log_dir, + self.current_date.format("%Y-%m-%d") + ) + } +} + +impl Drop for RollingFileLogger { + fn drop(&mut self) { + let _ = self.flush(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_log_error() { + let mut logger = RollingFileLogger::new("tests_output", 10).unwrap(); + logger.log_error("Test error").unwrap(); + assert_eq!(logger.stats.total_errors, 1); + } + + #[test] + fn test_log_frame() { + let mut logger = RollingFileLogger::new("tests_output", 10).unwrap(); + logger + .log_frame(0x01, "That was test frame #1".as_bytes()) + .unwrap(); + assert_eq!(logger.stats.total_messages, 1); + } + + #[test] + fn test_flush() { + let mut logger = RollingFileLogger::new("tests_output", 10).unwrap(); + logger + .log_frame(0x01, "That was test frame #2".as_bytes()) + .unwrap(); + logger.flush().unwrap(); + assert_eq!(logger.stats.total_messages, 1); + } +} diff --git a/logger/src/main.rs b/logger/src/main.rs new file mode 100644 index 0000000..1b8ae2b --- /dev/null +++ b/logger/src/main.rs @@ -0,0 +1,135 @@ +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; + +use crate::logger::RollingFileLogger; +use config_lib::serial_config::SerialPortConfig; +use log::{error, info, warn}; +use protocol_lib::inc_parser::{FrameParser, ParseResult}; +use signal_hook::consts::{SIGINT, SIGTERM}; +use signal_hook::iterator::Signals; +use std::time::Duration; + +/// Путь до файла-схемы параметров Serial порта устройства +const SERIAL_PORT_CONFIG_PATH: &str = "rk_nku_configs/rk3399_scheme.toml"; +/// Максимальное время ожидания ответа от устройства (`Heartbeat устройства - 60 секунд`) +const BOARD_RESPONSE_TIMEOUT_MS: std::time::Duration = std::time::Duration::from_secs(65); +/// Размер буфера для хранения принятых данных перед записью в файл +const BUFFER_SIZE: usize = 20; +/// Путь директории для хранения логов +const LOG_DIR: &str = "logs"; +/// Интервал между записями в лог файл +const FLUSH_INTERVAL_MS: u64 = 100; + +mod logger; + +fn main() -> Result<(), Box> { + env_logger::init(); + + // Инициализация обработчиков сигналов ОС + let mut signals = Signals::new(&[SIGINT, SIGTERM])?; + let handle = signals.handle(); + let running = Arc::new(AtomicBool::new(true)); + let running_clone = Arc::clone(&running); + + // Создание потока для обработки сигналов + let signal_thread = thread::spawn(move || { + for sig in signals.forever() { + match sig { + SIGINT => { + warn!("\n[*] Получен сигнал SIGINT."); + running_clone.store(false, Ordering::SeqCst); + break; + } + SIGTERM => { + warn!("\n[*] Получен сигнал SIGTERM."); + running_clone.store(false, Ordering::SeqCst); + break; + } + _ => {} + } + } + }); + + // Настройка последовательного порта + let serial_port_config = SerialPortConfig::new(SERIAL_PORT_CONFIG_PATH)?; + let port_name = serial_port_config.get_serial_name(); + let baudrate = serial_port_config.get_serial_baudrate(); + + info!("{}: {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); + info!("Порт: {:<30}", port_name); + info!("Скорость: {:<24}", baudrate); + info!("Место хранения логов: {:<27}", LOG_DIR); + + let mut serial_port = serialport::new(port_name, baudrate) + .timeout(BOARD_RESPONSE_TIMEOUT_MS) + .open()?; + + let mut logger = RollingFileLogger::new(LOG_DIR, BUFFER_SIZE)?; + let mut parser = FrameParser::new(); + + let mut buffer = [0u8; 512]; + let mut last_flush = std::time::Instant::now(); + let mut frame_counter = 0; + + while running.load(Ordering::SeqCst) { + match serial_port.read(&mut buffer) { + Ok(n) if n > 0 => { + // Обработка принятого сообщения побайтно + for &byte in &buffer[0..n] { + match parser.process_raw_byte(byte) { + ParseResult::FrameReady(frame) => { + logger.log_frame(frame.get_opcode(), frame.get_data().as_slice())?; + + frame_counter += 1; + + if frame_counter % 10 == 0 { + info!("[*] Записано {} сообщений", frame_counter); + } + } + ParseResult::Error(e) => { + logger.log_error(&e)?; + error!("[!] Ошибка парсинга: {}", e); + } + ParseResult::Incomplete => {} + } + } + last_flush = std::time::Instant::now(); + } + Ok(_) => {} + Err(e) => { + let error_msg = format!("Ошибка при чтении порта: {}", e); + logger.log_error(&error_msg)?; + error!("[!] {}", error_msg); + + // Try to reconnect + thread::sleep(Duration::from_millis(500)); + } + } + + // Periodic flush + if last_flush.elapsed() > Duration::from_millis(FLUSH_INTERVAL_MS) { + logger.flush()?; + } + } + + // Graceful shutdown + warn!("\n[*] Ожидания закрытие потока чтения сигналов ОС..."); + handle.close(); + let _ = signal_thread.join(); + + // Final flush + logger.flush()?; + + let stats = logger.stats(); + + info!("########################################################"); + info!(". Статистика сессии ."); + info!("Всего сообщений: {:<26}в•‘", stats.total_messages); + info!("Всего ошибок: {:<26}в•‘", stats.total_errors); + info!("Создано файлов с логами: {:<25}в•‘", stats.files_rotated); + info!("Текущий файл: {:<30}в•‘", logger.current_log_file()); + info!("########################################################"); + + Ok(()) +} diff --git a/logger/tests_output/uart_log_2025-12-10.txt b/logger/tests_output/uart_log_2025-12-10.txt new file mode 100644 index 0000000..6cce750 --- /dev/null +++ b/logger/tests_output/uart_log_2025-12-10.txt @@ -0,0 +1,5 @@ +[2025-12-10 14:34:29.234] ERROR | Test error +[2025-12-10 14:34:29.234] FRAME | OPCODE: 0x01 | CRC: 0x1234 | PAYLOAD: That was test frame +[2025-12-10 14:36:07.753] ERROR | Test error +[2025-12-10 14:36:07.753] FRAME | OPCODE: 0x01 | PAYLOAD: That was test frame #1 +[2025-12-10 14:36:07.753] FRAME | OPCODE: 0x01 | PAYLOAD: That was test frame #2 diff --git a/logger/tests_output/uart_log_2025-12-11.txt b/logger/tests_output/uart_log_2025-12-11.txt new file mode 100644 index 0000000..c40c968 --- /dev/null +++ b/logger/tests_output/uart_log_2025-12-11.txt @@ -0,0 +1,3 @@ +[2025-12-11 11:26:46.696] СООБЩЕНИЕ | ТИП: ОШИБКА | ДАННЫЕ: That was test frame #2 +[2025-12-11 11:26:46.696] ОШИБКА | Test error +[2025-12-11 11:26:46.696] СООБЩЕНИЕ | ТИП: ОШИБКА | ДАННЫЕ: That was test frame #1 diff --git a/menu_tui/Cargo.toml b/menu_tui/Cargo.toml index a133401..762da89 100644 --- a/menu_tui/Cargo.toml +++ b/menu_tui/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "menu_tui" -version = "0.2.0" +version = "0.2.2" edition = "2024" authors.workspace = true diff --git a/menu_tui/TODO.md b/menu_tui/TODO.md deleted file mode 100644 index ba4a936..0000000 --- a/menu_tui/TODO.md +++ /dev/null @@ -1,9 +0,0 @@ -# Рекомендации по улучшению - - 1.Рефакторинг обработки ошибок: Заменить все  `unwrap()` / `expect()`  на proper error handling с кастомным error enum - 2.Добавить логирование: Интегрировать  `log` / `defmt`  с выводом на UART для embedded-отладки - 3.Типобезопасные идентификаторы: Использовать `enum` вместо строк для имен `view` - 4.Оптимизация памяти: Рассмотреть  `Rc>`  для state management - 5.Unit-тесты: Покрыть тестами критичные модули (`DeviceParameters`, `NavigationManager`) - 6.Реализовать `update_view`: Добавить функционал обновления прошивки через HTTP/UART - 7.Документация: Дополнить `rustdoc` комментариями и примерами использования diff --git a/menu_tui/examples/simple.rs b/menu_tui/examples/simple.rs index c5702cc..3facdda 100644 --- a/menu_tui/examples/simple.rs +++ b/menu_tui/examples/simple.rs @@ -57,7 +57,7 @@ fn simulate_gpio_handlers(nav_manager: NavigationManager) { thread::sleep(Duration::from_secs(3)); loop { - thread::sleep(Duration::from_millis(3000)); + thread::sleep(Duration::from_millis(4000)); // Симуляция нажатия кнопки GPIO nav_select.select_item(); diff --git a/menu_tui/src/menu_navigation.rs b/menu_tui/src/menu_navigation.rs index cfaf075..1dcbe2d 100644 --- a/menu_tui/src/menu_navigation.rs +++ b/menu_tui/src/menu_navigation.rs @@ -12,26 +12,6 @@ use cursive::event::{Event, EventResult, Key}; use cursive::views::{CircularFocus, ListView, SelectView}; use cursive::{CbSink, Cursive, View}; -// TODO: Перенести в отдельный модуль -enum ActiveMenuView { - MainView, - ConfigView, - ExitView, - UpdateView, -} - -impl From<&str> for ActiveMenuView { - fn from(value: &str) -> Self { - match value { - "main_menu" => ActiveMenuView::MainView, - "config_menu" => ActiveMenuView::ConfigView, - "exit_menu" => ActiveMenuView::ExitView, - "update_menu" => ActiveMenuView::UpdateView, - _ => ActiveMenuView::MainView, - } - } -} - /// Менеджер навигации для управления меню c вызывающей стороны pub struct NavigationManager { // CbSink  — это thread-safe канал, позволяющий отправлять callback-функции из любого потока. diff --git a/menu_tui/src/views/config_view.rs b/menu_tui/src/views/config_view.rs index b5475a5..72d4d6b 100644 --- a/menu_tui/src/views/config_view.rs +++ b/menu_tui/src/views/config_view.rs @@ -63,7 +63,7 @@ pub(crate) fn show_config_view(siv: &mut Cursive) { // Кнопка возврата в главное меню parameter_list.add_child( "", - Button::new("Назад в главное меню", |s| { + Button::new("Назад", |s| { let state: MenuAppState = s .take_user_data() .expect("Не удалось выполнить take_user_data"); diff --git a/protocol_lib/.DS_Store b/protocol_lib/.DS_Store new file mode 100644 index 0000000..2043062 Binary files /dev/null and b/protocol_lib/.DS_Store differ diff --git a/protocol_lib/MU Protocol.md b/protocol_lib/MU Protocol.md deleted file mode 100644 index 893abdc..0000000 --- a/protocol_lib/MU Protocol.md +++ /dev/null @@ -1,93 +0,0 @@ -# **MU_protocol — Протокол обмена данными между микроконтроллером и одноплатным компьютером** - -## **1. Общее описание** - -Протокол предназначен для передачи данных между **Python Server App** и **одноплатным компьютером** по UART. Протокол обеспечивает: - -- Синхронизацию пакетов -- Целостность данных (через CRC16) -- Гибкость в передаче данных разных типов (определяется через `opcode`) - ---- - -## **2. Структура пакета** - -Каждый пакет состоит из следующих полей: - -| Поле | Размер | Тип | Описание | -|------------|--------|----------|----------| -| `sync1` | 1 байт | uint8 | Стартовый байт синхронизации, значение `0xAA` | -| `size` | 1 байт | uint8 | Размер поля `data` в байтах (от 0 до 255) | -| `opcode` | 1 байт | uint8 | Код операции (например, 0xDA для передачи данных о состоянии лифта) | -| `data` | N байт | массив | Полезная нагрузка | -| `crc16` | 2 байта| uint16 | CRC-16 контрольная сумма | -| `sync2` | 1 байт | uint8 | Конечный байт синхронизации, значение `0xBB` | - -### **Общая длина пакета**: -``` -Длина = 1 (sync1) + 1 (size) + 1 (opcode) + N (data) + 2 (crc16) + 1 (sync2) = 6 + N байт -``` - ---- - -## **3. Поля пакета** - -### **3.1. `sync1` и `sync2`** -- Используются для синхронизации начала и конца пакета -- Значения: `0xAA` и `0xBB` соответственно - -### **3.2. `size`** -- Определяет длину поля `data` -- Допустимые значения: от 0 до 255 - -### **3.3. `opcode`** -- Код операции, определяющий тип данных в поле `data` -- Примеры: - - `0xDA` — данные о состоянии лифта - - `0xDB` — команда от компьютера к микроконтроллеру - - `0xDC` — подтверждение приёма - - `0xDD` — запрос состояния - - и т.д. - -### **3.4. `data`** -- Полезная нагрузка, формат которой зависит от `opcode` -- Для `opcode: 0xDA` — строка вида `#STM:L%d:R%d:A%d:S%d:M%d:E#\r\n` - -### **3.5. `crc16`** -- CRC-16 контрольная сумма, рассчитанная по следующим параметрам: - -| Параметр | Значение | -|------------|------------------| -| Название | CRC-16 CCITT | -| Полином | `0x1021` (`x^16 + x^12 + x^5 + 1`) | -| Начальное значение | `0xFFFF` | -| Реверс входных данных | Нет | -| Реверс результата | Нет | -| Выходное XOR (`XorOut`)| `0x0000` | -| Контрольное значение (`"123456789"`) | `0x29B1` | -| Максимальная длина блока | 4095 байт (32767 бит) | - ---- - -## **4. Пример пакета** - -### **4.1. Исходные данные** -```c -opcode = 0xDA -data = "#STM:L10:R3:A1:S4:M0:E#\r\n" -``` - -### **4.2. Шаги формирования пакета** - -1. Вычислить длину `data`: `len(data) = 24` -2. Установить `size = 24` -3. Вычислить CRC16 от последовательности: `opcode + data` -4. Сформировать пакет: - -``` -[0xAA] [0x18] [0xDA] [data bytes...] [CRC16_H] [CRC16_L] [0xBB] -``` - ---- - - diff --git a/protocol_lib/src/client.rs b/protocol_lib/src/client.rs index 6dc855f..bd00e52 100644 --- a/protocol_lib/src/client.rs +++ b/protocol_lib/src/client.rs @@ -1,4 +1,4 @@ -use log::{debug, error, warn}; +use log::{error, warn}; use crate::mu_frame::MUFrame; use std::time::Duration; diff --git a/protocol_lib/src/inc_parser.rs b/protocol_lib/src/inc_parser.rs new file mode 100644 index 0000000..a81890a --- /dev/null +++ b/protocol_lib/src/inc_parser.rs @@ -0,0 +1,158 @@ +use crate::{ + MUFrame, + mu_frame::{SYNC1, SYNC2}, +}; + +/// Состояния парсера фреймов +#[derive(Debug, Clone, Copy, PartialEq)] +enum ParserState { + WaitingForSync1, + WaitingForLength, + WaitingForOpcode, + WaitingForPayload { length: u8, read: u8 }, + WaitingForCrcLow, + WaitingForCrcHigh, + WaitingForSync2, +} + +/// Контекст парсера фрейма +pub struct FrameParser { + state: ParserState, + frame_buffer: Vec, +} + +/// Результат парсинга данных принятых по UART +pub enum ParseResult { + /// Фрейм полностью принят + FrameReady(MUFrame), + /// Ошибка парсинга + Error(String), + /// Фрейм принят не полностью + Incomplete, +} + +impl FrameParser { + pub fn new() -> Self { + Self { + state: ParserState::WaitingForSync1, + frame_buffer: Vec::with_capacity(256), + } + } + + pub fn process_raw_byte(&mut self, byte: u8) -> ParseResult { + match self.state { + // Чтение SYNC1 байта + ParserState::WaitingForSync1 => { + if byte == SYNC1 { + self.frame_buffer.clear(); + self.frame_buffer.push(byte); + self.state = ParserState::WaitingForLength; + } + ParseResult::Incomplete + } + // Чтение длины payload + ParserState::WaitingForLength => { + if byte == 0 { + self.state = ParserState::WaitingForSync1; + return ParseResult::Error("Invalid payload length".to_string()); + } + self.frame_buffer.push(byte); + self.state = ParserState::WaitingForOpcode; + ParseResult::Incomplete + } + // Чтение opcode + ParserState::WaitingForOpcode => { + if !MUFrame::is_opcode_correct(byte) { + self.state = ParserState::WaitingForSync1; + return ParseResult::Error("Invalid opcode".to_string()); + } + self.frame_buffer.push(byte); + let length = self.frame_buffer[1]; + self.state = ParserState::WaitingForPayload { length, read: 0 }; + ParseResult::Incomplete + } + // Чтение payload + ParserState::WaitingForPayload { length, read } => { + self.frame_buffer.push(byte); + let new_read = read + 1; + + self.state = if new_read >= length { + ParserState::WaitingForCrcLow + } else { + ParserState::WaitingForPayload { + length, + read: new_read, + } + }; + ParseResult::Incomplete + } + // Чтение CRC - LSB + ParserState::WaitingForCrcLow => { + self.frame_buffer.push(byte); + self.state = ParserState::WaitingForCrcHigh; + ParseResult::Incomplete + } + // Чтение CRC - MSB + ParserState::WaitingForCrcHigh => { + self.frame_buffer.push(byte); + self.state = ParserState::WaitingForSync2; + ParseResult::Incomplete + } + // Чтение SYNC2 + ParserState::WaitingForSync2 => { + self.frame_buffer.push(byte); + + if byte != SYNC2 { + self.state = ParserState::WaitingForSync1; + return ParseResult::Error("Invalid SYNC2 byte".to_string()); + } + + // Попытка десериализации в MuFrame + let result = match MUFrame::deserialize(&self.frame_buffer) { + Ok(frame) => ParseResult::FrameReady(frame), + Err(e) => ParseResult::Error(e), + }; + self.state = ParserState::WaitingForSync1; + result + } + } + } + + /// Сброс состояния парсера в начальное + pub fn reset(&mut self) { + self.state = ParserState::WaitingForSync1; + self.frame_buffer.clear(); + } +} + +impl Default for FrameParser { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::MUFrame; + + #[test] + fn test_parsing() { + let serialized_vec = vec![ + 0xAA, 0x1A, 0xC0, 0x23, 0x53, 0x54, 0x4D, 0x3A, 0x4C, 0x30, 0x3A, 0x52, 0x31, 0x36, + 0x3A, 0x41, 0x31, 0x3A, 0x53, 0x30, 0x3A, 0x4D, 0x30, 0x3A, 0x45, 0x23, 0x0D, 0x0A, + 0x00, 0x80, 0x77, 0xBB, + ]; + + let mut parser = FrameParser::new(); + let deserilized_frame = MUFrame::deserialize(&serialized_vec).unwrap(); + assert!(deserilized_frame.validate_frame().is_ok()); + + for byte in serialized_vec { + let result = parser.process_raw_byte(byte); + if let ParseResult::FrameReady(frame) = result { + assert_eq!(frame, deserilized_frame); + } + } + } +} diff --git a/protocol_lib/src/lib.rs b/protocol_lib/src/lib.rs index 17692fa..4e49c0a 100644 --- a/protocol_lib/src/lib.rs +++ b/protocol_lib/src/lib.rs @@ -1,9 +1,11 @@ pub mod client; -mod mu_frame; +pub mod inc_parser; +pub mod mu_frame; +use crate::inc_parser::{FrameParser, ParseResult}; use crate::mu_frame::MUFrame; -use log::trace; +use log::{trace, warn}; use std::{ io::{Read, Write}, thread, @@ -23,6 +25,35 @@ fn send_proto_message(data: MUFrame, mut writer: Writer) -> Resul Ok(()) } +/// Прием сообщения +fn _recv_proto_messages(mut reader: Reader) -> Result, String> { + let mut read_buffer = [0; 512]; + let mut parser = FrameParser::new(); + let mut result = Vec::new(); + + match reader.read(&mut read_buffer) { + Ok(n) if n > 0 => { + trace!("Received raw message: {read_buffer:?}"); + for byte in &read_buffer[0..n] { + match parser.process_raw_byte(*byte) { + ParseResult::FrameReady(frame) => { + result.push(frame); + parser.reset(); + } + ParseResult::Error(e) => { + warn!("Error parsing frame: {}", e); + } + ParseResult::Incomplete => {} + } + } + } + Ok(_) => {} + Err(e) => return Err(e.to_string()), + }; + + Ok(result) +} + /// Прием сообщения fn recv_proto_message(mut reader: Reader) -> Result { let mut raw_frame = Vec::new(); @@ -81,4 +112,28 @@ mod tests { assert_eq!(received_frame.get_data(), frame_to_send.get_data()); assert_eq!(received_frame, frame_to_send); } + + #[test] + fn test_send_and_multiple_recv() { + let mut frame_to_send_1 = MUFrame::new(); + frame_to_send_1 + .set_data(b"get server_info\n".to_vec()) + .unwrap(); + + let mut frame_to_send_2 = MUFrame::new(); + frame_to_send_2 + .set_data(b"Just for test\n".to_vec()) + .unwrap(); + + let mut buf_1 = Vec::new(); + let mut buf_2 = Vec::new(); + send_proto_message(frame_to_send_1.clone(), &mut buf_1).unwrap(); + send_proto_message(frame_to_send_2.clone(), &mut buf_2).unwrap(); + + let doubled_buf = [buf_1.clone(), buf_2.clone()].concat(); + let received_frames = _recv_proto_messages(&doubled_buf[..]).unwrap(); + assert_eq!(received_frames.len(), 2); + assert_eq!(received_frames[0], frame_to_send_1); + assert_eq!(received_frames[1], frame_to_send_2); + } } diff --git a/protocol_lib/src/mu_frame.rs b/protocol_lib/src/mu_frame.rs index e8e9eaa..939ae17 100644 --- a/protocol_lib/src/mu_frame.rs +++ b/protocol_lib/src/mu_frame.rs @@ -1,10 +1,14 @@ use std::fmt::Display; -const SYNC1: u8 = 0xAA; -const SYNC2: u8 = 0xBB; -const MAX_DATA_SIZE: u8 = u8::MAX; -const CONSOLE_OPCODE: u8 = 0xC0; +pub const SYNC1: u8 = 0xAA; +pub const SYNC2: u8 = 0xBB; +pub const MAX_DATA_SIZE: u8 = u8::MAX; +pub const OPCODE_ERROR: u8 = 0x01; +pub const OPCODE_LOG: u8 = 0x19; +pub const OPCODE_DATA: u8 = 0xDA; +pub const OPCODE_CONSOLE: u8 = 0xC0; +pub const OPCODE_BOOTLOADER: u8 = 0xB1; /// Пакет данных протокола "МЮ" /// /// @@ -33,7 +37,7 @@ impl MUFrame { Self { prefix: SYNC1, length: 0, - opcode: CONSOLE_OPCODE, + opcode: OPCODE_CONSOLE, data: Vec::with_capacity(MAX_DATA_SIZE as usize), crc_low: 0x00, crc_high: 0x00, @@ -41,10 +45,30 @@ impl MUFrame { } } - pub(crate) fn get_data(&self) -> &Vec { + pub fn get_data(&self) -> &Vec { &self.data } + pub fn get_opcode(&self) -> u8 { + self.opcode + } + + /// Проверка корректности опкода (ERROR, LOG, DATA, CONSOLE) + pub fn is_opcode_correct(opcode: u8) -> bool { + return [OPCODE_ERROR, OPCODE_LOG, OPCODE_DATA, OPCODE_CONSOLE].contains(&opcode); + } + + /// Получение текстового описания опкода фрейма + pub fn get_opcode_description(opcode: u8) -> String { + match opcode { + OPCODE_ERROR => "ОШИБКА".to_string(), + OPCODE_LOG => "СТАТУС".to_string(), + OPCODE_DATA => "ДАННЫЕ".to_string(), + OPCODE_CONSOLE => "КОНСОЛЬ".to_string(), + _ => "UNKNOWN".to_string(), + } + } + /// Загрузка данных в фрейм, вычисление CRC и длины pub(crate) fn set_data(&mut self, data: Vec) -> Result<(), String> { if data.len() > MAX_DATA_SIZE as usize || data.is_empty() { @@ -78,7 +102,7 @@ impl MUFrame { frame.suffix = data[5 + frame.length as usize]; - frame.invalidate_frame()?; + frame.validate_frame()?; Ok(frame) } @@ -98,7 +122,7 @@ impl MUFrame { } /// Проверка валидности фрейма - fn invalidate_frame(&self) -> Result<(), String> { + pub(crate) fn validate_frame(&self) -> Result<(), String> { if !self.is_prefix_correct() { return Err("Bad prefix".to_string()); } @@ -203,7 +227,7 @@ mod tests { assert!(frame.is_prefix_correct()); assert!(frame.is_postfix_correct()); assert!(frame.is_crc_valid(0x7780)); - assert_eq!(frame.opcode, CONSOLE_OPCODE); + assert_eq!(frame.opcode, OPCODE_CONSOLE); assert_eq!(frame.data, b"#STM:L0:R16:A1:S0:M0:E#\r\n\0"); } @@ -218,8 +242,8 @@ mod tests { assert!(frame.is_prefix_correct()); assert!(frame.is_postfix_correct()); assert!(frame.is_crc_valid(0xB6BB)); - assert_eq!(frame.opcode, CONSOLE_OPCODE); + assert_eq!(frame.opcode, OPCODE_CONSOLE); assert_eq!(frame.data, b"#STM:L16:R16:A1:S2:M0:E#\r\n\0"); - frame.invalidate_frame().unwrap(); + frame.validate_frame().unwrap(); } } diff --git a/rk_nku_configs/menu_style.toml b/rk_nku_configs/menu_style.toml new file mode 100644 index 0000000..89086e9 --- /dev/null +++ b/rk_nku_configs/menu_style.toml @@ -0,0 +1,25 @@ +# First come some various options +shadow = false # Don't draw shadows around stacked views +borders = "simple" # Alternatives are "none" and "outset" + +# Here we define the color palette. +[colors] + background = "#000000" + # If the value is an array, the first valid color will be used. + # If the terminal doesn't support custom color, + # non-base colors will be skipped. + shadow = ["#000000", "black"] + view = "#d3d7cf" + + # Array and simple values have the same effect. + primary = ["#111111"] + secondary = "#EEEEEE" + tertiary = "#444444" + + # Hex values can use lower or uppercase. + title_primary = "#0000FF" + title_secondary = "#ffff55" + + # Lower precision values can use only 3 digits. + highlight = "#00F" + highlight_inactive = "#5555FF" \ No newline at end of file diff --git a/rk_nku_configs/nku_scheme.toml b/rk_nku_configs/nku_scheme.toml index 5d79403..645d96e 100644 --- a/rk_nku_configs/nku_scheme.toml +++ b/rk_nku_configs/nku_scheme.toml @@ -3,61 +3,100 @@ # possible_values - список возможных значений параметра # default - значение по умолчанию (одно из possible_values) # current - актуальное текущее значение параметра (одно из possible_values). Если не указано или некорректно, то используется значение по умолчанию +# should_sync - true, если параметр необходимо синхронизировать (pull & push) с внешним микроконтроллером [groupnumber] name = "Номер в группе" possible_values = [ - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "10", - "11", - "12", - "13", - "14", - "15", +"0", +"1", +"2", +"3", +"4", +"5", +"6", +"7", +"8", +"9", +"10", +"11", +"12", +"13", +"14", +"15", ] -default = "0" -current = "6" +default = "1" +current = "1" +should_sync = "true" [soundvolume] name = "Громкость звука" -possible_values = ["0%", "25%", "50%", "75%", "100%"] +possible_values = [ +"0%", +"25%", +"50%", +"75%", +"100%" +] default = "50%" -current = "100%" +current = "50%" +should_sync = "true" [musicvolume] name = "Громкость музыки" -possible_values = ["0%", "25%", "50%", "75%", "100%"] +possible_values = [ +"0%", +"25%", +"50%", +"75%", +"100%" +] default = "0%" -current = "100%" +current = "25%" +should_sync = "true" [loadcapacity] name = "Грузоподъемность" possible_values = [ - "СКРЫТО", - "240кг 3чел.", - "320кг 4чел.", - "400кг 5чел.", - "450кг 6чел.", - "525кг 7чел.", - "630кг 8чел.", - "800кг 10чел.", - "800кг 11чел.", - "1000кг 13чел.", - "1150кг 15чел.", - "1275кг 16чел.", - "1275кг 17чел.", - "1425кг 18чел.", - "1600кг 20чел.", - "1600кг 21чел.", +"СКРЫТО", +"240кг 3чел.", +"320кг 4чел.", +"400кг 5чел.", +"450кг 6чел.", +"525кг 7чел.", +"630кг 8чел.", +"800кг 10чел.", +"800кг 11чел.", +"1000кг 13чел.", +"1150кг 15чел.", +"1275кг 16чел.", +"1275кг 17чел.", +"1425кг 18чел.", +"1600кг 20чел.", +"1600кг 21чел.", ] default = "СКРЫТО" -current = "240кг 3чел." +current = "400кг 5чел." +should_sync = "true" + +[cubicmedia] +name = "Cubic Media" +possible_values = [ +"ВЫКЛ", +"ВКЛ" +] +default = "ВЫКЛ" +current = "ВКЛ" +should_sync = "true" + +[network_indicator_poll_interval] +name = "Опрос статуса сети" +possible_values = [ +"5s", +"10s", +"30s", +"60s" +] +default = "5s" +current = "5s" +should_sync = "false" diff --git a/rk_nku_menu/Cargo.toml b/rk_nku_menu/Cargo.toml index 82d4f84..e0bc458 100644 --- a/rk_nku_menu/Cargo.toml +++ b/rk_nku_menu/Cargo.toml @@ -1,13 +1,12 @@ [package] -name = "rk_smart_menu" -version = "0.1.0" +name = "rk_nku_menu" +version = "0.1.1" edition = "2024" authors.workspace = true [dependencies] thiserror = "2.0" -gpiocdev-embedded-hal = "0.1.2" -gpiocdev = "0.7.3" +sysfs_gpio = { version = "0.6.2" } log = { workspace = true } env_logger = { workspace = true } config_lib = { path = "../config_lib" } diff --git a/rk_nku_menu/src/main.rs b/rk_nku_menu/src/main.rs index 837b34c..d0ae1e2 100644 --- a/rk_nku_menu/src/main.rs +++ b/rk_nku_menu/src/main.rs @@ -1,11 +1,12 @@ -use gpiocdev::Request; +use std::time::{Duration, Instant}; + use log::debug; use menu_tui::menu_navigation::NavigationManager; use menu_tui::menu_process::DeviceMenu; -use std::time::Duration; +use sysfs_gpio::{Direction, Edge, Pin}; /// ### Путь к файлу-схемы параметров устройства -const NKU_DEVICE_CONFIG_PATH: &str = "rk_smart_configs/smart_scheme.toml"; -const TUI_APP_CONFIG_PATH: &str = "rk_smart_configs/menu_style.toml"; +const NKU_DEVICE_CONFIG_PATH: &str = "rk_nku_configs/nku_scheme.toml"; +const TUI_APP_CONFIG_PATH: &str = "rk_nku_configs/menu_style.toml"; /// Максимальное время бездействия [c], после достижения которого происходит выход из меню const IDLE_TIMEOUT_SEC: u64 = 30; @@ -42,72 +43,75 @@ fn main() -> Result<(), Box> { return Ok(()); } -/// ligpiod номер порта кнопки ввода -const S1_BTN: (&str, u8) = ("/dev/gpiochip3", 16); -/// ligpiod номер порта кнопки выбора -const S2_BTN: (&str, u8) = ("/dev/gpiochip2", 1); -/// ## Симуляция обработчиков GPIO кнопок -/// ### Расчёт номера пина в порядке libgpiod +/// Расчёт номера пина в порядке SYSFS /// ``` /// bank = 0; // GPIO0_B5 => 0, bank ∈ [0,4] /// group = 1; // GPIO0_B5 => 1, group ∈ {(A=0), (B=1), (C=2), (D=3)} /// X = 5; // GPIO0_B5 => 5, X ∈ [0,7] /// number = group * 8 + X = 1 * 8 + 5 = 13; /// pin = bank * 32 + number = 0 * 32 + 13 = 13; -/// -/// gpiochip_number = pin_number / 32; // Номер банка -/// line_offset = pin_number % 32; // Номер пина в банке /// ``` -/// + +/// SYSFS номер порта кнопки ввода +const S1_BTN: u8 = 124; //124 +/// SYSFS номер порта кнопки выбора +const S2_BTN: u8 = 125; //125 + fn gpio_navigation_handlers(nav_manager: NavigationManager) { // Кнопка 1 (GPIO): Навигация вниз let nav_down = nav_manager.clone(); std::thread::spawn(move || { - let down_btn_req = Request::builder() - .on_chip(S1_BTN.0) - .with_line(S1_BTN.1 as u32) - .as_input() - .with_edge_detection(gpiocdev::line::EdgeDetection::RisingEdge) - .request() - .unwrap(); - debug!("down_irq_thread launched!"); + let input = Pin::new(S1_BTN as u64); + debug!("return_irq_thread launched!"); + input.with_exported(|| { + input.set_direction(Direction::In)?; + input.set_edge(Edge::RisingEdge)?; + let mut poller = input.get_poller()?; - loop { - if down_btn_req.has_edge_event().unwrap() { - if let Ok(edge) = down_btn_req.read_edge_event() { - if edge.kind == gpiocdev::line::EdgeKind::Rising { - debug!("DownArrow pressed"); - // Симуляция нажатия кнопки DOWN - nav_down.navigate_down(); - std::thread::sleep(Duration::from_millis(400)); + let mut last_press = Instant::now() - Duration::from_millis(1000); + let debounce = Duration::from_millis(350); + + loop { + if let Some(pin_value) = poller.poll(1000)? { + if pin_value == 1 { + let now = Instant::now(); + if now.duration_since(last_press) >= debounce { + last_press = now; + nav_down.navigate_down(); + } else { + // Событие проигнорировано как дребезг + } } } } - } + }) }); // Кнопка 2 (GPIO): Выбор/подтверждение - let nav_select = nav_manager.clone(); + let nav_down = nav_manager.clone(); std::thread::spawn(move || { - let return_btn_req = Request::builder() - .on_chip(S2_BTN.0) - .with_line(S2_BTN.1 as u32) - .as_input() - .with_edge_detection(gpiocdev::line::EdgeDetection::RisingEdge) - .request() - .unwrap(); + let input = Pin::new(S2_BTN as u64); debug!("return_irq_thread launched!"); - loop { - if return_btn_req.has_edge_event().unwrap() { - if let Ok(edge) = return_btn_req.read_edge_event() { - if edge.kind == gpiocdev::line::EdgeKind::Rising { - debug!("Return pressed"); - // Симуляция нажатия кнопки ENTER - nav_select.select_item(); - std::thread::sleep(Duration::from_millis(400)); + input.with_exported(|| { + input.set_direction(Direction::In)?; + input.set_edge(Edge::RisingEdge)?; + let mut poller = input.get_poller()?; + + let mut last_press = Instant::now() - Duration::from_millis(1000); + let debounce = Duration::from_millis(350); + loop { + if let Some(pin_value) = poller.poll(1000)? { + if pin_value == 1 { + let now = Instant::now(); + if now.duration_since(last_press) >= debounce { + last_press = now; + nav_down.select_item(); + } else { + // Событие проигнорировано как дребезг + } } } } - } + }) }); } diff --git a/rk_nku_sync/Cargo.toml b/rk_nku_sync/Cargo.toml index 6f925f6..b6a55ca 100644 --- a/rk_nku_sync/Cargo.toml +++ b/rk_nku_sync/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rk_nku_sync" -version = "0.1.0" +version = "0.1.1" edition = "2024" authors.workspace = true @@ -10,3 +10,4 @@ config_lib = { path = "../config_lib" } clap = { workspace = true } log = { workspace = true } env_logger = { workspace = true } + diff --git a/rk_nku_sync/src/main.rs b/rk_nku_sync/src/main.rs index 9a7c3b3..1d9d73c 100644 --- a/rk_nku_sync/src/main.rs +++ b/rk_nku_sync/src/main.rs @@ -4,13 +4,13 @@ mod serial_config; use std::str::FromStr; use clap::Parser; -use log::{error, warn}; +use log::{error, info, warn}; /// Количество попыток выполнить запрос const REQUEST_ATTEMPTS: u8 = 5; #[derive(Parser)] -#[command(author = "Akimov Dmitry MU LLC", name = "nku_sync", version = "0.1.0", about, long_about = None)] +#[command(author = "Akimov Dmitry MU LLC", name = "smart_sync", version = "0.1.0", about, long_about = None)] struct Args { /// Тип команды: pull - запрос сохраненных в устройстве настроек, push - отправка новых настроек #[arg(short = 'm', long = "mode")] @@ -21,7 +21,7 @@ fn main() -> Result<(), String> { let args = Args::parse(); env_logger::init(); - warn!("rk_nku_sync> command mode: {:?}", args.mode); + info!("rk_nku_sync> command mode: {:?}", args.mode); let mut nku_client = nku_client::NkuClient::new()?; @@ -60,6 +60,8 @@ fn push_parameters(client: &mut nku_client::NkuClient) -> Result<(), String> { } } + info!("Parameters have been pushed to device!"); + // Запуск стриминга данных от станции attempts = 1; 'start_streaming_loop: loop { @@ -80,7 +82,7 @@ fn push_parameters(client: &mut nku_client::NkuClient) -> Result<(), String> { return Err("Start streaming failed!".to_string()); } } - + info!("Data streaming from MCU has been started!"); Ok(()) } @@ -90,7 +92,7 @@ fn pull_parameters(client: &mut nku_client::NkuClient) -> Result<(), String> { // Цикл попыток установить соединение 'pull_request_loop: loop { warn!("Pull request attempt: {attempts}"); - + let result = client.pull_parameters_from_device(); if result.is_ok() { break 'pull_request_loop; @@ -106,7 +108,7 @@ fn pull_parameters(client: &mut nku_client::NkuClient) -> Result<(), String> { return Err("Pull request failed!".to_string()); } } - + info!("Parameters have been pulled from device!"); Ok(()) } diff --git a/rk_nku_sync/src/serial_config.rs b/rk_nku_sync/src/serial_config.rs index c40313e..1f87bf0 100644 --- a/rk_nku_sync/src/serial_config.rs +++ b/rk_nku_sync/src/serial_config.rs @@ -9,10 +9,10 @@ pub struct SerialPortConfig { impl SerialPortConfig { /// Чтение параметров последовательного порта из файла-схемы TOML pub fn new(path_to_scheme: &str) -> Result { - let nku_serial_parameters = DeviceConfig::create_parameter_list(path_to_scheme)?; + let smart_serial_parameters = DeviceConfig::create_parameter_list(path_to_scheme)?; - let serial_name = nku_serial_parameters.get_parameter_value("device")?; - let serial_baudrate = nku_serial_parameters + let serial_name = smart_serial_parameters.get_parameter_value("device")?; + let serial_baudrate = smart_serial_parameters .get_parameter_value("baudrate")? .parse::() .map_err(|e: std::num::ParseIntError| e.to_string())?;