Merge pull request #2 from embassy-rs/main

Pull changes from base embassy repo
This commit is contained in:
Tyler 2023-07-16 19:08:01 -05:00 committed by GitHub
commit 6d8a5c6c20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
199 changed files with 4983 additions and 964 deletions

51
.github/ci/doc.sh vendored
View File

@ -6,7 +6,7 @@ set -euo pipefail
export RUSTUP_HOME=/ci/cache/rustup
export CARGO_HOME=/ci/cache/cargo
export CARGO_TARGET_DIR=/ci/cache/target
export BUILDER_THREADS=6
export BUILDER_THREADS=4
export BUILDER_COMPRESS=true
# force rustup to download the toolchain before starting building.
@ -15,30 +15,31 @@ export BUILDER_COMPRESS=true
# which makes rustup very sad
rustc --version > /dev/null
docserver-builder -i ./embassy-stm32 -o crates/embassy-stm32/git.zup
docserver-builder -i ./embassy-boot/boot -o crates/embassy-boot/git.zup
docserver-builder -i ./embassy-boot/nrf -o crates/embassy-boot-nrf/git.zup
docserver-builder -i ./embassy-boot/rp -o crates/embassy-boot-rp/git.zup
docserver-builder -i ./embassy-boot/stm32 -o crates/embassy-boot-stm32/git.zup
docserver-builder -i ./embassy-embedded-hal -o crates/embassy-embedded-hal/git.zup
docserver-builder -i ./embassy-executor -o crates/embassy-executor/git.zup
docserver-builder -i ./embassy-futures -o crates/embassy-futures/git.zup
docserver-builder -i ./embassy-lora -o crates/embassy-lora/git.zup
docserver-builder -i ./embassy-net -o crates/embassy-net/git.zup
docserver-builder -i ./embassy-net-driver -o crates/embassy-net-driver/git.zup
docserver-builder -i ./embassy-net-driver-channel -o crates/embassy-net-driver-channel/git.zup
docserver-builder -i ./embassy-nrf -o crates/embassy-nrf/git.zup
docserver-builder -i ./embassy-rp -o crates/embassy-rp/git.zup
docserver-builder -i ./embassy-sync -o crates/embassy-sync/git.zup
docserver-builder -i ./embassy-time -o crates/embassy-time/git.zup
docserver-builder -i ./embassy-usb -o crates/embassy-usb/git.zup
docserver-builder -i ./embassy-usb-driver -o crates/embassy-usb-driver/git.zup
docserver-builder -i ./embassy-usb-logger -o crates/embassy-usb-logger/git.zup
docserver-builder -i ./cyw43 -o crates/cyw43/git.zup
docserver-builder -i ./cyw43-pio -o crates/cyw43-pio/git.zup
docserver-builder -i ./embassy-net-w5500 -o crates/embassy-net-w5500/git.zup
docserver-builder -i ./embassy-stm32-wpan -o crates/embassy-stm32-wpan/git.zup
docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup
docserver-builder -i ./embassy-boot/boot -o webroot/crates/embassy-boot/git.zup
docserver-builder -i ./embassy-boot/nrf -o webroot/crates/embassy-boot-nrf/git.zup
docserver-builder -i ./embassy-boot/rp -o webroot/crates/embassy-boot-rp/git.zup
docserver-builder -i ./embassy-boot/stm32 -o webroot/crates/embassy-boot-stm32/git.zup
docserver-builder -i ./embassy-embedded-hal -o webroot/crates/embassy-embedded-hal/git.zup
docserver-builder -i ./embassy-executor -o webroot/crates/embassy-executor/git.zup
docserver-builder -i ./embassy-futures -o webroot/crates/embassy-futures/git.zup
docserver-builder -i ./embassy-lora -o webroot/crates/embassy-lora/git.zup
docserver-builder -i ./embassy-net -o webroot/crates/embassy-net/git.zup
docserver-builder -i ./embassy-net-driver -o webroot/crates/embassy-net-driver/git.zup
docserver-builder -i ./embassy-net-driver-channel -o webroot/crates/embassy-net-driver-channel/git.zup
docserver-builder -i ./embassy-nrf -o webroot/crates/embassy-nrf/git.zup
docserver-builder -i ./embassy-rp -o webroot/crates/embassy-rp/git.zup
docserver-builder -i ./embassy-sync -o webroot/crates/embassy-sync/git.zup
docserver-builder -i ./embassy-time -o webroot/crates/embassy-time/git.zup
docserver-builder -i ./embassy-usb -o webroot/crates/embassy-usb/git.zup
docserver-builder -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/git.zup
docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup
docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup
docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup
docserver-builder -i ./embassy-net-w5500 -o webroot/crates/embassy-net-w5500/git.zup
docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static
export KUBECONFIG=/ci/secrets/kubeconfig.yml
POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
kubectl cp crates $POD:/data
kubectl cp webroot/crates $POD:/data
kubectl cp webroot/static $POD:/data

4
ci.sh
View File

@ -5,10 +5,6 @@ set -euo pipefail
export RUSTFLAGS=-Dwarnings
export DEFMT_LOG=trace,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
# needed by wifi examples
export WIFI_NETWORK=x
export WIFI_PASSWORD=x
TARGET=$(rustc -vV | sed -n 's|host: ||p')
BUILD_EXTRA=""

View File

@ -11,7 +11,7 @@ log = ["dep:log"]
firmware-logs = []
[dependencies]
embassy-time = { version = "0.1.0", path = "../embassy-time"}
embassy-time = { version = "0.1.2", path = "../embassy-time"}
embassy-sync = { version = "0.2.0", path = "../embassy-sync"}
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
@ -24,7 +24,7 @@ cortex-m = "0.7.6"
cortex-m-rt = "0.7.0"
futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.10" }
embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.11" }
num_enum = { version = "0.5.7", default-features = false }
[package.metadata.embassy_docs]

View File

