aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2024-01-03 21:57:27 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2024-01-03 21:57:27 +0100
commitc2742cde3d034b2af9bbcee90765338ee094e6cc (patch)
treec35399d5d52725efbf3ebaaee83752574bf2ba1c
parent43201470d4092f54c176dd5ebd2d7b0bbf15192e (diff)
downloadcats-radio-node-c2742cde3d034b2af9bbcee90765338ee094e6cc.tar.gz
cats-radio-node-c2742cde3d034b2af9bbcee90765338ee094e6cc.tar.bz2
cats-radio-node-c2742cde3d034b2af9bbcee90765338ee094e6cc.zip
Add src/radio and freq config
-rw-r--r--Cargo.lock674
-rw-r--r--Cargo.toml7
-rw-r--r--src/config.rs2
-rw-r--r--src/main.rs64
-rw-r--r--src/radio.rs161
-rw-r--r--src/ui.rs24
-rw-r--r--static/style.css2
-rw-r--r--templates/settings.html1
8 files changed, 850 insertions, 85 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 27a6889..6fd1f8d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -38,9 +38,15 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
name = "anyhow"
-version = "1.0.78"
+version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca87830a3e3fb156dc96cfbd31cb620265dd053be734723f22b760d6cc3c3051"
+checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "askama"
@@ -62,8 +68,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a41603f7cdbf5ac4af60760f17253eb6adf6ec5b6f14a7ed830cf687d375f163"
dependencies = [
"askama",
- "axum-core",
- "http",
+ "axum-core 0.4.2",
+ "http 1.0.0",
]
[[package]]
@@ -79,7 +85,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde",
- "syn 2.0.45",
+ "syn 2.0.46",
]
[[package]]
@@ -98,14 +104,57 @@ dependencies = [
]
[[package]]
+name = "async-stream"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22068c0c19514942eefcfd4daf8976ef1aad84e61539f95cd200c35202f80af5"
+dependencies = [
+ "async-stream-impl 0.2.1",
+ "futures-core",
+]
+
+[[package]]
+name = "async-stream"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51"
+dependencies = [
+ "async-stream-impl 0.3.5",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-stream-impl"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25f9db3b38af870bf7e5cc649167533b493928e50744e2c30ae350230b414670"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "async-stream-impl"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.46",
+]
+
+[[package]]
name = "async-trait"
-version = "0.1.76"
+version = "0.1.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514"
+checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.45",
+ "syn 2.0.46",
]
[[package]]
@@ -135,18 +184,46 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "axum"
+version = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
+dependencies = [
+ "async-trait",
+ "axum-core 0.3.4",
+ "bitflags 1.3.2",
+ "bytes",
+ "futures-util",
+ "http 0.2.11",
+ "http-body 0.4.6",
+ "hyper 0.14.28",
+ "itoa",
+ "matchit",
+ "memchr",
+ "mime",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustversion",
+ "serde",
+ "sync_wrapper",
+ "tower",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "axum"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d09dbe0e490df5da9d69b36dca48a76635288a82f92eca90024883a56202026d"
dependencies = [
"async-trait",
- "axum-core",
+ "axum-core 0.4.2",
"bytes",
"futures-util",
- "http",
- "http-body",
+ "http 1.0.0",
+ "http-body 1.0.0",
"http-body-util",
- "hyper",
+ "hyper 1.1.0",
"hyper-util",
"itoa",
"matchit",
@@ -169,6 +246,23 @@ dependencies = [
[[package]]
name = "axum-core"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c"
+dependencies = [
+ "async-trait",
+ "bytes",
+ "futures-util",
+ "http 0.2.11",
+ "http-body 0.4.6",
+ "mime",
+ "rustversion",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "axum-core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e87c8503f93e6d144ee5690907ba22db7ba79ab001a932ab99034f0fe836b3df"
@@ -176,8 +270,8 @@ dependencies = [
"async-trait",
"bytes",
"futures-util",
- "http",
- "http-body",
+ "http 1.0.0",
+ "http-body 1.0.0",
"http-body-util",
"mime",
"pin-project-lite",
@@ -217,9 +311,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "basic-toml"
-version = "0.1.7"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f2139706359229bfa8f19142ac1155b4b80beafb7a60471ac5dd109d4a19778"
+checksum = "2db21524cad41c5591204d22d75e1970a2d1f71060214ca931dc7d5afe2c14e5"
dependencies = [
"serde",
]
@@ -240,6 +334,18 @@ dependencies = [
]
[[package]]
+name = "bitvec"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
+[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -267,13 +373,19 @@ dependencies = [
"anyhow",
"askama",
"askama_axum",
- "axum",
+ "async-stream 0.2.1",
+ "axum 0.7.3",
+ "ham-cats",
"log",
+ "rand",
+ "rf4463",
+ "rppal",
"serde",
"simple_logger",
"sqlx",
"tokio",
"toml",
+ "tonic",
"tower-http",
]
@@ -309,6 +421,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+
+[[package]]
name = "cpufeatures"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -352,6 +480,12 @@ dependencies = [
]
[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -394,6 +528,12 @@ dependencies = [
]
[[package]]
+name = "doc-comment"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
+
+[[package]]
name = "dotenvy"
version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -409,6 +549,41 @@ dependencies = [
]
[[package]]
+name = "embedded-hal"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
+dependencies = [
+ "nb 0.1.3",
+ "void",
+]
+
+[[package]]
+name = "embedded-hal"
+version = "1.0.0-alpha.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "129b101ddfee640565f7c07b301a31d95aa21e5acef21a491c307139f5fa4c91"
+
+[[package]]
+name = "embedded-hal-nb"
+version = "1.0.0-alpha.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e0760ec0a3bf76859d5e33f39542af103f157d5b2ecfb00ace56dd461472e3a"
+dependencies = [
+ "embedded-hal 1.0.0-alpha.9",
+ "nb 1.1.0",
+]
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -480,6 +655,12 @@ dependencies = [
]
[[package]]
+name = "funty"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+
+[[package]]
name = "futures-channel"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -580,6 +761,25 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "h2"
+version = "0.3.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http 0.2.11",
+ "indexmap 2.1.0",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "h2"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d308f63daf4181410c242d34c11f928dcb3aa105852019e043c9d1f4e4368a"
@@ -589,8 +789,8 @@ dependencies = [
"futures-core",
"futures-sink",
"futures-util",
- "http",
- "indexmap",
+ "http 1.0.0",
+ "indexmap 2.1.0",
"slab",
"tokio",
"tokio-util",
@@ -598,6 +798,37 @@ dependencies = [
]
[[package]]
+name = "half"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872"
+dependencies = [
+ "cfg-if",
+ "crunchy",
+]
+
+[[package]]
+name = "ham-cats"
+version = "0.2.0"
+source = "git+https://gitlab.scd31.com/cats/ham-cats#d22f541c9a7e1c3a6c6e9449d87212b060f5edfb"
+dependencies = [
+ "arrayvec",
+ "bitvec",
+ "crc",
+ "encoding_rs",
+ "half",
+ "labrador-ldpc",
+ "paste",
+ "snafu",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -613,7 +844,7 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7"
dependencies = [
- "hashbrown",
+ "hashbrown 0.14.3",
]
[[package]]
@@ -666,6 +897,17 @@ dependencies = [
[[package]]
name = "http"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea"
@@ -677,12 +919,23 @@ dependencies = [
[[package]]
name = "http-body"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
+dependencies = [
+ "bytes",
+ "http 0.2.11",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "http-body"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
dependencies = [
"bytes",
- "http",
+ "http 1.0.0",
]
[[package]]
@@ -693,8 +946,8 @@ checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840"
dependencies = [
"bytes",
"futures-util",
- "http",
- "http-body",
+ "http 1.0.0",
+ "http-body 1.0.0",
"pin-project-lite",
]
@@ -727,6 +980,30 @@ dependencies = [
[[package]]
name = "hyper"
+version = "0.14.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2 0.3.22",
+ "http 0.2.11",
+ "http-body 0.4.6",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "hyper"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5aa53871fc917b1a9ed87b683a5d86db645e23acb32c2e0785a353e522fb75"
@@ -734,9 +1011,9 @@ dependencies = [
"bytes",
"futures-channel",
"futures-util",
- "h2",
- "http",
- "http-body",
+ "h2 0.4.0",
+ "http 1.0.0",
+ "http-body 1.0.0",
"httparse",
"httpdate",
"itoa",
@@ -745,6 +1022,18 @@ dependencies = [
]
[[package]]
+name = "hyper-timeout"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1"
+dependencies = [
+ "hyper 0.14.28",
+ "pin-project-lite",
+ "tokio",
+ "tokio-io-timeout",
+]
+
+[[package]]
name = "hyper-util"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -753,9 +1042,9 @@ dependencies = [
"bytes",
"futures-channel",
"futures-util",
- "http",
- "http-body",
- "hyper",
+ "http 1.0.0",
+ "http-body 1.0.0",
+ "hyper 1.1.0",
"pin-project-lite",
"socket2",
"tokio",
@@ -774,12 +1063,22 @@ dependencies = [
[[package]]
name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown 0.12.3",
+]
+
+[[package]]
+name = "indexmap"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
dependencies = [
"equivalent",
- "hashbrown",
+ "hashbrown 0.14.3",
]
[[package]]
@@ -798,6 +1097,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
+name = "labrador-ldpc"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23c19ea22fc166b77441be6ea377e5aa20121490cdec0af18a14356d390f45b5"
+
+[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -916,6 +1221,21 @@ dependencies = [
]
[[package]]
+name = "nb"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
+dependencies = [
+ "nb 1.1.0",
+]
+
+[[package]]
+name = "nb"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
+
+[[package]]
name = "nix"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1019,6 +1339,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
+name = "openssl-probe"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+
+[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1079,7 +1405,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.45",
+ "syn 2.0.46",
]
[[package]]
@@ -1135,23 +1461,38 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
-version = "1.0.73"
+version = "1.0.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dd5e8a1f1029c43224ad5898e50140c2aebb1705f19e67c918ebf5b9e797fe1"
+checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db"
dependencies = [
"unicode-ident",
]
[[package]]
+name = "prost"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a"
+dependencies = [
+ "bytes",
+]
+
+[[package]]
name = "quote"
-version = "1.0.34"
+version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22a37c9326af5ed140c86a46655b5278de879853be5573c01df185b6f49a580a"
+checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
[[package]]
+name = "radium"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+
+[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1191,6 +1532,14 @@ dependencies = [
]
[[package]]
+name = "rf4463"
+version = "0.1.0"
+source = "git+https://gitlab.scd31.com/stephen/rf4463-lib#79c8def87540f8ab2663bfa3c9fb13db344ef84e"
+dependencies = [
+ "embedded-hal 0.2.7",
+]
+
+[[package]]
name = "ring"
version = "0.17.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1205,6 +1554,21 @@ dependencies = [
]
[[package]]
+name = "rppal"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "612e1a22e21f08a246657c6433fe52b773ae43d07c9ef88ccfc433cc8683caba"
+dependencies = [
+ "embedded-hal 0.2.7",
+ "embedded-hal 1.0.0-alpha.9",
+ "embedded-hal-nb",
+ "libc",
+ "nb 0.1.3",
+ "spin_sleep",
+ "void",
+]
+
+[[package]]
name = "rsa"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1249,12 +1613,25 @@ version = "0.21.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
dependencies = [
+ "log",
"ring",
"rustls-webpki",
"sct",
]
[[package]]
+name = "rustls-native-certs"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
+dependencies = [
+ "openssl-probe",
+ "rustls-pemfile",
+ "schannel",
+ "security-framework",
+]
+
+[[package]]
name = "rustls-pemfile"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1286,6 +1663,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
[[package]]
+name = "schannel"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
+dependencies = [
+ "windows-sys 0.52.0",
+]
+
+[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1302,30 +1688,53 @@ dependencies = [
]
[[package]]
+name = "security-framework"
+version = "2.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
name = "serde"
-version = "1.0.193"
+version = "1.0.194"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
+checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.193"
+version = "1.0.194"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
+checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.45",
+ "syn 2.0.46",
]
[[package]]
name = "serde_json"
-version = "1.0.109"
+version = "1.0.110"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9"
+checksum = "6fbd975230bada99c8bb618e0c365c2eefa219158d5c6c29610fd09ff1833257"
dependencies = [
"itoa",
"ryu",
@@ -1334,9 +1743,9 @@ dependencies = [
[[package]]
name = "serde_path_to_error"
-version = "0.1.14"
+version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335"
+checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c"
dependencies = [
"itoa",
"serde",
@@ -1432,6 +1841,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
[[package]]
+name = "snafu"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6"
+dependencies = [
+ "doc-comment",
+ "snafu-derive",
+]
+
+[[package]]
+name = "snafu-derive"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
name = "socket2"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1457,6 +1888,16 @@ dependencies = [
]
[[package]]
+name = "spin_sleep"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cafa7900db085f4354dbc7025e25d7a839a14360ea13b5fc4fd717f2d3b23134"
+dependencies = [
+ "once_cell",
+ "winapi",
+]
+
+[[package]]
name = "spki"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1512,7 +1953,7 @@ dependencies = [
"futures-util",
"hashlink",
"hex",
- "indexmap",
+ "indexmap 2.1.0",
"log",
"memchr",
"once_cell",
@@ -1706,9 +2147,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.45"
+version = "2.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eae3c679c56dc214320b67a1bc04ef3dfbd6411f6443974b5e4893231298e66"
+checksum = "89456b690ff72fddcecf231caedbe615c59480c93358a93dfae7fc29e3ebbf0e"
dependencies = [
"proc-macro2",
"quote",
@@ -1722,6 +2163,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
+[[package]]
name = "tempfile"
version = "3.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1736,22 +2183,22 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "1.0.53"
+version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2cd5904763bad08ad5513ddbb12cf2ae273ca53fa9f68e843e236ec6dfccc09"
+checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.53"
+version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19"
+checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.45",
+ "syn 2.0.46",
]
[[package]]
@@ -1820,6 +2267,16 @@ dependencies = [
]
[[package]]
+name = "tokio-io-timeout"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf"
+dependencies = [
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
name = "tokio-macros"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1827,7 +2284,17 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.45",
+ "syn 2.0.46",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
+dependencies = [
+ "rustls",
+ "tokio",
]
[[package]]
@@ -1882,7 +2349,7 @@ version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
dependencies = [
- "indexmap",
+ "indexmap 2.1.0",
"serde",
"serde_spanned",
"toml_datetime",
@@ -1890,6 +2357,37 @@ dependencies = [
]
[[package]]
+name = "tonic"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e"
+dependencies = [
+ "async-stream 0.3.5",
+ "async-trait",
+ "axum 0.6.20",
+ "base64",
+ "bytes",
+ "h2 0.3.22",
+ "http 0.2.11",
+ "http-body 0.4.6",
+ "hyper 0.14.28",
+ "hyper-timeout",
+ "percent-encoding",
+ "pin-project",
+ "prost",
+ "rustls",
+ "rustls-native-certs",
+ "rustls-pemfile",
+ "tokio",
+ "tokio-rustls",
+ "tokio-stream",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
name = "tower"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1897,9 +2395,13 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
dependencies = [
"futures-core",
"futures-util",
+ "indexmap 1.9.3",
"pin-project",
"pin-project-lite",
+ "rand",
+ "slab",
"tokio",
+ "tokio-util",
"tower-layer",
"tower-service",
"tracing",
@@ -1914,8 +2416,8 @@ dependencies = [
"bitflags 2.4.1",
"bytes",
"futures-util",
- "http",
- "http-body",
+ "http 1.0.0",
+ "http-body 1.0.0",
"http-body-util",
"http-range-header",
"httpdate",
@@ -1962,7 +2464,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.45",
+ "syn 2.0.46",
]
[[package]]
@@ -1975,6 +2477,12 @@ dependencies = [
]
[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2058,6 +2566,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2076,6 +2599,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50"
[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2209,14 +2754,23 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "winnow"
-version = "0.5.31"
+version = "0.5.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c"
+checksum = "8434aeec7b290e8da5c3f0d628cb0eac6cabcb31d14bb74f779a08109a5914d6"
dependencies = [
"memchr",
]
[[package]]
+name = "wyz"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
+dependencies = [
+ "tap",
+]
+
+[[package]]
name = "zerocopy"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2233,7 +2787,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.45",
+ "syn 2.0.46",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 91fb20d..452c41e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,5 +18,12 @@ sqlx = { version = "0.7", features = [ "runtime-tokio-rustls", "sqlite"]}
tokio = { version = "1", features = ["full"] }
tower-http = { version = "0.5.0", features = ["fs"] }
+ham-cats = { git = "https://gitlab.scd31.com/cats/ham-cats", commit = "d22f541c9a7e1c3a6c6e9449d87212b060f5edfb" }
+rf4463 = { git = "https://gitlab.scd31.com/stephen/rf4463-lib", commit = "79c8def87540f8ab2663bfa3c9fb13db344ef84e" }
+rppal = { version = "0.14", features = ["hal"] }
+tonic = { version = "0.10", features = ["tls", "tls-roots"] }
+async-stream = "0.2"
+rand = "0.8"
+
# Websockets example in https://github.com/tokio-rs/axum/tree/main/examples/websockets
# tokio-tungstenite = "0.21"
diff --git a/src/config.rs b/src/config.rs
index d54e01a..7700b45 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -69,6 +69,7 @@ impl Default for BeaconConfig {
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Config {
+ pub freq: u32, // kHz
pub callsign: String,
pub ssid: u8,
#[serde(default)]
@@ -81,6 +82,7 @@ pub struct Config {
impl Default for Config {
fn default() -> Self {
Config {
+ freq: 430500,
callsign: "CHANGEME".to_owned(),
ssid: 0,
icon: 0,
diff --git a/src/main.rs b/src/main.rs
index 20fedf6..9a4ae2b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,11 @@
+use anyhow::Context;
+use log::{debug, info, warn, error};
use std::sync::{Arc, Mutex};
+use tokio::sync::mpsc;
use sqlx::{Connection, SqliteConnection};
+use radio::{RadioManager, MAX_PACKET_LEN};
+mod radio;
mod config;
mod ui;
@@ -13,8 +18,7 @@ type SharedState = Arc<Mutex<AppState>>;
#[tokio::main]
async fn main() -> std::io::Result<()> {
-
- // simple_logger::
+ simple_logger::SimpleLogger::new().env().init().unwrap();
let mut conn = SqliteConnection::connect("sqlite:cats-radio-node.db").await.unwrap();
sqlx::migrate!()
@@ -24,12 +28,66 @@ async fn main() -> std::io::Result<()> {
let conf = config::Config::load().expect("Could not load config");
+ if conf.freq == 0 {
+ warn!("Frequency {0} is zero, disabling radio", conf.freq);
+ }
+ else if !(430000..=436380).contains(&conf.freq) {
+ error!("Frequency {} kHz out of range (430MHz - 436.375MHz), skipping radio setup", conf.freq);
+ }
+ else {
+ info!("Setting up radio");
+ let (packet_tx, mut packet_receive) = mpsc::channel(16);
+ let (packet_send, packet_rx) = mpsc::channel(16);
+ let mut radio = RadioManager::new(packet_tx, packet_rx).expect("Could not initialize radio");
+
+ let channel = ((conf.freq - 430000) / 25) as u8;
+ radio.set_channel(channel);
+ let actual_freq = 430000 + 25 * channel as u32;
+ info!("Setting up radio on {actual_freq} kHz...");
+
+ tokio::task::spawn(async move {
+ loop {
+ if let Err(e) = radio.process_forever().await {
+ error!("Radio error: {e}")
+ }
+ }
+ });
+
+ tokio::task::spawn(async move {
+ loop {
+ match packet_receive
+ .recv()
+ .await
+ .context("Packet receive channel died") {
+ Ok((packet, rssi)) => {
+ debug!("RX RSSI {} len {}", rssi, packet.len());
+ let mut buf = [0; MAX_PACKET_LEN];
+ match ham_cats::packet::Packet::fully_decode(&packet, &mut buf) {
+ Ok(packet) => {
+ if let Some(ident) = packet.identification() {
+ debug!(" From {}-{}", ident.callsign, ident.ssid);
+ }
+ // TODO save to db
+ }
+ Err(e) => {
+ warn!("Failed to decode packet: {}", e);
+ }
+ }
+ },
+ Err(e) => warn!("Failed to decode packet: {}", e),
+ }
+ }
+ });
+ }
+
let shared_state = Arc::new(Mutex::new(AppState {
conf,
db: Mutex::new(conn)
}));
- ui::serve(3000, shared_state).await;
+ let port = 3000;
+ info!("Setting up listener on port {port}");
+ ui::serve(port, shared_state).await;
Ok(())
}
diff --git a/src/radio.rs b/src/radio.rs
new file mode 100644
index 0000000..77f7c0f
--- /dev/null
+++ b/src/radio.rs
@@ -0,0 +1,161 @@
+use anyhow::{anyhow, bail, Context};
+use rand::{thread_rng, Rng};
+use rf4463::{config::RADIO_CONFIG_CATS, Rf4463};
+use rppal::{
+ gpio::{Gpio, OutputPin},
+ hal::Delay,
+ spi::{Bus, Mode, SlaveSelect, Spi},
+};
+use std::{
+ sync::Arc,
+ time::{Duration, Instant},
+};
+use tokio::sync::{
+ mpsc::{error::TryRecvError, Receiver, Sender},
+ Mutex,
+};
+
+pub const MAX_PACKET_LEN: usize = 8191;
+
+pub struct RadioManager {
+ radio: Rf4463<Spi, OutputPin, OutputPin, Delay>,
+
+ tx: Sender<(Vec<u8>, f64)>,
+ rx: Receiver<Vec<u8>>,
+ rx_buf: [u8; MAX_PACKET_LEN],
+ temperature: Arc<Mutex<f32>>,
+}
+
+impl RadioManager {
+ pub fn new(tx: Sender<(Vec<u8>, f64)>, rx: Receiver<Vec<u8>>) -> anyhow::Result<Self> {
+ let spi = Spi::new(Bus::Spi0, SlaveSelect::Ss0, 1_000_000, Mode::Mode0)?;
+ let gpio = Gpio::new()?;
+ let sdn = gpio.get(22)?.into_output();
+ let cs = gpio.get(24)?.into_output();
+
+ let delay = Delay::new();
+
+ let mut radio = Rf4463::new(spi, sdn, cs, delay, &mut RADIO_CONFIG_CATS.clone())
+ .map_err(|e| anyhow!("{e:?}"))?;
+ radio.set_channel(20);
+
+ let rx_buf = [0; MAX_PACKET_LEN];
+ let temperature = Arc::new(Mutex::new(radio.get_temp()?));
+
+ Ok(Self {
+ radio,
+ tx,
+ rx,
+ rx_buf,
+ temperature,
+ })
+ }
+
+ pub fn set_channel(&mut self, channel: u8) {
+ self.radio.set_channel(channel);
+ }
+
+ pub fn temperature_mutex(&self) -> Arc<Mutex<f32>> {
+ self.temperature.clone()
+ }
+
+ pub async fn process_forever(&mut self) -> anyhow::Result<()> {
+ loop {
+ self.tick().await?;
+
+ *self.temperature.lock().await = self.radio.get_temp()?;
+
+ match self.rx.try_recv() {
+ Ok(pkt) => {
+ self.tx(&pkt).await?;
+ }
+ Err(TryRecvError::Empty) => {}
+ Err(TryRecvError::Disconnected) => {
+ bail!("RX channel disconnected")
+ }
+ }
+
+ tokio::time::sleep(Duration::from_millis(25)).await;
+ }
+ }
+
+ async fn tick(&mut self) -> anyhow::Result<()> {
+ if self.radio.is_idle() {
+ self.radio
+ .start_rx(None, false)
+ .map_err(|e| anyhow!("{e}"))?;
+
+ tokio::time::sleep(Duration::from_millis(25)).await;
+ }
+
+ self.radio
+ .interrupt(Some(&mut self.rx_buf), None)
+ .map_err(|e| anyhow!("{e:?}"))?;
+
+ if let Some(data) = self
+ .radio
+ .finish_rx(&mut self.rx_buf)
+ .map_err(|e| anyhow!("{e}"))?
+ {
+ self.radio
+ .start_rx(None, false)
+ .map_err(|e| anyhow!("{e}"))?;
+
+ self.tx
+ .send((data.data().to_vec(), data.rssi()))
+ .await
+ .ok()
+ .context("TX channel died")?;
+ }
+
+ Ok(())
+ }
+
+ async fn tx(&mut self, data: &[u8]) -> anyhow::Result<()> {
+ // ensures we don't tx over a packet,
+ // and adds some random delay so that every node
+ // if offset slightly
+ self.tx_delay().await?;
+
+ self.radio.start_tx(data).map_err(|e| anyhow!("{e:?}"))?;
+
+ const TIMEOUT: Duration = Duration::from_secs(10);
+ let start_time = Instant::now();
+ while !self.radio.is_idle() {
+ self.radio
+ .interrupt(None, Some(data))
+ .map_err(|e| anyhow!("{e:?}"))?;
+
+ if start_time + TIMEOUT < Instant::now() {
+ bail!("Timeout while transmitting");
+ }
+
+ tokio::time::sleep(Duration::from_millis(25)).await;
+ }
+
+ Ok(())
+ }
+
+ async fn tx_delay(&mut self) -> anyhow::Result<()> {
+ loop {
+ let delay_ms = thread_rng().gen_range(0..50);
+
+ // since delay_ms < 100 we can safely sleep without calling tick
+ tokio::time::sleep(Duration::from_millis(delay_ms)).await;
+
+ let mut rx = false;
+
+ while self.radio.is_busy_rxing()? {
+ rx = true;
+ self.tick().await?;
+
+ tokio::time::sleep(Duration::from_millis(25)).await;
+ }
+
+ if !rx {
+ // didn't rx a packet, so we're safe to leave
+ break Ok(());
+ }
+ }
+ }
+}
diff --git a/src/ui.rs b/src/ui.rs
index aebcd4a..5a13bc0 100644
--- a/src/ui.rs
+++ b/src/ui.rs
@@ -21,27 +21,7 @@ pub async fn serve(port: u16, shared_state: SharedState) {
.route("/send", get(send))
.route("/settings", get(show_settings).post(post_settings))
.nest_service("/static", ServeDir::new("static"))
- /* requires tracing and tower, e.g.
- * tower = { version = "0.4", features = ["util", "timeout"] }
- * tower-http = { version = "0.5.0", features = ["add-extension", "trace"] }
- * tracing = "0.1"
- * tracing-subscriber = { version = "0.3", features = ["env-filter"] }
- .layer(
- ServiceBuilder::new()
- .layer(HandleErrorLayer::new(|error: BoxError| async move {
- ,if error.is::<tower::timeout::error::Elapsed>() {
- Ok(StatusCode::REQUEST_TIMEOUT)
- } else {
- Err((
- StatusCode::INTERNAL_SERVER_ERROR,
- format!("Unhandled internal error: {error}"),
- ))
- }
- }))
- .timeout(Duration::from_secs(10))
- .layer(TraceLayer::new_for_http())
- .into_inner(),
- )*/
+ /* For an example for timeouts and tracing, have a look at the git history */
.with_state(shared_state);
let listener = tokio::net::TcpListener::bind(("0.0.0.0", port)).await.unwrap();
@@ -122,6 +102,7 @@ async fn show_settings(State(state): State<SharedState>) -> SettingsTemplate<'st
#[derive(Deserialize, Debug)]
struct FormConfig {
+ freq: String,
callsign: String,
ssid: String,
icon: String,
@@ -164,6 +145,7 @@ impl TryFrom<FormConfig> for config::Config {
fn try_from(value: FormConfig) -> Result<Self, Self::Error> {
Ok(config::Config {
+ freq: value.freq.parse()?,
callsign: value.callsign,
ssid: value.ssid.parse()?,
icon: value.icon.parse()?,
diff --git a/static/style.css b/static/style.css
index 133246e..c23e8d0 100644
--- a/static/style.css
+++ b/static/style.css
@@ -1 +1 @@
-/*! tailwindcss v3.3.5 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }html{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));font-family:sans-serif}.m-2{margin:.5rem}.flex{display:flex}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-60{width:15rem}.w-8{width:2rem}.flex-auto{flex:1 1 auto}.flex-none{flex:none}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-sky-300>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(125 211 252/var(--tw-divide-opacity))}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.bg-sky-100{--tw-bg-opacity:1;background-color:rgb(224 242 254/var(--tw-bg-opacity))}.bg-sky-200{--tw-bg-opacity:1;background-color:rgb(186 230 253/var(--tw-bg-opacity))}.bg-sky-300{--tw-bg-opacity:1;background-color:rgb(125 211 252/var(--tw-bg-opacity))}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.pb-4{padding-bottom:1rem}.pt-2{padding-top:.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.font-semibold{font-weight:600}.text-sky-800{--tw-text-opacity:1;color:rgb(7 89 133/var(--tw-text-opacity))}.text-sky-900{--tw-text-opacity:1;color:rgb(12 74 110/var(--tw-text-opacity))}h1{font-size:1.125rem;line-height:1.75rem}h1,h2{font-weight:700}fieldset{margin:.5rem;border-radius:.375rem;padding:.5rem;font-weight:400;--tw-text-opacity:1;color:rgb(3 105 161/var(--tw-text-opacity));outline-style:solid;outline-color:#3b82f61a}fieldset:hover{outline-color:#3b82f64d}legend{padding:.25rem;font-variant:small-caps}label{padding:.5rem}input,label{margin:.25rem}.btn{margin-top:.25rem;margin-bottom:.25rem;border-radius:.25rem;padding:.25rem .5rem;font-weight:700;--tw-bg-opacity:1;background-color:rgb(14 165 233/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.btn:hover{--tw-bg-opacity:1;background-color:rgb(2 132 199/var(--tw-bg-opacity))}.textinput{border-radius:.375rem;border-width:2px;--tw-border-opacity:1;border-color:rgb(228 228 231/var(--tw-border-opacity));padding:.25rem;font-size:.875rem;line-height:1.25rem;font-weight:400;--tw-text-opacity:1;color:rgb(3 105 161/var(--tw-text-opacity));outline-style:solid;outline-width:0}.textinput:focus{border-width:2px;--tw-border-opacity:1;border-color:rgb(113 113 122/var(--tw-border-opacity));outline-width:0}.textinput:disabled{border-width:0;--tw-bg-opacity:1;background-color:rgb(250 250 250/var(--tw-bg-opacity))}.hover\:bg-sky-300:hover{--tw-bg-opacity:1;background-color:rgb(125 211 252/var(--tw-bg-opacity))} \ No newline at end of file
+/*! tailwindcss v3.3.5 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }html{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));font-family:sans-serif}.mt-1{margin-top:.25rem}.flex{display:flex}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-60{width:15rem}.w-8{width:2rem}.flex-auto{flex:1 1 auto}.flex-none{flex:none}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-sky-300>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(125 211 252/var(--tw-divide-opacity))}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.bg-sky-100{--tw-bg-opacity:1;background-color:rgb(224 242 254/var(--tw-bg-opacity))}.bg-sky-200{--tw-bg-opacity:1;background-color:rgb(186 230 253/var(--tw-bg-opacity))}.bg-sky-300{--tw-bg-opacity:1;background-color:rgb(125 211 252/var(--tw-bg-opacity))}.p-3{padding:.75rem}.p-4{padding:1rem}.pb-4{padding-bottom:1rem}.pt-2{padding-top:.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.font-semibold{font-weight:600}.text-sky-800{--tw-text-opacity:1;color:rgb(7 89 133/var(--tw-text-opacity))}.text-sky-900{--tw-text-opacity:1;color:rgb(12 74 110/var(--tw-text-opacity))}h1{font-size:1.125rem;line-height:1.75rem}h1,h2{font-weight:700}fieldset{margin:.5rem;border-radius:.375rem;padding:.5rem;font-weight:400;--tw-text-opacity:1;color:rgb(3 105 161/var(--tw-text-opacity));outline-style:solid;outline-color:#3b82f61a}fieldset:hover{outline-color:#3b82f64d}legend{padding:.25rem;font-variant:small-caps}label{padding:.5rem}input,label{margin:.25rem}.btn{margin-top:.25rem;margin-bottom:.25rem;border-radius:.25rem;padding:.25rem .5rem;font-weight:700;--tw-bg-opacity:1;background-color:rgb(14 165 233/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.btn:hover{--tw-bg-opacity:1;background-color:rgb(2 132 199/var(--tw-bg-opacity))}.textinput{border-radius:.375rem;border-width:2px;--tw-border-opacity:1;border-color:rgb(228 228 231/var(--tw-border-opacity));padding:.25rem;font-size:.875rem;line-height:1.25rem;font-weight:400;--tw-text-opacity:1;color:rgb(3 105 161/var(--tw-text-opacity));outline-style:solid;outline-width:0}.textinput:focus{border-width:2px;--tw-border-opacity:1;border-color:rgb(113 113 122/var(--tw-border-opacity));outline-width:0}.textinput:disabled{border-width:0;--tw-bg-opacity:1;background-color:rgb(250 250 250/var(--tw-bg-opacity))}.hover\:bg-sky-300:hover{--tw-bg-opacity:1;background-color:rgb(125 211 252/var(--tw-bg-opacity))} \ No newline at end of file
diff --git a/templates/settings.html b/templates/settings.html
index 545a199..a24137e 100644
--- a/templates/settings.html
+++ b/templates/settings.html
@@ -5,6 +5,7 @@
<form action="/settings" method="post">
<fieldset>
<legend>General</legend>
+ <div><label for="freq">Frequency [kHz]:</label><input class="textinput" type="text" name="freq" value="{{ conf.freq }}"></div>
<div><label for="callsign">Callsign:</label><input class="textinput" type="text" name="callsign" value="{{ conf.callsign }}"></div>
<div><label for="ssid">SSID:</label><input class="textinput" type="number" name="ssid" value="{{ conf.ssid }}"></div>
<div><label for="icon">Icon:</label><input class="textinput" type="number" name="icon" value="{{ conf.icon }}"></div>