diff --git a/Cargo.lock b/Cargo.lock index 292cae9c4ad4b776a6bd4babe74a00acdda552b1..9775354e5ca30162f68cef914f9ea08023448358 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,6 +56,18 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" +[[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 = "byteorder" version = "1.5.0" @@ -79,6 +91,7 @@ dependencies = [ "embedded-hal 0.2.7", "embedded-text", "fugit", + "ham-cats", "heapless 0.8.0", "panic-rtt-target", "rf4463", @@ -182,12 +195,24 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "debug-helper" version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e" +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + [[package]] name = "either" version = "1.13.0" @@ -278,6 +303,15 @@ dependencies = [ "object-chain", ] +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + [[package]] name = "float-cmp" version = "0.9.0" @@ -335,6 +369,12 @@ dependencies = [ "gcd", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures-core" version = "0.3.30" @@ -365,6 +405,31 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "ham-cats" +version = "0.2.1" +source = "git+https://gitlab.scd31.com/cats/ham-cats#c09720400728eae584ea285913d109b3b36b2f32" +dependencies = [ + "arrayvec", + "bitvec", + "crc", + "encoding_rs", + "half", + "labrador-ldpc", + "paste", + "snafu", +] + [[package]] name = "hash32" version = "0.2.1" @@ -412,6 +477,12 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "indexmap" version = "1.9.3" @@ -431,6 +502,12 @@ dependencies = [ "either", ] +[[package]] +name = "labrador-ldpc" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52bbada3351e4ae9078bcd095b83eac3a0bc29ed7d63031f062830f8f22485a4" + [[package]] name = "lock_api" version = "0.4.12" @@ -584,6 +661,12 @@ 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_core" version = "0.6.4" @@ -791,6 +874,28 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[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 = "spin" version = "0.9.8" @@ -828,6 +933,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "ufmt-write" version = "0.1.0" @@ -893,3 +1004,12 @@ checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" dependencies = [ "vcell", ] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/companion-software/Cargo.toml b/companion-software/Cargo.toml index f39204f463d15cc442fd9127510cc1454c64ada3..2ca7b570cd3f281ff35fb5bb35d530334179e2d5 100644 --- a/companion-software/Cargo.toml +++ b/companion-software/Cargo.toml @@ -23,3 +23,4 @@ crc = "3.2.1" rp2040-flash = "0.5.0" sectorize = "0.1.0" rf4463 = { path = "../rf4463-lib" } +ham-cats = { git = "https://gitlab.scd31.com/cats/ham-cats" } diff --git a/companion-software/src/controller.rs b/companion-software/src/controller.rs index 735cc6e3fbcd23b1269c33b45157d6648bc527ed..68ffb48f655e8189ea122f5e50e7e9cadf8d8bd4 100644 --- a/companion-software/src/controller.rs +++ b/companion-software/src/controller.rs @@ -8,7 +8,6 @@ use embedded_graphics::{ }; use heapless::{String, Vec}; use rp2040_hal::timer::Instant; -use rtt_target::rprintln; use crate::{ app::{monotonics, MySpi, HEIGHT, WIDTH}, @@ -202,7 +201,8 @@ impl Controller { self.tx_queue.remove(id); let message = self.storage.get_message(msg.id).unwrap(); - rprintln!("send message {}", message.content()); + + self.radio.send_message(&message, spi); } self.radio.tick(spi); diff --git a/companion-software/src/main.rs b/companion-software/src/main.rs index 2630382f8120e8807478aad3c59c757a87da3a79..8ee6815b83e8abda0a7f60bb6c55cbe6b5032b2d 100644 --- a/companion-software/src/main.rs +++ b/companion-software/src/main.rs @@ -28,7 +28,7 @@ mod app { drivers::st7789::St7789, gui::Element, keyboard::{Keyboard, Led}, - radio::RadioController, + radio::{RadioController, MAX_PACKET_LEN}, touchpad::Touchpad, voltage::VoltMeter, }; @@ -213,8 +213,7 @@ mod app { let row_ser = pins.gpio6.into_floating_input(); let row_ld = pins.gpio7.into_push_pull_output(); - let mut keyboard = - Keyboard::new(timer, col_clk, col_ser, col_rclk, row_clk, row_ser, row_ld); + let keyboard = Keyboard::new(timer, col_clk, col_ser, col_rclk, row_clk, row_ser, row_ld); let mut pwm = pwm_slices.pwm4; pwm.set_ph_correct(); @@ -247,7 +246,8 @@ mod app { // SPI Radio let radio_sdn = pins.gpio19.into_push_pull_output(); let radio_cs = pins.gpio21.into_push_pull_output(); - let radio = RadioController::new(&mut spi, radio_sdn, radio_cs, timer); + let buf = singleton!(: [u8; MAX_PACKET_LEN] = [0; MAX_PACKET_LEN]).unwrap(); + let radio = RadioController::new(&mut spi, radio_sdn, radio_cs, timer, buf); // Set up voltage monitoring let adc = Adc::new(pac.ADC, &mut pac.RESETS); diff --git a/companion-software/src/radio.rs b/companion-software/src/radio.rs index 8ffa94d337e55d87a4a45a5d50776a2c1a123e97..94c22049e34cdb15d55619c9bad54f1a794fe50c 100644 --- a/companion-software/src/radio.rs +++ b/companion-software/src/radio.rs @@ -1,3 +1,8 @@ +use ham_cats::{ + buffer::Buffer, + packet::Packet, + whisker::{Destination, Identification, NodeInfoBuilder, Route}, +}; use rf4463::{config, Rf4463}; use rp2040_hal::{ gpio::{ @@ -6,9 +11,8 @@ use rp2040_hal::{ }, Timer, }; -use rtt_target::rdbg; -use crate::app::MySpi; +use crate::{app::MySpi, storage::Message}; type SdnPin = Pin<Gpio19, FunctionSio<SioOutput>, PullDown>; type CsPin = Pin<Gpio21, FunctionSio<SioOutput>, PullDown>; @@ -16,35 +20,75 @@ type CsPin = Pin<Gpio21, FunctionSio<SioOutput>, PullDown>; type MyRf4463 = Rf4463<SdnPin, CsPin, Timer>; pub const MAX_PACKET_LEN: usize = 8191; -pub const CATS_FREQUENCY: u32 = 430_500_000; +const CATS_FREQUENCY: u32 = 430_500_000; +const HARDWARE_ID: u16 = 0x7c87; +const SOFTWARE_ID: u8 = 0; +const MAX_HOPS: u8 = 3; pub struct RadioController { radio: Option<MyRf4463>, + buf: &'static mut [u8; MAX_PACKET_LEN], } impl RadioController { - pub fn new(spi: &mut MySpi, sdn: SdnPin, cs: CsPin, delay: Timer) -> Self { + pub fn new( + spi: &mut MySpi, + sdn: SdnPin, + cs: CsPin, + delay: Timer, + buf: &'static mut [u8; MAX_PACKET_LEN], + ) -> Self { let mut config = config::RADIO_CONFIG_CATS; - let mut radio = Rf4463::new(spi, sdn, cs, delay, &mut config).ok(); + let radio = Rf4463::new(spi, sdn, cs, delay, &mut config).ok(); - if let Some(ref mut radio) = radio { - radio.set_frequency(spi, CATS_FREQUENCY).unwrap(); // TODO fix unwrap - radio.start_tx(spi, &[0x55; 4096]).unwrap(); - } + let mut s = Self { radio, buf }; - Self { radio } + Self::radio_handler(&mut s.radio, |rad| rad.set_frequency(spi, CATS_FREQUENCY)); + + s } pub fn tick(&mut self, spi: &mut MySpi) { - let Some(ref mut radio) = self.radio else { - return; - }; + Self::radio_handler(&mut self.radio, |rad| { + rad.interrupt(spi, None, Some(self.buf)) + }); + } - if let Err(e) = radio.interrupt(spi, None, Some(&[0xE3; 4096])) { - rdbg!(e); - self.radio = None; - } + // TODO hardware/software IDs + pub fn send_message(&mut self, message: &Message, spi: &mut MySpi) { + // Construct CATS packet + let mut buf = [0; MAX_PACKET_LEN]; + let mut pkt = Packet::new(&mut buf); + pkt.add_identification(Identification { + callsign: "VE9QLE".try_into().unwrap(), + ssid: 29, + icon: 0, + }) + .unwrap(); // TODO + + // TODO could do battery voltage here + pkt.add_node_info( + NodeInfoBuilder::default() + .hardware_id(HARDWARE_ID) + .software_id(SOFTWARE_ID) + .build(), + ) + .unwrap(); // TODO + + pkt.add_destination( + Destination::new(false, 0, message.callsign(), message.ssid()).unwrap(), + ) + .unwrap(); // TODO + + pkt.add_route(Route::new(MAX_HOPS)).unwrap(); // TODO + + pkt.add_comment(message.content()).unwrap(); // TODO + + let mut out = Buffer::new_empty(self.buf); + pkt.fully_encode(&mut out).unwrap(); // TODO + + Self::radio_handler(&mut self.radio, |rad| rad.start_tx(spi, &out)); } pub fn errored(&self) -> bool { @@ -57,4 +101,15 @@ impl RadioController { .map(|r| r.is_busy_txing()) .unwrap_or(false) } + + fn radio_handler<T, E, F: FnMut(&mut MyRf4463) -> Result<T, E>>( + radio: &mut Option<MyRf4463>, + mut f: F, + ) { + if let Some(ref mut rad) = radio { + if f(rad).is_err() { + *radio = None; + } + } + } } diff --git a/companion-software/src/storage/message.rs b/companion-software/src/storage/message.rs index 022176d86f0038358d66b377188562d8a059f7e3..64807871d341d05069535201fe9eaa71e183c440 100644 --- a/companion-software/src/storage/message.rs +++ b/companion-software/src/storage/message.rs @@ -137,6 +137,14 @@ impl Message { } } + pub fn callsign(&self) -> &str { + &self.callsign + } + + pub fn ssid(&self) -> u8 { + self.ssid + } + pub fn content(&self) -> &str { &self.message }