@ -30,7 +30,7 @@ TODO:
### Example 2: Create an access point (IP and credentials in the code)
- `cargo run --release --bin wifi_ap_tcp_server`
### Example 3: Connect to an existing network and create a server
- `WIFI_NETWORK=MyWifiNetwork WIFI_PASSWORD=MyWifiPassword cargo run --release --bin wifi_tcp_server`
- `cargo run --release --bin wifi_tcp_server`
After a few seconds, you should see that DHCP picks up an IP address like this
```

View File

@ -345,7 +345,9 @@ where
}
fn rx(&mut self, packet: &mut [u8]) {
let Some((sdpcm_header, payload)) = SdpcmHeader::parse(packet) else { return };
let Some((sdpcm_header, payload)) = SdpcmHeader::parse(packet) else {
return;
};
self.update_credit(&sdpcm_header);
@ -353,7 +355,9 @@ where
match channel {
CHANNEL_TYPE_CONTROL => {
let Some((cdc_header, response)) = CdcHeader::parse(payload) else { return; };
let Some((cdc_header, response)) = CdcHeader::parse(payload) else {
return;
};
trace!(" {:?}", cdc_header);
if cdc_header.id == self.ioctl_id {
@ -417,8 +421,12 @@ where
let status = event_packet.msg.status;
let event_payload = match evt_type {
Event::ESCAN_RESULT if status == EStatus::PARTIAL => {
let Some((_, bss_info)) = ScanResults::parse(evt_data) else { return };
let Some(bss_info) = BssInfo::parse(bss_info) else { return };
let Some((_, bss_info)) = ScanResults::parse(evt_data) else {
return;
};
let Some(bss_info) = BssInfo::parse(bss_info) else {
return;
};
events::Payload::BssInfo(*bss_info)
}
Event::ESCAN_RESULT => events::Payload::None,
@ -439,7 +447,9 @@ where
}
}
CHANNEL_TYPE_DATA => {
let Some((_, packet)) = BdcHeader::parse(payload) else { return };
let Some((_, packet)) = BdcHeader::parse(payload) else {
return;
};
trace!("rx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
match self.ch.try_rx_buf() {

View File

@ -15,15 +15,18 @@ target = "x86_64-unknown-linux-gnu"
std = []
# Enable nightly-only features
nightly = ["embassy-futures", "embedded-hal-async", "embedded-storage-async"]
time = ["dep:embassy-time"]
default = ["time"]
[dependencies]
embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true }
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
"unproven",
] }
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true }
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true }
embedded-storage = "0.3.0"
embedded-storage-async = { version = "0.4.0", optional = true }
nb = "1.0.0"

View File

@ -74,7 +74,21 @@ where
E: embedded_hal_1::spi::Error + 'static,
T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
{
async fn transfer<'a>(&'a mut self, read: &'a mut [u8], write: &'a [u8]) -> Result<(), Self::Error> {
async fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
async fn write(&mut self, data: &[u8]) -> Result<(), Self::Error> {
self.wrapped.write(data)?;
Ok(())
}
async fn read(&mut self, data: &mut [u8]) -> Result<(), Self::Error> {
self.wrapped.transfer(data)?;
Ok(())
}
async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
// Ensure we write the expected bytes
for i in 0..core::cmp::min(read.len(), write.len()) {
read[i] = write[i].clone();
@ -83,38 +97,7 @@ where
Ok(())
}
async fn transfer_in_place<'a>(&'a mut self, _: &'a mut [u8]) -> Result<(), Self::Error> {
todo!()
}
}
impl<T, E> embedded_hal_async::spi::SpiBusFlush for BlockingAsync<T>
where
E: embedded_hal_1::spi::Error + 'static,
T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
{
async fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<T, E> embedded_hal_async::spi::SpiBusWrite<u8> for BlockingAsync<T>
where
E: embedded_hal_1::spi::Error + 'static,
T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
{
async fn write(&mut self, data: &[u8]) -> Result<(), Self::Error> {
self.wrapped.write(data)?;
Ok(())
}
}
impl<T, E> embedded_hal_async::spi::SpiBusRead<u8> for BlockingAsync<T>
where
E: embedded_hal_1::spi::Error + 'static,
T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
{
async fn read(&mut self, data: &mut [u8]) -> Result<(), Self::Error> {
async fn transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Self::Error> {
self.wrapped.transfer(data)?;
Ok(())
}

View File

@ -69,54 +69,39 @@ where
type Error = T::Error;
}
impl<T> embedded_hal_async::spi::SpiBus<u8> for YieldingAsync<T>
impl<T, Word: 'static + Copy> embedded_hal_async::spi::SpiBus<Word> for YieldingAsync<T>
where
T: embedded_hal_async::spi::SpiBus,
{
async fn transfer<'a>(&'a mut self, read: &'a mut [u8], write: &'a [u8]) -> Result<(), Self::Error> {
self.wrapped.transfer(read, write).await?;
yield_now().await;
Ok(())
}
async fn transfer_in_place<'a>(&'a mut self, words: &'a mut [u8]) -> Result<(), Self::Error> {
self.wrapped.transfer_in_place(words).await?;
yield_now().await;
Ok(())
}
}
impl<T> embedded_hal_async::spi::SpiBusFlush for YieldingAsync<T>
where
T: embedded_hal_async::spi::SpiBusFlush,
T: embedded_hal_async::spi::SpiBus<Word>,
{
async fn flush(&mut self) -> Result<(), Self::Error> {
self.wrapped.flush().await?;
yield_now().await;
Ok(())
}
}
impl<T> embedded_hal_async::spi::SpiBusWrite<u8> for YieldingAsync<T>
where
T: embedded_hal_async::spi::SpiBusWrite<u8>,
{
async fn write(&mut self, data: &[u8]) -> Result<(), Self::Error> {
async fn write(&mut self, data: &[Word]) -> Result<(), Self::Error> {
self.wrapped.write(data).await?;
yield_now().await;
Ok(())
}
}
impl<T> embedded_hal_async::spi::SpiBusRead<u8> for YieldingAsync<T>
where
T: embedded_hal_async::spi::SpiBusRead<u8>,
{
async fn read(&mut self, data: &mut [u8]) -> Result<(), Self::Error> {
async fn read(&mut self, data: &mut [Word]) -> Result<(), Self::Error> {
self.wrapped.read(data).await?;
yield_now().await;
Ok(())
}
async fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
self.wrapped.transfer(read, write).await?;
yield_now().await;
Ok(())
}
async fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
self.wrapped.transfer_in_place(words).await?;
yield_now().await;
Ok(())
}
}
///

View File

@ -56,62 +56,6 @@ where
type Error = SpiDeviceError<BUS::Error, CS::Error>;
}
impl<M, BUS, CS> spi::SpiDeviceRead for SpiDevice<'_, M, BUS, CS>
where
M: RawMutex,
BUS: spi::SpiBusRead,
CS: OutputPin,
{
async fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> {
let mut bus = self.bus.lock().await;
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
let op_res: Result<(), BUS::Error> = try {
for buf in operations {
bus.read(buf).await?;
}
};
// On failure, it's important to still flush and deassert CS.
let flush_res = bus.flush().await;
let cs_res = self.cs.set_high();
let op_res = op_res.map_err(SpiDeviceError::Spi)?;
flush_res.map_err(SpiDeviceError::Spi)?;
cs_res.map_err(SpiDeviceError::Cs)?;
Ok(op_res)
}
}
impl<M, BUS, CS> spi::SpiDeviceWrite for SpiDevice<'_, M, BUS, CS>
where
M: RawMutex,
BUS: spi::SpiBusWrite,
CS: OutputPin,
{
async fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> {
let mut bus = self.bus.lock().await;
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
let op_res: Result<(), BUS::Error> = try {
for buf in operations {
bus.write(buf).await?;
}
};
// On failure, it's important to still flush and deassert CS.
let flush_res = bus.flush().await;
let cs_res = self.cs.set_high();
let op_res = op_res.map_err(SpiDeviceError::Spi)?;
flush_res.map_err(SpiDeviceError::Spi)?;
cs_res.map_err(SpiDeviceError::Cs)?;
Ok(op_res)
}
}
impl<M, BUS, CS> spi::SpiDevice for SpiDevice<'_, M, BUS, CS>
where
M: RawMutex,
@ -129,6 +73,12 @@ where
Operation::Write(buf) => bus.write(buf).await?,
Operation::Transfer(read, write) => bus.transfer(read, write).await?,
Operation::TransferInPlace(buf) => bus.transfer_in_place(buf).await?,
#[cfg(not(feature = "time"))]
Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
#[cfg(feature = "time")]
Operation::DelayUs(us) => {
embassy_time::Timer::after(embassy_time::Duration::from_micros(*us as _)).await
}
}
}
};
@ -172,64 +122,6 @@ where
type Error = SpiDeviceError<BUS::Error, CS::Error>;
}
impl<M, BUS, CS> spi::SpiDeviceWrite for SpiDeviceWithConfig<'_, M, BUS, CS>
where
M: RawMutex,
BUS: spi::SpiBusWrite + SetConfig,
CS: OutputPin,
{
async fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> {
let mut bus = self.bus.lock().await;
bus.set_config(&self.config);
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
let op_res: Result<(), BUS::Error> = try {
for buf in operations {
bus.write(buf).await?;
}
};
// On failure, it's important to still flush and deassert CS.
let flush_res = bus.flush().await;
let cs_res = self.cs.set_high();
let op_res = op_res.map_err(SpiDeviceError::Spi)?;
flush_res.map_err(SpiDeviceError::Spi)?;
cs_res.map_err(SpiDeviceError::Cs)?;
Ok(op_res)
}
}
impl<M, BUS, CS> spi::SpiDeviceRead for SpiDeviceWithConfig<'_, M, BUS, CS>
where
M: RawMutex,
BUS: spi::SpiBusRead + SetConfig,
CS: OutputPin,
{
async fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> {
let mut bus = self.bus.lock().await;
bus.set_config(&self.config);
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
let op_res: Result<(), BUS::Error> = try {
for buf in operations {
bus.read(buf).await?;
}
};
// On failure, it's important to still flush and deassert CS.
let flush_res = bus.flush().await;
let cs_res = self.cs.set_high();
let op_res = op_res.map_err(SpiDeviceError::Spi)?;
flush_res.map_err(SpiDeviceError::Spi)?;
cs_res.map_err(SpiDeviceError::Cs)?;
Ok(op_res)
}
}
impl<M, BUS, CS> spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS>
where
M: RawMutex,
@ -248,6 +140,12 @@ where
Operation::Write(buf) => bus.write(buf).await?,
Operation::Transfer(read, write) => bus.transfer(read, write).await?,
Operation::TransferInPlace(buf) => bus.transfer_in_place(buf).await?,
#[cfg(not(feature = "time"))]
Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
#[cfg(feature = "time")]
Operation::DelayUs(us) => {
embassy_time::Timer::after(embassy_time::Duration::from_micros(*us as _)).await
}
}
}
};

View File

@ -22,7 +22,7 @@ use core::cell::RefCell;
use embassy_sync::blocking_mutex::raw::RawMutex;
use embassy_sync::blocking_mutex::Mutex;
use embedded_hal_1::digital::OutputPin;
use embedded_hal_1::spi::{self, Operation, SpiBus, SpiBusRead, SpiBusWrite};
use embedded_hal_1::spi::{self, Operation, SpiBus};
use crate::shared_bus::SpiDeviceError;
use crate::SetConfig;
@ -48,58 +48,6 @@ where
type Error = SpiDeviceError<BUS::Error, CS::Error>;
}
impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceRead for SpiDevice<'_, M, BUS, CS>
where
M: RawMutex,
BUS: SpiBusRead,
CS: OutputPin,
{
fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> {
self.bus.lock(|bus| {
let mut bus = bus.borrow_mut();
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
let op_res = operations.iter_mut().try_for_each(|buf| bus.read(buf));
// On failure, it's important to still flush and deassert CS.
let flush_res = bus.flush();
let cs_res = self.cs.set_high();
let op_res = op_res.map_err(SpiDeviceError::Spi)?;
flush_res.map_err(SpiDeviceError::Spi)?;
cs_res.map_err(SpiDeviceError::Cs)?;
Ok(op_res)
})
}
}
impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceWrite for SpiDevice<'_, M, BUS, CS>
where
M: RawMutex,
BUS: SpiBusWrite,
CS: OutputPin,
{
fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> {
self.bus.lock(|bus| {
let mut bus = bus.borrow_mut();
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
let op_res = operations.iter().try_for_each(|buf| bus.write(buf));
// On failure, it's important to still flush and deassert CS.
let flush_res = bus.flush();
let cs_res = self.cs.set_high();
let op_res = op_res.map_err(SpiDeviceError::Spi)?;
flush_res.map_err(SpiDeviceError::Spi)?;
cs_res.map_err(SpiDeviceError::Cs)?;
Ok(op_res)
})
}
}
impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDevice<'_, M, BUS, CS>
where
M: RawMutex,
@ -116,6 +64,13 @@ where
Operation::Write(buf) => bus.write(buf),
Operation::Transfer(read, write) => bus.transfer(read, write),
Operation::TransferInPlace(buf) => bus.transfer_in_place(buf),
#[cfg(not(feature = "time"))]
Operation::DelayUs(_) => Err(SpiDeviceError::DelayUsNotSupported),
#[cfg(feature = "time")]
Operation::DelayUs(us) => {
embassy_time::block_for(embassy_time::Duration::from_micros(*us as _));
Ok(())
}
});
// On failure, it's important to still flush and deassert CS.
@ -199,58 +154,6 @@ where
type Error = SpiDeviceError<BUS::Error, CS::Error>;
}
impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceRead for SpiDeviceWithConfig<'_, M, BUS, CS>
where
M: RawMutex,
BUS: SpiBusRead + SetConfig,
CS: OutputPin,
{
fn read_transaction(&mut self, operations: &mut [&mut [u8]]) -> Result<(), Self::Error> {
self.bus.lock(|bus| {
let mut bus = bus.borrow_mut();
bus.set_config(&self.config);
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
let op_res = operations.iter_mut().try_for_each(|buf| bus.read(buf));
// On failure, it's important to still flush and deassert CS.
let flush_res = bus.flush();
let cs_res = self.cs.set_high();
let op_res = op_res.map_err(SpiDeviceError::Spi)?;
flush_res.map_err(SpiDeviceError::Spi)?;
cs_res.map_err(SpiDeviceError::Cs)?;
Ok(op_res)
})
}
}
impl<BUS, M, CS> embedded_hal_1::spi::SpiDeviceWrite for SpiDeviceWithConfig<'_, M, BUS, CS>
where
M: RawMutex,
BUS: SpiBusWrite + SetConfig,
CS: OutputPin,
{
fn write_transaction(&mut self, operations: &[&[u8]]) -> Result<(), Self::Error> {
self.bus.lock(|bus| {
let mut bus = bus.borrow_mut();
bus.set_config(&self.config);
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
let op_res = operations.iter().try_for_each(|buf| bus.write(buf));
// On failure, it's important to still flush and deassert CS.
let flush_res = bus.flush();
let cs_res = self.cs.set_high();
let op_res = op_res.map_err(SpiDeviceError::Spi)?;
flush_res.map_err(SpiDeviceError::Spi)?;
cs_res.map_err(SpiDeviceError::Cs)?;
Ok(op_res)
})
}
}
impl<BUS, M, CS> embedded_hal_1::spi::SpiDevice for SpiDeviceWithConfig<'_, M, BUS, CS>
where
M: RawMutex,
@ -268,6 +171,13 @@ where
Operation::Write(buf) => bus.write(buf),
Operation::Transfer(read, write) => bus.transfer(read, write),
Operation::TransferInPlace(buf) => bus.transfer_in_place(buf),
#[cfg(not(feature = "time"))]
Operation::DelayUs(_) => Err(SpiDeviceError::DelayUsNotSupported),
#[cfg(feature = "time")]
Operation::DelayUs(us) => {
embassy_time::block_for(embassy_time::Duration::from_micros(*us as _));
Ok(())
}
});
// On failure, it's important to still flush and deassert CS.

View File

@ -30,11 +30,14 @@ where
/// Error returned by SPI device implementations in this crate.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum SpiDeviceError<BUS, CS> {
/// An operation on the inner SPI bus failed.
Spi(BUS),
/// Setting the value of the Chip Select (CS) pin failed.
Cs(CS),
/// DelayUs operations are not supported when the `time` Cargo feature is not enabled.
DelayUsNotSupported,
}
impl<BUS, CS> spi::Error for SpiDeviceError<BUS, CS>
@ -46,6 +49,7 @@ where
match self {
Self::Spi(e) => e.kind(),
Self::Cs(_) => spi::ErrorKind::Other,
Self::DelayUsNotSupported => spi::ErrorKind::Other,
}
}
}

View File

@ -61,8 +61,8 @@ log = { version = "0.4.14", optional = true }
rtos-trace = { version = "0.1.2", optional = true }
futures-util = { version = "0.3.17", default-features = false }
embassy-macros = { version = "0.2.0", path = "../embassy-macros" }
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true}
embassy-macros = { version = "0.2.0", path = "../embassy-macros" }
embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true}
atomic-polyfill = "1.0.1"
critical-section = "1.1"
static_cell = "1.1"

View File

@ -165,6 +165,9 @@ impl<F: Future + 'static> TaskStorage<F> {
Poll::Ready(_) => {
this.future.drop_in_place();
this.raw.state.fetch_and(!STATE_SPAWNED, Ordering::AcqRel);
#[cfg(feature = "integrated-timers")]
this.raw.expires_at.set(Instant::MAX);
}
Poll::Pending => {}
}

View File

@ -161,7 +161,7 @@ pub trait Peripheral: Sized {
}
}
impl<'b, T: Deref> Peripheral for T
impl<'b, T: DerefMut> Peripheral for T
where
T::Target: Peripheral,
{

View File

@ -20,11 +20,11 @@ defmt = ["dep:defmt", "lorawan-device/defmt"]
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
embassy-time = { version = "0.1.0", path = "../embassy-time" }
embassy-time = { version = "0.1.2", path = "../embassy-time" }
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
embedded-hal-async = { version = "=0.2.0-alpha.1" }
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
embedded-hal-async = { version = "=0.2.0-alpha.2" }
embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false }
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
embedded-hal = { version = "0.2", features = ["unproven"] }
@ -32,3 +32,6 @@ bit_field = { version = "0.10" }
lora-phy = { version = "1" }
lorawan-device = { version = "0.10.0", default-features = false, features = ["async"] }
[patch.crates-io]
lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" }

View File

@ -7,13 +7,13 @@ edition = "2021"
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
embassy-time = { version = "0.1.0", path = "../embassy-time" }
embassy-time = { version = "0.1.2", path = "../embassy-time" }
embassy-sync = { version = "0.2.0", path = "../embassy-sync"}
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
embedded-hal = { version = "1.0.0-alpha.10" }
embedded-hal-async = { version = "=0.2.0-alpha.1" }
embedded-hal = { version = "1.0.0-alpha.11" }
embedded-hal-async = { version = "=0.2.0-alpha.2" }
noproto = { git="https://github.com/embassy-rs/noproto", default-features = false, features = ["derive"] }
#noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] }

View File

@ -54,7 +54,9 @@ impl<'a> Control<'a> {
})),
};
let resp = self.ioctl(req).await;
let proto::CtrlMsgPayload::RespConnectAp(resp) = resp.payload.unwrap() else { panic!("unexpected resp") };
let proto::CtrlMsgPayload::RespConnectAp(resp) = resp.payload.unwrap() else {
panic!("unexpected resp")
};
debug!("======= {:?}", Debug2Format(&resp));
assert_eq!(resp.resp, 0);
self.state_ch.set_link_state(LinkState::Up);
@ -71,7 +73,9 @@ impl<'a> Control<'a> {
)),
};
let resp = self.ioctl(req).await;
let proto::CtrlMsgPayload::RespGetMacAddress(resp) = resp.payload.unwrap() else { panic!("unexpected resp") };
let proto::CtrlMsgPayload::RespGetMacAddress(resp) = resp.payload.unwrap() else {
panic!("unexpected resp")
};
assert_eq!(resp.resp, 0);
// WHY IS THIS A STRING? WHYYYY
@ -100,7 +104,9 @@ impl<'a> Control<'a> {
payload: Some(proto::CtrlMsgPayload::ReqSetWifiMode(proto::CtrlMsgReqSetMode { mode })),
};
let resp = self.ioctl(req).await;
let proto::CtrlMsgPayload::RespSetWifiMode(resp) = resp.payload.unwrap() else { panic!("unexpected resp") };
let proto::CtrlMsgPayload::RespSetWifiMode(resp) = resp.payload.unwrap() else {
panic!("unexpected resp")
};
assert_eq!(resp.resp, 0);
}

View File

@ -311,14 +311,14 @@ where
fn handle_event(&self, data: &[u8]) {
let Ok(event) = noproto::read::<CtrlMsg>(data) else {
warn!("failed to parse event");
return
return;
};
debug!("event: {:?}", &event);
let Some(payload) = &event.payload else {
warn!("event without payload?");
return
return;
};
match payload {

View File

@ -8,11 +8,11 @@ license = "MIT OR Apache-2.0"
edition = "2021"
[dependencies]
embedded-hal = { version = "1.0.0-alpha.10" }
embedded-hal-async = { version = "=0.2.0-alpha.1" }
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
embassy-time = { version = "0.1.0" }
embassy-futures = { version = "0.1.0" }
embedded-hal = { version = "1.0.0-alpha.11" }
embedded-hal-async = { version = "=0.2.0-alpha.2" }
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
embassy-time = { version = "0.1.2", path = "../embassy-time" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
defmt = { version = "0.3", optional = true }
[package.metadata.embassy_docs]

View File

@ -22,7 +22,11 @@ impl<SPI: SpiDevice> SpiInterface<SPI> {
let address_phase = address.to_be_bytes();
let control_phase = [(block as u8) << 3 | 0b0000_0100];
let data_phase = data;
let operations = &[&address_phase[..], &control_phase, &data_phase];
self.0.write_transaction(operations).await
let operations = &mut [
Operation::Write(&address_phase[..]),
Operation::Write(&control_phase),
Operation::Write(&data_phase),
];
self.0.transaction(operations).await
}
}

View File

@ -50,7 +50,7 @@ smoltcp = { version = "0.10.0", default-features = false, features = [
] }
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
embassy-time = { version = "0.1.0", path = "../embassy-time" }
embassy-time = { version = "0.1.2", path = "../embassy-time" }
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
embedded-io = { version = "0.4.0", optional = true }

View File

@ -34,7 +34,7 @@ use smoltcp::socket::dhcpv4::{self, RetryConfig};
pub use smoltcp::wire::IpListenEndpoint;
#[cfg(feature = "medium-ethernet")]
pub use smoltcp::wire::{EthernetAddress, HardwareAddress};
pub use smoltcp::wire::{IpAddress, IpCidr};
pub use smoltcp::wire::{IpAddress, IpCidr, IpEndpoint};
#[cfg(feature = "proto-ipv4")]
pub use smoltcp::wire::{Ipv4Address, Ipv4Cidr};
#[cfg(feature = "proto-ipv6")]

View File

@ -3,7 +3,7 @@
use core::cell::RefCell;
use core::future::poll_fn;
use core::mem;
use core::task::Poll;
use core::task::{Context, Poll};
use embassy_net_driver::Driver;
use smoltcp::iface::{Interface, SocketHandle};
@ -102,37 +102,61 @@ impl<'a> UdpSocket<'a> {
///
/// Returns the number of bytes received and the remote endpoint.
pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), Error> {
poll_fn(move |cx| {
self.with_mut(|s, _| match s.recv_slice(buf) {
Ok((n, meta)) => Poll::Ready(Ok((n, meta.endpoint))),
// No data ready
Err(udp::RecvError::Exhausted) => {
s.register_recv_waker(cx.waker());
Poll::Pending
}
})
poll_fn(move |cx| self.poll_recv_from(buf, cx)).await
}
/// Receive a datagram.
///
/// When no datagram is available, this method will return `Poll::Pending` and
/// register the current task to be notified when a datagram is received.
///
/// When a datagram is received, this method will return `Poll::Ready` with the
/// number of bytes received and the remote endpoint.
pub fn poll_recv_from(&self, buf: &mut [u8], cx: &mut Context<'_>) -> Poll<Result<(usize, IpEndpoint), Error>> {
self.with_mut(|s, _| match s.recv_slice(buf) {
Ok((n, meta)) => Poll::Ready(Ok((n, meta.endpoint))),
// No data ready
Err(udp::RecvError::Exhausted) => {
s.register_recv_waker(cx.waker());
Poll::Pending
}
})
.await
}
/// Send a datagram to the specified remote endpoint.
///
/// This method will wait until the datagram has been sent.
///
/// When the remote endpoint is not reachable, this method will return `Err(Error::NoRoute)`
pub async fn send_to<T>(&self, buf: &[u8], remote_endpoint: T) -> Result<(), Error>
where
T: Into<IpEndpoint>,
{
let remote_endpoint = remote_endpoint.into();
poll_fn(move |cx| {
self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) {
// Entire datagram has been sent
Ok(()) => Poll::Ready(Ok(())),
Err(udp::SendError::BufferFull) => {
s.register_send_waker(cx.waker());
Poll::Pending
}
Err(udp::SendError::Unaddressable) => Poll::Ready(Err(Error::NoRoute)),
})
let remote_endpoint: IpEndpoint = remote_endpoint.into();
poll_fn(move |cx| self.poll_send_to(buf, remote_endpoint, cx)).await
}
/// Send a datagram to the specified remote endpoint.
///
/// When the datagram has been sent, this method will return `Poll::Ready(Ok())`.
///
/// When the socket's send buffer is full, this method will return `Poll::Pending`
/// and register the current task to be notified when the buffer has space available.
///
/// When the remote endpoint is not reachable, this method will return `Poll::Ready(Err(Error::NoRoute))`.
pub fn poll_send_to<T>(&self, buf: &[u8], remote_endpoint: T, cx: &mut Context<'_>) -> Poll<Result<(), Error>>
where
T: Into<IpEndpoint>,
{
self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) {
// Entire datagram has been sent
Ok(()) => Poll::Ready(Ok(())),
Err(udp::SendError::BufferFull) => {
s.register_send_waker(cx.waker());
Poll::Pending
}
Err(udp::SendError::Unaddressable) => Poll::Ready(Err(Error::NoRoute)),
})
.await
}
/// Returns the local endpoint of the socket.

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-nrf-v$VERSION/embassy-nrf/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nrf/src/"
features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "gpiote", "time-driver-rtc1"]
features = ["nightly", "time", "defmt", "unstable-pac", "unstable-traits", "gpiote", "time-driver-rtc1"]
flavors = [
{ regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" },
{ regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" },
@ -91,22 +91,22 @@ _dppi = []
_gpio-p1 = []
[dependencies]
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true }
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-3"] }
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true}
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true}
embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true}
embedded-io = { version = "0.4.0", features = ["async"], optional = true }
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
cortex-m-rt = ">=0.6.15,<0.8"
cortex-m = "0.7.6"
futures = { version = "0.3.17", default-features = false }
futures = { version = "0.3.17", default-features = false }
critical-section = "1.1"
rand_core = "0.6.3"
fixed = "1.10.0"
@ -114,13 +114,13 @@ embedded-storage = "0.3.0"
embedded-storage-async = { version = "0.4.0", optional = true }
cfg-if = "1.0.0"
nrf52805-pac = { version = "0.12.0", optional = true }
nrf52810-pac = { version = "0.12.0", optional = true }
nrf52811-pac = { version = "0.12.0", optional = true }
nrf52820-pac = { version = "0.12.0", optional = true }
nrf52832-pac = { version = "0.12.0", optional = true }
nrf52833-pac = { version = "0.12.0", optional = true }
nrf52840-pac = { version = "0.12.0", optional = true }
nrf52805-pac = { version = "0.12.0", optional = true }
nrf52810-pac = { version = "0.12.0", optional = true }
nrf52811-pac = { version = "0.12.0", optional = true }
nrf52820-pac = { version = "0.12.0", optional = true }
nrf52832-pac = { version = "0.12.0", optional = true }
nrf52833-pac = { version = "0.12.0", optional = true }
nrf52840-pac = { version = "0.12.0", optional = true }
nrf5340-app-pac = { version = "0.12.0", optional = true }
nrf5340-net-pac = { version = "0.12.0", optional = true }
nrf9160-pac = { version = "0.12.0", optional = true }

View File

@ -221,7 +221,7 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> {
}
/// Returns the IN event, for use with PPI.
pub fn event_in(&self) -> Event {
pub fn event_in(&self) -> Event<'d> {
let g = regs();
Event::from_reg(&g.events_in[self.ch.number()])
}
@ -292,21 +292,21 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> {
}
/// Returns the OUT task, for use with PPI.
pub fn task_out(&self) -> Task {
pub fn task_out(&self) -> Task<'d> {
let g = regs();
Task::from_reg(&g.tasks_out[self.ch.number()])
}
/// Returns the CLR task, for use with PPI.
#[cfg(not(feature = "nrf51"))]
pub fn task_clr(&self) -> Task {
pub fn task_clr(&self) -> Task<'d> {
let g = regs();
Task::from_reg(&g.tasks_clr[self.ch.number()])
}
/// Returns the SET task, for use with PPI.
#[cfg(not(feature = "nrf51"))]
pub fn task_set(&self) -> Task {
pub fn task_set(&self) -> Task<'d> {
let g = regs();
Task::from_reg(&g.tasks_set[self.ch.number()])
}

View File

@ -12,14 +12,14 @@ pub(crate) fn regs() -> &'static pac::dppic::RegisterBlock {
impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> {
/// Configure PPI channel to trigger `task` on `event`.
pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event, task: Task) -> Self {
pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event<'d>, task: Task<'d>) -> Self {
Ppi::new_many_to_many(ch, [event], [task])
}
}
impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> {
/// Configure PPI channel to trigger both `task1` and `task2` on `event`.
pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event, task1: Task, task2: Task) -> Self {
pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event<'d>, task1: Task<'d>, task2: Task<'d>) -> Self {
Ppi::new_many_to_many(ch, [event], [task1, task2])
}
}
@ -30,8 +30,8 @@ impl<'d, C: ConfigurableChannel, const EVENT_COUNT: usize, const TASK_COUNT: usi
/// Configure a DPPI channel to trigger all `tasks` when any of the `events` fires.
pub fn new_many_to_many(
ch: impl Peripheral<P = C> + 'd,
events: [Event; EVENT_COUNT],
tasks: [Task; TASK_COUNT],
events: [Event<'d>; EVENT_COUNT],
tasks: [Task<'d>; TASK_COUNT],
) -> Self {
into_ref!(ch);

View File

@ -15,6 +15,7 @@
//! many tasks and events, but any single task or event can only be coupled with one channel.
//!
use core::marker::PhantomData;
use core::ptr::NonNull;
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
@ -30,9 +31,9 @@ pub(crate) use _version::*;
pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> {
ch: PeripheralRef<'d, C>,
#[cfg(feature = "_dppi")]
events: [Event; EVENT_COUNT],
events: [Event<'d>; EVENT_COUNT],
#[cfg(feature = "_dppi")]
tasks: [Task; TASK_COUNT],
tasks: [Task<'d>; TASK_COUNT],
}
/// PPI channel group driver.
@ -95,7 +96,7 @@ impl<'d, G: Group> PpiGroup<'d, G> {
/// Get a reference to the "enable all" task.
///
/// When triggered, it will enable all the channels in this group.
pub fn task_enable_all(&self) -> Task {
pub fn task_enable_all(&self) -> Task<'d> {
let n = self.g.number();
Task::from_reg(&regs().tasks_chg[n].en)
}
@ -103,7 +104,7 @@ impl<'d, G: Group> PpiGroup<'d, G> {
/// Get a reference to the "disable all" task.
///
/// When triggered, it will disable all the channels in this group.
pub fn task_disable_all(&self) -> Task {
pub fn task_disable_all(&self) -> Task<'d> {
let n = self.g.number();
Task::from_reg(&regs().tasks_chg[n].dis)
}
@ -125,16 +126,16 @@ const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::<u32>();
/// When a task is subscribed to a PPI channel, it will run when the channel is triggered by
/// a published event.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Task(NonNull<u32>);
pub struct Task<'d>(NonNull<u32>, PhantomData<&'d ()>);
impl Task {
impl<'d> Task<'d> {
/// Create a new `Task` from a task register pointer
///
/// # Safety
///
/// `ptr` must be a pointer to a valid `TASKS_*` register from an nRF peripheral.
pub unsafe fn new_unchecked(ptr: NonNull<u32>) -> Self {
Self(ptr)
Self(ptr, PhantomData)
}
/// Triggers this task.
@ -143,7 +144,10 @@ impl Task {
}
pub(crate) fn from_reg<T>(reg: &T) -> Self {
Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
Self(
unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) },
PhantomData,
)
}
/// Address of subscription register for this task.
@ -156,26 +160,29 @@ impl Task {
/// # Safety
///
/// NonNull is not send, but this event is only allowed to point at registers and those exist in any context on the same core.
unsafe impl Send for Task {}
unsafe impl Send for Task<'_> {}
/// Represents an event that a peripheral can publish.
///
/// An event can be set to publish on a PPI channel when the event happens.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Event(NonNull<u32>);
pub struct Event<'d>(NonNull<u32>, PhantomData<&'d ()>);
impl Event {
impl<'d> Event<'d> {
/// Create a new `Event` from an event register pointer
///
/// # Safety
///
/// `ptr` must be a pointer to a valid `EVENTS_*` register from an nRF peripheral.
pub unsafe fn new_unchecked(ptr: NonNull<u32>) -> Self {
Self(ptr)
Self(ptr, PhantomData)
}
pub(crate) fn from_reg<T>(reg: &T) -> Self {
Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
pub(crate) fn from_reg<T>(reg: &'d T) -> Self {
Self(
unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) },
PhantomData,
)
}
/// Describes whether this Event is currently in a triggered state.
@ -198,7 +205,7 @@ impl Event {
/// # Safety
///
/// NonNull is not send, but this event is only allowed to point at registers and those exist in any context on the same core.
unsafe impl Send for Event {}
unsafe impl Send for Event<'_> {}
// ======================
// traits

View File

@ -3,12 +3,12 @@ use embassy_hal_common::into_ref;
use super::{Channel, ConfigurableChannel, Event, Ppi, StaticChannel, Task};
use crate::{pac, Peripheral};
impl Task {
impl<'d> Task<'d> {
fn reg_val(&self) -> u32 {
self.0.as_ptr() as _
}
}
impl Event {
impl<'d> Event<'d> {
fn reg_val(&self) -> u32 {
self.0.as_ptr() as _
}
@ -34,7 +34,7 @@ impl<'d, C: StaticChannel> Ppi<'d, C, 0, 1> {
impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> {
/// Configure PPI channel to trigger `task` on `event`.
pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event, task: Task) -> Self {
pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event<'d>, task: Task<'d>) -> Self {
into_ref!(ch);
let r = regs();
@ -49,7 +49,7 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> {
#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task
impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> {
/// Configure PPI channel to trigger both `task1` and `task2` on `event`.
pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event, task1: Task, task2: Task) -> Self {
pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event<'d>, task1: Task<'d>, task2: Task<'d>) -> Self {
into_ref!(ch);
let r = regs();

View File

@ -181,7 +181,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
/// Returns reference to `Stopped` event endpoint for PPI.
#[inline(always)]
pub fn event_stopped(&self) -> Event {
pub fn event_stopped(&self) -> Event<'d> {
let r = T::regs();
Event::from_reg(&r.events_stopped)
@ -189,7 +189,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
/// Returns reference to `LoopsDone` event endpoint for PPI.
#[inline(always)]
pub fn event_loops_done(&self) -> Event {
pub fn event_loops_done(&self) -> Event<'d> {
let r = T::regs();
Event::from_reg(&r.events_loopsdone)
@ -197,7 +197,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
/// Returns reference to `PwmPeriodEnd` event endpoint for PPI.
#[inline(always)]
pub fn event_pwm_period_end(&self) -> Event {
pub fn event_pwm_period_end(&self) -> Event<'d> {
let r = T::regs();
Event::from_reg(&r.events_pwmperiodend)
@ -205,7 +205,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
/// Returns reference to `Seq0 End` event endpoint for PPI.
#[inline(always)]
pub fn event_seq_end(&self) -> Event {
pub fn event_seq_end(&self) -> Event<'d> {
let r = T::regs();
Event::from_reg(&r.events_seqend[0])
@ -213,7 +213,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
/// Returns reference to `Seq1 End` event endpoint for PPI.
#[inline(always)]
pub fn event_seq1_end(&self) -> Event {
pub fn event_seq1_end(&self) -> Event<'d> {
let r = T::regs();
Event::from_reg(&r.events_seqend[1])
@ -221,7 +221,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
/// Returns reference to `Seq0 Started` event endpoint for PPI.
#[inline(always)]
pub fn event_seq0_started(&self) -> Event {
pub fn event_seq0_started(&self) -> Event<'d> {
let r = T::regs();
Event::from_reg(&r.events_seqstarted[0])
@ -229,7 +229,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
/// Returns reference to `Seq1 Started` event endpoint for PPI.
#[inline(always)]
pub fn event_seq1_started(&self) -> Event {
pub fn event_seq1_started(&self) -> Event<'d> {
let r = T::regs();
Event::from_reg(&r.events_seqstarted[1])
@ -240,7 +240,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
///
/// Interacting with the sequence while it runs puts it in an unknown state
#[inline(always)]
pub unsafe fn task_start_seq0(&self) -> Task {
pub unsafe fn task_start_seq0(&self) -> Task<'d> {
let r = T::regs();
Task::from_reg(&r.tasks_seqstart[0])
@ -251,7 +251,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
///
/// Interacting with the sequence while it runs puts it in an unknown state
#[inline(always)]
pub unsafe fn task_start_seq1(&self) -> Task {
pub unsafe fn task_start_seq1(&self) -> Task<'d> {
let r = T::regs();
Task::from_reg(&r.tasks_seqstart[1])
@ -262,7 +262,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
///
/// Interacting with the sequence while it runs puts it in an unknown state
#[inline(always)]
pub unsafe fn task_next_step(&self) -> Task {
pub unsafe fn task_next_step(&self) -> Task<'d> {
let r = T::regs();
Task::from_reg(&r.tasks_nextstep)
@ -273,7 +273,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
///
/// Interacting with the sequence while it runs puts it in an unknown state
#[inline(always)]
pub unsafe fn task_stop(&self) -> Task {
pub unsafe fn task_stop(&self) -> Task<'d> {
let r = T::regs();
Task::from_reg(&r.tasks_stop)

View File

@ -320,7 +320,9 @@ impl<'d, const N: usize> Saadc<'d, N> {
timer.cc(0).write(sample_counter);
timer.cc(0).short_compare_clear();
let mut sample_ppi = Ppi::new_one_to_one(ppi_ch2, timer.cc(0).event_compare(), Task::from_reg(&r.tasks_sample));
let timer_cc = timer.cc(0);
let mut sample_ppi = Ppi::new_one_to_one(ppi_ch2, timer_cc.event_compare(), Task::from_reg(&r.tasks_sample));
timer.start();

View File

@ -468,25 +468,19 @@ mod eh1 {
type Error = Error;
}
impl<'d, T: Instance> embedded_hal_1::spi::SpiBusFlush for Spim<'d, T> {
impl<'d, T: Instance> embedded_hal_1::spi::SpiBus<u8> for Spim<'d, T> {
fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<'d, T: Instance> embedded_hal_1::spi::SpiBusRead<u8> for Spim<'d, T> {
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_transfer(words, &[])
}
}
impl<'d, T: Instance> embedded_hal_1::spi::SpiBusWrite<u8> for Spim<'d, T> {
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(words)
}
}
impl<'d, T: Instance> embedded_hal_1::spi::SpiBus<u8> for Spim<'d, T> {
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
self.blocking_transfer(read, write)
}
@ -502,25 +496,19 @@ mod eha {
use super::*;
impl<'d, T: Instance> embedded_hal_async::spi::SpiBusFlush for Spim<'d, T> {
impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spim<'d, T> {
async fn flush(&mut self) -> Result<(), Error> {
Ok(())
}
}
impl<'d, T: Instance> embedded_hal_async::spi::SpiBusRead<u8> for Spim<'d, T> {
async fn read(&mut self, words: &mut [u8]) -> Result<(), Error> {
self.read(words).await
}
}
impl<'d, T: Instance> embedded_hal_async::spi::SpiBusWrite<u8> for Spim<'d, T> {
async fn write(&mut self, data: &[u8]) -> Result<(), Error> {
self.write(data).await
}
}
impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spim<'d, T> {
async fn transfer(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> {
self.transfer(rx, tx).await
}

View File

@ -168,21 +168,21 @@ impl<'d, T: Instance> Timer<'d, T> {
/// Returns the START task, for use with PPI.
///
/// When triggered, this task starts the timer.
pub fn task_start(&self) -> Task {
pub fn task_start(&self) -> Task<'d> {
Task::from_reg(&T::regs().tasks_start)
}
/// Returns the STOP task, for use with PPI.
///
/// When triggered, this task stops the timer.
pub fn task_stop(&self) -> Task {
pub fn task_stop(&self) -> Task<'d> {
Task::from_reg(&T::regs().tasks_stop)
}
/// Returns the CLEAR task, for use with PPI.
///
/// When triggered, this task resets the timer's counter to 0.
pub fn task_clear(&self) -> Task {
pub fn task_clear(&self) -> Task<'d> {
Task::from_reg(&T::regs().tasks_clear)
}
@ -190,7 +190,7 @@ impl<'d, T: Instance> Timer<'d, T> {
///
/// When triggered, this task increments the timer's counter by 1.
/// Only works in counter mode.
pub fn task_count(&self) -> Task {
pub fn task_count(&self) -> Task<'d> {
Task::from_reg(&T::regs().tasks_count)
}
@ -258,14 +258,14 @@ impl<'d, T: Instance> Cc<'d, T> {
/// Returns this CC register's CAPTURE task, for use with PPI.
///
/// When triggered, this task will capture the current value of the timer's counter in this register.
pub fn task_capture(&self) -> Task {
pub fn task_capture(&self) -> Task<'d> {
Task::from_reg(&T::regs().tasks_capture)
}
/// Returns this CC register's COMPARE event, for use with PPI.
///
/// This event will fire when the timer's counter reaches the value in this CC register.
pub fn event_compare(&self) -> Event {
pub fn event_compare(&self) -> Event<'d> {
Event::from_reg(&T::regs().events_compare[self.n])
}

View File

@ -56,7 +56,7 @@ unstable-traits = ["embedded-hal-1", "embedded-hal-nb"]
[dependencies]
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
embassy-time = { version = "0.1.2", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-2"] }
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
@ -79,9 +79,9 @@ fixed = "1.23.1"
rp-pac = { version = "6" }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true}
embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true}
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true}
embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true}
embedded-hal-nb = { version = "=1.0.0-alpha.3", optional = true}
paste = "1.0"
pio-proc = {version= "0.2" }

View File

@ -3,22 +3,17 @@ use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
use embassy_hal_common::{into_ref, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;
use embedded_hal_02::adc::{Channel, OneShot};
use crate::gpio::Pin;
use crate::gpio::sealed::Pin as GpioPin;
use crate::gpio::{self, AnyPin, Pull};
use crate::interrupt::typelevel::Binding;
use crate::interrupt::InterruptExt;
use crate::peripherals::ADC;
use crate::{interrupt, pac, peripherals, Peripheral};
static WAKER: AtomicWaker = AtomicWaker::new();
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum Error {
// No errors for now
}
static WAKER: AtomicWaker = AtomicWaker::new();
#[non_exhaustive]
pub struct Config {}
@ -28,11 +23,65 @@ impl Default for Config {
Self {}
}
}
pub struct Adc<'d> {
phantom: PhantomData<&'d ADC>,
pub struct Pin<'p> {
pin: PeripheralRef<'p, AnyPin>,
}
impl<'d> Adc<'d> {
impl<'p> Pin<'p> {
pub fn new(pin: impl Peripheral<P = impl AdcPin + 'p> + 'p, pull: Pull) -> Self {
into_ref!(pin);
pin.pad_ctrl().modify(|w| {
// manual says:
//
// > When using an ADC input shared with a GPIO pin, the pins
// > digital functions must be disabled by setting IE low and OD
// > high in the pins pad control register
w.set_ie(false);
w.set_od(true);
w.set_pue(pull == Pull::Up);
w.set_pde(pull == Pull::Down);
});
Self { pin: pin.map_into() }
}
fn channel(&self) -> u8 {
// this requires adc pins to be sequential and matching the adc channels,
// which is the case for rp2040
self.pin._pin() - 26
}
}
impl<'d> Drop for Pin<'d> {
fn drop(&mut self) {
self.pin.pad_ctrl().modify(|w| {
w.set_ie(true);
w.set_od(false);
w.set_pue(false);
w.set_pde(true);
});
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
ConversionFailed,
}
pub trait Mode {}
pub struct Async;
impl Mode for Async {}
pub struct Blocking;
impl Mode for Blocking {}
pub struct Adc<'d, M: Mode> {
phantom: PhantomData<(&'d ADC, M)>,
}
impl<'d, M: Mode> Adc<'d, M> {
#[inline]
fn regs() -> pac::adc::Adc {
pac::ADC
@ -45,11 +94,7 @@ impl<'d> Adc<'d> {
ret
}
pub fn new(
_inner: impl Peripheral<P = ADC> + 'd,
_irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>,
_config: Config,
) -> Self {
fn setup() {
let reset = Self::reset();
crate::reset::reset(reset);
crate::reset::unreset_wait(reset);
@ -58,6 +103,43 @@ impl<'d> Adc<'d> {
r.cs().write(|w| w.set_en(true));
// Wait for ADC ready
while !r.cs().read().ready() {}
}
fn sample_blocking(channel: u8) -> Result<u16, Error> {
let r = Self::regs();
r.cs().modify(|w| {
w.set_ainsel(channel);
w.set_start_once(true);
w.set_err(true);
});
while !r.cs().read().ready() {}
match r.cs().read().err() {
true => Err(Error::ConversionFailed),
false => Ok(r.result().read().result().into()),
}
}
pub fn blocking_read(&mut self, pin: &mut Pin) -> Result<u16, Error> {
Self::sample_blocking(pin.channel())
}
pub fn blocking_read_temperature(&mut self) -> Result<u16, Error> {
let r = Self::regs();
r.cs().modify(|w| w.set_ts_en(true));
while !r.cs().read().ready() {}
let result = Self::sample_blocking(4);
r.cs().modify(|w| w.set_ts_en(false));
result
}
}
impl<'d> Adc<'d, Async> {
pub fn new(
_inner: impl Peripheral<P = ADC> + 'd,
_irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>,
_config: Config,
) -> Self {
Self::setup();
// Setup IRQ
interrupt::ADC_IRQ_FIFO.unpend();
@ -80,76 +162,42 @@ impl<'d> Adc<'d> {
.await;
}
pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 {
async fn sample_async(channel: u8) -> Result<u16, Error> {
let r = Self::regs();
// disable pull-down and pull-up resistors
// pull-down resistors are enabled by default
pin.pad_ctrl().modify(|w| {
w.set_ie(true);
let (pu, pd) = (false, false);
w.set_pue(pu);
w.set_pde(pd);
});
r.cs().modify(|w| {
w.set_ainsel(PIN::channel());
w.set_start_once(true)
w.set_ainsel(channel);
w.set_start_once(true);
w.set_err(true);
});
Self::wait_for_ready().await;
r.result().read().result().into()
match r.cs().read().err() {
true => Err(Error::ConversionFailed),
false => Ok(r.result().read().result().into()),
}
}
pub async fn read_temperature(&mut self) -> u16 {
pub async fn read(&mut self, pin: &mut Pin<'_>) -> Result<u16, Error> {
Self::sample_async(pin.channel()).await
}
pub async fn read_temperature(&mut self) -> Result<u16, Error> {
let r = Self::regs();
r.cs().modify(|w| w.set_ts_en(true));
if !r.cs().read().ready() {
Self::wait_for_ready().await;
}
r.cs().modify(|w| {
w.set_ainsel(4);
w.set_start_once(true)
});
Self::wait_for_ready().await;
r.result().read().result().into()
}
pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 {
let r = Self::regs();
pin.pad_ctrl().modify(|w| {
w.set_ie(true);
let (pu, pd) = (false, false);
w.set_pue(pu);
w.set_pde(pd);
});
r.cs().modify(|w| {
w.set_ainsel(PIN::channel());
w.set_start_once(true)
});
while !r.cs().read().ready() {}
r.result().read().result().into()
}
pub fn blocking_read_temperature(&mut self) -> u16 {
let r = Self::regs();
r.cs().modify(|w| w.set_ts_en(true));
while !r.cs().read().ready() {}
r.cs().modify(|w| {
w.set_ainsel(4);
w.set_start_once(true)
});
while !r.cs().read().ready() {}
r.result().read().result().into()
let result = Self::sample_async(4).await;
r.cs().modify(|w| w.set_ts_en(false));
result
}
}
macro_rules! impl_pin {
($pin:ident, $channel:expr) => {
impl Channel<Adc<'static>> for peripherals::$pin {
type ID = u8;
fn channel() -> u8 {
$channel
}
}
};
impl<'d> Adc<'d, Blocking> {
pub fn new_blocking(_inner: impl Peripheral<P = ADC> + 'd, _config: Config) -> Self {
Self::setup();
Self { phantom: PhantomData }
}
}
pub struct InterruptHandler {
@ -158,24 +206,33 @@ pub struct InterruptHandler {
impl interrupt::typelevel::Handler<interrupt::typelevel::ADC_IRQ_FIFO> for InterruptHandler {
unsafe fn on_interrupt() {
let r = Adc::regs();
let r = Adc::<Async>::regs();
r.inte().write(|w| w.set_fifo(false));
WAKER.wake();
}
}
mod sealed {
pub trait AdcPin: crate::gpio::sealed::Pin {
fn channel(&mut self) -> u8;
}
}
pub trait AdcPin: sealed::AdcPin + gpio::Pin {}
macro_rules! impl_pin {
($pin:ident, $channel:expr) => {
impl sealed::AdcPin for peripherals::$pin {
fn channel(&mut self) -> u8 {
$channel
}
}
impl AdcPin for peripherals::$pin {}
};
}
impl_pin!(PIN_26, 0);
impl_pin!(PIN_27, 1);
impl_pin!(PIN_28, 2);
impl_pin!(PIN_29, 3);
impl<WORD, PIN> OneShot<Adc<'static>, WORD, PIN> for Adc<'static>
where
WORD: From<u16>,
PIN: Channel<Adc<'static>, ID = u8> + Pin,
{
type Error = ();
fn read(&mut self, pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
Ok(self.blocking_read(pin).into())
}
}

View File

@ -308,6 +308,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
// - QSPI (we're using it to run this code!)
// - PLLs (it may be suicide if that's what's clocking us)
// - USB, SYSCFG (breaks usb-to-swd on core1)
// - RTC (else there would be no more time...)
let mut peris = reset::ALL_PERIPHERALS;
peris.set_io_qspi(false);
// peris.set_io_bank0(false); // might be suicide if we're clocked from gpin
@ -317,6 +318,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
// TODO investigate if usb should be unreset here
peris.set_usbctrl(false);
peris.set_syscfg(false);
peris.set_rtc(false);
reset::reset(peris);
// Disable resus that may be enabled from previous software

View File

@ -41,7 +41,7 @@ impl From<Level> for bool {
}
/// Represents a pull setting for an input.
#[derive(Debug, Eq, PartialEq)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Pull {
None,
Up,
@ -566,13 +566,13 @@ impl<'d, T: Pin> Flex<'d, T> {
/// Is the output level high?
#[inline]
pub fn is_set_high(&self) -> bool {
(self.pin.sio_out().value().read() & self.bit()) == 0
!self.is_set_low()
}
/// Is the output level low?
#[inline]
pub fn is_set_low(&self) -> bool {
!self.is_set_high()
(self.pin.sio_out().value().read() & self.bit()) == 0
}
/// What level output is set to

View File

@ -252,7 +252,6 @@ pub fn init(config: config::Config) -> Peripherals {
#[cfg(feature = "time-driver")]
timer::init();
dma::init();
pio::init();
gpio::init();
}

View File

@ -16,12 +16,12 @@ use pio::{SideSet, Wrap};
use crate::dma::{Channel, Transfer, Word};
use crate::gpio::sealed::Pin as SealedPin;
use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate};
use crate::interrupt::InterruptExt;
use crate::interrupt::typelevel::{Binding, Handler, Interrupt};
use crate::pac::dma::vals::TreqSel;
use crate::relocate::RelocatedProgram;
use crate::{interrupt, pac, peripherals, pio_instr_util, RegExt};
use crate::{pac, peripherals, pio_instr_util, RegExt};
struct Wakers([AtomicWaker; 12]);
pub struct Wakers([AtomicWaker; 12]);
impl Wakers {
#[inline(always)]
@ -38,10 +38,6 @@ impl Wakers {
}
}
const NEW_AW: AtomicWaker = AtomicWaker::new();
const PIO_WAKERS_INIT: Wakers = Wakers([NEW_AW; 12]);
static WAKERS: [Wakers; 2] = [PIO_WAKERS_INIT; 2];
#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
@ -85,42 +81,20 @@ const RXNEMPTY_MASK: u32 = 1 << 0;
const TXNFULL_MASK: u32 = 1 << 4;
const SMIRQ_MASK: u32 = 1 << 8;
#[cfg(feature = "rt")]
#[interrupt]
fn PIO0_IRQ_0() {
use crate::pac;
let ints = pac::PIO0.irqs(0).ints().read().0;
for bit in 0..12 {
if ints & (1 << bit) != 0 {
WAKERS[0].0[bit].wake();
}
}
pac::PIO0.irqs(0).inte().write_clear(|m| m.0 = ints);
pub struct InterruptHandler<PIO: Instance> {
_pio: PhantomData<PIO>,
}
#[cfg(feature = "rt")]
#[interrupt]
fn PIO1_IRQ_0() {
use crate::pac;
let ints = pac::PIO1.irqs(0).ints().read().0;
for bit in 0..12 {
if ints & (1 << bit) != 0 {
WAKERS[1].0[bit].wake();
impl<PIO: Instance> Handler<PIO::Interrupt> for InterruptHandler<PIO> {
unsafe fn on_interrupt() {
let ints = PIO::PIO.irqs(0).ints().read().0;
for bit in 0..12 {
if ints & (1 << bit) != 0 {
PIO::wakers().0[bit].wake();
}
}
PIO::PIO.irqs(0).inte().write_clear(|m| m.0 = ints);
}
pac::PIO1.irqs(0).inte().write_clear(|m| m.0 = ints);
}
pub(crate) unsafe fn init() {
interrupt::PIO0_IRQ_0.disable();
interrupt::PIO0_IRQ_0.set_priority(interrupt::Priority::P3);
pac::PIO0.irqs(0).inte().write(|m| m.0 = 0);
interrupt::PIO0_IRQ_0.enable();
interrupt::PIO1_IRQ_0.disable();
interrupt::PIO1_IRQ_0.set_priority(interrupt::Priority::P3);
pac::PIO1.irqs(0).inte().write(|m| m.0 = 0);
interrupt::PIO1_IRQ_0.enable();
}
/// Future that waits for TX-FIFO to become writable
@ -144,7 +118,7 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PI
if self.get_mut().sm_tx.try_push(value) {
Poll::Ready(())
} else {
WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker());
PIO::wakers().fifo_out()[SM].register(cx.waker());
PIO::PIO.irqs(0).inte().write_set(|m| {
m.0 = TXNFULL_MASK << SM;
});
@ -181,7 +155,7 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO
if let Some(v) = self.sm_rx.try_pull() {
Poll::Ready(v)
} else {
WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker());
PIO::wakers().fifo_in()[SM].register(cx.waker());
PIO::PIO.irqs(0).inte().write_set(|m| {
m.0 = RXNEMPTY_MASK << SM;
});
@ -217,7 +191,7 @@ impl<'a, 'd, PIO: Instance> Future for IrqFuture<'a, 'd, PIO> {
return Poll::Ready(());
}
WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker());
PIO::wakers().irq()[self.irq_no as usize].register(cx.waker());
PIO::PIO.irqs(0).inte().write_set(|m| {
m.0 = SMIRQ_MASK << self.irq_no;
});
@ -949,9 +923,11 @@ pub struct Pio<'d, PIO: Instance> {
}
impl<'d, PIO: Instance> Pio<'d, PIO> {
pub fn new(_pio: impl Peripheral<P = PIO> + 'd) -> Self {
pub fn new(_pio: impl Peripheral<P = PIO> + 'd, _irq: impl Binding<PIO::Interrupt, InterruptHandler<PIO>>) -> Self {
PIO::state().users.store(5, Ordering::Release);
PIO::state().used_pins.store(0, Ordering::Release);
PIO::Interrupt::unpend();
unsafe { PIO::Interrupt::enable() };
Self {
common: Common {
instructions_used: 0,
@ -1017,6 +993,15 @@ mod sealed {
const PIO_NO: u8;
const PIO: &'static crate::pac::pio::Pio;
const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel;
type Interrupt: crate::interrupt::typelevel::Interrupt;
#[inline]
fn wakers() -> &'static Wakers {
const NEW_AW: AtomicWaker = AtomicWaker::new();
static WAKERS: Wakers = Wakers([NEW_AW; 12]);
&WAKERS
}
#[inline]
fn state() -> &'static State {
@ -1033,18 +1018,19 @@ mod sealed {
pub trait Instance: sealed::Instance + Sized + Unpin {}
macro_rules! impl_pio {
($name:ident, $pio:expr, $pac:ident, $funcsel:ident) => {
($name:ident, $pio:expr, $pac:ident, $funcsel:ident, $irq:ident) => {
impl sealed::Instance for peripherals::$name {
const PIO_NO: u8 = $pio;
const PIO: &'static pac::pio::Pio = &pac::$pac;
const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::$funcsel;
type Interrupt = crate::interrupt::typelevel::$irq;
}
impl Instance for peripherals::$name {}
};
}
impl_pio!(PIO0, 0, PIO0, PIO0_0);
impl_pio!(PIO1, 1, PIO1, PIO1_0);
impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0);
impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0);
pub trait PioPin: sealed::PioPin + gpio::Pin {}

View File

@ -25,6 +25,7 @@ pub enum Error {
}
/// Structure containing date and time information
#[derive(Clone, Debug)]
pub struct DateTime {
/// 0..4095
pub year: u16,

View File

@ -12,26 +12,24 @@ pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
use crate::clocks::clk_rtc_freq;
/// A reference to the real time clock of the system
pub struct RealTimeClock<'d, T: Instance> {
pub struct Rtc<'d, T: Instance> {
inner: PeripheralRef<'d, T>,
}
impl<'d, T: Instance> RealTimeClock<'d, T> {
impl<'d, T: Instance> Rtc<'d, T> {
/// Create a new instance of the real time clock, with the given date as an initial value.
///
/// # Errors
///
/// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range.
pub fn new(inner: impl Peripheral<P = T> + 'd, initial_date: DateTime) -> Result<Self, RtcError> {
pub fn new(inner: impl Peripheral<P = T> + 'd) -> Self {
into_ref!(inner);
// Set the RTC divider
inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1));
let mut result = Self { inner };
result.set_leap_year_check(true); // should be on by default, make sure this is the case.
result.set_datetime(initial_date)?;
Ok(result)
let result = Self { inner };
result
}
/// Enable or disable the leap year check. The rp2040 chip will always add a Feb 29th on every year that is divisable by 4, but this may be incorrect (e.g. on century years). This function allows you to disable this check.
@ -43,7 +41,37 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
});
}
/// Checks to see if this RealTimeClock is running
/// Set the time from internal format
pub fn restore(&mut self, ymd: rp_pac::rtc::regs::Rtc1, hms: rp_pac::rtc::regs::Rtc0) {
// disable RTC while we configure it
self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false));
while self.inner.regs().ctrl().read().rtc_active() {
core::hint::spin_loop();
}
self.inner.regs().setup_0().write(|w| {
*w = rp_pac::rtc::regs::Setup0(ymd.0);
});
self.inner.regs().setup_1().write(|w| {
*w = rp_pac::rtc::regs::Setup1(hms.0);
});
// Load the new datetime and re-enable RTC
self.inner.regs().ctrl().write(|w| w.set_load(true));
self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true));
while !self.inner.regs().ctrl().read().rtc_active() {
core::hint::spin_loop();
}
}
/// Get the time in internal format
pub fn save(&mut self) -> (rp_pac::rtc::regs::Rtc1, rp_pac::rtc::regs::Rtc0) {
let rtc_0: rp_pac::rtc::regs::Rtc0 = self.inner.regs().rtc_0().read();
let rtc_1 = self.inner.regs().rtc_1().read();
(rtc_1, rtc_0)
}
/// Checks to see if this Rtc is running
pub fn is_running(&self) -> bool {
self.inner.regs().ctrl().read().rtc_active()
}
@ -113,8 +141,8 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
/// # fn main() { }
/// # #[cfg(not(feature = "chrono"))]
/// # fn main() {
/// # use embassy_rp::rtc::{RealTimeClock, DateTimeFilter};
/// # let mut real_time_clock: RealTimeClock<embassy_rp::peripherals::RTC> = unsafe { core::mem::zeroed() };
/// # use embassy_rp::rtc::{Rtc, DateTimeFilter};
/// # let mut real_time_clock: Rtc<embassy_rp::peripherals::RTC> = unsafe { core::mem::zeroed() };
/// let now = real_time_clock.now().unwrap();
/// real_time_clock.schedule_alarm(
/// DateTimeFilter::default()
@ -150,7 +178,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
}
}
/// Errors that can occur on methods on [RealTimeClock]
/// Errors that can occur on methods on [Rtc]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RtcError {
/// An invalid DateTime was given or stored on the hardware.

View File

@ -545,25 +545,19 @@ mod eh1 {
type Error = Error;
}
impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBusFlush for Spi<'d, T, M> {
impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBus<u8> for Spi<'d, T, M> {
fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBusRead<u8> for Spi<'d, T, M> {
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_transfer(words, &[])
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBusWrite<u8> for Spi<'d, T, M> {
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(words)
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_1::spi::SpiBus<u8> for Spi<'d, T, M> {
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
self.blocking_transfer(read, write)
}
@ -578,30 +572,24 @@ mod eh1 {
mod eha {
use super::*;
impl<'d, T: Instance> embedded_hal_async::spi::SpiBusFlush for Spi<'d, T, Async> {
impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spi<'d, T, Async> {
async fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<'d, T: Instance> embedded_hal_async::spi::SpiBusWrite<u8> for Spi<'d, T, Async> {
async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
self.write(words).await
}
}
impl<'d, T: Instance> embedded_hal_async::spi::SpiBusRead<u8> for Spi<'d, T, Async> {
async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
self.read(words).await
}
}
impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spi<'d, T, Async> {
async fn transfer<'a>(&'a mut self, read: &'a mut [u8], write: &'a [u8]) -> Result<(), Self::Error> {
async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
self.transfer(read, write).await
}
async fn transfer_in_place<'a>(&'a mut self, words: &'a mut [u8]) -> Result<(), Self::Error> {
async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
self.transfer_in_place(words).await
}
}

View File

@ -361,6 +361,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
let regs = T::regs();
let siestatus = regs.sie_status().read();
let intrstatus = regs.intr().read();
if siestatus.resume() {
regs.sie_status().write(|w| w.set_resume(true));
@ -389,7 +390,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
return Poll::Ready(Event::Reset);
}
if siestatus.suspended() {
if siestatus.suspended() && intrstatus.dev_suspend() {
regs.sie_status().write(|w| w.set_suspended(true));
return Poll::Ready(Event::Suspend);
}

View File

@ -107,4 +107,36 @@ impl Watchdog {
w.set_trigger(true);
})
}
/// Store data in scratch register
pub fn set_scratch(&mut self, index: usize, value: u32) {
let watchdog = pac::WATCHDOG;
match index {
0 => watchdog.scratch0().write(|w| *w = value),
1 => watchdog.scratch1().write(|w| *w = value),
2 => watchdog.scratch2().write(|w| *w = value),
3 => watchdog.scratch3().write(|w| *w = value),
4 => watchdog.scratch4().write(|w| *w = value),
5 => watchdog.scratch5().write(|w| *w = value),
6 => watchdog.scratch6().write(|w| *w = value),
7 => watchdog.scratch7().write(|w| *w = value),
_ => panic!("Invalid watchdog scratch index"),
}
}
/// Read data from scratch register
pub fn get_scratch(&mut self, index: usize) -> u32 {
let watchdog = pac::WATCHDOG;
match index {
0 => watchdog.scratch0().read(),
1 => watchdog.scratch1().read(),
2 => watchdog.scratch2().read(),
3 => watchdog.scratch3().read(),
4 => watchdog.scratch4().read(),
5 => watchdog.scratch5().read(),
6 => watchdog.scratch6().read(),
7 => watchdog.scratch7().read(),
_ => panic!("Invalid watchdog scratch index"),
}
}
}

View File

@ -5,15 +5,15 @@ edition = "2021"
license = "MIT OR Apache-2.0"
[package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-wpan-v$VERSION/embassy-stm32-wpan/src"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32-wpan/src"
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-wpan-v$VERSION/embassy-stm32-wpan/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32-wpan/src/"
target = "thumbv7em-none-eabihf"
features = ["stm32wb55rg"]
[dependencies]
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" }
embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
@ -25,13 +25,14 @@ aligned = "0.4.1"
bit_field = "0.10.2"
stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
stm32wb-hci = { version = "0.1.2", features = ["version-5-0"], optional = true }
stm32wb-hci = { version = "0.1.3", optional = true }
bitflags = { version = "2.3.3", optional = true }
[features]
defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"]
defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "stm32wb-hci?/defmt"]
ble = ["dep:stm32wb-hci"]
mac = []
mac = ["dep:bitflags"]
stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ]
@ -48,4 +49,4 @@ stm32wb55rg = [ "embassy-stm32/stm32wb55rg" ]
stm32wb55vc = [ "embassy-stm32/stm32wb55vc" ]
stm32wb55ve = [ "embassy-stm32/stm32wb55ve" ]
stm32wb55vg = [ "embassy-stm32/stm32wb55vg" ]
stm32wb55vy = [ "embassy-stm32/stm32wb55vy" ]
stm32wb55vy = [ "embassy-stm32/stm32wb55vy" ]

View File

@ -37,7 +37,7 @@ pub struct CmdSerialStub {
}
#[derive(Copy, Clone, Default)]
#[repr(C, packed(4))]
#[repr(C, packed)]
pub struct CmdPacket {
pub header: PacketHeader,
pub cmdserial: CmdSerial,

View File

@ -6,6 +6,8 @@ use crate::PacketHeader;
#[derive(Debug)]
#[repr(C)]
pub enum TlPacketType {
MacCmd = 0x00,
BleCmd = 0x01,
AclData = 0x02,
BleEvt = 0x04,
@ -79,6 +81,7 @@ pub const CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255;
pub const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE;
pub const POOL_SIZE: usize = CFG_TL_BLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4);
pub const C_SIZE_CMD_STRING: usize = 256;
pub const fn divc(x: usize, y: usize) -> usize {
(x + y - 1) / y

View File

@ -26,6 +26,9 @@ pub mod sub;
pub mod tables;
pub mod unsafe_linked_list;
#[cfg(feature = "mac")]
pub mod mac;
#[cfg(feature = "ble")]
pub use crate::sub::ble::hci;
@ -60,9 +63,9 @@ impl<'d> TlMbox<'d> {
mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
traces_table: TL_TRACES_TABLE.as_ptr(),
mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(),
// zigbee_table: TL_ZIGBEE_TABLE.as_ptr(),
// lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(),
// ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(),
zigbee_table: TL_ZIGBEE_TABLE.as_ptr(),
lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(),
ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(),
});
TL_SYS_TABLE
@ -87,15 +90,15 @@ impl<'d> TlMbox<'d> {
TL_MAC_802_15_4_TABLE
.as_mut_ptr()
.write_volatile(MaybeUninit::zeroed().assume_init());
// TL_ZIGBEE_TABLE
// .as_mut_ptr()
// .write_volatile(MaybeUninit::zeroed().assume_init());
// TL_LLD_TESTS_TABLE
// .as_mut_ptr()
// .write_volatile(MaybeUninit::zeroed().assume_init());
// TL_BLE_LLD_TABLE
// .as_mut_ptr()
// .write_volatile(MaybeUninit::zeroed().assume_init());
TL_ZIGBEE_TABLE
.as_mut_ptr()
.write_volatile(MaybeUninit::zeroed().assume_init());
TL_LLD_TESTS_TABLE
.as_mut_ptr()
.write_volatile(MaybeUninit::zeroed().assume_init());
TL_BLE_LLD_TABLE
.as_mut_ptr()
.write_volatile(MaybeUninit::zeroed().assume_init());
EVT_POOL
.as_mut_ptr()
@ -103,18 +106,30 @@ impl<'d> TlMbox<'d> {
SYS_SPARE_EVT_BUF
.as_mut_ptr()
.write_volatile(MaybeUninit::zeroed().assume_init());
BLE_SPARE_EVT_BUF
CS_BUFFER
.as_mut_ptr()
.write_volatile(MaybeUninit::zeroed().assume_init());
#[cfg(feature = "ble")]
{
BLE_SPARE_EVT_BUF
.as_mut_ptr()
.write_volatile(MaybeUninit::zeroed().assume_init());
BLE_CMD_BUFFER
.as_mut_ptr()
.write_volatile(MaybeUninit::zeroed().assume_init());
HCI_ACL_DATA_BUFFER
.as_mut_ptr()
.write_volatile(MaybeUninit::zeroed().assume_init());
CS_BUFFER
}
#[cfg(feature = "mac")]
{
MAC_802_15_4_CMD_BUFFER
.as_mut_ptr()
.write_volatile(MaybeUninit::zeroed().assume_init());
MAC_802_15_4_NOTIF_RSP_EVT_BUFFER
.as_mut_ptr()
.write_volatile(MaybeUninit::zeroed().assume_init());
}

View File

@ -0,0 +1,467 @@
use super::opcodes::OpcodeM4ToM0;
use super::typedefs::{
AddressMode, Capabilities, DisassociationReason, GtsCharacteristics, KeyIdMode, MacAddress, MacChannel, MacStatus,
PanId, PibId, ScanType, SecurityLevel,
};
pub trait MacCommand {
const OPCODE: OpcodeM4ToM0;
const SIZE: usize;
fn copy_into_slice(&self, buf: &mut [u8]) {
unsafe { core::ptr::copy(self as *const _ as *const u8, buf as *mut _ as *mut u8, Self::SIZE) };
}
}
/// MLME ASSOCIATE Request used to request an association
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AssociateRequest {
/// the logical channel on which to attempt association
pub channel_number: MacChannel,
/// the channel page on which to attempt association
pub channel_page: u8,
/// coordinator addressing mode
pub coord_addr_mode: AddressMode,
/// operational capabilities of the associating device
pub capability_information: Capabilities,
/// the identifier of the PAN with which to associate
pub coord_pan_id: PanId,
/// the security level to be used
pub security_level: SecurityLevel,
/// the mode used to identify the key to be used
pub key_id_mode: KeyIdMode,
/// the originator of the key to be used
pub key_source: [u8; 8],
/// Coordinator address
pub coord_address: MacAddress,
/// the index of the key to be used
pub key_index: u8,
}
impl MacCommand for AssociateRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeAssociateReq;
const SIZE: usize = 25;
}
/// MLME DISASSOCIATE Request sed to request a disassociation
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DisassociateRequest {
/// device addressing mode used
pub device_addr_mode: AddressMode,
/// the identifier of the PAN of the device
pub device_pan_id: PanId,
/// the reason for the disassociation
pub disassociation_reason: DisassociationReason,
/// device address
pub device_address: MacAddress,
/// `true` if the disassociation notification command is to be sent indirectly
pub tx_indirect: bool,
/// the security level to be used
pub security_level: SecurityLevel,
/// the mode to be used to indetify the key to be used
pub key_id_mode: KeyIdMode,
/// the index of the key to be used
pub key_index: u8,
/// the originator of the key to be used
pub key_source: [u8; 8],
}
impl MacCommand for DisassociateRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeDisassociateReq;
const SIZE: usize = 24;
}
/// MLME GET Request used to request a PIB value
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GetRequest {
/// the name of the PIB attribute to read
pub pib_attribute: PibId,
}
impl MacCommand for GetRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeGetReq;
const SIZE: usize = 4;
}
/// MLME GTS Request used to request and maintain GTSs
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GtsRequest {
/// the characteristics of the GTS
pub characteristics: GtsCharacteristics,
/// the security level to be used
pub security_level: SecurityLevel,
/// the mode used to identify the key to be used
pub key_id_mode: KeyIdMode,
/// the index of the key to be used
pub key_index: u8,
/// the originator of the key to be used
pub key_source: [u8; 8],
}
impl MacCommand for GtsRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeGetReq;
const SIZE: usize = 12;
}
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ResetRequest {
/// MAC PIB attributes are set to their default values or not during reset
pub set_default_pib: bool,
}
impl MacCommand for ResetRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeResetReq;
const SIZE: usize = 4;
}
/// MLME RX ENABLE Request used to request that the receiver is either enabled
/// for a finite period of time or disabled
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct RxEnableRequest {
/// the request operation can be deferred or not
pub defer_permit: bool,
/// configure the transceiver to RX with ranging for a value of
/// RANGING_ON or to not enable ranging for RANGING_OFF
pub ranging_rx_control: u8,
/// number of symbols measured before the receiver is to be enabled or disabled
pub rx_on_time: [u8; 4],
/// number of symbols for which the receiver is to be enabled
pub rx_on_duration: [u8; 4],
}
impl MacCommand for RxEnableRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeRxEnableReq;
const SIZE: usize = 12;
fn copy_into_slice(&self, buf: &mut [u8]) {
buf[0] = self.defer_permit as u8;
buf[1] = self.ranging_rx_control as u8;
// stuffing to keep 32bit alignment
buf[2] = 0;
buf[3] = 0;
buf[4..8].copy_from_slice(&self.rx_on_time);
buf[8..12].copy_from_slice(&self.rx_on_duration);
}
}
/// MLME SCAN Request used to initiate a channel scan over a given list of channels
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ScanRequest {
/// the type of scan to be performed
pub scan_type: ScanType,
/// the time spent on scanning each channel
pub scan_duration: u8,
/// channel page on which to perform the scan
pub channel_page: u8,
/// security level to be used
pub security_level: SecurityLevel,
/// indicate which channels are to be scanned
pub scan_channels: [u8; 4],
/// originator the key to be used
pub key_source: [u8; 8],
/// mode used to identify the key to be used
pub key_id_mode: KeyIdMode,
/// index of the key to be used
pub key_index: u8,
}
impl MacCommand for ScanRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeScanReq;
const SIZE: usize = 20;
}
/// MLME SET Request used to attempt to write the given value to the indicated PIB attribute
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SetRequest {
/// the pointer to the value of the PIB attribute to set
pub pib_attribute_ptr: *const u8,
/// the name of the PIB attribute to set
pub pib_attribute: PibId,
}
impl MacCommand for SetRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSetReq;
const SIZE: usize = 8;
}
/// MLME START Request used by the FFDs to intiate a new PAN or to begin using a new superframe
/// configuration
#[derive(Default)]
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct StartRequest {
/// PAN indentifier to used by the device
pub pan_id: PanId,
/// logical channel on which to begin
pub channel_number: MacChannel,
/// channel page on which to begin
pub channel_page: u8,
/// time at which to begin transmitting beacons
pub start_time: [u8; 4],
/// indicated how often the beacon is to be transmitted
pub beacon_order: u8,
/// length of the active portion of the superframe
pub superframe_order: u8,
/// indicated wheter the device is a PAN coordinator or not
pub pan_coordinator: bool,
/// indicates if the receiver of the beaconing device is disabled or not
pub battery_life_extension: bool,
/// indicated if the coordinator realignment command is to be trasmitted
pub coord_realignment: u8,
/// indicated if the coordinator realignment command is to be trasmitted
pub coord_realign_security_level: SecurityLevel,
/// index of the key to be used
pub coord_realign_key_id_index: u8,
/// originator of the key to be used
pub coord_realign_key_source: [u8; 8],
/// security level to be used for beacon frames
pub beacon_security_level: SecurityLevel,
/// mode used to identify the key to be used
pub beacon_key_id_mode: KeyIdMode,
/// index of the key to be used
pub beacon_key_index: u8,
/// originator of the key to be used
pub beacon_key_source: [u8; 8],
}
impl MacCommand for StartRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeStartReq;
const SIZE: usize = 35;
}
/// MLME SYNC Request used to synchronize with the coordinator by acquiring and, if
/// specified, tracking its beacons
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SyncRequest {
/// the channel number on which to attempt coordinator synchronization
pub channel_number: MacChannel,
/// the channel page on which to attempt coordinator synchronization
pub channel_page: u8,
/// `true` if the MLME is to synchronize with the next beacon and attempts
/// to track all future beacons.
///
/// `false` if the MLME is to synchronize with only the next beacon
pub track_beacon: bool,
}
impl MacCommand for SyncRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSyncReq;
const SIZE: usize = 4;
}
/// MLME POLL Request propmts the device to request data from the coordinator
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PollRequest {
/// addressing mode of the coordinator
pub coord_addr_mode: AddressMode,
/// security level to be used
pub security_level: SecurityLevel,
/// mode used to identify the key to be used
pub key_id_mode: KeyIdMode,
/// index of the key to be used
pub key_index: u8,
/// coordinator address
pub coord_address: MacAddress,
/// originator of the key to be used
pub key_source: [u8; 8],
/// PAN identifier of the coordinator
pub coord_pan_id: PanId,
}
impl MacCommand for PollRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmePollReq;
const SIZE: usize = 24;
}
/// MLME DPS Request allows the next higher layer to request that the PHY utilize a
/// given pair of preamble codes for a single use pending expiration of the DPSIndexDuration
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DpsRequest {
/// the index value for the transmitter
tx_dps_index: u8,
/// the index value of the receiver
rx_dps_index: u8,
/// the number of symbols for which the transmitter and receiver will utilize the
/// respective DPS indices
dps_index_duration: u8,
}
impl MacCommand for DpsRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeDpsReq;
const SIZE: usize = 4;
}
/// MLME SOUNDING request primitive which is used by the next higher layer to request that
/// the PHY respond with channel sounding information
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SoundingRequest;
impl MacCommand for SoundingRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeSoundingReq;
const SIZE: usize = 4;
}
/// MLME CALIBRATE request primitive which used to obtain the results of a ranging
/// calibration request from an RDEV
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CalibrateRequest;
impl MacCommand for CalibrateRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeCalibrateReq;
const SIZE: usize = 4;
}
/// MCPS DATA Request used for MAC data related requests from the application
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DataRequest {
/// the handle assocated with the MSDU to be transmitted
pub msdu_ptr: *const u8,
/// source addressing mode used
pub src_addr_mode: AddressMode,
/// destination addressing mode used
pub dst_addr_mode: AddressMode,
/// destination PAN Id
pub dst_pan_id: PanId,
/// destination address
pub dst_address: MacAddress,
/// the number of octets contained in the MSDU
pub msdu_length: u8,
/// the handle assocated with the MSDU to be transmitted
pub msdu_handle: u8,
/// the ACK transmittion options for the MSDU
pub ack_tx: u8,
/// `true` if a GTS is to be used for transmission
///
/// `false` indicates that the CAP will be used
pub gts_tx: bool,
/// the pending bit transmission options for the MSDU
pub indirect_tx: u8,
/// the security level to be used
pub security_level: SecurityLevel,
/// the mode used to indentify the key to be used
pub key_id_mode: KeyIdMode,
/// the index of the key to be used
pub key_index: u8,
/// the originator of the key to be used
pub key_source: [u8; 8],
/// 2011 - the pulse repitition value
pub uwbprf: u8,
/// 2011 - the ranging configuration
pub ranging: u8,
/// 2011 - the preamble symbol repititions
pub uwb_preamble_symbol_repetitions: u8,
/// 2011 - indicates the data rate
pub datrate: u8,
}
impl Default for DataRequest {
fn default() -> Self {
Self {
msdu_ptr: 0 as *const u8,
src_addr_mode: AddressMode::NoAddress,
dst_addr_mode: AddressMode::NoAddress,
dst_pan_id: PanId([0, 0]),
dst_address: MacAddress { short: [0, 0] },
msdu_length: 0,
msdu_handle: 0,
ack_tx: 0,
gts_tx: false,
indirect_tx: 0,
security_level: SecurityLevel::Unsecure,
key_id_mode: KeyIdMode::Implicite,
key_index: 0,
key_source: [0u8; 8],
uwbprf: 0,
ranging: 0,
uwb_preamble_symbol_repetitions: 0,
datrate: 0,
}
}
}
impl MacCommand for DataRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::McpsDataReq;
const SIZE: usize = 40;
}
/// for MCPS PURGE Request used to purge an MSDU from the transaction queue
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PurgeRequest {
/// the handle associated with the MSDU to be purged from the transaction
/// queue
pub msdu_handle: u8,
}
impl MacCommand for PurgeRequest {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::McpsPurgeReq;
const SIZE: usize = 4;
}
/// MLME ASSOCIATE Response used to initiate a response to an MLME-ASSOCIATE.indication
#[repr(C)]
#[derive(Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AssociateResponse {
/// extended address of the device requesting association
pub device_address: [u8; 8],
/// 16-bitshort device address allocated by the coordinator on successful
/// association
pub assoc_short_address: [u8; 2],
/// status of the association attempt
pub status: MacStatus,
/// security level to be used
pub security_level: SecurityLevel,
/// the originator of the key to be used
pub key_source: [u8; 8],
/// the mode used to identify the key to be used
pub key_id_mode: KeyIdMode,
/// the index of the key to be used
pub key_index: u8,
}
impl MacCommand for AssociateResponse {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeAssociateRes;
const SIZE: usize = 24;
}
/// MLME ORPHAN Response used to respond to the MLME ORPHAN Indication
#[repr(C)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct OrphanResponse {
/// extended address of the orphaned device
pub orphan_address: [u8; 8],
/// short address allocated to the orphaned device
pub short_address: [u8; 2],
/// if the orphaned device is associated with coordinator or not
pub associated_member: bool,
/// security level to be used
pub security_level: SecurityLevel,
/// the originator of the key to be used
pub key_source: [u8; 8],
/// the mode used to identify the key to be used
pub key_id_mode: KeyIdMode,
/// the index of the key to be used
pub key_index: u8,
}
impl MacCommand for OrphanResponse {
const OPCODE: OpcodeM4ToM0 = OpcodeM4ToM0::MlmeOrphanRes;
const SIZE: usize = 24;
}

View File

@ -0,0 +1,4 @@
pub const MAX_PAN_DESC_SUPPORTED: usize = 6;
pub const MAX_SOUNDING_LIST_SUPPORTED: usize = 6;
pub const MAX_PENDING_ADDRESS: usize = 7;
pub const MAX_ED_SCAN_RESULTS_SUPPORTED: usize = 16;

View File

@ -0,0 +1,94 @@
use super::helpers::to_u16;
use super::indications::{
AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication,
DpsIndication, GtsIndication, OrphanIndication, PollIndication, SyncLossIndication,
};
use super::responses::{
AssociateConfirm, CalibrateConfirm, DataConfirm, DisassociateConfirm, DpsConfirm, GetConfirm, GtsConfirm,
PollConfirm, PurgeConfirm, ResetConfirm, RxEnableConfirm, ScanConfirm, SetConfirm, SoundingConfirm, StartConfirm,
};
use crate::mac::opcodes::OpcodeM0ToM4;
pub trait ParseableMacEvent {
const SIZE: usize;
fn validate(buf: &[u8]) -> Result<(), ()> {
if buf.len() < Self::SIZE {
return Err(());
}
Ok(())
}
fn try_parse(buf: &[u8]) -> Result<Self, ()>
where
Self: Sized;
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum MacEvent {
MlmeAssociateCnf(AssociateConfirm),
MlmeDisassociateCnf(DisassociateConfirm),
MlmeGetCnf(GetConfirm),
MlmeGtsCnf(GtsConfirm),
MlmeResetCnf(ResetConfirm),
MlmeRxEnableCnf(RxEnableConfirm),
MlmeScanCnf(ScanConfirm),
MlmeSetCnf(SetConfirm),
MlmeStartCnf(StartConfirm),
MlmePollCnf(PollConfirm),
MlmeDpsCnf(DpsConfirm),
MlmeSoundingCnf(SoundingConfirm),
MlmeCalibrateCnf(CalibrateConfirm),
McpsDataCnf(DataConfirm),
McpsPurgeCnf(PurgeConfirm),
MlmeAssociateInd(AssociateIndication),
MlmeDisassociateInd(DisassociateIndication),
MlmeBeaconNotifyInd(BeaconNotifyIndication),
MlmeCommStatusInd(CommStatusIndication),
MlmeGtsInd(GtsIndication),
MlmeOrphanInd(OrphanIndication),
MlmeSyncLossInd(SyncLossIndication),
MlmeDpsInd(DpsIndication),
McpsDataInd(DataIndication),
MlmePollInd(PollIndication),
}
impl TryFrom<&[u8]> for MacEvent {
type Error = ();
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
let opcode = to_u16(&value[0..2]);
let opcode = OpcodeM0ToM4::try_from(opcode)?;
let buf = &value[2..];
match opcode {
OpcodeM0ToM4::MlmeAssociateCnf => Ok(Self::MlmeAssociateCnf(AssociateConfirm::try_parse(buf)?)),
OpcodeM0ToM4::MlmeDisassociateCnf => Ok(Self::MlmeDisassociateCnf(DisassociateConfirm::try_parse(buf)?)),
OpcodeM0ToM4::MlmeGetCnf => Ok(Self::MlmeGetCnf(GetConfirm::try_parse(buf)?)),
OpcodeM0ToM4::MlmeGtsCnf => Ok(Self::MlmeGtsCnf(GtsConfirm::try_parse(buf)?)),
OpcodeM0ToM4::MlmeResetCnf => Ok(Self::MlmeResetCnf(ResetConfirm::try_parse(buf)?)),
OpcodeM0ToM4::MlmeRxEnableCnf => Ok(Self::MlmeRxEnableCnf(RxEnableConfirm::try_parse(buf)?)),
OpcodeM0ToM4::MlmeScanCnf => Ok(Self::MlmeScanCnf(ScanConfirm::try_parse(buf)?)),
OpcodeM0ToM4::MlmeSetCnf => Ok(Self::MlmeSetCnf(SetConfirm::try_parse(buf)?)),
OpcodeM0ToM4::MlmeStartCnf => Ok(Self::MlmeStartCnf(StartConfirm::try_parse(buf)?)),
OpcodeM0ToM4::MlmePollCnf => Ok(Self::MlmePollCnf(PollConfirm::try_parse(buf)?)),
OpcodeM0ToM4::MlmeDpsCnf => Ok(Self::MlmeDpsCnf(DpsConfirm::try_parse(buf)?)),
OpcodeM0ToM4::MlmeSoundingCnf => Ok(Self::MlmeSoundingCnf(SoundingConfirm::try_parse(buf)?)),
OpcodeM0ToM4::MlmeCalibrateCnf => Ok(Self::MlmeCalibrateCnf(CalibrateConfirm::try_parse(buf)?)),
OpcodeM0ToM4::McpsDataCnf => Ok(Self::McpsDataCnf(DataConfirm::try_parse(buf)?)),
OpcodeM0ToM4::McpsPurgeCnf => Ok(Self::McpsPurgeCnf(PurgeConfirm::try_parse(buf)?)),
OpcodeM0ToM4::MlmeAssociateInd => Ok(Self::MlmeAssociateInd(AssociateIndication::try_parse(buf)?)),
OpcodeM0ToM4::MlmeDisassociateInd => Ok(Self::MlmeDisassociateInd(DisassociateIndication::try_parse(buf)?)),
OpcodeM0ToM4::MlmeBeaconNotifyInd => Ok(Self::MlmeBeaconNotifyInd(BeaconNotifyIndication::try_parse(buf)?)),
OpcodeM0ToM4::MlmeCommStatusInd => Ok(Self::MlmeCommStatusInd(CommStatusIndication::try_parse(buf)?)),
OpcodeM0ToM4::MlmeGtsInd => Ok(Self::MlmeGtsInd(GtsIndication::try_parse(buf)?)),
OpcodeM0ToM4::MlmeOrphanInd => Ok(Self::MlmeOrphanInd(OrphanIndication::try_parse(buf)?)),
OpcodeM0ToM4::MlmeSyncLossInd => Ok(Self::MlmeSyncLossInd(SyncLossIndication::try_parse(buf)?)),
OpcodeM0ToM4::MlmeDpsInd => Ok(Self::MlmeDpsInd(DpsIndication::try_parse(buf)?)),
OpcodeM0ToM4::McpsDataInd => Ok(Self::McpsDataInd(DataIndication::try_parse(buf)?)),
OpcodeM0ToM4::MlmePollInd => Ok(Self::MlmePollInd(PollIndication::try_parse(buf)?)),
}
}
}

View File

@ -0,0 +1,7 @@
pub fn to_u16(buf: &[u8]) -> u16 {
((buf[1] as u16) << 8) | buf[0] as u16
}
pub fn to_u32(buf: &[u8]) -> u32 {
((buf[0] as u32) << 0) + ((buf[1] as u32) << 8) + ((buf[2] as u32) << 16) + ((buf[3] as u32) << 24)
}

View File

@ -0,0 +1,470 @@
use super::consts::MAX_PENDING_ADDRESS;
use super::event::ParseableMacEvent;
use super::helpers::to_u32;
use super::typedefs::{
AddressMode, Capabilities, DisassociationReason, KeyIdMode, MacAddress, MacChannel, MacStatus, PanDescriptor,
PanId, SecurityLevel,
};
/// MLME ASSOCIATE Indication which will be used by the MAC
/// to indicate the reception of an association request command
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AssociateIndication {
/// Extended address of the device requesting association
pub device_address: [u8; 8],
/// Operational capabilities of the device requesting association
pub capability_information: Capabilities,
/// Security level purportedly used by the received MAC command frame
pub security_level: SecurityLevel,
/// The mode used to identify the key used by the originator of frame
pub key_id_mode: KeyIdMode,
/// Index of the key used by the originator of the received frame
pub key_index: u8,
/// The originator of the key used by the originator of the received frame
pub key_source: [u8; 8],
}
impl ParseableMacEvent for AssociateIndication {
const SIZE: usize = 20;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
device_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]],
capability_information: Capabilities::from_bits(buf[8]).ok_or(())?,
security_level: SecurityLevel::try_from(buf[9])?,
key_id_mode: KeyIdMode::try_from(buf[10])?,
key_index: buf[11],
key_source: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]],
})
}
}
/// MLME DISASSOCIATE indication which will be used to send
/// disassociation indication to the application.
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DisassociateIndication {
/// Extended address of the device requesting association
pub device_address: [u8; 8],
/// The reason for the disassociation
pub disassociation_reason: DisassociationReason,
/// The security level to be used
pub security_level: SecurityLevel,
/// The mode used to identify the key to be used
pub key_id_mode: KeyIdMode,
/// The index of the key to be used
pub key_index: u8,
/// The originator of the key to be used
pub key_source: [u8; 8],
}
impl ParseableMacEvent for DisassociateIndication {
const SIZE: usize = 20;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
device_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]],
disassociation_reason: DisassociationReason::try_from(buf[8])?,
security_level: SecurityLevel::try_from(buf[9])?,
key_id_mode: KeyIdMode::try_from(buf[10])?,
key_index: buf[11],
key_source: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]],
})
}
}
/// MLME BEACON NOTIIFY Indication which is used to send parameters contained
/// within a beacon frame received by the MAC to the application
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct BeaconNotifyIndication {
/// he set of octets comprising the beacon payload to be transferred
/// from the MAC sublayer entity to the next higher layer
pub sdu_ptr: *const u8,
/// The PAN Descriptor for the received beacon
pub pan_descriptor: PanDescriptor,
/// The list of addresses of the devices
pub addr_list: [MacAddress; MAX_PENDING_ADDRESS],
/// Beacon Sequence Number
pub bsn: u8,
/// The beacon pending address specification
pub pend_addr_spec: u8,
/// Number of octets contained in the beacon payload of the beacon frame
pub sdu_length: u8,
}
impl ParseableMacEvent for BeaconNotifyIndication {
const SIZE: usize = 88;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
// TODO: this is unchecked
Self::validate(buf)?;
let addr_list = [
MacAddress::try_from(&buf[26..34])?,
MacAddress::try_from(&buf[34..42])?,
MacAddress::try_from(&buf[42..50])?,
MacAddress::try_from(&buf[50..58])?,
MacAddress::try_from(&buf[58..66])?,
MacAddress::try_from(&buf[66..74])?,
MacAddress::try_from(&buf[74..82])?,
];
Ok(Self {
sdu_ptr: to_u32(&buf[0..4]) as *const u8,
pan_descriptor: PanDescriptor::try_from(&buf[4..26])?,
addr_list,
bsn: buf[82],
pend_addr_spec: buf[83],
sdu_length: buf[83],
})
}
}
/// MLME COMM STATUS Indication which is used by the MAC to indicate a communications status
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CommStatusIndication {
/// The 16-bit PAN identifier of the device from which the frame
/// was received or to which the frame was being sent
pub pan_id: PanId,
/// Source addressing mode
pub src_addr_mode: AddressMode,
/// Destination addressing mode
pub dst_addr_mode: AddressMode,
/// Source address
pub src_address: MacAddress,
/// Destination address
pub dst_address: MacAddress,
/// The communications status
pub status: MacStatus,
/// Security level to be used
pub security_level: SecurityLevel,
/// Mode used to identify the key to be used
pub key_id_mode: KeyIdMode,
/// Index of the key to be used
pub key_index: u8,
/// Originator of the key to be used
pub key_source: [u8; 8],
}
impl ParseableMacEvent for CommStatusIndication {
const SIZE: usize = 32;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
let src_addr_mode = AddressMode::try_from(buf[2])?;
let dst_addr_mode = AddressMode::try_from(buf[3])?;
let src_address = match src_addr_mode {
AddressMode::NoAddress => MacAddress { short: [0, 0] },
AddressMode::Reserved => MacAddress { short: [0, 0] },
AddressMode::Short => MacAddress {
short: [buf[4], buf[5]],
},
AddressMode::Extended => MacAddress {
extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]],
},
};
let dst_address = match dst_addr_mode {
AddressMode::NoAddress => MacAddress { short: [0, 0] },
AddressMode::Reserved => MacAddress { short: [0, 0] },
AddressMode::Short => MacAddress {
short: [buf[12], buf[13]],
},
AddressMode::Extended => MacAddress {
extended: [buf[12], buf[13], buf[14], buf[15], buf[16], buf[17], buf[18], buf[19]],
},
};
Ok(Self {
pan_id: PanId([buf[0], buf[1]]),
src_addr_mode,
dst_addr_mode,
src_address,
dst_address,
status: MacStatus::try_from(buf[20])?,
security_level: SecurityLevel::try_from(buf[21])?,
key_id_mode: KeyIdMode::try_from(buf[22])?,
key_index: buf[23],
key_source: [buf[24], buf[25], buf[26], buf[27], buf[28], buf[29], buf[30], buf[31]],
})
}
}
/// MLME GTS Indication indicates that a GTS has been allocated or that a
/// previously allocated GTS has been deallocated
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GtsIndication {
/// The short address of the device that has been allocated or deallocated a GTS
pub device_address: [u8; 2],
/// The characteristics of the GTS
pub gts_characteristics: u8,
/// Security level to be used
pub security_level: SecurityLevel,
/// Mode used to identify the key to be used
pub key_id_mode: KeyIdMode,
/// Index of the key to be used
pub key_index: u8,
/// Originator of the key to be used
pub key_source: [u8; 8],
}
impl ParseableMacEvent for GtsIndication {
const SIZE: usize = 16;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
device_address: [buf[0], buf[1]],
gts_characteristics: buf[2],
security_level: SecurityLevel::try_from(buf[3])?,
key_id_mode: KeyIdMode::try_from(buf[4])?,
key_index: buf[5],
// 2 byte stuffing
key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]],
})
}
}
/// MLME ORPHAN Indication which is used by the coordinator to notify the
/// application of the presence of an orphaned device
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct OrphanIndication {
/// Extended address of the orphaned device
pub orphan_address: [u8; 8],
/// Originator of the key used by the originator of the received frame
pub key_source: [u8; 8],
/// Security level purportedly used by the received MAC command frame
pub security_level: SecurityLevel,
/// Mode used to identify the key used by originator of received frame
pub key_id_mode: KeyIdMode,
/// Index of the key used by the originator of the received frame
pub key_index: u8,
}
impl ParseableMacEvent for OrphanIndication {
const SIZE: usize = 20;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
orphan_address: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]],
key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]],
security_level: SecurityLevel::try_from(buf[16])?,
key_id_mode: KeyIdMode::try_from(buf[17])?,
key_index: buf[18],
// 1 byte stuffing
})
}
}
/// MLME SYNC LOSS Indication which is used by the MAC to indicate the loss
/// of synchronization with the coordinator
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SyncLossIndication {
/// The PAN identifier with which the device lost synchronization or to which it was realigned
pub pan_id: PanId,
/// The reason that synchronization was lost
pub loss_reason: u8,
/// The logical channel on which the device lost synchronization or to whi
pub channel_number: MacChannel,
/// The channel page on which the device lost synchronization or to which
pub channel_page: u8,
/// The security level used by the received MAC frame
pub security_level: SecurityLevel,
/// Mode used to identify the key used by originator of received frame
pub key_id_mode: KeyIdMode,
/// Index of the key used by the originator of the received frame
pub key_index: u8,
/// Originator of the key used by the originator of the received frame
pub key_source: [u8; 8],
}
impl ParseableMacEvent for SyncLossIndication {
const SIZE: usize = 16;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
pan_id: PanId([buf[0], buf[1]]),
loss_reason: buf[2],
channel_number: MacChannel::try_from(buf[3])?,
channel_page: buf[4],
security_level: SecurityLevel::try_from(buf[5])?,
key_id_mode: KeyIdMode::try_from(buf[6])?,
key_index: buf[7],
key_source: [buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]],
})
}
}
/// MLME DPS Indication which indicates the expiration of the DPSIndexDuration
/// and the resetting of the DPS values in the PHY
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DpsIndication;
impl ParseableMacEvent for DpsIndication {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self)
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(C, align(8))]
pub struct DataIndication {
/// Pointer to the set of octets forming the MSDU being indicated
pub msdu_ptr: *const u8,
/// Source addressing mode used
pub src_addr_mode: AddressMode,
/// Source PAN ID
pub src_pan_id: PanId,
/// Source address
pub src_address: MacAddress,
/// Destination addressing mode used
pub dst_addr_mode: AddressMode,
/// Destination PAN ID
pub dst_pan_id: PanId,
/// Destination address
pub dst_address: MacAddress,
/// The number of octets contained in the MSDU being indicated
pub msdu_length: u8,
/// QI value measured during reception of the MPDU
pub mpdu_link_quality: u8,
/// The data sequence number of the received data frame
pub dsn: u8,
/// The time, in symbols, at which the data were received
pub time_stamp: [u8; 4],
/// The security level purportedly used by the received data frame
pub security_level: SecurityLevel,
/// Mode used to identify the key used by originator of received frame
pub key_id_mode: KeyIdMode,
/// The originator of the key
pub key_source: [u8; 8],
/// The index of the key
pub key_index: u8,
/// he pulse repetition value of the received PPDU
pub uwbprf: u8,
/// The preamble symbol repetitions of the UWB PHY frame
pub uwn_preamble_symbol_repetitions: u8,
/// Indicates the data rate
pub datrate: u8,
/// time units corresponding to an RMARKER at the antenna at the end of a ranging exchange,
pub ranging_received: u8,
pub ranging_counter_start: u32,
pub ranging_counter_stop: u32,
/// ime units in a message exchange over which the tracking offset was measured
pub ranging_tracking_interval: u32,
/// time units slipped or advanced by the radio tracking system
pub ranging_offset: u32,
/// The FoM characterizing the ranging measurement
pub ranging_fom: u8,
/// The Received Signal Strength Indicator measured
pub rssi: u8,
}
impl ParseableMacEvent for DataIndication {
const SIZE: usize = 68;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
let src_addr_mode = AddressMode::try_from(buf[4])?;
let src_address = match src_addr_mode {
AddressMode::NoAddress => MacAddress { short: [0, 0] },
AddressMode::Reserved => MacAddress { short: [0, 0] },
AddressMode::Short => MacAddress {
short: [buf[7], buf[8]],
},
AddressMode::Extended => MacAddress {
extended: [buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14]],
},
};
let dst_addr_mode = AddressMode::try_from(buf[15])?;
let dst_address = match dst_addr_mode {
AddressMode::NoAddress => MacAddress { short: [0, 0] },
AddressMode::Reserved => MacAddress { short: [0, 0] },
AddressMode::Short => MacAddress {
short: [buf[18], buf[19]],
},
AddressMode::Extended => MacAddress {
extended: [buf[18], buf[19], buf[20], buf[21], buf[22], buf[23], buf[24], buf[25]],
},
};
Ok(Self {
msdu_ptr: to_u32(&buf[0..4]) as *const u8,
src_addr_mode,
src_pan_id: PanId([buf[5], buf[6]]),
src_address,
dst_addr_mode,
dst_pan_id: PanId([buf[16], buf[17]]),
dst_address,
msdu_length: buf[26],
mpdu_link_quality: buf[27],
dsn: buf[28],
time_stamp: [buf[29], buf[30], buf[31], buf[32]],
security_level: SecurityLevel::try_from(buf[33]).unwrap_or(SecurityLevel::Unsecure), // TODO: this is totaly wrong, but I'm too smol brain to fix it
key_id_mode: KeyIdMode::try_from(buf[34]).unwrap_or(KeyIdMode::Implicite), // TODO: this is totaly wrong, but I'm too smol brain to fix it
key_source: [buf[35], buf[36], buf[37], buf[38], buf[39], buf[40], buf[41], buf[42]],
key_index: buf[43],
uwbprf: buf[44],
uwn_preamble_symbol_repetitions: buf[45],
datrate: buf[46],
ranging_received: buf[47],
ranging_counter_start: to_u32(&buf[48..52]),
ranging_counter_stop: to_u32(&buf[52..56]),
ranging_tracking_interval: to_u32(&buf[56..60]),
ranging_offset: to_u32(&buf[60..64]),
ranging_fom: buf[65],
rssi: buf[66],
})
}
}
/// MLME POLL Indication which will be used for indicating the Data Request
/// reception to upper layer as defined in Zigbee r22 - D.8.2
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PollIndication {
/// addressing mode used
pub addr_mode: AddressMode,
/// Poll requester address
pub request_address: MacAddress,
}
impl ParseableMacEvent for PollIndication {
const SIZE: usize = 9;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
let addr_mode = AddressMode::try_from(buf[0])?;
let request_address = match addr_mode {
AddressMode::NoAddress => MacAddress { short: [0, 0] },
AddressMode::Reserved => MacAddress { short: [0, 0] },
AddressMode::Short => MacAddress {
short: [buf[1], buf[2]],
},
AddressMode::Extended => MacAddress {
extended: [buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8]],
},
};
Ok(Self {
addr_mode,
request_address,
})
}
}

View File

@ -0,0 +1,32 @@
#[macro_export]
macro_rules! numeric_enum {
(#[repr($repr:ident)]
$(#$attrs:tt)* $vis:vis enum $name:ident {
$($(#$enum_attrs:tt)* $enum:ident = $constant:expr),* $(,)?
} ) => {
#[repr($repr)]
$(#$attrs)*
$vis enum $name {
$($(#$enum_attrs)* $enum = $constant),*
}
impl ::core::convert::TryFrom<$repr> for $name {
type Error = ();
fn try_from(value: $repr) -> ::core::result::Result<Self, ()> {
match value {
$($constant => Ok( $name :: $enum ),)*
_ => Err(())
}
}
}
impl ::core::convert::From<$name> for $repr {
fn from(value: $name) -> $repr {
match value {
$($name :: $enum => $constant,)*
}
}
}
}
}

View File

@ -0,0 +1,9 @@
pub mod commands;
mod consts;
pub mod event;
mod helpers;
pub mod indications;
mod macros;
mod opcodes;
pub mod responses;
pub mod typedefs;

View File

@ -0,0 +1,92 @@
const ST_VENDOR_OGF: u16 = 0x3F;
const MAC_802_15_4_CMD_OPCODE_OFFSET: u16 = 0x280;
const fn opcode(ocf: u16) -> isize {
((ST_VENDOR_OGF << 9) | (MAC_802_15_4_CMD_OPCODE_OFFSET + ocf)) as isize
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum OpcodeM4ToM0 {
MlmeAssociateReq = opcode(0x00),
MlmeAssociateRes = opcode(0x01),
MlmeDisassociateReq = opcode(0x02),
MlmeGetReq = opcode(0x03),
MlmeGtsReq = opcode(0x04),
MlmeOrphanRes = opcode(0x05),
MlmeResetReq = opcode(0x06),
MlmeRxEnableReq = opcode(0x07),
MlmeScanReq = opcode(0x08),
MlmeSetReq = opcode(0x09),
MlmeStartReq = opcode(0x0A),
MlmeSyncReq = opcode(0x0B),
MlmePollReq = opcode(0x0C),
MlmeDpsReq = opcode(0x0D),
MlmeSoundingReq = opcode(0x0E),
MlmeCalibrateReq = opcode(0x0F),
McpsDataReq = opcode(0x10),
McpsPurgeReq = opcode(0x11),
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum OpcodeM0ToM4 {
MlmeAssociateCnf = 0x00,
MlmeDisassociateCnf,
MlmeGetCnf,
MlmeGtsCnf,
MlmeResetCnf,
MlmeRxEnableCnf,
MlmeScanCnf,
MlmeSetCnf,
MlmeStartCnf,
MlmePollCnf,
MlmeDpsCnf,
MlmeSoundingCnf,
MlmeCalibrateCnf,
McpsDataCnf,
McpsPurgeCnf,
MlmeAssociateInd,
MlmeDisassociateInd,
MlmeBeaconNotifyInd,
MlmeCommStatusInd,
MlmeGtsInd,
MlmeOrphanInd,
MlmeSyncLossInd,
MlmeDpsInd,
McpsDataInd,
MlmePollInd,
}
impl TryFrom<u16> for OpcodeM0ToM4 {
type Error = ();
fn try_from(value: u16) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::MlmeAssociateCnf),
1 => Ok(Self::MlmeDisassociateCnf),
2 => Ok(Self::MlmeGetCnf),
3 => Ok(Self::MlmeGtsCnf),
4 => Ok(Self::MlmeResetCnf),
5 => Ok(Self::MlmeRxEnableCnf),
6 => Ok(Self::MlmeScanCnf),
7 => Ok(Self::MlmeSetCnf),
8 => Ok(Self::MlmeStartCnf),
9 => Ok(Self::MlmePollCnf),
10 => Ok(Self::MlmeDpsCnf),
11 => Ok(Self::MlmeSoundingCnf),
12 => Ok(Self::MlmeCalibrateCnf),
13 => Ok(Self::McpsDataCnf),
14 => Ok(Self::McpsPurgeCnf),
15 => Ok(Self::MlmeAssociateInd),
16 => Ok(Self::MlmeDisassociateInd),
17 => Ok(Self::MlmeBeaconNotifyInd),
18 => Ok(Self::MlmeCommStatusInd),
19 => Ok(Self::MlmeGtsInd),
20 => Ok(Self::MlmeOrphanInd),
21 => Ok(Self::MlmeSyncLossInd),
22 => Ok(Self::MlmeDpsInd),
23 => Ok(Self::McpsDataInd),
24 => Ok(Self::MlmePollInd),
_ => Err(()),
}
}
}

View File

@ -0,0 +1,433 @@
use super::consts::{MAX_ED_SCAN_RESULTS_SUPPORTED, MAX_PAN_DESC_SUPPORTED, MAX_SOUNDING_LIST_SUPPORTED};
use super::event::ParseableMacEvent;
use super::helpers::to_u32;
use super::typedefs::{
AddressMode, AssociationStatus, KeyIdMode, MacAddress, MacStatus, PanDescriptor, PanId, PibId, ScanType,
SecurityLevel,
};
/// MLME ASSOCIATE Confirm used to inform of the initiating device whether
/// its request to associate was successful or unsuccessful
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AssociateConfirm {
/// short address allocated by the coordinator on successful association
pub assoc_short_address: [u8; 2],
/// status of the association request
pub status: AssociationStatus,
/// security level to be used
pub security_level: SecurityLevel,
/// the originator of the key to be used
pub key_source: [u8; 8],
/// the mode used to identify the key to be used
pub key_id_mode: KeyIdMode,
/// the index of the key to be used
pub key_index: u8,
}
impl ParseableMacEvent for AssociateConfirm {
const SIZE: usize = 16;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
assoc_short_address: [buf[0], buf[1]],
status: AssociationStatus::try_from(buf[2])?,
security_level: SecurityLevel::try_from(buf[3])?,
key_source: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]],
key_id_mode: KeyIdMode::try_from(buf[12])?,
key_index: buf[13],
})
}
}
/// MLME DISASSOCIATE Confirm used to send disassociation Confirmation to the application.
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DisassociateConfirm {
/// status of the disassociation attempt
pub status: MacStatus,
/// device addressing mode used
pub device_addr_mode: AddressMode,
/// the identifier of the PAN of the device
pub device_pan_id: PanId,
/// device address
pub device_address: MacAddress,
}
impl ParseableMacEvent for DisassociateConfirm {
const SIZE: usize = 12;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
let device_addr_mode = AddressMode::try_from(buf[1])?;
let device_address = match device_addr_mode {
AddressMode::NoAddress => MacAddress { short: [0, 0] },
AddressMode::Reserved => MacAddress { short: [0, 0] },
AddressMode::Short => MacAddress {
short: [buf[4], buf[5]],
},
AddressMode::Extended => MacAddress {
extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]],
},
};
Ok(Self {
status: MacStatus::try_from(buf[0])?,
device_addr_mode,
device_pan_id: PanId([buf[2], buf[3]]),
device_address,
})
}
}
/// MLME GET Confirm which requests information about a given PIB attribute
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GetConfirm {
/// The pointer to the value of the PIB attribute attempted to read
pub pib_attribute_value_ptr: *const u8,
/// Status of the GET attempt
pub status: MacStatus,
/// The name of the PIB attribute attempted to read
pub pib_attribute: PibId,
/// The lenght of the PIB attribute Value return
pub pib_attribute_value_len: u8,
}
impl ParseableMacEvent for GetConfirm {
const SIZE: usize = 8;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
let address = to_u32(&buf[0..4]);
Ok(Self {
pib_attribute_value_ptr: address as *const u8,
status: MacStatus::try_from(buf[4])?,
pib_attribute: PibId::try_from(buf[5])?,
pib_attribute_value_len: buf[6],
})
}
}
/// MLME GTS Confirm which eports the results of a request to allocate a new GTS
/// or to deallocate an existing GTS
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GtsConfirm {
/// The characteristics of the GTS
pub gts_characteristics: u8,
/// The status of the GTS reques
pub status: MacStatus,
}
impl ParseableMacEvent for GtsConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
gts_characteristics: buf[0],
status: MacStatus::try_from(buf[1])?,
})
}
}
/// MLME RESET Confirm which is used to report the results of the reset operation
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ResetConfirm {
/// The result of the reset operation
status: MacStatus,
}
impl ParseableMacEvent for ResetConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
status: MacStatus::try_from(buf[0])?,
})
}
}
/// MLME RX ENABLE Confirm which is used to report the results of the attempt
/// to enable or disable the receiver
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct RxEnableConfirm {
/// Result of the request to enable or disable the receiver
status: MacStatus,
}
impl ParseableMacEvent for RxEnableConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
status: MacStatus::try_from(buf[0])?,
})
}
}
/// MLME SCAN Confirm which is used to report the result of the channel scan request
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ScanConfirm {
/// Status of the scan request
pub status: MacStatus,
/// The type of scan performed
pub scan_type: ScanType,
/// Channel page on which the scan was performed
pub channel_page: u8,
/// Channels given in the request which were not scanned
pub unscanned_channels: [u8; 4],
/// Number of elements returned in the appropriate result lists
pub result_list_size: u8,
/// List of energy measurements
pub energy_detect_list: [u8; MAX_ED_SCAN_RESULTS_SUPPORTED],
/// List of PAN descriptors
pub pan_descriptor_list: [PanDescriptor; MAX_PAN_DESC_SUPPORTED],
/// Categorization of energy detected in channel
pub detected_category: u8,
/// For UWB PHYs, the list of energy measurements taken
pub uwb_energy_detect_list: [u8; MAX_ED_SCAN_RESULTS_SUPPORTED],
}
impl ParseableMacEvent for ScanConfirm {
const SIZE: usize = 185;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
// TODO: this is unchecked
Self::validate(buf)?;
let mut energy_detect_list = [0; MAX_ED_SCAN_RESULTS_SUPPORTED];
energy_detect_list.copy_from_slice(&buf[8..24]);
let pan_descriptor_list = [
PanDescriptor::try_from(&buf[24..46])?,
PanDescriptor::try_from(&buf[46..68])?,
PanDescriptor::try_from(&buf[68..90])?,
PanDescriptor::try_from(&buf[90..102])?,
PanDescriptor::try_from(&buf[102..124])?,
PanDescriptor::try_from(&buf[124..146])?,
];
let mut uwb_energy_detect_list = [0; MAX_ED_SCAN_RESULTS_SUPPORTED];
uwb_energy_detect_list.copy_from_slice(&buf[147..163]);
Ok(Self {
status: MacStatus::try_from(buf[0])?,
scan_type: ScanType::try_from(buf[1])?,
channel_page: buf[2],
unscanned_channels: [buf[3], buf[4], buf[5], buf[6]],
result_list_size: buf[7],
energy_detect_list,
pan_descriptor_list,
detected_category: buf[146],
uwb_energy_detect_list,
})
}
}
/// MLME SET Confirm which reports the result of an attempt to write a value to a PIB attribute
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SetConfirm {
/// The result of the set operation
pub status: MacStatus,
/// The name of the PIB attribute that was written
pub pin_attribute: PibId,
}
impl ParseableMacEvent for SetConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
status: MacStatus::try_from(buf[0])?,
pin_attribute: PibId::try_from(buf[1])?,
})
}
}
/// MLME START Confirm which is used to report the results of the attempt to
/// start using a new superframe configuration
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct StartConfirm {
/// Result of the attempt to start using an updated superframe configuration
pub status: MacStatus,
}
impl ParseableMacEvent for StartConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
status: MacStatus::try_from(buf[0])?,
})
}
}
/// MLME POLL Confirm which is used to report the result of a request to poll the coordinator for data
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PollConfirm {
/// The status of the data request
pub status: MacStatus,
}
impl ParseableMacEvent for PollConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
status: MacStatus::try_from(buf[0])?,
})
}
}
/// MLME DPS Confirm which reports the results of the attempt to enable or disable the DPS
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DpsConfirm {
/// The status of the DPS request
pub status: MacStatus,
}
impl ParseableMacEvent for DpsConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
status: MacStatus::try_from(buf[0])?,
})
}
}
/// MLME SOUNDING Confirm which reports the result of a request to the PHY to provide
/// channel sounding information
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SoundingConfirm {
/// Results of the sounding measurement
sounding_list: [u8; MAX_SOUNDING_LIST_SUPPORTED],
}
impl ParseableMacEvent for SoundingConfirm {
const SIZE: usize = 1;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
let mut sounding_list = [0u8; MAX_SOUNDING_LIST_SUPPORTED];
sounding_list[..buf.len()].copy_from_slice(buf);
Ok(Self { sounding_list })
}
}
/// MLME CALIBRATE Confirm which reports the result of a request to the PHY
/// to provide internal propagation path information
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CalibrateConfirm {
/// The status of the attempt to return sounding data
pub status: MacStatus,
/// A count of the propagation time from the ranging counter
/// to the transmit antenna
pub cal_tx_rmaker_offset: u32,
/// A count of the propagation time from the receive antenna
/// to the ranging counter
pub cal_rx_rmaker_offset: u32,
}
impl ParseableMacEvent for CalibrateConfirm {
const SIZE: usize = 12;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
status: MacStatus::try_from(buf[0])?,
// 3 byte stuffing
cal_tx_rmaker_offset: to_u32(&buf[4..8]),
cal_rx_rmaker_offset: to_u32(&buf[8..12]),
})
}
}
/// MCPS DATA Confirm which will be used for reporting the results of
/// MAC data related requests from the application
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DataConfirm {
/// The handle associated with the MSDU being confirmed
pub msdu_handle: u8,
/// The time, in symbols, at which the data were transmitted
pub time_stamp: [u8; 4],
/// ranging status
pub ranging_received: u8,
/// The status of the last MSDU transmission
pub status: MacStatus,
/// time units corresponding to an RMARKER at the antenna at
/// the beginning of a ranging exchange
pub ranging_counter_start: u32,
/// time units corresponding to an RMARKER at the antenna
/// at the end of a ranging exchange
pub ranging_counter_stop: u32,
/// time units in a message exchange over which the tracking offset was measured
pub ranging_tracking_interval: u32,
/// time units slipped or advanced by the radio tracking system
pub ranging_offset: u32,
/// The FoM characterizing the ranging measurement
pub ranging_fom: u8,
}
impl ParseableMacEvent for DataConfirm {
const SIZE: usize = 28;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
msdu_handle: buf[0],
time_stamp: [buf[1], buf[2], buf[3], buf[4]],
ranging_received: buf[5],
status: MacStatus::try_from(buf[6])?,
ranging_counter_start: to_u32(&buf[7..11]),
ranging_counter_stop: to_u32(&buf[11..15]),
ranging_tracking_interval: to_u32(&buf[15..19]),
ranging_offset: to_u32(&buf[19..23]),
ranging_fom: buf[24],
})
}
}
/// MCPS PURGE Confirm which will be used by the MAC to notify the application of
/// the status of its request to purge an MSDU from the transaction queue
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PurgeConfirm {
/// Handle associated with the MSDU requested to be purged from the transaction queue
pub msdu_handle: u8,
/// The status of the request
pub status: MacStatus,
}
impl ParseableMacEvent for PurgeConfirm {
const SIZE: usize = 4;
fn try_parse(buf: &[u8]) -> Result<Self, ()> {
Self::validate(buf)?;
Ok(Self {
msdu_handle: buf[0],
status: MacStatus::try_from(buf[1])?,
})
}
}

View File

@ -0,0 +1,363 @@
use crate::numeric_enum;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum MacError {
Error = 0x01,
NotImplemented = 0x02,
NotSupported = 0x03,
HardwareNotSupported = 0x04,
Undefined = 0x05,
}
impl From<u8> for MacError {
fn from(value: u8) -> Self {
match value {
0x01 => Self::Error,
0x02 => Self::NotImplemented,
0x03 => Self::NotSupported,
0x04 => Self::HardwareNotSupported,
0x05 => Self::Undefined,
_ => Self::Undefined,
}
}
}
numeric_enum! {
#[repr(u8)]
#[derive(Debug, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum MacStatus {
#[default]
Success = 0x00,
Failure = 0xFF
}
}
numeric_enum! {
#[repr(u8)]
/// this enum contains all the MAC PIB Ids
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum PibId {
// PHY
CurrentChannel = 0x00,
ChannelsSupported = 0x01,
TransmitPower = 0x02,
CCAMode = 0x03,
CurrentPage = 0x04,
MaxFrameDuration = 0x05,
SHRDuration = 0x06,
SymbolsPerOctet = 0x07,
// MAC
AckWaitDuration = 0x40,
AssociationPermit = 0x41,
AutoRequest = 0x42,
BeaconPayload = 0x45,
BeaconPayloadLength = 0x46,
BeaconOrder = 0x47,
Bsn = 0x49,
CoordExtendedAdddress = 0x4A,
CoordShortAddress = 0x4B,
Dsn = 0x4C,
MaxFrameTotalWaitTime = 0x58,
MaxFrameRetries = 0x59,
PanId = 0x50,
ResponseWaitTime = 0x5A,
RxOnWhenIdle = 0x52,
SecurityEnabled = 0x5D,
ShortAddress = 0x53,
SuperframeOrder = 0x54,
TimestampSupported = 0x5C,
TransactionPersistenceTime = 0x55,
MaxBe = 0x57,
LifsPeriod = 0x5E,
SifsPeriod = 0x5F,
MaxCsmaBackoffs = 0x4E,
MinBe = 0x4F,
PanCoordinator = 0x10,
AssocPanCoordinator = 0x11,
ExtendedAddress = 0x6F,
AclEntryDescriptor = 0x70,
AclEntryDescriptorSize = 0x71,
DefaultSecurity = 0x72,
DefaultSecurityMaterialLength = 0x73,
DefaultSecurityMaterial = 0x74,
DefaultSecuritySuite = 0x75,
SecurityMode = 0x76,
CurrentAclEntries = 0x80,
DefaultSecurityExtendedAddress = 0x81,
AssociatedPanCoordinator = 0x56,
PromiscuousMode = 0x51,
}
}
numeric_enum! {
#[repr(u8)]
#[derive(Default, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum AddressMode {
#[default]
NoAddress = 0x00,
Reserved = 0x01,
Short = 0x02,
Extended = 0x03,
}
}
#[derive(Clone, Copy)]
pub union MacAddress {
pub short: [u8; 2],
pub extended: [u8; 8],
}
#[cfg(feature = "defmt")]
impl defmt::Format for MacAddress {
fn format(&self, fmt: defmt::Formatter) {
unsafe {
defmt::write!(
fmt,
"MacAddress {{ short: {}, extended: {} }}",
self.short,
self.extended
)
}
}
}
impl Default for MacAddress {
fn default() -> Self {
Self { short: [0, 0] }
}
}
impl MacAddress {
pub const BROADCAST: Self = Self { short: [0xFF, 0xFF] };
}
impl TryFrom<&[u8]> for MacAddress {
type Error = ();
fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
const SIZE: usize = 8;
if buf.len() < SIZE {
return Err(());
}
Ok(Self {
extended: [buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]],
})
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GtsCharacteristics {
pub fields: u8,
}
/// MAC PAN Descriptor which contains the network details of the device from
/// which the beacon is received
#[derive(Default, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PanDescriptor {
/// PAN identifier of the coordinator
pub coord_pan_id: PanId,
/// Coordinator addressing mode
pub coord_addr_mode: AddressMode,
/// The current logical channel occupied by the network
pub logical_channel: MacChannel,
/// Coordinator address
pub coord_addr: MacAddress,
/// The current channel page occupied by the network
pub channel_page: u8,
/// PAN coordinator is accepting GTS requests or not
pub gts_permit: bool,
/// Superframe specification as specified in the received beacon frame
pub superframe_spec: [u8; 2],
/// The time at which the beacon frame was received, in symbols
pub time_stamp: [u8; 4],
/// The LQI at which the network beacon was received
pub link_quality: u8,
/// Security level purportedly used by the received beacon frame
pub security_level: u8,
}
impl TryFrom<&[u8]> for PanDescriptor {
type Error = ();
fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
const SIZE: usize = 22;
if buf.len() < SIZE {
return Err(());
}
let coord_addr_mode = AddressMode::try_from(buf[2])?;
let coord_addr = match coord_addr_mode {
AddressMode::NoAddress => MacAddress { short: [0, 0] },
AddressMode::Reserved => MacAddress { short: [0, 0] },
AddressMode::Short => MacAddress {
short: [buf[4], buf[5]],
},
AddressMode::Extended => MacAddress {
extended: [buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]],
},
};
Ok(Self {
coord_pan_id: PanId([buf[0], buf[1]]),
coord_addr_mode,
logical_channel: MacChannel::try_from(buf[3])?,
coord_addr,
channel_page: buf[12],
gts_permit: buf[13] != 0,
superframe_spec: [buf[14], buf[15]],
time_stamp: [buf[16], buf[17], buf[18], buf[19]],
link_quality: buf[20],
security_level: buf[21],
// 2 byte stuffing
})
}
}
numeric_enum! {
#[repr(u8)]
#[derive(Default, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Building wireless applications with STM32WB series MCUs - Application note 13.10.3
pub enum MacChannel {
Channel11 = 0x0B,
Channel12 = 0x0C,
Channel13 = 0x0D,
Channel14 = 0x0E,
Channel15 = 0x0F,
#[default]
Channel16 = 0x10,
Channel17 = 0x11,
Channel18 = 0x12,
Channel19 = 0x13,
Channel20 = 0x14,
Channel21 = 0x15,
Channel22 = 0x16,
Channel23 = 0x17,
Channel24 = 0x18,
Channel25 = 0x19,
Channel26 = 0x1A,
}
}
#[cfg(not(feature = "defmt"))]
bitflags::bitflags! {
pub struct Capabilities: u8 {
/// 1 if the device is capabaleof becoming a PAN coordinator
const IS_COORDINATOR_CAPABLE = 0b00000001;
/// 1 if the device is an FFD, 0 if it is an RFD
const IS_FFD = 0b00000010;
/// 1 if the device is receiving power from mains, 0 if it is battery-powered
const IS_MAINS_POWERED = 0b00000100;
/// 1 if the device does not disable its receiver to conserver power during idle periods
const RECEIVER_ON_WHEN_IDLE = 0b00001000;
// 0b00010000 reserved
// 0b00100000 reserved
/// 1 if the device is capable of sending and receiving secured MAC frames
const IS_SECURE = 0b01000000;
/// 1 if the device wishes the coordinator to allocate a short address as a result of the association
const ALLOCATE_ADDRESS = 0b10000000;
}
}
#[cfg(feature = "defmt")]
defmt::bitflags! {
pub struct Capabilities: u8 {
/// 1 if the device is capabaleof becoming a PAN coordinator
const IS_COORDINATOR_CAPABLE = 0b00000001;
/// 1 if the device is an FFD, 0 if it is an RFD
const IS_FFD = 0b00000010;
/// 1 if the device is receiving power from mains, 0 if it is battery-powered
const IS_MAINS_POWERED = 0b00000100;
/// 1 if the device does not disable its receiver to conserver power during idle periods
const RECEIVER_ON_WHEN_IDLE = 0b00001000;
// 0b00010000 reserved
// 0b00100000 reserved
/// 1 if the device is capable of sending and receiving secured MAC frames
const IS_SECURE = 0b01000000;
/// 1 if the device wishes the coordinator to allocate a short address as a result of the association
const ALLOCATE_ADDRESS = 0b10000000;
}
}
numeric_enum! {
#[repr(u8)]
#[derive(Default, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum KeyIdMode {
#[default]
/// the key is determined implicitly from the originator and recipient(s) of the frame
Implicite = 0x00,
/// the key is determined explicitly using a 1 bytes key source and a 1 byte key index
Explicite1Byte = 0x01,
/// the key is determined explicitly using a 4 bytes key source and a 1 byte key index
Explicite4Byte = 0x02,
/// the key is determined explicitly using a 8 bytes key source and a 1 byte key index
Explicite8Byte = 0x03,
}
}
numeric_enum! {
#[repr(u8)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum AssociationStatus {
/// Association successful
Success = 0x00,
/// PAN at capacity
PanAtCapacity = 0x01,
/// PAN access denied
PanAccessDenied = 0x02
}
}
numeric_enum! {
#[repr(u8)]
#[derive(Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DisassociationReason {
/// The coordinator wishes the device to leave the PAN.
CoordRequested = 0x01,
/// The device wishes to leave the PAN.
DeviceRequested = 0x02,
}
}
numeric_enum! {
#[repr(u8)]
#[derive(Default, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SecurityLevel {
/// MAC Unsecured Mode Security
#[default]
Unsecure = 0x00,
/// MAC ACL Mode Security
AclMode = 0x01,
/// MAC Secured Mode Security
Secured = 0x02,
}
}
numeric_enum! {
#[repr(u8)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ScanType {
EdScan = 0x00,
Active = 0x01,
Passive = 0x02,
Orphan = 0x03
}
}
/// newtype for Pan Id
#[derive(Default, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PanId(pub [u8; 2]);
impl PanId {
pub const BROADCAST: Self = Self([0xFF, 0xFF]);
}

View File

@ -11,9 +11,10 @@ use embassy_sync::waitqueue::AtomicWaker;
use crate::cmd::CmdPacket;
use crate::consts::TlPacketType;
use crate::evt::{EvtBox, EvtPacket};
use crate::tables::{
Mac802_15_4Table, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, TL_MAC_802_15_4_TABLE,
};
use crate::mac::commands::MacCommand;
use crate::mac::event::MacEvent;
use crate::mac::typedefs::MacError;
use crate::tables::{MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER};
use crate::{channels, evt};
static MAC_WAKER: AtomicWaker = AtomicWaker::new();
@ -25,21 +26,13 @@ pub struct Mac {
impl Mac {
pub(crate) fn new() -> Self {
unsafe {
TL_MAC_802_15_4_TABLE.as_mut_ptr().write_volatile(Mac802_15_4Table {
p_cmdrsp_buffer: MAC_802_15_4_CMD_BUFFER.as_mut_ptr().cast(),
p_notack_buffer: MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr().cast(),
evt_queue: ptr::null_mut(),
});
}
Self { phantom: PhantomData }
}
/// `HW_IPCC_MAC_802_15_4_EvtNot`
///
/// This function will stall if the previous `EvtBox` has not been dropped
pub async fn read(&self) -> EvtBox<Self> {
pub async fn tl_read(&self) -> EvtBox<Self> {
// Wait for the last event box to be dropped
poll_fn(|cx| {
MAC_WAKER.register(cx.waker());
@ -63,9 +56,9 @@ impl Mac {
}
/// `HW_IPCC_MAC_802_15_4_CmdEvtNot`
pub async fn write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 {
self.write(opcode, payload).await;
Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
pub async fn tl_write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 {
self.tl_write(opcode, payload).await;
Ipcc::flush(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL).await;
unsafe {
let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket;
@ -76,19 +69,46 @@ impl Mac {
}
/// `TL_MAC_802_15_4_SendCmd`
pub async fn write(&self, opcode: u16, payload: &[u8]) {
pub async fn tl_write(&self, opcode: u16, payload: &[u8]) {
Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe {
CmdPacket::write_into(
MAC_802_15_4_CMD_BUFFER.as_mut_ptr(),
TlPacketType::OtCmd,
TlPacketType::MacCmd,
opcode,
payload,
);
})
.await;
}
pub async fn send_command<T>(&self, cmd: &T) -> Result<(), MacError>
where
T: MacCommand,
{
let mut payload = [0u8; MAX_PACKET_SIZE];
cmd.copy_into_slice(&mut payload);
let response = self
.tl_write_and_get_response(T::OPCODE as u16, &payload[..T::SIZE])
.await;
if response == 0x00 {
Ok(())
} else {
Err(MacError::from(response))
}
}
pub async fn read(&self) -> Result<MacEvent, ()> {
let evt_box = self.tl_read().await;
let payload = evt_box.payload();
MacEvent::try_from(payload)
}
}
const MAX_PACKET_SIZE: usize = 255;
impl evt::MemoryManager for Mac {
/// SAFETY: passing a pointer to something other than a managed event packet is UB
unsafe fn drop_event_packet(_: *mut EvtPacket) {

View File

@ -4,20 +4,21 @@ use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::task::Poll;
use aligned::{Aligned, A4};
use cortex_m::interrupt;
use embassy_stm32::ipcc::Ipcc;
use embassy_sync::waitqueue::AtomicWaker;
use crate::consts::POOL_SIZE;
use crate::evt::EvtPacket;
use crate::tables::{
MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUF_QUEUE, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE,
};
#[cfg(feature = "ble")]
use crate::tables::BLE_SPARE_EVT_BUF;
use crate::tables::{MemManagerTable, EVT_POOL, FREE_BUF_QUEUE, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE};
use crate::unsafe_linked_list::LinkedListNode;
use crate::{channels, evt};
static MM_WAKER: AtomicWaker = AtomicWaker::new();
static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
static mut LOCAL_FREE_BUF_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit());
pub struct MemoryManager {
phantom: PhantomData<MemoryManager>,
@ -30,7 +31,10 @@ impl MemoryManager {
LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable {
#[cfg(feature = "ble")]
spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
#[cfg(not(feature = "ble"))]
spare_ble_buffer: core::ptr::null(),
spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(),
blepool: EVT_POOL.as_ptr().cast(),
blepoolsize: POOL_SIZE as u32,

View File

@ -50,7 +50,7 @@ impl Sys {
}
/// `HW_IPCC_SYS_CmdEvtNot`
pub async fn write_and_get_response(&self, opcode: ShciOpcode, payload: &[u8]) -> SchiCommandStatus {
pub async fn write_and_get_response(&self, opcode: ShciOpcode, payload: &[u8]) -> Result<SchiCommandStatus, ()> {
self.write(opcode, payload).await;
Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
@ -59,17 +59,36 @@ impl Sys {
let p_command_event = &((*p_event_packet).evt_serial.evt.payload) as *const _ as *const CcEvt;
let p_payload = &((*p_command_event).payload) as *const u8;
ptr::read_volatile(p_payload).try_into().unwrap()
ptr::read_volatile(p_payload).try_into()
}
}
#[cfg(feature = "mac")]
pub async fn shci_c2_mac_802_15_4_init(&self) -> SchiCommandStatus {
pub async fn shci_c2_mac_802_15_4_init(&self) -> Result<SchiCommandStatus, ()> {
use crate::tables::{
Mac802_15_4Table, TracesTable, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER,
TL_MAC_802_15_4_TABLE, TL_TRACES_TABLE, TRACES_EVT_QUEUE,
};
unsafe {
LinkedListNode::init_head(TRACES_EVT_QUEUE.as_mut_ptr() as *mut _);
TL_TRACES_TABLE.as_mut_ptr().write_volatile(TracesTable {
traces_queue: TRACES_EVT_QUEUE.as_ptr() as *const _,
});
TL_MAC_802_15_4_TABLE.as_mut_ptr().write_volatile(Mac802_15_4Table {
p_cmdrsp_buffer: MAC_802_15_4_CMD_BUFFER.as_mut_ptr().cast(),
p_notack_buffer: MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr().cast(),
evt_queue: core::ptr::null_mut(),
});
};
self.write_and_get_response(ShciOpcode::Mac802_15_4Init, &[]).await
}
#[cfg(feature = "ble")]
pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> SchiCommandStatus {
pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> Result<SchiCommandStatus, ()> {
self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await
}

View File

@ -4,6 +4,8 @@ use aligned::{Aligned, A4};
use bit_field::BitField;
use crate::cmd::{AclDataPacket, CmdPacket};
#[cfg(feature = "mac")]
use crate::consts::C_SIZE_CMD_STRING;
use crate::consts::{POOL_SIZE, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE};
use crate::unsafe_linked_list::LinkedListNode;
@ -80,7 +82,7 @@ impl WirelessFwInfoTable {
}
#[derive(Debug, Clone)]
#[repr(C, align(4))]
#[repr(C)]
pub struct DeviceInfoTable {
pub safe_boot_info_table: SafeBootInfoTable,
pub rss_info_table: RssInfoTable,
@ -88,7 +90,7 @@ pub struct DeviceInfoTable {
}
#[derive(Debug)]
#[repr(C, align(4))]
#[repr(C)]
pub struct BleTable {
pub pcmd_buffer: *mut CmdPacket,
pub pcs_buffer: *const u8,
@ -97,16 +99,15 @@ pub struct BleTable {
}
#[derive(Debug)]
#[repr(C, align(4))]
#[repr(C)]
pub struct ThreadTable {
pub nostack_buffer: *const u8,
pub clicmdrsp_buffer: *const u8,
pub otcmdrsp_buffer: *const u8,
}
// TODO: use later
#[derive(Debug)]
#[repr(C, align(4))]
#[repr(C)]
pub struct LldTestsTable {
pub clicmdrsp_buffer: *const u8,
pub m0cmd_buffer: *const u8,
@ -114,7 +115,7 @@ pub struct LldTestsTable {
// TODO: use later
#[derive(Debug)]
#[repr(C, align(4))]
#[repr(C)]
pub struct BleLldTable {
pub cmdrsp_buffer: *const u8,
pub m0cmd_buffer: *const u8,
@ -122,7 +123,7 @@ pub struct BleLldTable {
// TODO: use later
#[derive(Debug)]
#[repr(C, align(4))]
#[repr(C)]
pub struct ZigbeeTable {
pub notif_m0_to_m4_buffer: *const u8,
pub appli_cmd_m4_to_m0_bufer: *const u8,
@ -130,14 +131,14 @@ pub struct ZigbeeTable {
}
#[derive(Debug)]
#[repr(C, align(4))]
#[repr(C)]
pub struct SysTable {
pub pcmd_buffer: *mut CmdPacket,
pub sys_queue: *const LinkedListNode,
}
#[derive(Debug)]
#[repr(C, align(4))]
#[repr(C)]
pub struct MemManagerTable {
pub spare_ble_buffer: *const u8,
pub spare_sys_buffer: *const u8,
@ -152,13 +153,13 @@ pub struct MemManagerTable {
}
#[derive(Debug)]
#[repr(C, align(4))]
#[repr(C)]
pub struct TracesTable {
pub traces_queue: *const u8,
}
#[derive(Debug)]
#[repr(C, align(4))]
#[repr(C)]
pub struct Mac802_15_4Table {
pub p_cmdrsp_buffer: *const u8,
pub p_notack_buffer: *const u8,
@ -176,6 +177,9 @@ pub struct RefTable {
pub mem_manager_table: *const MemManagerTable,
pub traces_table: *const TracesTable,
pub mac_802_15_4_table: *const Mac802_15_4Table,
pub zigbee_table: *const ZigbeeTable,
pub lld_tests_table: *const LldTestsTable,
pub ble_lld_table: *const BleLldTable,
}
// --------------------- ref table ---------------------
@ -183,57 +187,57 @@ pub struct RefTable {
pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit();
#[link_section = "MB_MEM1"]
pub static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit();
pub static mut TL_DEVICE_INFO_TABLE: Aligned<A4, MaybeUninit<DeviceInfoTable>> = Aligned(MaybeUninit::uninit());
#[link_section = "MB_MEM1"]
pub static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit();
pub static mut TL_BLE_TABLE: Aligned<A4, MaybeUninit<BleTable>> = Aligned(MaybeUninit::uninit());
#[link_section = "MB_MEM1"]
pub static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit();
// #[link_section = "MB_MEM1"]
// pub static mut TL_LLD_TESTS_TABLE: MaybeUninit<LldTestTable> = MaybeUninit::uninit();
// #[link_section = "MB_MEM1"]
// pub static mut TL_BLE_LLD_TABLE: MaybeUninit<BleLldTable> = MaybeUninit::uninit();
pub static mut TL_THREAD_TABLE: Aligned<A4, MaybeUninit<ThreadTable>> = Aligned(MaybeUninit::uninit());
#[link_section = "MB_MEM1"]
pub static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit();
pub static mut TL_LLD_TESTS_TABLE: Aligned<A4, MaybeUninit<LldTestsTable>> = Aligned(MaybeUninit::uninit());
#[link_section = "MB_MEM1"]
pub static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit();
pub static mut TL_BLE_LLD_TABLE: Aligned<A4, MaybeUninit<BleLldTable>> = Aligned(MaybeUninit::uninit());
#[link_section = "MB_MEM1"]
pub static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit();
pub static mut TL_SYS_TABLE: Aligned<A4, MaybeUninit<SysTable>> = Aligned(MaybeUninit::uninit());
#[link_section = "MB_MEM1"]
pub static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit();
pub static mut TL_MEM_MANAGER_TABLE: Aligned<A4, MaybeUninit<MemManagerTable>> = Aligned(MaybeUninit::uninit());
// #[link_section = "MB_MEM1"]
// pub static mut TL_ZIGBEE_TABLE: MaybeUninit<ZigbeeTable> = MaybeUninit::uninit();
#[link_section = "MB_MEM1"]
pub static mut TL_TRACES_TABLE: Aligned<A4, MaybeUninit<TracesTable>> = Aligned(MaybeUninit::uninit());
#[link_section = "MB_MEM1"]
pub static mut TL_MAC_802_15_4_TABLE: Aligned<A4, MaybeUninit<Mac802_15_4Table>> = Aligned(MaybeUninit::uninit());
#[link_section = "MB_MEM1"]
pub static mut TL_ZIGBEE_TABLE: Aligned<A4, MaybeUninit<ZigbeeTable>> = Aligned(MaybeUninit::uninit());
// --------------------- tables ---------------------
#[link_section = "MB_MEM1"]
pub static mut FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
pub static mut FREE_BUF_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit());
#[allow(dead_code)]
#[link_section = "MB_MEM1"]
pub static mut TRACES_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
pub static mut TRACES_EVT_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit());
#[link_section = "MB_MEM2"]
pub static mut CS_BUFFER: MaybeUninit<Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]>> =
MaybeUninit::uninit();
pub static mut CS_BUFFER: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]>> =
Aligned(MaybeUninit::uninit());
#[link_section = "MB_MEM2"]
pub static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
pub static mut EVT_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit());
#[link_section = "MB_MEM2"]
pub static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
pub static mut SYSTEM_EVT_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit());
// --------------------- app tables ---------------------
#[cfg(feature = "mac")]
#[link_section = "MB_MEM2"]
pub static mut MAC_802_15_4_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
pub static mut MAC_802_15_4_CMD_BUFFER: Aligned<A4, MaybeUninit<CmdPacket>> = Aligned(MaybeUninit::uninit());
#[cfg(feature = "mac")]
#[link_section = "MB_MEM2"]
@ -242,23 +246,31 @@ pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit<
> = MaybeUninit::uninit();
#[link_section = "MB_MEM2"]
pub static mut EVT_POOL: MaybeUninit<Aligned<A4, [u8; POOL_SIZE]>> = MaybeUninit::uninit();
pub static mut EVT_POOL: Aligned<A4, MaybeUninit<[u8; POOL_SIZE]>> = Aligned(MaybeUninit::uninit());
#[link_section = "MB_MEM2"]
pub static mut SYS_CMD_BUF: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
pub static mut SYS_CMD_BUF: Aligned<A4, MaybeUninit<CmdPacket>> = Aligned(MaybeUninit::uninit());
#[link_section = "MB_MEM2"]
pub static mut SYS_SPARE_EVT_BUF: MaybeUninit<Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>> =
MaybeUninit::uninit();
pub static mut SYS_SPARE_EVT_BUF: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>> =
Aligned(MaybeUninit::uninit());
#[cfg(feature = "mac")]
#[link_section = "MB_MEM2"]
pub static mut MAC_802_15_4_CNFINDNOT: Aligned<A4, MaybeUninit<[u8; C_SIZE_CMD_STRING]>> =
Aligned(MaybeUninit::uninit());
#[cfg(feature = "ble")]
#[link_section = "MB_MEM1"]
pub static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
pub static mut BLE_CMD_BUFFER: Aligned<A4, MaybeUninit<CmdPacket>> = Aligned(MaybeUninit::uninit());
#[cfg(feature = "ble")]
#[link_section = "MB_MEM2"]
pub static mut BLE_SPARE_EVT_BUF: MaybeUninit<Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>> =
MaybeUninit::uninit();
pub static mut BLE_SPARE_EVT_BUF: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]>> =
Aligned(MaybeUninit::uninit());
#[cfg(feature = "ble")]
#[link_section = "MB_MEM2"]
// fuck these "magic" numbers from ST ---v---v
pub static mut HCI_ACL_DATA_BUFFER: MaybeUninit<Aligned<A4, [u8; TL_PACKET_HEADER_SIZE + 5 + 251]>> =
MaybeUninit::uninit();
pub static mut HCI_ACL_DATA_BUFFER: Aligned<A4, MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]>> =
Aligned(MaybeUninit::uninit());

View File

@ -32,7 +32,7 @@ flavors = [
[dependencies]
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-4"] }
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
@ -40,9 +40,9 @@ embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true}
embedded-hal-nb = { version = "=1.0.0-alpha.2", optional = true}
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true}
embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true}
embedded-hal-nb = { version = "=1.0.0-alpha.3", optional = true}
embedded-storage = "0.3.0"
embedded-storage-async = { version = "0.4.0", optional = true }

View File

@ -348,9 +348,7 @@ fn main() {
g.extend(quote! {
impl crate::rcc::sealed::RccPeripheral for peripherals::#pname {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| unsafe {
crate::rcc::get_freqs().#clk
})
unsafe { crate::rcc::get_freqs().#clk }
}
fn enable() {
critical_section::with(|_| {

View File

@ -1,3 +1,4 @@
use core::cell::{RefCell, RefMut};
use core::future::poll_fn;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
@ -72,7 +73,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup
}
pub struct Can<'d, T: Instance> {
can: bxcan::Can<BxcanInstance<'d, T>>,
pub can: RefCell<bxcan::Can<BxcanInstance<'d, T>>>,
}
#[derive(Debug)]
@ -147,19 +148,24 @@ impl<'d, T: Instance> Can<'d, T> {
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled();
Self { can }
let can_ref_cell = RefCell::new(can);
Self { can: can_ref_cell }
}
pub fn set_bitrate(&mut self, bitrate: u32) {
let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap();
self.can.modify_config().set_bit_timing(bit_timing).leave_disabled();
self.can
.borrow_mut()
.modify_config()
.set_bit_timing(bit_timing)
.leave_disabled();
}
/// Queues the message to be sent but exerts backpressure
pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
if let Ok(status) = self.can.transmit(frame) {
if let Ok(status) = self.can.borrow_mut().transmit(frame) {
return Poll::Ready(status);
}
@ -341,6 +347,79 @@ impl<'d, T: Instance> Can<'d, T> {
// Pack into BTR register values
Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler as u32 - 1))
}
pub fn split<'c>(&'c self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) {
(CanTx { can: &self.can }, CanRx { can: &self.can })
}
pub fn as_mut(&self) -> RefMut<'_, bxcan::Can<BxcanInstance<'d, T>>> {
self.can.borrow_mut()
}
}
pub struct CanTx<'c, 'd, T: Instance> {
can: &'c RefCell<bxcan::Can<BxcanInstance<'d, T>>>,
}
impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
if let Ok(status) = self.can.borrow_mut().transmit(frame) {
return Poll::Ready(status);
}
Poll::Pending
})
.await
}
pub async fn flush(&self, mb: bxcan::Mailbox) {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
if T::regs().tsr().read().tme(mb.index()) {
return Poll::Ready(());
}
Poll::Pending
})
.await;
}
}
#[allow(dead_code)]
pub struct CanRx<'c, 'd, T: Instance> {
can: &'c RefCell<bxcan::Can<BxcanInstance<'d, T>>>,
}
impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> {
pub async fn read(&mut self) -> Result<(u16, bxcan::Frame), BusError> {
poll_fn(|cx| {
T::state().err_waker.register(cx.waker());
if let Poll::Ready((time, frame)) = T::state().rx_queue.recv().poll_unpin(cx) {
return Poll::Ready(Ok((time, frame)));
} else if let Some(err) = self.curr_error() {
return Poll::Ready(Err(err));
}
Poll::Pending
})
.await
}
fn curr_error(&self) -> Option<BusError> {
let err = { T::regs().esr().read() };
if err.boff() {
return Some(BusError::BusOff);
} else if err.epvf() {
return Some(BusError::BusPassive);
} else if err.ewgf() {
return Some(BusError::BusWarning);
} else if let Some(err) = err.lec().into_bus_err() {
return Some(err);
}
None
}
}
enum RxFifo {
@ -358,7 +437,7 @@ impl<'d, T: Instance> Drop for Can<'d, T> {
}
impl<'d, T: Instance> Deref for Can<'d, T> {
type Target = bxcan::Can<BxcanInstance<'d, T>>;
type Target = RefCell<bxcan::Can<BxcanInstance<'d, T>>>;
fn deref(&self) -> &Self::Target {
&self.can

View File

@ -264,7 +264,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
});
let tx_request = self.dma.request();
let dma_channel = &self.dma;
let dma_channel = &mut self.dma;
let tx_options = crate::dma::TransferOptions {
circular,
@ -376,7 +376,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
});
let tx_request = self.dma.request();
let dma_channel = &self.dma;
let dma_channel = &mut self.dma;
let tx_options = crate::dma::TransferOptions {
circular,

View File

@ -1,10 +1,9 @@
use core::future::Future;
use core::marker::PhantomData;
use core::pin::Pin;
use core::sync::atomic::{fence, Ordering};
use core::sync::atomic::{fence, AtomicUsize, Ordering};
use core::task::{Context, Poll, Waker};
use atomic_polyfill::AtomicUsize;
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;

View File

@ -1,5 +1,11 @@
//! Generic SMI Ethernet PHY
#[cfg(feature = "time")]
use embassy_time::{Duration, Timer};
use futures::task::Context;
#[cfg(feature = "time")]
use futures::FutureExt;
use super::{StationManagement, PHY};
#[allow(dead_code)]
@ -36,25 +42,48 @@ mod phy_consts {
use self::phy_consts::*;
/// Generic SMI Ethernet PHY
pub struct GenericSMI;
pub struct GenericSMI {
#[cfg(feature = "time")]
poll_interval: Duration,
}
impl GenericSMI {
#[cfg(feature = "time")]
pub fn new() -> Self {
Self {
poll_interval: Duration::from_millis(500),
}
}
#[cfg(not(feature = "time"))]
pub fn new() -> Self {
Self {}
}
}
unsafe impl PHY for GenericSMI {
/// Reset PHY and wait for it to come out of reset.
fn phy_reset<S: StationManagement>(sm: &mut S) {
fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) {
sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET);
while sm.smi_read(PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {}
}
/// PHY initialisation.
fn phy_init<S: StationManagement>(sm: &mut S) {
fn phy_init<S: StationManagement>(&mut self, sm: &mut S) {
// Clear WU CSR
Self::smi_write_ext(sm, PHY_REG_WUCSR, 0);
self.smi_write_ext(sm, PHY_REG_WUCSR, 0);
// Enable auto-negotiation
sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M);
}
fn poll_link<S: StationManagement>(sm: &mut S) -> bool {
fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool {
#[cfg(not(feature = "time"))]
cx.waker().wake_by_ref();
#[cfg(feature = "time")]
let _ = Timer::after(self.poll_interval).poll_unpin(cx);
let bsr = sm.smi_read(PHY_REG_BSR);
// No link without autonegotiate
@ -73,8 +102,12 @@ unsafe impl PHY for GenericSMI {
/// Public functions for the PHY
impl GenericSMI {
pub fn set_poll_interval(&mut self, poll_interval: Duration) {
self.poll_interval = poll_interval
}
// Writes a value to an extended PHY register in MMD address space
fn smi_write_ext<S: StationManagement>(sm: &mut S, reg_addr: u16, reg_data: u16) {
fn smi_write_ext<S: StationManagement>(&mut self, sm: &mut S, reg_addr: u16, reg_data: u16) {
sm.smi_write(PHY_REG_CTL, 0x0003); // set address
sm.smi_write(PHY_REG_ADDAR, reg_addr);
sm.smi_write(PHY_REG_CTL, 0x4003); // set data

View File

@ -81,9 +81,7 @@ impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P>
}
fn link_state(&mut self, cx: &mut Context) -> LinkState {
// TODO: wake cx.waker on link state change
cx.waker().wake_by_ref();
if P::poll_link(self) {
if self.phy.poll_link(&mut self.station_management, cx) {
LinkState::Up
} else {
LinkState::Down
@ -148,11 +146,11 @@ pub unsafe trait StationManagement {
/// The methods cannot move S
pub unsafe trait PHY {
/// Reset PHY and wait for it to come out of reset.
fn phy_reset<S: StationManagement>(sm: &mut S);
fn phy_reset<S: StationManagement>(&mut self, sm: &mut S);
/// PHY initialisation.
fn phy_init<S: StationManagement>(sm: &mut S);
fn phy_init<S: StationManagement>(&mut self, sm: &mut S);
/// Poll link to see if it is up and FD with 100Mbps
fn poll_link<S: StationManagement>(sm: &mut S) -> bool;
fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool;
}
pub(crate) mod sealed {

View File

@ -3,6 +3,7 @@
mod rx_desc;
mod tx_desc;
use core::marker::PhantomData;
use core::sync::atomic::{fence, Ordering};
use embassy_hal_common::{into_ref, PeripheralRef};
@ -48,9 +49,8 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
pub(crate) rx: RDesRing<'d>,
pins: [PeripheralRef<'d, AnyPin>; 9],
_phy: P,
clock_range: Cr,
phy_addr: u8,
pub(crate) phy: P,
pub(crate) station_management: EthernetStationManagement<T>,
pub(crate) mac_addr: [u8; 6],
}
@ -224,9 +224,12 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
let mut this = Self {
_peri: peri,
pins,
_phy: phy,
clock_range,
phy_addr,
phy: phy,
station_management: EthernetStationManagement {
peri: PhantomData,
clock_range: clock_range,
phy_addr: phy_addr,
},
mac_addr,
tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
@ -256,8 +259,8 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
w.set_tie(true);
});
P::phy_reset(&mut this);
P::phy_init(&mut this);
this.phy.phy_reset(&mut this.station_management);
this.phy.phy_init(&mut this.station_management);
interrupt::ETH.unpend();
unsafe { interrupt::ETH.enable() };
@ -266,7 +269,13 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
}
}
unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
pub struct EthernetStationManagement<T: Instance> {
peri: PhantomData<T>,
clock_range: Cr,
phy_addr: u8,
}
unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
fn smi_read(&mut self, reg: u8) -> u16 {
let mac = ETH.ethernet_mac();

View File

@ -1,5 +1,6 @@
mod descriptors;
use core::marker::PhantomData;
use core::sync::atomic::{fence, Ordering};
use embassy_hal_common::{into_ref, PeripheralRef};
@ -40,9 +41,8 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
pub(crate) tx: TDesRing<'d>,
pub(crate) rx: RDesRing<'d>,
pins: [PeripheralRef<'d, AnyPin>; 9],
_phy: P,
clock_range: u8,
phy_addr: u8,
pub(crate) phy: P,
pub(crate) station_management: EthernetStationManagement<T>,
pub(crate) mac_addr: [u8; 6],
}
@ -201,9 +201,12 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
pins,
_phy: phy,
clock_range,
phy_addr,
phy: phy,
station_management: EthernetStationManagement {
peri: PhantomData,
clock_range: clock_range,
phy_addr: phy_addr,
},
mac_addr,
};
@ -229,8 +232,8 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
w.set_tie(true);
});
P::phy_reset(&mut this);
P::phy_init(&mut this);
this.phy.phy_reset(&mut this.station_management);
this.phy.phy_init(&mut this.station_management);
interrupt::ETH.unpend();
unsafe { interrupt::ETH.enable() };
@ -239,7 +242,13 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
}
}
unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
pub struct EthernetStationManagement<T: Instance> {
peri: PhantomData<T>,
clock_range: u8,
phy_addr: u8,
}
unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
fn smi_read(&mut self, reg: u8) -> u16 {
let mac = ETH.ethernet_mac();

View File

@ -1,6 +1,6 @@
use core::marker::PhantomData;
use core::sync::atomic::{fence, Ordering};
use atomic_polyfill::{fence, Ordering};
use embassy_hal_common::drop::OnDrop;
use embassy_hal_common::into_ref;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;

View File

@ -1,6 +1,6 @@
use core::marker::PhantomData;
use core::sync::atomic::{fence, Ordering};
use atomic_polyfill::{fence, Ordering};
use embassy_hal_common::drop::OnDrop;
use embassy_hal_common::{into_ref, PeripheralRef};
use stm32_metapac::FLASH_BASE;

View File

@ -1,7 +1,6 @@
use core::convert::TryInto;
use core::ptr::write_volatile;
use atomic_polyfill::{fence, Ordering};
use core::sync::atomic::{fence, Ordering};
use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
use crate::flash::Error;

View File

@ -1,7 +1,6 @@
use core::convert::TryInto;
use core::ptr::write_volatile;
use atomic_polyfill::{fence, Ordering};
use core::sync::atomic::{fence, Ordering};
use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
use crate::flash::Error;

View File

@ -1,8 +1,7 @@
use core::convert::TryInto;
use core::ptr::write_volatile;
use core::sync::atomic::{fence, Ordering};
use core::sync::atomic::{fence, AtomicBool, Ordering};
use atomic_polyfill::AtomicBool;
use embassy_sync::waitqueue::AtomicWaker;
use pac::flash::regs::Sr;
use pac::FLASH_SIZE;

View File

@ -1,7 +1,6 @@
use core::convert::TryInto;
use core::ptr::write_volatile;
use atomic_polyfill::{fence, Ordering};
use core::sync::atomic::{fence, Ordering};
use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE};
use crate::flash::Error;

View File

@ -1,6 +1,5 @@
use core::ptr::write_volatile;
use atomic_polyfill::{fence, Ordering};
use core::sync::atomic::{fence, Ordering};
use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
use crate::flash::Error;

View File

@ -86,6 +86,24 @@ macro_rules! fmc_sdram_constructor {
}
impl<'d, T: Instance> Fmc<'d, T> {
fmc_sdram_constructor!(sdram_a12bits_d16bits_4banks_bank1: (
bank: stm32_fmc::SdramTargetBank::Bank1,
addr: [
(a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin)
],
ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
d: [
(d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
(d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin)
],
nbl: [
(nbl0: NBL0Pin), (nbl1: NBL1Pin)
],
ctrl: [
(sdcke: SDCKE0Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE0Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
]
));
fmc_sdram_constructor!(sdram_a12bits_d32bits_4banks_bank1: (
bank: stm32_fmc::SdramTargetBank::Bank1,
addr: [

View File

@ -382,13 +382,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// I2C start
//
// ST SAD+W
Self::master_write(
if let Err(err) = Self::master_write(
address,
write.len().min(255),
Stop::Software,
last_chunk_idx != 0,
&check_timeout,
)?;
) {
if send_stop {
self.master_stop();
}
return Err(err);
}
for (number, chunk) in write.chunks(255).enumerate() {
if number != 0 {
@ -399,18 +404,22 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// Wait until we are allowed to send data
// (START has been ACKed or last byte when
// through)
self.wait_txe(&check_timeout)?;
if let Err(err) = self.wait_txe(&check_timeout) {
if send_stop {
self.master_stop();
}
return Err(err);
}
T::regs().txdr().write(|w| w.set_txdata(*byte));
}
}
// Wait until the write finishes
self.wait_tc(&check_timeout)?;
let result = self.wait_tc(&check_timeout);
if send_stop {
self.master_stop();
}
Ok(())
result
}
async fn write_dma_internal(
@ -707,13 +716,16 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let first_length = write[0].len();
let last_slice_index = write.len() - 1;
Self::master_write(
if let Err(err) = Self::master_write(
address,
first_length.min(255),
Stop::Software,
(first_length > 255) || (last_slice_index != 0),
&check_timeout,
)?;
) {
self.master_stop();
return Err(err);
}
for (idx, slice) in write.iter().enumerate() {
let slice_len = slice.len();
@ -726,27 +738,36 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let last_chunk_idx = total_chunks.saturating_sub(1);
if idx != 0 {
Self::master_continue(
if let Err(err) = Self::master_continue(
slice_len.min(255),
(idx != last_slice_index) || (slice_len > 255),
&check_timeout,
)?;
) {
self.master_stop();
return Err(err);
}
}
for (number, chunk) in slice.chunks(255).enumerate() {
if number != 0 {
Self::master_continue(
if let Err(err) = Self::master_continue(
chunk.len(),
(number != last_chunk_idx) || (idx != last_slice_index),
&check_timeout,
)?;
) {
self.master_stop();
return Err(err);
}
}
for byte in chunk {
// Wait until we are allowed to send data
// (START has been ACKed or last byte when
// through)
self.wait_txe(&check_timeout)?;
if let Err(err) = self.wait_txe(&check_timeout) {
self.master_stop();
return Err(err);
}
// Put byte on the wire
//self.i2c.txdr.write(|w| w.txdata().bits(*byte));
@ -755,10 +776,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
}
}
// Wait until the write finishes
self.wait_tc(&check_timeout)?;
let result = self.wait_tc(&check_timeout);
self.master_stop();
Ok(())
result
}
pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {

View File

@ -1,8 +1,7 @@
use core::future::poll_fn;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
use atomic_polyfill::{compiler_fence, Ordering};
use self::sealed::Instance;
use crate::interrupt;
use crate::interrupt::typelevel::Interrupt;

View File

@ -473,11 +473,11 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
w.set_divm(0);
});
return PllOutput{
return PllOutput {
p: None,
q: None,
r: None,
}
};
};
assert!(1 <= config.prediv && config.prediv <= 63);

View File

@ -740,7 +740,7 @@ mod pll {
}
};
let vco_ck = output + pll_x_p;
let vco_ck = output * pll_x_p;
assert!(pll_x_p < 128);
assert!(vco_ck >= VCO_MIN);

View File

@ -1,6 +1,7 @@
use core::marker::PhantomData;
use embassy_hal_common::into_ref;
use stm32_metapac::rcc::regs::Cfgr;
use stm32_metapac::rcc::vals::{Lsedrv, Mcopre, Mcosel};
use crate::gpio::sealed::AFType;
@ -439,6 +440,26 @@ impl<'d, T: McoInstance> Mco<'d, T> {
}
pub(crate) unsafe fn init(config: Config) {
// Switch to MSI to prevent problems with PLL configuration.
if !RCC.cr().read().msion() {
// Turn on MSI and configure it to 4MHz.
RCC.cr().modify(|w| {
w.set_msirgsel(true); // MSI Range is provided by MSIRANGE[3:0].
w.set_msirange(MSIRange::default().into());
w.set_msipllen(false);
w.set_msion(true)
});
// Wait until MSI is running
while !RCC.cr().read().msirdy() {}
}
if RCC.cfgr().read().sws() != Sw::MSI {
// Set MSI as a clock source, reset prescalers.
RCC.cfgr().write_value(Cfgr::default());
// Wait for clock switch status bits to change.
while RCC.cfgr().read().sws() != Sw::MSI {}
}
match config.rtc_mux {
RtcClockSource::LSE32 => {
// 1. Unlock the backup domain
@ -660,6 +681,8 @@ pub(crate) unsafe fn init(config: Config) {
}
};
RCC.apb1enr1().modify(|w| w.set_pwren(true));
set_freqs(Clocks {
sys: Hertz(sys_clk),
ahb1: Hertz(ahb_freq),

View File

@ -83,12 +83,12 @@ static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
/// Safety: Sets a mutable global.
pub(crate) unsafe fn set_freqs(freqs: Clocks) {
debug!("rcc: {:?}", freqs);
CLOCK_FREQS.as_mut_ptr().write(freqs);
CLOCK_FREQS = MaybeUninit::new(freqs);
}
/// Safety: Reads a mutable global.
pub(crate) unsafe fn get_freqs() -> &'static Clocks {
&*CLOCK_FREQS.as_ptr()
CLOCK_FREQS.assume_init_ref()
}
#[cfg(feature = "unstable-pac")]

View File

@ -1,4 +1,5 @@
use crate::pac::{FLASH, RCC};
use crate::pac::pwr::vals::Dbp;
use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
@ -184,6 +185,8 @@ pub struct Config {
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
pub enable_lsi: bool,
pub enable_rtc_apb: bool,
pub rtc_mux: RtcClockSource,
}
impl Default for Config {
@ -196,10 +199,25 @@ impl Default for Config {
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
enable_lsi: false,
enable_rtc_apb: false,
rtc_mux: RtcClockSource::LSI32,
}
}
}
pub enum RtcClockSource {
LSE32,
LSI32,
}
#[repr(u8)]
pub enum Lsedrv {
Low = 0,
MediumLow = 1,
MediumHigh = 2,
High = 3,
}
pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw, vos) = match config.mux {
ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::Range2),
@ -266,6 +284,32 @@ pub(crate) unsafe fn init(config: Config) {
while FLASH.acr().read().latency() != ws {}
match config.rtc_mux {
RtcClockSource::LSE32 => {
// 1. Unlock the backup domain
PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED));
// 2. Setup the LSE
RCC.bdcr().modify(|w| {
// Enable LSE
w.set_lseon(true);
// Max drive strength
// TODO: should probably be settable
w.set_lsedrv(Lsedrv::High as u8); //---// PAM - should not be commented
});
// Wait until LSE is running
while !RCC.bdcr().read().lserdy() {}
}
RtcClockSource::LSI32 => {
// Turn on the internal 32 kHz LSI oscillator
RCC.csr().modify(|w| w.set_lsion(true));
// Wait until LSI is running
while !RCC.csr().read().lsirdy() {}
}
}
match config.mux {
ClockSrc::HSI16 => {
// Enable HSI16
@ -287,11 +331,26 @@ pub(crate) unsafe fn init(config: Config) {
w.set_msirgsel(true);
w.set_msirange(range.into());
w.set_msion(true);
if let RtcClockSource::LSE32 = config.rtc_mux {
// If LSE is enabled, enable calibration of MSI
w.set_msipllen(true);
} else {
w.set_msipllen(false);
}
});
while !RCC.cr().read().msirdy() {}
}
}
if config.enable_rtc_apb {
// enable peripheral clock for communication
crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true));
// read to allow the pwr clock to enable
crate::pac::PWR.cr1().read();
}
RCC.extcfgr().modify(|w| {
if config.shd_ahb_pre == AHBPrescaler::NotDivided {
w.set_shdhpre(0);

View File

@ -172,6 +172,7 @@ impl sealed::Instance for crate::peripherals::RTC {
const BACKUP_REGISTER_COUNT: usize = 32;
fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> {
#[allow(clippy::if_same_then_else)]
if register < Self::BACKUP_REGISTER_COUNT {
//Some(rtc.bkpr()[register].read().bits())
None // RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC

View File

@ -852,25 +852,19 @@ mod eh1 {
type Error = Error;
}
impl<'d, T: Instance, Tx, Rx> embedded_hal_1::spi::SpiBusFlush for Spi<'d, T, Tx, Rx> {
impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> {
fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBusRead<W> for Spi<'d, T, Tx, Rx> {
fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
self.blocking_read(words)
}
}
impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBusWrite<W> for Spi<'d, T, Tx, Rx> {
fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
self.blocking_write(words)
}
}
impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> {
fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
self.blocking_transfer(read, write)
}
@ -895,32 +889,25 @@ mod eh1 {
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
mod eha {
use super::*;
impl<'d, T: Instance, Tx, Rx> embedded_hal_async::spi::SpiBusFlush for Spi<'d, T, Tx, Rx> {
impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> {
async fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<'d, T: Instance, Tx: TxDma<T>, Rx, W: Word> embedded_hal_async::spi::SpiBusWrite<W> for Spi<'d, T, Tx, Rx> {
async fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
self.write(words).await
}
}
impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBusRead<W>
for Spi<'d, T, Tx, Rx>
{
async fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
self.read(words).await
}
}
impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> {
async fn transfer<'a>(&'a mut self, read: &'a mut [W], write: &'a [W]) -> Result<(), Self::Error> {
async fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
self.transfer(read, write).await
}
async fn transfer_in_place<'a>(&'a mut self, words: &'a mut [W]) -> Result<(), Self::Error> {
async fn transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
self.transfer_in_place(words).await
}
}

View File

@ -1,8 +1,8 @@
use core::cell::UnsafeCell;
use core::marker::PhantomData;
use core::sync::atomic::{AtomicBool, AtomicU16, Ordering};
use core::task::Poll;
use atomic_polyfill::{AtomicBool, AtomicU16, Ordering};
use embassy_hal_common::{into_ref, Peripheral};
use embassy_sync::waitqueue::AtomicWaker;
use embassy_usb_driver::{
@ -648,7 +648,7 @@ impl<'d, T: Instance> Bus<'d, T> {
let r = T::regs();
let core_id = r.cid().read().0;
info!("Core id {:08x}", core_id);
trace!("Core id {:08x}", core_id);
// Wait for AHB ready.
while !r.grstctl().read().ahbidl() {}
@ -1154,14 +1154,22 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointOut for Endpoint<'d, T, Out> {
trace!("read start len={}", buf.len());
poll_fn(|cx| {
let r = T::regs();
let index = self.info.addr.index();
let state = T::state();
state.ep_out_wakers[index].register(cx.waker());
let doepctl = r.doepctl(index).read();
trace!("read ep={:?}: doepctl {:08x}", self.info.addr, doepctl.0,);
if !doepctl.usbaep() {
trace!("read ep={:?} error disabled", self.info.addr);
return Poll::Ready(Err(EndpointError::Disabled));
}
let len = state.ep_out_size[index].load(Ordering::Relaxed);
if len != EP_OUT_BUFFER_EMPTY {
trace!("read done len={}", len);
trace!("read ep={:?} done len={}", self.info.addr, len);
if len as usize > buf.len() {
return Poll::Ready(Err(EndpointError::BufferOverflow));
@ -1214,7 +1222,12 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
let diepctl = r.diepctl(index).read();
let dtxfsts = r.dtxfsts(index).read();
info!("diepctl {:08x} ftxfsts {:08x}", diepctl.0, dtxfsts.0);
trace!(
"write ep={:?}: diepctl {:08x} ftxfsts {:08x}",
self.info.addr,
diepctl.0,
dtxfsts.0
);
if !diepctl.usbaep() {
trace!("write ep={:?} wait for prev: error disabled", self.info.addr);
Poll::Ready(Err(EndpointError::Disabled))

View File

@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 0.1.2 - 2023-07-05
- Update `embedded-hal-async` to `0.2.0-alpha.2`.
- Update `embedded-hal v1` to `1.0.0-alpha.11`. (Note: v0.2 support is kept unchanged).
## 0.1.1 - 2023-04-13
- Update `embedded-hal-async` to `0.2.0-alpha.1` (uses `async fn` in traits).

View File

@ -1,6 +1,6 @@
[package]
name = "embassy-time"
version = "0.1.1"
version = "0.1.2"
edition = "2021"
description = "Instant and Duration for embedded no-std systems, with async timer support"
repository = "https://github.com/embassy-rs/embassy"
@ -23,7 +23,7 @@ target = "x86_64-unknown-linux-gnu"
features = ["nightly", "defmt", "unstable-traits", "std"]
[features]
std = ["tick-hz-1_000_000"]
std = ["tick-hz-1_000_000", "critical-section/std"]
wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000"]
# Enable nightly-only features
@ -152,8 +152,8 @@ defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" }
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
embedded-hal-async = { version = "=0.2.0-alpha.1", optional = true}
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true}
embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true}
futures-util = { version = "0.3.17", default-features = false }
atomic-polyfill = "1.0.1"

View File

@ -36,7 +36,7 @@
//! ```
//! use embassy_time::driver::{Driver, AlarmHandle};
//!
//! struct MyDriver{}; // not public!
//! struct MyDriver{} // not public!
//! embassy_time::time_driver_impl!(static DRIVER: MyDriver = MyDriver{});
//!
//! impl Driver for MyDriver {

