Compare commits

...

4 Commits

Author SHA1 Message Date
9ddf8b08e4 docs: document usb-logger and usb-dfu 2023-12-19 16:33:05 +01:00
c995732b0e Merge pull request #2320 from embassy-rs/cyw43-docs
docs: document public apis for cyw43 driver
2023-12-19 15:12:45 +00:00
39c166ef9b docs: document public apis for cyw43 driver 2023-12-19 16:08:06 +01:00
5e76c8b41a Merge pull request #2317 from embassy-rs/embassy-rp-rustdoc-2
docs: document all embassy-rp public apis
2023-12-19 13:52:21 +00:00
13 changed files with 120 additions and 8 deletions

17
cyw43-pio/README.md Normal file
View File

@ -0,0 +1,17 @@
# cyw43-pio
RP2040 PIO driver for the nonstandard half-duplex SPI used in the Pico W. The PIO driver offloads SPI communication with the WiFi chip and improves throughput.
## Minimum supported Rust version (MSRV)
Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
## License
This work is licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
<http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option.

View File

@ -1,5 +1,7 @@
#![no_std] #![no_std]
#![allow(async_fn_in_trait)] #![allow(async_fn_in_trait)]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
use core::slice; use core::slice;
@ -11,6 +13,7 @@ use embassy_rp::{Peripheral, PeripheralRef};
use fixed::FixedU32; use fixed::FixedU32;
use pio_proc::pio_asm; use pio_proc::pio_asm;
/// SPI comms driven by PIO.
pub struct PioSpi<'d, CS: Pin, PIO: Instance, const SM: usize, DMA> { pub struct PioSpi<'d, CS: Pin, PIO: Instance, const SM: usize, DMA> {
cs: Output<'d, CS>, cs: Output<'d, CS>,
sm: StateMachine<'d, PIO, SM>, sm: StateMachine<'d, PIO, SM>,
@ -25,6 +28,7 @@ where
CS: Pin, CS: Pin,
PIO: Instance, PIO: Instance,
{ {
/// Create a new instance of PioSpi.
pub fn new<DIO, CLK>( pub fn new<DIO, CLK>(
common: &mut Common<'d, PIO>, common: &mut Common<'d, PIO>,
mut sm: StateMachine<'d, PIO, SM>, mut sm: StateMachine<'d, PIO, SM>,
@ -143,6 +147,7 @@ where
} }
} }
/// Write data to peripheral and return status.
pub async fn write(&mut self, write: &[u32]) -> u32 { pub async fn write(&mut self, write: &[u32]) -> u32 {
self.sm.set_enable(false); self.sm.set_enable(false);
let write_bits = write.len() * 32 - 1; let write_bits = write.len() * 32 - 1;
@ -170,6 +175,7 @@ where
status status
} }
/// Send command and read response into buffer.
pub async fn cmd_read(&mut self, cmd: u32, read: &mut [u32]) -> u32 { pub async fn cmd_read(&mut self, cmd: u32, read: &mut [u32]) -> u32 {
self.sm.set_enable(false); self.sm.set_enable(false);
let write_bits = 31; let write_bits = 31;

View File

@ -45,6 +45,10 @@ nc 192.168.0.250 1234
``` ```
Send it some data, you should see it echoed back and printed in the firmware's logs. Send it some data, you should see it echoed back and printed in the firmware's logs.
## Minimum supported Rust version (MSRV)
Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
## License ## License
This work is licensed under either of This work is licensed under either of

View File

@ -12,17 +12,23 @@ use crate::ioctl::{IoctlState, IoctlType};
use crate::structs::*; use crate::structs::*;
use crate::{countries, events, PowerManagementMode}; use crate::{countries, events, PowerManagementMode};
/// Control errors.
#[derive(Debug)] #[derive(Debug)]
pub struct Error { pub struct Error {
/// Status code.
pub status: u32, pub status: u32,
} }
/// Multicast errors.
#[derive(Debug)] #[derive(Debug)]
pub enum AddMulticastAddressError { pub enum AddMulticastAddressError {
/// Not a multicast address.
NotMulticast, NotMulticast,
/// No free address slots.
NoFreeSlots, NoFreeSlots,
} }
/// Control driver.
pub struct Control<'a> { pub struct Control<'a> {
state_ch: ch::StateRunner<'a>, state_ch: ch::StateRunner<'a>,
events: &'a Events, events: &'a Events,
@ -38,6 +44,7 @@ impl<'a> Control<'a> {
} }
} }
/// Initialize WiFi controller.
pub async fn init(&mut self, clm: &[u8]) { pub async fn init(&mut self, clm: &[u8]) {
const CHUNK_SIZE: usize = 1024; const CHUNK_SIZE: usize = 1024;
@ -154,6 +161,7 @@ impl<'a> Control<'a> {
self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await; self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await;
} }
/// Set power management mode.
pub async fn set_power_management(&mut self, mode: PowerManagementMode) { pub async fn set_power_management(&mut self, mode: PowerManagementMode) {
// power save mode // power save mode
let mode_num = mode.mode(); let mode_num = mode.mode();
@ -166,6 +174,7 @@ impl<'a> Control<'a> {
self.ioctl_set_u32(86, 0, mode_num).await; self.ioctl_set_u32(86, 0, mode_num).await;
} }
/// Join an unprotected network with the provided ssid.
pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> { pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> {
self.set_iovar_u32("ampdu_ba_wsize", 8).await; self.set_iovar_u32("ampdu_ba_wsize", 8).await;
@ -183,6 +192,7 @@ impl<'a> Control<'a> {
self.wait_for_join(i).await self.wait_for_join(i).await
} }
/// Join an protected network with the provided ssid and passphrase.
pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> {
self.set_iovar_u32("ampdu_ba_wsize", 8).await; self.set_iovar_u32("ampdu_ba_wsize", 8).await;
@ -250,16 +260,19 @@ impl<'a> Control<'a> {
} }
} }
/// Set GPIO pin on WiFi chip.
pub async fn gpio_set(&mut self, gpio_n: u8, gpio_en: bool) { pub async fn gpio_set(&mut self, gpio_n: u8, gpio_en: bool) {
assert!(gpio_n < 3); assert!(gpio_n < 3);
self.set_iovar_u32x2("gpioout", 1 << gpio_n, if gpio_en { 1 << gpio_n } else { 0 }) self.set_iovar_u32x2("gpioout", 1 << gpio_n, if gpio_en { 1 << gpio_n } else { 0 })
.await .await
} }
/// Start open access point.
pub async fn start_ap_open(&mut self, ssid: &str, channel: u8) { pub async fn start_ap_open(&mut self, ssid: &str, channel: u8) {
self.start_ap(ssid, "", Security::OPEN, channel).await; self.start_ap(ssid, "", Security::OPEN, channel).await;
} }
/// Start WPA2 protected access point.
pub async fn start_ap_wpa2(&mut self, ssid: &str, passphrase: &str, channel: u8) { pub async fn start_ap_wpa2(&mut self, ssid: &str, passphrase: &str, channel: u8) {
self.start_ap(ssid, passphrase, Security::WPA2_AES_PSK, channel).await; self.start_ap(ssid, passphrase, Security::WPA2_AES_PSK, channel).await;
} }
@ -494,13 +507,14 @@ impl<'a> Control<'a> {
} }
} }
/// WiFi network scanner.
pub struct Scanner<'a> { pub struct Scanner<'a> {
subscriber: EventSubscriber<'a>, subscriber: EventSubscriber<'a>,
events: &'a Events, events: &'a Events,
} }
impl Scanner<'_> { impl Scanner<'_> {
/// wait for the next found network /// Wait for the next found network.
pub async fn next(&mut self) -> Option<BssInfo> { pub async fn next(&mut self) -> Option<BssInfo> {
let event = self.subscriber.next_message_pure().await; let event = self.subscriber.next_message_pure().await;
if event.header.status != EStatus::PARTIAL { if event.header.status != EStatus::PARTIAL {

View File

@ -2,6 +2,8 @@
#![no_main] #![no_main]
#![allow(async_fn_in_trait)] #![allow(async_fn_in_trait)]
#![deny(unused_must_use)] #![deny(unused_must_use)]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
// This mod MUST go first, so that the others see its macros. // This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt; pub(crate) mod fmt;
@ -102,6 +104,7 @@ const CHIP: Chip = Chip {
chanspec_ctl_sb_mask: 0x0700, chanspec_ctl_sb_mask: 0x0700,
}; };
/// Driver state.
pub struct State { pub struct State {
ioctl_state: IoctlState, ioctl_state: IoctlState,
ch: ch::State<MTU, 4, 4>, ch: ch::State<MTU, 4, 4>,
@ -109,6 +112,7 @@ pub struct State {
} }
impl State { impl State {
/// Create new driver state holder.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
ioctl_state: IoctlState::new(), ioctl_state: IoctlState::new(),
@ -118,6 +122,7 @@ impl State {
} }
} }
/// Power management modes.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PowerManagementMode { pub enum PowerManagementMode {
/// Custom, officially unsupported mode. Use at your own risk. /// Custom, officially unsupported mode. Use at your own risk.
@ -203,8 +208,13 @@ impl PowerManagementMode {
} }
} }
/// Embassy-net driver.
pub type NetDriver<'a> = ch::Device<'a, MTU>; pub type NetDriver<'a> = ch::Device<'a, MTU>;
/// Create a new instance of the CYW43 driver.
///
/// Returns a handle to the network device, control handle and a runner for driving the low level
/// stack.
pub async fn new<'a, PWR, SPI>( pub async fn new<'a, PWR, SPI>(
state: &'a mut State, state: &'a mut State,
pwr: PWR, pwr: PWR,

View File

@ -34,6 +34,7 @@ impl Default for LogState {
} }
} }
/// Driver communicating with the WiFi chip.
pub struct Runner<'a, PWR, SPI> { pub struct Runner<'a, PWR, SPI> {
ch: ch::Runner<'a, MTU>, ch: ch::Runner<'a, MTU>,
bus: Bus<PWR, SPI>, bus: Bus<PWR, SPI>,
@ -222,6 +223,7 @@ where
} }
} }
/// Run the
pub async fn run(mut self) -> ! { pub async fn run(mut self) -> ! {
let mut buf = [0; 512]; let mut buf = [0; 512];
loop { loop {

View File

@ -4,13 +4,16 @@ use crate::fmt::Bytes;
macro_rules! impl_bytes { macro_rules! impl_bytes {
($t:ident) => { ($t:ident) => {
impl $t { impl $t {
/// Bytes consumed by this type.
pub const SIZE: usize = core::mem::size_of::<Self>(); pub const SIZE: usize = core::mem::size_of::<Self>();
/// Convert to byte array.
#[allow(unused)] #[allow(unused)]
pub fn to_bytes(&self) -> [u8; Self::SIZE] { pub fn to_bytes(&self) -> [u8; Self::SIZE] {
unsafe { core::mem::transmute(*self) } unsafe { core::mem::transmute(*self) }
} }
/// Create from byte array.
#[allow(unused)] #[allow(unused)]
pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> &Self { pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> &Self {
let alignment = core::mem::align_of::<Self>(); let alignment = core::mem::align_of::<Self>();
@ -23,6 +26,7 @@ macro_rules! impl_bytes {
unsafe { core::mem::transmute(bytes) } unsafe { core::mem::transmute(bytes) }
} }
/// Create from mutable byte array.
#[allow(unused)] #[allow(unused)]
pub fn from_bytes_mut(bytes: &mut [u8; Self::SIZE]) -> &mut Self { pub fn from_bytes_mut(bytes: &mut [u8; Self::SIZE]) -> &mut Self {
let alignment = core::mem::align_of::<Self>(); let alignment = core::mem::align_of::<Self>();
@ -204,6 +208,7 @@ pub struct EthernetHeader {
} }
impl EthernetHeader { impl EthernetHeader {
/// Swap endianness.
pub fn byteswap(&mut self) { pub fn byteswap(&mut self) {
self.ether_type = self.ether_type.to_be(); self.ether_type = self.ether_type.to_be();
} }
@ -472,19 +477,26 @@ impl ScanResults {
#[repr(C, packed(2))] #[repr(C, packed(2))]
#[non_exhaustive] #[non_exhaustive]
pub struct BssInfo { pub struct BssInfo {
/// Version.
pub version: u32, pub version: u32,
/// Length.
pub length: u32, pub length: u32,
/// BSSID.
pub bssid: [u8; 6], pub bssid: [u8; 6],
/// Beacon period.
pub beacon_period: u16, pub beacon_period: u16,
/// Capability.
pub capability: u16, pub capability: u16,
/// SSID length.
pub ssid_len: u8, pub ssid_len: u8,
/// SSID.
pub ssid: [u8; 32], pub ssid: [u8; 32],
// there will be more stuff here // there will be more stuff here
} }
impl_bytes!(BssInfo); impl_bytes!(BssInfo);
impl BssInfo { impl BssInfo {
pub fn parse(packet: &mut [u8]) -> Option<&mut Self> { pub(crate) fn parse(packet: &mut [u8]) -> Option<&mut Self> {
if packet.len() < BssInfo::SIZE { if packet.len() < BssInfo::SIZE {
return None; return None;
} }

20
embassy-usb-dfu/README.md Normal file
View File

@ -0,0 +1,20 @@
# embassy-usb-dfu
An implementation of the USB DFU 1.1 protocol using embassy-boot. It has 2 components depending on which feature is enabled by the user.
* DFU protocol mode, enabled by the `dfu` feature. This mode corresponds to the transfer phase DFU protocol described by the USB IF. It supports DFU_DNLOAD requests if marked by the user, and will automatically reset the chip once a DFU transaction has been completed. It also responds to DFU_GETSTATUS, DFU_GETSTATE, DFU_ABORT, and DFU_CLRSTATUS with no user intervention.
* DFU runtime mode, enabled by the `application feature`. This mode allows users to expose a DFU interface on their USB device, informing the host of the capability to DFU over USB, and allowing the host to reset the device into its bootloader to complete a DFU operation. Supports DFU_GETSTATUS and DFU_DETACH. When detach/reset is seen by the device as described by the standard, will write a new DFU magic number into the bootloader state in flash, and reset the system.
## Minimum supported Rust version (MSRV)
Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
## License
This work is licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
<http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option.

View File

@ -24,6 +24,7 @@ pub struct Control<'d, STATE: NorFlash, RST: Reset> {
} }
impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> { impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> {
/// Create a new DFU instance to expose a DFU interface.
pub fn new(firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes) -> Self { pub fn new(firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes) -> Self {
Control { Control {
firmware_state, firmware_state,

View File

@ -1,3 +1,4 @@
//! USB DFU constants.
pub(crate) const USB_CLASS_APPN_SPEC: u8 = 0xFE; pub(crate) const USB_CLASS_APPN_SPEC: u8 = 0xFE;
pub(crate) const APPN_SPEC_SUBCLASS_DFU: u8 = 0x01; pub(crate) const APPN_SPEC_SUBCLASS_DFU: u8 = 0x01;
#[allow(unused)] #[allow(unused)]
@ -18,10 +19,15 @@ defmt::bitflags! {
#[cfg(not(feature = "defmt"))] #[cfg(not(feature = "defmt"))]
bitflags::bitflags! { bitflags::bitflags! {
/// Attributes supported by the DFU controller.
pub struct DfuAttributes: u8 { pub struct DfuAttributes: u8 {
/// Generate WillDetache sequence on bus.
const WILL_DETACH = 0b0000_1000; const WILL_DETACH = 0b0000_1000;
/// Device can communicate during manifestation phase.
const MANIFESTATION_TOLERANT = 0b0000_0100; const MANIFESTATION_TOLERANT = 0b0000_0100;
/// Capable of upload.
const CAN_UPLOAD = 0b0000_0010; const CAN_UPLOAD = 0b0000_0010;
/// Capable of download.
const CAN_DOWNLOAD = 0b0000_0001; const CAN_DOWNLOAD = 0b0000_0001;
} }
} }
@ -29,7 +35,7 @@ bitflags::bitflags! {
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)] #[repr(u8)]
#[allow(unused)] #[allow(unused)]
pub enum State { pub(crate) enum State {
AppIdle = 0, AppIdle = 0,
AppDetach = 1, AppDetach = 1,
DfuIdle = 2, DfuIdle = 2,
@ -46,7 +52,7 @@ pub enum State {
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)] #[repr(u8)]
#[allow(unused)] #[allow(unused)]
pub enum Status { pub(crate) enum Status {
Ok = 0x00, Ok = 0x00,
ErrTarget = 0x01, ErrTarget = 0x01,
ErrFile = 0x02, ErrFile = 0x02,
@ -67,7 +73,7 @@ pub enum Status {
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)] #[repr(u8)]
pub enum Request { pub(crate) enum Request {
Detach = 0, Detach = 0,
Dnload = 1, Dnload = 1,
Upload = 2, Upload = 2,

View File

@ -23,6 +23,7 @@ pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_S
} }
impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> { impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> {
/// Create a new DFU instance to handle DFU transfers.
pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self { pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self {
Self { Self {
updater, updater,

View File

@ -1,12 +1,14 @@
#![no_std] #![no_std]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
mod fmt; mod fmt;
pub mod consts; pub mod consts;
#[cfg(feature = "dfu")] #[cfg(feature = "dfu")]
mod bootloader; mod dfu;
#[cfg(feature = "dfu")] #[cfg(feature = "dfu")]
pub use self::bootloader::*; pub use self::dfu::*;
#[cfg(feature = "application")] #[cfg(feature = "application")]
mod application; mod application;
@ -17,7 +19,7 @@ pub use self::application::*;
all(feature = "dfu", feature = "application"), all(feature = "dfu", feature = "application"),
not(any(feature = "dfu", feature = "application")) not(any(feature = "dfu", feature = "application"))
))] ))]
compile_error!("usb-dfu must be compiled with exactly one of `bootloader`, or `application` features"); compile_error!("usb-dfu must be compiled with exactly one of `dfu`, or `application` features");
/// Provides a platform-agnostic interface for initiating a system reset. /// Provides a platform-agnostic interface for initiating a system reset.
/// ///
@ -26,9 +28,11 @@ compile_error!("usb-dfu must be compiled with exactly one of `bootloader`, or `a
/// ///
/// If alternate behaviour is desired, a custom implementation of Reset can be provided as a type argument to the usb_dfu function. /// If alternate behaviour is desired, a custom implementation of Reset can be provided as a type argument to the usb_dfu function.
pub trait Reset { pub trait Reset {
/// Reset the device.
fn sys_reset() -> !; fn sys_reset() -> !;
} }
/// Reset immediately.
#[cfg(feature = "esp32c3-hal")] #[cfg(feature = "esp32c3-hal")]
pub struct ResetImmediate; pub struct ResetImmediate;
@ -40,6 +44,7 @@ impl Reset for ResetImmediate {
} }
} }
/// Reset immediately.
#[cfg(feature = "cortex-m")] #[cfg(feature = "cortex-m")]
pub struct ResetImmediate; pub struct ResetImmediate;

View File

@ -13,3 +13,17 @@ async fn logger_task(driver: Driver<'static, USB>) {
embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver); embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver);
} }
``` ```
## Minimum supported Rust version (MSRV)
Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
## License
This work is licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
<http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option.