diff --git a/.cargo/config.toml b/.cargo/config.toml index a975521..3054f14 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -3,7 +3,7 @@ runner = "probe-rs run --chip RP2040 --preverify" [build] target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ -rustflags = ["-Z", "unstable-options", "-C", "panic=immediate-abort"] +rustflags = ["-Z", "unstable-options", "-C", "panic=immediate-abort", "--cfg", "getrandom_backend=\"custom\""] [env] DEFMT_LOG = "info" diff --git a/Cargo.lock b/Cargo.lock index 37123d4..b59d302 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,16 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -83,7 +93,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" dependencies = [ - "rustc_version", + "rustc_version 0.2.3", ] [[package]] @@ -131,6 +141,15 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -182,6 +201,41 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + [[package]] name = "cobs" version = "0.3.0" @@ -279,6 +333,31 @@ dependencies = [ "typenum", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "fiat-crypto", + "rustc_version 0.4.1", + "subtle", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "cyw43" version = "0.6.0" @@ -412,6 +491,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -765,6 +845,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "fixed" version = "1.30.0" @@ -881,6 +967,18 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + [[package]] name = "gimli" version = "0.32.3" @@ -950,6 +1048,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + [[package]] name = "is_ci" version = "1.2.0" @@ -1192,6 +1299,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "owo-colors" version = "4.3.0" @@ -1281,6 +1394,7 @@ dependencies = [ "embassy-strike-driver", "embassy-sync", "embassy-time", + "getrandom", "heapless 0.8.0", "jiff", "panic-probe", @@ -1292,6 +1406,7 @@ dependencies = [ "sachy-mdns", "sachy-sntp", "serde", + "snow", "static_cell", "striker-proto", ] @@ -1350,6 +1465,17 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "portable-atomic" version = "1.13.1" @@ -1427,6 +1553,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand_core" version = "0.6.4" @@ -1527,7 +1659,16 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver", + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.27", ] [[package]] @@ -1614,6 +1755,12 @@ dependencies = [ "semver-parser", ] +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "semver-parser" version = "0.7.0" @@ -1710,6 +1857,20 @@ dependencies = [ "managed", ] +[[package]] +name = "snow" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "599b506ccc4aff8cf7844bc42cf783009a434c1e26c964432560fb6d6ad02d82" +dependencies = [ + "blake2", + "chacha20poly1305", + "curve25519-dalek", + "getrandom", + "rustc_version 0.4.1", + "subtle", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -1752,6 +1913,12 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "supports-color" version = "3.0.2" @@ -1939,6 +2106,16 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "vcell" version = "0.1.3" @@ -1976,6 +2153,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "winapi-util" version = "0.1.11" @@ -2083,22 +2269,34 @@ dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + [[package]] name = "zerocopy" -version = "0.8.40" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.40" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" dependencies = [ "proc-macro2", "quote", "syn 2.0.117", ] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" diff --git a/Cargo.toml b/Cargo.toml index e290d23..fd9fd2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,9 +55,8 @@ striker-proto = { git = "https://tangled.org/sachy.dev/striker", package = "stri embassy-strike-driver = { git = "https://tangled.org/sachy.dev/strike-sensor", package = "embassy-strike-driver", features = [ "rp2040", "alloc", - "debug" + "debug", ] } - embassy-embedded-hal = { version = "0.5.0" } embassy-sync = { version = "0.7.2" } embassy-executor = { version = "0.9.0", features = [ @@ -92,6 +91,13 @@ embassy-net = { version = "0.7.1", features = [ ] } cyw43 = { version = "0.6.0", features = ["firmware-logs"] } cyw43-pio = { version = "0.9.0" } +snow = { version = "0.10", default-features = false, features = [ + "use-curve25519", + "use-chacha20poly1305", + "use-blake2", + "use-getrandom", +] } +getrandom = { version = "0.3.4", default-features = false } [build-dependencies] sachy-config = { git = "https://tangled.org/sachy.dev/sachy-embed-core", package = "sachy-config" } diff --git a/README.md b/README.md index dee0ca8..5dac7b1 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ Pico Strike! is a Rust written firmware to have a RPi Pico W (RP2040) do lightni ## Network - [x] Wifi stack setup - [X] Serializing for multiple packet types for external sources -- [ ] Support runtime configuration for detector sensitivity over network (optional) -- [ ] Encryption for communication +- [x] Support runtime configuration for detector sensitivity over network (optional) +- [x] Encryption for communication - [x] mDNS SD for exposing network address and endpoint information - [ ] Home Assistant integration and setup (stretch goal) - [ ] OTA updates (stretch goal, completely optional) diff --git a/pico-config.example.toml b/pico-config.example.toml index 3c4174a..7bea9bd 100644 --- a/pico-config.example.toml +++ b/pico-config.example.toml @@ -2,9 +2,10 @@ SSID = "CHANGEME" PASSWORD = "astrongpassword123" HOST_NAME = "strike" +NOISE_PSK = { kind = "bytes", value = "FwDnM8ikl63kopPSMm9dvz8NljGVoJWNR2ue7YWs45A=" } [constants] -HEAP_SIZE = { type = "usize", value = "65536" } +HEAP_SIZE = { type = "usize", value = "131072" } BLOCK_SIZE = { type = "usize", value = "512" } HOST_PORT = { type = "u16", value = "6125" } BLIP_THRESHOLD = { type = "u16", value = "18" } diff --git a/src/errors.rs b/src/errors.rs index 6cd32af..5d4dfb9 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,3 +1,5 @@ +use core::num::TryFromIntError; + use alloc::collections::TryReserveError; use embassy_rp::rtc::RtcError; use sachy_sntp::SntpError; @@ -8,14 +10,20 @@ pub enum PicoError { InvalidSntpTime(SntpError), InvalidRtcTime, AllocationError, + NoisePayloadTooBig, + TcpError(embassy_net::tcp::Error), + NoiseProtoError, } impl core::fmt::Display for PicoError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - PicoError::InvalidSntpTime(reason) => write!(f, "Invalid SNTP time: {reason:?}"), - PicoError::InvalidRtcTime => write!(f, "Invalid RTC time: Year is out of bounds"), - PicoError::AllocationError => write!(f, "Failed to allocate memory"), + Self::InvalidSntpTime(reason) => write!(f, "Invalid SNTP time: {reason:?}"), + Self::InvalidRtcTime => write!(f, "Invalid RTC time: Year is out of bounds"), + Self::AllocationError => write!(f, "Failed to allocate memory"), + Self::NoisePayloadTooBig => write!(f, "Invalid payload size"), + Self::TcpError(error) => write!(f, "Network error: {error:?}"), + Self::NoiseProtoError => write!(f, "Noise protocol failure"), } } } @@ -39,3 +47,22 @@ impl From for PicoError { Self::AllocationError } } + +impl From for PicoError { + fn from(_value: TryFromIntError) -> Self { + Self::NoisePayloadTooBig + } +} + +impl From for PicoError { + fn from(value: embassy_net::tcp::Error) -> Self { + Self::TcpError(value) + } +} + +impl From for PicoError { + fn from(_value: snow::Error) -> Self { + Self::NoiseProtoError + } +} + diff --git a/src/locks.rs b/src/locks.rs index 507253a..4ac69be 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -3,5 +3,5 @@ use embassy_rp::spinlock_mutex::SpinlockRawMutex; pub type AllocatorLock = SpinlockRawMutex<0>; pub type RtcLock = SpinlockRawMutex<1>; pub type ConnectionStatusLock = SpinlockRawMutex<2>; -pub type NetDataLock = SpinlockRawMutex<3>; +pub type DataTransferLock = SpinlockRawMutex<3>; pub type ConfigUpdateLock = SpinlockRawMutex<4>; diff --git a/src/main.rs b/src/main.rs index 5d7a4bd..415055b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,3 @@ -#![feature(impl_trait_in_assoc_type)] #![feature(allocator_api)] #![allow(unexpected_cfgs)] #![no_std] @@ -23,6 +22,7 @@ use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi}; use embassy_executor::Executor; use embassy_rp::{ adc as rp_adc, bind_interrupts, + clocks::RoscRng, gpio::{Level, Output}, multicore::{Stack, spawn_core1}, peripherals::PIO0, @@ -52,6 +52,23 @@ bind_interrupts!(struct Irqs { RTC_IRQ => rp_rtc::InterruptHandler, rtc::GlobalRtcHandler; }); +#[unsafe(no_mangle)] +unsafe extern "Rust" fn __getrandom_v03_custom( + dest: *mut u8, + len: usize, +) -> Result<(), getrandom::Error> { + let slice = unsafe { + // Initialise the buffer with zeros before transmuting it into + // a mutable slice + core::ptr::write_bytes(dest, 0, len); + core::slice::from_raw_parts_mut(dest, len) + }; + + RoscRng.fill_bytes(slice); + + Ok(()) +} + #[cortex_m_rt::entry] fn main() -> ! { let p = embassy_rp::init(Default::default()); @@ -62,8 +79,7 @@ fn main() -> ! { info!("Initialising drivers"); let pwm = embassy_strike_driver::drivers::rp::PwmDriver::new(p.PWM_SLICE5, p.PIN_27); - let adc = - embassy_strike_driver::drivers::rp::AdcDriver::new(p.ADC, p.PIN_26, p.DMA_CH1, Irqs); + let adc = embassy_strike_driver::drivers::rp::AdcDriver::new(p.ADC, p.PIN_26, p.DMA_CH1, Irqs); let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); diff --git a/src/net.rs b/src/net.rs index 326b37a..beee2ce 100644 --- a/src/net.rs +++ b/src/net.rs @@ -1,4 +1,5 @@ mod mdns; +mod noise; mod rpc; mod sntp; @@ -16,6 +17,7 @@ use sachy_mdns::{ use crate::{ constants::{HOST_NAME, HOST_PORT}, + net::noise::NOISE_PROTO, rtc::GlobalRtc, updates::UpdateConnection, utils::try_static_buffer_with, @@ -42,6 +44,7 @@ pub async fn udp_stack(stack: embassy_net::Stack<'static>, rtc: GlobalRtc<'stati .config_v4() .map(|config| config.address.address().into()), HOST_PORT, + [NOISE_PROTO], )); loop { @@ -75,7 +78,7 @@ pub async fn tcp_stack(stack: embassy_net::Stack<'static>) { loop { stack.wait_config_up().await; - select(stack.wait_link_down(), rpc::data_loop(&mut tcp, &net_data)).await; + select(stack.wait_link_down(), rpc::rpc_loop(&mut tcp, &net_data)).await; net_data.clear(); diff --git a/src/net/noise.rs b/src/net/noise.rs new file mode 100644 index 0000000..17370df --- /dev/null +++ b/src/net/noise.rs @@ -0,0 +1,164 @@ +use embassy_futures::select::select; +use embassy_net::tcp::{TcpReader, TcpSocket, TcpWriter}; +use embassy_sync::{ + blocking_mutex::raw::NoopRawMutex, lazy_lock::LazyLock, mutex::Mutex, once_lock::OnceLock, +}; +use sachy_fmt::unwrap; +use snow::{Builder, Keypair, TransportState, params::NoiseParams}; + +use crate::{ + constants::NOISE_PSK, errors::PicoError, rpc::RpcServer, updates::UpdateConnection, + utils::try_buffer, +}; + +pub static NOISE_PROTO: &str = "Noise_XXpsk3_25519_ChaChaPoly_BLAKE2s"; + +static PARAMS: LazyLock = + LazyLock::new(|| unwrap!(NOISE_PROTO.parse(), "Unable to parse Noise proto schema")); + +static LOCAL_PRIVATE_KEY: OnceLock = OnceLock::new(); + +pub struct NoiseSession { + transport: Mutex, +} + +impl NoiseSession { + pub async fn initialize<'device>(tcp: &mut TcpSocket<'device>) -> Result { + let state = noise_handshake(tcp).await?; + + Ok(Self { + transport: Mutex::new(state), + }) + } + + pub async fn run<'device>(self, tcp: &mut TcpSocket<'device>) { + let (reader, writer) = tcp.split(); + + select(self.read_loop(reader), self.write_loop(writer)).await; + } + + async fn read_loop<'device>(&self, mut reader: TcpReader<'device>) { + let mut buffer = unwrap!(try_buffer(8192)); + + let (packet_buf, msg_buf) = buffer.split_at_mut(4096); + + loop { + let Ok(received) = noise_recv(&mut reader, packet_buf).await else { + break; + }; + + if let Ok(msg) = self.transport.lock().await.read_message(received, msg_buf) + && let Ok(req) = striker_proto::receive_request(&mut msg_buf[..msg]) + { + let Some((resp, resp_tx)) = RpcServer::handle_request(req) + .await + .zip(UpdateConnection::can_update()) + else { + break; + }; + resp_tx.try_send(resp).ok(); + } + } + } + + async fn write_loop<'device>(&self, mut writer: TcpWriter<'device>) { + let outgoing = UpdateConnection::get_receiver(); + + let mut buffer = unwrap!(try_buffer(8192)); + + let (msg_buf, enc_buf) = buffer.split_at_mut(4096); + + loop { + let data = outgoing.receive().await; + + let packet = unwrap!(striker_proto::send_response(data, msg_buf)); + let written = unwrap!( + self.transport.lock().await.write_message(packet, enc_buf), + "Payload too big" + ); + + if noise_send(&mut writer, &enc_buf[..written]).await.is_err() { + break; + } + + if writer.flush().await.is_err() { + break; + } + } + } +} + +async fn noise_handshake<'device>( + tcp: &mut TcpSocket<'device>, +) -> Result { + let builder = Builder::new(PARAMS.get().clone()); + let static_key = LOCAL_PRIVATE_KEY + .get_or_init(|| unwrap!(builder.generate_keypair(), "Failed to generate key pair")); + + let mut noise = builder + .local_private_key(&static_key.private)? + .psk(3, &NOISE_PSK)? + .build_responder()?; + + let (mut reader, mut writer) = tcp.split(); + + let mut buffer = try_buffer(4096)?; + + let (payload, packet) = buffer.split_at_mut(2048); + + noise.read_message(noise_recv(&mut reader, packet).await?, payload)?; + + let len = noise.write_message(&[], payload)?; + + noise_send(&mut writer, &payload[..len]).await?; + + noise.read_message(noise_recv(&mut reader, packet).await?, payload)?; + + let transport = noise.into_transport_mode()?; + + Ok(transport) +} + +/// Hyper-basic stream transport receiver. 16-bit BE size followed by payload. +async fn noise_recv<'device, 'buffer>( + stream: &mut TcpReader<'device>, + packet: &'buffer mut [u8], +) -> Result<&'buffer [u8], PicoError> { + loop { + if let Some(written) = stream + .read_with(|buf| { + buf.split_at_checked(2).map_or((0, None), |(size, rest)| { + let mut msg_len_buf = [0u8; 2]; + msg_len_buf.copy_from_slice(size); + let buf_size = usize::from(u16::from_be_bytes(msg_len_buf)); + packet[..buf_size].copy_from_slice(&rest[..buf_size]); + + (2 + buf_size, Some(buf_size)) + }) + }) + .await? + { + return Ok(&packet[..written]); + } + } +} + +async fn noise_send<'device>( + stream: &mut TcpWriter<'device>, + payload: &[u8], +) -> Result<(), PicoError> { + let len = u16::try_from(payload.len())?; + while !stream + .write_with(|buf| { + buf.split_at_mut_checked(2) + .map_or((0, false), |(msg_size, rest)| { + msg_size.copy_from_slice(&len.to_be_bytes()); + rest[..payload.len()].copy_from_slice(payload); + (2 + payload.len(), true) + }) + }) + .await? + {} + stream.flush().await?; + Ok(()) +} diff --git a/src/net/rpc.rs b/src/net/rpc.rs index 0be6296..d18c580 100644 --- a/src/net/rpc.rs +++ b/src/net/rpc.rs @@ -1,15 +1,12 @@ -use alloc::vec; -use embassy_futures::select::select; -use embassy_net::tcp::{TcpReader, TcpSocket, TcpWriter}; -use sachy_fmt::{error, info, unwrap}; +use embassy_net::tcp::TcpSocket; +use sachy_fmt::{error, info}; use crate::{ constants::HOST_PORT, - rpc::RpcServer, updates::{NetDataReceiver, UpdateConnection}, }; -pub async fn data_loop<'device>(tcp: &mut TcpSocket<'device>, net_data: &NetDataReceiver) { +pub async fn rpc_loop<'device>(tcp: &mut TcpSocket<'device>, net_data: &NetDataReceiver) { loop { UpdateConnection::disconnect(); @@ -17,63 +14,21 @@ pub async fn data_loop<'device>(tcp: &mut TcpSocket<'device>, net_data: &NetData continue; } - info!("Connected!"); - UpdateConnection::connect(); + match super::noise::NoiseSession::initialize(tcp).await { + Ok(session) => { + info!("Connected!"); + UpdateConnection::connect(); - let (reader, writer) = tcp.split(); + session.run(tcp).await; - select(read_loop(reader), write_loop(writer, net_data)).await; + net_data.clear(); - net_data.clear(); - - tcp.abort(); - tcp.flush().await.ok(); - - info!("DISCONNECT"); - } -} - -async fn read_loop<'device>(mut reader: TcpReader<'device>) { - let mut buf = vec![0u8; 2048]; - - loop { - match reader.read(&mut buf).await { - Ok(0) | Err(_) => break, - Ok(read) => { - if let Ok(req) = striker_proto::receive_request(&mut buf[..read]) - .inspect_err(|e| error!("Proto Error: {}", e)) - { - let Some((resp, resp_tx)) = RpcServer::handle_request(req) - .await - .zip(UpdateConnection::can_update()) - else { - break; - }; - resp_tx.try_send(resp).ok(); - } + info!("DISCONNECT"); } + Err(e) => error!("Session init failure: {}", e), } - } -} - -async fn write_loop<'device>(mut writer: TcpWriter<'device>, net_data: &NetDataReceiver) { - loop { - let data = net_data.receive().await; - if writer - .write_with(|buf| { - let written = unwrap!(striker_proto::send_response(data, buf)); - - (written.len(), ()) - }) - .await - .is_err() - { - break; - } - - if writer.flush().await.is_err() { - break; - } + tcp.abort(); + tcp.flush().await.ok(); } } diff --git a/src/updates.rs b/src/updates.rs index 3fe669c..509e77d 100644 --- a/src/updates.rs +++ b/src/updates.rs @@ -4,13 +4,13 @@ use sachy_fmt::info; use striker_proto::{StrikerResponse, Update}; use crate::{ - locks::NetDataLock, + locks::DataTransferLock, state::{DETECTOR_CONFIG, DETECTOR_CONFIG_UPDATES, DEVICE_STATE, DeviceState}, }; -pub type NetDataChannel = Channel; -pub type NetDataSender = Sender<'static, NetDataLock, StrikerResponse, 8>; -pub type NetDataReceiver = Receiver<'static, NetDataLock, StrikerResponse, 8>; +pub type NetDataChannel = Channel; +pub type NetDataSender = Sender<'static, DataTransferLock, StrikerResponse, 8>; +pub type NetDataReceiver = Receiver<'static, DataTransferLock, StrikerResponse, 8>; static NET_CHANNEL: NetDataChannel = Channel::new();