View File

@ -1,10 +1,10 @@
use core::sync::atomic::{AtomicU8, Ordering};
use std::cell::{RefCell, UnsafeCell};
use std::mem::MaybeUninit;
use std::sync::{Condvar, Mutex, Once};
use std::time::{Duration as StdDuration, Instant as StdInstant};
use std::{mem, ptr, thread};
use atomic_polyfill::{AtomicU8, Ordering};
use critical_section::Mutex as CsMutex;
use crate::driver::{AlarmHandle, Driver};

View File

@ -1,9 +1,9 @@
use core::sync::atomic::{AtomicU8, Ordering};
use std::cell::UnsafeCell;
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::{Mutex, Once};
use atomic_polyfill::{AtomicU8, Ordering};
use wasm_bindgen::prelude::*;
use wasm_timer::Instant as StdInstant;

View File

@ -16,7 +16,7 @@ const QUEUE_SIZE: usize = 16;
#[cfg(feature = "generic-queue-32")]
const QUEUE_SIZE: usize = 32;
#[cfg(feature = "generic-queue-64")]
const QUEUE_SIZE: usize = 32;
const QUEUE_SIZE: usize = 64;
#[cfg(feature = "generic-queue-128")]
const QUEUE_SIZE: usize = 128;
#[cfg(not(any(

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly"] }
embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly"] }
embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = ["nightly"] }
embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf", features = ["nightly"] }

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly"] }
embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] }
embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32h743zi", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }

Some files were not shown because too many files have changed in this diff Show More