Merge branch 'main' of github.com:embassy-rs/embassy
This commit is contained in:
commit
f0a86d1a34
7
.github/ci/test.sh
vendored
7
.github/ci/test.sh
vendored
@ -8,6 +8,10 @@ export RUSTUP_HOME=/ci/cache/rustup
|
|||||||
export CARGO_HOME=/ci/cache/cargo
|
export CARGO_HOME=/ci/cache/cargo
|
||||||
export CARGO_TARGET_DIR=/ci/cache/target
|
export CARGO_TARGET_DIR=/ci/cache/target
|
||||||
|
|
||||||
|
# needed for "dumb HTTP" transport support
|
||||||
|
# used when pointing stm32-metapac to a CI-built one.
|
||||||
|
export CARGO_NET_GIT_FETCH_WITH_CLI=true
|
||||||
|
|
||||||
cargo test --manifest-path ./embassy-futures/Cargo.toml
|
cargo test --manifest-path ./embassy-futures/Cargo.toml
|
||||||
cargo test --manifest-path ./embassy-sync/Cargo.toml
|
cargo test --manifest-path ./embassy-sync/Cargo.toml
|
||||||
cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml
|
cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml
|
||||||
@ -21,7 +25,8 @@ cargo test --manifest-path ./embassy-boot/Cargo.toml --features ed25519-salty
|
|||||||
|
|
||||||
cargo test --manifest-path ./embassy-nrf/Cargo.toml --no-default-features --features nrf52840,time-driver-rtc1,gpiote
|
cargo test --manifest-path ./embassy-nrf/Cargo.toml --no-default-features --features nrf52840,time-driver-rtc1,gpiote
|
||||||
|
|
||||||
cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver
|
cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp2040,_test
|
||||||
|
cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp235xa,_test
|
||||||
|
|
||||||
cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f429vg,exti,time-driver-any,exti
|
cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f429vg,exti,time-driver-any,exti
|
||||||
cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f732ze,exti,time-driver-any,exti
|
cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f732ze,exti,time-driver-any,exti
|
||||||
|
|||||||
58
ci.sh
58
ci.sh
@ -2,11 +2,13 @@
|
|||||||
|
|
||||||
set -eo pipefail
|
set -eo pipefail
|
||||||
|
|
||||||
# check-cfg is stable on rustc 1.79 but not cargo 1.79.
|
if ! command -v cargo-batch &> /dev/null; then
|
||||||
# however, our cargo-batch is currently based on cargo 1.80, which does support check-cfg.
|
echo "cargo-batch could not be found. Install it with the following command:"
|
||||||
# so, force build.rs scripts to emit check-cfg commands.
|
echo ""
|
||||||
# when 1.80 hits stable we can make build.rs unconditionally emit check-cfg and remove all this.
|
echo " cargo install --git https://github.com/embassy-rs/cargo-batch cargo --bin cargo-batch --locked"
|
||||||
export EMBASSY_FORCE_CHECK_CFG=1
|
echo ""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
export RUSTFLAGS=-Dwarnings
|
export RUSTFLAGS=-Dwarnings
|
||||||
export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
|
export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
|
||||||
@ -80,10 +82,13 @@ cargo batch \
|
|||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time,time-driver-rtc1 \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time,time-driver-rtc1 \
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time \
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,time \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,time \
|
||||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt \
|
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt,rp2040 \
|
||||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log \
|
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log,rp2040 \
|
||||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics \
|
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics,rp2040 \
|
||||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,qspi-as-gpio \
|
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,qspi-as-gpio,rp2040 \
|
||||||
|
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,defmt,rp235xa \
|
||||||
|
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,log,rp235xa \
|
||||||
|
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,rp235xa,binary-info \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \
|
||||||
@ -171,12 +176,17 @@ cargo batch \
|
|||||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
|
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
|
||||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs' \
|
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs' \
|
||||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \
|
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \
|
||||||
--- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features '' \
|
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs,bluetooth' \
|
||||||
--- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'overclock' \
|
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs,bluetooth' \
|
||||||
|
--- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \
|
||||||
|
--- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040,overclock' \
|
||||||
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
|
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
|
||||||
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
|
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
|
||||||
--- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi \
|
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \
|
||||||
--- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
|
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns \
|
||||||
|
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns \
|
||||||
|
--- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi --features embassy-rp/rp2040 \
|
||||||
|
--- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \
|
||||||
--- build --release --manifest-path docs/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
|
--- build --release --manifest-path docs/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
|
||||||
--- build --release --manifest-path docs/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \
|
--- build --release --manifest-path docs/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \
|
||||||
--- build --release --manifest-path docs/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \
|
--- build --release --manifest-path docs/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \
|
||||||
@ -186,8 +196,11 @@ cargo batch \
|
|||||||
--- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
|
--- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
|
||||||
--- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
|
--- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
|
||||||
--- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \
|
--- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \
|
||||||
|
--- build --release --manifest-path examples/nrf9151/s/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9151/s \
|
||||||
|
--- build --release --manifest-path examples/nrf9151/ns/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9151/ns \
|
||||||
--- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/nrf51 \
|
--- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/nrf51 \
|
||||||
--- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
|
--- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
|
||||||
|
--- build --release --manifest-path examples/rp23/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/rp23 \
|
||||||
--- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \
|
--- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \
|
||||||
--- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \
|
--- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \
|
||||||
--- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \
|
--- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \
|
||||||
@ -202,6 +215,8 @@ cargo batch \
|
|||||||
--- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32h5 \
|
--- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32h5 \
|
||||||
--- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \
|
--- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \
|
||||||
--- build --release --manifest-path examples/stm32h735/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h735 \
|
--- build --release --manifest-path examples/stm32h735/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h735 \
|
||||||
|
--- build --release --manifest-path examples/stm32h755cm4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h755cm4 \
|
||||||
|
--- build --release --manifest-path examples/stm32h755cm7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h755cm7 \
|
||||||
--- build --release --manifest-path examples/stm32h7rs/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7rs \
|
--- build --release --manifest-path examples/stm32h7rs/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7rs \
|
||||||
--- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \
|
--- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \
|
||||||
--- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \
|
--- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \
|
||||||
@ -214,6 +229,9 @@ cargo batch \
|
|||||||
--- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wl \
|
--- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wl \
|
||||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \
|
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \
|
||||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \
|
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \
|
||||||
|
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns,skip-include --out-dir out/examples/boot/nrf9120 \
|
||||||
|
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns,skip-include --out-dir out/examples/boot/nrf9151 \
|
||||||
|
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns,skip-include --out-dir out/examples/boot/nrf9161 \
|
||||||
--- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \
|
--- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \
|
||||||
--- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \
|
--- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \
|
||||||
--- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \
|
--- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \
|
||||||
@ -225,10 +243,13 @@ cargo batch \
|
|||||||
--- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32wb-dfu \
|
--- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32wb-dfu \
|
||||||
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
|
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
|
||||||
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
|
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
|
||||||
|
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \
|
||||||
|
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns \
|
||||||
|
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns \
|
||||||
--- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
|
--- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
|
||||||
--- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
|
--- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \
|
||||||
--- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg \
|
--- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg \
|
||||||
--- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h747xi-cm7 \
|
--- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h743zi \
|
||||||
--- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
|
--- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \
|
||||||
@ -269,6 +290,9 @@ cargo batch \
|
|||||||
$BUILD_EXTRA
|
$BUILD_EXTRA
|
||||||
|
|
||||||
|
|
||||||
|
# temporarily disabled, bluepill board got bricked
|
||||||
|
rm -rf out/tests/stm32f103c8
|
||||||
|
|
||||||
rm out/tests/stm32wb55rg/wpan_mac
|
rm out/tests/stm32wb55rg/wpan_mac
|
||||||
rm out/tests/stm32wb55rg/wpan_ble
|
rm out/tests/stm32wb55rg/wpan_ble
|
||||||
|
|
||||||
@ -278,8 +302,10 @@ rm out/tests/stm32f207zg/eth
|
|||||||
# doesn't work, gives "noise error", no idea why. usart_dma does pass.
|
# doesn't work, gives "noise error", no idea why. usart_dma does pass.
|
||||||
rm out/tests/stm32u5a5zj/usart
|
rm out/tests/stm32u5a5zj/usart
|
||||||
|
|
||||||
# flaky, perhaps bad wire
|
# flaky, probably due to bad ringbuffered dma code.
|
||||||
rm out/tests/stm32l152re/usart_rx_ringbuffered
|
rm out/tests/stm32l152re/usart_rx_ringbuffered
|
||||||
|
rm out/tests/stm32f207zg/usart_rx_ringbuffered
|
||||||
|
rm out/tests/stm32wl55jc/usart_rx_ringbuffered
|
||||||
|
|
||||||
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
|
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
|
||||||
echo No teleprobe token found, skipping running HIL tests
|
echo No teleprobe token found, skipping running HIL tests
|
||||||
|
|||||||
BIN
cyw43-firmware/43439A0.bin
Executable file → Normal file
BIN
cyw43-firmware/43439A0.bin
Executable file → Normal file
Binary file not shown.
BIN
cyw43-firmware/43439A0_btfw.bin
Normal file
BIN
cyw43-firmware/43439A0_btfw.bin
Normal file
Binary file not shown.
BIN
cyw43-firmware/43439A0_clm.bin
Executable file → Normal file
BIN
cyw43-firmware/43439A0_clm.bin
Executable file → Normal file
Binary file not shown.
@ -1,9 +1,14 @@
|
|||||||
# WiFi firmware
|
# WiFi + Bluetooth firmware blobs
|
||||||
|
|
||||||
Firmware obtained from https://github.com/Infineon/wifi-host-driver/tree/master/WiFi_Host_Driver/resources/firmware/COMPONENT_43439
|
Firmware obtained from https://github.com/georgerobotics/cyw43-driver/tree/main/firmware
|
||||||
|
|
||||||
Licensed under the [Infineon Permissive Binary License](./LICENSE-permissive-binary-license-1.0.txt)
|
Licensed under the [Infineon Permissive Binary License](./LICENSE-permissive-binary-license-1.0.txt)
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
* 2023-07-28: synced with `ad3bad0` - Update 43439 fw from 7.95.55 ot 7.95.62
|
* 2023-08-21: synced with `a1dc885` - Update 43439 fw + clm to come from `wb43439A0_7_95_49_00_combined.h` + add Bluetooth firmware
|
||||||
|
* 2023-07-28: synced with `ad3bad0` - Update 43439 fw from 7.95.55 to 7.95.62
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
If you update these files, please update the lengths in the `tests/rp/src/bin/cyw43_perf.rs` test (which relies on these files running from RAM).
|
||||||
|
|||||||
17
cyw43-pio/CHANGELOG.md
Normal file
17
cyw43-pio/CHANGELOG.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
## 0.2.0 - 2024-08-05
|
||||||
|
|
||||||
|
- Update to cyw43 0.2.0
|
||||||
|
- Update to embassy-rp 0.2.0
|
||||||
|
|
||||||
|
## 0.1.0 - 2024-01-11
|
||||||
|
|
||||||
|
- First release
|
||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cyw43-pio"
|
name = "cyw43-pio"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "RP2040 PIO SPI implementation for cyw43"
|
description = "RP2040 PIO SPI implementation for cyw43"
|
||||||
keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"]
|
keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"]
|
||||||
@ -15,8 +15,8 @@ documentation = "https://docs.embassy.dev/cyw43-pio"
|
|||||||
overclock = []
|
overclock = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cyw43 = { version = "0.1.0", path = "../cyw43" }
|
cyw43 = { version = "0.2.0", path = "../cyw43" }
|
||||||
embassy-rp = { version = "0.1.0", path = "../embassy-rp" }
|
embassy-rp = { version = "0.2.0", path = "../embassy-rp" }
|
||||||
pio-proc = "0.2"
|
pio-proc = "0.2"
|
||||||
pio = "0.2.1"
|
pio = "0.2.1"
|
||||||
fixed = "1.23.1"
|
fixed = "1.23.1"
|
||||||
@ -26,3 +26,4 @@ defmt = { version = "0.3", optional = true }
|
|||||||
src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-pio-v$VERSION/cyw43-pio/src/"
|
src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-pio-v$VERSION/cyw43-pio/src/"
|
||||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43-pio/src/"
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43-pio/src/"
|
||||||
target = "thumbv6m-none-eabi"
|
target = "thumbv6m-none-eabi"
|
||||||
|
features = ["embassy-rp/rp2040"]
|
||||||
|
|||||||
@ -181,7 +181,10 @@ where
|
|||||||
let read_bits = read.len() * 32 + 32 - 1;
|
let read_bits = read.len() * 32 + 32 - 1;
|
||||||
|
|
||||||
#[cfg(feature = "defmt")]
|
#[cfg(feature = "defmt")]
|
||||||
defmt::trace!("write={} read={}", write_bits, read_bits);
|
defmt::trace!("cmd_read write={} read={}", write_bits, read_bits);
|
||||||
|
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
defmt::trace!("cmd_read cmd = {:02x} len = {}", cmd, read.len());
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
instr::set_y(&mut self.sm, read_bits as u32);
|
instr::set_y(&mut self.sm, read_bits as u32);
|
||||||
@ -201,6 +204,10 @@ where
|
|||||||
.rx()
|
.rx()
|
||||||
.dma_pull(self.dma.reborrow(), slice::from_mut(&mut status))
|
.dma_pull(self.dma.reborrow(), slice::from_mut(&mut status))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
defmt::trace!("cmd_read cmd = {:02x} len = {} read = {:08x}", cmd, read.len(), read);
|
||||||
|
|
||||||
status
|
status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
cyw43/CHANGELOG.md
Normal file
23
cyw43/CHANGELOG.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
## 0.2.0 - 2024-08-05
|
||||||
|
|
||||||
|
- Update to new versions of embassy-{time,sync}
|
||||||
|
- Add more fields to the BssInfo packet struct #2461
|
||||||
|
- Extend the Scan API #2282
|
||||||
|
- Reuse buf to reduce stack usage #2580
|
||||||
|
- Add MAC address getter to cyw43 controller #2818
|
||||||
|
- Add function to join WPA2 network with precomputed PSK. #2885
|
||||||
|
- Add function to close soft AP. #3042
|
||||||
|
- Fixing missing re-export #3211
|
||||||
|
|
||||||
|
## 0.1.0 - 2024-01-11
|
||||||
|
|
||||||
|
- First release
|
||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cyw43"
|
name = "cyw43"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Rust driver for the CYW43439 WiFi chip, used in the Raspberry Pi Pico W."
|
description = "Rust driver for the CYW43439 WiFi chip, used in the Raspberry Pi Pico W."
|
||||||
keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"]
|
keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"]
|
||||||
@ -10,17 +10,18 @@ repository = "https://github.com/embassy-rs/embassy"
|
|||||||
documentation = "https://docs.embassy.dev/cyw43"
|
documentation = "https://docs.embassy.dev/cyw43"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
defmt = ["dep:defmt", "heapless/defmt-03", "embassy-time/defmt"]
|
defmt = ["dep:defmt", "heapless/defmt-03", "embassy-time/defmt", "bt-hci?/defmt", "embedded-io-async?/defmt-03"]
|
||||||
log = ["dep:log"]
|
log = ["dep:log"]
|
||||||
|
bluetooth = ["dep:bt-hci", "dep:embedded-io-async"]
|
||||||
|
|
||||||
# Fetch console logs from the WiFi firmware and forward them to `log` or `defmt`.
|
# Fetch console logs from the WiFi firmware and forward them to `log` or `defmt`.
|
||||||
firmware-logs = []
|
firmware-logs = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-time = { version = "0.3.1", path = "../embassy-time"}
|
embassy-time = { version = "0.3.2", path = "../embassy-time"}
|
||||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync"}
|
embassy-sync = { version = "0.6.0", path = "../embassy-sync"}
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
||||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"}
|
embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"}
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.17", optional = true }
|
log = { version = "0.4.17", optional = true }
|
||||||
@ -31,9 +32,12 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
|
|||||||
|
|
||||||
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
|
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
|
||||||
num_enum = { version = "0.5.7", default-features = false }
|
num_enum = { version = "0.5.7", default-features = false }
|
||||||
|
|
||||||
heapless = "0.8.0"
|
heapless = "0.8.0"
|
||||||
|
|
||||||
|
# Bluetooth deps
|
||||||
|
embedded-io-async = { version = "0.6.0", optional = true }
|
||||||
|
bt-hci = { version = "0.1.0", optional = true }
|
||||||
|
|
||||||
[package.metadata.embassy_docs]
|
[package.metadata.embassy_docs]
|
||||||
src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/"
|
src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/"
|
||||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/"
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/"
|
||||||
|
|||||||
508
cyw43/src/bluetooth.rs
Normal file
508
cyw43/src/bluetooth.rs
Normal file
@ -0,0 +1,508 @@
|
|||||||
|
use core::cell::RefCell;
|
||||||
|
use core::future::Future;
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
|
use bt_hci::transport::WithIndicator;
|
||||||
|
use bt_hci::{ControllerToHostPacket, FromHciBytes, HostToControllerPacket, PacketKind, WriteHci};
|
||||||
|
use embassy_futures::yield_now;
|
||||||
|
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||||
|
use embassy_sync::zerocopy_channel;
|
||||||
|
use embassy_time::{Duration, Timer};
|
||||||
|
use embedded_hal_1::digital::OutputPin;
|
||||||
|
|
||||||
|
use crate::bus::Bus;
|
||||||
|
pub use crate::bus::SpiBusCyw43;
|
||||||
|
use crate::consts::*;
|
||||||
|
use crate::util::round_up;
|
||||||
|
use crate::{util, CHIP};
|
||||||
|
|
||||||
|
pub(crate) struct BtState {
|
||||||
|
rx: [BtPacketBuf; 4],
|
||||||
|
tx: [BtPacketBuf; 4],
|
||||||
|
inner: MaybeUninit<BtStateInnre<'static>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BtState {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
rx: [const { BtPacketBuf::new() }; 4],
|
||||||
|
tx: [const { BtPacketBuf::new() }; 4],
|
||||||
|
inner: MaybeUninit::uninit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BtStateInnre<'d> {
|
||||||
|
rx: zerocopy_channel::Channel<'d, NoopRawMutex, BtPacketBuf>,
|
||||||
|
tx: zerocopy_channel::Channel<'d, NoopRawMutex, BtPacketBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bluetooth driver.
|
||||||
|
pub struct BtDriver<'d> {
|
||||||
|
rx: RefCell<zerocopy_channel::Receiver<'d, NoopRawMutex, BtPacketBuf>>,
|
||||||
|
tx: RefCell<zerocopy_channel::Sender<'d, NoopRawMutex, BtPacketBuf>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct BtRunner<'d> {
|
||||||
|
pub(crate) tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, BtPacketBuf>,
|
||||||
|
rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, BtPacketBuf>,
|
||||||
|
|
||||||
|
// Bluetooth circular buffers
|
||||||
|
addr: u32,
|
||||||
|
h2b_write_pointer: u32,
|
||||||
|
b2h_read_pointer: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
const BT_HCI_MTU: usize = 1024;
|
||||||
|
|
||||||
|
/// Represents a packet of size MTU.
|
||||||
|
pub(crate) struct BtPacketBuf {
|
||||||
|
pub(crate) len: usize,
|
||||||
|
pub(crate) buf: [u8; BT_HCI_MTU],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BtPacketBuf {
|
||||||
|
/// Create a new packet buffer.
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
len: 0,
|
||||||
|
buf: [0; BT_HCI_MTU],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new<'d>(state: &'d mut BtState) -> (BtRunner<'d>, BtDriver<'d>) {
|
||||||
|
// safety: this is a self-referential struct, however:
|
||||||
|
// - it can't move while the `'d` borrow is active.
|
||||||
|
// - when the borrow ends, the dangling references inside the MaybeUninit will never be used again.
|
||||||
|
let state_uninit: *mut MaybeUninit<BtStateInnre<'d>> =
|
||||||
|
(&mut state.inner as *mut MaybeUninit<BtStateInnre<'static>>).cast();
|
||||||
|
let state = unsafe { &mut *state_uninit }.write(BtStateInnre {
|
||||||
|
rx: zerocopy_channel::Channel::new(&mut state.rx[..]),
|
||||||
|
tx: zerocopy_channel::Channel::new(&mut state.tx[..]),
|
||||||
|
});
|
||||||
|
|
||||||
|
let (rx_sender, rx_receiver) = state.rx.split();
|
||||||
|
let (tx_sender, tx_receiver) = state.tx.split();
|
||||||
|
|
||||||
|
(
|
||||||
|
BtRunner {
|
||||||
|
tx_chan: tx_receiver,
|
||||||
|
rx_chan: rx_sender,
|
||||||
|
|
||||||
|
addr: 0,
|
||||||
|
h2b_write_pointer: 0,
|
||||||
|
b2h_read_pointer: 0,
|
||||||
|
},
|
||||||
|
BtDriver {
|
||||||
|
rx: RefCell::new(rx_receiver),
|
||||||
|
tx: RefCell::new(tx_sender),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct CybtFwCb<'a> {
|
||||||
|
pub p_next_line_start: &'a [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct HexFileData<'a> {
|
||||||
|
pub addr_mode: i32,
|
||||||
|
pub hi_addr: u16,
|
||||||
|
pub dest_addr: u32,
|
||||||
|
pub p_ds: &'a mut [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_firmware_patch_line(p_btfw_cb: &mut CybtFwCb, hfd: &mut HexFileData) -> u32 {
|
||||||
|
let mut abs_base_addr32 = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let num_bytes = p_btfw_cb.p_next_line_start[0];
|
||||||
|
p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[1..];
|
||||||
|
|
||||||
|
let addr = (p_btfw_cb.p_next_line_start[0] as u16) << 8 | p_btfw_cb.p_next_line_start[1] as u16;
|
||||||
|
p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[2..];
|
||||||
|
|
||||||
|
let line_type = p_btfw_cb.p_next_line_start[0];
|
||||||
|
p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[1..];
|
||||||
|
|
||||||
|
if num_bytes == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
hfd.p_ds[..num_bytes as usize].copy_from_slice(&p_btfw_cb.p_next_line_start[..num_bytes as usize]);
|
||||||
|
p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[num_bytes as usize..];
|
||||||
|
|
||||||
|
match line_type {
|
||||||
|
BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS => {
|
||||||
|
hfd.hi_addr = (hfd.p_ds[0] as u16) << 8 | hfd.p_ds[1] as u16;
|
||||||
|
hfd.addr_mode = BTFW_ADDR_MODE_EXTENDED;
|
||||||
|
}
|
||||||
|
BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS => {
|
||||||
|
hfd.hi_addr = (hfd.p_ds[0] as u16) << 8 | hfd.p_ds[1] as u16;
|
||||||
|
hfd.addr_mode = BTFW_ADDR_MODE_SEGMENT;
|
||||||
|
}
|
||||||
|
BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS => {
|
||||||
|
abs_base_addr32 = (hfd.p_ds[0] as u32) << 24
|
||||||
|
| (hfd.p_ds[1] as u32) << 16
|
||||||
|
| (hfd.p_ds[2] as u32) << 8
|
||||||
|
| hfd.p_ds[3] as u32;
|
||||||
|
hfd.addr_mode = BTFW_ADDR_MODE_LINEAR32;
|
||||||
|
}
|
||||||
|
BTFW_HEX_LINE_TYPE_DATA => {
|
||||||
|
hfd.dest_addr = addr as u32;
|
||||||
|
match hfd.addr_mode {
|
||||||
|
BTFW_ADDR_MODE_EXTENDED => hfd.dest_addr += (hfd.hi_addr as u32) << 16,
|
||||||
|
BTFW_ADDR_MODE_SEGMENT => hfd.dest_addr += (hfd.hi_addr as u32) << 4,
|
||||||
|
BTFW_ADDR_MODE_LINEAR32 => hfd.dest_addr += abs_base_addr32,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
return num_bytes as u32;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> BtRunner<'a> {
|
||||||
|
pub(crate) async fn init_bluetooth(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>, firmware: &[u8]) {
|
||||||
|
trace!("init_bluetooth");
|
||||||
|
bus.bp_write32(CHIP.bluetooth_base_address + BT2WLAN_PWRUP_ADDR, BT2WLAN_PWRUP_WAKE)
|
||||||
|
.await;
|
||||||
|
Timer::after(Duration::from_millis(2)).await;
|
||||||
|
self.upload_bluetooth_firmware(bus, firmware).await;
|
||||||
|
self.wait_bt_ready(bus).await;
|
||||||
|
self.init_bt_buffers(bus).await;
|
||||||
|
self.wait_bt_awake(bus).await;
|
||||||
|
self.bt_set_host_ready(bus).await;
|
||||||
|
self.bt_toggle_intr(bus).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn upload_bluetooth_firmware(
|
||||||
|
&mut self,
|
||||||
|
bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>,
|
||||||
|
firmware: &[u8],
|
||||||
|
) {
|
||||||
|
// read version
|
||||||
|
let version_length = firmware[0];
|
||||||
|
let _version = &firmware[1..=version_length as usize];
|
||||||
|
// skip version + 1 extra byte as per cybt_shared_bus_driver.c
|
||||||
|
let firmware = &firmware[version_length as usize + 2..];
|
||||||
|
// buffers
|
||||||
|
let mut data_buffer: [u8; 0x100] = [0; 0x100];
|
||||||
|
let mut aligned_data_buffer: [u8; 0x100] = [0; 0x100];
|
||||||
|
// structs
|
||||||
|
let mut btfw_cb = CybtFwCb {
|
||||||
|
p_next_line_start: firmware,
|
||||||
|
};
|
||||||
|
let mut hfd = HexFileData {
|
||||||
|
addr_mode: BTFW_ADDR_MODE_EXTENDED,
|
||||||
|
hi_addr: 0,
|
||||||
|
dest_addr: 0,
|
||||||
|
p_ds: &mut data_buffer,
|
||||||
|
};
|
||||||
|
loop {
|
||||||
|
let num_fw_bytes = read_firmware_patch_line(&mut btfw_cb, &mut hfd);
|
||||||
|
if num_fw_bytes == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let fw_bytes = &hfd.p_ds[0..num_fw_bytes as usize];
|
||||||
|
let mut dest_start_addr = hfd.dest_addr + CHIP.bluetooth_base_address;
|
||||||
|
let mut aligned_data_buffer_index: usize = 0;
|
||||||
|
// pad start
|
||||||
|
if !util::is_aligned(dest_start_addr, 4) {
|
||||||
|
let num_pad_bytes = dest_start_addr % 4;
|
||||||
|
let padded_dest_start_addr = util::round_down(dest_start_addr, 4);
|
||||||
|
let memory_value = bus.bp_read32(padded_dest_start_addr).await;
|
||||||
|
let memory_value_bytes = memory_value.to_le_bytes();
|
||||||
|
// Copy the previous memory value's bytes to the start
|
||||||
|
for i in 0..num_pad_bytes as usize {
|
||||||
|
aligned_data_buffer[aligned_data_buffer_index] = memory_value_bytes[i];
|
||||||
|
aligned_data_buffer_index += 1;
|
||||||
|
}
|
||||||
|
// Copy the firmware bytes after the padding bytes
|
||||||
|
for i in 0..num_fw_bytes as usize {
|
||||||
|
aligned_data_buffer[aligned_data_buffer_index] = fw_bytes[i];
|
||||||
|
aligned_data_buffer_index += 1;
|
||||||
|
}
|
||||||
|
dest_start_addr = padded_dest_start_addr;
|
||||||
|
} else {
|
||||||
|
// Directly copy fw_bytes into aligned_data_buffer if no start padding is required
|
||||||
|
for i in 0..num_fw_bytes as usize {
|
||||||
|
aligned_data_buffer[aligned_data_buffer_index] = fw_bytes[i];
|
||||||
|
aligned_data_buffer_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// pad end
|
||||||
|
let mut dest_end_addr = dest_start_addr + aligned_data_buffer_index as u32;
|
||||||
|
if !util::is_aligned(dest_end_addr, 4) {
|
||||||
|
let offset = dest_end_addr % 4;
|
||||||
|
let num_pad_bytes_end = 4 - offset;
|
||||||
|
let padded_dest_end_addr = util::round_down(dest_end_addr, 4);
|
||||||
|
let memory_value = bus.bp_read32(padded_dest_end_addr).await;
|
||||||
|
let memory_value_bytes = memory_value.to_le_bytes();
|
||||||
|
// Append the necessary memory bytes to pad the end of aligned_data_buffer
|
||||||
|
for i in offset..4 {
|
||||||
|
aligned_data_buffer[aligned_data_buffer_index] = memory_value_bytes[i as usize];
|
||||||
|
aligned_data_buffer_index += 1;
|
||||||
|
}
|
||||||
|
dest_end_addr += num_pad_bytes_end;
|
||||||
|
} else {
|
||||||
|
// pad end alignment not needed
|
||||||
|
}
|
||||||
|
let buffer_to_write = &aligned_data_buffer[0..aligned_data_buffer_index as usize];
|
||||||
|
assert!(dest_start_addr % 4 == 0);
|
||||||
|
assert!(dest_end_addr % 4 == 0);
|
||||||
|
assert!(aligned_data_buffer_index % 4 == 0);
|
||||||
|
bus.bp_write(dest_start_addr, buffer_to_write).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn wait_bt_ready(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
|
||||||
|
trace!("wait_bt_ready");
|
||||||
|
let mut success = false;
|
||||||
|
for _ in 0..300 {
|
||||||
|
let val = bus.bp_read32(BT_CTRL_REG_ADDR).await;
|
||||||
|
trace!("BT_CTRL_REG_ADDR = {:08x}", val);
|
||||||
|
if val & BTSDIO_REG_FW_RDY_BITMASK != 0 {
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Timer::after(Duration::from_millis(1)).await;
|
||||||
|
}
|
||||||
|
assert!(success == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn wait_bt_awake(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
|
||||||
|
trace!("wait_bt_awake");
|
||||||
|
let mut success = false;
|
||||||
|
for _ in 0..300 {
|
||||||
|
let val = bus.bp_read32(BT_CTRL_REG_ADDR).await;
|
||||||
|
trace!("BT_CTRL_REG_ADDR = {:08x}", val);
|
||||||
|
if val & BTSDIO_REG_BT_AWAKE_BITMASK != 0 {
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Timer::after(Duration::from_millis(1)).await;
|
||||||
|
}
|
||||||
|
assert!(success == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn bt_set_host_ready(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
|
||||||
|
trace!("bt_set_host_ready");
|
||||||
|
let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
|
||||||
|
// TODO: do we need to swap endianness on this read?
|
||||||
|
let new_val = old_val | BTSDIO_REG_SW_RDY_BITMASK;
|
||||||
|
bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use this
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) async fn bt_set_awake(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>, awake: bool) {
|
||||||
|
trace!("bt_set_awake");
|
||||||
|
let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
|
||||||
|
// TODO: do we need to swap endianness on this read?
|
||||||
|
let new_val = if awake {
|
||||||
|
old_val | BTSDIO_REG_WAKE_BT_BITMASK
|
||||||
|
} else {
|
||||||
|
old_val & !BTSDIO_REG_WAKE_BT_BITMASK
|
||||||
|
};
|
||||||
|
bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn bt_toggle_intr(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
|
||||||
|
trace!("bt_toggle_intr");
|
||||||
|
let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
|
||||||
|
// TODO: do we need to swap endianness on this read?
|
||||||
|
let new_val = old_val ^ BTSDIO_REG_DATA_VALID_BITMASK;
|
||||||
|
bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use this
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) async fn bt_set_intr(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
|
||||||
|
trace!("bt_set_intr");
|
||||||
|
let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
|
||||||
|
let new_val = old_val | BTSDIO_REG_DATA_VALID_BITMASK;
|
||||||
|
bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn init_bt_buffers(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
|
||||||
|
trace!("init_bt_buffers");
|
||||||
|
self.addr = bus.bp_read32(WLAN_RAM_BASE_REG_ADDR).await;
|
||||||
|
assert!(self.addr != 0);
|
||||||
|
trace!("wlan_ram_base_addr = {:08x}", self.addr);
|
||||||
|
bus.bp_write32(self.addr + BTSDIO_OFFSET_HOST2BT_IN, 0).await;
|
||||||
|
bus.bp_write32(self.addr + BTSDIO_OFFSET_HOST2BT_OUT, 0).await;
|
||||||
|
bus.bp_write32(self.addr + BTSDIO_OFFSET_BT2HOST_IN, 0).await;
|
||||||
|
bus.bp_write32(self.addr + BTSDIO_OFFSET_BT2HOST_OUT, 0).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn bt_bus_request(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
|
||||||
|
// TODO: CYW43_THREAD_ENTER mutex?
|
||||||
|
self.bt_set_awake(bus, true).await;
|
||||||
|
self.wait_bt_awake(bus).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn hci_write(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
|
||||||
|
self.bt_bus_request(bus).await;
|
||||||
|
|
||||||
|
// NOTE(unwrap): we only call this when we do have a packet in the queue.
|
||||||
|
let buf = self.tx_chan.try_receive().unwrap();
|
||||||
|
debug!("HCI tx: {:02x}", crate::fmt::Bytes(&buf.buf[..buf.len]));
|
||||||
|
|
||||||
|
let len = buf.len as u32 - 1; // len doesn't include hci type byte
|
||||||
|
let rounded_len = round_up(len, 4);
|
||||||
|
let total_len = 4 + rounded_len;
|
||||||
|
|
||||||
|
let read_pointer = bus.bp_read32(self.addr + BTSDIO_OFFSET_HOST2BT_OUT).await;
|
||||||
|
let available = read_pointer.wrapping_sub(self.h2b_write_pointer + 4) % BTSDIO_FWBUF_SIZE;
|
||||||
|
if available < total_len {
|
||||||
|
warn!(
|
||||||
|
"bluetooth tx queue full, retrying. len {} available {}",
|
||||||
|
total_len, available
|
||||||
|
);
|
||||||
|
yield_now().await;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build header
|
||||||
|
let mut header = [0u8; 4];
|
||||||
|
header[0] = len as u8;
|
||||||
|
header[1] = (len >> 8) as u8;
|
||||||
|
header[2] = (len >> 16) as u8;
|
||||||
|
header[3] = buf.buf[0]; // HCI type byte
|
||||||
|
|
||||||
|
// Write header
|
||||||
|
let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF + self.h2b_write_pointer;
|
||||||
|
bus.bp_write(addr, &header).await;
|
||||||
|
self.h2b_write_pointer = (self.h2b_write_pointer + 4) % BTSDIO_FWBUF_SIZE;
|
||||||
|
|
||||||
|
// Write payload.
|
||||||
|
let payload = &buf.buf[1..][..rounded_len as usize];
|
||||||
|
if self.h2b_write_pointer as usize + payload.len() > BTSDIO_FWBUF_SIZE as usize {
|
||||||
|
// wraparound
|
||||||
|
let n = BTSDIO_FWBUF_SIZE - self.h2b_write_pointer;
|
||||||
|
let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF + self.h2b_write_pointer;
|
||||||
|
bus.bp_write(addr, &payload[..n as usize]).await;
|
||||||
|
let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF;
|
||||||
|
bus.bp_write(addr, &payload[n as usize..]).await;
|
||||||
|
} else {
|
||||||
|
// no wraparound
|
||||||
|
let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF + self.h2b_write_pointer;
|
||||||
|
bus.bp_write(addr, payload).await;
|
||||||
|
}
|
||||||
|
self.h2b_write_pointer = (self.h2b_write_pointer + payload.len() as u32) % BTSDIO_FWBUF_SIZE;
|
||||||
|
|
||||||
|
// Update pointer.
|
||||||
|
bus.bp_write32(self.addr + BTSDIO_OFFSET_HOST2BT_IN, self.h2b_write_pointer)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
self.bt_toggle_intr(bus).await;
|
||||||
|
|
||||||
|
self.tx_chan.receive_done();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn bt_has_work(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) -> bool {
|
||||||
|
let int_status = bus.bp_read32(CHIP.sdiod_core_base_address + SDIO_INT_STATUS).await;
|
||||||
|
if int_status & I_HMB_FC_CHANGE != 0 {
|
||||||
|
bus.bp_write32(
|
||||||
|
CHIP.sdiod_core_base_address + SDIO_INT_STATUS,
|
||||||
|
int_status & I_HMB_FC_CHANGE,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn handle_irq(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
|
||||||
|
if self.bt_has_work(bus).await {
|
||||||
|
loop {
|
||||||
|
// Check if we have data.
|
||||||
|
let write_pointer = bus.bp_read32(self.addr + BTSDIO_OFFSET_BT2HOST_IN).await;
|
||||||
|
let available = write_pointer.wrapping_sub(self.b2h_read_pointer) % BTSDIO_FWBUF_SIZE;
|
||||||
|
if available == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read header
|
||||||
|
let mut header = [0u8; 4];
|
||||||
|
let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF + self.b2h_read_pointer;
|
||||||
|
bus.bp_read(addr, &mut header).await;
|
||||||
|
|
||||||
|
// calc length
|
||||||
|
let len = header[0] as u32 | ((header[1]) as u32) << 8 | ((header[2]) as u32) << 16;
|
||||||
|
let rounded_len = round_up(len, 4);
|
||||||
|
if available < 4 + rounded_len {
|
||||||
|
warn!("ringbuf data not enough for a full packet?");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.b2h_read_pointer = (self.b2h_read_pointer + 4) % BTSDIO_FWBUF_SIZE;
|
||||||
|
|
||||||
|
// Obtain a buf from the channel.
|
||||||
|
let buf = self.rx_chan.send().await;
|
||||||
|
|
||||||
|
buf.buf[0] = header[3]; // hci packet type
|
||||||
|
let payload = &mut buf.buf[1..][..rounded_len as usize];
|
||||||
|
if self.b2h_read_pointer as usize + payload.len() > BTSDIO_FWBUF_SIZE as usize {
|
||||||
|
// wraparound
|
||||||
|
let n = BTSDIO_FWBUF_SIZE - self.b2h_read_pointer;
|
||||||
|
let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF + self.b2h_read_pointer;
|
||||||
|
bus.bp_read(addr, &mut payload[..n as usize]).await;
|
||||||
|
let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF;
|
||||||
|
bus.bp_read(addr, &mut payload[n as usize..]).await;
|
||||||
|
} else {
|
||||||
|
// no wraparound
|
||||||
|
let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF + self.b2h_read_pointer;
|
||||||
|
bus.bp_read(addr, payload).await;
|
||||||
|
}
|
||||||
|
self.b2h_read_pointer = (self.b2h_read_pointer + payload.len() as u32) % BTSDIO_FWBUF_SIZE;
|
||||||
|
bus.bp_write32(self.addr + BTSDIO_OFFSET_BT2HOST_OUT, self.b2h_read_pointer)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
buf.len = 1 + len as usize;
|
||||||
|
debug!("HCI rx: {:02x}", crate::fmt::Bytes(&buf.buf[..buf.len]));
|
||||||
|
|
||||||
|
self.rx_chan.send_done();
|
||||||
|
|
||||||
|
self.bt_toggle_intr(bus).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> embedded_io_async::ErrorType for BtDriver<'d> {
|
||||||
|
type Error = core::convert::Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> bt_hci::transport::Transport for BtDriver<'d> {
|
||||||
|
fn read<'a>(&self, rx: &'a mut [u8]) -> impl Future<Output = Result<ControllerToHostPacket<'a>, Self::Error>> {
|
||||||
|
async {
|
||||||
|
let ch = &mut *self.rx.borrow_mut();
|
||||||
|
let buf = ch.receive().await;
|
||||||
|
let n = buf.len;
|
||||||
|
assert!(n < rx.len());
|
||||||
|
rx[..n].copy_from_slice(&buf.buf[..n]);
|
||||||
|
ch.receive_done();
|
||||||
|
|
||||||
|
let kind = PacketKind::from_hci_bytes_complete(&rx[..1]).unwrap();
|
||||||
|
let (res, _) = ControllerToHostPacket::from_hci_bytes_with_kind(kind, &rx[1..n]).unwrap();
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write a complete HCI packet from the tx buffer
|
||||||
|
fn write<T: HostToControllerPacket>(&self, val: &T) -> impl Future<Output = Result<(), Self::Error>> {
|
||||||
|
async {
|
||||||
|
let ch = &mut *self.tx.borrow_mut();
|
||||||
|
let buf = ch.send().await;
|
||||||
|
let buf_len = buf.buf.len();
|
||||||
|
let mut slice = &mut buf.buf[..];
|
||||||
|
WithIndicator::new(val).write_hci(&mut slice).unwrap();
|
||||||
|
buf.len = buf_len - slice.len();
|
||||||
|
ch.send_done();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,7 +4,7 @@ use embedded_hal_1::digital::OutputPin;
|
|||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
|
||||||
use crate::consts::*;
|
use crate::consts::*;
|
||||||
use crate::slice8_mut;
|
use crate::util::slice8_mut;
|
||||||
|
|
||||||
/// Custom Spi Trait that _only_ supports the bus operation of the cyw43
|
/// Custom Spi Trait that _only_ supports the bus operation of the cyw43
|
||||||
/// Implementors are expected to hold the CS pin low during an operation.
|
/// Implementors are expected to hold the CS pin low during an operation.
|
||||||
@ -48,44 +48,91 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn init(&mut self) {
|
pub async fn init(&mut self, bluetooth_enabled: bool) {
|
||||||
// Reset
|
// Reset
|
||||||
|
trace!("WL_REG off/on");
|
||||||
self.pwr.set_low().unwrap();
|
self.pwr.set_low().unwrap();
|
||||||
Timer::after_millis(20).await;
|
Timer::after_millis(20).await;
|
||||||
self.pwr.set_high().unwrap();
|
self.pwr.set_high().unwrap();
|
||||||
Timer::after_millis(250).await;
|
Timer::after_millis(250).await;
|
||||||
|
|
||||||
|
trace!("read REG_BUS_TEST_RO");
|
||||||
while self
|
while self
|
||||||
.read32_swapped(REG_BUS_TEST_RO)
|
.read32_swapped(FUNC_BUS, REG_BUS_TEST_RO)
|
||||||
.inspect(|v| trace!("{:#x}", v))
|
.inspect(|v| trace!("{:#x}", v))
|
||||||
.await
|
.await
|
||||||
!= FEEDBEAD
|
!= FEEDBEAD
|
||||||
{}
|
{}
|
||||||
|
|
||||||
self.write32_swapped(REG_BUS_TEST_RW, TEST_PATTERN).await;
|
trace!("write REG_BUS_TEST_RW");
|
||||||
let val = self.read32_swapped(REG_BUS_TEST_RW).await;
|
self.write32_swapped(FUNC_BUS, REG_BUS_TEST_RW, TEST_PATTERN).await;
|
||||||
|
let val = self.read32_swapped(FUNC_BUS, REG_BUS_TEST_RW).await;
|
||||||
trace!("{:#x}", val);
|
trace!("{:#x}", val);
|
||||||
assert_eq!(val, TEST_PATTERN);
|
assert_eq!(val, TEST_PATTERN);
|
||||||
|
|
||||||
let val = self.read32_swapped(REG_BUS_CTRL).await;
|
trace!("read REG_BUS_CTRL");
|
||||||
|
let val = self.read32_swapped(FUNC_BUS, REG_BUS_CTRL).await;
|
||||||
trace!("{:#010b}", (val & 0xff));
|
trace!("{:#010b}", (val & 0xff));
|
||||||
|
|
||||||
// 32-bit word length, little endian (which is the default endianess).
|
// 32-bit word length, little endian (which is the default endianess).
|
||||||
|
// TODO: C library is uint32_t val = WORD_LENGTH_32 | HIGH_SPEED_MODE| ENDIAN_BIG | INTERRUPT_POLARITY_HIGH | WAKE_UP | 0x4 << (8 * SPI_RESPONSE_DELAY) | INTR_WITH_STATUS << (8 * SPI_STATUS_ENABLE);
|
||||||
|
trace!("write REG_BUS_CTRL");
|
||||||
self.write32_swapped(
|
self.write32_swapped(
|
||||||
|
FUNC_BUS,
|
||||||
REG_BUS_CTRL,
|
REG_BUS_CTRL,
|
||||||
WORD_LENGTH_32 | HIGH_SPEED | INTERRUPT_HIGH | WAKE_UP | STATUS_ENABLE | INTERRUPT_WITH_STATUS,
|
WORD_LENGTH_32
|
||||||
|
| HIGH_SPEED
|
||||||
|
| INTERRUPT_POLARITY_HIGH
|
||||||
|
| WAKE_UP
|
||||||
|
| 0x4 << (8 * REG_BUS_RESPONSE_DELAY)
|
||||||
|
| STATUS_ENABLE << (8 * REG_BUS_STATUS_ENABLE)
|
||||||
|
| INTR_WITH_STATUS << (8 * REG_BUS_STATUS_ENABLE),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
trace!("read REG_BUS_CTRL");
|
||||||
let val = self.read8(FUNC_BUS, REG_BUS_CTRL).await;
|
let val = self.read8(FUNC_BUS, REG_BUS_CTRL).await;
|
||||||
trace!("{:#b}", val);
|
trace!("{:#b}", val);
|
||||||
|
|
||||||
|
// TODO: C doesn't do this? i doubt it messes anything up
|
||||||
|
trace!("read REG_BUS_TEST_RO");
|
||||||
let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await;
|
let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await;
|
||||||
trace!("{:#x}", val);
|
trace!("{:#x}", val);
|
||||||
assert_eq!(val, FEEDBEAD);
|
assert_eq!(val, FEEDBEAD);
|
||||||
|
|
||||||
|
// TODO: C doesn't do this? i doubt it messes anything up
|
||||||
|
trace!("read REG_BUS_TEST_RW");
|
||||||
let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await;
|
let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await;
|
||||||
trace!("{:#x}", val);
|
trace!("{:#x}", val);
|
||||||
assert_eq!(val, TEST_PATTERN);
|
assert_eq!(val, TEST_PATTERN);
|
||||||
|
|
||||||
|
trace!("write SPI_RESP_DELAY_F1 CYW43_BACKPLANE_READ_PAD_LEN_BYTES");
|
||||||
|
self.write8(FUNC_BUS, SPI_RESP_DELAY_F1, WHD_BUS_SPI_BACKPLANE_READ_PADD_SIZE)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// TODO: Make sure error interrupt bits are clear?
|
||||||
|
// cyw43_write_reg_u8(self, BUS_FUNCTION, SPI_INTERRUPT_REGISTER, DATA_UNAVAILABLE | COMMAND_ERROR | DATA_ERROR | F1_OVERFLOW) != 0)
|
||||||
|
trace!("Make sure error interrupt bits are clear");
|
||||||
|
self.write8(
|
||||||
|
FUNC_BUS,
|
||||||
|
REG_BUS_INTERRUPT,
|
||||||
|
(IRQ_DATA_UNAVAILABLE | IRQ_COMMAND_ERROR | IRQ_DATA_ERROR | IRQ_F1_OVERFLOW) as u8,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// Enable a selection of interrupts
|
||||||
|
// TODO: why not all of these F2_F3_FIFO_RD_UNDERFLOW | F2_F3_FIFO_WR_OVERFLOW | COMMAND_ERROR | DATA_ERROR | F2_PACKET_AVAILABLE | F1_OVERFLOW | F1_INTR
|
||||||
|
trace!("enable a selection of interrupts");
|
||||||
|
let mut val = IRQ_F2_F3_FIFO_RD_UNDERFLOW
|
||||||
|
| IRQ_F2_F3_FIFO_WR_OVERFLOW
|
||||||
|
| IRQ_COMMAND_ERROR
|
||||||
|
| IRQ_DATA_ERROR
|
||||||
|
| IRQ_F2_PACKET_AVAILABLE
|
||||||
|
| IRQ_F1_OVERFLOW;
|
||||||
|
if bluetooth_enabled {
|
||||||
|
val = val | IRQ_F1_INTR;
|
||||||
|
}
|
||||||
|
self.write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, val).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) {
|
pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) {
|
||||||
@ -107,6 +154,8 @@ where
|
|||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub async fn bp_read(&mut self, mut addr: u32, mut data: &mut [u8]) {
|
pub async fn bp_read(&mut self, mut addr: u32, mut data: &mut [u8]) {
|
||||||
|
trace!("bp_read addr = {:08x}", addr);
|
||||||
|
|
||||||
// It seems the HW force-aligns the addr
|
// It seems the HW force-aligns the addr
|
||||||
// to 2 if data.len() >= 2
|
// to 2 if data.len() >= 2
|
||||||
// to 4 if data.len() >= 4
|
// to 4 if data.len() >= 4
|
||||||
@ -140,6 +189,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn bp_write(&mut self, mut addr: u32, mut data: &[u8]) {
|
pub async fn bp_write(&mut self, mut addr: u32, mut data: &[u8]) {
|
||||||
|
trace!("bp_write addr = {:08x}", addr);
|
||||||
|
|
||||||
// It seems the HW force-aligns the addr
|
// It seems the HW force-aligns the addr
|
||||||
// to 2 if data.len() >= 2
|
// to 2 if data.len() >= 2
|
||||||
// to 4 if data.len() >= 4
|
// to 4 if data.len() >= 4
|
||||||
@ -196,23 +247,32 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn backplane_readn(&mut self, addr: u32, len: u32) -> u32 {
|
async fn backplane_readn(&mut self, addr: u32, len: u32) -> u32 {
|
||||||
|
trace!("backplane_readn addr = {:08x} len = {}", addr, len);
|
||||||
|
|
||||||
self.backplane_set_window(addr).await;
|
self.backplane_set_window(addr).await;
|
||||||
|
|
||||||
let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK;
|
let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK;
|
||||||
if len == 4 {
|
if len == 4 {
|
||||||
bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG
|
bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG;
|
||||||
}
|
}
|
||||||
self.readn(FUNC_BACKPLANE, bus_addr, len).await
|
|
||||||
|
let val = self.readn(FUNC_BACKPLANE, bus_addr, len).await;
|
||||||
|
|
||||||
|
trace!("backplane_readn addr = {:08x} len = {} val = {:08x}", addr, len, val);
|
||||||
|
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn backplane_writen(&mut self, addr: u32, val: u32, len: u32) {
|
async fn backplane_writen(&mut self, addr: u32, val: u32, len: u32) {
|
||||||
|
trace!("backplane_writen addr = {:08x} len = {} val = {:08x}", addr, len, val);
|
||||||
|
|
||||||
self.backplane_set_window(addr).await;
|
self.backplane_set_window(addr).await;
|
||||||
|
|
||||||
let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK;
|
let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK;
|
||||||
if len == 4 {
|
if len == 4 {
|
||||||
bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG
|
bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG;
|
||||||
}
|
}
|
||||||
self.writen(FUNC_BACKPLANE, bus_addr, val, len).await
|
self.writen(FUNC_BACKPLANE, bus_addr, val, len).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn backplane_set_window(&mut self, addr: u32) {
|
async fn backplane_set_window(&mut self, addr: u32) {
|
||||||
@ -293,8 +353,8 @@ where
|
|||||||
self.status = self.spi.cmd_write(&[cmd, val]).await;
|
self.status = self.spi.cmd_write(&[cmd, val]).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read32_swapped(&mut self, addr: u32) -> u32 {
|
async fn read32_swapped(&mut self, func: u32, addr: u32) -> u32 {
|
||||||
let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4);
|
let cmd = cmd_word(READ, INC_ADDR, func, addr, 4);
|
||||||
let cmd = swap16(cmd);
|
let cmd = swap16(cmd);
|
||||||
let mut buf = [0; 1];
|
let mut buf = [0; 1];
|
||||||
|
|
||||||
@ -303,8 +363,8 @@ where
|
|||||||
swap16(buf[0])
|
swap16(buf[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn write32_swapped(&mut self, addr: u32, val: u32) {
|
async fn write32_swapped(&mut self, func: u32, addr: u32, val: u32) {
|
||||||
let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4);
|
let cmd = cmd_word(WRITE, INC_ADDR, func, addr, 4);
|
||||||
let buf = [swap16(cmd), swap16(val)];
|
let buf = [swap16(cmd), swap16(val)];
|
||||||
|
|
||||||
self.status = self.spi.cmd_write(&buf).await;
|
self.status = self.spi.cmd_write(&buf).await;
|
||||||
|
|||||||
@ -5,19 +5,33 @@ pub(crate) const FUNC_BACKPLANE: u32 = 1;
|
|||||||
pub(crate) const FUNC_WLAN: u32 = 2;
|
pub(crate) const FUNC_WLAN: u32 = 2;
|
||||||
pub(crate) const FUNC_BT: u32 = 3;
|
pub(crate) const FUNC_BT: u32 = 3;
|
||||||
|
|
||||||
|
// Register addresses
|
||||||
pub(crate) const REG_BUS_CTRL: u32 = 0x0;
|
pub(crate) const REG_BUS_CTRL: u32 = 0x0;
|
||||||
|
pub(crate) const REG_BUS_RESPONSE_DELAY: u32 = 0x1;
|
||||||
|
pub(crate) const REG_BUS_STATUS_ENABLE: u32 = 0x2;
|
||||||
pub(crate) const REG_BUS_INTERRUPT: u32 = 0x04; // 16 bits - Interrupt status
|
pub(crate) const REG_BUS_INTERRUPT: u32 = 0x04; // 16 bits - Interrupt status
|
||||||
pub(crate) const REG_BUS_INTERRUPT_ENABLE: u32 = 0x06; // 16 bits - Interrupt mask
|
pub(crate) const REG_BUS_INTERRUPT_ENABLE: u32 = 0x06; // 16 bits - Interrupt mask
|
||||||
pub(crate) const REG_BUS_STATUS: u32 = 0x8;
|
pub(crate) const REG_BUS_STATUS: u32 = 0x8;
|
||||||
pub(crate) const REG_BUS_TEST_RO: u32 = 0x14;
|
pub(crate) const REG_BUS_TEST_RO: u32 = 0x14;
|
||||||
pub(crate) const REG_BUS_TEST_RW: u32 = 0x18;
|
pub(crate) const REG_BUS_TEST_RW: u32 = 0x18;
|
||||||
pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c;
|
pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c;
|
||||||
|
|
||||||
|
// SPI_BUS_CONTROL Bits
|
||||||
pub(crate) const WORD_LENGTH_32: u32 = 0x1;
|
pub(crate) const WORD_LENGTH_32: u32 = 0x1;
|
||||||
|
pub(crate) const ENDIAN_BIG: u32 = 0x2;
|
||||||
|
pub(crate) const CLOCK_PHASE: u32 = 0x4;
|
||||||
|
pub(crate) const CLOCK_POLARITY: u32 = 0x8;
|
||||||
pub(crate) const HIGH_SPEED: u32 = 0x10;
|
pub(crate) const HIGH_SPEED: u32 = 0x10;
|
||||||
pub(crate) const INTERRUPT_HIGH: u32 = 1 << 5;
|
pub(crate) const INTERRUPT_POLARITY_HIGH: u32 = 0x20;
|
||||||
pub(crate) const WAKE_UP: u32 = 1 << 7;
|
pub(crate) const WAKE_UP: u32 = 0x80;
|
||||||
pub(crate) const STATUS_ENABLE: u32 = 1 << 16;
|
|
||||||
pub(crate) const INTERRUPT_WITH_STATUS: u32 = 1 << 17;
|
// SPI_STATUS_ENABLE bits
|
||||||
|
pub(crate) const STATUS_ENABLE: u32 = 0x01;
|
||||||
|
pub(crate) const INTR_WITH_STATUS: u32 = 0x02;
|
||||||
|
pub(crate) const RESP_DELAY_ALL: u32 = 0x04;
|
||||||
|
pub(crate) const DWORD_PKT_LEN_EN: u32 = 0x08;
|
||||||
|
pub(crate) const CMD_ERR_CHK_EN: u32 = 0x20;
|
||||||
|
pub(crate) const DATA_ERR_CHK_EN: u32 = 0x40;
|
||||||
|
|
||||||
// SPI_STATUS_REGISTER bits
|
// SPI_STATUS_REGISTER bits
|
||||||
pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001;
|
pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001;
|
||||||
@ -51,6 +65,13 @@ pub(crate) const REG_BACKPLANE_READ_FRAME_BC_HIGH: u32 = 0x1001C;
|
|||||||
pub(crate) const REG_BACKPLANE_WAKEUP_CTRL: u32 = 0x1001E;
|
pub(crate) const REG_BACKPLANE_WAKEUP_CTRL: u32 = 0x1001E;
|
||||||
pub(crate) const REG_BACKPLANE_SLEEP_CSR: u32 = 0x1001F;
|
pub(crate) const REG_BACKPLANE_SLEEP_CSR: u32 = 0x1001F;
|
||||||
|
|
||||||
|
pub(crate) const I_HMB_SW_MASK: u32 = 0x000000f0;
|
||||||
|
pub(crate) const I_HMB_FC_CHANGE: u32 = 1 << 5;
|
||||||
|
pub(crate) const SDIO_INT_STATUS: u32 = 0x20;
|
||||||
|
pub(crate) const SDIO_INT_HOST_MASK: u32 = 0x24;
|
||||||
|
|
||||||
|
pub(crate) const SPI_F2_WATERMARK: u8 = 0x20;
|
||||||
|
|
||||||
pub(crate) const BACKPLANE_WINDOW_SIZE: usize = 0x8000;
|
pub(crate) const BACKPLANE_WINDOW_SIZE: usize = 0x8000;
|
||||||
pub(crate) const BACKPLANE_ADDRESS_MASK: u32 = 0x7FFF;
|
pub(crate) const BACKPLANE_ADDRESS_MASK: u32 = 0x7FFF;
|
||||||
pub(crate) const BACKPLANE_ADDRESS_32BIT_FLAG: u32 = 0x08000;
|
pub(crate) const BACKPLANE_ADDRESS_32BIT_FLAG: u32 = 0x08000;
|
||||||
@ -92,17 +113,6 @@ pub(crate) const IRQ_F1_INTR: u16 = 0x2000;
|
|||||||
pub(crate) const IRQ_F2_INTR: u16 = 0x4000;
|
pub(crate) const IRQ_F2_INTR: u16 = 0x4000;
|
||||||
pub(crate) const IRQ_F3_INTR: u16 = 0x8000;
|
pub(crate) const IRQ_F3_INTR: u16 = 0x8000;
|
||||||
|
|
||||||
pub(crate) const IOCTL_CMD_UP: u32 = 2;
|
|
||||||
pub(crate) const IOCTL_CMD_DOWN: u32 = 3;
|
|
||||||
pub(crate) const IOCTL_CMD_SET_SSID: u32 = 26;
|
|
||||||
pub(crate) const IOCTL_CMD_SET_CHANNEL: u32 = 30;
|
|
||||||
pub(crate) const IOCTL_CMD_DISASSOC: u32 = 52;
|
|
||||||
pub(crate) const IOCTL_CMD_ANTDIV: u32 = 64;
|
|
||||||
pub(crate) const IOCTL_CMD_SET_AP: u32 = 118;
|
|
||||||
pub(crate) const IOCTL_CMD_SET_VAR: u32 = 263;
|
|
||||||
pub(crate) const IOCTL_CMD_GET_VAR: u32 = 262;
|
|
||||||
pub(crate) const IOCTL_CMD_SET_PASSPHRASE: u32 = 268;
|
|
||||||
|
|
||||||
pub(crate) const CHANNEL_TYPE_CONTROL: u8 = 0;
|
pub(crate) const CHANNEL_TYPE_CONTROL: u8 = 0;
|
||||||
pub(crate) const CHANNEL_TYPE_EVENT: u8 = 1;
|
pub(crate) const CHANNEL_TYPE_EVENT: u8 = 1;
|
||||||
pub(crate) const CHANNEL_TYPE_DATA: u8 = 2;
|
pub(crate) const CHANNEL_TYPE_DATA: u8 = 2;
|
||||||
@ -119,6 +129,44 @@ pub(crate) const WPA2_SECURITY: u32 = 0x00400000;
|
|||||||
pub(crate) const MIN_PSK_LEN: usize = 8;
|
pub(crate) const MIN_PSK_LEN: usize = 8;
|
||||||
pub(crate) const MAX_PSK_LEN: usize = 64;
|
pub(crate) const MAX_PSK_LEN: usize = 64;
|
||||||
|
|
||||||
|
// Bluetooth firmware extraction constants.
|
||||||
|
pub(crate) const BTFW_ADDR_MODE_UNKNOWN: i32 = 0;
|
||||||
|
pub(crate) const BTFW_ADDR_MODE_EXTENDED: i32 = 1;
|
||||||
|
pub(crate) const BTFW_ADDR_MODE_SEGMENT: i32 = 2;
|
||||||
|
pub(crate) const BTFW_ADDR_MODE_LINEAR32: i32 = 3;
|
||||||
|
|
||||||
|
pub(crate) const BTFW_HEX_LINE_TYPE_DATA: u8 = 0;
|
||||||
|
pub(crate) const BTFW_HEX_LINE_TYPE_END_OF_DATA: u8 = 1;
|
||||||
|
pub(crate) const BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS: u8 = 2;
|
||||||
|
pub(crate) const BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS: u8 = 4;
|
||||||
|
pub(crate) const BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS: u8 = 5;
|
||||||
|
|
||||||
|
// Bluetooth constants.
|
||||||
|
pub(crate) const SPI_RESP_DELAY_F1: u32 = 0x001d;
|
||||||
|
pub(crate) const WHD_BUS_SPI_BACKPLANE_READ_PADD_SIZE: u8 = 4;
|
||||||
|
|
||||||
|
pub(crate) const BT2WLAN_PWRUP_WAKE: u32 = 3;
|
||||||
|
pub(crate) const BT2WLAN_PWRUP_ADDR: u32 = 0x640894;
|
||||||
|
|
||||||
|
pub(crate) const BT_CTRL_REG_ADDR: u32 = 0x18000c7c;
|
||||||
|
pub(crate) const HOST_CTRL_REG_ADDR: u32 = 0x18000d6c;
|
||||||
|
pub(crate) const WLAN_RAM_BASE_REG_ADDR: u32 = 0x18000d68;
|
||||||
|
|
||||||
|
pub(crate) const BTSDIO_REG_DATA_VALID_BITMASK: u32 = 1 << 1;
|
||||||
|
pub(crate) const BTSDIO_REG_BT_AWAKE_BITMASK: u32 = 1 << 8;
|
||||||
|
pub(crate) const BTSDIO_REG_WAKE_BT_BITMASK: u32 = 1 << 17;
|
||||||
|
pub(crate) const BTSDIO_REG_SW_RDY_BITMASK: u32 = 1 << 24;
|
||||||
|
pub(crate) const BTSDIO_REG_FW_RDY_BITMASK: u32 = 1 << 24;
|
||||||
|
|
||||||
|
pub(crate) const BTSDIO_FWBUF_SIZE: u32 = 0x1000;
|
||||||
|
pub(crate) const BTSDIO_OFFSET_HOST_WRITE_BUF: u32 = 0;
|
||||||
|
pub(crate) const BTSDIO_OFFSET_HOST_READ_BUF: u32 = BTSDIO_FWBUF_SIZE;
|
||||||
|
|
||||||
|
pub(crate) const BTSDIO_OFFSET_HOST2BT_IN: u32 = 0x00002000;
|
||||||
|
pub(crate) const BTSDIO_OFFSET_HOST2BT_OUT: u32 = 0x00002004;
|
||||||
|
pub(crate) const BTSDIO_OFFSET_BT2HOST_IN: u32 = 0x00002008;
|
||||||
|
pub(crate) const BTSDIO_OFFSET_BT2HOST_OUT: u32 = 0x0000200C;
|
||||||
|
|
||||||
// Security type (authentication and encryption types are combined using bit mask)
|
// Security type (authentication and encryption types are combined using bit mask)
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
@ -317,3 +365,306 @@ impl core::fmt::Display for FormatInterrupt {
|
|||||||
core::fmt::Debug::fmt(self, f)
|
core::fmt::Debug::fmt(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub(crate) enum Ioctl {
|
||||||
|
GetMagic = 0,
|
||||||
|
GetVersion = 1,
|
||||||
|
Up = 2,
|
||||||
|
Down = 3,
|
||||||
|
GetLoop = 4,
|
||||||
|
SetLoop = 5,
|
||||||
|
Dump = 6,
|
||||||
|
GetMsglevel = 7,
|
||||||
|
SetMsglevel = 8,
|
||||||
|
GetPromisc = 9,
|
||||||
|
SetPromisc = 10,
|
||||||
|
GetRate = 12,
|
||||||
|
GetInstance = 14,
|
||||||
|
GetInfra = 19,
|
||||||
|
SetInfra = 20,
|
||||||
|
GetAuth = 21,
|
||||||
|
SetAuth = 22,
|
||||||
|
GetBssid = 23,
|
||||||
|
SetBssid = 24,
|
||||||
|
GetSsid = 25,
|
||||||
|
SetSsid = 26,
|
||||||
|
Restart = 27,
|
||||||
|
GetChannel = 29,
|
||||||
|
SetChannel = 30,
|
||||||
|
GetSrl = 31,
|
||||||
|
SetSrl = 32,
|
||||||
|
GetLrl = 33,
|
||||||
|
SetLrl = 34,
|
||||||
|
GetPlcphdr = 35,
|
||||||
|
SetPlcphdr = 36,
|
||||||
|
GetRadio = 37,
|
||||||
|
SetRadio = 38,
|
||||||
|
GetPhytype = 39,
|
||||||
|
DumpRate = 40,
|
||||||
|
SetRateParams = 41,
|
||||||
|
GetKey = 44,
|
||||||
|
SetKey = 45,
|
||||||
|
GetRegulatory = 46,
|
||||||
|
SetRegulatory = 47,
|
||||||
|
GetPassiveScan = 48,
|
||||||
|
SetPassiveScan = 49,
|
||||||
|
Scan = 50,
|
||||||
|
ScanResults = 51,
|
||||||
|
Disassoc = 52,
|
||||||
|
Reassoc = 53,
|
||||||
|
GetRoamTrigger = 54,
|
||||||
|
SetRoamTrigger = 55,
|
||||||
|
GetRoamDelta = 56,
|
||||||
|
SetRoamDelta = 57,
|
||||||
|
GetRoamScanPeriod = 58,
|
||||||
|
SetRoamScanPeriod = 59,
|
||||||
|
Evm = 60,
|
||||||
|
GetTxant = 61,
|
||||||
|
SetTxant = 62,
|
||||||
|
GetAntdiv = 63,
|
||||||
|
SetAntdiv = 64,
|
||||||
|
GetClosed = 67,
|
||||||
|
SetClosed = 68,
|
||||||
|
GetMaclist = 69,
|
||||||
|
SetMaclist = 70,
|
||||||
|
GetRateset = 71,
|
||||||
|
SetRateset = 72,
|
||||||
|
Longtrain = 74,
|
||||||
|
GetBcnprd = 75,
|
||||||
|
SetBcnprd = 76,
|
||||||
|
GetDtimprd = 77,
|
||||||
|
SetDtimprd = 78,
|
||||||
|
GetSrom = 79,
|
||||||
|
SetSrom = 80,
|
||||||
|
GetWepRestrict = 81,
|
||||||
|
SetWepRestrict = 82,
|
||||||
|
GetCountry = 83,
|
||||||
|
SetCountry = 84,
|
||||||
|
GetPm = 85,
|
||||||
|
SetPm = 86,
|
||||||
|
GetWake = 87,
|
||||||
|
SetWake = 88,
|
||||||
|
GetForcelink = 90,
|
||||||
|
SetForcelink = 91,
|
||||||
|
FreqAccuracy = 92,
|
||||||
|
CarrierSuppress = 93,
|
||||||
|
GetPhyreg = 94,
|
||||||
|
SetPhyreg = 95,
|
||||||
|
GetRadioreg = 96,
|
||||||
|
SetRadioreg = 97,
|
||||||
|
GetRevinfo = 98,
|
||||||
|
GetUcantdiv = 99,
|
||||||
|
SetUcantdiv = 100,
|
||||||
|
RReg = 101,
|
||||||
|
WReg = 102,
|
||||||
|
GetMacmode = 105,
|
||||||
|
SetMacmode = 106,
|
||||||
|
GetMonitor = 107,
|
||||||
|
SetMonitor = 108,
|
||||||
|
GetGmode = 109,
|
||||||
|
SetGmode = 110,
|
||||||
|
GetLegacyErp = 111,
|
||||||
|
SetLegacyErp = 112,
|
||||||
|
GetRxAnt = 113,
|
||||||
|
GetCurrRateset = 114,
|
||||||
|
GetScansuppress = 115,
|
||||||
|
SetScansuppress = 116,
|
||||||
|
GetAp = 117,
|
||||||
|
SetAp = 118,
|
||||||
|
GetEapRestrict = 119,
|
||||||
|
SetEapRestrict = 120,
|
||||||
|
ScbAuthorize = 121,
|
||||||
|
ScbDeauthorize = 122,
|
||||||
|
GetWdslist = 123,
|
||||||
|
SetWdslist = 124,
|
||||||
|
GetAtim = 125,
|
||||||
|
SetAtim = 126,
|
||||||
|
GetRssi = 127,
|
||||||
|
GetPhyantdiv = 128,
|
||||||
|
SetPhyantdiv = 129,
|
||||||
|
ApRxOnly = 130,
|
||||||
|
GetTxPathPwr = 131,
|
||||||
|
SetTxPathPwr = 132,
|
||||||
|
GetWsec = 133,
|
||||||
|
SetWsec = 134,
|
||||||
|
GetPhyNoise = 135,
|
||||||
|
GetBssInfo = 136,
|
||||||
|
GetPktcnts = 137,
|
||||||
|
GetLazywds = 138,
|
||||||
|
SetLazywds = 139,
|
||||||
|
GetBandlist = 140,
|
||||||
|
GetBand = 141,
|
||||||
|
SetBand = 142,
|
||||||
|
ScbDeauthenticate = 143,
|
||||||
|
GetShortslot = 144,
|
||||||
|
GetShortslotOverride = 145,
|
||||||
|
SetShortslotOverride = 146,
|
||||||
|
GetShortslotRestrict = 147,
|
||||||
|
SetShortslotRestrict = 148,
|
||||||
|
GetGmodeProtection = 149,
|
||||||
|
GetGmodeProtectionOverride = 150,
|
||||||
|
SetGmodeProtectionOverride = 151,
|
||||||
|
Upgrade = 152,
|
||||||
|
GetIgnoreBcns = 155,
|
||||||
|
SetIgnoreBcns = 156,
|
||||||
|
GetScbTimeout = 157,
|
||||||
|
SetScbTimeout = 158,
|
||||||
|
GetAssoclist = 159,
|
||||||
|
GetClk = 160,
|
||||||
|
SetClk = 161,
|
||||||
|
GetUp = 162,
|
||||||
|
Out = 163,
|
||||||
|
GetWpaAuth = 164,
|
||||||
|
SetWpaAuth = 165,
|
||||||
|
GetUcflags = 166,
|
||||||
|
SetUcflags = 167,
|
||||||
|
GetPwridx = 168,
|
||||||
|
SetPwridx = 169,
|
||||||
|
GetTssi = 170,
|
||||||
|
GetSupRatesetOverride = 171,
|
||||||
|
SetSupRatesetOverride = 172,
|
||||||
|
GetProtectionControl = 178,
|
||||||
|
SetProtectionControl = 179,
|
||||||
|
GetPhylist = 180,
|
||||||
|
EncryptStrength = 181,
|
||||||
|
DecryptStatus = 182,
|
||||||
|
GetKeySeq = 183,
|
||||||
|
GetScanChannelTime = 184,
|
||||||
|
SetScanChannelTime = 185,
|
||||||
|
GetScanUnassocTime = 186,
|
||||||
|
SetScanUnassocTime = 187,
|
||||||
|
GetScanHomeTime = 188,
|
||||||
|
SetScanHomeTime = 189,
|
||||||
|
GetScanNprobes = 190,
|
||||||
|
SetScanNprobes = 191,
|
||||||
|
GetPrbRespTimeout = 192,
|
||||||
|
SetPrbRespTimeout = 193,
|
||||||
|
GetAtten = 194,
|
||||||
|
SetAtten = 195,
|
||||||
|
GetShmem = 196,
|
||||||
|
SetShmem = 197,
|
||||||
|
SetWsecTest = 200,
|
||||||
|
ScbDeauthenticateForReason = 201,
|
||||||
|
TkipCountermeasures = 202,
|
||||||
|
GetPiomode = 203,
|
||||||
|
SetPiomode = 204,
|
||||||
|
SetAssocPrefer = 205,
|
||||||
|
GetAssocPrefer = 206,
|
||||||
|
SetRoamPrefer = 207,
|
||||||
|
GetRoamPrefer = 208,
|
||||||
|
SetLed = 209,
|
||||||
|
GetLed = 210,
|
||||||
|
GetInterferenceMode = 211,
|
||||||
|
SetInterferenceMode = 212,
|
||||||
|
GetChannelQa = 213,
|
||||||
|
StartChannelQa = 214,
|
||||||
|
GetChannelSel = 215,
|
||||||
|
StartChannelSel = 216,
|
||||||
|
GetValidChannels = 217,
|
||||||
|
GetFakefrag = 218,
|
||||||
|
SetFakefrag = 219,
|
||||||
|
GetPwroutPercentage = 220,
|
||||||
|
SetPwroutPercentage = 221,
|
||||||
|
SetBadFramePreempt = 222,
|
||||||
|
GetBadFramePreempt = 223,
|
||||||
|
SetLeapList = 224,
|
||||||
|
GetLeapList = 225,
|
||||||
|
GetCwmin = 226,
|
||||||
|
SetCwmin = 227,
|
||||||
|
GetCwmax = 228,
|
||||||
|
SetCwmax = 229,
|
||||||
|
GetWet = 230,
|
||||||
|
SetWet = 231,
|
||||||
|
GetPub = 232,
|
||||||
|
GetKeyPrimary = 235,
|
||||||
|
SetKeyPrimary = 236,
|
||||||
|
GetAciArgs = 238,
|
||||||
|
SetAciArgs = 239,
|
||||||
|
UnsetCallback = 240,
|
||||||
|
SetCallback = 241,
|
||||||
|
GetRadar = 242,
|
||||||
|
SetRadar = 243,
|
||||||
|
SetSpectManagment = 244,
|
||||||
|
GetSpectManagment = 245,
|
||||||
|
WdsGetRemoteHwaddr = 246,
|
||||||
|
WdsGetWpaSup = 247,
|
||||||
|
SetCsScanTimer = 248,
|
||||||
|
GetCsScanTimer = 249,
|
||||||
|
MeasureRequest = 250,
|
||||||
|
Init = 251,
|
||||||
|
SendQuiet = 252,
|
||||||
|
Keepalive = 253,
|
||||||
|
SendPwrConstraint = 254,
|
||||||
|
UpgradeStatus = 255,
|
||||||
|
CurrentPwr = 256,
|
||||||
|
GetScanPassiveTime = 257,
|
||||||
|
SetScanPassiveTime = 258,
|
||||||
|
LegacyLinkBehavior = 259,
|
||||||
|
GetChannelsInCountry = 260,
|
||||||
|
GetCountryList = 261,
|
||||||
|
GetVar = 262,
|
||||||
|
SetVar = 263,
|
||||||
|
NvramGet = 264,
|
||||||
|
NvramSet = 265,
|
||||||
|
NvramDump = 266,
|
||||||
|
Reboot = 267,
|
||||||
|
SetWsecPmk = 268,
|
||||||
|
GetAuthMode = 269,
|
||||||
|
SetAuthMode = 270,
|
||||||
|
GetWakeentry = 271,
|
||||||
|
SetWakeentry = 272,
|
||||||
|
NdconfigItem = 273,
|
||||||
|
Nvotpw = 274,
|
||||||
|
Otpw = 275,
|
||||||
|
IovBlockGet = 276,
|
||||||
|
IovModulesGet = 277,
|
||||||
|
SoftReset = 278,
|
||||||
|
GetAllowMode = 279,
|
||||||
|
SetAllowMode = 280,
|
||||||
|
GetDesiredBssid = 281,
|
||||||
|
SetDesiredBssid = 282,
|
||||||
|
DisassocMyap = 283,
|
||||||
|
GetNbands = 284,
|
||||||
|
GetBandstates = 285,
|
||||||
|
GetWlcBssInfo = 286,
|
||||||
|
GetAssocInfo = 287,
|
||||||
|
GetOidPhy = 288,
|
||||||
|
SetOidPhy = 289,
|
||||||
|
SetAssocTime = 290,
|
||||||
|
GetDesiredSsid = 291,
|
||||||
|
GetChanspec = 292,
|
||||||
|
GetAssocState = 293,
|
||||||
|
SetPhyState = 294,
|
||||||
|
GetScanPending = 295,
|
||||||
|
GetScanreqPending = 296,
|
||||||
|
GetPrevRoamReason = 297,
|
||||||
|
SetPrevRoamReason = 298,
|
||||||
|
GetBandstatesPi = 299,
|
||||||
|
GetPhyState = 300,
|
||||||
|
GetBssWpaRsn = 301,
|
||||||
|
GetBssWpa2Rsn = 302,
|
||||||
|
GetBssBcnTs = 303,
|
||||||
|
GetIntDisassoc = 304,
|
||||||
|
SetNumPeers = 305,
|
||||||
|
GetNumBss = 306,
|
||||||
|
GetWsecPmk = 318,
|
||||||
|
GetRandomBytes = 319,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) const WSEC_TKIP: u32 = 0x02;
|
||||||
|
pub(crate) const WSEC_AES: u32 = 0x04;
|
||||||
|
|
||||||
|
pub(crate) const AUTH_OPEN: u32 = 0x00;
|
||||||
|
pub(crate) const AUTH_SAE: u32 = 0x03;
|
||||||
|
|
||||||
|
pub(crate) const MFP_NONE: u32 = 0;
|
||||||
|
pub(crate) const MFP_CAPABLE: u32 = 1;
|
||||||
|
pub(crate) const MFP_REQUIRED: u32 = 2;
|
||||||
|
|
||||||
|
pub(crate) const WPA_AUTH_DISABLED: u32 = 0x0000;
|
||||||
|
pub(crate) const WPA_AUTH_WPA_PSK: u32 = 0x0004;
|
||||||
|
pub(crate) const WPA_AUTH_WPA2_PSK: u32 = 0x0080;
|
||||||
|
pub(crate) const WPA_AUTH_WPA3_SAE_PSK: u32 = 0x40000;
|
||||||
|
|||||||
@ -35,16 +35,19 @@ pub struct Control<'a> {
|
|||||||
ioctl_state: &'a IoctlState,
|
ioctl_state: &'a IoctlState,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum ScanType {
|
pub enum ScanType {
|
||||||
Active,
|
Active,
|
||||||
Passive,
|
Passive,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
/// Scan options.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[non_exhaustive]
|
||||||
pub struct ScanOptions {
|
pub struct ScanOptions {
|
||||||
|
/// SSID to scan for.
|
||||||
pub ssid: Option<heapless::String<32>>,
|
pub ssid: Option<heapless::String<32>>,
|
||||||
/// If set to `None`, all APs will be returned. If set to `Some`, only APs
|
/// If set to `None`, all APs will be returned. If set to `Some`, only APs
|
||||||
/// with the specified BSSID will be returned.
|
/// with the specified BSSID will be returned.
|
||||||
@ -72,6 +75,79 @@ impl Default for ScanOptions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Authentication type, used in [`JoinOptions::auth`].
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum JoinAuth {
|
||||||
|
/// Open network
|
||||||
|
Open,
|
||||||
|
/// WPA only
|
||||||
|
Wpa,
|
||||||
|
/// WPA2 only
|
||||||
|
Wpa2,
|
||||||
|
/// WPA3 only
|
||||||
|
Wpa3,
|
||||||
|
/// WPA2 + WPA3
|
||||||
|
Wpa2Wpa3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Options for [`Control::join`].
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct JoinOptions<'a> {
|
||||||
|
/// Authentication type. Default `Wpa2Wpa3`.
|
||||||
|
pub auth: JoinAuth,
|
||||||
|
/// Enable TKIP encryption. Default false.
|
||||||
|
pub cipher_tkip: bool,
|
||||||
|
/// Enable AES encryption. Default true.
|
||||||
|
pub cipher_aes: bool,
|
||||||
|
/// Passphrase. Default empty.
|
||||||
|
pub passphrase: &'a [u8],
|
||||||
|
/// If false, `passphrase` is the human-readable passphrase string.
|
||||||
|
/// If true, `passphrase` is the result of applying the PBKDF2 hash to the
|
||||||
|
/// passphrase string. This makes it possible to avoid storing unhashed passwords.
|
||||||
|
///
|
||||||
|
/// This is not compatible with WPA3.
|
||||||
|
/// Default false.
|
||||||
|
pub passphrase_is_prehashed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> JoinOptions<'a> {
|
||||||
|
/// Create a new `JoinOptions` for joining open networks.
|
||||||
|
pub fn new_open() -> Self {
|
||||||
|
Self {
|
||||||
|
auth: JoinAuth::Open,
|
||||||
|
cipher_tkip: false,
|
||||||
|
cipher_aes: false,
|
||||||
|
passphrase: &[],
|
||||||
|
passphrase_is_prehashed: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new `JoinOptions` for joining encrypted networks.
|
||||||
|
///
|
||||||
|
/// Defaults to supporting WPA2+WPA3 with AES only, you may edit
|
||||||
|
/// the returned options to change this.
|
||||||
|
pub fn new(passphrase: &'a [u8]) -> Self {
|
||||||
|
let mut this = Self::default();
|
||||||
|
this.passphrase = passphrase;
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Default for JoinOptions<'a> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
auth: JoinAuth::Wpa2Wpa3,
|
||||||
|
cipher_tkip: false,
|
||||||
|
cipher_aes: true,
|
||||||
|
passphrase: &[],
|
||||||
|
passphrase_is_prehashed: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Control<'a> {
|
impl<'a> Control<'a> {
|
||||||
pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self {
|
pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -81,8 +157,7 @@ impl<'a> Control<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize WiFi controller.
|
async fn load_clm(&mut self, clm: &[u8]) {
|
||||||
pub async fn init(&mut self, clm: &[u8]) {
|
|
||||||
const CHUNK_SIZE: usize = 1024;
|
const CHUNK_SIZE: usize = 1024;
|
||||||
|
|
||||||
debug!("Downloading CLM...");
|
debug!("Downloading CLM...");
|
||||||
@ -108,12 +183,17 @@ impl<'a> Control<'a> {
|
|||||||
buf[0..8].copy_from_slice(b"clmload\x00");
|
buf[0..8].copy_from_slice(b"clmload\x00");
|
||||||
buf[8..20].copy_from_slice(&header.to_bytes());
|
buf[8..20].copy_from_slice(&header.to_bytes());
|
||||||
buf[20..][..chunk.len()].copy_from_slice(&chunk);
|
buf[20..][..chunk.len()].copy_from_slice(&chunk);
|
||||||
self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..8 + 12 + chunk.len()])
|
self.ioctl(IoctlType::Set, Ioctl::SetVar, 0, &mut buf[..8 + 12 + chunk.len()])
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check clmload ok
|
// check clmload ok
|
||||||
assert_eq!(self.get_iovar_u32("clmload_status").await, 0);
|
assert_eq!(self.get_iovar_u32("clmload_status").await, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize WiFi controller.
|
||||||
|
pub async fn init(&mut self, clm: &[u8]) {
|
||||||
|
self.load_clm(&clm).await;
|
||||||
|
|
||||||
debug!("Configuring misc stuff...");
|
debug!("Configuring misc stuff...");
|
||||||
|
|
||||||
@ -139,7 +219,7 @@ impl<'a> Control<'a> {
|
|||||||
Timer::after_millis(100).await;
|
Timer::after_millis(100).await;
|
||||||
|
|
||||||
// Set antenna to chip antenna
|
// Set antenna to chip antenna
|
||||||
self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await;
|
self.ioctl_set_u32(Ioctl::SetAntdiv, 0, 0).await;
|
||||||
|
|
||||||
self.set_iovar_u32("bus:txglom", 0).await;
|
self.set_iovar_u32("bus:txglom", 0).await;
|
||||||
Timer::after_millis(100).await;
|
Timer::after_millis(100).await;
|
||||||
@ -177,24 +257,24 @@ impl<'a> Control<'a> {
|
|||||||
|
|
||||||
Timer::after_millis(100).await;
|
Timer::after_millis(100).await;
|
||||||
|
|
||||||
self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto
|
self.ioctl_set_u32(Ioctl::SetGmode, 0, 1).await; // SET_GMODE = auto
|
||||||
self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any
|
self.ioctl_set_u32(Ioctl::SetBand, 0, 0).await; // SET_BAND = any
|
||||||
|
|
||||||
Timer::after_millis(100).await;
|
Timer::after_millis(100).await;
|
||||||
|
|
||||||
self.state_ch.set_hardware_address(HardwareAddress::Ethernet(mac_addr));
|
self.state_ch.set_hardware_address(HardwareAddress::Ethernet(mac_addr));
|
||||||
|
|
||||||
debug!("INIT DONE");
|
debug!("cyw43 control init done");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the WiFi interface up.
|
/// Set the WiFi interface up.
|
||||||
async fn up(&mut self) {
|
async fn up(&mut self) {
|
||||||
self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await;
|
self.ioctl(IoctlType::Set, Ioctl::Up, 0, &mut []).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the interface down.
|
/// Set the interface down.
|
||||||
async fn down(&mut self) {
|
async fn down(&mut self) {
|
||||||
self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await;
|
self.ioctl(IoctlType::Set, Ioctl::Down, 0, &mut []).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set power management mode.
|
/// Set power management mode.
|
||||||
@ -207,17 +287,74 @@ impl<'a> Control<'a> {
|
|||||||
self.set_iovar_u32("bcn_li_dtim", mode.dtim_period() as u32).await;
|
self.set_iovar_u32("bcn_li_dtim", mode.dtim_period() as u32).await;
|
||||||
self.set_iovar_u32("assoc_listen", mode.assoc() as u32).await;
|
self.set_iovar_u32("assoc_listen", mode.assoc() as u32).await;
|
||||||
}
|
}
|
||||||
self.ioctl_set_u32(86, 0, mode_num).await;
|
self.ioctl_set_u32(Ioctl::SetPm, 0, mode_num).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Join an unprotected network with the provided ssid.
|
/// Join an unprotected network with the provided ssid.
|
||||||
pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> {
|
pub async fn join(&mut self, ssid: &str, options: JoinOptions<'_>) -> Result<(), Error> {
|
||||||
self.set_iovar_u32("ampdu_ba_wsize", 8).await;
|
self.set_iovar_u32("ampdu_ba_wsize", 8).await;
|
||||||
|
|
||||||
self.ioctl_set_u32(134, 0, 0).await; // wsec = open
|
if options.auth == JoinAuth::Open {
|
||||||
self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await;
|
self.ioctl_set_u32(Ioctl::SetWsec, 0, 0).await;
|
||||||
self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1
|
self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await;
|
||||||
self.ioctl_set_u32(22, 0, 0).await; // set_auth = open (0)
|
self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await;
|
||||||
|
self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await;
|
||||||
|
self.ioctl_set_u32(Ioctl::SetWpaAuth, 0, WPA_AUTH_DISABLED).await;
|
||||||
|
} else {
|
||||||
|
let mut wsec = 0;
|
||||||
|
if options.cipher_aes {
|
||||||
|
wsec |= WSEC_AES;
|
||||||
|
}
|
||||||
|
if options.cipher_tkip {
|
||||||
|
wsec |= WSEC_TKIP;
|
||||||
|
}
|
||||||
|
self.ioctl_set_u32(Ioctl::SetWsec, 0, wsec).await;
|
||||||
|
|
||||||
|
self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await;
|
||||||
|
self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await;
|
||||||
|
self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await;
|
||||||
|
|
||||||
|
Timer::after_millis(100).await;
|
||||||
|
|
||||||
|
let (wpa12, wpa3, auth, mfp, wpa_auth) = match options.auth {
|
||||||
|
JoinAuth::Open => unreachable!(),
|
||||||
|
JoinAuth::Wpa => (true, false, AUTH_OPEN, MFP_NONE, WPA_AUTH_WPA_PSK),
|
||||||
|
JoinAuth::Wpa2 => (true, false, AUTH_OPEN, MFP_CAPABLE, WPA_AUTH_WPA2_PSK),
|
||||||
|
JoinAuth::Wpa3 => (false, true, AUTH_SAE, MFP_REQUIRED, WPA_AUTH_WPA3_SAE_PSK),
|
||||||
|
JoinAuth::Wpa2Wpa3 => (true, true, AUTH_SAE, MFP_CAPABLE, WPA_AUTH_WPA3_SAE_PSK),
|
||||||
|
};
|
||||||
|
|
||||||
|
if wpa12 {
|
||||||
|
let mut flags = 0;
|
||||||
|
if !options.passphrase_is_prehashed {
|
||||||
|
flags |= 1;
|
||||||
|
}
|
||||||
|
let mut pfi = PassphraseInfo {
|
||||||
|
len: options.passphrase.len() as _,
|
||||||
|
flags,
|
||||||
|
passphrase: [0; 64],
|
||||||
|
};
|
||||||
|
pfi.passphrase[..options.passphrase.len()].copy_from_slice(options.passphrase);
|
||||||
|
Timer::after_millis(3).await;
|
||||||
|
self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut pfi.to_bytes())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
if wpa3 {
|
||||||
|
let mut pfi = SaePassphraseInfo {
|
||||||
|
len: options.passphrase.len() as _,
|
||||||
|
passphrase: [0; 128],
|
||||||
|
};
|
||||||
|
pfi.passphrase[..options.passphrase.len()].copy_from_slice(options.passphrase);
|
||||||
|
Timer::after_millis(3).await;
|
||||||
|
self.set_iovar("sae_password", &pfi.to_bytes()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await;
|
||||||
|
self.ioctl_set_u32(Ioctl::SetAuth, 0, auth).await;
|
||||||
|
self.set_iovar_u32("mfp", mfp).await;
|
||||||
|
self.ioctl_set_u32(Ioctl::SetWpaAuth, 0, wpa_auth).await;
|
||||||
|
}
|
||||||
|
|
||||||
let mut i = SsidInfo {
|
let mut i = SsidInfo {
|
||||||
len: ssid.len() as _,
|
len: ssid.len() as _,
|
||||||
@ -228,69 +365,13 @@ impl<'a> Control<'a> {
|
|||||||
self.wait_for_join(i).await
|
self.wait_for_join(i).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Join a protected network with the provided ssid and [`PassphraseInfo`].
|
|
||||||
async fn join_wpa2_passphrase_info(&mut self, ssid: &str, passphrase_info: &PassphraseInfo) -> Result<(), Error> {
|
|
||||||
self.set_iovar_u32("ampdu_ba_wsize", 8).await;
|
|
||||||
|
|
||||||
self.ioctl_set_u32(134, 0, 4).await; // wsec = wpa2
|
|
||||||
self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await;
|
|
||||||
self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await;
|
|
||||||
self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await;
|
|
||||||
|
|
||||||
Timer::after_millis(100).await;
|
|
||||||
|
|
||||||
self.ioctl(
|
|
||||||
IoctlType::Set,
|
|
||||||
IOCTL_CMD_SET_PASSPHRASE,
|
|
||||||
0,
|
|
||||||
&mut passphrase_info.to_bytes(),
|
|
||||||
)
|
|
||||||
.await; // WLC_SET_WSEC_PMK
|
|
||||||
|
|
||||||
self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1
|
|
||||||
self.ioctl_set_u32(22, 0, 0).await; // set_auth = 0 (open)
|
|
||||||
self.ioctl_set_u32(165, 0, 0x80).await; // set_wpa_auth
|
|
||||||
|
|
||||||
let mut i = SsidInfo {
|
|
||||||
len: ssid.len() as _,
|
|
||||||
ssid: [0; 32],
|
|
||||||
};
|
|
||||||
i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes());
|
|
||||||
|
|
||||||
self.wait_for_join(i).await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Join a protected network with the provided ssid and passphrase.
|
|
||||||
pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> {
|
|
||||||
let mut pfi = PassphraseInfo {
|
|
||||||
len: passphrase.len() as _,
|
|
||||||
flags: 1,
|
|
||||||
passphrase: [0; 64],
|
|
||||||
};
|
|
||||||
pfi.passphrase[..passphrase.len()].copy_from_slice(passphrase.as_bytes());
|
|
||||||
self.join_wpa2_passphrase_info(ssid, &pfi).await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Join a protected network with the provided ssid and precomputed PSK.
|
|
||||||
pub async fn join_wpa2_psk(&mut self, ssid: &str, psk: &[u8; 32]) -> Result<(), Error> {
|
|
||||||
let mut pfi = PassphraseInfo {
|
|
||||||
len: psk.len() as _,
|
|
||||||
flags: 0,
|
|
||||||
passphrase: [0; 64],
|
|
||||||
};
|
|
||||||
pfi.passphrase[..psk.len()].copy_from_slice(psk);
|
|
||||||
self.join_wpa2_passphrase_info(ssid, &pfi).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> {
|
async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> {
|
||||||
self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]);
|
self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]);
|
||||||
let mut subscriber = self.events.queue.subscriber().unwrap();
|
let mut subscriber = self.events.queue.subscriber().unwrap();
|
||||||
// the actual join operation starts here
|
// the actual join operation starts here
|
||||||
// we make sure to enable events before so we don't miss any
|
// we make sure to enable events before so we don't miss any
|
||||||
|
|
||||||
// set_ssid
|
self.ioctl(IoctlType::Set, Ioctl::SetSsid, 0, &mut i.to_bytes()).await;
|
||||||
self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes())
|
|
||||||
.await;
|
|
||||||
|
|
||||||
// to complete the join, we wait for a SET_SSID event
|
// to complete the join, we wait for a SET_SSID event
|
||||||
// we also save the AUTH status for the user, it may be interesting
|
// we also save the AUTH status for the user, it may be interesting
|
||||||
@ -351,7 +432,7 @@ impl<'a> Control<'a> {
|
|||||||
self.up().await;
|
self.up().await;
|
||||||
|
|
||||||
// Turn on AP mode
|
// Turn on AP mode
|
||||||
self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 1).await;
|
self.ioctl_set_u32(Ioctl::SetAp, 0, 1).await;
|
||||||
|
|
||||||
// Set SSID
|
// Set SSID
|
||||||
let mut i = SsidInfoWithIndex {
|
let mut i = SsidInfoWithIndex {
|
||||||
@ -365,7 +446,7 @@ impl<'a> Control<'a> {
|
|||||||
self.set_iovar("bsscfg:ssid", &i.to_bytes()).await;
|
self.set_iovar("bsscfg:ssid", &i.to_bytes()).await;
|
||||||
|
|
||||||
// Set channel number
|
// Set channel number
|
||||||
self.ioctl_set_u32(IOCTL_CMD_SET_CHANNEL, 0, channel as u32).await;
|
self.ioctl_set_u32(Ioctl::SetChannel, 0, channel as u32).await;
|
||||||
|
|
||||||
// Set security
|
// Set security
|
||||||
self.set_iovar_u32x2("bsscfg:wsec", 0, (security as u32) & 0xFF).await;
|
self.set_iovar_u32x2("bsscfg:wsec", 0, (security as u32) & 0xFF).await;
|
||||||
@ -382,7 +463,7 @@ impl<'a> Control<'a> {
|
|||||||
passphrase: [0; 64],
|
passphrase: [0; 64],
|
||||||
};
|
};
|
||||||
pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes());
|
pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes());
|
||||||
self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes())
|
self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut pfi.to_bytes())
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,7 +480,7 @@ impl<'a> Control<'a> {
|
|||||||
self.set_iovar_u32x2("bss", 0, 0).await; // bss = BSS_DOWN
|
self.set_iovar_u32x2("bss", 0, 0).await; // bss = BSS_DOWN
|
||||||
|
|
||||||
// Turn off AP mode
|
// Turn off AP mode
|
||||||
self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 0).await;
|
self.ioctl_set_u32(Ioctl::SetAp, 0, 0).await;
|
||||||
|
|
||||||
// Temporarily set wifi down
|
// Temporarily set wifi down
|
||||||
self.down().await;
|
self.down().await;
|
||||||
@ -478,11 +559,11 @@ impl<'a> Control<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn set_iovar(&mut self, name: &str, val: &[u8]) {
|
async fn set_iovar(&mut self, name: &str, val: &[u8]) {
|
||||||
self.set_iovar_v::<64>(name, val).await
|
self.set_iovar_v::<196>(name, val).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_iovar_v<const BUFSIZE: usize>(&mut self, name: &str, val: &[u8]) {
|
async fn set_iovar_v<const BUFSIZE: usize>(&mut self, name: &str, val: &[u8]) {
|
||||||
debug!("set {} = {:02x}", name, Bytes(val));
|
debug!("iovar set {} = {:02x}", name, Bytes(val));
|
||||||
|
|
||||||
let mut buf = [0; BUFSIZE];
|
let mut buf = [0; BUFSIZE];
|
||||||
buf[..name.len()].copy_from_slice(name.as_bytes());
|
buf[..name.len()].copy_from_slice(name.as_bytes());
|
||||||
@ -490,13 +571,13 @@ impl<'a> Control<'a> {
|
|||||||
buf[name.len() + 1..][..val.len()].copy_from_slice(val);
|
buf[name.len() + 1..][..val.len()].copy_from_slice(val);
|
||||||
|
|
||||||
let total_len = name.len() + 1 + val.len();
|
let total_len = name.len() + 1 + val.len();
|
||||||
self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..total_len])
|
self.ioctl_inner(IoctlType::Set, Ioctl::SetVar, 0, &mut buf[..total_len])
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this is not really working, it always returns all zeros.
|
// TODO this is not really working, it always returns all zeros.
|
||||||
async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize {
|
async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize {
|
||||||
debug!("get {}", name);
|
debug!("iovar get {}", name);
|
||||||
|
|
||||||
let mut buf = [0; 64];
|
let mut buf = [0; 64];
|
||||||
buf[..name.len()].copy_from_slice(name.as_bytes());
|
buf[..name.len()].copy_from_slice(name.as_bytes());
|
||||||
@ -504,7 +585,7 @@ impl<'a> Control<'a> {
|
|||||||
|
|
||||||
let total_len = max(name.len() + 1, res.len());
|
let total_len = max(name.len() + 1, res.len());
|
||||||
let res_len = self
|
let res_len = self
|
||||||
.ioctl(IoctlType::Get, IOCTL_CMD_GET_VAR, 0, &mut buf[..total_len])
|
.ioctl_inner(IoctlType::Get, Ioctl::GetVar, 0, &mut buf[..total_len])
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let out_len = min(res.len(), res_len);
|
let out_len = min(res.len(), res_len);
|
||||||
@ -512,12 +593,20 @@ impl<'a> Control<'a> {
|
|||||||
out_len
|
out_len
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn ioctl_set_u32(&mut self, cmd: u32, iface: u32, val: u32) {
|
async fn ioctl_set_u32(&mut self, cmd: Ioctl, iface: u32, val: u32) {
|
||||||
let mut buf = val.to_le_bytes();
|
let mut buf = val.to_le_bytes();
|
||||||
self.ioctl(IoctlType::Set, cmd, iface, &mut buf).await;
|
self.ioctl(IoctlType::Set, cmd, iface, &mut buf).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize {
|
async fn ioctl(&mut self, kind: IoctlType, cmd: Ioctl, iface: u32, buf: &mut [u8]) -> usize {
|
||||||
|
if kind == IoctlType::Set {
|
||||||
|
debug!("ioctl set {:?} iface {} = {:02x}", cmd, iface, Bytes(buf));
|
||||||
|
}
|
||||||
|
let n = self.ioctl_inner(kind, cmd, iface, buf).await;
|
||||||
|
n
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn ioctl_inner(&mut self, kind: IoctlType, cmd: Ioctl, iface: u32, buf: &mut [u8]) -> usize {
|
||||||
struct CancelOnDrop<'a>(&'a IoctlState);
|
struct CancelOnDrop<'a>(&'a IoctlState);
|
||||||
|
|
||||||
impl CancelOnDrop<'_> {
|
impl CancelOnDrop<'_> {
|
||||||
@ -609,7 +698,7 @@ impl<'a> Control<'a> {
|
|||||||
}
|
}
|
||||||
/// Leave the wifi, with which we are currently associated.
|
/// Leave the wifi, with which we are currently associated.
|
||||||
pub async fn leave(&mut self) {
|
pub async fn leave(&mut self) {
|
||||||
self.ioctl(IoctlType::Set, IOCTL_CMD_DISASSOC, 0, &mut []).await;
|
self.ioctl(IoctlType::Set, Ioctl::Disassoc, 0, &mut []).await;
|
||||||
info!("Disassociated")
|
info!("Disassociated")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,10 @@ use core::task::{Poll, Waker};
|
|||||||
|
|
||||||
use embassy_sync::waitqueue::WakerRegistration;
|
use embassy_sync::waitqueue::WakerRegistration;
|
||||||
|
|
||||||
|
use crate::consts::Ioctl;
|
||||||
use crate::fmt::Bytes;
|
use crate::fmt::Bytes;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum IoctlType {
|
pub enum IoctlType {
|
||||||
Get = 0,
|
Get = 0,
|
||||||
Set = 2,
|
Set = 2,
|
||||||
@ -16,7 +17,7 @@ pub enum IoctlType {
|
|||||||
pub struct PendingIoctl {
|
pub struct PendingIoctl {
|
||||||
pub buf: *mut [u8],
|
pub buf: *mut [u8],
|
||||||
pub kind: IoctlType,
|
pub kind: IoctlType,
|
||||||
pub cmd: u32,
|
pub cmd: Ioctl,
|
||||||
pub iface: u32,
|
pub iface: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +102,7 @@ impl IoctlState {
|
|||||||
self.state.set(IoctlStateInner::Done { resp_len: 0 });
|
self.state.set(IoctlStateInner::Done { resp_len: 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn do_ioctl(&self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize {
|
pub async fn do_ioctl(&self, kind: IoctlType, cmd: Ioctl, iface: u32, buf: &mut [u8]) -> usize {
|
||||||
self.state
|
self.state
|
||||||
.set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface }));
|
.set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface }));
|
||||||
self.wake_runner();
|
self.wake_runner();
|
||||||
|
|||||||
@ -8,18 +8,18 @@
|
|||||||
// This mod MUST go first, so that the others see its macros.
|
// This mod MUST go first, so that the others see its macros.
|
||||||
pub(crate) mod fmt;
|
pub(crate) mod fmt;
|
||||||
|
|
||||||
|
#[cfg(feature = "bluetooth")]
|
||||||
|
mod bluetooth;
|
||||||
mod bus;
|
mod bus;
|
||||||
mod consts;
|
mod consts;
|
||||||
|
mod control;
|
||||||
mod countries;
|
mod countries;
|
||||||
mod events;
|
mod events;
|
||||||
mod ioctl;
|
mod ioctl;
|
||||||
mod structs;
|
|
||||||
|
|
||||||
mod control;
|
|
||||||
mod nvram;
|
mod nvram;
|
||||||
mod runner;
|
mod runner;
|
||||||
|
mod structs;
|
||||||
use core::slice;
|
mod util;
|
||||||
|
|
||||||
use embassy_net_driver_channel as ch;
|
use embassy_net_driver_channel as ch;
|
||||||
use embedded_hal_1::digital::OutputPin;
|
use embedded_hal_1::digital::OutputPin;
|
||||||
@ -28,7 +28,9 @@ use ioctl::IoctlState;
|
|||||||
|
|
||||||
use crate::bus::Bus;
|
use crate::bus::Bus;
|
||||||
pub use crate::bus::SpiBusCyw43;
|
pub use crate::bus::SpiBusCyw43;
|
||||||
pub use crate::control::{AddMulticastAddressError, Control, Error as ControlError, Scanner};
|
pub use crate::control::{
|
||||||
|
AddMulticastAddressError, Control, Error as ControlError, JoinAuth, JoinOptions, ScanOptions, Scanner,
|
||||||
|
};
|
||||||
pub use crate::runner::Runner;
|
pub use crate::runner::Runner;
|
||||||
pub use crate::structs::BssInfo;
|
pub use crate::structs::BssInfo;
|
||||||
|
|
||||||
@ -56,6 +58,7 @@ impl Core {
|
|||||||
struct Chip {
|
struct Chip {
|
||||||
arm_core_base_address: u32,
|
arm_core_base_address: u32,
|
||||||
socsram_base_address: u32,
|
socsram_base_address: u32,
|
||||||
|
bluetooth_base_address: u32,
|
||||||
socsram_wrapper_base_address: u32,
|
socsram_wrapper_base_address: u32,
|
||||||
sdiod_core_base_address: u32,
|
sdiod_core_base_address: u32,
|
||||||
pmu_base_address: u32,
|
pmu_base_address: u32,
|
||||||
@ -83,6 +86,7 @@ const WRAPPER_REGISTER_OFFSET: u32 = 0x100000;
|
|||||||
const CHIP: Chip = Chip {
|
const CHIP: Chip = Chip {
|
||||||
arm_core_base_address: 0x18003000 + WRAPPER_REGISTER_OFFSET,
|
arm_core_base_address: 0x18003000 + WRAPPER_REGISTER_OFFSET,
|
||||||
socsram_base_address: 0x18004000,
|
socsram_base_address: 0x18004000,
|
||||||
|
bluetooth_base_address: 0x19000000,
|
||||||
socsram_wrapper_base_address: 0x18004000 + WRAPPER_REGISTER_OFFSET,
|
socsram_wrapper_base_address: 0x18004000 + WRAPPER_REGISTER_OFFSET,
|
||||||
sdiod_core_base_address: 0x18002000,
|
sdiod_core_base_address: 0x18002000,
|
||||||
pmu_base_address: 0x18000000,
|
pmu_base_address: 0x18000000,
|
||||||
@ -107,6 +111,12 @@ const CHIP: Chip = Chip {
|
|||||||
/// Driver state.
|
/// Driver state.
|
||||||
pub struct State {
|
pub struct State {
|
||||||
ioctl_state: IoctlState,
|
ioctl_state: IoctlState,
|
||||||
|
net: NetState,
|
||||||
|
#[cfg(feature = "bluetooth")]
|
||||||
|
bt: bluetooth::BtState,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NetState {
|
||||||
ch: ch::State<MTU, 4, 4>,
|
ch: ch::State<MTU, 4, 4>,
|
||||||
events: Events,
|
events: Events,
|
||||||
}
|
}
|
||||||
@ -116,8 +126,12 @@ impl State {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
ioctl_state: IoctlState::new(),
|
ioctl_state: IoctlState::new(),
|
||||||
ch: ch::State::new(),
|
net: NetState {
|
||||||
events: Events::new(),
|
ch: ch::State::new(),
|
||||||
|
events: Events::new(),
|
||||||
|
},
|
||||||
|
#[cfg(feature = "bluetooth")]
|
||||||
|
bt: bluetooth::BtState::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,21 +239,60 @@ where
|
|||||||
PWR: OutputPin,
|
PWR: OutputPin,
|
||||||
SPI: SpiBusCyw43,
|
SPI: SpiBusCyw43,
|
||||||
{
|
{
|
||||||
let (ch_runner, device) = ch::new(&mut state.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
|
let (ch_runner, device) = ch::new(&mut state.net.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
|
||||||
let state_ch = ch_runner.state_runner();
|
let state_ch = ch_runner.state_runner();
|
||||||
|
|
||||||
let mut runner = Runner::new(ch_runner, Bus::new(pwr, spi), &state.ioctl_state, &state.events);
|
let mut runner = Runner::new(
|
||||||
|
ch_runner,
|
||||||
|
Bus::new(pwr, spi),
|
||||||
|
&state.ioctl_state,
|
||||||
|
&state.net.events,
|
||||||
|
#[cfg(feature = "bluetooth")]
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
runner.init(firmware).await;
|
runner.init(firmware, None).await;
|
||||||
|
let control = Control::new(state_ch, &state.net.events, &state.ioctl_state);
|
||||||
|
|
||||||
(
|
(device, control, runner)
|
||||||
device,
|
|
||||||
Control::new(state_ch, &state.events, &state.ioctl_state),
|
|
||||||
runner,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
|
/// Create a new instance of the CYW43 driver.
|
||||||
let len = x.len() * 4;
|
///
|
||||||
unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
|
/// Returns a handle to the network device, control handle and a runner for driving the low level
|
||||||
|
/// stack.
|
||||||
|
#[cfg(feature = "bluetooth")]
|
||||||
|
pub async fn new_with_bluetooth<'a, PWR, SPI>(
|
||||||
|
state: &'a mut State,
|
||||||
|
pwr: PWR,
|
||||||
|
spi: SPI,
|
||||||
|
wifi_firmware: &[u8],
|
||||||
|
bluetooth_firmware: &[u8],
|
||||||
|
) -> (
|
||||||
|
NetDriver<'a>,
|
||||||
|
bluetooth::BtDriver<'a>,
|
||||||
|
Control<'a>,
|
||||||
|
Runner<'a, PWR, SPI>,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
PWR: OutputPin,
|
||||||
|
SPI: SpiBusCyw43,
|
||||||
|
{
|
||||||
|
let (ch_runner, device) = ch::new(&mut state.net.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
|
||||||
|
let state_ch = ch_runner.state_runner();
|
||||||
|
|
||||||
|
let (bt_runner, bt_driver) = bluetooth::new(&mut state.bt);
|
||||||
|
let mut runner = Runner::new(
|
||||||
|
ch_runner,
|
||||||
|
Bus::new(pwr, spi),
|
||||||
|
&state.ioctl_state,
|
||||||
|
&state.net.events,
|
||||||
|
#[cfg(feature = "bluetooth")]
|
||||||
|
Some(bt_runner),
|
||||||
|
);
|
||||||
|
|
||||||
|
runner.init(wifi_firmware, Some(bluetooth_firmware)).await;
|
||||||
|
let control = Control::new(state_ch, &state.net.events, &state.ioctl_state);
|
||||||
|
|
||||||
|
(device, bt_driver, control, runner)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use embassy_futures::select::{select3, Either3};
|
use embassy_futures::select::{select4, Either4};
|
||||||
use embassy_net_driver_channel as ch;
|
use embassy_net_driver_channel as ch;
|
||||||
use embassy_time::{block_for, Duration, Timer};
|
use embassy_time::{block_for, Duration, Timer};
|
||||||
use embedded_hal_1::digital::OutputPin;
|
use embedded_hal_1::digital::OutputPin;
|
||||||
@ -11,7 +11,8 @@ use crate::fmt::Bytes;
|
|||||||
use crate::ioctl::{IoctlState, IoctlType, PendingIoctl};
|
use crate::ioctl::{IoctlState, IoctlType, PendingIoctl};
|
||||||
use crate::nvram::NVRAM;
|
use crate::nvram::NVRAM;
|
||||||
use crate::structs::*;
|
use crate::structs::*;
|
||||||
use crate::{events, slice8_mut, Core, CHIP, MTU};
|
use crate::util::slice8_mut;
|
||||||
|
use crate::{events, Core, CHIP, MTU};
|
||||||
|
|
||||||
#[cfg(feature = "firmware-logs")]
|
#[cfg(feature = "firmware-logs")]
|
||||||
struct LogState {
|
struct LogState {
|
||||||
@ -36,7 +37,7 @@ impl Default for LogState {
|
|||||||
/// Driver communicating with the WiFi chip.
|
/// Driver communicating with the WiFi chip.
|
||||||
pub struct Runner<'a, PWR, SPI> {
|
pub struct Runner<'a, PWR, SPI> {
|
||||||
ch: ch::Runner<'a, MTU>,
|
ch: ch::Runner<'a, MTU>,
|
||||||
bus: Bus<PWR, SPI>,
|
pub(crate) bus: Bus<PWR, SPI>,
|
||||||
|
|
||||||
ioctl_state: &'a IoctlState,
|
ioctl_state: &'a IoctlState,
|
||||||
ioctl_id: u16,
|
ioctl_id: u16,
|
||||||
@ -47,6 +48,9 @@ pub struct Runner<'a, PWR, SPI> {
|
|||||||
|
|
||||||
#[cfg(feature = "firmware-logs")]
|
#[cfg(feature = "firmware-logs")]
|
||||||
log: LogState,
|
log: LogState,
|
||||||
|
|
||||||
|
#[cfg(feature = "bluetooth")]
|
||||||
|
pub(crate) bt: Option<crate::bluetooth::BtRunner<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, PWR, SPI> Runner<'a, PWR, SPI>
|
impl<'a, PWR, SPI> Runner<'a, PWR, SPI>
|
||||||
@ -59,6 +63,7 @@ where
|
|||||||
bus: Bus<PWR, SPI>,
|
bus: Bus<PWR, SPI>,
|
||||||
ioctl_state: &'a IoctlState,
|
ioctl_state: &'a IoctlState,
|
||||||
events: &'a Events,
|
events: &'a Events,
|
||||||
|
#[cfg(feature = "bluetooth")] bt: Option<crate::bluetooth::BtRunner<'a>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ch,
|
ch,
|
||||||
@ -70,33 +75,52 @@ where
|
|||||||
events,
|
events,
|
||||||
#[cfg(feature = "firmware-logs")]
|
#[cfg(feature = "firmware-logs")]
|
||||||
log: LogState::default(),
|
log: LogState::default(),
|
||||||
|
#[cfg(feature = "bluetooth")]
|
||||||
|
bt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn init(&mut self, firmware: &[u8]) {
|
pub(crate) async fn init(&mut self, wifi_fw: &[u8], bt_fw: Option<&[u8]>) {
|
||||||
self.bus.init().await;
|
self.bus.init(bt_fw.is_some()).await;
|
||||||
|
|
||||||
// Init ALP (Active Low Power) clock
|
// Init ALP (Active Low Power) clock
|
||||||
|
debug!("init alp");
|
||||||
self.bus
|
self.bus
|
||||||
.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ)
|
.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
debug!("set f2 watermark");
|
||||||
|
self.bus
|
||||||
|
.write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 0x10)
|
||||||
|
.await;
|
||||||
|
let watermark = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK).await;
|
||||||
|
debug!("watermark = {:02x}", watermark);
|
||||||
|
assert!(watermark == 0x10);
|
||||||
|
|
||||||
debug!("waiting for clock...");
|
debug!("waiting for clock...");
|
||||||
while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {}
|
while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {}
|
||||||
debug!("clock ok");
|
debug!("clock ok");
|
||||||
|
|
||||||
|
// clear request for ALP
|
||||||
|
debug!("clear request for ALP");
|
||||||
|
self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0).await;
|
||||||
|
|
||||||
let chip_id = self.bus.bp_read16(0x1800_0000).await;
|
let chip_id = self.bus.bp_read16(0x1800_0000).await;
|
||||||
debug!("chip ID: {}", chip_id);
|
debug!("chip ID: {}", chip_id);
|
||||||
|
|
||||||
// Upload firmware.
|
// Upload firmware.
|
||||||
self.core_disable(Core::WLAN).await;
|
self.core_disable(Core::WLAN).await;
|
||||||
|
self.core_disable(Core::SOCSRAM).await; // TODO: is this needed if we reset right after?
|
||||||
self.core_reset(Core::SOCSRAM).await;
|
self.core_reset(Core::SOCSRAM).await;
|
||||||
|
|
||||||
|
// this is 4343x specific stuff: Disable remap for SRAM_3
|
||||||
self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await;
|
self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await;
|
||||||
self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await;
|
self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await;
|
||||||
|
|
||||||
let ram_addr = CHIP.atcm_ram_base_address;
|
let ram_addr = CHIP.atcm_ram_base_address;
|
||||||
|
|
||||||
debug!("loading fw");
|
debug!("loading fw");
|
||||||
self.bus.bp_write(ram_addr, firmware).await;
|
self.bus.bp_write(ram_addr, wifi_fw).await;
|
||||||
|
|
||||||
debug!("loading nvram");
|
debug!("loading nvram");
|
||||||
// Round up to 4 bytes.
|
// Round up to 4 bytes.
|
||||||
@ -116,10 +140,23 @@ where
|
|||||||
self.core_reset(Core::WLAN).await;
|
self.core_reset(Core::WLAN).await;
|
||||||
assert!(self.core_is_up(Core::WLAN).await);
|
assert!(self.core_is_up(Core::WLAN).await);
|
||||||
|
|
||||||
|
// wait until HT clock is available; takes about 29ms
|
||||||
|
debug!("wait for HT clock");
|
||||||
while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
|
while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
|
||||||
|
|
||||||
// "Set up the interrupt mask and enable interrupts"
|
// "Set up the interrupt mask and enable interrupts"
|
||||||
// self.bus.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await;
|
debug!("setup interrupt mask");
|
||||||
|
self.bus
|
||||||
|
.bp_write32(CHIP.sdiod_core_base_address + SDIO_INT_HOST_MASK, I_HMB_SW_MASK)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// Set up the interrupt mask and enable interrupts
|
||||||
|
if bt_fw.is_some() {
|
||||||
|
debug!("bluetooth setup interrupt mask");
|
||||||
|
self.bus
|
||||||
|
.bp_write32(CHIP.sdiod_core_base_address + SDIO_INT_HOST_MASK, I_HMB_FC_CHANGE)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
self.bus
|
self.bus
|
||||||
.write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, IRQ_F2_PACKET_AVAILABLE)
|
.write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, IRQ_F2_PACKET_AVAILABLE)
|
||||||
@ -128,11 +165,11 @@ where
|
|||||||
// "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped."
|
// "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped."
|
||||||
// Sounds scary...
|
// Sounds scary...
|
||||||
self.bus
|
self.bus
|
||||||
.write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 32)
|
.write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, SPI_F2_WATERMARK)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// wait for wifi startup
|
// wait for F2 to be ready
|
||||||
debug!("waiting for wifi init...");
|
debug!("waiting for F2 to be ready...");
|
||||||
while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {}
|
while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {}
|
||||||
|
|
||||||
// Some random configs related to sleep.
|
// Some random configs related to sleep.
|
||||||
@ -153,19 +190,27 @@ where
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// clear pulls
|
// clear pulls
|
||||||
|
debug!("clear pad pulls");
|
||||||
self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await;
|
self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await;
|
||||||
let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await;
|
let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await;
|
||||||
|
|
||||||
// start HT clock
|
// start HT clock
|
||||||
//self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await;
|
self.bus
|
||||||
//debug!("waiting for HT clock...");
|
.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10)
|
||||||
//while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
|
.await; // SBSDIO_HT_AVAIL_REQ
|
||||||
//debug!("clock ok");
|
debug!("waiting for HT clock...");
|
||||||
|
while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
|
||||||
|
debug!("clock ok");
|
||||||
|
|
||||||
#[cfg(feature = "firmware-logs")]
|
#[cfg(feature = "firmware-logs")]
|
||||||
self.log_init().await;
|
self.log_init().await;
|
||||||
|
|
||||||
debug!("wifi init done");
|
#[cfg(feature = "bluetooth")]
|
||||||
|
if let Some(bt_fw) = bt_fw {
|
||||||
|
self.bt.as_mut().unwrap().init_bluetooth(&mut self.bus, bt_fw).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("cyw43 runner init done");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "firmware-logs")]
|
#[cfg(feature = "firmware-logs")]
|
||||||
@ -222,7 +267,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the
|
/// Run the CYW43 event handling loop.
|
||||||
pub async fn run(mut self) -> ! {
|
pub async fn run(mut self) -> ! {
|
||||||
let mut buf = [0; 512];
|
let mut buf = [0; 512];
|
||||||
loop {
|
loop {
|
||||||
@ -231,11 +276,27 @@ where
|
|||||||
|
|
||||||
if self.has_credit() {
|
if self.has_credit() {
|
||||||
let ioctl = self.ioctl_state.wait_pending();
|
let ioctl = self.ioctl_state.wait_pending();
|
||||||
let tx = self.ch.tx_buf();
|
let wifi_tx = self.ch.tx_buf();
|
||||||
|
#[cfg(feature = "bluetooth")]
|
||||||
|
let bt_tx = async {
|
||||||
|
match &mut self.bt {
|
||||||
|
Some(bt) => bt.tx_chan.receive().await,
|
||||||
|
None => core::future::pending().await,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#[cfg(not(feature = "bluetooth"))]
|
||||||
|
let bt_tx = core::future::pending::<()>();
|
||||||
|
|
||||||
|
// interrupts aren't working yet for bluetooth. Do busy-polling instead.
|
||||||
|
// Note for this to work `ev` has to go last in the `select()`. It prefers
|
||||||
|
// first futures if they're ready, so other select branches don't get starved.`
|
||||||
|
#[cfg(feature = "bluetooth")]
|
||||||
|
let ev = core::future::ready(());
|
||||||
|
#[cfg(not(feature = "bluetooth"))]
|
||||||
let ev = self.bus.wait_for_event();
|
let ev = self.bus.wait_for_event();
|
||||||
|
|
||||||
match select3(ioctl, tx, ev).await {
|
match select4(ioctl, wifi_tx, bt_tx, ev).await {
|
||||||
Either3::First(PendingIoctl {
|
Either4::First(PendingIoctl {
|
||||||
buf: iobuf,
|
buf: iobuf,
|
||||||
kind,
|
kind,
|
||||||
cmd,
|
cmd,
|
||||||
@ -244,7 +305,7 @@ where
|
|||||||
self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }, &mut buf).await;
|
self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }, &mut buf).await;
|
||||||
self.check_status(&mut buf).await;
|
self.check_status(&mut buf).await;
|
||||||
}
|
}
|
||||||
Either3::Second(packet) => {
|
Either4::Second(packet) => {
|
||||||
trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
|
trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
|
||||||
|
|
||||||
let buf8 = slice8_mut(&mut buf);
|
let buf8 = slice8_mut(&mut buf);
|
||||||
@ -298,8 +359,19 @@ where
|
|||||||
self.ch.tx_done();
|
self.ch.tx_done();
|
||||||
self.check_status(&mut buf).await;
|
self.check_status(&mut buf).await;
|
||||||
}
|
}
|
||||||
Either3::Third(()) => {
|
Either4::Third(_) => {
|
||||||
|
#[cfg(feature = "bluetooth")]
|
||||||
|
self.bt.as_mut().unwrap().hci_write(&mut self.bus).await;
|
||||||
|
}
|
||||||
|
Either4::Fourth(()) => {
|
||||||
self.handle_irq(&mut buf).await;
|
self.handle_irq(&mut buf).await;
|
||||||
|
|
||||||
|
// If we do busy-polling, make sure to yield.
|
||||||
|
// `handle_irq` will only do a 32bit read if there's no work to do, which is really fast.
|
||||||
|
// Depending on optimization level, it is possible that the 32-bit read finishes on
|
||||||
|
// first poll, so it never yields and we starve all other tasks.
|
||||||
|
#[cfg(feature = "bluetooth")]
|
||||||
|
embassy_futures::yield_now().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -314,17 +386,24 @@ where
|
|||||||
async fn handle_irq(&mut self, buf: &mut [u32; 512]) {
|
async fn handle_irq(&mut self, buf: &mut [u32; 512]) {
|
||||||
// Receive stuff
|
// Receive stuff
|
||||||
let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await;
|
let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await;
|
||||||
trace!("irq{}", FormatInterrupt(irq));
|
if irq != 0 {
|
||||||
|
trace!("irq{}", FormatInterrupt(irq));
|
||||||
|
}
|
||||||
|
|
||||||
if irq & IRQ_F2_PACKET_AVAILABLE != 0 {
|
if irq & IRQ_F2_PACKET_AVAILABLE != 0 {
|
||||||
self.check_status(buf).await;
|
self.check_status(buf).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
if irq & IRQ_DATA_UNAVAILABLE != 0 {
|
if irq & IRQ_DATA_UNAVAILABLE != 0 {
|
||||||
// TODO what should we do here?
|
// this seems to be ignorable with no ill effects.
|
||||||
warn!("IRQ DATA_UNAVAILABLE, clearing...");
|
trace!("IRQ DATA_UNAVAILABLE, clearing...");
|
||||||
self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await;
|
self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "bluetooth")]
|
||||||
|
if let Some(bt) = &mut self.bt {
|
||||||
|
bt.handle_irq(&mut self.bus).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle F2 events while status register is set
|
/// Handle F2 events while status register is set
|
||||||
@ -481,7 +560,7 @@ where
|
|||||||
self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0
|
self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8], buf: &mut [u32; 512]) {
|
async fn send_ioctl(&mut self, kind: IoctlType, cmd: Ioctl, iface: u32, data: &[u8], buf: &mut [u32; 512]) {
|
||||||
let buf8 = slice8_mut(buf);
|
let buf8 = slice8_mut(buf);
|
||||||
|
|
||||||
let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len();
|
let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len();
|
||||||
@ -503,7 +582,7 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
let cdc_header = CdcHeader {
|
let cdc_header = CdcHeader {
|
||||||
cmd: cmd,
|
cmd: cmd as u32,
|
||||||
len: data.len() as _,
|
len: data.len() as _,
|
||||||
flags: kind as u16 | (iface as u16) << 12,
|
flags: kind as u16 | (iface as u16) << 12,
|
||||||
id: self.ioctl_id,
|
id: self.ioctl_id,
|
||||||
|
|||||||
@ -394,6 +394,15 @@ pub struct PassphraseInfo {
|
|||||||
}
|
}
|
||||||
impl_bytes!(PassphraseInfo);
|
impl_bytes!(PassphraseInfo);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct SaePassphraseInfo {
|
||||||
|
pub len: u16,
|
||||||
|
pub passphrase: [u8; 128],
|
||||||
|
}
|
||||||
|
impl_bytes!(SaePassphraseInfo);
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|||||||
20
cyw43/src/util.rs
Normal file
20
cyw43/src/util.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
use core::slice;
|
||||||
|
|
||||||
|
pub(crate) fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
|
||||||
|
let len = x.len() * 4;
|
||||||
|
unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_aligned(a: u32, x: u32) -> bool {
|
||||||
|
(a & (x - 1)) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn round_down(x: u32, a: u32) -> u32 {
|
||||||
|
x & !(a - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn round_up(x: u32, a: u32) -> u32 {
|
||||||
|
((x + a - 1) / a) * a
|
||||||
|
}
|
||||||
@ -6,9 +6,9 @@ version = "0.1.0"
|
|||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-executor = { version = "0.5.0", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] }
|
embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] }
|
||||||
embassy-time = { version = "0.3.1", path = "../../../embassy-time", features = ["defmt"] }
|
embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt"] }
|
||||||
embassy-nrf = { version = "0.1.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] }
|
embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] }
|
||||||
|
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
defmt-rtt = "0.3"
|
defmt-rtt = "0.3"
|
||||||
|
|||||||
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
cortex-m = "0.7"
|
cortex-m = "0.7"
|
||||||
cortex-m-rt = "0.7"
|
cortex-m-rt = "0.7"
|
||||||
embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] }
|
embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] }
|
||||||
embassy-executor = { version = "0.5.0", features = ["arch-cortex-m", "executor-thread"] }
|
embassy-executor = { version = "0.6.0", features = ["arch-cortex-m", "executor-thread"] }
|
||||||
|
|
||||||
defmt = "0.3.0"
|
defmt = "0.3.0"
|
||||||
defmt-rtt = "0.3.0"
|
defmt-rtt = "0.3.0"
|
||||||
|
|||||||
@ -4,7 +4,7 @@ So you've got one of the examples running, but what now? Let's go through a simp
|
|||||||
|
|
||||||
== Main
|
== Main
|
||||||
|
|
||||||
The full example can be found link:https://github.com/embassy-rs/embassy/tree/master/docs/examples/basic[here].
|
The full example can be found link:https://github.com/embassy-rs/embassy/tree/main/docs/examples/basic[here].
|
||||||
|
|
||||||
NOTE: If you’re using VS Code and rust-analyzer to view and edit the examples, you may need to make some changes to `.vscode/settings.json` to tell it which project we’re working on. Follow the instructions commented in that file to get rust-analyzer working correctly.
|
NOTE: If you’re using VS Code and rust-analyzer to view and edit the examples, you may need to make some changes to `.vscode/settings.json` to tell it which project we’re working on. Follow the instructions commented in that file to get rust-analyzer working correctly.
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/pages/embassy_in_the_wild.adoc[add more]!
|
Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/pages/embassy_in_the_wild.adoc[add more]!
|
||||||
|
|
||||||
|
* link:https://github.com/1-rafael-1/pi-pico-alarmclock-rust[A Raspberry Pi Pico W Alarmclock]
|
||||||
|
** A hobbyist project building an alarm clock around a Pi Pico W complete with code, components list and enclosure design files.
|
||||||
* link:https://github.com/haobogu/rmk/[RMK: A feature-rich Rust keyboard firmware]
|
* link:https://github.com/haobogu/rmk/[RMK: A feature-rich Rust keyboard firmware]
|
||||||
** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more!
|
** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more!
|
||||||
** Targets STM32, RP2040, nRF52 and ESP32 MCUs
|
** Targets STM32, RP2040, nRF52 and ESP32 MCUs
|
||||||
|
|||||||
@ -352,8 +352,23 @@ There are two main ways to handle concurrency in Embassy:
|
|||||||
|
|
||||||
In general, either of these approaches will work. The main differences of these approaches are:
|
In general, either of these approaches will work. The main differences of these approaches are:
|
||||||
|
|
||||||
When using **separate tasks**, each task needs its own RAM allocation, so there's a little overhead for each task, so one task that does three things will likely be a little bit smaller than three tasks that do one thing (not a lot, probably a couple dozen bytes). In contrast, with **multiple futures in one task**, you don't need multiple task allocations, and it will generally be easier to share data, or use borrowed resources, inside of a single task.
|
When using **separate tasks**, each task needs its own RAM allocation, so there's a little overhead for each task, so one task that does three things will likely be a little bit smaller than three tasks that do one thing (not a lot, probably a couple dozen bytes). In contrast, with **multiple futures in one task**, you don't need multiple task allocations, and it will generally be easier to share data, or use borrowed resources, inside of a single task.
|
||||||
|
An example showcasing some methods for sharing things between tasks link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/sharing.rs[can be found here].
|
||||||
|
|
||||||
But when it comes to "waking" tasks, for example when a data transfer is complete or a button is pressed, it's faster to wake a dedicated task, because that task does not need to check which future is actually ready. `join` and `select` must check ALL of the futures they are managing to see which one (or which ones) are ready to do more work. This is because all Rust executors (like Embassy or Tokio) only have the ability to wake tasks, not specific futures. This means you will use slightly less CPU time juggling futures when using dedicated tasks.
|
But when it comes to "waking" tasks, for example when a data transfer is complete or a button is pressed, it's faster to wake a dedicated task, because that task does not need to check which future is actually ready. `join` and `select` must check ALL of the futures they are managing to see which one (or which ones) are ready to do more work. This is because all Rust executors (like Embassy or Tokio) only have the ability to wake tasks, not specific futures. This means you will use slightly less CPU time juggling futures when using dedicated tasks.
|
||||||
|
|
||||||
Practically, there's not a LOT of difference either way - so go with what makes it easier for you and your code first, but there will be some details that are slightly different in each case.
|
Practically, there's not a LOT of difference either way - so go with what makes it easier for you and your code first, but there will be some details that are slightly different in each case.
|
||||||
|
|
||||||
|
== splitting peripherals resources between tasks
|
||||||
|
|
||||||
|
There are two ways to split resources between tasks, either manually assigned or by a convenient macro. See link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/assign_resources.rs[this example]
|
||||||
|
|
||||||
|
== My code/driver works in debug mode, but not release mode (or with LTO)
|
||||||
|
|
||||||
|
Issues like these while implementing drivers often fall into one of the following general causes, which are a good list of common errors to check for:
|
||||||
|
|
||||||
|
1. Some kind of race condition - the faster code means you miss an interrupt or something
|
||||||
|
2. Some kind of UB, if you have unsafe code, or something like DMA with fences missing
|
||||||
|
3. Some kind of hardware errata, or some hardware misconfiguration like wrong clock speeds
|
||||||
|
4. Some issue with an interrupt handler, either enabling, disabling, or re-enabling of interrupts when necessary
|
||||||
|
5. Some kind of async issue, like not registering wakers fully before checking flags, or not registering or pending wakers at the right time
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
= Starting a new project
|
= Starting a new project
|
||||||
|
|
||||||
Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project.
|
Once you’ve successfully xref:#_getting_started[run some example projects], the next step is to make a standalone Embassy project.
|
||||||
|
|
||||||
== Tools for generating Embassy projects
|
== Tools for generating Embassy projects
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
= Embassy nRF HAL
|
= Embassy nRF HAL
|
||||||
|
|
||||||
The link:https://github.com/embassy-rs/embassy/tree/master/embassy-nrf[Embassy nRF HAL] is based on the PACs (Peripheral Access Crate) from link:https://github.com/nrf-rs/[nrf-rs].
|
The link:https://github.com/embassy-rs/embassy/tree/main/embassy-nrf[Embassy nRF HAL] is based on the PACs (Peripheral Access Crate) from link:https://github.com/nrf-rs/[nrf-rs].
|
||||||
|
|
||||||
== Timer driver
|
== Timer driver
|
||||||
|
|
||||||
|
|||||||
@ -48,7 +48,7 @@ link:https://github.com/lora-rs/lora-rs[lora-rs] supports LoRa networking on a w
|
|||||||
link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
|
link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
|
||||||
|
|
||||||
=== Bootloader and DFU
|
=== Bootloader and DFU
|
||||||
link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
|
link:https://github.com/embassy-rs/embassy/tree/main/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
|
||||||
|
|
||||||
== What is DMA?
|
== What is DMA?
|
||||||
|
|
||||||
@ -77,3 +77,7 @@ For more reading material on async Rust and Embassy:
|
|||||||
* link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparsion of FreeRTOS and Embassy]
|
* link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparsion of FreeRTOS and Embassy]
|
||||||
* link:https://dev.to/apollolabsbin/series/20707[Tutorials]
|
* link:https://dev.to/apollolabsbin/series/20707[Tutorials]
|
||||||
* link:https://blog.drogue.io/firmware-updates-part-1/[Firmware Updates with Embassy]
|
* link:https://blog.drogue.io/firmware-updates-part-1/[Firmware Updates with Embassy]
|
||||||
|
|
||||||
|
Videos:
|
||||||
|
|
||||||
|
* link:https://www.youtube.com/watch?v=wni5h5vIPhU[From Zero to Async in Embedded Rust]
|
||||||
@ -8,7 +8,7 @@ The following examples shows different ways to use the on-board LED on a Raspber
|
|||||||
|
|
||||||
Using mutual exclusion is the simplest way to share a peripheral.
|
Using mutual exclusion is the simplest way to share a peripheral.
|
||||||
|
|
||||||
TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here].
|
TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
|
||||||
[,rust]
|
[,rust]
|
||||||
----
|
----
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
@ -78,7 +78,7 @@ To indicate that the pin will be set to an Output. The `AnyPin` could have been
|
|||||||
|
|
||||||
A channel is another way to ensure exclusive access to a resource. Using a channel is great in the cases where the access can happen at a later point in time, allowing you to enqueue operations and do other things.
|
A channel is another way to ensure exclusive access to a resource. Using a channel is great in the cases where the access can happen at a later point in time, allowing you to enqueue operations and do other things.
|
||||||
|
|
||||||
TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here].
|
TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
|
||||||
[,rust]
|
[,rust]
|
||||||
----
|
----
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
@ -126,3 +126,9 @@ async fn toggle_led(control: Sender<'static, ThreadModeRawMutex, LedState, 64>,
|
|||||||
|
|
||||||
This example replaces the Mutex with a Channel, and uses another task (the main loop) to drive the LED. The advantage of this approach is that only a single task references the peripheral, separating concerns. However, using a Mutex has a lower overhead and might be necessary if you need to ensure
|
This example replaces the Mutex with a Channel, and uses another task (the main loop) to drive the LED. The advantage of this approach is that only a single task references the peripheral, separating concerns. However, using a Mutex has a lower overhead and might be necessary if you need to ensure
|
||||||
that the operation is completed before continuing to do other work in your task.
|
that the operation is completed before continuing to do other work in your task.
|
||||||
|
|
||||||
|
An example showcasing more methods for sharing link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/sharing.rs[can be found here].
|
||||||
|
|
||||||
|
== Sharing an I2C or SPI bus between multiple devices
|
||||||
|
|
||||||
|
An example of how to deal with multiple devices sharing a common I2C or SPI bus link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/shared_bus.rs[can be found here].
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
= Embassy STM32 HAL
|
= Embassy STM32 HAL
|
||||||
|
|
||||||
The link:https://github.com/embassy-rs/embassy/tree/master/embassy-stm32[Embassy STM32 HAL] is based on the `stm32-metapac` project.
|
The link:https://github.com/embassy-rs/embassy/tree/main/embassy-stm32[Embassy STM32 HAL] is based on the `stm32-metapac` project.
|
||||||
|
|
||||||
== The infinite variant problem
|
== The infinite variant problem
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ The `embassy::time::Timer` type provides two timing methods.
|
|||||||
|
|
||||||
An example of a delay is provided as follows:
|
An example of a delay is provided as follows:
|
||||||
|
|
||||||
TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here].
|
TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
|
||||||
[,rust]
|
[,rust]
|
||||||
----
|
----
|
||||||
use embassy::executor::{task, Executor};
|
use embassy::executor::{task, Executor};
|
||||||
@ -41,7 +41,7 @@ that expect a generic delay implementation to be provided.
|
|||||||
|
|
||||||
An example of how this can be used:
|
An example of how this can be used:
|
||||||
|
|
||||||
TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here].
|
TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
|
||||||
[,rust]
|
[,rust]
|
||||||
----
|
----
|
||||||
use embassy::executor::{task, Executor};
|
use embassy::executor::{task, Executor};
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
name = "embassy-boot-nrf"
|
name = "embassy-boot-nrf"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
description = "Bootloader lib for nRF chips"
|
description = "Bootloader lib for nRF chips"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://github.com/embassy-rs/embassy"
|
repository = "https://github.com/embassy-rs/embassy"
|
||||||
@ -25,8 +25,8 @@ defmt = { version = "0.3", optional = true }
|
|||||||
log = { version = "0.4.17", optional = true }
|
log = { version = "0.4.17", optional = true }
|
||||||
|
|
||||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||||
embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", default-features = false }
|
embassy-nrf = { version = "0.2.0", path = "../embassy-nrf", default-features = false }
|
||||||
embassy-boot = { version = "0.2.0", path = "../embassy-boot" }
|
embassy-boot = { version = "0.3.0", path = "../embassy-boot" }
|
||||||
cortex-m = { version = "0.7.6" }
|
cortex-m = { version = "0.7.6" }
|
||||||
cortex-m-rt = { version = "0.7" }
|
cortex-m-rt = { version = "0.7" }
|
||||||
embedded-storage = "0.3.1"
|
embedded-storage = "0.3.1"
|
||||||
|
|||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
name = "embassy-boot-rp"
|
name = "embassy-boot-rp"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
description = "Bootloader lib for RP2040 chips"
|
description = "Bootloader lib for RP2040 chips"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://github.com/embassy-rs/embassy"
|
repository = "https://github.com/embassy-rs/embassy"
|
||||||
@ -16,6 +16,7 @@ categories = [
|
|||||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-rp-v$VERSION/src/"
|
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-rp-v$VERSION/src/"
|
||||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot-rp/src/"
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot-rp/src/"
|
||||||
target = "thumbv6m-none-eabi"
|
target = "thumbv6m-none-eabi"
|
||||||
|
features = ["embassy-rp/rp2040"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
|
||||||
@ -24,9 +25,9 @@ defmt = { version = "0.3", optional = true }
|
|||||||
log = { version = "0.4", optional = true }
|
log = { version = "0.4", optional = true }
|
||||||
|
|
||||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||||
embassy-rp = { version = "0.1.0", path = "../embassy-rp", default-features = false }
|
embassy-rp = { version = "0.2.0", path = "../embassy-rp", default-features = false }
|
||||||
embassy-boot = { version = "0.2.0", path = "../embassy-boot" }
|
embassy-boot = { version = "0.3.0", path = "../embassy-boot" }
|
||||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
embassy-time = { version = "0.3.2", path = "../embassy-time" }
|
||||||
|
|
||||||
cortex-m = { version = "0.7.6" }
|
cortex-m = { version = "0.7.6" }
|
||||||
cortex-m-rt = { version = "0.7" }
|
cortex-m-rt = { version = "0.7" }
|
||||||
|
|||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ log = { version = "0.4", optional = true }
|
|||||||
|
|
||||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false }
|
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false }
|
||||||
embassy-boot = { version = "0.2.0", path = "../embassy-boot" }
|
embassy-boot = { version = "0.3.0", path = "../embassy-boot" }
|
||||||
cortex-m = { version = "0.7.6" }
|
cortex-m = { version = "0.7.6" }
|
||||||
cortex-m-rt = { version = "0.7" }
|
cortex-m-rt = { version = "0.7" }
|
||||||
embedded-storage = "0.3.1"
|
embedded-storage = "0.3.1"
|
||||||
|
|||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
name = "embassy-boot"
|
name = "embassy-boot"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks."
|
description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks."
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://github.com/embassy-rs/embassy"
|
repository = "https://github.com/embassy-rs/embassy"
|
||||||
@ -27,8 +27,8 @@ features = ["defmt"]
|
|||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
digest = "0.10"
|
digest = "0.10"
|
||||||
log = { version = "0.4", optional = true }
|
log = { version = "0.4", optional = true }
|
||||||
ed25519-dalek = { version = "2", default_features = false, features = ["digest"], optional = true }
|
ed25519-dalek = { version = "2", default-features = false, features = ["digest"], optional = true }
|
||||||
embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
|
embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" }
|
||||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||||
embedded-storage = "0.3.1"
|
embedded-storage = "0.3.1"
|
||||||
embedded-storage-async = { version = "0.4.1" }
|
embedded-storage-async = { version = "0.4.1" }
|
||||||
@ -42,7 +42,7 @@ rand = "0.8"
|
|||||||
futures = { version = "0.3", features = ["executor"] }
|
futures = { version = "0.3", features = ["executor"] }
|
||||||
sha1 = "0.10.5"
|
sha1 = "0.10.5"
|
||||||
critical-section = { version = "1.1.1", features = ["std"] }
|
critical-section = { version = "1.1.1", features = ["std"] }
|
||||||
ed25519-dalek = { version = "2", default_features = false, features = ["std", "rand_core", "digest"] }
|
ed25519-dalek = { version = "2", default-features = false, features = ["std", "rand_core", "digest"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
ed25519-dalek = ["dep:ed25519-dalek", "_verify"]
|
ed25519-dalek = ["dep:ed25519-dalek", "_verify"]
|
||||||
|
|||||||
@ -236,10 +236,10 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
|
|||||||
///
|
///
|
||||||
pub fn prepare_boot(&mut self, aligned_buf: &mut [u8]) -> Result<State, BootError> {
|
pub fn prepare_boot(&mut self, aligned_buf: &mut [u8]) -> Result<State, BootError> {
|
||||||
const {
|
const {
|
||||||
assert!(Self::PAGE_SIZE % ACTIVE::WRITE_SIZE as u32 == 0);
|
core::assert!(Self::PAGE_SIZE % ACTIVE::WRITE_SIZE as u32 == 0);
|
||||||
assert!(Self::PAGE_SIZE % ACTIVE::ERASE_SIZE as u32 == 0);
|
core::assert!(Self::PAGE_SIZE % ACTIVE::ERASE_SIZE as u32 == 0);
|
||||||
assert!(Self::PAGE_SIZE % DFU::WRITE_SIZE as u32 == 0);
|
core::assert!(Self::PAGE_SIZE % DFU::WRITE_SIZE as u32 == 0);
|
||||||
assert!(Self::PAGE_SIZE % DFU::ERASE_SIZE as u32 == 0);
|
core::assert!(Self::PAGE_SIZE % DFU::ERASE_SIZE as u32 == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we have enough progress pages to store copy progress
|
// Ensure we have enough progress pages to store copy progress
|
||||||
|
|||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
21
embassy-embedded-hal/CHANGELOG.md
Normal file
21
embassy-embedded-hal/CHANGELOG.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Changelog for embassy-embedded-hal
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
## 0.2.0 - 2024-08-05
|
||||||
|
|
||||||
|
- Add Clone derive to flash Partition in embassy-embedded-hal
|
||||||
|
- Add support for all word sizes to async shared spi
|
||||||
|
- Add Copy and 'static constraint to Word type in SPI structs
|
||||||
|
- Improve flexibility by introducing SPI word size as a generic parameter
|
||||||
|
- Allow changing Spi/I2cDeviceWithConfig's config at runtime
|
||||||
|
- Impl `MultiwriteNorFlash` for `BlockingAsync`
|
||||||
|
|
||||||
|
## 0.1.0 - 2024-01-10
|
||||||
|
|
||||||
|
- First release
|
||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "embassy-embedded-hal"
|
name = "embassy-embedded-hal"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Collection of utilities to use `embedded-hal` and `embedded-storage` traits with Embassy."
|
description = "Collection of utilities to use `embedded-hal` and `embedded-storage` traits with Embassy."
|
||||||
@ -29,7 +29,7 @@ default = ["time"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||||
embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true }
|
embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true }
|
||||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
|
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
|
||||||
"unproven",
|
"unproven",
|
||||||
] }
|
] }
|
||||||
|
|||||||
@ -18,6 +18,16 @@ pub struct Partition<'a, M: RawMutex, T: NorFlash> {
|
|||||||
size: u32,
|
size: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, M: RawMutex, T: NorFlash> Clone for Partition<'a, M, T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
flash: self.flash,
|
||||||
|
offset: self.offset,
|
||||||
|
size: self.size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, M: RawMutex, T: NorFlash> Partition<'a, M, T> {
|
impl<'a, M: RawMutex, T: NorFlash> Partition<'a, M, T> {
|
||||||
/// Create a new partition
|
/// Create a new partition
|
||||||
pub const fn new(flash: &'a Mutex<M, T>, offset: u32, size: u32) -> Self {
|
pub const fn new(flash: &'a Mutex<M, T>, offset: u32, size: u32) -> Self {
|
||||||
|
|||||||
@ -19,6 +19,16 @@ pub struct BlockingPartition<'a, M: RawMutex, T: NorFlash> {
|
|||||||
size: u32,
|
size: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, M: RawMutex, T: NorFlash> Clone for BlockingPartition<'a, M, T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
flash: self.flash,
|
||||||
|
offset: self.offset,
|
||||||
|
size: self.size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, M: RawMutex, T: NorFlash> BlockingPartition<'a, M, T> {
|
impl<'a, M: RawMutex, T: NorFlash> BlockingPartition<'a, M, T> {
|
||||||
/// Create a new partition
|
/// Create a new partition
|
||||||
pub const fn new(flash: &'a Mutex<M, RefCell<T>>, offset: u32, size: u32) -> Self {
|
pub const fn new(flash: &'a Mutex<M, RefCell<T>>, offset: u32, size: u32) -> Self {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "embassy-executor-macros"
|
name = "embassy-executor-macros"
|
||||||
version = "0.4.1"
|
version = "0.5.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "macros for creating the entry point and tasks for embassy-executor"
|
description = "macros for creating the entry point and tasks for embassy-executor"
|
||||||
|
|||||||
@ -70,7 +70,7 @@ pub fn wasm() -> TokenStream {
|
|||||||
let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(::embassy_executor::Executor::new()));
|
let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(::embassy_executor::Executor::new()));
|
||||||
|
|
||||||
executor.start(|spawner| {
|
executor.start(|spawner| {
|
||||||
spawner.spawn(__embassy_main(spawner)).unwrap();
|
spawner.must_spawn(__embassy_main(spawner));
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
## 0.6.0 - 2024-08-05
|
||||||
|
|
||||||
|
- Add collapse_debuginfo to fmt.rs macros.
|
||||||
|
- initial support for avr
|
||||||
|
- use nightly waker_getters APIs
|
||||||
|
|
||||||
## 0.5.0 - 2024-01-11
|
## 0.5.0 - 2024-01-11
|
||||||
|
|
||||||
- Updated to `embassy-time-driver 0.1`, `embassy-time-queue-driver 0.1`, compatible with `embassy-time v0.3` and higher.
|
- Updated to `embassy-time-driver 0.1`, `embassy-time-queue-driver 0.1`, compatible with `embassy-time v0.3` and higher.
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "embassy-executor"
|
name = "embassy-executor"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "async/await executor designed for embedded usage"
|
description = "async/await executor designed for embedded usage"
|
||||||
@ -33,7 +33,7 @@ defmt = { version = "0.3", optional = true }
|
|||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
rtos-trace = { version = "0.1.2", optional = true }
|
rtos-trace = { version = "0.1.2", optional = true }
|
||||||
|
|
||||||
embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macros" }
|
embassy-executor-macros = { version = "0.5.0", path = "../embassy-executor-macros" }
|
||||||
embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true }
|
embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true }
|
||||||
embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true }
|
embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true }
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
@ -79,7 +79,7 @@ arch-cortex-m = ["_arch", "dep:cortex-m"]
|
|||||||
## RISC-V 32
|
## RISC-V 32
|
||||||
arch-riscv32 = ["_arch"]
|
arch-riscv32 = ["_arch"]
|
||||||
## WASM
|
## WASM
|
||||||
arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"]
|
arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys", "critical-section/std"]
|
||||||
## AVR
|
## AVR
|
||||||
arch-avr = ["_arch", "dep:portable-atomic", "dep:avr-device"]
|
arch-avr = ["_arch", "dep:portable-atomic", "dep:avr-device"]
|
||||||
|
|
||||||
|
|||||||
@ -8,8 +8,6 @@
|
|||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::OsString;
|
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
|
/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
|
||||||
/// them (`cargo:rust-check-cfg=cfg(X)`).
|
/// them (`cargo:rust-check-cfg=cfg(X)`).
|
||||||
@ -17,7 +15,6 @@ use std::process::Command;
|
|||||||
pub struct CfgSet {
|
pub struct CfgSet {
|
||||||
enabled: HashSet<String>,
|
enabled: HashSet<String>,
|
||||||
declared: HashSet<String>,
|
declared: HashSet<String>,
|
||||||
emit_declared: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CfgSet {
|
impl CfgSet {
|
||||||
@ -25,7 +22,6 @@ impl CfgSet {
|
|||||||
Self {
|
Self {
|
||||||
enabled: HashSet::new(),
|
enabled: HashSet::new(),
|
||||||
declared: HashSet::new(),
|
declared: HashSet::new(),
|
||||||
emit_declared: is_rustc_nightly(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +45,7 @@ impl CfgSet {
|
|||||||
///
|
///
|
||||||
/// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
|
/// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
|
||||||
pub fn declare(&mut self, cfg: impl AsRef<str>) {
|
pub fn declare(&mut self, cfg: impl AsRef<str>) {
|
||||||
if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared {
|
if self.declared.insert(cfg.as_ref().to_owned()) {
|
||||||
println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
|
println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,21 +65,6 @@ impl CfgSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_rustc_nightly() -> bool {
|
|
||||||
if env::var_os("EMBASSY_FORCE_CHECK_CFG").is_some() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
|
|
||||||
|
|
||||||
let output = Command::new(rustc)
|
|
||||||
.arg("--version")
|
|
||||||
.output()
|
|
||||||
.expect("failed to run `rustc --version`");
|
|
||||||
|
|
||||||
String::from_utf8_lossy(&output.stdout).contains("nightly")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets configs that describe the target platform.
|
/// Sets configs that describe the target platform.
|
||||||
pub fn set_target_cfgs(cfgs: &mut CfgSet) {
|
pub fn set_target_cfgs(cfgs: &mut CfgSet) {
|
||||||
let target = env::var("TARGET").unwrap();
|
let target = env::var("TARGET").unwrap();
|
||||||
|
|||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
#![cfg_attr(not(any(feature = "arch-std", feature = "arch-wasm")), no_std)]
|
#![cfg_attr(not(any(feature = "arch-std", feature = "arch-wasm")), no_std)]
|
||||||
#![cfg_attr(feature = "nightly", feature(waker_getters))]
|
|
||||||
#![allow(clippy::new_without_default)]
|
#![allow(clippy::new_without_default)]
|
||||||
#![doc = include_str!("../README.md")]
|
#![doc = include_str!("../README.md")]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|||||||
@ -50,8 +50,7 @@ pub fn task_from_waker(waker: &Waker) -> TaskRef {
|
|||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
{
|
{
|
||||||
let raw_waker = waker.as_raw();
|
(waker.vtable(), waker.data())
|
||||||
(raw_waker.vtable(), raw_waker.data())
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -237,7 +237,7 @@ impl<Fut: Future, const N: usize> Future for SelectArray<Fut, N> {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
pub struct SelectSlice<'a, Fut> {
|
pub struct SelectSlice<'a, Fut> {
|
||||||
inner: &'a mut [Fut],
|
inner: Pin<&'a mut [Fut]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new future which will select over a slice of futures.
|
/// Creates a new future which will select over a slice of futures.
|
||||||
@ -247,31 +247,26 @@ pub struct SelectSlice<'a, Fut> {
|
|||||||
/// future that was ready.
|
/// future that was ready.
|
||||||
///
|
///
|
||||||
/// If the slice is empty, the resulting future will be Pending forever.
|
/// If the slice is empty, the resulting future will be Pending forever.
|
||||||
pub fn select_slice<'a, Fut: Future>(slice: &'a mut [Fut]) -> SelectSlice<'a, Fut> {
|
pub fn select_slice<'a, Fut: Future>(slice: Pin<&'a mut [Fut]>) -> SelectSlice<'a, Fut> {
|
||||||
SelectSlice { inner: slice }
|
SelectSlice { inner: slice }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Fut: Future> Future for SelectSlice<'a, Fut> {
|
impl<'a, Fut: Future> Future for SelectSlice<'a, Fut> {
|
||||||
type Output = (Fut::Output, usize);
|
type Output = (Fut::Output, usize);
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
// Safety: Since `self` is pinned, `inner` cannot move. Since `inner` cannot move,
|
// Safety: refer to
|
||||||
// its elements also cannot move. Therefore it is safe to access `inner` and pin
|
// https://users.rust-lang.org/t/working-with-pinned-slices-are-there-any-structurally-pinning-vec-like-collection-types/50634/2
|
||||||
// references to the contained futures.
|
#[inline(always)]
|
||||||
let item = unsafe {
|
fn pin_iter<T>(slice: Pin<&mut [T]>) -> impl Iterator<Item = Pin<&mut T>> {
|
||||||
self.get_unchecked_mut()
|
unsafe { slice.get_unchecked_mut().iter_mut().map(|v| Pin::new_unchecked(v)) }
|
||||||
.inner
|
|
||||||
.iter_mut()
|
|
||||||
.enumerate()
|
|
||||||
.find_map(|(i, f)| match Pin::new_unchecked(f).poll(cx) {
|
|
||||||
Poll::Pending => None,
|
|
||||||
Poll::Ready(e) => Some((i, e)),
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
match item {
|
|
||||||
Some((idx, res)) => Poll::Ready((res, idx)),
|
|
||||||
None => Poll::Pending,
|
|
||||||
}
|
}
|
||||||
|
for (i, fut) in pin_iter(self.inner.as_mut()).enumerate() {
|
||||||
|
if let Poll::Ready(res) = fut.poll(cx) {
|
||||||
|
return Poll::Ready((res, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Poll::Pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "embassy-hal-internal"
|
name = "embassy-hal-internal"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Internal implementation details for Embassy HALs. DO NOT USE DIRECTLY."
|
description = "Internal implementation details for Embassy HALs. DO NOT USE DIRECTLY."
|
||||||
|
|||||||
@ -8,8 +8,6 @@
|
|||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::OsString;
|
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
|
/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
|
||||||
/// them (`cargo:rust-check-cfg=cfg(X)`).
|
/// them (`cargo:rust-check-cfg=cfg(X)`).
|
||||||
@ -17,7 +15,6 @@ use std::process::Command;
|
|||||||
pub struct CfgSet {
|
pub struct CfgSet {
|
||||||
enabled: HashSet<String>,
|
enabled: HashSet<String>,
|
||||||
declared: HashSet<String>,
|
declared: HashSet<String>,
|
||||||
emit_declared: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CfgSet {
|
impl CfgSet {
|
||||||
@ -25,7 +22,6 @@ impl CfgSet {
|
|||||||
Self {
|
Self {
|
||||||
enabled: HashSet::new(),
|
enabled: HashSet::new(),
|
||||||
declared: HashSet::new(),
|
declared: HashSet::new(),
|
||||||
emit_declared: is_rustc_nightly(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +45,7 @@ impl CfgSet {
|
|||||||
///
|
///
|
||||||
/// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
|
/// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
|
||||||
pub fn declare(&mut self, cfg: impl AsRef<str>) {
|
pub fn declare(&mut self, cfg: impl AsRef<str>) {
|
||||||
if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared {
|
if self.declared.insert(cfg.as_ref().to_owned()) {
|
||||||
println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
|
println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,21 +65,6 @@ impl CfgSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_rustc_nightly() -> bool {
|
|
||||||
if env::var_os("EMBASSY_FORCE_CHECK_CFG").is_some() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
|
|
||||||
|
|
||||||
let output = Command::new(rustc)
|
|
||||||
.arg("--version")
|
|
||||||
.output()
|
|
||||||
.expect("failed to run `rustc --version`");
|
|
||||||
|
|
||||||
String::from_utf8_lossy(&output.stdout).contains("nightly")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets configs that describe the target platform.
|
/// Sets configs that describe the target platform.
|
||||||
pub fn set_target_cfgs(cfgs: &mut CfgSet) {
|
pub fn set_target_cfgs(cfgs: &mut CfgSet) {
|
||||||
let target = env::var("TARGET").unwrap();
|
let target = env::var("TARGET").unwrap();
|
||||||
|
|||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,8 +16,8 @@ log = { version = "0.4", default-features = false, optional = true }
|
|||||||
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
|
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
|
||||||
embedded-hal-async = { version = "1.0" }
|
embedded-hal-async = { version = "1.0" }
|
||||||
embedded-hal-bus = { version = "0.1", features = ["async"] }
|
embedded-hal-bus = { version = "0.1", features = ["async"] }
|
||||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
|
embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" }
|
||||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
embassy-time = { version = "0.3.2", path = "../embassy-time" }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
bitfield = "0.14.0"
|
bitfield = "0.14.0"
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ APL can be used in [`intrinsic safety applications/explosion hazardous areas`](h
|
|||||||
|
|
||||||
## Supported SPI modes
|
## Supported SPI modes
|
||||||
|
|
||||||
`ADIN1110` supports two SPI modes. `Generic` and [`OPEN Alliance 10BASE-T1x MAC-PHY serial interface`](https://opensig.org/download/document/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf)
|
`ADIN1110` supports two SPI modes. `Generic` and [`OPEN Alliance 10BASE-T1x MAC-PHY serial interface`](https://opensig.org/wp-content/uploads/2023/12/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf)
|
||||||
|
|
||||||
Both modes support with and without additional CRC.
|
Both modes support with and without additional CRC.
|
||||||
Currently only `Generic` SPI with or without CRC is supported.
|
Currently only `Generic` SPI with or without CRC is supported.
|
||||||
|
|||||||
@ -16,7 +16,7 @@ const CRC8X_TABLE: [u8; 256] = [
|
|||||||
0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3,
|
0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3,
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Calculate the crc of a pease of data.
|
/// Calculate the crc of a piece of data.
|
||||||
pub fn crc8(data: &[u8]) -> u8 {
|
pub fn crc8(data: &[u8]) -> u8 {
|
||||||
data.iter().fold(0, |crc, &byte| CRC8X_TABLE[usize::from(byte ^ crc)])
|
data.iter().fold(0, |crc, &byte| CRC8X_TABLE[usize::from(byte ^ crc)])
|
||||||
}
|
}
|
||||||
|
|||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,13 @@ 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/),
|
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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
## 0.3.0 - 2024-08-05
|
||||||
|
|
||||||
|
- Add collapse_debuginfo to fmt.rs macros.
|
||||||
|
- Update embassy-sync version
|
||||||
|
|
||||||
## 0.2.0 - 2023-10-18
|
## 0.2.0 - 2023-10-18
|
||||||
|
|
||||||
- Update `embassy-net-driver` to v0.2
|
- Update `embassy-net-driver` to v0.2
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "embassy-net-driver-channel"
|
name = "embassy-net-driver-channel"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack."
|
description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack."
|
||||||
|
|||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ documentation = "https://docs.embassy.dev/embassy-net-enc28j60"
|
|||||||
embedded-hal = { version = "1.0" }
|
embedded-hal = { version = "1.0" }
|
||||||
embedded-hal-async = { version = "1.0" }
|
embedded-hal-async = { version = "1.0" }
|
||||||
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
embassy-time = { version = "0.3.2", path = "../embassy-time" }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
|
|||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,10 +17,10 @@ log = [ "dep:log" ]
|
|||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
|
|
||||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
embassy-time = { version = "0.3.2", path = "../embassy-time" }
|
||||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync"}
|
embassy-sync = { version = "0.6.0", path = "../embassy-sync"}
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
||||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"}
|
embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"}
|
||||||
|
|
||||||
embedded-hal = { version = "1.0" }
|
embedded-hal = { version = "1.0" }
|
||||||
embedded-hal-async = { version = "1.0" }
|
embedded-hal-async = { version = "1.0" }
|
||||||
|
|||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
use heapless::{String, Vec};
|
use heapless::{String, Vec};
|
||||||
|
|
||||||
/// internal supporting structures for CtrlMsg
|
/// internal supporting structures for CtrlMsg
|
||||||
|
|||||||
38
embassy-net-nrf91/Cargo.toml
Normal file
38
embassy-net-nrf91/Cargo.toml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
[package]
|
||||||
|
name = "embassy-net-nrf91"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
description = "embassy-net driver for Nordic nRF91-series cellular modems"
|
||||||
|
keywords = ["embedded", "nrf91", "embassy-net", "cellular"]
|
||||||
|
categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
repository = "https://github.com/embassy-rs/embassy"
|
||||||
|
documentation = "https://docs.embassy.dev/embassy-net-nrf91"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
defmt = [ "dep:defmt", "heapless/defmt-03" ]
|
||||||
|
log = [ "dep:log" ]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
defmt = { version = "0.3", optional = true }
|
||||||
|
log = { version = "0.4.14", optional = true }
|
||||||
|
|
||||||
|
nrf9160-pac = { version = "0.12.0" }
|
||||||
|
|
||||||
|
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
||||||
|
embassy-sync = { version = "0.6.0", path = "../embassy-sync"}
|
||||||
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
||||||
|
embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"}
|
||||||
|
|
||||||
|
heapless = "0.8"
|
||||||
|
embedded-io = "0.6.1"
|
||||||
|
at-commands = "0.5.4"
|
||||||
|
|
||||||
|
[package.metadata.embassy_docs]
|
||||||
|
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-nrf91-v$VERSION/embassy-net-nrf91/src/"
|
||||||
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-nrf91/src/"
|
||||||
|
target = "thumbv7em-none-eabi"
|
||||||
|
features = ["defmt"]
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
features = ["defmt"]
|
||||||
9
embassy-net-nrf91/README.md
Normal file
9
embassy-net-nrf91/README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# nRF91 `embassy-net` integration
|
||||||
|
|
||||||
|
[`embassy-net`](https://crates.io/crates/embassy-net) driver for Nordic nRF91-series cellular modems.
|
||||||
|
|
||||||
|
See the [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/nrf9160) directory for usage examples with the nRF9160.
|
||||||
|
|
||||||
|
## Interoperability
|
||||||
|
|
||||||
|
This crate can run on any executor.
|
||||||
350
embassy-net-nrf91/src/context.rs
Normal file
350
embassy-net-nrf91/src/context.rs
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
//! Helper utility to configure a specific modem context.
|
||||||
|
use core::net::IpAddr;
|
||||||
|
use core::str::FromStr;
|
||||||
|
|
||||||
|
use at_commands::builder::CommandBuilder;
|
||||||
|
use at_commands::parser::CommandParser;
|
||||||
|
use embassy_time::{Duration, Timer};
|
||||||
|
use heapless::Vec;
|
||||||
|
|
||||||
|
/// Provides a higher level API for controlling a given context.
|
||||||
|
pub struct Control<'a> {
|
||||||
|
control: crate::Control<'a>,
|
||||||
|
cid: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration for a given context
|
||||||
|
pub struct Config<'a> {
|
||||||
|
/// Desired APN address.
|
||||||
|
pub apn: &'a [u8],
|
||||||
|
/// Desired authentication protocol.
|
||||||
|
pub auth_prot: AuthProt,
|
||||||
|
/// Credentials.
|
||||||
|
pub auth: Option<(&'a [u8], &'a [u8])>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Authentication protocol.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum AuthProt {
|
||||||
|
/// No authentication.
|
||||||
|
None = 0,
|
||||||
|
/// PAP authentication.
|
||||||
|
Pap = 1,
|
||||||
|
/// CHAP authentication.
|
||||||
|
Chap = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Error returned by control.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum Error {
|
||||||
|
/// Not enough space for command.
|
||||||
|
BufferTooSmall,
|
||||||
|
/// Error parsing response from modem.
|
||||||
|
AtParseError,
|
||||||
|
/// Error parsing IP addresses.
|
||||||
|
AddrParseError,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<at_commands::parser::ParseError> for Error {
|
||||||
|
fn from(_: at_commands::parser::ParseError) -> Self {
|
||||||
|
Self::AtParseError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Status of a given context.
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
pub struct Status {
|
||||||
|
/// Attached to APN or not.
|
||||||
|
pub attached: bool,
|
||||||
|
/// IP if assigned.
|
||||||
|
pub ip: Option<IpAddr>,
|
||||||
|
/// Gateway if assigned.
|
||||||
|
pub gateway: Option<IpAddr>,
|
||||||
|
/// DNS servers if assigned.
|
||||||
|
pub dns: Vec<IpAddr, 2>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
impl defmt::Format for Status {
|
||||||
|
fn format(&self, f: defmt::Formatter<'_>) {
|
||||||
|
defmt::write!(f, "attached: {}", self.attached);
|
||||||
|
if let Some(ip) = &self.ip {
|
||||||
|
defmt::write!(f, ", ip: {}", defmt::Debug2Format(&ip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Control<'a> {
|
||||||
|
/// Create a new instance of a control handle for a given context.
|
||||||
|
///
|
||||||
|
/// Will wait for the modem to be initialized if not.
|
||||||
|
pub async fn new(control: crate::Control<'a>, cid: u8) -> Self {
|
||||||
|
control.wait_init().await;
|
||||||
|
Self { control, cid }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform a raw AT command
|
||||||
|
pub async fn at_command(&self, req: &[u8], resp: &mut [u8]) -> usize {
|
||||||
|
self.control.at_command(req, resp).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configures the modem with the provided config.
|
||||||
|
///
|
||||||
|
/// NOTE: This will disconnect the modem from any current APN and should not
|
||||||
|
/// be called if the configuration has not been changed.
|
||||||
|
///
|
||||||
|
/// After configuring, invoke [`enable()`] to activate the configuration.
|
||||||
|
pub async fn configure(&self, config: &Config<'_>) -> Result<(), Error> {
|
||||||
|
let mut cmd: [u8; 256] = [0; 256];
|
||||||
|
let mut buf: [u8; 256] = [0; 256];
|
||||||
|
|
||||||
|
let op = CommandBuilder::create_set(&mut cmd, true)
|
||||||
|
.named("+CFUN")
|
||||||
|
.with_int_parameter(0)
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
|
||||||
|
|
||||||
|
let op = CommandBuilder::create_set(&mut cmd, true)
|
||||||
|
.named("+CGDCONT")
|
||||||
|
.with_int_parameter(self.cid)
|
||||||
|
.with_string_parameter("IP")
|
||||||
|
.with_string_parameter(config.apn)
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
// info!("RES1: {}", unsafe { core::str::from_utf8_unchecked(&buf[..n]) });
|
||||||
|
CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
|
||||||
|
|
||||||
|
let mut op = CommandBuilder::create_set(&mut cmd, true)
|
||||||
|
.named("+CGAUTH")
|
||||||
|
.with_int_parameter(self.cid)
|
||||||
|
.with_int_parameter(config.auth_prot as u8);
|
||||||
|
if let Some((username, password)) = config.auth {
|
||||||
|
op = op.with_string_parameter(username).with_string_parameter(password);
|
||||||
|
}
|
||||||
|
let op = op.finish().map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
// info!("RES2: {}", unsafe { core::str::from_utf8_unchecked(&buf[..n]) });
|
||||||
|
CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attach to the PDN
|
||||||
|
pub async fn attach(&self) -> Result<(), Error> {
|
||||||
|
let mut cmd: [u8; 256] = [0; 256];
|
||||||
|
let mut buf: [u8; 256] = [0; 256];
|
||||||
|
let op = CommandBuilder::create_set(&mut cmd, true)
|
||||||
|
.named("+CGATT")
|
||||||
|
.with_int_parameter(1)
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read current connectivity status for modem.
|
||||||
|
pub async fn detach(&self) -> Result<(), Error> {
|
||||||
|
let mut cmd: [u8; 256] = [0; 256];
|
||||||
|
let mut buf: [u8; 256] = [0; 256];
|
||||||
|
let op = CommandBuilder::create_set(&mut cmd, true)
|
||||||
|
.named("+CGATT")
|
||||||
|
.with_int_parameter(0)
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn attached(&self) -> Result<bool, Error> {
|
||||||
|
let mut cmd: [u8; 256] = [0; 256];
|
||||||
|
let mut buf: [u8; 256] = [0; 256];
|
||||||
|
|
||||||
|
let op = CommandBuilder::create_query(&mut cmd, true)
|
||||||
|
.named("+CGATT")
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
let (res,) = CommandParser::parse(&buf[..n])
|
||||||
|
.expect_identifier(b"+CGATT: ")
|
||||||
|
.expect_int_parameter()
|
||||||
|
.expect_identifier(b"\r\nOK")
|
||||||
|
.finish()?;
|
||||||
|
Ok(res == 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read current connectivity status for modem.
|
||||||
|
pub async fn status(&self) -> Result<Status, Error> {
|
||||||
|
let mut cmd: [u8; 256] = [0; 256];
|
||||||
|
let mut buf: [u8; 256] = [0; 256];
|
||||||
|
|
||||||
|
let op = CommandBuilder::create_query(&mut cmd, true)
|
||||||
|
.named("+CGATT")
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
let (res,) = CommandParser::parse(&buf[..n])
|
||||||
|
.expect_identifier(b"+CGATT: ")
|
||||||
|
.expect_int_parameter()
|
||||||
|
.expect_identifier(b"\r\nOK")
|
||||||
|
.finish()?;
|
||||||
|
let attached = res == 1;
|
||||||
|
if !attached {
|
||||||
|
return Ok(Status {
|
||||||
|
attached,
|
||||||
|
ip: None,
|
||||||
|
gateway: None,
|
||||||
|
dns: Vec::new(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let op = CommandBuilder::create_set(&mut cmd, true)
|
||||||
|
.named("+CGPADDR")
|
||||||
|
.with_int_parameter(self.cid)
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
let (_, ip1, _ip2) = CommandParser::parse(&buf[..n])
|
||||||
|
.expect_identifier(b"+CGPADDR: ")
|
||||||
|
.expect_int_parameter()
|
||||||
|
.expect_optional_string_parameter()
|
||||||
|
.expect_optional_string_parameter()
|
||||||
|
.expect_identifier(b"\r\nOK")
|
||||||
|
.finish()?;
|
||||||
|
|
||||||
|
let ip = if let Some(ip) = ip1 {
|
||||||
|
let ip = IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?;
|
||||||
|
Some(ip)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let op = CommandBuilder::create_set(&mut cmd, true)
|
||||||
|
.named("+CGCONTRDP")
|
||||||
|
.with_int_parameter(self.cid)
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
let (_cid, _bid, _apn, _mask, gateway, dns1, dns2, _, _, _, _, _mtu) = CommandParser::parse(&buf[..n])
|
||||||
|
.expect_identifier(b"+CGCONTRDP: ")
|
||||||
|
.expect_int_parameter()
|
||||||
|
.expect_optional_int_parameter()
|
||||||
|
.expect_optional_string_parameter()
|
||||||
|
.expect_optional_string_parameter()
|
||||||
|
.expect_optional_string_parameter()
|
||||||
|
.expect_optional_string_parameter()
|
||||||
|
.expect_optional_string_parameter()
|
||||||
|
.expect_optional_int_parameter()
|
||||||
|
.expect_optional_int_parameter()
|
||||||
|
.expect_optional_int_parameter()
|
||||||
|
.expect_optional_int_parameter()
|
||||||
|
.expect_optional_int_parameter()
|
||||||
|
.expect_identifier(b"\r\nOK")
|
||||||
|
.finish()?;
|
||||||
|
|
||||||
|
let gateway = if let Some(ip) = gateway {
|
||||||
|
if ip.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut dns = Vec::new();
|
||||||
|
if let Some(ip) = dns1 {
|
||||||
|
dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ip) = dns2 {
|
||||||
|
dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Status {
|
||||||
|
attached,
|
||||||
|
ip,
|
||||||
|
gateway,
|
||||||
|
dns,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wait_attached(&self) -> Result<Status, Error> {
|
||||||
|
while !self.attached().await? {
|
||||||
|
Timer::after(Duration::from_secs(1)).await;
|
||||||
|
}
|
||||||
|
let status = self.status().await?;
|
||||||
|
Ok(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disable modem
|
||||||
|
pub async fn disable(&self) -> Result<(), Error> {
|
||||||
|
let mut cmd: [u8; 256] = [0; 256];
|
||||||
|
let mut buf: [u8; 256] = [0; 256];
|
||||||
|
|
||||||
|
let op = CommandBuilder::create_set(&mut cmd, true)
|
||||||
|
.named("+CFUN")
|
||||||
|
.with_int_parameter(0)
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable modem
|
||||||
|
pub async fn enable(&self) -> Result<(), Error> {
|
||||||
|
let mut cmd: [u8; 256] = [0; 256];
|
||||||
|
let mut buf: [u8; 256] = [0; 256];
|
||||||
|
|
||||||
|
let op = CommandBuilder::create_set(&mut cmd, true)
|
||||||
|
.named("+CFUN")
|
||||||
|
.with_int_parameter(1)
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
|
||||||
|
|
||||||
|
// Make modem survive PDN detaches
|
||||||
|
let op = CommandBuilder::create_set(&mut cmd, true)
|
||||||
|
.named("%XPDNCFG")
|
||||||
|
.with_int_parameter(1)
|
||||||
|
.finish()
|
||||||
|
.map_err(|_| Error::BufferTooSmall)?;
|
||||||
|
let n = self.control.at_command(op, &mut buf).await;
|
||||||
|
CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run a control loop for this context, ensuring that reaattach is handled.
|
||||||
|
pub async fn run<F: Fn(&Status)>(&self, reattach: F) -> Result<(), Error> {
|
||||||
|
self.enable().await?;
|
||||||
|
let status = self.wait_attached().await?;
|
||||||
|
let mut fd = self.control.open_raw_socket().await;
|
||||||
|
reattach(&status);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if !self.attached().await? {
|
||||||
|
trace!("detached");
|
||||||
|
|
||||||
|
self.control.close_raw_socket(fd).await;
|
||||||
|
let status = self.wait_attached().await?;
|
||||||
|
trace!("attached");
|
||||||
|
fd = self.control.open_raw_socket().await;
|
||||||
|
reattach(&status);
|
||||||
|
}
|
||||||
|
Timer::after(Duration::from_secs(10)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
274
embassy-net-nrf91/src/fmt.rs
Normal file
274
embassy-net-nrf91/src/fmt.rs
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
#![macro_use]
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
use core::fmt::{Debug, Display, LowerHex};
|
||||||
|
|
||||||
|
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||||
|
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||||
|
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! assert {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::assert!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::assert!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! assert_eq {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::assert_eq!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::assert_eq!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! assert_ne {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::assert_ne!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::assert_ne!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! debug_assert {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::debug_assert!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::debug_assert!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! debug_assert_eq {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::debug_assert_eq!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::debug_assert_eq!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! debug_assert_ne {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::debug_assert_ne!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::debug_assert_ne!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! todo {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::todo!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::todo!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::core::unreachable!($($x)*)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unreachable!($($x)*)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! panic {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
{
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
::core::panic!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::panic!($($x)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! trace {
|
||||||
|
($s:literal $(, $x:expr)* $(,)?) => {
|
||||||
|
{
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
::log::trace!($s $(, $x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::trace!($s $(, $x)*);
|
||||||
|
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||||
|
let _ = ($( & $x ),*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! debug {
|
||||||
|
($s:literal $(, $x:expr)* $(,)?) => {
|
||||||
|
{
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
::log::debug!($s $(, $x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::debug!($s $(, $x)*);
|
||||||
|
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||||
|
let _ = ($( & $x ),*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! info {
|
||||||
|
($s:literal $(, $x:expr)* $(,)?) => {
|
||||||
|
{
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
::log::info!($s $(, $x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::info!($s $(, $x)*);
|
||||||
|
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||||
|
let _ = ($( & $x ),*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! warn {
|
||||||
|
($s:literal $(, $x:expr)* $(,)?) => {
|
||||||
|
{
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
::log::warn!($s $(, $x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::warn!($s $(, $x)*);
|
||||||
|
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||||
|
let _ = ($( & $x ),*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! error {
|
||||||
|
($s:literal $(, $x:expr)* $(,)?) => {
|
||||||
|
{
|
||||||
|
#[cfg(feature = "log")]
|
||||||
|
::log::error!($s $(, $x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
::defmt::error!($s $(, $x)*);
|
||||||
|
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||||
|
let _ = ($( & $x ),*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! unwrap {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unwrap!($($x)*)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
|
#[collapse_debuginfo(yes)]
|
||||||
|
macro_rules! unwrap {
|
||||||
|
($arg:expr) => {
|
||||||
|
match $crate::fmt::Try::into_result($arg) {
|
||||||
|
::core::result::Result::Ok(t) => t,
|
||||||
|
::core::result::Result::Err(e) => {
|
||||||
|
::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($arg:expr, $($msg:expr),+ $(,)? ) => {
|
||||||
|
match $crate::fmt::Try::into_result($arg) {
|
||||||
|
::core::result::Result::Ok(t) => t,
|
||||||
|
::core::result::Result::Err(e) => {
|
||||||
|
::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub struct NoneError;
|
||||||
|
|
||||||
|
pub trait Try {
|
||||||
|
type Ok;
|
||||||
|
type Error;
|
||||||
|
fn into_result(self) -> Result<Self::Ok, Self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Try for Option<T> {
|
||||||
|
type Ok = T;
|
||||||
|
type Error = NoneError;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_result(self) -> Result<T, NoneError> {
|
||||||
|
self.ok_or(NoneError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E> Try for Result<T, E> {
|
||||||
|
type Ok = T;
|
||||||
|
type Error = E;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_result(self) -> Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct Bytes<'a>(pub &'a [u8]);
|
||||||
|
|
||||||
|
impl<'a> Debug for Bytes<'a> {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
write!(f, "{:#02x?}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Display for Bytes<'a> {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
write!(f, "{:#02x?}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LowerHex for Bytes<'a> {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
write!(f, "{:#02x?}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
|
impl<'a> defmt::Format for Bytes<'a> {
|
||||||
|
fn format(&self, fmt: defmt::Formatter) {
|
||||||
|
defmt::write!(fmt, "{:02x}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
1046
embassy-net-nrf91/src/lib.rs
Normal file
1046
embassy-net-nrf91/src/lib.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -18,7 +18,7 @@ defmt = { version = "0.3", optional = true }
|
|||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
|
|
||||||
embedded-io-async = { version = "0.6.1" }
|
embedded-io-async = { version = "0.6.1" }
|
||||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
|
embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
ppproto = { version = "0.1.2"}
|
ppproto = { version = "0.1.2"}
|
||||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||||
|
|||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,8 +12,8 @@ documentation = "https://docs.embassy.dev/embassy-net-wiznet"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
embedded-hal = { version = "1.0" }
|
embedded-hal = { version = "1.0" }
|
||||||
embedded-hal-async = { version = "1.0" }
|
embedded-hal-async = { version = "1.0" }
|
||||||
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
|
embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" }
|
||||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
embassy-time = { version = "0.3.2", path = "../embassy-time" }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
|
|
||||||
|
|||||||
@ -44,6 +44,8 @@ raw = ["smoltcp/socket-raw"]
|
|||||||
tcp = ["smoltcp/socket-tcp"]
|
tcp = ["smoltcp/socket-tcp"]
|
||||||
## Enable DNS support
|
## Enable DNS support
|
||||||
dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"]
|
dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"]
|
||||||
|
## Enable mDNS support
|
||||||
|
mdns = ["dns", "smoltcp/socket-mdns"]
|
||||||
## Enable DHCPv4 support
|
## Enable DHCPv4 support
|
||||||
dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"]
|
dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"]
|
||||||
## Enable DHCPv4 support with hostname
|
## Enable DHCPv4 support with hostname
|
||||||
@ -72,7 +74,7 @@ smoltcp = { version = "0.11.0", default-features = false, features = [
|
|||||||
] }
|
] }
|
||||||
|
|
||||||
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
embassy-time = { version = "0.3.2", path = "../embassy-time" }
|
||||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||||
embedded-io-async = { version = "0.6.1" }
|
embedded-io-async = { version = "0.6.1" }
|
||||||
|
|
||||||
|
|||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,6 +34,8 @@ use embassy_sync::waitqueue::WakerRegistration;
|
|||||||
use embassy_time::{Instant, Timer};
|
use embassy_time::{Instant, Timer};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
|
#[cfg(feature = "dns")]
|
||||||
|
pub use smoltcp::config::DNS_MAX_SERVER_COUNT;
|
||||||
#[cfg(feature = "igmp")]
|
#[cfg(feature = "igmp")]
|
||||||
pub use smoltcp::iface::MulticastError;
|
pub use smoltcp::iface::MulticastError;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
@ -413,8 +415,11 @@ impl<D: Driver> Stack<D> {
|
|||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// let config = embassy_net::Config::dhcpv4(Default::default());
|
/// let config = embassy_net::Config::dhcpv4(Default::default());
|
||||||
///// Init network stack
|
/// // Init network stack
|
||||||
/// static RESOURCES: StaticCell<embassy_net::StackResources<2> = StaticCell::new();
|
/// // NOTE: DHCP and DNS need one socket slot if enabled. This is why we're
|
||||||
|
/// // provisioning space for 3 sockets here: one for DHCP, one for DNS, and one for your code (e.g. TCP).
|
||||||
|
/// // If you use more sockets you must increase this. If you don't enable DHCP or DNS you can decrease it.
|
||||||
|
/// static RESOURCES: StaticCell<embassy_net::StackResources<3>> = StaticCell::new();
|
||||||
/// static STACK: StaticCell<embassy_net::Stack> = StaticCell::new();
|
/// static STACK: StaticCell<embassy_net::Stack> = StaticCell::new();
|
||||||
/// let stack = &*STACK.init(embassy_net::Stack::new(
|
/// let stack = &*STACK.init(embassy_net::Stack::new(
|
||||||
/// device,
|
/// device,
|
||||||
@ -823,9 +828,17 @@ impl<D: Driver> Inner<D> {
|
|||||||
|
|
||||||
// Apply DNS servers
|
// Apply DNS servers
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
s.sockets
|
if !dns_servers.is_empty() {
|
||||||
.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket)
|
let count = if dns_servers.len() > DNS_MAX_SERVER_COUNT {
|
||||||
.update_servers(&dns_servers[..]);
|
warn!("Number of DNS servers exceeds DNS_MAX_SERVER_COUNT, truncating list.");
|
||||||
|
DNS_MAX_SERVER_COUNT
|
||||||
|
} else {
|
||||||
|
dns_servers.len()
|
||||||
|
};
|
||||||
|
s.sockets
|
||||||
|
.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket)
|
||||||
|
.update_servers(&dns_servers[..count]);
|
||||||
|
}
|
||||||
|
|
||||||
self.config_waker.wake();
|
self.config_waker.wake();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,6 +79,15 @@ impl<'a> TcpReader<'a> {
|
|||||||
///
|
///
|
||||||
/// Returns how many bytes were read, or an error. If no data is available, it waits
|
/// Returns how many bytes were read, or an error. If no data is available, it waits
|
||||||
/// until there is at least one byte available.
|
/// until there is at least one byte available.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
/// A return value of Ok(0) means that we have read all data and the remote
|
||||||
|
/// side has closed our receive half of the socket. The remote can no longer
|
||||||
|
/// send bytes.
|
||||||
|
///
|
||||||
|
/// The send half of the socket is still open. If you want to reconnect using
|
||||||
|
/// the socket you split this reader off the send half needs to be closed using
|
||||||
|
/// [`abort()`](TcpSocket::abort).
|
||||||
pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
self.io.read(buf).await
|
self.io.read(buf).await
|
||||||
}
|
}
|
||||||
@ -273,6 +282,9 @@ impl<'a> TcpSocket<'a> {
|
|||||||
///
|
///
|
||||||
/// Returns how many bytes were read, or an error. If no data is available, it waits
|
/// Returns how many bytes were read, or an error. If no data is available, it waits
|
||||||
/// until there is at least one byte available.
|
/// until there is at least one byte available.
|
||||||
|
///
|
||||||
|
/// A return value of Ok(0) means that the socket was closed and is longer
|
||||||
|
/// able to receive any data.
|
||||||
pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
self.io.read(buf).await
|
self.io.read(buf).await
|
||||||
}
|
}
|
||||||
@ -297,6 +309,10 @@ impl<'a> TcpSocket<'a> {
|
|||||||
///
|
///
|
||||||
/// If the timeout is set, the socket will be closed if no data is received for the
|
/// If the timeout is set, the socket will be closed if no data is received for the
|
||||||
/// specified duration.
|
/// specified duration.
|
||||||
|
///
|
||||||
|
/// # Note:
|
||||||
|
/// Set a keep alive interval ([`set_keep_alive`] to prevent timeouts when
|
||||||
|
/// the remote could still respond.
|
||||||
pub fn set_timeout(&mut self, duration: Option<Duration>) {
|
pub fn set_timeout(&mut self, duration: Option<Duration>) {
|
||||||
self.io
|
self.io
|
||||||
.with_mut(|s, _| s.set_timeout(duration.map(duration_to_smoltcp)))
|
.with_mut(|s, _| s.set_timeout(duration.map(duration_to_smoltcp)))
|
||||||
@ -308,6 +324,9 @@ impl<'a> TcpSocket<'a> {
|
|||||||
/// the specified duration of inactivity.
|
/// the specified duration of inactivity.
|
||||||
///
|
///
|
||||||
/// If not set, the socket will not send keep-alive packets.
|
/// If not set, the socket will not send keep-alive packets.
|
||||||
|
///
|
||||||
|
/// By setting a [`timeout`](Self::timeout) larger then the keep alive you
|
||||||
|
/// can detect a remote endpoint that no longer answers.
|
||||||
pub fn set_keep_alive(&mut self, interval: Option<Duration>) {
|
pub fn set_keep_alive(&mut self, interval: Option<Duration>) {
|
||||||
self.io
|
self.io
|
||||||
.with_mut(|s, _| s.set_keep_alive(interval.map(duration_to_smoltcp)))
|
.with_mut(|s, _| s.set_keep_alive(interval.map(duration_to_smoltcp)))
|
||||||
@ -515,7 +534,7 @@ impl<'d> TcpIo<'d> {
|
|||||||
async fn flush(&mut self) -> Result<(), Error> {
|
async fn flush(&mut self) -> Result<(), Error> {
|
||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
self.with_mut(|s, _| {
|
self.with_mut(|s, _| {
|
||||||
let data_pending = s.send_queue() > 0;
|
let data_pending = (s.send_queue() > 0) && s.state() != tcp::State::Closed;
|
||||||
let fin_pending = matches!(
|
let fin_pending = matches!(
|
||||||
s.state(),
|
s.state(),
|
||||||
tcp::State::FinWait1 | tcp::State::Closing | tcp::State::LastAck
|
tcp::State::FinWait1 | tcp::State::Closing | tcp::State::LastAck
|
||||||
@ -660,12 +679,25 @@ pub mod client {
|
|||||||
pub struct TcpClient<'d, D: Driver, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> {
|
pub struct TcpClient<'d, D: Driver, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> {
|
||||||
stack: &'d Stack<D>,
|
stack: &'d Stack<D>,
|
||||||
state: &'d TcpClientState<N, TX_SZ, RX_SZ>,
|
state: &'d TcpClientState<N, TX_SZ, RX_SZ>,
|
||||||
|
socket_timeout: Option<Duration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, D, N, TX_SZ, RX_SZ> {
|
impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, D, N, TX_SZ, RX_SZ> {
|
||||||
/// Create a new `TcpClient`.
|
/// Create a new `TcpClient`.
|
||||||
pub fn new(stack: &'d Stack<D>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Self {
|
pub fn new(stack: &'d Stack<D>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Self {
|
||||||
Self { stack, state }
|
Self {
|
||||||
|
stack,
|
||||||
|
state,
|
||||||
|
socket_timeout: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the timeout for each socket created by this `TcpClient`.
|
||||||
|
///
|
||||||
|
/// If the timeout is set, the socket will be closed if no data is received for the
|
||||||
|
/// specified duration.
|
||||||
|
pub fn set_timeout(&mut self, timeout: Option<Duration>) {
|
||||||
|
self.socket_timeout = timeout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -691,6 +723,7 @@ pub mod client {
|
|||||||
};
|
};
|
||||||
let remote_endpoint = (addr, remote.port());
|
let remote_endpoint = (addr, remote.port());
|
||||||
let mut socket = TcpConnection::new(&self.stack, self.state)?;
|
let mut socket = TcpConnection::new(&self.stack, self.state)?;
|
||||||
|
socket.socket.set_timeout(self.socket_timeout.clone());
|
||||||
socket
|
socket
|
||||||
.socket
|
.socket
|
||||||
.connect(remote_endpoint)
|
.connect(remote_endpoint)
|
||||||
|
|||||||
@ -138,6 +138,35 @@ impl<'a> UdpSocket<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Receive a datagram with a zero-copy function.
|
||||||
|
///
|
||||||
|
/// 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 call the provided function
|
||||||
|
/// with the number of bytes received and the remote endpoint and return
|
||||||
|
/// `Poll::Ready` with the function's returned value.
|
||||||
|
pub async fn recv_from_with<F, R>(&mut self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&[u8], UdpMetadata) -> R,
|
||||||
|
{
|
||||||
|
let mut f = Some(f);
|
||||||
|
poll_fn(move |cx| {
|
||||||
|
self.with_mut(|s, _| {
|
||||||
|
match s.recv() {
|
||||||
|
Ok((buffer, endpoint)) => Poll::Ready(unwrap!(f.take())(buffer, endpoint)),
|
||||||
|
Err(udp::RecvError::Truncated) => unreachable!(),
|
||||||
|
Err(udp::RecvError::Exhausted) => {
|
||||||
|
// socket buffer is empty wait until at least one byte has arrived
|
||||||
|
s.register_recv_waker(cx.waker());
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
/// Send a datagram to the specified remote endpoint.
|
/// Send a datagram to the specified remote endpoint.
|
||||||
///
|
///
|
||||||
/// This method will wait until the datagram has been sent.
|
/// This method will wait until the datagram has been sent.
|
||||||
@ -181,6 +210,40 @@ impl<'a> UdpSocket<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a datagram to the specified remote endpoint with a zero-copy function.
|
||||||
|
///
|
||||||
|
/// This method will wait until the buffer can fit the requested size before
|
||||||
|
/// calling the function to fill its contents.
|
||||||
|
///
|
||||||
|
/// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)`
|
||||||
|
pub async fn send_to_with<T, F, R>(&mut self, size: usize, remote_endpoint: T, f: F) -> Result<R, SendError>
|
||||||
|
where
|
||||||
|
T: Into<UdpMetadata> + Copy,
|
||||||
|
F: FnOnce(&mut [u8]) -> R,
|
||||||
|
{
|
||||||
|
let mut f = Some(f);
|
||||||
|
poll_fn(move |cx| {
|
||||||
|
self.with_mut(|s, _| {
|
||||||
|
match s.send(size, remote_endpoint) {
|
||||||
|
Ok(buffer) => Poll::Ready(Ok(unwrap!(f.take())(buffer))),
|
||||||
|
Err(udp::SendError::BufferFull) => {
|
||||||
|
s.register_send_waker(cx.waker());
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
Err(udp::SendError::Unaddressable) => {
|
||||||
|
// If no sender/outgoing port is specified, there is not really "no route"
|
||||||
|
if s.endpoint().port == 0 {
|
||||||
|
Poll::Ready(Err(SendError::SocketNotBound))
|
||||||
|
} else {
|
||||||
|
Poll::Ready(Err(SendError::NoRoute))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the local endpoint of the socket.
|
/// Returns the local endpoint of the socket.
|
||||||
pub fn endpoint(&self) -> IpListenEndpoint {
|
pub fn endpoint(&self) -> IpListenEndpoint {
|
||||||
self.with(|s, _| s.endpoint())
|
self.with(|s, _| s.endpoint())
|
||||||
|
|||||||
@ -7,24 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
- Drop `sealed` mod
|
## 0.2.0 - 2024-08-05
|
||||||
- nrf52840: Add dcdc voltage parameter to configure REG0 regulator
|
|
||||||
- radio: Add support for IEEE 802.15.4 and BLE via radio peripheral
|
- Support for NRF chips:
|
||||||
- spim: Reduce trace-level messages ("Copying SPIM tx buffer..")
|
- nrf51
|
||||||
- uart: Add support for rx- or tx-only BufferedUart
|
- nrf9151
|
||||||
- uart: Implement splitting Rx/Tx
|
- Support for new peripherals:
|
||||||
- spi: Allow specifying OutputDrive for SPI spins
|
- EGU
|
||||||
- pdm: Fix gain register value derivation
|
- radio - low-level support for IEEE 802.15.4 and BLE via radio peripheral
|
||||||
- spim: Implement chunked DMA transfers
|
- Peripheral changes:
|
||||||
- spi: Add bounds checks for EasyDMA buffer size
|
- gpio: Drop GPIO Pin generics (API break)
|
||||||
- uarte: Add support for handling RX errors
|
- pdm: Fix gain register value derivation
|
||||||
- nrf51: Implement support for nrf51 chip
|
- pwm:
|
||||||
- pwm: Expose `duty` method
|
- Expose `duty` method
|
||||||
- pwm: Fix infinite loop
|
- Expose `pwm::PWM_CLK_HZ` and add `is_enabled` method
|
||||||
- spi: Add support for configuring bit order for bus
|
- Allow specifying OutputDrive for PWM channels
|
||||||
- pwm: Expose `pwm::PWM_CLK_HZ` and add `is_enabled` method
|
- Fix infinite loop
|
||||||
- gpio: Drop GPIO Pin generics (API break)
|
- spim:
|
||||||
- pwm: Allow specifying OutputDrive for PWM channels
|
- Reduce trace-level messages ("Copying SPIM tx buffer..")
|
||||||
|
- Support configuring bit order for bus
|
||||||
|
- Allow specifying OutputDrive for SPI pins
|
||||||
|
- Add bounds checks for EasyDMA buffer size
|
||||||
|
- Implement chunked DMA transfers
|
||||||
|
- uart:
|
||||||
|
- Add support for rx- or tx-only BufferedUart
|
||||||
|
- Implement splitting Rx/Tx
|
||||||
|
- Add support for handling RX errors
|
||||||
|
- Miscellaneous changes:
|
||||||
|
- Add `collapse_debuginfo` to fmt.rs macros.
|
||||||
|
- Drop `sealed` mod
|
||||||
|
- nrf52840: Add dcdc voltage parameter to configure REG0 regulator
|
||||||
|
|
||||||
## 0.1.0 - 2024-01-12
|
## 0.1.0 - 2024-01-12
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "embassy-nrf"
|
name = "embassy-nrf"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers"
|
description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers"
|
||||||
@ -40,6 +40,7 @@ rt = [
|
|||||||
"nrf5340-app-pac?/rt",
|
"nrf5340-app-pac?/rt",
|
||||||
"nrf5340-net-pac?/rt",
|
"nrf5340-net-pac?/rt",
|
||||||
"nrf9160-pac?/rt",
|
"nrf9160-pac?/rt",
|
||||||
|
"nrf9120-pac?/rt",
|
||||||
]
|
]
|
||||||
|
|
||||||
## Enable features requiring `embassy-time`
|
## Enable features requiring `embassy-time`
|
||||||
@ -96,9 +97,18 @@ nrf5340-app-ns = ["_nrf5340-app", "_ns"]
|
|||||||
## nRF5340 network core
|
## nRF5340 network core
|
||||||
nrf5340-net = ["_nrf5340-net"]
|
nrf5340-net = ["_nrf5340-net"]
|
||||||
## nRF9160 in Secure mode
|
## nRF9160 in Secure mode
|
||||||
nrf9160-s = ["_nrf9160", "_s"]
|
nrf9160-s = ["_nrf9160", "_s", "_nrf91"]
|
||||||
## nRF9160 in Non-Secure mode
|
## nRF9160 in Non-Secure mode
|
||||||
nrf9160-ns = ["_nrf9160", "_ns"]
|
nrf9160-ns = ["_nrf9160", "_ns", "_nrf91"]
|
||||||
|
## The nRF9120 is the internal part number for the nRF9161 and nRF9151.
|
||||||
|
## nRF9120 in Secure mode
|
||||||
|
nrf9120-s = ["_nrf9120", "_s", "_nrf91"]
|
||||||
|
nrf9151-s = ["nrf9120-s"]
|
||||||
|
nrf9161-s = ["nrf9120-s"]
|
||||||
|
## nRF9120 in Non-Secure mode
|
||||||
|
nrf9120-ns = ["_nrf9120", "_ns", "_nrf91"]
|
||||||
|
nrf9151-ns = ["nrf9120-ns"]
|
||||||
|
nrf9161-ns = ["nrf9120-ns"]
|
||||||
|
|
||||||
# Features starting with `_` are for internal use only. They're not intended
|
# Features starting with `_` are for internal use only. They're not intended
|
||||||
# to be enabled by other crates, and are not covered by semver guarantees.
|
# to be enabled by other crates, and are not covered by semver guarantees.
|
||||||
@ -107,8 +117,10 @@ _nrf5340-app = ["_nrf5340", "nrf5340-app-pac"]
|
|||||||
_nrf5340-net = ["_nrf5340", "nrf5340-net-pac"]
|
_nrf5340-net = ["_nrf5340", "nrf5340-net-pac"]
|
||||||
_nrf5340 = ["_gpio-p1", "_dppi"]
|
_nrf5340 = ["_gpio-p1", "_dppi"]
|
||||||
_nrf9160 = ["nrf9160-pac", "_dppi"]
|
_nrf9160 = ["nrf9160-pac", "_dppi"]
|
||||||
|
_nrf9120 = ["nrf9120-pac", "_dppi"]
|
||||||
_nrf52 = ["_ppi"]
|
_nrf52 = ["_ppi"]
|
||||||
_nrf51 = ["_ppi"]
|
_nrf51 = ["_ppi"]
|
||||||
|
_nrf91 = []
|
||||||
|
|
||||||
_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"]
|
_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"]
|
||||||
|
|
||||||
@ -125,10 +137,10 @@ _nrf52832_anomaly_109 = []
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
|
embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
|
||||||
embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true }
|
embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true }
|
||||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||||
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
|
embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
|
||||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" }
|
||||||
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
|
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
|
||||||
|
|
||||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
||||||
@ -161,3 +173,4 @@ nrf52840-pac = { version = "0.12.0", optional = true }
|
|||||||
nrf5340-app-pac = { version = "0.12.0", optional = true }
|
nrf5340-app-pac = { version = "0.12.0", optional = true }
|
||||||
nrf5340-net-pac = { version = "0.12.0", optional = true }
|
nrf5340-net-pac = { version = "0.12.0", optional = true }
|
||||||
nrf9160-pac = { version = "0.12.0", optional = true }
|
nrf9160-pac = { version = "0.12.0", optional = true }
|
||||||
|
nrf9120-pac = { version = "0.12.0", optional = true }
|
||||||
|
|||||||
@ -219,6 +219,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if `rx_buffer.len()` is odd.
|
/// Panics if `rx_buffer.len()` is odd.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
uarte: impl Peripheral<P = U> + 'd,
|
uarte: impl Peripheral<P = U> + 'd,
|
||||||
timer: impl Peripheral<P = T> + 'd,
|
timer: impl Peripheral<P = T> + 'd,
|
||||||
@ -254,6 +255,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if `rx_buffer.len()` is odd.
|
/// Panics if `rx_buffer.len()` is odd.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new_with_rtscts(
|
pub fn new_with_rtscts(
|
||||||
uarte: impl Peripheral<P = U> + 'd,
|
uarte: impl Peripheral<P = U> + 'd,
|
||||||
timer: impl Peripheral<P = T> + 'd,
|
timer: impl Peripheral<P = T> + 'd,
|
||||||
@ -286,6 +288,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn new_inner(
|
fn new_inner(
|
||||||
peri: PeripheralRef<'d, U>,
|
peri: PeripheralRef<'d, U>,
|
||||||
timer: PeripheralRef<'d, T>,
|
timer: PeripheralRef<'d, T>,
|
||||||
@ -355,6 +358,11 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
self.tx.write(buf).await
|
self.tx.write(buf).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try writing a buffer without waiting, returning how many bytes were written.
|
||||||
|
pub fn try_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
|
||||||
|
self.tx.try_write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
/// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
|
/// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
|
||||||
pub async fn flush(&mut self) -> Result<(), Error> {
|
pub async fn flush(&mut self) -> Result<(), Error> {
|
||||||
self.tx.flush().await
|
self.tx.flush().await
|
||||||
@ -479,6 +487,29 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try writing a buffer without waiting, returning how many bytes were written.
|
||||||
|
pub fn try_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
|
||||||
|
//trace!("poll_write: {:?}", buf.len());
|
||||||
|
let s = U::buffered_state();
|
||||||
|
let mut tx = unsafe { s.tx_buf.writer() };
|
||||||
|
|
||||||
|
let tx_buf = tx.push_slice();
|
||||||
|
if tx_buf.is_empty() {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let n = min(tx_buf.len(), buf.len());
|
||||||
|
tx_buf[..n].copy_from_slice(&buf[..n]);
|
||||||
|
tx.push_done(n);
|
||||||
|
|
||||||
|
//trace!("poll_write: queued {:?}", n);
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
U::Interrupt::pend();
|
||||||
|
|
||||||
|
Ok(n)
|
||||||
|
}
|
||||||
|
|
||||||
/// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
|
/// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
|
||||||
pub async fn flush(&mut self) -> Result<(), Error> {
|
pub async fn flush(&mut self) -> Result<(), Error> {
|
||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
@ -534,6 +565,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if `rx_buffer.len()` is odd.
|
/// Panics if `rx_buffer.len()` is odd.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
uarte: impl Peripheral<P = U> + 'd,
|
uarte: impl Peripheral<P = U> + 'd,
|
||||||
timer: impl Peripheral<P = T> + 'd,
|
timer: impl Peripheral<P = T> + 'd,
|
||||||
@ -564,6 +596,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if `rx_buffer.len()` is odd.
|
/// Panics if `rx_buffer.len()` is odd.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new_with_rts(
|
pub fn new_with_rts(
|
||||||
uarte: impl Peripheral<P = U> + 'd,
|
uarte: impl Peripheral<P = U> + 'd,
|
||||||
timer: impl Peripheral<P = T> + 'd,
|
timer: impl Peripheral<P = T> + 'd,
|
||||||
@ -590,6 +623,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn new_inner(
|
fn new_inner(
|
||||||
peri: PeripheralRef<'d, U>,
|
peri: PeripheralRef<'d, U>,
|
||||||
timer: PeripheralRef<'d, T>,
|
timer: PeripheralRef<'d, T>,
|
||||||
@ -614,6 +648,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
|
|||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn new_innerer(
|
fn new_innerer(
|
||||||
peri: PeripheralRef<'d, U>,
|
peri: PeripheralRef<'d, U>,
|
||||||
timer: PeripheralRef<'d, T>,
|
timer: PeripheralRef<'d, T>,
|
||||||
@ -766,6 +801,12 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
|
|||||||
rx.pop_done(amt);
|
rx.pop_done(amt);
|
||||||
U::regs().intenset.write(|w| w.rxstarted().set());
|
U::regs().intenset.write(|w| w.rxstarted().set());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// we are ready to read if there is data in the buffer
|
||||||
|
fn read_ready() -> Result<bool, Error> {
|
||||||
|
let state = U::buffered_state();
|
||||||
|
Ok(!state.rx_buf.is_empty())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarteRx<'a, U, T> {
|
impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarteRx<'a, U, T> {
|
||||||
@ -827,6 +868,18 @@ mod _embedded_io {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'d, U: UarteInstance, T: TimerInstance + 'd> embedded_io_async::ReadReady for BufferedUarte<'d, U, T> {
|
||||||
|
fn read_ready(&mut self) -> Result<bool, Self::Error> {
|
||||||
|
BufferedUarteRx::<'d, U, T>::read_ready()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, U: UarteInstance, T: TimerInstance + 'd> embedded_io_async::ReadReady for BufferedUarteRx<'d, U, T> {
|
||||||
|
fn read_ready(&mut self) -> Result<bool, Self::Error> {
|
||||||
|
Self::read_ready()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarte<'d, U, T> {
|
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarte<'d, U, T> {
|
||||||
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
|
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
|
||||||
self.fill_buf().await
|
self.fill_buf().await
|
||||||
|
|||||||
430
embassy-nrf/src/chips/nrf9120.rs
Normal file
430
embassy-nrf/src/chips/nrf9120.rs
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
/// Peripheral Access Crate
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub mod pac {
|
||||||
|
// The nRF9120 has a secure and non-secure (NS) mode.
|
||||||
|
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
||||||
|
|
||||||
|
pub use nrf9120_pac::NVIC_PRIO_BITS;
|
||||||
|
|
||||||
|
#[cfg(feature="rt")]
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use nrf9120_pac::interrupt;
|
||||||
|
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use nrf9120_pac::{
|
||||||
|
Interrupt,
|
||||||
|
|
||||||
|
cc_host_rgf_s as cc_host_rgf,
|
||||||
|
clock_ns as clock,
|
||||||
|
cryptocell_s as cryptocell,
|
||||||
|
ctrl_ap_peri_s as ctrl_ap_peri,
|
||||||
|
dppic_ns as dppic,
|
||||||
|
egu0_ns as egu0,
|
||||||
|
ficr_s as ficr,
|
||||||
|
fpu_ns as fpu,
|
||||||
|
gpiote0_s as gpiote,
|
||||||
|
i2s_ns as i2s,
|
||||||
|
ipc_ns as ipc,
|
||||||
|
kmu_ns as kmu,
|
||||||
|
nvmc_ns as nvmc,
|
||||||
|
p0_ns as p0,
|
||||||
|
pdm_ns as pdm,
|
||||||
|
power_ns as power,
|
||||||
|
pwm0_ns as pwm0,
|
||||||
|
regulators_ns as regulators,
|
||||||
|
rtc0_ns as rtc0,
|
||||||
|
saadc_ns as saadc,
|
||||||
|
spim0_ns as spim0,
|
||||||
|
spis0_ns as spis0,
|
||||||
|
spu_s as spu,
|
||||||
|
tad_s as tad,
|
||||||
|
timer0_ns as timer0,
|
||||||
|
twim0_ns as twim0,
|
||||||
|
twis0_ns as twis0,
|
||||||
|
uarte0_ns as uarte0,
|
||||||
|
uicr_s as uicr,
|
||||||
|
vmc_ns as vmc,
|
||||||
|
wdt_ns as wdt,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Non-Secure mode (NS) peripherals
|
||||||
|
pub mod ns {
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use nrf9120_pac::{
|
||||||
|
CLOCK_NS as CLOCK,
|
||||||
|
DPPIC_NS as DPPIC,
|
||||||
|
EGU0_NS as EGU0,
|
||||||
|
EGU1_NS as EGU1,
|
||||||
|
EGU2_NS as EGU2,
|
||||||
|
EGU3_NS as EGU3,
|
||||||
|
EGU4_NS as EGU4,
|
||||||
|
EGU5_NS as EGU5,
|
||||||
|
FPU_NS as FPU,
|
||||||
|
GPIOTE1_NS as GPIOTE1,
|
||||||
|
I2S_NS as I2S,
|
||||||
|
IPC_NS as IPC,
|
||||||
|
KMU_NS as KMU,
|
||||||
|
NVMC_NS as NVMC,
|
||||||
|
P0_NS as P0,
|
||||||
|
PDM_NS as PDM,
|
||||||
|
POWER_NS as POWER,
|
||||||
|
PWM0_NS as PWM0,
|
||||||
|
PWM1_NS as PWM1,
|
||||||
|
PWM2_NS as PWM2,
|
||||||
|
PWM3_NS as PWM3,
|
||||||
|
REGULATORS_NS as REGULATORS,
|
||||||
|
RTC0_NS as RTC0,
|
||||||
|
RTC1_NS as RTC1,
|
||||||
|
SAADC_NS as SAADC,
|
||||||
|
SPIM0_NS as SPIM0,
|
||||||
|
SPIM1_NS as SPIM1,
|
||||||
|
SPIM2_NS as SPIM2,
|
||||||
|
SPIM3_NS as SPIM3,
|
||||||
|
SPIS0_NS as SPIS0,
|
||||||
|
SPIS1_NS as SPIS1,
|
||||||
|
SPIS2_NS as SPIS2,
|
||||||
|
SPIS3_NS as SPIS3,
|
||||||
|
TIMER0_NS as TIMER0,
|
||||||
|
TIMER1_NS as TIMER1,
|
||||||
|
TIMER2_NS as TIMER2,
|
||||||
|
TWIM0_NS as TWIM0,
|
||||||
|
TWIM1_NS as TWIM1,
|
||||||
|
TWIM2_NS as TWIM2,
|
||||||
|
TWIM3_NS as TWIM3,
|
||||||
|
TWIS0_NS as TWIS0,
|
||||||
|
TWIS1_NS as TWIS1,
|
||||||
|
TWIS2_NS as TWIS2,
|
||||||
|
TWIS3_NS as TWIS3,
|
||||||
|
UARTE0_NS as UARTE0,
|
||||||
|
UARTE1_NS as UARTE1,
|
||||||
|
UARTE2_NS as UARTE2,
|
||||||
|
UARTE3_NS as UARTE3,
|
||||||
|
VMC_NS as VMC,
|
||||||
|
WDT_NS as WDT,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Secure mode (S) peripherals
|
||||||
|
pub mod s {
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use nrf9120_pac::{
|
||||||
|
CC_HOST_RGF_S as CC_HOST_RGF,
|
||||||
|
CLOCK_S as CLOCK,
|
||||||
|
CRYPTOCELL_S as CRYPTOCELL,
|
||||||
|
CTRL_AP_PERI_S as CTRL_AP_PERI,
|
||||||
|
DPPIC_S as DPPIC,
|
||||||
|
EGU0_S as EGU0,
|
||||||
|
EGU1_S as EGU1,
|
||||||
|
EGU2_S as EGU2,
|
||||||
|
EGU3_S as EGU3,
|
||||||
|
EGU4_S as EGU4,
|
||||||
|
EGU5_S as EGU5,
|
||||||
|
FICR_S as FICR,
|
||||||
|
FPU as FPU,
|
||||||
|
GPIOTE0_S as GPIOTE0,
|
||||||
|
I2S_S as I2S,
|
||||||
|
IPC_S as IPC,
|
||||||
|
KMU_S as KMU,
|
||||||
|
NVMC_S as NVMC,
|
||||||
|
P0_S as P0,
|
||||||
|
PDM_S as PDM,
|
||||||
|
POWER_S as POWER,
|
||||||
|
PWM0_S as PWM0,
|
||||||
|
PWM1_S as PWM1,
|
||||||
|
PWM2_S as PWM2,
|
||||||
|
PWM3_S as PWM3,
|
||||||
|
REGULATORS_S as REGULATORS,
|
||||||
|
RTC0_S as RTC0,
|
||||||
|
RTC1_S as RTC1,
|
||||||
|
SAADC_S as SAADC,
|
||||||
|
SPIM0_S as SPIM0,
|
||||||
|
SPIM1_S as SPIM1,
|
||||||
|
SPIM2_S as SPIM2,
|
||||||
|
SPIM3_S as SPIM3,
|
||||||
|
SPIS0_S as SPIS0,
|
||||||
|
SPIS1_S as SPIS1,
|
||||||
|
SPIS2_S as SPIS2,
|
||||||
|
SPIS3_S as SPIS3,
|
||||||
|
SPU_S as SPU,
|
||||||
|
TAD_S as TAD,
|
||||||
|
TIMER0_S as TIMER0,
|
||||||
|
TIMER1_S as TIMER1,
|
||||||
|
TIMER2_S as TIMER2,
|
||||||
|
TWIM0_S as TWIM0,
|
||||||
|
TWIM1_S as TWIM1,
|
||||||
|
TWIM2_S as TWIM2,
|
||||||
|
TWIM3_S as TWIM3,
|
||||||
|
TWIS0_S as TWIS0,
|
||||||
|
TWIS1_S as TWIS1,
|
||||||
|
TWIS2_S as TWIS2,
|
||||||
|
TWIS3_S as TWIS3,
|
||||||
|
UARTE0_S as UARTE0,
|
||||||
|
UARTE1_S as UARTE1,
|
||||||
|
UARTE2_S as UARTE2,
|
||||||
|
UARTE3_S as UARTE3,
|
||||||
|
UICR_S as UICR,
|
||||||
|
VMC_S as VMC,
|
||||||
|
WDT_S as WDT,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "_ns")]
|
||||||
|
pub use ns::*;
|
||||||
|
#[cfg(feature = "_s")]
|
||||||
|
pub use s::*;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||||
|
pub const EASY_DMA_SIZE: usize = (1 << 13) - 1;
|
||||||
|
pub const FORCE_COPY_BUFFER_SIZE: usize = 1024;
|
||||||
|
|
||||||
|
pub const FLASH_SIZE: usize = 1024 * 1024;
|
||||||
|
|
||||||
|
embassy_hal_internal::peripherals! {
|
||||||
|
// RTC
|
||||||
|
RTC0,
|
||||||
|
RTC1,
|
||||||
|
|
||||||
|
// WDT
|
||||||
|
WDT,
|
||||||
|
|
||||||
|
// NVMC
|
||||||
|
NVMC,
|
||||||
|
|
||||||
|
// UARTE, TWI & SPI
|
||||||
|
SERIAL0,
|
||||||
|
SERIAL1,
|
||||||
|
SERIAL2,
|
||||||
|
SERIAL3,
|
||||||
|
|
||||||
|
// SAADC
|
||||||
|
SAADC,
|
||||||
|
|
||||||
|
// PWM
|
||||||
|
PWM0,
|
||||||
|
PWM1,
|
||||||
|
PWM2,
|
||||||
|
PWM3,
|
||||||
|
|
||||||
|
// TIMER
|
||||||
|
TIMER0,
|
||||||
|
TIMER1,
|
||||||
|
TIMER2,
|
||||||
|
|
||||||
|
// GPIOTE
|
||||||
|
GPIOTE_CH0,
|
||||||
|
GPIOTE_CH1,
|
||||||
|
GPIOTE_CH2,
|
||||||
|
GPIOTE_CH3,
|
||||||
|
GPIOTE_CH4,
|
||||||
|
GPIOTE_CH5,
|
||||||
|
GPIOTE_CH6,
|
||||||
|
GPIOTE_CH7,
|
||||||
|
|
||||||
|
// PPI
|
||||||
|
PPI_CH0,
|
||||||
|
PPI_CH1,
|
||||||
|
PPI_CH2,
|
||||||
|
PPI_CH3,
|
||||||
|
PPI_CH4,
|
||||||
|
PPI_CH5,
|
||||||
|
PPI_CH6,
|
||||||
|
PPI_CH7,
|
||||||
|
PPI_CH8,
|
||||||
|
PPI_CH9,
|
||||||
|
PPI_CH10,
|
||||||
|
PPI_CH11,
|
||||||
|
PPI_CH12,
|
||||||
|
PPI_CH13,
|
||||||
|
PPI_CH14,
|
||||||
|
PPI_CH15,
|
||||||
|
|
||||||
|
PPI_GROUP0,
|
||||||
|
PPI_GROUP1,
|
||||||
|
PPI_GROUP2,
|
||||||
|
PPI_GROUP3,
|
||||||
|
PPI_GROUP4,
|
||||||
|
PPI_GROUP5,
|
||||||
|
|
||||||
|
// GPIO port 0
|
||||||
|
P0_00,
|
||||||
|
P0_01,
|
||||||
|
P0_02,
|
||||||
|
P0_03,
|
||||||
|
P0_04,
|
||||||
|
P0_05,
|
||||||
|
P0_06,
|
||||||
|
P0_07,
|
||||||
|
P0_08,
|
||||||
|
P0_09,
|
||||||
|
P0_10,
|
||||||
|
P0_11,
|
||||||
|
P0_12,
|
||||||
|
P0_13,
|
||||||
|
P0_14,
|
||||||
|
P0_15,
|
||||||
|
P0_16,
|
||||||
|
P0_17,
|
||||||
|
P0_18,
|
||||||
|
P0_19,
|
||||||
|
P0_20,
|
||||||
|
P0_21,
|
||||||
|
P0_22,
|
||||||
|
P0_23,
|
||||||
|
P0_24,
|
||||||
|
P0_25,
|
||||||
|
P0_26,
|
||||||
|
P0_27,
|
||||||
|
P0_28,
|
||||||
|
P0_29,
|
||||||
|
P0_30,
|
||||||
|
P0_31,
|
||||||
|
|
||||||
|
// PDM
|
||||||
|
PDM,
|
||||||
|
|
||||||
|
// EGU
|
||||||
|
EGU0,
|
||||||
|
EGU1,
|
||||||
|
EGU2,
|
||||||
|
EGU3,
|
||||||
|
EGU4,
|
||||||
|
EGU5,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_uarte!(SERIAL0, UARTE0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
|
||||||
|
impl_uarte!(SERIAL1, UARTE1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
|
||||||
|
impl_uarte!(SERIAL2, UARTE2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
|
||||||
|
impl_uarte!(SERIAL3, UARTE3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
|
||||||
|
|
||||||
|
impl_spim!(SERIAL0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
|
||||||
|
impl_spim!(SERIAL1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
|
||||||
|
impl_spim!(SERIAL2, SPIM2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
|
||||||
|
impl_spim!(SERIAL3, SPIM3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
|
||||||
|
|
||||||
|
impl_spis!(SERIAL0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
|
||||||
|
impl_spis!(SERIAL1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
|
||||||
|
impl_spis!(SERIAL2, SPIS2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
|
||||||
|
impl_spis!(SERIAL3, SPIS3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
|
||||||
|
|
||||||
|
impl_twim!(SERIAL0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
|
||||||
|
impl_twim!(SERIAL1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
|
||||||
|
impl_twim!(SERIAL2, TWIM2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
|
||||||
|
impl_twim!(SERIAL3, TWIM3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
|
||||||
|
|
||||||
|
impl_twis!(SERIAL0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
|
||||||
|
impl_twis!(SERIAL1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
|
||||||
|
impl_twis!(SERIAL2, TWIS2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
|
||||||
|
impl_twis!(SERIAL3, TWIS3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
|
||||||
|
|
||||||
|
impl_pwm!(PWM0, PWM0, PWM0);
|
||||||
|
impl_pwm!(PWM1, PWM1, PWM1);
|
||||||
|
impl_pwm!(PWM2, PWM2, PWM2);
|
||||||
|
impl_pwm!(PWM3, PWM3, PWM3);
|
||||||
|
|
||||||
|
impl_pdm!(PDM, PDM, PDM);
|
||||||
|
|
||||||
|
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||||
|
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||||
|
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||||
|
|
||||||
|
impl_pin!(P0_00, 0, 0);
|
||||||
|
impl_pin!(P0_01, 0, 1);
|
||||||
|
impl_pin!(P0_02, 0, 2);
|
||||||
|
impl_pin!(P0_03, 0, 3);
|
||||||
|
impl_pin!(P0_04, 0, 4);
|
||||||
|
impl_pin!(P0_05, 0, 5);
|
||||||
|
impl_pin!(P0_06, 0, 6);
|
||||||
|
impl_pin!(P0_07, 0, 7);
|
||||||
|
impl_pin!(P0_08, 0, 8);
|
||||||
|
impl_pin!(P0_09, 0, 9);
|
||||||
|
impl_pin!(P0_10, 0, 10);
|
||||||
|
impl_pin!(P0_11, 0, 11);
|
||||||
|
impl_pin!(P0_12, 0, 12);
|
||||||
|
impl_pin!(P0_13, 0, 13);
|
||||||
|
impl_pin!(P0_14, 0, 14);
|
||||||
|
impl_pin!(P0_15, 0, 15);
|
||||||
|
impl_pin!(P0_16, 0, 16);
|
||||||
|
impl_pin!(P0_17, 0, 17);
|
||||||
|
impl_pin!(P0_18, 0, 18);
|
||||||
|
impl_pin!(P0_19, 0, 19);
|
||||||
|
impl_pin!(P0_20, 0, 20);
|
||||||
|
impl_pin!(P0_21, 0, 21);
|
||||||
|
impl_pin!(P0_22, 0, 22);
|
||||||
|
impl_pin!(P0_23, 0, 23);
|
||||||
|
impl_pin!(P0_24, 0, 24);
|
||||||
|
impl_pin!(P0_25, 0, 25);
|
||||||
|
impl_pin!(P0_26, 0, 26);
|
||||||
|
impl_pin!(P0_27, 0, 27);
|
||||||
|
impl_pin!(P0_28, 0, 28);
|
||||||
|
impl_pin!(P0_29, 0, 29);
|
||||||
|
impl_pin!(P0_30, 0, 30);
|
||||||
|
impl_pin!(P0_31, 0, 31);
|
||||||
|
|
||||||
|
impl_ppi_channel!(PPI_CH0, 0 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH1, 1 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH2, 2 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH3, 3 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH4, 4 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH5, 5 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH6, 6 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH7, 7 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH8, 8 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH9, 9 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH10, 10 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH11, 11 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH12, 12 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH13, 13 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH14, 14 => configurable);
|
||||||
|
impl_ppi_channel!(PPI_CH15, 15 => configurable);
|
||||||
|
|
||||||
|
impl_saadc_input!(P0_13, ANALOG_INPUT0);
|
||||||
|
impl_saadc_input!(P0_14, ANALOG_INPUT1);
|
||||||
|
impl_saadc_input!(P0_15, ANALOG_INPUT2);
|
||||||
|
impl_saadc_input!(P0_16, ANALOG_INPUT3);
|
||||||
|
impl_saadc_input!(P0_17, ANALOG_INPUT4);
|
||||||
|
impl_saadc_input!(P0_18, ANALOG_INPUT5);
|
||||||
|
impl_saadc_input!(P0_19, ANALOG_INPUT6);
|
||||||
|
impl_saadc_input!(P0_20, ANALOG_INPUT7);
|
||||||
|
|
||||||
|
impl_egu!(EGU0, EGU0, EGU0);
|
||||||
|
impl_egu!(EGU1, EGU1, EGU1);
|
||||||
|
impl_egu!(EGU2, EGU2, EGU2);
|
||||||
|
impl_egu!(EGU3, EGU3, EGU3);
|
||||||
|
impl_egu!(EGU4, EGU4, EGU4);
|
||||||
|
impl_egu!(EGU5, EGU5, EGU5);
|
||||||
|
|
||||||
|
embassy_hal_internal::interrupt_mod!(
|
||||||
|
SPU,
|
||||||
|
CLOCK_POWER,
|
||||||
|
SPIM0_SPIS0_TWIM0_TWIS0_UARTE0,
|
||||||
|
SPIM1_SPIS1_TWIM1_TWIS1_UARTE1,
|
||||||
|
SPIM2_SPIS2_TWIM2_TWIS2_UARTE2,
|
||||||
|
SPIM3_SPIS3_TWIM3_TWIS3_UARTE3,
|
||||||
|
GPIOTE0,
|
||||||
|
SAADC,
|
||||||
|
TIMER0,
|
||||||
|
TIMER1,
|
||||||
|
TIMER2,
|
||||||
|
RTC0,
|
||||||
|
RTC1,
|
||||||
|
WDT,
|
||||||
|
EGU0,
|
||||||
|
EGU1,
|
||||||
|
EGU2,
|
||||||
|
EGU3,
|
||||||
|
EGU4,
|
||||||
|
EGU5,
|
||||||
|
PWM0,
|
||||||
|
PWM1,
|
||||||
|
PWM2,
|
||||||
|
PDM,
|
||||||
|
PWM3,
|
||||||
|
I2S,
|
||||||
|
IPC,
|
||||||
|
FPU,
|
||||||
|
GPIOTE1,
|
||||||
|
KMU,
|
||||||
|
CRYPTOCELL,
|
||||||
|
);
|
||||||
@ -90,19 +90,15 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "defmt"))]
|
|
||||||
#[collapse_debuginfo(yes)]
|
#[collapse_debuginfo(yes)]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::core::unreachable!($($x)*)
|
{
|
||||||
};
|
#[cfg(not(feature = "defmt"))]
|
||||||
}
|
::core::unreachable!($($x)*);
|
||||||
|
#[cfg(feature = "defmt")]
|
||||||
#[cfg(feature = "defmt")]
|
::defmt::unreachable!($($x)*);
|
||||||
#[collapse_debuginfo(yes)]
|
}
|
||||||
macro_rules! unreachable {
|
|
||||||
($($x:tt)*) => {
|
|
||||||
::defmt::unreachable!($($x)*)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -534,11 +534,13 @@ mod eh02 {
|
|||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||||
Ok(self.set_high())
|
self.set_high();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
Ok(self.set_low())
|
self.set_low();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -580,11 +582,13 @@ mod eh02 {
|
|||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||||
Ok(self.set_high())
|
self.set_high();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
Ok(self.set_low())
|
self.set_low();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,11 +632,13 @@ impl<'d> embedded_hal_1::digital::ErrorType for Output<'d> {
|
|||||||
|
|
||||||
impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> {
|
impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> {
|
||||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||||
Ok(self.set_high())
|
self.set_high();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
Ok(self.set_low())
|
self.set_low();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -665,11 +671,13 @@ impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> {
|
|||||||
|
|
||||||
impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> {
|
impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> {
|
||||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||||
Ok(self.set_high())
|
self.set_high();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||||
Ok(self.set_low())
|
self.set_low();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -53,9 +53,9 @@ pub enum OutputChannelPolarity {
|
|||||||
|
|
||||||
fn regs() -> &'static pac::gpiote::RegisterBlock {
|
fn regs() -> &'static pac::gpiote::RegisterBlock {
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s"))] {
|
if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s", feature="nrf9120-s"))] {
|
||||||
unsafe { &*pac::GPIOTE0::ptr() }
|
unsafe { &*pac::GPIOTE0::ptr() }
|
||||||
} else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns"))] {
|
} else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns", feature="nrf9120-ns"))] {
|
||||||
unsafe { &*pac::GPIOTE1::ptr() }
|
unsafe { &*pac::GPIOTE1::ptr() }
|
||||||
} else {
|
} else {
|
||||||
unsafe { &*pac::GPIOTE::ptr() }
|
unsafe { &*pac::GPIOTE::ptr() }
|
||||||
@ -81,9 +81,9 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Enable interrupts
|
// Enable interrupts
|
||||||
#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))]
|
#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))]
|
||||||
let irq = interrupt::GPIOTE0;
|
let irq = interrupt::GPIOTE0;
|
||||||
#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))]
|
#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns", feature = "nrf9120-ns"))]
|
||||||
let irq = interrupt::GPIOTE1;
|
let irq = interrupt::GPIOTE1;
|
||||||
#[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))]
|
#[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))]
|
||||||
let irq = interrupt::GPIOTE;
|
let irq = interrupt::GPIOTE;
|
||||||
@ -96,14 +96,14 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
|
|||||||
g.intenset.write(|w| w.port().set());
|
g.intenset.write(|w| w.port().set());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))]
|
#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))]
|
||||||
#[cfg(feature = "rt")]
|
#[cfg(feature = "rt")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn GPIOTE0() {
|
fn GPIOTE0() {
|
||||||
unsafe { handle_gpiote_interrupt() };
|
unsafe { handle_gpiote_interrupt() };
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))]
|
#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns", feature = "nrf9120-ns"))]
|
||||||
#[cfg(feature = "rt")]
|
#[cfg(feature = "rt")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn GPIOTE1() {
|
fn GPIOTE1() {
|
||||||
|
|||||||
@ -24,8 +24,36 @@
|
|||||||
feature = "nrf5340-net",
|
feature = "nrf5340-net",
|
||||||
feature = "nrf9160-s",
|
feature = "nrf9160-s",
|
||||||
feature = "nrf9160-ns",
|
feature = "nrf9160-ns",
|
||||||
|
feature = "nrf9120-s",
|
||||||
|
feature = "nrf9120-ns",
|
||||||
|
feature = "nrf9151-s",
|
||||||
|
feature = "nrf9151-ns",
|
||||||
|
feature = "nrf9161-s",
|
||||||
|
feature = "nrf9161-ns",
|
||||||
)))]
|
)))]
|
||||||
compile_error!("No chip feature activated. You must activate exactly one of the following features: nrf52810, nrf52811, nrf52832, nrf52833, nrf52840");
|
compile_error!(
|
||||||
|
"No chip feature activated. You must activate exactly one of the following features:
|
||||||
|
nrf51,
|
||||||
|
nrf52805,
|
||||||
|
nrf52810,
|
||||||
|
nrf52811,
|
||||||
|
nrf52820,
|
||||||
|
nrf52832,
|
||||||
|
nrf52833,
|
||||||
|
nrf52840,
|
||||||
|
nrf5340-app-s,
|
||||||
|
nrf5340-app-ns,
|
||||||
|
nrf5340-net,
|
||||||
|
nrf9160-s,
|
||||||
|
nrf9160-ns,
|
||||||
|
nrf9120-s,
|
||||||
|
nrf9120-ns,
|
||||||
|
nrf9151-s,
|
||||||
|
nrf9151-ns,
|
||||||
|
nrf9161-s,
|
||||||
|
nrf9161-ns,
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
#[cfg(all(feature = "reset-pin-as-gpio", not(feature = "_nrf52")))]
|
#[cfg(all(feature = "reset-pin-as-gpio", not(feature = "_nrf52")))]
|
||||||
compile_error!("feature `reset-pin-as-gpio` is only valid for nRF52 series chips.");
|
compile_error!("feature `reset-pin-as-gpio` is only valid for nRF52 series chips.");
|
||||||
@ -47,7 +75,7 @@ pub mod gpio;
|
|||||||
pub mod gpiote;
|
pub mod gpiote;
|
||||||
|
|
||||||
// TODO: tested on other chips
|
// TODO: tested on other chips
|
||||||
#[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340-app")))]
|
#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))]
|
||||||
pub mod radio;
|
pub mod radio;
|
||||||
|
|
||||||
#[cfg(not(feature = "nrf51"))]
|
#[cfg(not(feature = "nrf51"))]
|
||||||
@ -62,7 +90,7 @@ pub mod nvmc;
|
|||||||
feature = "nrf52833",
|
feature = "nrf52833",
|
||||||
feature = "nrf52840",
|
feature = "nrf52840",
|
||||||
feature = "_nrf5340-app",
|
feature = "_nrf5340-app",
|
||||||
feature = "_nrf9160"
|
feature = "_nrf91",
|
||||||
))]
|
))]
|
||||||
pub mod pdm;
|
pub mod pdm;
|
||||||
pub mod ppi;
|
pub mod ppi;
|
||||||
@ -73,11 +101,11 @@ pub mod ppi;
|
|||||||
feature = "_nrf5340-net"
|
feature = "_nrf5340-net"
|
||||||
)))]
|
)))]
|
||||||
pub mod pwm;
|
pub mod pwm;
|
||||||
#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))]
|
#[cfg(not(any(feature = "nrf51", feature = "_nrf91", feature = "_nrf5340-net")))]
|
||||||
pub mod qdec;
|
pub mod qdec;
|
||||||
#[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))]
|
#[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))]
|
||||||
pub mod qspi;
|
pub mod qspi;
|
||||||
#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))]
|
#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))]
|
||||||
pub mod rng;
|
pub mod rng;
|
||||||
#[cfg(not(any(feature = "nrf51", feature = "nrf52820", feature = "_nrf5340-net")))]
|
#[cfg(not(any(feature = "nrf51", feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||||
pub mod saadc;
|
pub mod saadc;
|
||||||
@ -85,7 +113,7 @@ pub mod saadc;
|
|||||||
pub mod spim;
|
pub mod spim;
|
||||||
#[cfg(not(feature = "nrf51"))]
|
#[cfg(not(feature = "nrf51"))]
|
||||||
pub mod spis;
|
pub mod spis;
|
||||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||||
pub mod temp;
|
pub mod temp;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
#[cfg(not(feature = "nrf51"))]
|
#[cfg(not(feature = "nrf51"))]
|
||||||
@ -116,6 +144,7 @@ pub mod wdt;
|
|||||||
#[cfg_attr(feature = "_nrf5340-app", path = "chips/nrf5340_app.rs")]
|
#[cfg_attr(feature = "_nrf5340-app", path = "chips/nrf5340_app.rs")]
|
||||||
#[cfg_attr(feature = "_nrf5340-net", path = "chips/nrf5340_net.rs")]
|
#[cfg_attr(feature = "_nrf5340-net", path = "chips/nrf5340_net.rs")]
|
||||||
#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")]
|
#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")]
|
||||||
|
#[cfg_attr(feature = "_nrf9120", path = "chips/nrf9120.rs")]
|
||||||
mod chip;
|
mod chip;
|
||||||
|
|
||||||
/// Macro to bind interrupts to handlers.
|
/// Macro to bind interrupts to handlers.
|
||||||
@ -196,15 +225,15 @@ pub mod config {
|
|||||||
/// Internal RC oscillator
|
/// Internal RC oscillator
|
||||||
InternalRC,
|
InternalRC,
|
||||||
/// Synthesized from the high frequency clock source.
|
/// Synthesized from the high frequency clock source.
|
||||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||||
Synthesized,
|
Synthesized,
|
||||||
/// External source from xtal.
|
/// External source from xtal.
|
||||||
ExternalXtal,
|
ExternalXtal,
|
||||||
/// External source from xtal with low swing applied.
|
/// External source from xtal with low swing applied.
|
||||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||||
ExternalLowSwing,
|
ExternalLowSwing,
|
||||||
/// External source from xtal with full swing applied.
|
/// External source from xtal with full swing applied.
|
||||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||||
ExternalFullSwing,
|
ExternalFullSwing,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +251,7 @@ pub mod config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Settings for enabling the built in DCDC converters.
|
/// Settings for enabling the built in DCDC converters.
|
||||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||||
pub struct DcdcConfig {
|
pub struct DcdcConfig {
|
||||||
/// Config for the first stage DCDC (VDDH -> VDD), if disabled LDO will be used.
|
/// Config for the first stage DCDC (VDDH -> VDD), if disabled LDO will be used.
|
||||||
#[cfg(feature = "nrf52840")]
|
#[cfg(feature = "nrf52840")]
|
||||||
@ -264,7 +293,7 @@ pub mod config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Settings for enabling the built in DCDC converter.
|
/// Settings for enabling the built in DCDC converter.
|
||||||
#[cfg(feature = "_nrf9160")]
|
#[cfg(feature = "_nrf91")]
|
||||||
pub struct DcdcConfig {
|
pub struct DcdcConfig {
|
||||||
/// Config for the main rail, if disabled LDO will be used.
|
/// Config for the main rail, if disabled LDO will be used.
|
||||||
pub regmain: bool,
|
pub regmain: bool,
|
||||||
@ -298,7 +327,7 @@ pub mod config {
|
|||||||
// xtals if they know they have them.
|
// xtals if they know they have them.
|
||||||
hfclk_source: HfclkSource::Internal,
|
hfclk_source: HfclkSource::Internal,
|
||||||
lfclk_source: LfclkSource::InternalRC,
|
lfclk_source: LfclkSource::InternalRC,
|
||||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||||
dcdc: DcdcConfig {
|
dcdc: DcdcConfig {
|
||||||
#[cfg(feature = "nrf52840")]
|
#[cfg(feature = "nrf52840")]
|
||||||
reg0: false,
|
reg0: false,
|
||||||
@ -312,7 +341,7 @@ pub mod config {
|
|||||||
regmain: false,
|
regmain: false,
|
||||||
regradio: false,
|
regradio: false,
|
||||||
},
|
},
|
||||||
#[cfg(feature = "_nrf9160")]
|
#[cfg(feature = "_nrf91")]
|
||||||
dcdc: DcdcConfig { regmain: false },
|
dcdc: DcdcConfig { regmain: false },
|
||||||
#[cfg(feature = "gpiote")]
|
#[cfg(feature = "gpiote")]
|
||||||
gpiote_interrupt_priority: crate::interrupt::Priority::P0,
|
gpiote_interrupt_priority: crate::interrupt::Priority::P0,
|
||||||
@ -329,7 +358,7 @@ pub mod config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "_nrf9160")]
|
#[cfg(feature = "_nrf91")]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
mod consts {
|
mod consts {
|
||||||
pub const UICR_APPROTECT: *mut u32 = 0x00FF8000 as *mut u32;
|
pub const UICR_APPROTECT: *mut u32 = 0x00FF8000 as *mut u32;
|
||||||
@ -468,7 +497,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
|||||||
// UICR.APPROTECT = Enabled
|
// UICR.APPROTECT = Enabled
|
||||||
let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_ENABLED);
|
let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_ENABLED);
|
||||||
needs_reset |= res == WriteResult::Written;
|
needs_reset |= res == WriteResult::Written;
|
||||||
#[cfg(any(feature = "_nrf5340-app", feature = "_nrf9160"))]
|
#[cfg(any(feature = "_nrf5340-app", feature = "_nrf91"))]
|
||||||
{
|
{
|
||||||
let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED);
|
let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED);
|
||||||
needs_reset |= res == WriteResult::Written;
|
needs_reset |= res == WriteResult::Written;
|
||||||
@ -552,7 +581,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure LFCLK.
|
// Configure LFCLK.
|
||||||
#[cfg(not(any(feature = "nrf51", feature = "_nrf5340", feature = "_nrf9160")))]
|
#[cfg(not(any(feature = "nrf51", feature = "_nrf5340", feature = "_nrf91")))]
|
||||||
match config.lfclk_source {
|
match config.lfclk_source {
|
||||||
config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()),
|
config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()),
|
||||||
config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()),
|
config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()),
|
||||||
@ -572,7 +601,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
|||||||
w
|
w
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
#[cfg(feature = "_nrf9160")]
|
#[cfg(feature = "_nrf91")]
|
||||||
match config.lfclk_source {
|
match config.lfclk_source {
|
||||||
config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().lfrc()),
|
config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().lfrc()),
|
||||||
config::LfclkSource::ExternalXtal => r.lfclksrc.write(|w| w.src().lfxo()),
|
config::LfclkSource::ExternalXtal => r.lfclksrc.write(|w| w.src().lfxo()),
|
||||||
@ -585,7 +614,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
|||||||
r.tasks_lfclkstart.write(|w| unsafe { w.bits(1) });
|
r.tasks_lfclkstart.write(|w| unsafe { w.bits(1) });
|
||||||
while r.events_lfclkstarted.read().bits() == 0 {}
|
while r.events_lfclkstarted.read().bits() == 0 {}
|
||||||
|
|
||||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
|
||||||
{
|
{
|
||||||
// Setup DCDCs.
|
// Setup DCDCs.
|
||||||
let pwr = unsafe { &*pac::POWER::ptr() };
|
let pwr = unsafe { &*pac::POWER::ptr() };
|
||||||
@ -597,7 +626,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
|||||||
pwr.dcdcen.write(|w| w.dcdcen().set_bit());
|
pwr.dcdcen.write(|w| w.dcdcen().set_bit());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "_nrf9160")]
|
#[cfg(feature = "_nrf91")]
|
||||||
{
|
{
|
||||||
// Setup DCDC.
|
// Setup DCDC.
|
||||||
let reg = unsafe { &*pac::REGULATORS::ptr() };
|
let reg = unsafe { &*pac::REGULATORS::ptr() };
|
||||||
@ -629,7 +658,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
|||||||
time_driver::init(config.time_interrupt_priority);
|
time_driver::init(config.time_interrupt_priority);
|
||||||
|
|
||||||
// Disable UARTE (enabled by default for some reason)
|
// Disable UARTE (enabled by default for some reason)
|
||||||
#[cfg(feature = "_nrf9160")]
|
#[cfg(feature = "_nrf91")]
|
||||||
unsafe {
|
unsafe {
|
||||||
(*pac::UARTE0::ptr()).enable.write(|w| w.enable().disabled());
|
(*pac::UARTE0::ptr()).enable.write(|w| w.enable().disabled());
|
||||||
(*pac::UARTE1::ptr()).enable.write(|w| w.enable().disabled());
|
(*pac::UARTE1::ptr()).enable.write(|w| w.enable().disabled());
|
||||||
|
|||||||
@ -60,23 +60,23 @@ impl<'d> Nvmc<'d> {
|
|||||||
while p.ready.read().ready().is_busy() {}
|
while p.ready.read().ready().is_busy() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340")))]
|
#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))]
|
||||||
fn wait_ready_write(&mut self) {
|
fn wait_ready_write(&mut self) {
|
||||||
self.wait_ready();
|
self.wait_ready();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "_nrf9160", feature = "_nrf5340"))]
|
#[cfg(any(feature = "_nrf91", feature = "_nrf5340"))]
|
||||||
fn wait_ready_write(&mut self) {
|
fn wait_ready_write(&mut self) {
|
||||||
let p = Self::regs();
|
let p = Self::regs();
|
||||||
while p.readynext.read().readynext().is_busy() {}
|
while p.readynext.read().readynext().is_busy() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340")))]
|
#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))]
|
||||||
fn erase_page(&mut self, page_addr: u32) {
|
fn erase_page(&mut self, page_addr: u32) {
|
||||||
Self::regs().erasepage().write(|w| unsafe { w.bits(page_addr) });
|
Self::regs().erasepage().write(|w| unsafe { w.bits(page_addr) });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "_nrf9160", feature = "_nrf5340"))]
|
#[cfg(any(feature = "_nrf91", feature = "_nrf5340"))]
|
||||||
fn erase_page(&mut self, page_addr: u32) {
|
fn erase_page(&mut self, page_addr: u32) {
|
||||||
let first_page_word = page_addr as *mut u32;
|
let first_page_word = page_addr as *mut u32;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|||||||
@ -21,7 +21,7 @@ pub use crate::pac::pdm::pdmclkctrl::FREQ_A as Frequency;
|
|||||||
feature = "nrf52840",
|
feature = "nrf52840",
|
||||||
feature = "nrf52833",
|
feature = "nrf52833",
|
||||||
feature = "_nrf5340-app",
|
feature = "_nrf5340-app",
|
||||||
feature = "_nrf9160",
|
feature = "_nrf91",
|
||||||
))]
|
))]
|
||||||
pub use crate::pac::pdm::ratio::RATIO_A as Ratio;
|
pub use crate::pac::pdm::ratio::RATIO_A as Ratio;
|
||||||
use crate::{interrupt, Peripheral};
|
use crate::{interrupt, Peripheral};
|
||||||
@ -121,7 +121,7 @@ impl<'d, T: Instance> Pdm<'d, T> {
|
|||||||
feature = "nrf52840",
|
feature = "nrf52840",
|
||||||
feature = "nrf52833",
|
feature = "nrf52833",
|
||||||
feature = "_nrf5340-app",
|
feature = "_nrf5340-app",
|
||||||
feature = "_nrf9160",
|
feature = "_nrf91",
|
||||||
))]
|
))]
|
||||||
r.ratio.write(|w| w.ratio().variant(config.ratio));
|
r.ratio.write(|w| w.ratio().variant(config.ratio));
|
||||||
r.mode.write(|w| {
|
r.mode.write(|w| {
|
||||||
@ -374,7 +374,7 @@ pub struct Config {
|
|||||||
feature = "nrf52840",
|
feature = "nrf52840",
|
||||||
feature = "nrf52833",
|
feature = "nrf52833",
|
||||||
feature = "_nrf5340-app",
|
feature = "_nrf5340-app",
|
||||||
feature = "_nrf9160",
|
feature = "_nrf91",
|
||||||
))]
|
))]
|
||||||
pub ratio: Ratio,
|
pub ratio: Ratio,
|
||||||
/// Gain left in dB
|
/// Gain left in dB
|
||||||
@ -393,7 +393,7 @@ impl Default for Config {
|
|||||||
feature = "nrf52840",
|
feature = "nrf52840",
|
||||||
feature = "nrf52833",
|
feature = "nrf52833",
|
||||||
feature = "_nrf5340-app",
|
feature = "_nrf5340-app",
|
||||||
feature = "_nrf9160",
|
feature = "_nrf91",
|
||||||
))]
|
))]
|
||||||
ratio: Ratio::RATIO80,
|
ratio: Ratio::RATIO80,
|
||||||
gain_left: I7F1::ZERO,
|
gain_left: I7F1::ZERO,
|
||||||
|
|||||||
@ -78,7 +78,8 @@ impl Default for Config {
|
|||||||
|
|
||||||
/// Used to configure an individual SAADC peripheral channel.
|
/// Used to configure an individual SAADC peripheral channel.
|
||||||
///
|
///
|
||||||
/// See the `Default` impl for suitable default values.
|
/// Construct using the `single_ended` or `differential` methods. These provide sensible defaults
|
||||||
|
/// for the public fields, which can be overridden if required.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct ChannelConfig<'d> {
|
pub struct ChannelConfig<'d> {
|
||||||
/// Reference voltage of the SAADC input.
|
/// Reference voltage of the SAADC input.
|
||||||
@ -722,9 +723,9 @@ macro_rules! impl_saadc_input {
|
|||||||
pub struct VddInput;
|
pub struct VddInput;
|
||||||
|
|
||||||
impl_peripheral!(VddInput);
|
impl_peripheral!(VddInput);
|
||||||
#[cfg(not(feature = "_nrf9160"))]
|
#[cfg(not(feature = "_nrf91"))]
|
||||||
impl_saadc_input!(@local, VddInput, VDD);
|
impl_saadc_input!(@local, VddInput, VDD);
|
||||||
#[cfg(feature = "_nrf9160")]
|
#[cfg(feature = "_nrf91")]
|
||||||
impl_saadc_input!(@local, VddInput, VDDGPIO);
|
impl_saadc_input!(@local, VddInput, VDDGPIO);
|
||||||
|
|
||||||
/// A dummy `Input` pin implementation for SAADC peripheral sampling from the
|
/// A dummy `Input` pin implementation for SAADC peripheral sampling from the
|
||||||
|
|||||||
@ -30,9 +30,9 @@ impl Config {
|
|||||||
pub fn try_new(_wdt: &peripherals::WDT) -> Option<Self> {
|
pub fn try_new(_wdt: &peripherals::WDT) -> Option<Self> {
|
||||||
let r = unsafe { &*WDT::ptr() };
|
let r = unsafe { &*WDT::ptr() };
|
||||||
|
|
||||||
#[cfg(not(feature = "_nrf9160"))]
|
#[cfg(not(feature = "_nrf91"))]
|
||||||
let runstatus = r.runstatus.read().runstatus().bit();
|
let runstatus = r.runstatus.read().runstatus().bit();
|
||||||
#[cfg(feature = "_nrf9160")]
|
#[cfg(feature = "_nrf91")]
|
||||||
let runstatus = r.runstatus.read().runstatuswdt().bit();
|
let runstatus = r.runstatus.read().runstatuswdt().bit();
|
||||||
|
|
||||||
if runstatus {
|
if runstatus {
|
||||||
@ -83,9 +83,9 @@ impl Watchdog {
|
|||||||
let crv = config.timeout_ticks.max(MIN_TICKS);
|
let crv = config.timeout_ticks.max(MIN_TICKS);
|
||||||
let rren = (1u32 << N) - 1;
|
let rren = (1u32 << N) - 1;
|
||||||
|
|
||||||
#[cfg(not(feature = "_nrf9160"))]
|
#[cfg(not(feature = "_nrf91"))]
|
||||||
let runstatus = r.runstatus.read().runstatus().bit();
|
let runstatus = r.runstatus.read().runstatus().bit();
|
||||||
#[cfg(feature = "_nrf9160")]
|
#[cfg(feature = "_nrf91")]
|
||||||
let runstatus = r.runstatus.read().runstatuswdt().bit();
|
let runstatus = r.runstatus.read().runstatuswdt().bit();
|
||||||
|
|
||||||
if runstatus {
|
if runstatus {
|
||||||
@ -184,8 +184,9 @@ impl WatchdogHandle {
|
|||||||
|
|
||||||
/// Steal a watchdog handle by index.
|
/// Steal a watchdog handle by index.
|
||||||
///
|
///
|
||||||
/// Safety: watchdog must be initialized, index must be between 0 and N-1 where
|
/// # Safety
|
||||||
/// N is the handle count when initializing.
|
/// Watchdog must be initialized and `index` must be between `0` and `N-1`
|
||||||
|
/// where `N` is the handle count when initializing.
|
||||||
pub unsafe fn steal(index: u8) -> Self {
|
pub unsafe fn steal(index: u8) -> Self {
|
||||||
Self { index }
|
Self { index }
|
||||||
}
|
}
|
||||||
|
|||||||
32
embassy-rp/CHANGELOG.md
Normal file
32
embassy-rp/CHANGELOG.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Changelog for embassy-rp
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
## 0.2.0 - 2024-08-05
|
||||||
|
|
||||||
|
- Add read_to_break_with_count
|
||||||
|
- add option to provide your own boot2
|
||||||
|
- Add multichannel ADC
|
||||||
|
- Add collapse_debuginfo to fmt.rs macros.
|
||||||
|
- Use raw slices .len() method instead of unsafe hacks.
|
||||||
|
- Add missing word "pin" in rp pwm documentation
|
||||||
|
- Add Clone and Copy to Error types
|
||||||
|
- fix spinlocks staying locked after reset.
|
||||||
|
- wait until read matches for PSM accesses.
|
||||||
|
- Remove generics
|
||||||
|
- fix drop implementation of BufferedUartRx and BufferedUartTx
|
||||||
|
- implement `embedded_storage_async::nor_flash::MultiwriteNorFlash`
|
||||||
|
- rp usb: wake ep-wakers after stalling
|
||||||
|
- rp usb: add stall implementation
|
||||||
|
- Add parameter for enabling pull-up and pull-down in RP PWM input mode
|
||||||
|
- rp: remove mod sealed.
|
||||||
|
- rename pins data type and the macro
|
||||||
|
- rename pwm channels to pwm slices, including in documentation
|
||||||
|
- rename the Channel trait to Slice and the PwmPin to PwmChannel
|
||||||
|
- i2c: Fix race condition that appears on fast repeated transfers.
|
||||||
|
- Add a basic "read to break" function
|
||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "embassy-rp"
|
name = "embassy-rp"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 microcontroller"
|
description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 microcontroller"
|
||||||
@ -14,7 +14,9 @@ src_base = "https://github.com/embassy-rs/embassy/blob/embassy-rp-v$VERSION/emba
|
|||||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-rp/src/"
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-rp/src/"
|
||||||
features = ["defmt", "unstable-pac", "time-driver"]
|
features = ["defmt", "unstable-pac", "time-driver"]
|
||||||
flavors = [
|
flavors = [
|
||||||
{ name = "rp2040", target = "thumbv6m-none-eabi" },
|
{ name = "rp2040", target = "thumbv6m-none-eabi", features = ["rp2040"] },
|
||||||
|
{ name = "rp235xa", target = "thumbv8m.main-none-eabihf", features = ["rp235xa"] },
|
||||||
|
{ name = "rp235xb", target = "thumbv8m.main-none-eabihf", features = ["rp235xb"] },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
@ -22,13 +24,13 @@ features = ["defmt", "unstable-pac", "time-driver"]
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "rt" ]
|
default = [ "rt" ]
|
||||||
## Enable the rt feature of [`rp-pac`](https://docs.rs/crates/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization.
|
## Enable the rt feature of [`rp-pac`](https://docs.rs/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization.
|
||||||
rt = [ "rp-pac/rt" ]
|
rt = [ "rp-pac/rt" ]
|
||||||
|
|
||||||
## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
|
## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
|
||||||
defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"]
|
defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"]
|
||||||
|
|
||||||
## Configure the critical section crate to use an implementation that is safe for multicore use on rp2040.
|
## Configure the [`critical-section`](https://docs.rs/critical-section) crate to use an implementation that is safe for multicore use on rp2040.
|
||||||
critical-section-impl = ["critical-section/restore-state-u8"]
|
critical-section-impl = ["critical-section/restore-state-u8"]
|
||||||
|
|
||||||
## Reexport the PAC for the currently enabled chip at `embassy_rp::pac`.
|
## Reexport the PAC for the currently enabled chip at `embassy_rp::pac`.
|
||||||
@ -88,13 +90,30 @@ boot2-w25x10cl = []
|
|||||||
## ```
|
## ```
|
||||||
boot2-none = []
|
boot2-none = []
|
||||||
|
|
||||||
|
## Configure the hal for use with the rp2040
|
||||||
|
rp2040 = ["rp-pac/rp2040"]
|
||||||
|
_rp235x = ["rp-pac/rp235x"]
|
||||||
|
## Configure the hal for use with the rp235xA
|
||||||
|
rp235xa = ["_rp235x"]
|
||||||
|
## Configure the hal for use with the rp235xB
|
||||||
|
rp235xb = ["_rp235x"]
|
||||||
|
|
||||||
|
# hack around cortex-m peripherals being wrong when running tests.
|
||||||
|
_test = []
|
||||||
|
|
||||||
|
## Add a binary-info header block containing picotool-compatible metadata.
|
||||||
|
##
|
||||||
|
## Takes up a little flash space, but picotool can then report the name of your
|
||||||
|
## program and other details.
|
||||||
|
binary-info = ["rt", "dep:rp-binary-info", "rp-binary-info?/binary-info"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||||
embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
|
embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
|
||||||
embassy-time = { version = "0.3.1", path = "../embassy-time" }
|
embassy-time = { version = "0.3.2", path = "../embassy-time" }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
|
embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
|
||||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" }
|
||||||
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
|
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
|
||||||
atomic-polyfill = "1.0.1"
|
atomic-polyfill = "1.0.1"
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
@ -112,7 +131,7 @@ embedded-storage-async = { version = "0.4.1" }
|
|||||||
rand_core = "0.6.4"
|
rand_core = "0.6.4"
|
||||||
fixed = "1.23.1"
|
fixed = "1.23.1"
|
||||||
|
|
||||||
rp-pac = { version = "6" }
|
rp-pac = { git = "https://github.com/embassy-rs/rp-pac.git", rev = "a7f42d25517f7124ad3b4ed492dec8b0f50a0e6c", feature = ["rt"] }
|
||||||
|
|
||||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
||||||
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
|
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
|
||||||
@ -123,7 +142,9 @@ pio-proc = {version= "0.2" }
|
|||||||
pio = {version= "0.2.1" }
|
pio = {version= "0.2.1" }
|
||||||
rp2040-boot2 = "0.3"
|
rp2040-boot2 = "0.3"
|
||||||
document-features = "0.2.7"
|
document-features = "0.2.7"
|
||||||
|
sha2-const-stable = "0.1"
|
||||||
|
rp-binary-info = { version = "0.1.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
embassy-executor = { version = "0.5.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] }
|
embassy-executor = { version = "0.6.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] }
|
||||||
static_cell = { version = "2" }
|
static_cell = { version = "2" }
|
||||||
|
|||||||
202
embassy-rp/LICENSE-APACHE
Normal file
202
embassy-rp/LICENSE-APACHE
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright (c) Embassy project contributors
|
||||||
|
Portions copyright (c) rp-rs organization
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
26
embassy-rp/LICENSE-MIT
Normal file
26
embassy-rp/LICENSE-MIT
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Copyright (c) Embassy project contributors
|
||||||
|
Portions copyright (c) rp-rs organization
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any
|
||||||
|
person obtaining a copy of this software and associated
|
||||||
|
documentation files (the "Software"), to deal in the
|
||||||
|
Software without restriction, including without
|
||||||
|
limitation the rights to use, copy, modify, merge,
|
||||||
|
publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software
|
||||||
|
is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice
|
||||||
|
shall be included in all copies or substantial portions
|
||||||
|
of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||||
|
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||||
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
@ -23,5 +23,5 @@ The `embassy-rp` HAL implements the traits from [embedded-hal](https://crates.io
|
|||||||
|
|
||||||
This crate can run on any executor.
|
This crate can run on any executor.
|
||||||
|
|
||||||
Optionally, some features requiring [`embassy-time`](https://crates.io/crates/embassy-time) can be activated with the `time` feature. If you enable it,
|
Optionally, some features requiring [`embassy-time`](https://crates.io/crates/embassy-time) can be activated with the `time-driver` feature. If you enable it,
|
||||||
you must link an `embassy-time` driver in your project.
|
you must link an `embassy-time` driver in your project.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user