Merge pull request #2 from embassy-rs/main
Pull changes from base embassy repo
This commit is contained in:
commit
6d8a5c6c20
199 changed files with 4983 additions and 964 deletions
51
.github/ci/doc.sh
vendored
51
.github/ci/doc.sh
vendored
|
@ -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
4
ci.sh
|
@ -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=""
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
```
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -69,51 +69,36 @@ 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(())
|
||||
}
|
||||
|
||||
async fn read(&mut self, data: &mut [Word]) -> Result<(), Self::Error> {
|
||||
self.wrapped.read(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> {
|
||||
self.wrapped.read(data).await?;
|
||||
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(())
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ 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-time = { version = "0.1.2", path = "../embassy-time", optional = true}
|
||||
atomic-polyfill = "1.0.1"
|
||||
critical-section = "1.1"
|
||||
static_cell = "1.1"
|
||||
|
|
|
@ -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 => {}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
{
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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" }
|
||||
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.0" }
|
||||
embassy-futures = { version = "0.1.0" }
|
||||
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]
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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,7 +102,17 @@ 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| {
|
||||
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
|
||||
|
@ -111,17 +121,33 @@ impl<'a> UdpSocket<'a> {
|
|||
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| {
|
||||
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(())),
|
||||
|
@ -131,8 +157,6 @@ impl<'a> UdpSocket<'a> {
|
|||
}
|
||||
Err(udp::SendError::Unaddressable) => Poll::Ready(Err(Error::NoRoute)),
|
||||
})
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Returns the local endpoint of the socket.
|
||||
|
|
|
@ -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,15 +91,15 @@ _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 }
|
||||
|
|
|
@ -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()])
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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(®s().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(®s().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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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])
|
||||
}
|
||||
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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 pin’s
|
||||
// > digital functions must be disabled by setting IE low and OD
|
||||
// > high in the pin’s 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,77 +162,43 @@ 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 {
|
||||
_empty: (),
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -252,7 +252,6 @@ pub fn init(config: config::Config) -> Peripherals {
|
|||
#[cfg(feature = "time-driver")]
|
||||
timer::init();
|
||||
dma::init();
|
||||
pio::init();
|
||||
gpio::init();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
pub struct InterruptHandler<PIO: Instance> {
|
||||
_pio: PhantomData<PIO>,
|
||||
}
|
||||
|
||||
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 {
|
||||
WAKERS[0].0[bit].wake();
|
||||
PIO::wakers().0[bit].wake();
|
||||
}
|
||||
}
|
||||
pac::PIO0.irqs(0).inte().write_clear(|m| m.0 = ints);
|
||||
PIO::PIO.irqs(0).inte().write_clear(|m| m.0 = ints);
|
||||
}
|
||||
|
||||
#[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();
|
||||
}
|
||||
}
|
||||
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 {}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ pub enum Error {
|
|||
}
|
||||
|
||||
/// Structure containing date and time information
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DateTime {
|
||||
/// 0..4095
|
||||
pub year: u16,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" ]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
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());
|
||||
}
|
||||
|
|
467
embassy-stm32-wpan/src/mac/commands.rs
Normal file
467
embassy-stm32-wpan/src/mac/commands.rs
Normal 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;
|
||||
}
|
4
embassy-stm32-wpan/src/mac/consts.rs
Normal file
4
embassy-stm32-wpan/src/mac/consts.rs
Normal 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;
|
94
embassy-stm32-wpan/src/mac/event.rs
Normal file
94
embassy-stm32-wpan/src/mac/event.rs
Normal 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)?)),
|
||||
}
|
||||
}
|
||||
}
|
7
embassy-stm32-wpan/src/mac/helpers.rs
Normal file
7
embassy-stm32-wpan/src/mac/helpers.rs
Normal 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)
|
||||
}
|
470
embassy-stm32-wpan/src/mac/indications.rs
Normal file
470
embassy-stm32-wpan/src/mac/indications.rs
Normal 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,
|
||||
})
|
||||
}
|
||||
}
|
32
embassy-stm32-wpan/src/mac/macros.rs
Normal file
32
embassy-stm32-wpan/src/mac/macros.rs
Normal 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,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
embassy-stm32-wpan/src/mac/mod.rs
Normal file
9
embassy-stm32-wpan/src/mac/mod.rs
Normal 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;
|
92
embassy-stm32-wpan/src/mac/opcodes.rs
Normal file
92
embassy-stm32-wpan/src/mac/opcodes.rs
Normal 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(()),
|
||||
}
|
||||
}
|
||||
}
|
433
embassy-stm32-wpan/src/mac/responses.rs
Normal file
433
embassy-stm32-wpan/src/mac/responses.rs
Normal 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])?,
|
||||
})
|
||||
}
|
||||
}
|
363
embassy-stm32-wpan/src/mac/typedefs.rs
Normal file
363
embassy-stm32-wpan/src/mac/typedefs.rs
Normal 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]);
|
||||
}
|
|
@ -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,18 +69,45 @@ 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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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(|_| {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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: [
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -477,7 +477,7 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
|
|||
p: None,
|
||||
q: None,
|
||||
r: None,
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
assert!(1 <= config.prediv && config.prediv <= 63);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue