diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d4bbf48..6d53898 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -74,12 +74,12 @@ jobs: if: ${{ matrix.os == 'ubuntu-latest' && matrix.target == 'x86_64-unknown-linux-gnu' }} run: sudo apt install -y libusb-1.0-0 libusb-1.0-0-dev - - name: Install libusb (armv7) - if: ${{ matrix.target == 'armv7-unknown-linux-gnueabihf' }} - uses: ryankurte/action-apt@v0.3.0 + - name: Install libusb and gcc (apt armv7) + if: ${{ matrix.os == 'ubuntu-latest' && matrix.target == 'armv7-unknown-linux-gnueabihf' }} + uses: ryankurte/action-apt@v0.4.1 with: arch: armhf - packages: libusb-1.0-0-dev:armhf + packages: libusb-1.0-0:armhf libusb-1.0-0-dev:armhf gcc-arm-linux-gnueabihf - name: Install cross toolchain (armv7) if: ${{ matrix.target == 'armv7-unknown-linux-gnueabihf' }} diff --git a/Cargo.lock b/Cargo.lock index 0bb4144..05117ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,27 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "CoreFoundation-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0e9889e6db118d49d88d84728d0e964d973a5680befb5f85f55141beea5c20b" +dependencies = [ + "libc", + "mach", +] + +[[package]] +name = "IOKit-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99696c398cbaf669d2368076bdb3d627fb0ce51a26899d7c61228c5c0af3bf4a" +dependencies = [ + "CoreFoundation-sys", + "libc", + "mach", +] + [[package]] name = "addr2line" version = "0.16.0" @@ -17,6 +38,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + [[package]] name = "ansi_term" version = "0.11.0" @@ -144,9 +174,9 @@ checksum = "338089f42c427b86394a5ee60ff321da23a5c89c9d89514c829687b26359fcff" [[package]] name = "defmt" -version = "0.3.1" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9252abe43d4c0a5df0c5c865129fa8daad338bb33357ba40023a37cd34b4a7b9" +checksum = "a8a2d011b2fee29fb7d659b83c43fce9a2cb4df453e16d441a51448e448f3f98" dependencies = [ "bitflags", "defmt-macros", @@ -204,8 +234,6 @@ dependencies = [ [[package]] name = "driver-pal" version = "0.8.0-alpha.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d4b407622815edaabcb93b62d983f9fa13baeb5cb087a28754c6332d3a0ca9" dependencies = [ "driver-cp2130", "embedded-hal", @@ -219,10 +247,17 @@ dependencies = [ [[package]] name = "embedded-hal" -version = "1.0.0-alpha.7" +version = "1.0.0-alpha.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93cc714edeae73aa1ff259af4498595360b2992e0e9c59801873ed198a7f2216" +checksum = "f65c4d073f5d91c66e629b216818a4c9747eeda0debedf2deda9a0a947e4e93b" + +[[package]] +name = "embedded-hal-nb" +version = "1.0.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465fffd56a95bbc105c17965bca1c1d5815027b1cc6bb183bc05d04563d065c" dependencies = [ + "embedded-hal", "nb", ] @@ -273,7 +308,7 @@ checksum = "409296415b8abc7b47e5b77096faae14595c53724972da227434fc8f4b05ec8b" dependencies = [ "bitflags", "libc", - "nix", + "nix 0.23.1", ] [[package]] @@ -321,16 +356,7 @@ dependencies = [ "bitflags", "byteorder", "libc", - "nix", -] - -[[package]] -name = "ioctl-rs" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7970510895cee30b3e9128319f2cefd4bde883a39f38baa279567ba3a7eb97d" -dependencies = [ - "libc", + "nix 0.23.1", ] [[package]] @@ -347,9 +373,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.123" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libusb1-sys" @@ -365,18 +391,17 @@ dependencies = [ [[package]] name = "linux-embedded-hal" -version = "0.4.0-alpha.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f67fcef5d29b3ca6328cb283cb7e944e942f54d229709b71bb618f67af55be" +version = "0.4.0-alpha.3" +source = "git+https://github.com/rust-embedded/linux-embedded-hal#a0d986b106dbd6db21b14a5ea98b9a409d59df58" dependencies = [ "cast", "embedded-hal", + "embedded-hal-nb", "gpio-cdev", "i2cdev", "nb", - "nix", - "serial-core", - "serial-unix", + "nix 0.23.1", + "serialport", "spidev", "sysfs_gpio", ] @@ -390,6 +415,24 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "mach" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9" +dependencies = [ + "libc", +] + +[[package]] +name = "mach2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" +dependencies = [ + "libc", +] + [[package]] name = "matchers" version = "0.0.1" @@ -443,6 +486,17 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -644,6 +698,8 @@ version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ + "aho-corasick", + "memchr", "regex-syntax", ] @@ -699,6 +755,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "serde" version = "1.0.144" @@ -731,24 +793,20 @@ dependencies = [ ] [[package]] -name = "serial-core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f46209b345401737ae2125fe5b19a77acce90cd53e1658cda928e4fe9a64581" -dependencies = [ - "libc", -] - -[[package]] -name = "serial-unix" -version = "0.4.0" +name = "serialport" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03fbca4c9d866e24a459cbca71283f545a37f8e3e002ad8c70593871453cab7" +checksum = "c32634e2bd4311420caa504404a55fad2131292c485c97014cbed89a5899885f" dependencies = [ - "ioctl-rs", - "libc", - "serial-core", - "termios", + "CoreFoundation-sys", + "IOKit-sys", + "bitflags", + "cfg-if", + "mach2", + "nix 0.26.4", + "regex", + "scopeguard", + "winapi", ] [[package]] @@ -796,7 +854,7 @@ checksum = "5c43e891adf1abc1e09b10f80c8d91959ee20ec28425c6dadac78844ba4c709f" dependencies = [ "bitflags", "libc", - "nix", + "nix 0.23.1", ] [[package]] @@ -900,7 +958,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ef9c9bcbfeb596ce4da59b2c59736235f35dcd516f03958ea10834473224157" dependencies = [ - "nix", + "nix 0.23.1", ] [[package]] @@ -912,15 +970,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "termios" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d9cf598a6d7ce700a4e6a9199da127e6819a61e64b68609683cc9a01b5683a" -dependencies = [ - "libc", -] - [[package]] name = "textwrap" version = "0.11.0" @@ -1144,3 +1193,7 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[patch.unused]] +name = "radio" +version = "0.11.1" diff --git a/Cargo.toml b/Cargo.toml index 4216eaf..6a09abd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,51 +26,36 @@ std = [ "radio/std", "driver-pal/mock", "failure/std", "hex", "thiserror" ] poll-irq = [] patch-unknown-state = [] tests = [ "driver-pal/mock" ] -util = [ "std", "structopt", "tracing", "tracing-subscriber", "humantime", "crc16", "driver-pal", "driver-pal/hal", "radio/helpers" ] +util = [ "std", "clap", "tracing", "tracing-subscriber", "humantime", "crc16", "driver-pal", "driver-pal/hal", "radio/helpers" ] default = [ "std", "util", "serde", "driver-pal/hal-cp2130", "driver-pal/hal-linux", "patch-unknown-state" ] [dependencies] -radio = { version = "0.11.0", default_features = false } -embedded-hal = "1.0.0-alpha.7" -defmt = {version = "0.3.0", optional = true } +radio = { version = "0.12.1", default_features = false } +embedded-hal = "1.0.0" +embedded-hal-bus = "0.1.0" +driver-pal = { version = "0.9.0", default_features = false, optional=true } -driver-pal = { version = "0.8.0-alpha.6", default_features = false, optional=true } - -bitflags = "1.0.4" +defmt = {version = "0.3.5", optional = true } +bitflags = "2.4.0" libc = "0.2.123" log = { version = "0.4.17", default_features = false } -strum = { version = "0.24.0", default_features = false, features = [ "derive" ] } - +strum = { version = "0.26.2", default_features = false, features = [ "derive" ] } crc16 = { version = "0.4.0", optional = true } hex = { version = "0.4.2", optional = true } - humantime = { version = "2.0.1", optional = true } -structopt = { version = "0.3.26", optional = true } +clap = { version = "4.4.7", optional = true, features = [ "derive", "env" ] } thiserror = { version = "1.0.30", optional = true } +failure = { version = "0.1.7", features = [ "derive" ], default-features = false } +serde = { version = "1.0.144", optional = true , features = ["derive"]} -[dependencies.failure] -version = "0.1.7" -features = [ "derive" ] -default-features = false - -[dependencies.serde] -features = ["derive"] -optional = true -version = "1.0.144" - -[dependencies.tracing] -optional = true -version = "0.1.34" - -[dependencies.tracing-subscriber] -optional = true -version = "0.2.16" +tracing = { version = "0.1.34", optional = true } +tracing-subscriber = { version = "0.3.18", optional = true, features = [ "env-filter" ] } [dev-dependencies] -color-backtrace = "0.5.0" -toml = "0.5.8" +color-backtrace = "0.6.1" +toml = "0.8.12" serde = { version = "1.0.144", features = [ "derive" ] } serde_derive = "1.0.0" @@ -78,7 +63,3 @@ serde_derive = "1.0.0" name = "sx128x-util" path = "src/util/main.rs" required-features = ["util"] - - -[patch.crates-io] -#radio = { git = "https://github.com/rust-iot/radio-hal" } diff --git a/src/base.rs b/src/base.rs index b63ce95..2823030 100644 --- a/src/base.rs +++ b/src/base.rs @@ -4,83 +4,85 @@ use core::fmt::Debug; use log::{error, trace}; -use embedded_hal::digital::PinState; -use embedded_hal::digital::blocking::{InputPin, OutputPin}; +use embedded_hal::{ + delay::DelayNs, + digital::{InputPin, OutputPin, PinState}, + spi::{ErrorType, Operation, SpiDevice}, +}; - -use embedded_hal::delay::blocking::DelayUs; -use embedded_hal::spi::blocking::{Transactional, Operation}; - -use crate::{device::*, SpiBase}; -use crate::Error; +use crate::{device::*, Error}; /// Hal implementation can be generic over SPI or UART connections pub trait Hal { type CommsError: Debug + 'static; type PinError: Debug + 'static; - type DelayError: Debug + 'static; /// Reset the device - fn reset(&mut self) -> Result<(), Error>; + fn reset(&mut self) -> Result<(), Error>; /// Fetch radio device busy pin value - fn get_busy(&mut self) -> Result>; + fn get_busy(&mut self) -> Result>; /// Fetch radio device ready / irq (DIO) pin value - fn get_dio(&mut self) -> Result>; + fn get_dio(&mut self) -> Result>; /// Delay for the specified time - fn delay_ms(&mut self, ms: u32) -> Result<(), Self::DelayError>; + fn delay_ms(&mut self, ms: u32); /// Delay for the specified time - fn delay_us(&mut self, us: u32) -> Result<(), Self::DelayError>; + fn delay_us(&mut self, us: u32); + + /// Delay for the specified time + fn delay_ns(&mut self, ns: u32); /// Write the specified command and data fn write_cmd( &mut self, command: u8, data: &[u8], - ) -> Result<(), Error>; + ) -> Result<(), Error>; + /// Read the specified command and data fn read_cmd( &mut self, command: u8, data: &mut [u8], - ) -> Result<(), Error>; + ) -> Result<(), Error>; /// Write to the specified register fn write_regs( &mut self, reg: u16, data: &[u8], - ) -> Result<(), Error>; + ) -> Result<(), Error>; + /// Read from the specified register fn read_regs( &mut self, reg: u16, data: &mut [u8], - ) -> Result<(), Error>; + ) -> Result<(), Error>; /// Write to the specified buffer fn write_buff( &mut self, offset: u8, data: &[u8], - ) -> Result<(), Error>; + ) -> Result<(), Error>; /// Read from the specified buffer fn read_buff( &mut self, offset: u8, data: &mut [u8], - ) -> Result<(), Error>; + ) -> Result<(), Error>; /// Wait on radio device busy - fn wait_busy(&mut self) -> Result<(), Error> { + fn wait_busy(&mut self) -> Result<(), Error> { // TODO: timeouts here let mut timeout = 0; while self.get_busy()? == PinState::High { - self.delay_ms(1).map_err(Error::Delay)?; + self.delay_ms(1); timeout += 1; if timeout > BUSY_TIMEOUT_MS { @@ -93,9 +95,9 @@ pub trait Hal { } /// Read a single u8 value from the specified register - fn read_reg(&mut self, reg: u16) -> Result> { + fn read_reg(&mut self, reg: u16) -> Result> { let mut incoming = [0u8; 1]; - self.read_regs(reg.into(), &mut incoming)?; + self.read_regs(reg, &mut incoming)?; Ok(incoming[0]) } @@ -104,8 +106,8 @@ pub trait Hal { &mut self, reg: u16, value: u8, - ) -> Result<(), Error> { - self.write_regs(reg.into(), &[value])?; + ) -> Result<(), Error> { + self.write_regs(reg, &[value])?; Ok(()) } @@ -115,81 +117,90 @@ pub trait Hal { reg: u16, mask: u8, value: u8, - ) -> Result> { + ) -> Result> { let existing = self.read_reg(reg)?; let updated = (existing & !mask) | (value & mask); self.write_reg(reg, updated)?; Ok(updated) } - fn prefix_read(&mut self, prefix: &[u8], data: &mut [u8]) -> Result<(), Error>; + fn prefix_read( + &mut self, + prefix: &[u8], + data: &mut [u8], + ) -> Result<(), Error>; - fn prefix_write(&mut self, prefix: &[u8], data: &[u8]) -> Result<(), Error>; + fn prefix_write( + &mut self, + prefix: &[u8], + data: &[u8], + ) -> Result<(), Error>; } pub trait HalError { type E: Debug; } -impl HalError for T +impl HalError for T where T: Hal, { - type E = Error<::CommsError, ::PinError, ::DelayError>; + type E = Error<::CommsError, ::PinError>; } /// Base interface for radio device -pub struct Base { +pub struct Base< + Spi: SpiDevice, + Busy: InputPin, + Ready: InputPin, + Sdn: OutputPin, + Delay: DelayNs, +> { pub spi: Spi, - pub cs: Cs, pub busy: Busy, pub ready: Ready, pub sdn: Sdn, pub delay: Delay, } - -impl Hal for Base +impl Hal for Base where - Spi: SpiBase, - ::Error: Debug + 'static, - - Cs: OutputPin, - Busy: InputPin, - Ready: InputPin, - Sdn: OutputPin, + Spi: SpiDevice, + ::Error: Debug + 'static, + + Busy: InputPin, + Ready: InputPin, + Sdn: OutputPin, PinError: Debug + 'static, - Delay: DelayUs, - ::Error: Debug + 'static, + Delay: DelayNs, { - type CommsError = ::Error; + type CommsError = ::Error; type PinError = PinError; - type DelayError = ::Error; /// Reset the radio - fn reset(&mut self) -> Result<(), Error> { - self.delay_ms(20).map_err(Error::Delay)?; - + fn reset(&mut self) -> Result<(), Error> { + self.delay_ms(20); + self.sdn.set_low().map_err(Error::Pin)?; - - self.delay_ms(50).map_err(Error::Delay)?; - + + self.delay_ms(50); + self.sdn.set_high().map_err(Error::Pin)?; - - self.delay_ms(20).map_err(Error::Delay)?; + + self.delay_ms(20); Ok(()) } - fn get_busy(&mut self) -> Result> { + fn get_busy(&mut self) -> Result> { match self.busy.is_high().map_err(Error::Pin)? { true => Ok(PinState::High), false => Ok(PinState::Low), } } - fn get_dio(&mut self) -> Result> { + fn get_dio(&mut self) -> Result> { match self.ready.is_high().map_err(Error::Pin)? { true => Ok(PinState::High), false => Ok(PinState::Low), @@ -197,41 +208,41 @@ where } /// Delay for the specified time - fn delay_ms(&mut self, ms: u32) -> Result<(), ::Error> { - self.delay.delay_ms(ms) + fn delay_ms(&mut self, ms: u32) { + self.delay.delay_ms(ms); } /// Delay for the specified time - fn delay_us(&mut self, ms: u32) -> Result<(), ::Error> { - self.delay.delay_us(ms) + fn delay_us(&mut self, us: u32) { + self.delay.delay_us(us); } - /// Write data with prefix, asserting CS as required - fn prefix_write(&mut self, prefix: &[u8], data: &[u8]) -> Result<(), Error> { - self.cs.set_low().map_err(Error::Pin)?; - - let r = self.spi.exec(&mut [ - Operation::Write(prefix), - Operation::Write(data), - ]).map_err(Error::Comms); - - self.cs.set_high().map_err(Error::Pin)?; + fn delay_ns(&mut self, ns: u32) { + self.delay.delay_ns(ns); + } - r + /// Write data with prefix, asserting CS as required + fn prefix_write( + &mut self, + prefix: &[u8], + data: &[u8], + ) -> Result<(), Error> { + self + .spi + .transaction(&mut [Operation::Write(prefix), Operation::Write(data)]) + .map_err(Error::Comms) } /// Read data with prefix, asserting CS as required - fn prefix_read(&mut self, prefix: &[u8], data: &mut [u8]) -> Result<(), Error> { - self.cs.set_low().map_err(Error::Pin)?; - - let r = self.spi.exec(&mut [ - Operation::Write(prefix), - Operation::Read(data), - ]).map_err(Error::Comms); - - self.cs.set_high().map_err(Error::Pin)?; - - r + fn prefix_read( + &mut self, + prefix: &[u8], + data: &mut [u8], + ) -> Result<(), Error> { + self + .spi + .transaction(&mut [Operation::Write(prefix), Operation::Read(data)]) + .map_err(Error::Comms) } /// Write the specified command and data @@ -239,16 +250,16 @@ where &mut self, command: u8, data: &[u8], - ) -> Result<(), Error> { + ) -> Result<(), Error> { // Setup register write command - let out_buf: [u8; 1] = [command as u8]; + let out_buf: [u8; 1] = [command]; trace!("write_cmd cmd: {:02x?} data: {:02x?}", out_buf, data); self.wait_busy()?; let r = self.prefix_write(&out_buf, data); - + self.wait_busy()?; r } @@ -258,14 +269,14 @@ where &mut self, command: u8, data: &mut [u8], - ) -> Result<(), Error> { + ) -> Result<(), Error> { // Setup register read command - let out_buf: [u8; 2] = [command as u8, 0x00]; + let out_buf: [u8; 2] = [command, 0x00]; self.wait_busy()?; - + let r = self.prefix_read(&out_buf, data); - + self.wait_busy()?; trace!("read_cmd cmd: {:02x?} data: {:02x?}", out_buf, data); @@ -278,7 +289,7 @@ where &mut self, reg: u16, data: &[u8], - ) -> Result<(), Error> { + ) -> Result<(), Error> { // Setup register write command let out_buf: [u8; 3] = [ Commands::WiteRegister as u8, @@ -289,7 +300,7 @@ where trace!("write_regs cmd: {:02x?} data: {:02x?}", out_buf, data); self.wait_busy()?; - + let r = self.prefix_write(&out_buf, data); self.wait_busy()?; @@ -301,7 +312,7 @@ where &mut self, reg: u16, data: &mut [u8], - ) -> Result<(), Error> { + ) -> Result<(), Error> { // Setup register read command let out_buf: [u8; 4] = [ Commands::ReadRegister as u8, @@ -311,7 +322,7 @@ where ]; self.wait_busy()?; - + let r = self.prefix_read(&out_buf, data); self.wait_busy()?; @@ -326,14 +337,14 @@ where &mut self, offset: u8, data: &[u8], - ) -> Result<(), Error> { + ) -> Result<(), Error> { // Setup register write command let out_buf: [u8; 2] = [Commands::WriteBuffer as u8, offset]; trace!("write_buff cmd: {:02x?}", out_buf); self.wait_busy()?; - + let r = self.prefix_write(&out_buf, data); self.wait_busy()?; @@ -345,13 +356,13 @@ where &mut self, offset: u8, data: &mut [u8], - ) -> Result<(), Error> { + ) -> Result<(), Error> { // Setup register read command let out_buf: [u8; 3] = [Commands::ReadBuffer as u8, offset, 0]; trace!(" data: {:02x?}", out_buf); self.wait_busy()?; - + let r = self.prefix_read(&out_buf, data); self.wait_busy()?; diff --git a/src/device/common.rs b/src/device/common.rs index 34711c1..ed8d03b 100644 --- a/src/device/common.rs +++ b/src/device/common.rs @@ -1,7 +1,7 @@ /// Modulation shaping parameter for GFSK, FLRC and BLE modes #[derive(Copy, Clone, PartialEq, Debug)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[cfg_attr(feature = "util", derive(structopt::StructOpt))] +#[cfg_attr(feature = "util", derive(clap::Parser))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ModShaping { /// No filtering @@ -36,7 +36,7 @@ pub enum PreambleLength { /// Bitrate-Bandwidth for GFSK and BLE modes #[derive(Copy, Clone, PartialEq, Debug)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[cfg_attr(feature = "util", derive(structopt::StructOpt))] +#[cfg_attr(feature = "util", derive(clap::Parser))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum GfskBleBitrateBandwidth { /// Raw baudrate: 2000 kbps Bandwidth: 2.4 MHz diff --git a/src/device/mod.rs b/src/device/mod.rs index ba23123..101de87 100644 --- a/src/device/mod.rs +++ b/src/device/mod.rs @@ -117,7 +117,7 @@ impl Config { /// Convert a provided frequency into configuration steps pub fn freq_to_steps(&self, f: f32) -> f32 { - f / self.freq_step() as f32 + f / self.freq_step() } } @@ -476,6 +476,7 @@ pub enum AutoTx { bitflags! { /// Interrupt flags register + #[derive(Copy, Clone, PartialEq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Irq: u16 { const TX_DONE = 0x0001; @@ -502,6 +503,7 @@ pub type DioMask = Irq; bitflags! { /// Packet status register + #[derive(Copy, Clone, PartialEq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PacketStatus: u8 { /// Top flag value unknown due to lack of complete datasheet @@ -518,6 +520,7 @@ bitflags! { bitflags! { /// TxRx status packet status byte + #[derive(Copy, Clone, PartialEq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct TxRxStatus: u8 { /// Top flag value unknown due to lack of complete datasheet @@ -528,6 +531,7 @@ bitflags! { bitflags! { /// TxRx status register + #[derive(Copy, Clone, PartialEq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct SyncAddrStatus: u8 { const SYNC_ERROR = (1 << 6); @@ -536,6 +540,7 @@ bitflags! { bitflags! { /// Radio calibration parameters + #[derive(Copy, Clone, PartialEq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CalibrationParams: u8 { const ADCBulkPEnable = (1 << 5); diff --git a/src/lib.rs b/src/lib.rs index a710006..f15fb59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,13 +19,13 @@ use base::Base; use log::{debug, error, trace, warn}; #[cfg(feature = "defmt")] -use defmt::{trace, debug, error, warn}; - -use embedded_hal::delay::blocking::DelayUs; -use embedded_hal::digital::blocking::{InputPin, OutputPin}; -use embedded_hal::spi::blocking::{Transactional, Transfer, Write}; -use embedded_hal::spi::{Mode as SpiMode, Phase, Polarity}; +use defmt::{debug, error, trace, warn}; +use embedded_hal::{ + delay::DelayNs, + digital::{InputPin, OutputPin}, + spi::{ErrorType, Mode as SpiMode, Phase, Polarity, SpiDevice}, +}; pub use radio::{Channel as _, Interrupts as _, State as _}; @@ -59,8 +59,7 @@ pub const NUM_RETRIES: usize = 3; #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "thiserror", derive(thiserror::Error))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Error -{ +pub enum Error { #[cfg_attr(feature = "thiserror", error("communication error: {:?}", 0))] /// Communications (SPI or UART) error Comms(CommsError), @@ -69,10 +68,6 @@ pub enum Error = Sx128x>; - -/// Helper to group SPI functions by error, not needed when e-h@1.0.0-alpha.8 lands -pub trait SpiBase: Transfer::Error> + Write::Error> + Transactional::Error> { - type Error; -} - -impl + Write + Transactional, E> SpiBase for T { - type Error = E; -} +pub type Sx128xSpi = + Sx128x>; -impl - Sx128x< - Base, - > +impl + Sx128x> where - Spi: SpiBase, - ::Error: Debug, + Spi: SpiDevice, + ::Error: Debug, - CsPin: OutputPin, BusyPin: InputPin, ReadyPin: InputPin, SdnPin: OutputPin, PinError: Debug, - Delay: DelayUs, - ::Error: Debug, + Delay: DelayNs, { /// Create an Sx128x with the provided `Spi` implementation and pins pub fn spi( spi: Spi, - cs: CsPin, busy: BusyPin, ready: ReadyPin, sdn: SdnPin, delay: Delay, config: &Config, - ) -> Result::Error, PinError, ::Error>> { + ) -> Result::Error, PinError>> { // Create SpiWrapper over spi/cs/busy - let hal = Base{spi, cs, sdn, busy, ready, delay}; + let hal = Base { + spi, + sdn, + busy, + ready, + delay, + }; // Create instance with new hal Self::new(hal, config) } @@ -199,10 +187,12 @@ where Hal: base::Hal, ::CommsError: Debug + 'static, ::PinError: Debug + 'static, - ::DelayError: Debug + 'static, { /// Create a new Sx128x instance over a generic Hal implementation - pub fn new(hal: Hal, config: &Config) -> Result::CommsError, ::PinError, ::DelayError>> { + pub fn new( + hal: Hal, + config: &Config, + ) -> Result::CommsError, ::PinError>> { let mut sx128x = Self::build(hal); debug!("Resetting device"); @@ -259,10 +249,7 @@ where } } - pub fn configure( - &mut self, - config: &Config, - ) -> Result<(), ::E> { + pub fn configure(&mut self, config: &Config) -> Result<(), ::E> { // Switch to standby mode self.set_state(State::StandbyRc)?; @@ -306,7 +293,7 @@ where trace!("Setting frequency ({:?} MHz, {} index)", f / 1000 / 1000, c); - let data: [u8; 3] = [(c >> 16) as u8, (c >> 8) as u8, (c >> 0) as u8]; + let data: [u8; 3] = [(c >> 16) as u8, (c >> 8) as u8, c as u8]; self.hal.write_cmd(Commands::SetRfFrequency as u8, &data) } @@ -316,7 +303,7 @@ where power: i8, ramp: RampTime, ) -> Result<(), ::E> { - if power > 13 || power < -18 { + if !(-18..=13).contains(&power) { warn!("TX power out of range (-18 < p < 13)"); } @@ -340,10 +327,7 @@ where } /// Set IRQ mask - pub fn set_irq_mask( - &mut self, - irq: Irq, - ) -> Result<(), ::E> { + pub fn set_irq_mask(&mut self, irq: Irq) -> Result<(), ::E> { trace!("Setting IRQ mask: {:?}", irq); let raw = irq.bits(); @@ -401,7 +385,7 @@ where if self.packet_type != packet_type { trace!("Setting packet type: {:?}", packet_type); self.hal - .write_cmd(Commands::SetPacketType as u8, &[packet_type.clone() as u8])?; + .write_cmd(Commands::SetPacketType as u8, &[packet_type as u8])?; self.packet_type = packet_type; } @@ -411,14 +395,14 @@ where c.sync_word_length as u8, c.sync_word_match as u8, c.header_type as u8, - c.payload_length as u8, + c.payload_length, c.crc_mode as u8, c.whitening as u8, ], LoRa(c) | Ranging(c) => [ - c.preamble_length as u8, + c.preamble_length, c.header_type as u8, - c.payload_length as u8, + c.payload_length, c.crc_mode as u8, c.invert_iq as u8, 0u8, @@ -429,7 +413,7 @@ where c.sync_word_length as u8, c.sync_word_match as u8, c.header_type as u8, - c.payload_length as u8, + c.payload_length, c.crc_mode as u8, c.whitening as u8, ], @@ -466,9 +450,7 @@ where Ok(()) } - pub(crate) fn get_rx_buffer_status( - &mut self, - ) -> Result<(u8, u8), ::E> { + pub(crate) fn get_rx_buffer_status(&mut self) -> Result<(u8, u8), ::E> { use device::lora::LoRaHeader; let mut status = [0u8; 2]; @@ -527,10 +509,7 @@ where Ok(()) } - pub fn calibrate( - &mut self, - c: CalibrationParams, - ) -> Result<(), ::E> { + pub fn calibrate(&mut self, c: CalibrationParams) -> Result<(), ::E> { trace!("Calibrate {:?}", c); self.hal.write_cmd(Commands::Calibrate as u8, &[c.bits()]) } @@ -546,10 +525,7 @@ where // TODO: this could got into a mode config object maybe? #[allow(dead_code)] - pub(crate) fn set_auto_tx( - &mut self, - a: AutoTx, - ) -> Result<(), ::E> { + pub(crate) fn set_auto_tx(&mut self, a: AutoTx) -> Result<(), ::E> { let data = match a { AutoTx::Enabled(timeout_us) => { let compensated = timeout_us - AUTO_RX_TX_OFFSET; @@ -643,20 +619,17 @@ where } } -impl DelayUs for Sx128x +impl DelayNs for Sx128x where Hal: base::Hal, { - type Error = ::E; - - fn delay_us(&mut self, t: u32) -> Result<(), Self::Error> { - self.hal.delay_us(t).map_err(|e| Error::Delay(e)) + fn delay_ns(&mut self, t: u32) { + self.hal.delay_ns(t); } } /// `radio::State` implementation for the SX128x -impl radio::State - for Sx128x +impl radio::State for Sx128x where Hal: base::Hal, { @@ -701,8 +674,7 @@ where } /// `radio::Busy` implementation for the SX128x -impl radio::Busy - for Sx128x +impl radio::Busy for Sx128x where Hal: base::Hal, { @@ -723,8 +695,7 @@ where } /// `radio::Channel` implementation for the SX128x -impl radio::Channel - for Sx128x +impl radio::Channel for Sx128x where Hal: base::Hal, { @@ -741,7 +712,7 @@ where // Set frequency let freq = ch.frequency(); - if freq < FREQ_MIN || freq > FREQ_MAX { + if !(FREQ_MIN..=FREQ_MAX).contains(&freq) { return Err(Error::InvalidFrequency); } @@ -751,7 +722,7 @@ where let packet_type = PacketType::from(ch); if self.packet_type != packet_type { self.hal - .write_cmd(Commands::SetPacketType as u8, &[packet_type.clone() as u8])?; + .write_cmd(Commands::SetPacketType as u8, &[packet_type as u8])?; self.packet_type = packet_type; } @@ -769,8 +740,7 @@ where } /// `radio::Power` implementation for the SX128x -impl radio::Power - for Sx128x +impl radio::Power for Sx128x where Hal: base::Hal, { @@ -784,8 +754,7 @@ where } /// `radio::Interrupts` implementation for the SX128x -impl radio::Interrupts - for Sx128x +impl radio::Interrupts for Sx128x where Hal: base::Hal, { @@ -812,8 +781,7 @@ where } /// `radio::Transmit` implementation for the SX128x -impl radio::Transmit - for Sx128x +impl radio::Transmit for Sx128x where Hal: base::Hal, { @@ -835,14 +803,9 @@ where if let Err(e) = self.configure_modem(&modem_config) { if let Ok(s) = self.get_state() { - error!( - "TX error setting modem (state: {:?})", - s - ); + error!("TX error setting modem (state: {:?})", s); } else { - error!( - "TX error setting modem", - ); + error!("TX error setting modem",); } return Err(e); } @@ -850,14 +813,9 @@ where // Reset buffer addr if let Err(e) = self.set_buff_base_addr(0, 0) { if let Ok(s) = self.get_state() { - error!( - "TX error setting buffer base addr (state: {:?})", - s - ); + error!("TX error setting buffer base addr (state: {:?})", s); } else { - error!( - "TX error setting buffer base addr", - ); + error!("TX error setting buffer base addr",); } return Err(e); @@ -923,8 +881,7 @@ where } /// `radio::Receive` implementation for the SX128x -impl radio::Receive - for Sx128x +impl radio::Receive for Sx128x where Hal: base::Hal, { @@ -947,14 +904,9 @@ where // Reset buffer addr if let Err(e) = self.set_buff_base_addr(0, 0) { if let Ok(s) = self.get_state() { - error!( - "RX error setting buffer base addr (state: {:?})", - s - ); + error!("RX error setting buffer base addr (state: {:?})", s); } else { - error!( - "RX error setting buffer base addr", - ); + error!("RX error setting buffer base addr",); } return Err(e); } @@ -965,14 +917,9 @@ where if let Err(e) = self.configure_modem(&modem_config) { if let Ok(s) = self.get_state() { - error!( - "RX error setting configuration (state: {:?})", - s - ); + error!("RX error setting configuration (state: {:?})", s); } else { - error!( - "RX error setting configuration", - ); + error!("RX error setting configuration",); } return Err(e); } @@ -1054,7 +1001,7 @@ where } /// Fetch a received packet - fn get_received<'a>(&mut self, data: &'a mut [u8]) -> Result<(usize, Self::Info), Self::Error> { + fn get_received(&mut self, data: &mut [u8]) -> Result<(usize, Self::Info), Self::Error> { // Fetch RX buffer information let (ptr, len) = self.get_rx_buffer_status()?; @@ -1083,8 +1030,7 @@ where } /// `radio::Rssi` implementation for the SX128x -impl radio::Rssi - for Sx128x +impl radio::Rssi for Sx128x where Hal: base::Hal, { @@ -1099,64 +1045,10 @@ where } } -#[cfg(all(feature = "std", test))] +#[cfg(test)] mod tests { - use crate::base::Hal; - use crate::device::RampTime; - use crate::Sx128x; - - use driver_pal::mock::{Mock, Spi}; - - use radio::State as _; - - pub mod vectors; - - #[test] - #[ignore] // Ignored awaiting further driver-pal revision - fn test_api_reset() { - let mut m = Mock::new(); - let (spi, sdn, _busy, delay) = (m.spi(), m.pin(), m.pin(), m.delay()); - let mut radio = Sx128x::::build(spi.clone()); - - m.expect(vectors::reset(&spi, &sdn, &delay)); - radio.hal.reset().unwrap(); - m.finalise(); - } - - #[test] - #[ignore] // Ignored awaiting further driver-pal revision - fn test_api_status() { - let mut m = Mock::new(); - let (spi, sdn, _busy, delay) = (m.spi(), m.pin(), m.pin(), m.delay()); - let mut radio = Sx128x::::build(spi.clone()); - - m.expect(vectors::status(&spi, &sdn, &delay)); - radio.get_state().unwrap(); - m.finalise(); - } - - #[test] - #[ignore] // Ignored awaiting further driver-pal revision - fn test_api_firmware_version() { - let mut m = Mock::new(); - let (spi, sdn, _busy, delay) = (m.spi(), m.pin(), m.pin(), m.delay()); - let mut radio = Sx128x::::build(spi.clone()); - - m.expect(vectors::firmware_version(&spi, &sdn, &delay, 16)); - let version = radio.firmware_version().unwrap(); - m.finalise(); - assert_eq!(version, 16); - } - #[test] - #[ignore] // Ignored awaiting further driver-pal revision - fn test_api_power_ramp() { - let mut m = Mock::new(); - let (spi, sdn, _busy, delay) = (m.spi(), m.pin(), m.pin(), m.delay()); - let mut radio = Sx128x::::build(spi.clone()); - - m.expect(vectors::set_power_ramp(&spi, &sdn, &delay, 0x1f, 0xe0)); - radio.set_power_ramp(13, RampTime::Ramp20Us).unwrap(); - m.finalise(); + fn it_works() { + assert_eq!(2 + 2, 4); } } diff --git a/src/util/main.rs b/src/util/main.rs index 657d757..757cdab 100644 --- a/src/util/main.rs +++ b/src/util/main.rs @@ -1,7 +1,7 @@ extern crate libc; +use clap::Parser; use log::{debug, error, info, trace}; -use structopt::StructOpt; use tracing_subscriber::filter::EnvFilter; use tracing_subscriber::FmtSubscriber; @@ -15,13 +15,13 @@ use options::*; fn main() { // Load options - let opts = Options::from_args(); + let opts = Options::parse(); // Initialise logging let filter = EnvFilter::from_default_env() .add_directive(format!("radio_sx128x={}", opts.log_level).parse().unwrap()) .add_directive(format!("sx128x_util={}", opts.log_level).parse().unwrap()) - .add_directive(format!("driver_cp2130=info").parse().unwrap()); + .add_directive("driver_cp2130=info".to_string().parse().unwrap()); let _ = FmtSubscriber::builder() .with_env_filter(filter) @@ -46,7 +46,6 @@ fn main() { info!("Initialising Radio"); let mut radio = Sx128x::spi( spi, - pins.cs, pins.busy, pins.ready, pins.reset, @@ -64,7 +63,6 @@ fn main() { .firmware_version() .expect("error fetching chip version"); info!("Silicon version: 0x{:X}", version); - return; } _ => { if let Some(mut syncword) = opts.syncword { diff --git a/src/util/options.rs b/src/util/options.rs index ea95e1a..c1c0129 100644 --- a/src/util/options.rs +++ b/src/util/options.rs @@ -1,66 +1,71 @@ +use std::str::FromStr; + +use clap::Parser; use driver_pal::hal::DeviceConfig; -use structopt::StructOpt; use tracing_subscriber::filter::LevelFilter; use radio::helpers::Operation; -use radio_sx128x::device::common::GfskFlrcCrcModes::*; -use radio_sx128x::device::common::PreambleLength::*; -use radio_sx128x::device::{common, flrc, lora}; -use radio_sx128x::prelude::*; +use radio_sx128x::{ + device::{ + common::{self, GfskFlrcCrcModes::*, PreambleLength::*}, + flrc, lora, + }, + prelude::*, +}; -#[derive(StructOpt)] -#[structopt(name = "Sx128x-util")] +#[derive(Parser)] +#[clap(name = "Sx128x-util")] /// A Command Line Interface (CLI) for interacting with a local Sx128x radio device pub struct Options { - #[structopt(subcommand)] + #[clap(subcommand)] /// Request for remote-hal server pub command: Command, - #[structopt(flatten)] + #[clap(flatten)] pub spi_config: DeviceConfig, /// Use onboard DCDC instead of LDO - #[structopt(long, env = "USE_DCDC")] + #[clap(long, env = "USE_DCDC")] pub use_dcdc: bool, /// Set CRC length (0, 2, 3 bytes) - #[structopt(long, default_value = "2", env = "CRC_MODE")] + #[clap(long, default_value = "2", env = "CRC_MODE")] pub crc_mode: u8, /// Set preamble length - #[structopt(long, default_value = "16", env = "PREAMBLE_LEN")] + #[clap(long, default_value = "16", env = "PREAMBLE_LEN")] pub preamble_len: u8, - #[structopt(long, default_value = "info")] + #[clap(long, default_value = "info")] /// Configure radio log level pub log_level: LevelFilter, /// Set sync word in hex (base 16), from LSB to MSB without spaces - #[structopt(long)] + #[clap(long, value_parser=HexData::from_str)] pub syncword: Option, } -#[derive(StructOpt, PartialEq, Debug)] +#[derive(Parser, PartialEq, Debug)] pub enum Command { - #[structopt(name = "chip-version")] + #[clap(name = "chip-version")] /// Fetch the device silicon/firmware version FirmwareVersion, - #[structopt(name = "lora")] + #[clap(name = "lora")] /// LoRa mode configuration and operations LoRa(LoRaCommand), - #[structopt(name = "gfsk")] + #[clap(name = "gfsk")] /// GFSK mode configuration and operations Gfsk(GfskCommand), - #[structopt(name = "flrc")] + #[clap(name = "flrc")] /// FLRC mode configuration and operations Flrc(FlrcCommand), } -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub struct HexData(pub Vec); impl std::str::FromStr for HexData { @@ -173,54 +178,54 @@ impl Options { } /// LoRa mode command wrapper -#[derive(StructOpt, PartialEq, Debug)] +#[derive(Parser, PartialEq, Debug)] pub struct LoRaCommand { /// Operating frequency in GHz /// This must be in a range of 2.40 to 2.50 GHz - #[structopt(long = "freq-ghz", default_value = "2.44")] + #[clap(long = "freq-ghz", default_value = "2.44")] pub frequency: f32, - #[structopt(subcommand)] + #[clap(subcommand)] /// Operation to execute pub operation: Operation, } /// GFSK mode command wrapper -#[derive(StructOpt, PartialEq, Debug)] +#[derive(Parser, PartialEq, Debug)] pub struct GfskCommand { /// Operating frequency in GHz /// This must be in a range of 2.40 to 2.50 GHz - #[structopt(long = "freq-ghz", default_value = "2.44")] + #[clap(long = "freq-ghz", default_value = "2.44")] pub frequency: f32, - #[structopt(subcommand)] + #[clap(subcommand)] /// Operation to execute pub operation: Operation, } /// FLRC mode command wrapper -#[derive(StructOpt, PartialEq, Debug)] +#[derive(Parser, PartialEq, Debug)] pub struct FlrcCommand { /// Operating frequency in GHz /// This must be in a range of 2.40 to 2.50 GHz - #[structopt(long = "freq-ghz", default_value = "2.44", env = "FLRC_FREQ_GHZ")] + #[clap(long = "freq-ghz", default_value = "2.44", env = "FLRC_FREQ_GHZ")] pub frequency: f32, /// FLRC bitrate-bandwidth in kbps /// (options: 2600_2400, 2080_2400, 1300_1200, 1040_1200, 650_600, 520_600, 325_300, 260_300) - #[structopt(long = "br-bw", default_value = "260_300", env = "FLRC_BR_BW")] + #[clap(long = "br-bw", default_value = "260_300", env = "FLRC_BR_BW")] pub bitrate_bandwidth: flrc::FlrcBitrate, /// FLRC coding rate /// (options: 3/4, 1/2, 1/0) - #[structopt(long = "cr", default_value = "3/4", env = "FLRC_CR")] + #[clap(long = "cr", default_value = "3/4", env = "FLRC_CR")] pub code_rate: flrc::FlrcCodingRate, /// Disable Sync word matching - #[structopt(long)] + #[clap(long)] pub no_syncword: bool, - #[structopt(subcommand)] + #[clap(subcommand)] /// Operation to execute pub operation: Operation, } diff --git a/tests/integration.rs b/tests/integration.rs index 5591a79..efac1d0 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -8,15 +8,14 @@ use std::time::Duration; use log::{debug, info}; use driver_pal::hal::*; -use driver_pal::wrapper::Wrapper; + use radio::{Receive, Transmit}; -use radio_sx128x::prelude::*; +use radio_sx128x::{base::Base, prelude::*}; -pub type SpiWrapper = - Wrapper; +pub type SpiWrapper = Base; -pub type Radio = Sx128x; +pub type Radio = Sx128x; #[derive(Debug, serde::Deserialize)] pub struct TestConfig { @@ -28,11 +27,10 @@ fn load_radio(rf_config: &Config, device_config: &DeviceConfig) -> Radio { debug!("Connecting to radio"); let HalInst { base: _, spi, pins } = - HalInst::load(&device_config).expect("error connecting to HAL"); + HalInst::load(device_config).expect("error connecting to HAL"); let radio = Sx128x::spi( spi, - pins.cs, pins.busy, pins.ready, pins.reset, @@ -66,7 +64,7 @@ fn test_tx_rx(radio1: &mut Radio, radio2: &mut Radio) { let mut sent = false; let mut received = false; let mut buff = [0u8; 1024]; - let mut n = 0; + let n = 0; // Configure receive radio1.start_receive().unwrap();