Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8acbb8b082 | ||
|
|
4a7682f3a6 | ||
|
|
491fe78572 | ||
|
|
b07b4a03e1 | ||
|
|
3f1af9bf9d | ||
|
|
4b08be6bed | ||
|
|
0572c1030f |
No files matched your search
Generated
+215
-157
@@ -127,16 +127,16 @@ dependencies = [
|
||||
"futures-lite",
|
||||
"parking",
|
||||
"polling",
|
||||
"rustix 1.1.2",
|
||||
"rustix 1.1.3",
|
||||
"slab",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "3.4.1"
|
||||
version = "3.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc"
|
||||
checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"event-listener-strategy",
|
||||
@@ -169,7 +169,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"rustix 1.1.2",
|
||||
"rustix 1.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -184,7 +184,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"rustix 1.1.2",
|
||||
"rustix 1.1.3",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"windows-sys 0.61.2",
|
||||
@@ -204,7 +204,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -221,7 +221,7 @@ checksum = "99e1aca718ea7b89985790c94aad72d77533063fe00bc497bb79a7c2dae6a661"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -232,9 +232,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.8.7"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425"
|
||||
checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8"
|
||||
dependencies = [
|
||||
"axum-core",
|
||||
"axum-macros",
|
||||
@@ -266,9 +266,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22"
|
||||
checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
@@ -291,7 +291,7 @@ checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -372,9 +372,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.19.0"
|
||||
version = "3.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
@@ -405,9 +405,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.46"
|
||||
version = "1.2.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36"
|
||||
checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
@@ -427,9 +427,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.42"
|
||||
version = "0.4.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
|
||||
checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
@@ -465,18 +465,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.51"
|
||||
version = "4.5.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
|
||||
checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.51"
|
||||
version = "4.5.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
|
||||
checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
@@ -484,9 +484,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.6"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
|
||||
checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
@@ -539,7 +539,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -580,9 +580,9 @@ dependencies = [
|
||||
|
||||
[[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",
|
||||
]
|
||||
@@ -668,9 +668,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.9.0"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
|
||||
checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
|
||||
|
||||
[[package]]
|
||||
name = "deluxe"
|
||||
@@ -682,7 +682,7 @@ dependencies = [
|
||||
"deluxe-macros",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -695,7 +695,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -705,12 +705,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f87546d9c837f0b7557e47b8bd6eae52c3c223141b76aa233c345c9ab41d9117"
|
||||
dependencies = [
|
||||
"deluxe-core",
|
||||
"heck",
|
||||
"heck 0.4.1",
|
||||
"if_chain",
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -721,7 +721,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -962,7 +962,7 @@ dependencies = [
|
||||
"deluxe",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -980,7 +980,7 @@ dependencies = [
|
||||
"embedded-io-async",
|
||||
"ethercrab-wire",
|
||||
"futures-lite",
|
||||
"heapless",
|
||||
"heapless 0.8.0",
|
||||
"io-uring",
|
||||
"libc",
|
||||
"log",
|
||||
@@ -1002,7 +1002,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d15828cb020fb44c92ca67e1ee3c122c9621c2e00d383d066e488f0619023ba2"
|
||||
dependencies = [
|
||||
"ethercrab-wire-derive",
|
||||
"heapless",
|
||||
"heapless 0.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1014,14 +1014,14 @@ dependencies = [
|
||||
"criterion",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "euclid"
|
||||
version = "0.22.11"
|
||||
version = "0.22.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48"
|
||||
checksum = "df61bf483e837f88d5c2291dcf55c67be7e676b3a51acc48db3a7b163b91ed63"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
@@ -1055,9 +1055,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.5"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
|
||||
checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
@@ -1170,9 +1170,9 @@ checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.12"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386"
|
||||
checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
@@ -1223,9 +1223,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.0"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
@@ -1237,12 +1237,28 @@ dependencies = [
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed"
|
||||
dependencies = [
|
||||
"hash32",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.5.2"
|
||||
@@ -1251,12 +1267,11 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.3.1"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
|
||||
checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
@@ -1339,9 +1354,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.18"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56"
|
||||
checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@@ -1352,7 +1367,7 @@ dependencies = [
|
||||
"hyper",
|
||||
"libc",
|
||||
"pin-project-lite",
|
||||
"socket2 0.6.1",
|
||||
"socket2 0.6.2",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -1390,9 +1405,9 @@ checksum = "cd62e6b5e86ea8eeeb8db1de02880a6abc01a397b2ebb64b5d74ac255318f5cb"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.12.0"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
|
||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@@ -1466,15 +1481,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.15"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.82"
|
||||
version = "0.3.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
|
||||
checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
@@ -1488,9 +1503,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.177"
|
||||
version = "0.2.180"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
@@ -1551,9 +1566,9 @@ dependencies = [
|
||||
|
||||
[[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 = "mach2"
|
||||
@@ -1577,11 +1592,14 @@ dependencies = [
|
||||
"ethercrab",
|
||||
"euclid",
|
||||
"lazy_static",
|
||||
"modbus",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serialport",
|
||||
"smol",
|
||||
"socketioxide",
|
||||
"strum",
|
||||
"strum_macros 0.26.4",
|
||||
"textplots",
|
||||
"tonic",
|
||||
"tracing",
|
||||
@@ -1660,15 +1678,26 @@ checksum = "c505b3e17ed6b70a7ed2e67fbb2c560ee327353556120d6e72f5232b6880d536"
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
|
||||
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "modbus"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/just-some-entity/modbus-rs.git#e71a27aaf4356402d38dca6224e8c2b66183dc1e"
|
||||
dependencies = [
|
||||
"crc",
|
||||
"heapless 0.9.2",
|
||||
"libc",
|
||||
"strum_macros 0.27.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "0.1.3"
|
||||
@@ -1821,17 +1850,11 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pcap"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83cdabc34a80d9ec3563694cc31423fba6bb9bab4f31a9a5d5b85f29bd6d660a"
|
||||
checksum = "bbd2eecc2ddc671ec563b5b39f846556aade68a65d1afb14d8fe6b30b0457d75"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"errno 0.2.8",
|
||||
@@ -1850,9 +1873,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.8.3"
|
||||
version = "2.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4"
|
||||
checksum = "2c9eb05c21a464ea704b53158d358a31e6425db2f63a1a7312268b05fe2b75f7"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"ucd-trie",
|
||||
@@ -1860,9 +1883,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.8.3"
|
||||
version = "2.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de"
|
||||
checksum = "68f9dbced329c441fa79d80472764b1a2c7e57123553b8519b36663a2fb234ed"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_generator",
|
||||
@@ -1870,22 +1893,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.8.3"
|
||||
version = "2.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843"
|
||||
checksum = "3bb96d5051a78f44f43c8f712d8e810adb0ebf923fc9ed2655a7f66f63ba8ee5"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.8.3"
|
||||
version = "2.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a"
|
||||
checksum = "602113b5b5e8621770cfd490cfd90b9f84ab29bd2b0e49ad83eb6d186cef2365"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"sha2",
|
||||
@@ -1908,7 +1931,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1982,7 +2005,7 @@ dependencies = [
|
||||
"concurrent-queue",
|
||||
"hermit-abi",
|
||||
"pin-project-lite",
|
||||
"rustix 1.1.2",
|
||||
"rustix 1.1.3",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
@@ -2007,9 +2030,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -2072,9 +2095,9 @@ 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",
|
||||
]
|
||||
@@ -2128,31 +2151,28 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rmp"
|
||||
version = "0.8.14"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4"
|
||||
checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"num-traits",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rmp-serde"
|
||||
version = "1.3.0"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db"
|
||||
checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"rmp",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.26"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
|
||||
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
@@ -2175,9 +2195,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
|
||||
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"errno 0.3.14",
|
||||
@@ -2194,9 +2214,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.20"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
@@ -2221,7 +2241,7 @@ checksum = "22f968c5ea23d555e670b449c1c5e7b2fc399fdaec1d304a17cd48e288abc107"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2251,20 +2271,20 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.145"
|
||||
version = "1.0.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
|
||||
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2381,10 +2401,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.6"
|
||||
version = "1.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
|
||||
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
|
||||
dependencies = [
|
||||
"errno 0.3.14",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -2453,9 +2474,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.1"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
|
||||
checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.60.2",
|
||||
@@ -2560,6 +2581,37 @@ version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.26.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.27.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
@@ -2573,9 +2625,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.111"
|
||||
version = "2.0.114"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
|
||||
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2606,22 +2658,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.17"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.17"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
|
||||
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2660,15 +2712,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.48.0"
|
||||
version = "1.49.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
|
||||
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"pin-project-lite",
|
||||
"socket2 0.6.1",
|
||||
"socket2 0.6.2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
@@ -2681,14 +2733,14 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
|
||||
checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
@@ -2709,9 +2761,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.17"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594"
|
||||
checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
@@ -2768,9 +2820,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
|
||||
checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
@@ -2787,9 +2839,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.6.6"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
|
||||
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bytes",
|
||||
@@ -2843,7 +2895,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2858,9 +2910,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-journald"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0b4143302cf1022dac868d521e36e8b27691f72c84b3311750d5188ebba657"
|
||||
checksum = "2d3a81ed245bfb62592b1e2bc153e77656d94ee6a0497683a65a12ccaf2438d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"tracing-core",
|
||||
@@ -2880,9 +2932,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.20"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
|
||||
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"matchers",
|
||||
@@ -2940,18 +2992,18 @@ checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
|
||||
|
||||
[[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 = "unicase"
|
||||
version = "2.8.1"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
|
||||
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
@@ -3035,18 +3087,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasip2"
|
||||
version = "1.0.1+wasi-0.2.4"
|
||||
version = "1.0.2+wasi-0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
|
||||
checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.105"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
|
||||
checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
@@ -3057,9 +3109,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.105"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
|
||||
checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -3067,22 +3119,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.105"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
|
||||
checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.105"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
|
||||
checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -3139,7 +3191,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3150,7 +3202,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3396,9 +3448,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.46.0"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
@@ -3411,20 +3463,26 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.27"
|
||||
version = "0.8.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
|
||||
checksum = "71ddd76bcebeed25db614f82bf31a9f4222d3fbba300e6fb6c00afa26cbd4d9d"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.27"
|
||||
version = "0.8.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
|
||||
checksum = "d8187381b52e32220d50b255276aa16a084ec0a9017a0ca2152a1f55c539758d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.111",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439"
|
||||
@@ -18,11 +18,11 @@ pub fn set_interface_managed(interface: &str, managed: bool) -> bool {
|
||||
true => "yes",
|
||||
false => "no",
|
||||
};
|
||||
tracing::info!(
|
||||
"set_interface_managed for {} managed was set to: {}",
|
||||
interface,
|
||||
managed_str
|
||||
);
|
||||
// tracing::info!(
|
||||
// "set_interface_managed for {} managed was set to: {}",
|
||||
// interface,
|
||||
// managed_str
|
||||
// );
|
||||
let status = Command::new("nmcli")
|
||||
.args(["dev", "set", interface, "managed", managed_str])
|
||||
.status();
|
||||
@@ -52,7 +52,7 @@ fn is_ethernet(interface: &str) -> std::io::Result<bool> {
|
||||
}
|
||||
|
||||
pub async fn discover_ethercat_interface() -> Result<String, anyhow::Error> {
|
||||
tracing::info!("Discovering EtherCAT interface...");
|
||||
//tracing::info!("Discovering EtherCAT interface...");
|
||||
|
||||
// Set up a custom panic hook that suppresses panic output
|
||||
let default_hook = std::panic::take_hook();
|
||||
@@ -119,7 +119,7 @@ pub async fn discover_ethercat_interface() -> Result<String, anyhow::Error> {
|
||||
}
|
||||
|
||||
fn test_interface(interface: &str) -> Result<(), anyhow::Error> {
|
||||
tracing::info!("Testing interface: {}", interface);
|
||||
//tracing::info!("Testing interface: {}", interface);
|
||||
|
||||
let pdu_storage = Box::leak(Box::new(PduStorage::<
|
||||
IFACE_DISCOVERY_MAX_FRAMES,
|
||||
|
||||
@@ -52,11 +52,11 @@ pub fn set_interface_managed(interface: &str, managed: bool) -> bool {
|
||||
true => "yes",
|
||||
false => "no",
|
||||
};
|
||||
tracing::info!(
|
||||
"set_interface_managed for {} managed was set to: {}",
|
||||
interface,
|
||||
managed_str
|
||||
);
|
||||
// tracing::info!(
|
||||
// "set_interface_managed for {} managed was set to: {}",
|
||||
// interface,
|
||||
// managed_str
|
||||
// );
|
||||
let status = Command::new("nmcli")
|
||||
.args(["dev", "set", interface, "managed", managed_str])
|
||||
.status();
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
# Documentation for the US-3202510 220 V Single‑Phase to Three‑Phase 0.75 kW VFD Inverter
|
||||
|
||||
## 1. Specification, Features and Technical Data
|
||||
|
||||
### 1.1 Specification
|
||||
|
||||
- **Control Mode:** V/F Control
|
||||
- **Nominal Voltage:** 220 V
|
||||
- **Rated Power:** 750 W, 400 W, 200 W, 300 W
|
||||
- **Input Voltage:** Single Phase 220 V
|
||||
- **Output Voltage:** Three Phase 220 V
|
||||
- **Dimensions:** 52.00 / 80.00 / 90.00 / 147.00 mm (reference)
|
||||
|
||||
---
|
||||
|
||||
|
||||
### 1.2 Features
|
||||
|
||||
- Output frequency range: **1.0–99.0 Hz**, suitable for general speed control
|
||||
- Built-in intelligent logic controller for simple logic control
|
||||
- Compact size, easy installation, simple commissioning
|
||||
- Clear and easy-to-understand parameters for general applications
|
||||
- Equipped with a built-in speed potentiometer; external potentiometer supported
|
||||
- Specifically designed for **220 V, ≤0.75 kW three-phase AC motors**
|
||||
- Integrated solution for equipment manufacturers, reducing system cost and improving reliability
|
||||
- Electronic thermal overload protection, replacing traditional motor protection devices
|
||||
- External LED indicator output supported for on-site indication
|
||||
- User-friendly interface with simple parameter setting
|
||||
- Adjustable V/F curve for special applications
|
||||
- Shift key allows viewing real-time parameters
|
||||
- Uses a new-generation **IPM module** with comprehensive protection functions
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 1.3 Models and Technical Data
|
||||
|
||||
**Single-phase power supply: 200–240 VAC, 50/60 Hz**
|
||||
|
||||
| Inverter Model | Power Capacity (kVA) | Input Current (A) | Output Current (A) | Compatible Motor (kW) |
|
||||
| ----------------| ----------------------| -------------------| --------------------| -----------------------|
|
||||
| US00R2G1 | 3.0 | 3.2 | 1.6 | 0.2 |
|
||||
| US00R4G1 | 3.8 | 4.3 | 2.1 | 0.4 |
|
||||
| US00R7G1 | 5.6 | 6.0 | 3.1 | 0.75 |
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 1.4 Front Panel and Terminal Diagram
|
||||
|
||||
<img src="../assets/US-3202510_spec.png" alt="VFD Front Panel and Terminal Layout" style="max-width:600px;">
|
||||
|
||||
---
|
||||
|
||||
### 1.5 Dimensions
|
||||
|
||||
<img src="../assets/US-3202510_dimensions.png" alt="VFD Front Panel and Terminal Layout" style="max-width:600px;">
|
||||
|
||||
---
|
||||
|
||||
## 2. Terminals and Wiring
|
||||
|
||||
### 2.1 Main Terminal Wiring
|
||||
|
||||
| Terminal Mark | Name | Description |
|
||||
| ---------------| --------------------------| --------------------------------------------------|
|
||||
| AC, AC | Single-phase power input | Connection point for single-phase 220 V AC power |
|
||||
| U, V, W | Inverter output | Connect to three-phase AC motor |
|
||||
| FG | Ground terminal | Protective earth connection |
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 2.2 Signal Terminal Wiring
|
||||
|
||||
| Category | Terminal Symbol | Terminal Name | Function Description |
|
||||
| ----------------| -----------------| ------------------------| ----------------------------------------------|
|
||||
| Power | 5V, COM | External 5V power | Provides 5V power for external potentiometer |
|
||||
| Analog input | VR, COM | Analog input | Input voltage range: DC 0–5 V |
|
||||
| Digital input | M1, COM | Forward run | Forward rotation control |
|
||||
| Digital input | M2 / D3, COM | Reverse / multi-speed | Reverse rotation or multi-speed stage 3 |
|
||||
| Digital input | D2, COM | Multi-speed terminal 2 | Multi-speed function 2 |
|
||||
| Digital input | D1, COM | Multi-speed terminal 1 | Multi-speed function 1 |
|
||||
| Digital output | M0, 5V | Digital output | For external 5V relay or indicator |
|
||||
| Communication | RS−, RS+ | RS485 interface | MODBUS control |
|
||||
|
||||
---
|
||||
|
||||
### 2.2.1 Signal Terminal Layout
|
||||
|
||||
| Index | Symbol |
|
||||
| -------| --------|
|
||||
| 1 | +5V |
|
||||
| 2 | VR |
|
||||
| 3 | COM |
|
||||
| 4 | M0 |
|
||||
| 5 | M1 |
|
||||
| 6 | M2/D3 |
|
||||
| 7 | RS485- |
|
||||
| 8 | RS485+ |
|
||||
| 9 | D2 |
|
||||
| 10 | D1 |
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 3. Control Panel
|
||||
|
||||
### 3.1 Indicator Lights and Display
|
||||
|
||||
| Indicator | Function | Description |
|
||||
| -----------| -------------------| -------------------------------------------------------------|
|
||||
| POWER | Power indicator | Steady ON = power on; Red flashing = keypad locked |
|
||||
| FWD | Forward indicator | Steady ON = motor running forward; Flashing = motor stopped |
|
||||
| REV | Reverse indicator | Steady ON = motor running reverse; Flashing = motor stopped |
|
||||
| Display | Display | Shows current parameters and fault information |
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 3.2 Physical Controls
|
||||
|
||||
| Key / Control | Type | Function (Run Mode) | Function (Parameter Setting Mode) |
|
||||
| ---------------| ---------------| -----------------------------------------------------------| ---------------------------------------------------------------------------|
|
||||
| P.K / SHIFT | Button | View IPM temperature, DC bus voltage/current, motor speed | Shift digit |
|
||||
| MENU / ESC | Button | Enter parameter setting mode | Exit |
|
||||
| SAVE / LOCK | Button | — | Long press to lock/unlock keypad; auto-lock after 3 minutes of inactivity |
|
||||
| FWD / REV | Button | Toggle forward/reverse rotation | — |
|
||||
| ↑ | Button | — | Increase value |
|
||||
| ON / OFF | Button | Start/stop motor | Confirm value |
|
||||
| ↓ | Button | — | Decrease value |
|
||||
| SPEED | Potentiometer | Adjust motor speed | — |
|
||||
|
||||
---
|
||||
|
||||
|
||||
## 4. Parameters
|
||||
|
||||
### 4.1 Editing Parameters
|
||||
|
||||
1. **Enter Edit Mode**
|
||||
- Press the **MENU/ESC** key.
|
||||
- The digital display will flash `-0.1-`.
|
||||
|
||||
2. **Select Function Code**
|
||||
- Use the **↑/↓ keys** to adjust the value and choose the desired **function code**.
|
||||
- Refer to **Table 4.1** below for available function codes.
|
||||
|
||||
3. **Set Sub-Code**
|
||||
- During the setting process, use the **P.K/SHIFT** and **↑/↓ keys** to select the sub-code.
|
||||
- Press **ON/OFF** to enter the sub-code selection.
|
||||
- After selecting the sub-code, press **ON/OFF** again to return to the function code screen (display flashes `-X.X-`).
|
||||
- Repeat for the next function code as needed.
|
||||
|
||||
4. **Save Settings**
|
||||
- After all settings are selected, press the **SAVE/LOCK** key (display flashes `SAVE`).
|
||||
- Press **SAVE/LOCK** again to confirm saving.
|
||||
- When the display stops flashing, the data is saved.
|
||||
|
||||
5. **Operation After Saving**
|
||||
- The VFD will run according to the saved parameters **without needing a power cycle**.
|
||||
|
||||
6. **Exit Without Saving**
|
||||
- Press **MENU/ESC** to exit without saving — previous parameters remain unchanged.
|
||||
- If no key is pressed for **20 seconds**, the interface will automatically return to the run screen.
|
||||
|
||||
---
|
||||
|
||||
### 4.2 Parameter Table
|
||||
|
||||
| Function Code | Definition | Factory Value | Setting Range | Description |
|
||||
| ---------------| -------------------------------------------------| ---------------| ---------------| ---------------------------------------------------------------------------------------------------|
|
||||
| 0.1 | Acceleration Time | 7 | 1–15 | 1–15 corresponds to 5–0.1 s; smaller value = faster (each step is about twice as fast) |
|
||||
| 0.2 | Deceleration Time | 7 | 1–15 | 1–15 corresponds to 5–0.1 s; smaller value = faster (each step is about twice as fast) |
|
||||
| 0.4 | V/F Frequency Compensation | 20 | 5–30 Hz | V/F frequency compensation |
|
||||
| 0.5 | V/F Voltage Compensation | 41 | 25–85 | V/F voltage compensation |
|
||||
| 0.7 | MODBUS Communication Baud Rate | 4 | 024–384 | 096 = 9600 bps |
|
||||
| 0.9 | MODBUS Address | 1 | 1–249 | MODBUS address |
|
||||
| 1.0 | Frequency Source Selection | 2 | 0–4 | 0: Panel keys, 1: Panel potentiometer, 2: External analog VR, 3: MODBUS 485, 4: Multi-speed input |
|
||||
| 1.1 | Command Source Selection | 0 | 0–4 | 2: Power-on forward, 3: Power-on reverse, 4: External port, 0: free stop |
|
||||
| 1.2 | Stop Mode | 1 | 0–2 | 1: Deceleration stop, 2: Immediate stop; 0: MI1 forward/stop, MI2 reverse/stop |
|
||||
| 1.3 | MI Function Selection | 0 | 0–2 | 1: MI1 run/stop, MI2 reverse/forward; 2: MI1 run/stop, MI2 multi-speed |
|
||||
| 1.4 | MO Function Selection | 0 | 0–2 | 1: Setting reached indicator, 2: Fault indicator |
|
||||
| 1.6 | Overheat Protection Value | 90 | 40–100 °C | Overheat protection threshold |
|
||||
| 1.7 | Maximum Operating Frequency | 50.0 | 1.0–99.0 Hz | Maximum frequency setting |
|
||||
| 1.8 | Minimum Operating Frequency | 0 | 0.0–30.0 Hz | Minimum frequency setting |
|
||||
| 1.9 | Rated Operating Frequency | 50.0 | 1.0–99.0 Hz | Default power-on frequency |
|
||||
| 2.0 | Output Voltage Corresponding Frequency | 50.0 | 35–99.0 Hz | Output voltage corresponding frequency |
|
||||
| 2.1 | Multi-speed 1 Set Frequency | 5.0 | 1.0–99.0 Hz | Multi-speed 1 frequency |
|
||||
| 2.2 | Multi-speed 2 Set Frequency | 10.0 | 1.0–99.0 Hz | Multi-speed 2 frequency |
|
||||
| 2.3 | Multi-speed 3 Set Frequency | 20.0 | 1.0–99.0 Hz | Multi-speed 3 frequency |
|
||||
| 2.4 | Multi-speed 4 Set Frequency | 25.0 | 1.0–99.0 Hz | Multi-speed 4 frequency |
|
||||
| 2.5 | Multi-speed 5 Set Frequency | 35.0 | 1.0–99.0 Hz | Multi-speed 5 frequency |
|
||||
| 2.6 | Multi-speed 6 Set Frequency | 40.0 | 1.0–99.0 Hz | Multi-speed 6 frequency |
|
||||
| 2.7 | Multi-speed 7 Set Frequency | 45.0 | 1.0–99.0 Hz | Multi-speed 7 frequency |
|
||||
| 2.8 | Frequency Reached During Run | 45.0 | 1.0–99.0 Hz | Frequency reached during operation |
|
||||
| 3.5 | Motor Pole Pairs | 2 | 1–6 | 2 corresponds to 1500 rpm |
|
||||
| 3.7 | Motor Speed | 1500 | 1–9999 | Motor operating speed |
|
||||
| 3.8 | Multi-speed 0 Set Frequency | 1.0 | 1.0–99.0 Hz | Multi-speed 0 frequency |
|
||||
| 4.0 | Overcurrent Protection Value | 8.00 A | 2.00–9.00 A | Motor protection current setting |
|
||||
| 4.1 | Overvoltage Protection Value | 520.0 V | 100–900 V | Motor protection voltage setting |
|
||||
| 4.2 | Overload Protection Value | 2400 W | 400–2700 W | Motor protection power setting |
|
||||
| 4.3 | Carrier Frequency Setting | 0 | 0–1 | 0: 10 kHz, 1: 20 kHz |
|
||||
| 4.4 | Power-loss Detection Enable | 1 | 0–1 | 0: Off, 1: On; 0 = fan and motor start/stop together |
|
||||
| 4.5 | Fan Operation Mode | 0 | 0–2 | 1: Fan stops 5 s after motor stops; 2: Fan runs continuously until power off |
|
||||
| 4.6 | Motor Speed Synchronization Mode | 0–2 | 0–2 | 1: Motor speed sync within 300 ms after speed change; 2: Motor sync every 1 s |
|
||||
| 5.0 | Bluetooth / RS485 / External Terminal Selection | 0–2 | 0–2 | 1: Serial = Bluetooth; 2: Serial = external expansion |
|
||||
| 6.0 | Expansion Board – Year/Month | — | — | 0x23 = 2023, 0x10 = October |
|
||||
| 6.1 | Expansion Board – Day/Version | — | — | 0x25 = 25th, 0x10 = version 1.0 |
|
||||
| 6.2 | Expansion Board – Response Interval | 1000 | 100–5000 ms | Time interval for expansion board reporting |
|
||||
| 6.3 | Expansion Board – Response Enable | 0–1 | 0–1 | 0: Do not report; 1: Enable reporting |
|
||||
| 6.8 | Expansion Board – Voltage | — | — | Voltage reading, e.g., 503 = 5.03 V |
|
||||
| 9.1 | Restore Factory Settings | — | — | Display flashes `CL`; press confirm to restore |
|
||||
| 9.2 | Firmware Version | 107 | — | Display version number, e.g., V107 |
|
||||
| 9.3 | Output Waveform Selection | 0–1 | 0–1 | 0: Standard sine; 1: Enhanced sine control waveform |
|
||||
| 9.4 | MCU Reset | — | — | Display flashes 8.88; press confirm to reset MCU |
|
||||
| 9.6 | Continuous Motor Speed Display | 0 | 0–1 | 0: Auto return to frequency display after inactivity; 1: auto return to speed display |
|
||||
| 9.7 | Panel 3-Minute Lock Switch | 0 | 0–1 | 0: Auto lock after 3 minutes no operation; 1: No lock |
|
||||
| 9.8 | Motor Speed Display Multiplier | 0 | 0–100 | 0: display off; other: divides speed, e.g., 4 → 1500 rpm becomes 375 rpm (requires 9.6 = 1) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
## 5. Fault Alarms and Countermeasures
|
||||
|
||||
The VFD has multiple warning indicators and protection functions.
|
||||
When an abnormal fault occurs, the protection function activates and the VFD stops output. The display panel shows a fault code.
|
||||
|
||||
### Table 5.1 – Fault Codes
|
||||
|
||||
| Fault Code | Fault Name | Fault Description | Countermeasure |
|
||||
| ------------| ------------------------------------| ----------------------------------------------------------------------------------------------------| ---------------------------------------------|
|
||||
| E-0.1 | VFD Overheat | VFD temperature exceeds 1.6× set protection value; display flashes; max frequency limited to 30 Hz | After clearing the fault, restart the motor |
|
||||
| E-0.2 | Pulse Overcurrent | VFD current exceeds 4.0× set protection value; motor stops | After clearing the fault, restart the motor |
|
||||
| E-0.4 | VFD Overload | VFD voltage × current exceeds 4.2× set power; display flashes; operation continues | After clearing the fault, restart the motor |
|
||||
| E-0.5 | Approaching IGBT Temperature Limit | VFD temperature >120°C, near IGBT limit; motor stops | After clearing the fault, restart the motor |
|
||||
| E-0.6 | Temperature Sensor Open | VFD temperature sensor open; display flashes; operation continues | After clearing the fault, restart the motor |
|
||||
| E-0.7 | Temperature Sensor Short | VFD temperature sensor shorted; display flashes; operation continues | After clearing the fault, restart the motor |
|
||||
| E-0.8 | 100% Overload | VFD overload warning lasts 6 s; motor stops | After clearing the fault, restart the motor |
|
||||
| E-0.9 | VFD Thermal Protection | Overheat protection warning >1 minute; motor stops | After clearing the fault, restart the motor |
|
||||
| E-1.0 | Bus Overvoltage Protection | VFD voltage exceeds 4.1× set protection value; motor stops | After clearing the fault, restart the motor |
|
||||
| E-1.1 | IGBT VF0 Protection | IGBT module VF0 fault; module overload; motor stops | After clearing the fault, restart the motor |
|
||||
|
||||
## 6. Multi-speed Settings
|
||||
|
||||
| D1 | D2 | D3 | Set Frequency | Corresponding Parameter |
|
||||
| -----| -----| -----| ---------------| -------------------------|
|
||||
| OFF | OFF | OFF | Multi-speed 0 | -3.8- |
|
||||
| ON | OFF | OFF | Multi-speed 1 | -2.1- |
|
||||
| OFF | ON | OFF | Multi-speed 2 | -2.2- |
|
||||
| ON | ON | OFF | Multi-speed 3 | -2.3- |
|
||||
| OFF | OFF | ON | Multi-speed 4 | -2.4- |
|
||||
| ON | OFF | ON | Multi-speed 5 | -2.5- |
|
||||
| OFF | ON | ON | Multi-speed 6 | -2.6- |
|
||||
| ON | ON | ON | Multi-speed 7 | -2.7- |
|
||||
|
||||
---
|
||||
|
||||
|
||||
## 7. Low-Frequency V/F Compensation
|
||||
|
||||
The VFD allows **low-frequency V/F compensation** to improve motor torque under load.
|
||||
|
||||
- Based on the connected load, you can set values in parameters `-0.3-`, `-0.4-`, and `-0.5-` according to the **linear V/F curve** (see Table 7.1).
|
||||
- Low-frequency compensation **increases motor torque**.
|
||||
- You must choose the **upper frequency limit for torque boosting**:
|
||||
- Set the **maximum voltage ratio** in `-0.3-` and `-0.4-` for the desired frequency.
|
||||
- Reference the corresponding or nearest frequency in Table 2.
|
||||
|
||||
**Behavior:**
|
||||
- When operating **above this frequency**, the V/F slope increases → torque boost.
|
||||
- When operating **below this frequency**, the V/F slope decreases → torque decreases.
|
||||
|
||||
**Example:**
|
||||
- Parameter `-0.3-` = 20.0 Hz
|
||||
- Parameter `-0.4-` = 60, 50, 30
|
||||
- Parameter `-0.5-` default = 8
|
||||
- The three V/F curves correspond to different voltage ratios at 20 Hz:
|
||||
- Curve 1: 60% voltage ratio
|
||||
- Curve 2: 55% voltage ratio
|
||||
- Curve 3: 30% voltage ratio
|
||||
|
||||
This allows fine-tuning of torque at low speeds while keeping proper V/F control at higher frequencies.
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Table 7.1 – Linear V/F Curve Values for Low-Frequency Compensation
|
||||
|
||||
<img src="../assets/US-3202510_freq.png" alt="VFD Frequency Compensation Curve" style="max-width:600px;">
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 8. Modbus Interface
|
||||
|
||||
### 8.1 Internal Register List
|
||||
- Communication format: MODBUS-RTU
|
||||
- Data bits: 8
|
||||
- Stop bits: 1
|
||||
- Parity: None
|
||||
- Default baud rate: 9600 bps
|
||||
|
||||
---
|
||||
|
||||
|
||||
### 8.2 Holding Register Group (Read/Write)
|
||||
|
||||
| Hex Addr | Dec Addr | Data Type | Description | Notes |
|
||||
| ---------:| ---------:| -----------------| ----------------------| ---------------------------------------|
|
||||
| 0x0002 | 2 | Unsigned 16-bit | MODBUS set frequency | 500 / 10 = 50.0 Hz |
|
||||
| 0x0003 | 3 | Unsigned 16-bit | MODBUS run command | 1: Forward, 2: Stop, 3: Reverse |
|
||||
| 0x0004 | 4 | Unsigned 16-bit | Acceleration time | 1–15 → 5–0.1s (1 = 5s, 2 = 2.5s etc.) |
|
||||
| 0x0005 | 5 | Unsigned 16-bit | Deceleration time | 1–15 → 5–0.1s (1 = 5s, 2 = 2.5s etc.) |
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 8.3 Input Registers (Read-only)
|
||||
|
||||
| Hex Addr | Dec Addr | Data Type | Description | Notes |
|
||||
| ---------:| ---------:| -----------------| ---------------------------| -------------------------------|
|
||||
| 0x0008 | 8 | Unsigned 16-bit | DC bus voltage | 3100 / 10 = 310.0 V |
|
||||
| 0x0009 | 9 | Unsigned 16-bit | DC bus current | 132 / 100 = 1.32 A |
|
||||
| 0x000A | 10 | Unsigned 16-bit | Drive temperature | 43 = 43 °C |
|
||||
| 0x000B | 11 | Unsigned 16-bit | System status | 0: Idle, 1: Running, 2: Fault |
|
||||
| 0x000C | 12 | Unsigned 16-bit | Error code | See error table below |
|
||||
| 0x000D | 13 | Unsigned 16-bit | Current running frequency | 500 / 10 = 50.0 Hz |
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 8.4 Error Codes
|
||||
|
||||
| Code | Description |
|
||||
| -----:| -------------------------------|
|
||||
| 0 | No fault |
|
||||
| 1 | Pulse overcurrent |
|
||||
| 2 | IGBT overcurrent protection |
|
||||
| 3 | DC bus overvoltage protection |
|
||||
| 4 | Temperature near IGBT limit |
|
||||
| 5 | Inverter thermal protection |
|
||||
| 6 | Inverter overload 100% |
|
||||
| 7 | Inverter power cut |
|
||||
Generated
+13
-34
@@ -10326,9 +10326,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/seroval": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/seroval/-/seroval-1.4.0.tgz",
|
||||
"integrity": "sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==",
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/seroval/-/seroval-1.5.0.tgz",
|
||||
"integrity": "sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
@@ -10336,9 +10336,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/seroval-plugins": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.4.0.tgz",
|
||||
"integrity": "sha512-zir1aWzoiax6pbBVjoYVd0O1QQXgIL3eVGBMsBsNmM8Ukq90yGaWlfx0AB9dTS8GPqrOrbXn79vmItCUP9U3BQ==",
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.5.0.tgz",
|
||||
"integrity": "sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
@@ -10581,36 +10581,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/solid-js": {
|
||||
"version": "1.9.10",
|
||||
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.10.tgz",
|
||||
"integrity": "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"csstype": "^3.1.0",
|
||||
"seroval": "~1.3.0",
|
||||
"seroval-plugins": "~1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/solid-js/node_modules/seroval": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/seroval/-/seroval-1.3.2.tgz",
|
||||
"integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==",
|
||||
"version": "1.9.11",
|
||||
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.11.tgz",
|
||||
"integrity": "sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/solid-js/node_modules/seroval-plugins": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.3.3.tgz",
|
||||
"integrity": "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"seroval": "^1.0"
|
||||
"dependencies": {
|
||||
"csstype": "^3.1.0",
|
||||
"seroval": "~1.5.0",
|
||||
"seroval-plugins": "~1.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sonner": {
|
||||
|
||||
@@ -30,6 +30,9 @@ export function useMachines(): UseMachine[] {
|
||||
const machinePreset = getMachineProperties(
|
||||
machine.machine_identification_unique.machine_identification,
|
||||
);
|
||||
|
||||
console.log("Machine!: {}", machine);
|
||||
|
||||
const vendorPreset = getVendorProperties(
|
||||
machinePreset!.machine_identification.vendor,
|
||||
);
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
import React from "react";
|
||||
|
||||
import { ControlCard } from "@/control/ControlCard";
|
||||
import { Page } from "@/components/Page";
|
||||
import { ControlGrid } from "@/control/ControlGrid";
|
||||
import { TimeSeriesValueNumeric } from "@/control/TimeSeriesValue";
|
||||
import { MinMaxValue, TIMEFRAME_OPTIONS } from "@/control/MinMaxValue";
|
||||
import { EditValue } from "@/control/EditValue";
|
||||
import { Label } from "@/control/Label";
|
||||
|
||||
import { usePellet1 as usePellet1 } from "./usePelletizer";
|
||||
|
||||
import { SelectionGroupBoolean } from "@/control/SelectionGroup";
|
||||
import { createTimeSeries, TimeSeries } from "@/lib/timeseries";
|
||||
import { roundToDecimals } from "@/lib/decimal";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
|
||||
export function Pellet1ConfigPage() {
|
||||
const {
|
||||
//state
|
||||
state,
|
||||
defaultState,
|
||||
|
||||
//live values
|
||||
frequency,
|
||||
temperature,
|
||||
voltage,
|
||||
current,
|
||||
|
||||
// mutation functions
|
||||
SetRunning,
|
||||
SetDirection,
|
||||
SetFrequencyTarget,
|
||||
SetAccelerationLevel,
|
||||
SetDecelerationLevel,
|
||||
} = usePellet1();
|
||||
|
||||
// Extract values from consolidated state
|
||||
const running = state?.inverter_state?.running ?? false;
|
||||
const direction = state?.inverter_state?.direction ?? true;
|
||||
const frequency_target = state?.inverter_state?.frequency_target ?? 0;
|
||||
const acceleration_level = state?.inverter_state?.acceleration_level ?? 0;
|
||||
const deceleration_level = state?.inverter_state?.deceleration_level ?? 0;
|
||||
|
||||
// Shared timeframe state (default 5 minutes)
|
||||
const [timeframe, setTimeframe] = React.useState<number>(5 * 60 * 1000);
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<ControlGrid columns={2}>
|
||||
<ControlCard title="Advanced Inverter Configuration">
|
||||
<SelectionGroupBoolean
|
||||
value={running}
|
||||
optionTrue={{ children: "On" }}
|
||||
optionFalse={{ children: "Off" }}
|
||||
onChange={(v) => {
|
||||
SetRunning(v)
|
||||
}}
|
||||
/>
|
||||
|
||||
<Label label="Rotation Direction">
|
||||
<SelectionGroupBoolean
|
||||
value={direction}
|
||||
optionTrue={{ children: "Forward" }}
|
||||
optionFalse={{ children: "Backward" }}
|
||||
onChange={(v) => {
|
||||
SetDirection(v)
|
||||
}}
|
||||
/>
|
||||
</Label>
|
||||
|
||||
<Label label="Set Target Frequency">
|
||||
<EditValue
|
||||
title="Set Target Frequency"
|
||||
value={frequency_target}
|
||||
unit="Hz"
|
||||
step={0.1}
|
||||
min={0}
|
||||
max={50}
|
||||
renderValue={(value) => value.toFixed(1)}
|
||||
onChange={(val) => {
|
||||
SetFrequencyTarget(val);
|
||||
}}
|
||||
defaultValue={5}
|
||||
/>
|
||||
</Label>
|
||||
<Label label="Set Acceleration Level">
|
||||
<EditValue
|
||||
title="Set Acceleration Level"
|
||||
value={acceleration_level}
|
||||
unit={undefined}
|
||||
step={1}
|
||||
min={1}
|
||||
max={15}
|
||||
renderValue={(value) => value.toFixed(0)}
|
||||
onChange={(val) => SetAccelerationLevel(val)}
|
||||
defaultValue={7}
|
||||
/>
|
||||
</Label>
|
||||
<Label label="Set Deceleration Level">
|
||||
<EditValue
|
||||
title="Set Deceleration Level"
|
||||
value={deceleration_level}
|
||||
unit={undefined}
|
||||
step={1}
|
||||
min={1}
|
||||
max={15}
|
||||
renderValue={(value) => value.toFixed(0)}
|
||||
onChange={(val) => SetDecelerationLevel(val)}
|
||||
defaultValue={7}
|
||||
/>
|
||||
</Label>
|
||||
</ControlCard>
|
||||
</ControlGrid>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
import React from "react";
|
||||
|
||||
import { ControlCard } from "@/control/ControlCard";
|
||||
import { Page } from "@/components/Page";
|
||||
import { ControlGrid } from "@/control/ControlGrid";
|
||||
import { TimeSeriesValueNumeric } from "@/control/TimeSeriesValue";
|
||||
import { MinMaxValue, TIMEFRAME_OPTIONS } from "@/control/MinMaxValue";
|
||||
import { EditValue } from "@/control/EditValue";
|
||||
import { Label } from "@/control/Label";
|
||||
|
||||
import { usePellet1 as usePellet1 } from "./usePelletizer";
|
||||
|
||||
import { SelectionGroupBoolean } from "@/control/SelectionGroup";
|
||||
import { createTimeSeries, TimeSeries } from "@/lib/timeseries";
|
||||
import { roundToDecimals } from "@/lib/decimal";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
|
||||
export function Pellet1ControlPage() {
|
||||
const {
|
||||
//state
|
||||
state,
|
||||
defaultState,
|
||||
|
||||
//live values
|
||||
frequency,
|
||||
temperature,
|
||||
voltage,
|
||||
current,
|
||||
|
||||
// mutation functions
|
||||
SetRunning,
|
||||
SetDirection,
|
||||
SetFrequencyTarget,
|
||||
SetAccelerationLevel,
|
||||
SetDecelerationLevel,
|
||||
} = usePellet1();
|
||||
|
||||
// Extract values from consolidated state
|
||||
const running = state?.inverter_state?.running ?? false;
|
||||
const direction = state?.inverter_state?.direction ?? true;
|
||||
const frequency_target = state?.inverter_state?.frequency_target ?? 0;
|
||||
const acceleration_level = state?.inverter_state?.acceleration_level ?? 0;
|
||||
const deceleration_level = state?.inverter_state?.deceleration_level ?? 0;
|
||||
|
||||
// Shared timeframe state (default 5 minutes)
|
||||
const [timeframe, setTimeframe] = React.useState<number>(5 * 60 * 1000);
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<ControlGrid columns={2}>
|
||||
<ControlCard title="Motor Configuration">
|
||||
<SelectionGroupBoolean
|
||||
value={running}
|
||||
optionTrue={{ children: "On" }}
|
||||
optionFalse={{ children: "Off" }}
|
||||
onChange={(v) => {
|
||||
SetRunning(v)
|
||||
}}
|
||||
/>
|
||||
|
||||
<Label label="Speed">
|
||||
<EditValue
|
||||
title="Speed"
|
||||
value={frequency_target * 2}
|
||||
unit="%"
|
||||
step={0.5}
|
||||
min={0}
|
||||
max={100}
|
||||
renderValue={(value) => value.toFixed(1)}
|
||||
onChange={(val) => {
|
||||
SetFrequencyTarget(val / 2);
|
||||
}}
|
||||
defaultValue={5}
|
||||
/>
|
||||
</Label>
|
||||
</ControlCard>
|
||||
|
||||
<ControlCard title="Inverter Status">
|
||||
|
||||
{
|
||||
/*
|
||||
|
||||
<Badge
|
||||
className={`text-md ${true ? "bg-white-600 border-green-600 text-green-600" : "bg-red-600 font-bold text-white"} mx-auto h-12 w-[100%] border-3 text-lg`}
|
||||
>
|
||||
{ true ? "Running" : "PULSE OVERCURRENT"}
|
||||
</Badge>
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
<TimeSeriesValueNumeric
|
||||
label="Frequency"
|
||||
unit="Hz"
|
||||
renderValue={(value) => roundToDecimals(value, 1)}
|
||||
timeseries={ frequency }
|
||||
/>
|
||||
|
||||
<TimeSeriesValueNumeric
|
||||
label="Temperature"
|
||||
unit="C"
|
||||
renderValue={(value) => roundToDecimals(value, 1)}
|
||||
timeseries={ temperature }
|
||||
/>
|
||||
|
||||
<TimeSeriesValueNumeric
|
||||
label="Voltage"
|
||||
unit="V"
|
||||
renderValue={(value) => roundToDecimals(value, 1)}
|
||||
timeseries={ voltage }
|
||||
/>
|
||||
|
||||
<TimeSeriesValueNumeric
|
||||
label="Current"
|
||||
unit="A"
|
||||
renderValue={(value) => roundToDecimals(value, 1)}
|
||||
timeseries={ current }
|
||||
/>
|
||||
</ControlCard>
|
||||
</ControlGrid>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
import { Page } from "@/components/Page";
|
||||
import {
|
||||
AutoSyncedBigGraph,
|
||||
SyncedFloatingControlPanel,
|
||||
useGraphSync,
|
||||
type GraphConfig,
|
||||
} from "@/components/graph";
|
||||
|
||||
import React from "react";
|
||||
import { usePellet1 } from "./usePelletizer";
|
||||
|
||||
export function Pellet1GraphsPage() {
|
||||
const { diameter, x_diameter, y_diameter, roundness, state } = usePellet1();
|
||||
|
||||
const syncHook = useGraphSync("diameter-roundness-group");
|
||||
const targetDiameter = state?.laser_state?.target_diameter ?? 0;
|
||||
const lowerTolerance = state?.laser_state?.lower_tolerance ?? 0;
|
||||
const higherTolerance = state?.laser_state?.higher_tolerance ?? 0;
|
||||
|
||||
const isTwoAxis = !!x_diameter?.current || !!y_diameter?.current;
|
||||
|
||||
// Convert roundness from ratio (0-1) to percentage (0-100)
|
||||
const roundnessPercent = React.useMemo(() => {
|
||||
if (!roundness) return null;
|
||||
|
||||
const transformValue = (
|
||||
val: { value: number; timestamp: number } | null,
|
||||
) => {
|
||||
if (!val) return null;
|
||||
return { value: val.value * 100, timestamp: val.timestamp };
|
||||
};
|
||||
|
||||
const transformSeries = (series: any) => {
|
||||
if (!series || !series.values) return series;
|
||||
return {
|
||||
...series,
|
||||
values: series.values.map(transformValue),
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
current: roundness.current
|
||||
? transformValue(roundness.current)
|
||||
: null,
|
||||
long: transformSeries(roundness.long),
|
||||
short: transformSeries(roundness.short),
|
||||
};
|
||||
}, [roundness]);
|
||||
|
||||
const diameterColor = "#3b82f6"; // blue
|
||||
const xDiameterColor = "#ef4444"; // red
|
||||
const yDiameterColor = "#22c55e"; // green
|
||||
const roundnessColor = "#eab308"; // yellow
|
||||
|
||||
// config for all graphs
|
||||
const baseGraphConfig: GraphConfig = {
|
||||
title: "",
|
||||
defaultTimeWindow: 30 * 60 * 1000, // 30 minutes Standard
|
||||
colors: {
|
||||
grid: "#e2e8f0",
|
||||
axis: "#64748b",
|
||||
background: "#ffffff",
|
||||
},
|
||||
};
|
||||
|
||||
// Diameter-Graph (Diameter, X-Diameter, Y-Diameter)
|
||||
const diameterGraphData = [
|
||||
{
|
||||
newData: diameter,
|
||||
color: diameterColor,
|
||||
title: "Diameter",
|
||||
lines: [
|
||||
// Tolerance for diameter
|
||||
{
|
||||
type: "threshold" as const,
|
||||
value: targetDiameter + higherTolerance,
|
||||
label: "Upper Tolerance",
|
||||
color: diameterColor,
|
||||
dash: [5, 5],
|
||||
},
|
||||
{
|
||||
type: "threshold" as const,
|
||||
value: targetDiameter - lowerTolerance,
|
||||
label: "Lower Tolerance",
|
||||
color: diameterColor,
|
||||
dash: [5, 5],
|
||||
},
|
||||
{
|
||||
type: "target" as const,
|
||||
value: targetDiameter,
|
||||
label: "Target",
|
||||
color: diameterColor,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
...(isTwoAxis && x_diameter
|
||||
? [
|
||||
{
|
||||
newData: x_diameter,
|
||||
color: xDiameterColor,
|
||||
title: "X-Diameter",
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(isTwoAxis && y_diameter
|
||||
? [
|
||||
{
|
||||
newData: y_diameter,
|
||||
color: yDiameterColor,
|
||||
title: "Y-Diameter",
|
||||
},
|
||||
]
|
||||
: []),
|
||||
];
|
||||
|
||||
// Roundness-Graph
|
||||
const roundnessGraphData = {
|
||||
newData: roundnessPercent,
|
||||
color: roundnessColor,
|
||||
title: "Roundness (%)",
|
||||
};
|
||||
|
||||
return (
|
||||
<Page className="pb-27">
|
||||
<div className="flex flex-col gap-4">
|
||||
{/* Graph 1: Diameter */}
|
||||
<AutoSyncedBigGraph
|
||||
syncHook={syncHook}
|
||||
newData={diameterGraphData}
|
||||
unit="mm"
|
||||
renderValue={(value) => value.toFixed(3)}
|
||||
config={{
|
||||
...baseGraphConfig,
|
||||
title: "Diameter (mm)",
|
||||
exportFilename: "diameter_data",
|
||||
colors: {
|
||||
...baseGraphConfig.colors,
|
||||
primary: diameterColor,
|
||||
},
|
||||
}}
|
||||
graphId="diameter-graph"
|
||||
/>
|
||||
|
||||
{/* Graph 2: Roundness */}
|
||||
{isTwoAxis && roundnessPercent && (
|
||||
<AutoSyncedBigGraph
|
||||
syncHook={syncHook}
|
||||
newData={roundnessGraphData}
|
||||
unit="%"
|
||||
renderValue={(value) => value.toFixed(2)}
|
||||
config={{
|
||||
...baseGraphConfig,
|
||||
title: "Roundness (%)",
|
||||
exportFilename: "roundness_data",
|
||||
colors: {
|
||||
...baseGraphConfig.colors,
|
||||
primary: roundnessColor,
|
||||
},
|
||||
}}
|
||||
graphId="roundness-graph"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<SyncedFloatingControlPanel controlProps={syncHook.controlProps} />
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Page } from "@/components/Page";
|
||||
import { MarkdownWithToc } from "@/components/MarkdownWithToc";
|
||||
import React from "react";
|
||||
import laserManualContent from "@/assets/markdown/laser/manual.md?raw";
|
||||
|
||||
export function Pellet1ManualPage() {
|
||||
return (
|
||||
<Page>
|
||||
<MarkdownWithToc markdownContent={laserManualContent} />
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Topbar } from "@/components/Topbar";
|
||||
import { pelletizer1SerialRoute } from "@/routes/routes";
|
||||
import React from "react";
|
||||
|
||||
export function Pellet1Page() {
|
||||
const { serial } = pelletizer1SerialRoute.useParams();
|
||||
return (
|
||||
<Topbar
|
||||
pathname={`/_sidebar/machines/pelletizer1/${serial}`}
|
||||
items={[
|
||||
{
|
||||
link: "control",
|
||||
activeLink: "control",
|
||||
title: "Control",
|
||||
icon: "lu:CirclePlay",
|
||||
},
|
||||
{
|
||||
link: "config",
|
||||
activeLink: "config",
|
||||
title: "Config",
|
||||
icon: "lu:ChartSpline",
|
||||
},
|
||||
// {
|
||||
// link: "graphs",
|
||||
// activeLink: "graphs",
|
||||
// title: "Graphs",
|
||||
// icon: "lu:ChartSpline",
|
||||
// },
|
||||
// {
|
||||
// link: "settings",
|
||||
// activeLink: "settings",
|
||||
// title: "Config",
|
||||
// icon: "lu:ChartSpline",
|
||||
// },
|
||||
// {
|
||||
// link: "manual",
|
||||
// activeLink: "manual",
|
||||
// title: "Manual",
|
||||
// icon: "lu:BookOpen",
|
||||
// },
|
||||
// {
|
||||
// link: "presets",
|
||||
// activeLink: "presets",
|
||||
// title: "Presets",
|
||||
// icon: "lu:Save",
|
||||
// },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import React from "react";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Preset } from "@/lib/preset/preset";
|
||||
import { laser1 } from "@/machines/properties";
|
||||
import { PresetPreviewEntries } from "@/components/preset/PresetPreviewTable";
|
||||
import { PresetsPage } from "@/components/preset/PresetsPage";
|
||||
|
||||
import { usePellet1 } from "./usePelletizer";
|
||||
|
||||
const laser1PresetDataSchema = z
|
||||
.object({
|
||||
targetDiameter: z.number(),
|
||||
lowerTolerance: z.number(),
|
||||
higherTolerance: z.number(),
|
||||
})
|
||||
.partial();
|
||||
|
||||
type Laser1 = z.infer<typeof laser1PresetDataSchema>;
|
||||
|
||||
const schemas = new Map([[1, laser1PresetDataSchema]]);
|
||||
|
||||
const previewEntries: PresetPreviewEntries<Laser1> = [
|
||||
{
|
||||
name: "Target Diameter",
|
||||
unit: "mm",
|
||||
renderValue: (data: Laser1) => data?.targetDiameter?.toFixed(3),
|
||||
},
|
||||
{
|
||||
name: "Lower Tolerance",
|
||||
unit: "mm",
|
||||
renderValue: (data: Laser1) => data?.lowerTolerance?.toFixed(3),
|
||||
},
|
||||
{
|
||||
name: "Higher Tolerance",
|
||||
unit: "mm",
|
||||
renderValue: (data: Laser1) => data?.higherTolerance?.toFixed(3),
|
||||
},
|
||||
];
|
||||
|
||||
export function Pellet1PresetsPage() {
|
||||
const {
|
||||
setTargetDiameter,
|
||||
setLowerTolerance,
|
||||
setHigherTolerance,
|
||||
defaultState,
|
||||
state,
|
||||
} = usePellet1();
|
||||
|
||||
const applyPreset = (preset: Preset<Laser1>) => {
|
||||
const targetDiameter = preset?.data?.targetDiameter ?? 1.75;
|
||||
const lowerTolerance = preset?.data?.lowerTolerance ?? 0.05;
|
||||
const higherTolerance = preset?.data?.higherTolerance ?? 0.05;
|
||||
|
||||
setTargetDiameter(targetDiameter);
|
||||
setLowerTolerance(lowerTolerance);
|
||||
setHigherTolerance(higherTolerance);
|
||||
};
|
||||
|
||||
const toPresetData = (s: typeof state): Laser1 => ({
|
||||
targetDiameter: s?.laser_state.target_diameter,
|
||||
lowerTolerance: s?.laser_state.lower_tolerance,
|
||||
higherTolerance: s?.laser_state.higher_tolerance,
|
||||
});
|
||||
|
||||
return (
|
||||
<PresetsPage
|
||||
machine_identification={laser1.machine_identification}
|
||||
currentState={toPresetData(state)}
|
||||
schemas={schemas}
|
||||
schemaVersion={1}
|
||||
applyPreset={applyPreset}
|
||||
previewEntries={previewEntries}
|
||||
defaultState={toPresetData(defaultState)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* @file pellet1Namespace.ts
|
||||
* @description TypeScript implementation of Pellet1 namespace with Zod schema validation.
|
||||
*/
|
||||
|
||||
import { StoreApi } from "zustand";
|
||||
import { create } from "zustand";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
EventHandler,
|
||||
eventSchema,
|
||||
Event,
|
||||
handleUnhandledEventError,
|
||||
NamespaceId,
|
||||
createNamespaceHookImplementation,
|
||||
ThrottledStoreUpdater,
|
||||
} from "../../../client/socketioStore";
|
||||
import { MachineIdentificationUnique } from "@/machines/types";
|
||||
import {
|
||||
createTimeSeries,
|
||||
TimeSeries,
|
||||
TimeSeriesValue,
|
||||
} from "@/lib/timeseries";
|
||||
|
||||
// ========== Event Schema Definitions ==========
|
||||
/**
|
||||
* Live values from Pellet (30 FPS)
|
||||
*/
|
||||
export const liveValuesEventDataSchema = z.object({
|
||||
inverter_values: z.object({
|
||||
frequency: z.number(),
|
||||
temperature: z.number(),
|
||||
voltage: z.number(),
|
||||
current: z.number(),
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* State event from Pellet (on state changes only)
|
||||
*/
|
||||
export const stateEventDataSchema = z.object({
|
||||
is_default_state: z.boolean(),
|
||||
|
||||
inverter_state: z.object({
|
||||
running: z.boolean(),
|
||||
direction: z.boolean(),
|
||||
frequency_target: z.number(),
|
||||
acceleration_level: z.number(),
|
||||
deceleration_level: z.number(),
|
||||
}),
|
||||
});
|
||||
|
||||
// ========== Event Schemas with Wrappers ==========
|
||||
export const liveValuesEventSchema = eventSchema(liveValuesEventDataSchema);
|
||||
export const stateEventSchema = eventSchema(stateEventDataSchema);
|
||||
|
||||
// ========== Type Inferences ==========
|
||||
export type LiveValuesEvent = z.infer<typeof liveValuesEventSchema>;
|
||||
export type StateEvent = z.infer<typeof stateEventSchema>;
|
||||
|
||||
export type Pellet1NamespaceStore = {
|
||||
|
||||
state: StateEvent | null;
|
||||
defaultState: StateEvent | null;
|
||||
|
||||
// Time series data for live values
|
||||
frequency: TimeSeries;
|
||||
temperature: TimeSeries;
|
||||
voltage: TimeSeries;
|
||||
current: TimeSeries;
|
||||
};
|
||||
|
||||
// Constants for time durations
|
||||
const HALF_SECOND = 500;
|
||||
|
||||
const { initialTimeSeries: frequency, insert: addFrequency } =
|
||||
createTimeSeries({ sampleIntervalLong: HALF_SECOND });
|
||||
|
||||
const { initialTimeSeries: temperature, insert: addTemperature } =
|
||||
createTimeSeries({ sampleIntervalLong: HALF_SECOND });
|
||||
|
||||
const { initialTimeSeries: voltage, insert: addVoltage } =
|
||||
createTimeSeries({ sampleIntervalLong: HALF_SECOND });
|
||||
|
||||
const { initialTimeSeries: current, insert: addCurrent } =
|
||||
createTimeSeries({ sampleIntervalLong: HALF_SECOND });
|
||||
|
||||
/**
|
||||
* Factory function to create a new Pellet1 namespace store
|
||||
* @returns A new Zustand store instance for Pellet1 namespace
|
||||
*/
|
||||
export const createPellet1NamespaceStore =
|
||||
(): StoreApi<Pellet1NamespaceStore> =>
|
||||
create<Pellet1NamespaceStore>(() => {
|
||||
return {
|
||||
state: null,
|
||||
defaultState: null,
|
||||
frequency,
|
||||
temperature,
|
||||
voltage,
|
||||
current,
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates a message handler for Pellet1 namespace events with validation and appropriate caching strategies
|
||||
* @param store The store to update when messages are received
|
||||
* @param throttledUpdater Throttled updater for batching updates at 30 FPS
|
||||
* @returns A message handler function
|
||||
*/
|
||||
export function pellet1MessageHandler(
|
||||
store: StoreApi<Pellet1NamespaceStore>,
|
||||
throttledUpdater: ThrottledStoreUpdater<Pellet1NamespaceStore>,
|
||||
): EventHandler {
|
||||
return (event: Event<any>) =>
|
||||
{
|
||||
const eventName = event.name;
|
||||
|
||||
// Helper function to update store through buffer
|
||||
const updateStore = (updater: (state: Pellet1NamespaceStore) => Pellet1NamespaceStore) =>
|
||||
{
|
||||
throttledUpdater.updateWith(updater);
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// Apply appropriate caching strategy based on event type
|
||||
if (eventName === "StateEvent")
|
||||
{
|
||||
const stateEvent = stateEventSchema.parse(event);
|
||||
|
||||
console.log(stateEvent);
|
||||
|
||||
updateStore((state) => ({
|
||||
...state,
|
||||
state: stateEvent,
|
||||
// only set default state if is_default_state is true
|
||||
defaultState: stateEvent.data.is_default_state
|
||||
? stateEvent
|
||||
: state.defaultState,
|
||||
}));
|
||||
}
|
||||
// Live values events (keep for 1 hour)
|
||||
else if (eventName === "LiveValuesEvent")
|
||||
{
|
||||
const liveValuesEvent = liveValuesEventSchema.parse(event);
|
||||
|
||||
const frequencyValue: TimeSeriesValue = {
|
||||
value: liveValuesEvent.data.inverter_values.frequency,
|
||||
timestamp: event.ts,
|
||||
};
|
||||
|
||||
updateStore((state) => ({ ...state, frequency: addFrequency(state.frequency, frequencyValue) }));
|
||||
|
||||
const temperatureValue: TimeSeriesValue = {
|
||||
value: liveValuesEvent.data.inverter_values.temperature,
|
||||
timestamp: event.ts,
|
||||
};
|
||||
|
||||
updateStore((state) => ({
|
||||
...state,
|
||||
temperature: addTemperature(state.temperature, temperatureValue),
|
||||
}));
|
||||
|
||||
const voltageValue: TimeSeriesValue = {
|
||||
value: liveValuesEvent.data.inverter_values.voltage,
|
||||
timestamp: event.ts,
|
||||
};
|
||||
|
||||
updateStore((state) => ({
|
||||
...state,
|
||||
voltage: addVoltage(state.voltage, voltageValue),
|
||||
}));
|
||||
|
||||
const currentValue: TimeSeriesValue = {
|
||||
value: liveValuesEvent.data.inverter_values.current,
|
||||
timestamp: event.ts,
|
||||
};
|
||||
|
||||
updateStore((state) => ({
|
||||
...state,
|
||||
current: addCurrent(state.current, currentValue),
|
||||
}));
|
||||
|
||||
|
||||
} else {
|
||||
handleUnhandledEventError(eventName);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Unexpected error processing ${eventName} event:`,
|
||||
error,
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the Pellet1 namespace implementation
|
||||
*/
|
||||
const usePellet1NamespaceImplementation =
|
||||
createNamespaceHookImplementation<Pellet1NamespaceStore>({
|
||||
createStore: createPellet1NamespaceStore,
|
||||
createEventHandler: pellet1MessageHandler,
|
||||
});
|
||||
|
||||
export function usePellet1Namespace(
|
||||
machine_identification_unique: MachineIdentificationUnique,
|
||||
): Pellet1NamespaceStore {
|
||||
// Generate namespace ID from validated machine ID
|
||||
const namespaceId: NamespaceId = {
|
||||
type: "machine",
|
||||
machine_identification_unique,
|
||||
};
|
||||
|
||||
// Use the implementation with validated namespace ID
|
||||
return usePellet1NamespaceImplementation(namespaceId);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const liveValuesEventDataSchema = z.object({
|
||||
frequency: z.number(),
|
||||
temperature: z.number(),
|
||||
voltage: z.number(),
|
||||
current: z.number(),
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const stateEventDataSchema = z.object({
|
||||
is_default_state: z.boolean(),
|
||||
|
||||
inverter_state: z.object({
|
||||
running_state: z.number(),
|
||||
frequency_target: z.number(),
|
||||
acceleration_level: z.number(),
|
||||
deceleration_level: z.number(),
|
||||
|
||||
error_code: z.number().nullable(),
|
||||
system_status: z.number(),
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,185 @@
|
||||
import { toastError } from "@/components/Toast";
|
||||
import { useMachineMutate as useMachineMutation } from "@/client/useClient";
|
||||
import { MachineIdentificationUnique } from "@/machines/types";
|
||||
import { pelletizer } from "@/machines/properties";
|
||||
import { pelletizer1SerialRoute } from "@/routes/routes";
|
||||
import { z } from "zod";
|
||||
import { usePellet1Namespace, StateEvent } from "./namespace";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { useStateOptimistic } from "@/lib/useStateOptimistic";
|
||||
import { produce } from "immer";
|
||||
|
||||
function usePellet(machine_identification_unique: MachineIdentificationUnique) {
|
||||
// Get consolidated state and live values from namespace
|
||||
const { state, defaultState, frequency, temperature, voltage, current } =
|
||||
usePellet1Namespace(machine_identification_unique);
|
||||
|
||||
// Single optimistic state for all state management
|
||||
const stateOptimistic = useStateOptimistic<StateEvent>();
|
||||
|
||||
useEffect(() => { if (state) { stateOptimistic.setReal(state); } }, [state]);
|
||||
|
||||
// Helper function for optimistic updates using produce
|
||||
const updateStateOptimistically = (
|
||||
producer: (current: StateEvent) => void,
|
||||
serverRequest: () => void,
|
||||
) => {
|
||||
const currentState = stateOptimistic.value;
|
||||
if (currentState && !stateOptimistic.isOptimistic) {
|
||||
stateOptimistic.setOptimistic(produce(currentState, producer));
|
||||
}
|
||||
serverRequest();
|
||||
};
|
||||
|
||||
// Mutation schemas
|
||||
const schemaRunning = z.object({ SetRunning: z.boolean() });
|
||||
const { request: requestRunning } = useMachineMutation(schemaRunning);
|
||||
|
||||
const schemaDirection = z.object({ SetDirection: z.boolean() });
|
||||
const { request: requestDirection } = useMachineMutation(schemaDirection);
|
||||
|
||||
const schemaFrequencyTarget = z.object({ SetFrequencyTarget: z.number() });
|
||||
const { request: requestFrequencyTarget } = useMachineMutation(schemaFrequencyTarget);
|
||||
|
||||
const schemaAccelerationLevel = z.object({ SetAccelerationLevel: z.number() });
|
||||
const { request: requestAccelerationLevel } = useMachineMutation(schemaAccelerationLevel);
|
||||
|
||||
const schemaDecelerationLevel = z.object({ SetDecelerationLevel: z.number() });
|
||||
const { request: requestDecelerationLevel } = useMachineMutation(schemaDecelerationLevel);
|
||||
|
||||
const SetRunning = (running: boolean) => {
|
||||
updateStateOptimistically(
|
||||
(current) => {
|
||||
current.data.inverter_state.running = running;
|
||||
},
|
||||
() =>
|
||||
requestRunning({
|
||||
machine_identification_unique,
|
||||
data: {
|
||||
SetRunning: running,
|
||||
},
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const SetDirection = (forward: boolean) => {
|
||||
updateStateOptimistically(
|
||||
(current) => {
|
||||
current.data.inverter_state.direction = forward;
|
||||
},
|
||||
() =>
|
||||
requestDirection({
|
||||
machine_identification_unique,
|
||||
data: {
|
||||
SetDirection: forward,
|
||||
},
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const SetFrequencyTarget = (frequency_target: number) =>
|
||||
{
|
||||
updateStateOptimistically(
|
||||
(current) => {
|
||||
current.data.inverter_state.frequency_target = frequency_target;
|
||||
},
|
||||
() =>
|
||||
requestFrequencyTarget({
|
||||
machine_identification_unique,
|
||||
data: {
|
||||
SetFrequencyTarget: frequency_target,
|
||||
},
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const SetAccelerationLevel = (acceleration_level: number) => {
|
||||
updateStateOptimistically(
|
||||
(current) => {
|
||||
current.data.inverter_state.acceleration_level = acceleration_level;
|
||||
},
|
||||
() =>
|
||||
requestAccelerationLevel({
|
||||
machine_identification_unique,
|
||||
data: {
|
||||
SetAccelerationLevel: acceleration_level,
|
||||
},
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const SetDecelerationLevel = (deceleration_level: number) => {
|
||||
updateStateOptimistically(
|
||||
(current) => {
|
||||
current.data.inverter_state.deceleration_level = deceleration_level;
|
||||
},
|
||||
() =>
|
||||
requestDecelerationLevel({
|
||||
machine_identification_unique,
|
||||
data: {
|
||||
SetDecelerationLevel: deceleration_level,
|
||||
},
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
// Consolidated state
|
||||
state: stateOptimistic.value?.data,
|
||||
|
||||
// Default state for initial values
|
||||
defaultState: defaultState?.data,
|
||||
|
||||
// Live values (TimeSeries)
|
||||
frequency,
|
||||
temperature,
|
||||
voltage,
|
||||
current,
|
||||
|
||||
// Loading states
|
||||
isLoading: stateOptimistic.isOptimistic,
|
||||
isDisabled: !stateOptimistic.isInitialized,
|
||||
|
||||
// Action functions
|
||||
SetRunning,
|
||||
SetDirection,
|
||||
SetFrequencyTarget,
|
||||
SetAccelerationLevel,
|
||||
SetDecelerationLevel,
|
||||
};
|
||||
}
|
||||
|
||||
export function usePellet1()
|
||||
{
|
||||
const { serial: serialString } = pelletizer1SerialRoute.useParams();
|
||||
|
||||
// Memoize the machine identification to keep it stable between renders
|
||||
const machineIdentification: MachineIdentificationUnique = useMemo(() =>
|
||||
{
|
||||
const serial = parseInt(serialString); // Use 0 as fallback if NaN
|
||||
|
||||
if (isNaN(serial)) {
|
||||
toastError(
|
||||
"Invalid Serial Number",
|
||||
`"${serialString}" is not a valid serial number.`,
|
||||
);
|
||||
|
||||
return {
|
||||
machine_identification: {
|
||||
vendor: 0,
|
||||
machine: 0,
|
||||
},
|
||||
serial: 0,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
machine_identification: pelletizer.machine_identification,
|
||||
serial,
|
||||
};
|
||||
}, [serialString]); // Only recreate when serialString changes
|
||||
|
||||
const pellet = usePellet(machineIdentification);
|
||||
|
||||
return { ...pellet };
|
||||
}
|
||||
@@ -302,6 +302,18 @@ export const laser1: MachineProperties = {
|
||||
device_roles: [],
|
||||
};
|
||||
|
||||
export const pelletizer: MachineProperties = {
|
||||
name: "Pelletizer",
|
||||
version: "V1",
|
||||
slug: "pelletizer1",
|
||||
icon: "lu:CircleDotDashed",
|
||||
machine_identification: {
|
||||
vendor: VENDOR_QITECH,
|
||||
machine: 0x000b,
|
||||
},
|
||||
device_roles: [],
|
||||
};
|
||||
|
||||
export const mock1: MachineProperties = {
|
||||
name: "Mock",
|
||||
version: "V1",
|
||||
@@ -573,6 +585,7 @@ export const machineProperties: MachineProperties[] = [
|
||||
extruder3,
|
||||
extruder2,
|
||||
laser1,
|
||||
pelletizer,
|
||||
mock1,
|
||||
buffer1,
|
||||
wagoPower1,
|
||||
|
||||
@@ -43,6 +43,12 @@ import { Laser1GraphsPage } from "@/machines/laser/laser1/Laser1Graph";
|
||||
import { Laser1Page } from "@/machines/laser/laser1/Laser1Page";
|
||||
import { Laser1PresetsPage } from "@/machines/laser/laser1/Laser1PresetsPage";
|
||||
|
||||
import { Pellet1Page } from "@/machines/pelletizer/pelletizer1/Page";
|
||||
import { Pellet1ControlPage } from "@/machines/pelletizer/pelletizer1/ControlPage";
|
||||
import { Pellet1GraphsPage } from "@/machines/pelletizer/pelletizer1/Graph";
|
||||
import { Pellet1ConfigPage } from "@/machines/pelletizer/pelletizer1/ConfigPage";
|
||||
import { Pellet1PresetsPage } from "@/machines/pelletizer/pelletizer1/PresetsPage";
|
||||
|
||||
import { Mock1ControlPage } from "@/machines/mock/mock1/Mock1ControlPage";
|
||||
import { Mock1GraphPage } from "@/machines/mock/mock1/Mock1Graph";
|
||||
import { Mock1ManualPage } from "@/machines/mock/mock1/Mock1Manual";
|
||||
@@ -285,6 +291,38 @@ export const laser1PresetsRoute = createRoute({
|
||||
component: () => <Laser1PresetsPage />,
|
||||
});
|
||||
|
||||
// --- pelletizer
|
||||
export const pelletizer1SerialRoute = createRoute({
|
||||
getParentRoute: () => machinesRoute,
|
||||
path: "pelletizer1/$serial",
|
||||
component: () => <Pellet1Page />,
|
||||
});
|
||||
|
||||
export const pelletizer1ControlRoute = createRoute({
|
||||
getParentRoute: () => pelletizer1SerialRoute,
|
||||
path: "control",
|
||||
component: () => <Pellet1ControlPage />,
|
||||
});
|
||||
|
||||
export const pelletizer1ConfigRoute = createRoute({
|
||||
getParentRoute: () => pelletizer1SerialRoute,
|
||||
path: "config",
|
||||
component: () => <Pellet1ConfigPage />,
|
||||
});
|
||||
|
||||
export const pelletizer1GraphsRoute = createRoute({
|
||||
getParentRoute: () => pelletizer1SerialRoute,
|
||||
path: "graphs",
|
||||
component: () => <Pellet1GraphsPage />,
|
||||
});
|
||||
|
||||
export const pelletizer1PresetsRoute = createRoute({
|
||||
getParentRoute: () => pelletizer1SerialRoute,
|
||||
path: "presets",
|
||||
component: () => <Pellet1PresetsPage />,
|
||||
});
|
||||
|
||||
// --- mock
|
||||
export const mock1SerialRoute = createRoute({
|
||||
getParentRoute: () => machinesRoute,
|
||||
path: "mock1/$serial",
|
||||
@@ -470,6 +508,14 @@ export const rootTree = RootRoute.addChildren([
|
||||
laser1GraphsRoute,
|
||||
laser1PresetsRoute,
|
||||
]),
|
||||
|
||||
pelletizer1SerialRoute.addChildren([
|
||||
pelletizer1ControlRoute,
|
||||
pelletizer1GraphsRoute,
|
||||
pelletizer1ConfigRoute,
|
||||
pelletizer1PresetsRoute,
|
||||
]),
|
||||
|
||||
testMachineSerialRoute.addChildren([testMachineControlRoute]),
|
||||
|
||||
analogInputTestMachineSerialRoute.addChildren([
|
||||
|
||||
@@ -31,6 +31,13 @@ serialport = "4.7.3"
|
||||
tracing = { version = "0.1.44", features = ["attributes"] }
|
||||
tonic = { version = "0.13.1", optional = true }
|
||||
|
||||
# modbus interfaces
|
||||
modbus = { git = "https://github.com/just-some-entity/modbus-rs.git", features = ["linux-rtu-transport"] }
|
||||
|
||||
# enum stuff
|
||||
strum = "0.26"
|
||||
strum_macros = "0.26"
|
||||
|
||||
[dev-dependencies]
|
||||
approx = "0.5.1"
|
||||
textplots = "0.8.7"
|
||||
|
||||
@@ -26,6 +26,7 @@ pub mod extruder1;
|
||||
pub mod extruder2;
|
||||
pub mod ip20_test_machine;
|
||||
pub mod laser;
|
||||
pub mod pelletizer;
|
||||
pub mod machine_identification;
|
||||
pub mod mock;
|
||||
pub mod registry;
|
||||
@@ -39,6 +40,7 @@ pub const VENDOR_QITECH: u16 = 0x0001;
|
||||
pub const MACHINE_WINDER_V1: u16 = 0x0002;
|
||||
pub const MACHINE_EXTRUDER_V1: u16 = 0x0004;
|
||||
pub const MACHINE_LASER_V1: u16 = 0x0006;
|
||||
pub const MACHINE_PELLETIZER: u16 = 0x000B;
|
||||
pub const MACHINE_MOCK: u16 = 0x0007;
|
||||
pub const MACHINE_BUFFER_V1: u16 = 0x0008;
|
||||
pub const MACHINE_AQUAPATH_V1: u16 = 0x0009;
|
||||
|
||||
@@ -54,6 +54,7 @@ impl MachineIdentification {
|
||||
x if x == MACHINE_WINDER_V1 => "winder_v1".to_string(),
|
||||
x if x == MACHINE_EXTRUDER_V1 => "extruder_v1".to_string(),
|
||||
x if x == MACHINE_LASER_V1 => "laser_v1".to_string(),
|
||||
x if x == MACHINE_PELLETIZER => "pelletizer_v1".to_string(),
|
||||
x if x == MACHINE_MOCK => "mock".to_string(),
|
||||
x if x == MACHINE_AQUAPATH_V1 => "aquapath_v1".to_string(),
|
||||
x if x == MACHINE_BUFFER_V1 => "buffer_v1".to_string(),
|
||||
@@ -182,6 +183,7 @@ use crate::MACHINE_EXTRUDER_V1;
|
||||
use crate::MACHINE_EXTRUDER_V2;
|
||||
use crate::MACHINE_LASER_V1;
|
||||
use crate::MACHINE_MOCK;
|
||||
use crate::MACHINE_PELLETIZER;
|
||||
use crate::MACHINE_WAGO_POWER_V1;
|
||||
use crate::MACHINE_WINDER_V1;
|
||||
use crate::TEST_MACHINE;
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use serde::de::VariantAccess;
|
||||
use units::frequency::hertz;
|
||||
|
||||
use crate::MachineAct;
|
||||
use crate::MachineMessage;
|
||||
use crate::MachineValues;
|
||||
|
||||
use super::Pelletizer;
|
||||
|
||||
impl MachineAct for Pelletizer
|
||||
{
|
||||
fn act(&mut self, now: Instant)
|
||||
{
|
||||
if let Ok(msg) = self.api_receiver.try_recv()
|
||||
{
|
||||
self.act_machine_message(msg);
|
||||
};
|
||||
|
||||
let should_emit =
|
||||
now.duration_since(self.last_measurement_emit)
|
||||
> Duration::from_secs_f64(1.0 / 12.0);
|
||||
|
||||
let mut mutated: bool = false;
|
||||
let mut inverter_snapshot_id: u64 = 0;
|
||||
|
||||
{
|
||||
let mut inverter = smol::block_on(async {
|
||||
self.inverter.write().await
|
||||
});
|
||||
|
||||
if let Some(value) = self.mutation_request.running.take()
|
||||
{
|
||||
tracing::warn!("Setting running to: {}", value);
|
||||
|
||||
inverter.set_running(value);
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if let Some(value) = self.mutation_request.direction.take()
|
||||
{
|
||||
tracing::warn!("Setting direction to: {}", value);
|
||||
|
||||
inverter.set_direction(value);
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if let Some(value) = self.mutation_request.frequency.take()
|
||||
{
|
||||
tracing::warn!("Setting to: {}", value);
|
||||
|
||||
inverter.set_frequency_target((value * 10.0) as u16);
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if let Some(value) = self.mutation_request.accleration_level.take()
|
||||
{
|
||||
tracing::warn!("Setting to: {}", value);
|
||||
|
||||
inverter.set_acceleration_level(value);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if let Some(value) = self.mutation_request.decleration_level.take()
|
||||
{
|
||||
tracing::warn!("Setting to: {}", value);
|
||||
|
||||
inverter.set_deceleration_level(value);
|
||||
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if should_emit {
|
||||
inverter.refresh_status();
|
||||
}
|
||||
|
||||
if mutated { }
|
||||
|
||||
inverter.update();
|
||||
|
||||
inverter_snapshot_id = inverter.config.snapshot_id;
|
||||
} // drop lock
|
||||
|
||||
if should_emit
|
||||
{
|
||||
if self.inverter_snapshot_id != inverter_snapshot_id
|
||||
{
|
||||
self.emit_state();
|
||||
self.inverter_snapshot_id = inverter_snapshot_id;
|
||||
}
|
||||
|
||||
self.emit_live_values();
|
||||
self.last_measurement_emit = now;
|
||||
}
|
||||
}
|
||||
|
||||
fn act_machine_message(&mut self, msg: MachineMessage)
|
||||
{
|
||||
match msg
|
||||
{
|
||||
MachineMessage::SubscribeNamespace(namespace) =>
|
||||
{
|
||||
self.namespace.namespace = Some(namespace);
|
||||
self.emit_state();
|
||||
}
|
||||
|
||||
MachineMessage::UnsubscribeNamespace => match &mut self.namespace.namespace
|
||||
{
|
||||
Some(namespace) =>
|
||||
{
|
||||
tracing::info!("UnsubscribeNamespace");
|
||||
namespace.socket_queue_tx.close();
|
||||
namespace.sockets.clear();
|
||||
namespace.events.clear();
|
||||
}
|
||||
None => todo!(),
|
||||
},
|
||||
MachineMessage::HttpApiJsonRequest(value) =>
|
||||
{
|
||||
use crate::MachineApi;
|
||||
let _res = self.api_mutate(value);
|
||||
}
|
||||
MachineMessage::ConnectToMachine(_machine_connection) => {}
|
||||
MachineMessage::DisconnectMachine(_machine_connection) => {}
|
||||
MachineMessage::RequestValues(sender) =>
|
||||
{
|
||||
tracing::error!("REQUESTED VALUES");
|
||||
|
||||
let state = serde_json::to_value(self.create_state_event()).expect("Failed to serialize state");
|
||||
|
||||
let live_values = serde_json::to_value(self.create_live_values_event()).expect("Failed to serialize live values");
|
||||
|
||||
sender.send_blocking(MachineValues{ state, live_values }).expect("Failed to send values");
|
||||
sender.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
use crate::{MachineApi, MachineMessage};
|
||||
|
||||
use super::Pelletizer;
|
||||
use control_core::socketio::{
|
||||
event::{Event, GenericEvent},
|
||||
namespace::{
|
||||
CacheFn, CacheableEvents, Namespace, NamespaceCacheingLogic, cache_first_and_last_event,
|
||||
},
|
||||
};
|
||||
use control_core_derive::BuildEvent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use smol::channel::Sender;
|
||||
use std::sync::Arc;
|
||||
use tracing::instrument;
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct LiveValuesEvent
|
||||
{
|
||||
pub inverter_values: InverterLiveValues
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct InverterLiveValues
|
||||
{
|
||||
pub frequency: f64,
|
||||
pub temperature: f64,
|
||||
pub voltage: f64,
|
||||
pub current: f64,
|
||||
}
|
||||
|
||||
impl LiveValuesEvent {
|
||||
pub fn build(&self) -> Event<Self> {
|
||||
Event::new("LiveValuesEvent", self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone, PartialEq, BuildEvent)]
|
||||
pub struct StateEvent {
|
||||
pub is_default_state: bool,
|
||||
|
||||
pub inverter_state: InverterState,
|
||||
}
|
||||
|
||||
impl StateEvent {
|
||||
pub fn build(&self) -> Event<Self> {
|
||||
Event::new("StateEvent", self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone, PartialEq)]
|
||||
pub struct InverterState
|
||||
{
|
||||
pub running: bool,
|
||||
pub direction: bool,
|
||||
pub frequency_target: f64,
|
||||
pub acceleration_level: u16,
|
||||
pub deceleration_level: u16,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Clone, PartialEq)]
|
||||
pub struct RotationState
|
||||
{
|
||||
pub forward: bool,
|
||||
}
|
||||
|
||||
pub enum PelletMachineEvents {
|
||||
LiveValues(Event<LiveValuesEvent>),
|
||||
State(Event<StateEvent>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PelletMachineNamespace {
|
||||
pub namespace: Option<Namespace>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
/// Mutation for controlling the Pellet machine
|
||||
enum Mutation
|
||||
{
|
||||
SetRunning(bool),
|
||||
SetDirection(bool),
|
||||
SetFrequencyTarget(f64),
|
||||
SetAccelerationLevel(u16),
|
||||
SetDecelerationLevel(u16),
|
||||
}
|
||||
|
||||
impl MachineApi for Pelletizer {
|
||||
fn api_get_sender(&self) -> Sender<MachineMessage> {
|
||||
self.api_sender.clone()
|
||||
}
|
||||
|
||||
fn api_mutate(&mut self, request_body: Value) -> Result<(), anyhow::Error>
|
||||
{
|
||||
tracing::error!("Received: {:?}", &request_body);
|
||||
|
||||
let mutation: Mutation = serde_json::from_value(request_body)?;
|
||||
|
||||
match mutation
|
||||
{
|
||||
Mutation::SetRunning(running) =>
|
||||
{
|
||||
self.mutation_request.running = Some(running);
|
||||
}
|
||||
Mutation::SetDirection(forward) =>
|
||||
{
|
||||
self.mutation_request.direction = Some(forward);
|
||||
}
|
||||
Mutation::SetFrequencyTarget(frequency) =>
|
||||
{
|
||||
self.mutation_request.frequency = Some(frequency);
|
||||
}
|
||||
Mutation::SetAccelerationLevel(level) =>
|
||||
{
|
||||
self.mutation_request.accleration_level = Some(level);
|
||||
}
|
||||
Mutation::SetDecelerationLevel(level) =>
|
||||
{
|
||||
self.mutation_request.decleration_level = Some(level);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn api_event_namespace(&mut self) -> Option<Namespace> {
|
||||
self.namespace.namespace.clone()
|
||||
}
|
||||
}
|
||||
|
||||
//TODO; rename NamespaceCacheingLogic to NamespaceCachingLogic
|
||||
impl NamespaceCacheingLogic<PelletMachineEvents> for PelletMachineNamespace {
|
||||
#[instrument(skip_all)]
|
||||
fn emit(&mut self, events: PelletMachineEvents) {
|
||||
let event = Arc::new(events.event_value());
|
||||
let buffer_fn = events.event_cache_fn();
|
||||
|
||||
if let Some(ns) = &mut self.namespace { ns.emit(event, &buffer_fn) }
|
||||
}
|
||||
}
|
||||
|
||||
impl CacheableEvents<Self> for PelletMachineEvents {
|
||||
fn event_value(&self) -> GenericEvent {
|
||||
match self {
|
||||
Self::LiveValues(event) => event.into(),
|
||||
Self::State(event) => event.into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn event_cache_fn(&self) -> CacheFn {
|
||||
let cache_first_and_last = cache_first_and_last_event();
|
||||
|
||||
match self {
|
||||
Self::LiveValues(_) => cache_first_and_last,
|
||||
Self::State(_) => cache_first_and_last,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
|
||||
use crate::pelletizer::Pelletizer;
|
||||
|
||||
use crate::pelletizer::api::{InverterLiveValues, InverterState, LiveValuesEvent, PelletMachineEvents, StateEvent};
|
||||
|
||||
use control_core::socketio::event::BuildEvent;
|
||||
|
||||
use control_core::socketio::namespace::NamespaceCacheingLogic;
|
||||
|
||||
impl Pelletizer
|
||||
{
|
||||
pub fn emit_state(&mut self)
|
||||
{
|
||||
let event = self.create_state_event().build();
|
||||
self.namespace.emit(PelletMachineEvents::State(event));
|
||||
self.emitted_default_state = true;
|
||||
}
|
||||
|
||||
pub fn emit_live_values(&mut self)
|
||||
{
|
||||
let event = self.create_live_values_event().build();
|
||||
self.namespace.emit(PelletMachineEvents::LiveValues(event));
|
||||
}
|
||||
|
||||
pub fn create_state_event(&self) -> StateEvent
|
||||
{
|
||||
let inverter = smol::block_on(async {
|
||||
self.inverter.read().await
|
||||
});
|
||||
|
||||
tracing::error!("EMIT STATE: {:?}", inverter.config);
|
||||
|
||||
StateEvent
|
||||
{
|
||||
is_default_state: !self.emitted_default_state,
|
||||
inverter_state: InverterState {
|
||||
running: inverter.config.running,
|
||||
direction: inverter.config.direction,
|
||||
frequency_target: (inverter.config.frequency_target as f64) / 10.0,
|
||||
acceleration_level: inverter.config.acceleration_level,
|
||||
deceleration_level: inverter.config.deceleration_level,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_live_values_event(&self) -> LiveValuesEvent
|
||||
{
|
||||
let inverter = smol::block_on(async {
|
||||
self.inverter.read().await
|
||||
});
|
||||
|
||||
if let Some(status) = inverter.status
|
||||
{
|
||||
return LiveValuesEvent {
|
||||
inverter_values: InverterLiveValues {
|
||||
voltage: status.voltage.value,
|
||||
current: status.current.value,
|
||||
temperature: status.temperature.value,
|
||||
frequency: status.frequency.value,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
LiveValuesEvent {
|
||||
inverter_values: InverterLiveValues {
|
||||
voltage: 0.0,
|
||||
current: 0.0,
|
||||
temperature: 0.0,
|
||||
frequency: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
//use serde::{Deserialize, Serialize};
|
||||
|
||||
|
||||
use crate::{
|
||||
MACHINE_PELLETIZER, MachineMessage, VENDOR_QITECH,
|
||||
machine_identification::{MachineIdentification, MachineIdentificationUnique},
|
||||
};
|
||||
|
||||
use smol::{
|
||||
channel::{Receiver, Sender},
|
||||
lock::RwLock,
|
||||
};
|
||||
use socketioxide::extract::SocketRef;
|
||||
|
||||
use crate::{AsyncThreadMessage, serial::devices::us_3202510::US3202510};
|
||||
|
||||
use std::{sync::Arc, time::Instant};
|
||||
|
||||
pub mod act;
|
||||
pub mod api;
|
||||
pub mod new;
|
||||
pub mod emit;
|
||||
|
||||
use crate::Machine;
|
||||
|
||||
use api::{PelletMachineNamespace};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Pelletizer
|
||||
{
|
||||
// stuff for every machine
|
||||
api_receiver: Receiver<MachineMessage>,
|
||||
api_sender: Sender<MachineMessage>,
|
||||
main_sender: Option<Sender<AsyncThreadMessage>>,
|
||||
machine_identification_unique: MachineIdentificationUnique,
|
||||
|
||||
emitted_default_state: bool,
|
||||
|
||||
// socketio
|
||||
namespace: PelletMachineNamespace,
|
||||
last_measurement_emit: Instant,
|
||||
|
||||
// machine specific
|
||||
inverter: Arc<RwLock<US3202510>>,
|
||||
|
||||
inverter_snapshot_id: u64,
|
||||
|
||||
mutation_request: MutationRequests
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MutationRequests
|
||||
{
|
||||
running: Option<bool>,
|
||||
direction: Option<bool>,
|
||||
frequency: Option<f64>,
|
||||
accleration_level: Option<u16>,
|
||||
decleration_level: Option<u16>,
|
||||
}
|
||||
|
||||
impl Machine for Pelletizer
|
||||
{
|
||||
fn get_machine_identification_unique(&self) -> MachineIdentificationUnique
|
||||
{
|
||||
self.machine_identification_unique.clone()
|
||||
}
|
||||
|
||||
fn get_main_sender(&self) -> Option<Sender<AsyncThreadMessage>>
|
||||
{
|
||||
self.main_sender.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl PelletMachineNamespace
|
||||
{
|
||||
pub async fn disconnect_all(&self)
|
||||
{
|
||||
for socket in self.connected_sockets().await
|
||||
{
|
||||
let _ = socket.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
async fn connected_sockets(&self) -> Vec<SocketRef>
|
||||
{
|
||||
if self.namespace.is_none()
|
||||
{ vec![] }
|
||||
else
|
||||
{ self.namespace.clone().unwrap().sockets.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Pelletizer
|
||||
{
|
||||
fn drop(&mut self)
|
||||
{
|
||||
tracing::info!(
|
||||
"[Pelletizer::{:?}] Dropping machine and disconnecting clients...",
|
||||
self.machine_identification_unique
|
||||
);
|
||||
smol::block_on(self.namespace.disconnect_all());
|
||||
}
|
||||
}
|
||||
|
||||
impl Pelletizer
|
||||
{
|
||||
pub const MACHINE_IDENTIFICATION: MachineIdentification = MachineIdentification {
|
||||
vendor: VENDOR_QITECH,
|
||||
machine: MACHINE_PELLETIZER,
|
||||
};
|
||||
|
||||
pub fn update(&mut self)
|
||||
{
|
||||
//let laser_data = smol::block_on(async { self.inverter.read().await.get_data().await });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::pelletizer::MutationRequests;
|
||||
use crate::serial::devices::us_3202510::US3202510;
|
||||
use crate::serial::{registry::SERIAL_DEVICE_REGISTRY};
|
||||
use crate::{MachineNewHardware, MachineNewTrait};
|
||||
|
||||
use super::{Pelletizer, api::PelletMachineNamespace};
|
||||
|
||||
use anyhow::Error;
|
||||
|
||||
impl MachineNewTrait for Pelletizer
|
||||
{
|
||||
fn new(params: &crate::MachineNewParams<'_, '_, '_, '_, '_, '_, '_>) -> Result<Self, Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let hardware_serial = match params.hardware
|
||||
{
|
||||
MachineNewHardware::Serial(serial) => *serial,
|
||||
_ => return Err(Error::msg("Invalid hardware type for Pelletizer")),
|
||||
};
|
||||
|
||||
let inverter = match smol::block_on(
|
||||
SERIAL_DEVICE_REGISTRY.downcast_arc_rwlock::<US3202510>(hardware_serial.device.clone()),
|
||||
) {
|
||||
Ok(inverter) => inverter,
|
||||
Err(_) => return Err(Error::msg("Failed to downcast to US3202510")),
|
||||
};
|
||||
|
||||
let (sender, receiver) = smol::channel::unbounded();
|
||||
|
||||
let pelletizer = Self {
|
||||
main_sender: params.main_thread_channel.clone(),
|
||||
api_receiver: receiver,
|
||||
api_sender: sender,
|
||||
machine_identification_unique: params.get_machine_identification_unique(),
|
||||
|
||||
namespace: PelletMachineNamespace {
|
||||
namespace: params.namespace.clone(),
|
||||
},
|
||||
|
||||
emitted_default_state: false,
|
||||
last_measurement_emit: Instant::now(),
|
||||
|
||||
inverter,
|
||||
|
||||
inverter_snapshot_id: 0,
|
||||
|
||||
mutation_request: MutationRequests {
|
||||
running: None,
|
||||
direction: None,
|
||||
frequency: None,
|
||||
accleration_level: None,
|
||||
decleration_level: None,
|
||||
}
|
||||
};
|
||||
|
||||
Ok(pelletizer)
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ use crate::{
|
||||
use crate::extruder1::ExtruderV2;
|
||||
#[cfg(not(feature = "mock-machine"))]
|
||||
use crate::{
|
||||
aquapath1::AquaPathV1, buffer1::BufferV1, extruder2::ExtruderV3, laser::LaserMachine,
|
||||
aquapath1::AquaPathV1, buffer1::BufferV1, extruder2::ExtruderV3, laser::LaserMachine, pelletizer::Pelletizer,
|
||||
winder2::Winder2,
|
||||
};
|
||||
|
||||
@@ -118,6 +118,9 @@ lazy_static! {
|
||||
#[cfg(not(feature = "mock-machine"))]
|
||||
mc.register::<LaserMachine>(LaserMachine::MACHINE_IDENTIFICATION);
|
||||
|
||||
#[cfg(not(feature = "mock-machine"))]
|
||||
mc.register::<Pelletizer>(Pelletizer::MACHINE_IDENTIFICATION);
|
||||
|
||||
#[cfg(not(feature = "mock-machine"))]
|
||||
mc.register::<BufferV1>(BufferV1::MACHINE_IDENTIFICATION);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#[cfg(feature = "mock-machine")]
|
||||
pub mod extruder_mock;
|
||||
pub mod laser;
|
||||
pub mod us_3202510;
|
||||
#[cfg(feature = "mock-machine")]
|
||||
pub mod mock;
|
||||
#[cfg(feature = "mock-machine")]
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
|
||||
use modbus::{RequestResult, rtu::{DispatchError, backends::LinuxTransport}};
|
||||
// external deps
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// use modbus::ExceptionCode
|
||||
|
||||
// internal deps
|
||||
pub use request::Request;
|
||||
|
||||
use units::{Frequency, electric_current::ampere, electric_potential::volt, frequency::hertz, thermodynamic_temperature::{degree_celsius, kelvin}};
|
||||
|
||||
// modules
|
||||
mod register;
|
||||
mod request;
|
||||
mod serial_device;
|
||||
|
||||
mod transport;
|
||||
|
||||
use crate::serial::devices::us_3202510::{register::{HoldingRegister, InputRegister}, transport::{CustomTransport, EntryContext}};
|
||||
|
||||
type ModbusInterface = modbus::rtu::Interface<CustomTransport, EntryContext, 25>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct US3202510
|
||||
{
|
||||
pub path: String,
|
||||
pub config: Config,
|
||||
pub status: Option<Status>,
|
||||
|
||||
failed_attempts: u8,
|
||||
interface: ModbusInterface,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct Config
|
||||
{
|
||||
pub snapshot_id: u64,
|
||||
|
||||
pub running: bool,
|
||||
pub direction: bool,
|
||||
pub frequency_target: u16, // 0 - 99hz
|
||||
pub frequency_min: u16,
|
||||
pub frequency_max: u16,
|
||||
pub acceleration_level: u16, // 1 - 15
|
||||
pub deceleration_level: u16, // 1 - 15
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct Status
|
||||
{
|
||||
pub frequency: units::Frequency, // 1 - 99hz
|
||||
pub voltage: units::ElectricPotential,
|
||||
pub current: units::ElectricCurrent,
|
||||
pub temperature: units::ThermodynamicTemperature,
|
||||
pub operation_status: OperationStatus,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub enum Direction
|
||||
{
|
||||
#[default]
|
||||
Stopped,
|
||||
Forward,
|
||||
Reverse,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub enum OperationStatus
|
||||
{
|
||||
#[default]
|
||||
Idle,
|
||||
Running,
|
||||
Fault,
|
||||
}
|
||||
|
||||
impl US3202510
|
||||
{
|
||||
pub fn update(&mut self)
|
||||
{
|
||||
if self.config.snapshot_id == 0
|
||||
{
|
||||
self.refresh_config();
|
||||
self.config.snapshot_id += 1;
|
||||
}
|
||||
|
||||
match self.interface.await_result()
|
||||
{
|
||||
Ok(result) =>
|
||||
{
|
||||
self.handle_result(result);
|
||||
},
|
||||
Err(e) =>
|
||||
{
|
||||
match e
|
||||
{
|
||||
modbus::rtu::ReceiveError::NoPendingRequest => {},
|
||||
|
||||
e =>
|
||||
{
|
||||
tracing::error!("Error reciving result: {:?}", e);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
if !self.interface.has_pending_request()
|
||||
{
|
||||
match self.interface.dispatch_next_request()
|
||||
{
|
||||
Ok(_) =>
|
||||
{
|
||||
tracing::error!("Success sending request: {:?}", self.interface);
|
||||
},
|
||||
Err(e) =>
|
||||
{
|
||||
match e
|
||||
{
|
||||
DispatchError::RequestPending => {},
|
||||
DispatchError::QueueEmpty => {},
|
||||
DispatchError::Transport(err) =>
|
||||
{
|
||||
tracing::error!("Error sending request: {}", err);
|
||||
},
|
||||
DispatchError::BridgeDropped =>
|
||||
{
|
||||
tracing::error!("Bridge dropped");
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn queue_request(&mut self, request: Request)
|
||||
{
|
||||
let data = request.to_interface_request();
|
||||
match self.interface.queue_request(data.type_id, data.payload, data.priority)
|
||||
{
|
||||
Ok(_) => {},
|
||||
Err(x) =>
|
||||
{
|
||||
match x
|
||||
{
|
||||
modbus::QueueItemError::QueueFull => { tracing::error!("QueueFull!"); },
|
||||
modbus::QueueItemError::DuplicateItem => { tracing::error!("DuplicateItem!"); },
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn refresh_status(&mut self)
|
||||
{
|
||||
self.queue_request(Request::RefreshStatus);
|
||||
}
|
||||
|
||||
pub fn refresh_config(&mut self)
|
||||
{
|
||||
self.queue_request(Request::RefreshState);
|
||||
}
|
||||
|
||||
pub fn set_running(&mut self, running: bool)
|
||||
{
|
||||
if self.config.running == running { return; }
|
||||
|
||||
tracing::error!("Setting running to: {}", running);
|
||||
|
||||
match running
|
||||
{
|
||||
true =>
|
||||
{
|
||||
let value: u16 = match self.config.direction
|
||||
{
|
||||
true => 1,
|
||||
false => 3,
|
||||
};
|
||||
|
||||
self.queue_request(Request::SetRotationState(value));
|
||||
},
|
||||
false => { self.queue_request(Request::SetRotationState(2)); },
|
||||
}
|
||||
|
||||
self.config.running = running;
|
||||
}
|
||||
|
||||
pub fn set_direction(&mut self, direction: bool)
|
||||
{
|
||||
if self.config.direction != direction && self.config.running
|
||||
{
|
||||
let value: u16 = if direction { 1 } else { 3 };
|
||||
|
||||
tracing::error!("Setting direction to: {}", value);
|
||||
|
||||
|
||||
self.queue_request(Request::SetRotationState(value));
|
||||
}
|
||||
|
||||
self.config.direction = direction;
|
||||
}
|
||||
|
||||
pub fn set_frequency_target(&mut self, frequency: u16)
|
||||
{
|
||||
self.config.frequency_target = frequency.min(990);
|
||||
self.queue_request(Request::SetFrequencyTarget(self.config.frequency_target));
|
||||
}
|
||||
|
||||
pub fn set_acceleration_level(&mut self, acceleration_level: u16)
|
||||
{
|
||||
self.config.acceleration_level = acceleration_level.clamp(1, 15);
|
||||
self.queue_request(Request::SetAccelerationLevel(self.config.acceleration_level));
|
||||
}
|
||||
|
||||
pub fn set_deceleration_level(&mut self, deceleration_level: u16)
|
||||
{
|
||||
self.config.deceleration_level = deceleration_level.clamp(1, 15);
|
||||
self.queue_request(Request::SetDecelerationLevel(self.config.deceleration_level));
|
||||
}
|
||||
|
||||
fn handle_result(&mut self, response: RequestResult)
|
||||
{
|
||||
match response
|
||||
{
|
||||
RequestResult::ReadHoldingRegisters(data) =>
|
||||
{
|
||||
tracing::error!("BRANCH: HIT: {:?}", data);
|
||||
|
||||
let frequency_target: u16 =
|
||||
*data.result.get(0)
|
||||
.unwrap_or(&0);
|
||||
|
||||
let _run_command: u16 =
|
||||
*data.result.get(1)
|
||||
.unwrap_or(&0);
|
||||
|
||||
let acceleration_level: u16 =
|
||||
*data.result.get(2)
|
||||
.unwrap_or(&0);
|
||||
|
||||
let deceleration_level: u16 =
|
||||
*data.result.get(3)
|
||||
.unwrap_or(&0);
|
||||
|
||||
self.config.running = _run_command != 2;
|
||||
self.config.frequency_target = frequency_target;
|
||||
self.config.acceleration_level = acceleration_level;
|
||||
self.config.deceleration_level = deceleration_level;
|
||||
|
||||
self.config.snapshot_id += 1;
|
||||
},
|
||||
RequestResult::ReadInputRegisters(data) =>
|
||||
{
|
||||
let frequency: u16 = *data.result.get(InputRegister::CurrentFrequency as usize).unwrap_or(&0);
|
||||
|
||||
let voltage: u16 = *data.result.get(InputRegister::BusVoltage as usize).unwrap_or(&0);
|
||||
|
||||
let current: u16 = *data.result.get(InputRegister::LineCurrent as usize).unwrap_or(&0);
|
||||
|
||||
let temperature: u16 = *data.result.get(InputRegister::DriveTemperature as usize).unwrap_or(&0);
|
||||
|
||||
let operation_status: u16 = *data.result.get(InputRegister::SystemStatus as usize).unwrap_or(&0);
|
||||
|
||||
self.status = Some(Status {
|
||||
frequency: units::Frequency::new::<hertz>((frequency as f64) / 10.0),
|
||||
voltage: units::ElectricPotential::new::<volt>((voltage as f64) / 10.0),
|
||||
current: units::ElectricCurrent::new::<ampere>((current as f64) / 10.0),
|
||||
temperature: units::ThermodynamicTemperature::new::<kelvin>((temperature as f64)),
|
||||
operation_status: if operation_status == 0 { OperationStatus::Idle } else if operation_status == 1 {OperationStatus::Running } else { OperationStatus::Fault },
|
||||
});
|
||||
},
|
||||
RequestResult::PresetHoldingRegister(request_result_data) =>
|
||||
{
|
||||
tracing::error!("PresetHoldingRegister: WORKED");
|
||||
|
||||
self.config.snapshot_id += 1;
|
||||
},
|
||||
RequestResult::Exception(request_result_data) =>
|
||||
{
|
||||
tracing::error!("Received exception: {:?}", request_result_data.result);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests
|
||||
{
|
||||
#[test]
|
||||
fn test_requests() {}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
use strum_macros::{EnumCount};
|
||||
|
||||
#[derive(Debug, Clone, Copy, EnumCount)]
|
||||
pub enum HoldingRegister
|
||||
{
|
||||
/// Register 0x0002
|
||||
SetFrequency = 0x2,
|
||||
|
||||
/// Register 0x0003
|
||||
#[allow(dead_code)]
|
||||
RunCommand = 0x3,
|
||||
|
||||
/// Register 0x0004
|
||||
#[allow(dead_code)]
|
||||
AccelerationTime = 0x4,
|
||||
|
||||
/// Register 0x0005
|
||||
#[allow(dead_code)]
|
||||
DecelerationTime = 0x5,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, EnumCount)]
|
||||
pub enum InputRegister
|
||||
{
|
||||
/// Register 0x0008
|
||||
#[allow(dead_code)]
|
||||
BusVoltage,
|
||||
|
||||
/// Register 0x0009
|
||||
#[allow(dead_code)]
|
||||
LineCurrent,
|
||||
|
||||
/// Register 0x000A
|
||||
#[allow(dead_code)]
|
||||
DriveTemperature,
|
||||
|
||||
/// Register 0x000B
|
||||
#[allow(dead_code)]
|
||||
SystemStatus,
|
||||
|
||||
/// Register 0x000C
|
||||
#[allow(dead_code)]
|
||||
ErrorCode,
|
||||
|
||||
/// Register 0x000D
|
||||
#[allow(dead_code)]
|
||||
CurrentFrequency,
|
||||
}
|
||||
|
||||
impl HoldingRegister
|
||||
{
|
||||
pub const OFFSET: u16 = 0x2;
|
||||
|
||||
pub const fn address(self) -> u16
|
||||
{
|
||||
match self
|
||||
{
|
||||
Self::SetFrequency => Self::OFFSET, // 0x0002
|
||||
Self::RunCommand => Self::OFFSET + 1, // 0x0003
|
||||
Self::AccelerationTime => Self::OFFSET + 2, // 0x0004
|
||||
Self::DecelerationTime => Self::OFFSET + 3, // 0x0005
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InputRegister
|
||||
{
|
||||
pub const OFFSET: u16 = 0x8;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const fn address(self) -> u16
|
||||
{
|
||||
match self
|
||||
{
|
||||
Self::BusVoltage => Self::OFFSET, // 0x0008
|
||||
Self::LineCurrent => Self::OFFSET + 1, // 0x0009
|
||||
Self::DriveTemperature => Self::OFFSET + 2, // 0x000A
|
||||
Self::SystemStatus => Self::OFFSET + 3, // 0x000B
|
||||
Self::ErrorCode => Self::OFFSET + 4, // 0x000C
|
||||
Self::CurrentFrequency => Self::OFFSET + 5, // 0x000D
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
use modbus::request::WriteRegister;
|
||||
use strum::EnumCount;
|
||||
use strum_macros::{EnumCount};
|
||||
|
||||
use crate::serial::devices::us_3202510::register::HoldingRegister;
|
||||
use crate::serial::devices::us_3202510::register::InputRegister;
|
||||
|
||||
use modbus::Request as InterfaceRequest;
|
||||
|
||||
use modbus::request::ReadRegisters;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
|
||||
pub enum Request
|
||||
{
|
||||
RefreshStatus,
|
||||
RefreshState,
|
||||
SetRotationState(u16),
|
||||
SetFrequencyTarget(u16),
|
||||
SetAccelerationLevel(u16),
|
||||
SetDecelerationLevel(u16),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RequestData
|
||||
{
|
||||
pub type_id: u32,
|
||||
pub priority: u32,
|
||||
pub payload: InterfaceRequest,
|
||||
}
|
||||
|
||||
impl Request
|
||||
{
|
||||
pub fn to_interface_request(&self) -> RequestData
|
||||
{
|
||||
match self
|
||||
{
|
||||
Request::RefreshStatus =>
|
||||
{
|
||||
let payload =
|
||||
InterfaceRequest::ReadInputRegisters(
|
||||
ReadRegisters
|
||||
{
|
||||
start_address: InputRegister::OFFSET,
|
||||
quantity: InputRegister::COUNT as u16,
|
||||
}
|
||||
);
|
||||
|
||||
RequestData { type_id: 0, priority: 10, payload }
|
||||
}
|
||||
Request::RefreshState =>
|
||||
{
|
||||
let payload =
|
||||
InterfaceRequest::ReadHoldingRegisters(
|
||||
ReadRegisters
|
||||
{
|
||||
start_address: HoldingRegister::OFFSET,
|
||||
quantity: HoldingRegister::COUNT as u16,
|
||||
}
|
||||
);
|
||||
|
||||
RequestData { type_id: 1, priority: 20, payload }
|
||||
}
|
||||
Request::SetRotationState(value) =>
|
||||
{
|
||||
let payload =
|
||||
InterfaceRequest::PresetHoldingRegister(
|
||||
WriteRegister
|
||||
{
|
||||
address: HoldingRegister::RunCommand as u16,
|
||||
value: *value,
|
||||
}
|
||||
);
|
||||
|
||||
RequestData { type_id: 2, priority: 100, payload }
|
||||
},
|
||||
Request::SetFrequencyTarget(value) =>
|
||||
{
|
||||
let payload =
|
||||
InterfaceRequest::PresetHoldingRegister(
|
||||
WriteRegister
|
||||
{
|
||||
address: HoldingRegister::SetFrequency as u16,
|
||||
value: *value,
|
||||
}
|
||||
);
|
||||
|
||||
RequestData { type_id: 3, priority: 50, payload }
|
||||
}
|
||||
Request::SetAccelerationLevel(value) =>
|
||||
{
|
||||
let payload =
|
||||
InterfaceRequest::PresetHoldingRegister(
|
||||
WriteRegister
|
||||
{
|
||||
address: HoldingRegister::AccelerationTime as u16,
|
||||
value: *value,
|
||||
}
|
||||
);
|
||||
|
||||
RequestData { type_id: 4, priority: 30, payload }
|
||||
},
|
||||
Request::SetDecelerationLevel(value) =>
|
||||
{
|
||||
let payload =
|
||||
InterfaceRequest::PresetHoldingRegister(
|
||||
WriteRegister
|
||||
{
|
||||
address: HoldingRegister::DecelerationTime as u16,
|
||||
value: *value,
|
||||
}
|
||||
);
|
||||
|
||||
RequestData { type_id: 5, priority: 30, payload }
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
|
||||
use anyhow::anyhow;
|
||||
use modbus::{Request, request::ReadRegisters, rtu::backends::LinuxTransport};
|
||||
use smol::lock::RwLock;
|
||||
|
||||
use control_core::{
|
||||
helpers::hashing::{byte_folding_u16, hash_djb2},
|
||||
};
|
||||
use units::{ConstZero, Frequency};
|
||||
|
||||
use super::US3202510;
|
||||
|
||||
use crate::{
|
||||
MACHINE_PELLETIZER,
|
||||
SerialDevice,
|
||||
SerialDeviceNew,
|
||||
SerialDeviceNewParams,
|
||||
VENDOR_QITECH,
|
||||
machine_identification::{
|
||||
DeviceHardwareIdentification, DeviceHardwareIdentificationSerial, DeviceIdentification, DeviceMachineIdentification, MachineIdentification, MachineIdentificationUnique
|
||||
}, serial::devices::us_3202510::{Config, ModbusInterface, request, transport::CustomTransport}
|
||||
};
|
||||
|
||||
use serialport::{DataBits, FlowControl, Parity, StopBits};
|
||||
|
||||
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
impl SerialDevice for US3202510 {}
|
||||
|
||||
impl SerialDeviceNew for US3202510
|
||||
{
|
||||
fn new_serial(
|
||||
params: &SerialDeviceNewParams,
|
||||
) -> Result<(DeviceIdentification, Arc<RwLock<Self>>), anyhow::Error>
|
||||
{
|
||||
let hash = hash_djb2(params.path.as_bytes());
|
||||
|
||||
let serial = byte_folding_u16(&hash.to_le_bytes());
|
||||
|
||||
let device_identification = DeviceIdentification {
|
||||
device_machine_identification: Some(DeviceMachineIdentification {
|
||||
machine_identification_unique: MachineIdentificationUnique {
|
||||
machine_identification: MachineIdentification {
|
||||
vendor: VENDOR_QITECH,
|
||||
machine: MACHINE_PELLETIZER,
|
||||
},
|
||||
serial,
|
||||
},
|
||||
role: 0,
|
||||
}),
|
||||
device_hardware_identification: DeviceHardwareIdentification::Serial(
|
||||
DeviceHardwareIdentificationSerial {
|
||||
path: params.path.clone(),
|
||||
},
|
||||
),
|
||||
};
|
||||
|
||||
// let interface_config = modbus_rtu::Config {
|
||||
// slave_id: 1,
|
||||
// path: params.path.clone(),
|
||||
// data_bits: DataBits::Eight,
|
||||
// parity: Parity::None,
|
||||
// stop_bits: StopBits::One,
|
||||
// flow_control: FlowControl::None,
|
||||
// timeout: Duration::from_millis(1000),
|
||||
// baudrate: 9600,
|
||||
// machine_operation_delay: Duration::from_millis(100),
|
||||
// };
|
||||
|
||||
let port =
|
||||
serialport::new(params.path.clone(), 9600)
|
||||
.data_bits(DataBits::Eight)
|
||||
.parity(Parity::None)
|
||||
.flow_control(FlowControl::None)
|
||||
.baud_rate(9600)
|
||||
.stop_bits(StopBits::One)
|
||||
.timeout(Duration::from_millis(500))
|
||||
.open()
|
||||
.expect("");
|
||||
|
||||
let transport = CustomTransport::new(port, 1);
|
||||
|
||||
let interface = ModbusInterface::new(transport);
|
||||
|
||||
// let request: [u8; 8] = [
|
||||
// 0x01, // slave id
|
||||
// 0x04, // Read Input Registers
|
||||
// 0x00, 0x08, // start address
|
||||
// 0x00, 0x06, // quantity
|
||||
// 0xB1, 0xCA, // CRC (lo, hi)
|
||||
// ];
|
||||
|
||||
|
||||
let _self = Arc::new(RwLock::new(Self {
|
||||
path: params.path.clone(),
|
||||
config: Config {
|
||||
running: false,
|
||||
direction: true,
|
||||
frequency_target: 0,
|
||||
frequency_max: 50,
|
||||
frequency_min: 0,
|
||||
acceleration_level: 7,
|
||||
deceleration_level: 7,
|
||||
snapshot_id: 0,
|
||||
},
|
||||
status: None,
|
||||
failed_attempts: 0,
|
||||
interface,
|
||||
}));
|
||||
|
||||
Ok((device_identification, _self))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
use std::io;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use modbus::WithContext;
|
||||
use modbus::rtu::{FrameParseError, Transport as TransportTrait};
|
||||
use modbus::rtu::{DispatchError, ReceiveError};
|
||||
use modbus::rtu::Frame;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CustomTransport
|
||||
{
|
||||
port: std::sync::Mutex<Box<dyn serialport::SerialPort>>,
|
||||
slave_id: u8,
|
||||
}
|
||||
|
||||
// #[derive(Debug, Clone, PartialEq)]
|
||||
// pub struct EntryContext
|
||||
// {
|
||||
// type_id: u32
|
||||
// }
|
||||
|
||||
pub type EntryContext = u32;
|
||||
|
||||
impl CustomTransport
|
||||
{
|
||||
pub fn new(port: Box<dyn serialport::SerialPort>, slave_id: u8) -> Self
|
||||
{
|
||||
let p = std::sync::Mutex::new(port);
|
||||
|
||||
Self { port: p ,slave_id }
|
||||
}
|
||||
}
|
||||
|
||||
// implement InterfaceTransport for your RTU frames
|
||||
impl TransportTrait<EntryContext> for CustomTransport
|
||||
{
|
||||
type Error = io::Error;
|
||||
|
||||
fn slave_id(&self) -> u8 { self.slave_id }
|
||||
|
||||
fn try_send(
|
||||
&mut self,
|
||||
item: WithContext<Frame, EntryContext>
|
||||
) -> Result<(), DispatchError<Self::Error>>
|
||||
{
|
||||
let mut port = self.port.lock().unwrap();
|
||||
|
||||
match port.write_all(item.payload.bytes())
|
||||
{
|
||||
Ok(_) => {},
|
||||
Err(e) =>
|
||||
{
|
||||
tracing::error!("Error: try_send: {:?}", e);
|
||||
|
||||
return Err(DispatchError::BridgeDropped);
|
||||
},
|
||||
}
|
||||
|
||||
match port.flush()
|
||||
{
|
||||
Ok(_) => {},
|
||||
Err(e) =>
|
||||
{
|
||||
tracing::error!("Error: try_send: {:?}", e);
|
||||
|
||||
return Err(DispatchError::BridgeDropped);
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_recv(
|
||||
&mut self
|
||||
) -> Result<Option<Frame>, ReceiveError<Self::Error>>
|
||||
{
|
||||
let mut port = self.port.lock().unwrap();
|
||||
|
||||
let mut buf = [0u8; 256];
|
||||
match port.read(&mut buf)
|
||||
{
|
||||
Ok(0) => Ok(None),
|
||||
Ok(n) =>
|
||||
{
|
||||
match Frame::from_bytes(&buf[..n])
|
||||
{
|
||||
Ok(frame) => Ok(Some(frame)),
|
||||
Err(e) =>
|
||||
{
|
||||
Err(ReceiveError::ParseError(e))
|
||||
},
|
||||
}
|
||||
}
|
||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
|
||||
Err(e) => Err(ReceiveError::Transport(e)),
|
||||
}
|
||||
}
|
||||
|
||||
fn send(
|
||||
&mut self,
|
||||
item: WithContext<Frame, EntryContext>
|
||||
) -> Result<(), DispatchError<Self::Error>>
|
||||
{
|
||||
let mut port = self.port.lock().unwrap();
|
||||
|
||||
match port.write_all(item.payload.bytes())
|
||||
{
|
||||
Ok(_) => {},
|
||||
Err(e) =>
|
||||
{
|
||||
tracing::error!("Error: try_send: {:?}", e);
|
||||
},
|
||||
}
|
||||
|
||||
match port.flush()
|
||||
{
|
||||
Ok(_) => {},
|
||||
Err(e) =>
|
||||
{
|
||||
tracing::error!("Error: try_send: {:?}", e);
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn recv(&mut self) -> Result<Frame, ReceiveError<Self::Error>>
|
||||
{
|
||||
let mut port = self.port.lock().unwrap();
|
||||
|
||||
let mut buf = [0u8; 256];
|
||||
let mut pos = 0;
|
||||
|
||||
let mut now: Instant = Instant::now();
|
||||
let timeout = Duration::from_secs(1);
|
||||
|
||||
loop
|
||||
{
|
||||
match port.read(&mut buf[pos..])
|
||||
{
|
||||
Ok(0) =>
|
||||
{
|
||||
return Err(ReceiveError::ParseError(FrameParseError::TooSmall(0)));
|
||||
}
|
||||
Ok(n) =>
|
||||
{
|
||||
pos += n;
|
||||
|
||||
if let Ok(frame) = Frame::from_bytes(&buf[..pos])
|
||||
{
|
||||
return Ok(frame);
|
||||
}
|
||||
|
||||
now = Instant::now(); // reset timeout timer
|
||||
}
|
||||
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock =>
|
||||
{
|
||||
if now.elapsed() >= timeout
|
||||
{
|
||||
if pos > 0
|
||||
{
|
||||
match Frame::from_bytes(&buf[..pos])
|
||||
{
|
||||
Ok(frame) => { return Ok(frame); },
|
||||
Err(e) => { return Err(ReceiveError::ParseError(e)); },
|
||||
}
|
||||
}
|
||||
|
||||
return Err(ReceiveError::Timeout);
|
||||
}
|
||||
|
||||
std::thread::sleep(Duration::from_millis(150));
|
||||
}
|
||||
Err(e) => return Err(ReceiveError::Transport(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ use lazy_static::lazy_static;
|
||||
use crate::{
|
||||
SerialDevice, SerialDeviceIdentification, machine_identification::DeviceIdentification,
|
||||
serial::devices::laser::Laser,
|
||||
serial::devices::us_3202510::US3202510,
|
||||
};
|
||||
|
||||
#[cfg(feature = "mock-machine")]
|
||||
@@ -109,6 +110,11 @@ lazy_static! {
|
||||
product_id: 0x6001,
|
||||
});
|
||||
|
||||
sdr.register::<US3202510>(SerialDeviceIdentification {
|
||||
vendor_id: 0x0403,
|
||||
product_id: 0x6001,
|
||||
});
|
||||
|
||||
// Register MockSerialDevice when mock-machine feature is enabled
|
||||
#[cfg(feature = "mock-machine")]
|
||||
sdr.register::<MockSerialDevice>(SerialDeviceIdentification {
|
||||
|
||||
@@ -10,7 +10,7 @@ buildNpmPackage rec {
|
||||
ELECTRON_SKIP_BINARY_DOWNLOAD = 1;
|
||||
|
||||
makeCacheWritable = true;
|
||||
npmDepsHash = "sha256-UHPIoyMTzr7jkvbpZsePaNJ6s76h3R/0pcnbCkOcdYo=";
|
||||
npmDepsHash = "sha256-wzVjsgcZsViPOyQKlKTb5gJIeY416KyCSiheSXSRZoc=";
|
||||
npmFlags = [ "--no-audit" "--no-fund" ];
|
||||
|
||||
installPhase = ''
|
||||
|
||||
@@ -17,7 +17,7 @@ pub async fn find_ethercat_interface() -> String {
|
||||
return interface;
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!("No working interface found: {}. Retrying...", e);
|
||||
// tracing::warn!("No working interface found: {}. Retrying...", e);
|
||||
Timer::after(Duration::from_secs(1)).await;
|
||||
}
|
||||
}
|
||||
|
||||
+13
-18
@@ -3,16 +3,9 @@ use crate::{
|
||||
socketio::main_namespace::machines_event::MachineObj,
|
||||
};
|
||||
use machines::{
|
||||
AsyncThreadMessage, MachineConnection, MachineNewHardware, MachineNewHardwareSerial,
|
||||
MachineNewParams, SerialDevice, SerialDeviceIdentification, SerialDeviceNew,
|
||||
SerialDeviceNewParams,
|
||||
laser::LaserMachine,
|
||||
machine_identification::{
|
||||
AsyncThreadMessage, MachineConnection, MachineNewHardware, MachineNewHardwareSerial, MachineNewParams, SerialDevice, SerialDeviceIdentification, SerialDeviceNew, SerialDeviceNewParams, laser::LaserMachine, machine_identification::{
|
||||
DeviceIdentification, DeviceIdentificationIdentified, MachineIdentificationUnique,
|
||||
},
|
||||
registry::{MACHINE_REGISTRY, MachineRegistry},
|
||||
serial::{devices::laser::Laser, init::SerialDetection},
|
||||
winder2::api::GenericEvent,
|
||||
}, pelletizer::Pelletizer, registry::{MACHINE_REGISTRY, MachineRegistry}, serial::{devices::{laser::Laser, us_3202510::US3202510}, init::SerialDetection}, winder2::api::GenericEvent
|
||||
};
|
||||
#[cfg(feature = "development-build")]
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
@@ -164,19 +157,20 @@ pub async fn handle_serial_device_hotplug(
|
||||
app_state: Arc<SharedState>,
|
||||
map: HashMap<String, UsbPortInfo>,
|
||||
) {
|
||||
let laser_ident = SerialDeviceIdentification {
|
||||
// IDENTIFIER OF THE USB DEVICE, NOT THE ACTUAL DEVICE
|
||||
let usb_interface_id = SerialDeviceIdentification {
|
||||
vendor_id: 0x0403,
|
||||
product_id: 0x6001,
|
||||
};
|
||||
|
||||
let laser = SerialDetection::get_path_by_id(laser_ident, map);
|
||||
let path = SerialDetection::get_path_by_id(usb_interface_id, map);
|
||||
let mut unique_ident: Option<MachineIdentificationUnique> = None;
|
||||
|
||||
{
|
||||
let machines = app_state.current_machines_meta.lock().await;
|
||||
for machine in machines.iter() {
|
||||
if machine.machine_identification_unique.machine_identification
|
||||
== LaserMachine::MACHINE_IDENTIFICATION
|
||||
for machine in machines.iter()
|
||||
{
|
||||
if machine.machine_identification_unique.machine_identification == Pelletizer::MACHINE_IDENTIFICATION
|
||||
{
|
||||
unique_ident = Some(machine.machine_identification_unique.clone());
|
||||
break;
|
||||
@@ -185,11 +179,12 @@ pub async fn handle_serial_device_hotplug(
|
||||
}
|
||||
|
||||
// Machine isnt connected, so add it back
|
||||
if laser.is_some() && unique_ident.is_none() {
|
||||
if path.is_some() && unique_ident.is_none() {
|
||||
let serial_params = SerialDeviceNewParams {
|
||||
path: laser.unwrap(),
|
||||
path: path.unwrap(),
|
||||
};
|
||||
match Laser::new_serial(&serial_params) {
|
||||
|
||||
match US3202510::new_serial(&serial_params) {
|
||||
Ok((device_identification, serial_device)) => {
|
||||
add_serial_device(
|
||||
app_state.clone(),
|
||||
@@ -202,7 +197,7 @@ pub async fn handle_serial_device_hotplug(
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
} else if laser.is_none() && unique_ident.is_some() {
|
||||
} else if path.is_none() && unique_ident.is_some() {
|
||||
let unique_ident = unique_ident.unwrap();
|
||||
app_state
|
||||
.clone()
|
||||
|
||||
Reference in new issue
Block a user