diff options
| author | Mathias <[email protected]> | 2022-09-29 10:00:13 +0200 |
|---|---|---|
| committer | Mathias <[email protected]> | 2022-09-29 10:00:13 +0200 |
| commit | 7ee7109508b463f98ea9ae08e061aeaca28016e6 (patch) | |
| tree | 50723244067224c6c32603e21fbe8ec36c76898e | |
| parent | 18dc0dea636daa6e48aa9208b5a74cdfedc8b513 (diff) | |
| parent | 77ece3f903735b50f265ddd43520c50e0f28c1a1 (diff) | |
Rebase on master
61 files changed, 1923 insertions, 1145 deletions
| @@ -58,6 +58,7 @@ cargo batch \ | |||
| 58 | --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,log \ | 58 | --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,log \ |
| 59 | --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits \ | 59 | --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits \ |
| 60 | --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \ | 60 | --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \ |
| 61 | --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,intrinsics \ | ||
| 61 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits \ | 62 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits \ |
| 62 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \ | 63 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \ |
| 63 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits \ | 64 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits \ |
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index 96878ace9..8286601ec 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs | |||
| @@ -604,6 +604,21 @@ impl FirmwareUpdater { | |||
| 604 | self.dfu.len() | 604 | self.dfu.len() |
| 605 | } | 605 | } |
| 606 | 606 | ||
| 607 | /// Obtain the current state. | ||
| 608 | /// | ||
| 609 | /// This is useful to check if the bootloader has just done a swap, in order | ||
| 610 | /// to do verifications and self-tests of the new image before calling | ||
| 611 | /// `mark_booted`. | ||
| 612 | pub async fn get_state<F: AsyncNorFlash>(&mut self, flash: &mut F, aligned: &mut [u8]) -> Result<State, F::Error> { | ||
| 613 | flash.read(self.state.from as u32, aligned).await?; | ||
| 614 | |||
| 615 | if !aligned.iter().any(|&b| b != SWAP_MAGIC) { | ||
| 616 | Ok(State::Swap) | ||
| 617 | } else { | ||
| 618 | Ok(State::Boot) | ||
| 619 | } | ||
| 620 | } | ||
| 621 | |||
| 607 | /// Mark to trigger firmware swap on next boot. | 622 | /// Mark to trigger firmware swap on next boot. |
| 608 | /// | 623 | /// |
| 609 | /// # Safety | 624 | /// # Safety |
| @@ -660,12 +675,6 @@ impl FirmwareUpdater { | |||
| 660 | ) -> Result<(), F::Error> { | 675 | ) -> Result<(), F::Error> { |
| 661 | assert!(data.len() >= F::ERASE_SIZE); | 676 | assert!(data.len() >= F::ERASE_SIZE); |
| 662 | 677 | ||
| 663 | trace!( | ||
| 664 | "Writing firmware at offset 0x{:x} len {}", | ||
| 665 | self.dfu.from + offset, | ||
| 666 | data.len() | ||
| 667 | ); | ||
| 668 | |||
| 669 | flash | 678 | flash |
| 670 | .erase( | 679 | .erase( |
| 671 | (self.dfu.from + offset) as u32, | 680 | (self.dfu.from + offset) as u32, |
| @@ -679,7 +688,156 @@ impl FirmwareUpdater { | |||
| 679 | self.dfu.from + offset + data.len() | 688 | self.dfu.from + offset + data.len() |
| 680 | ); | 689 | ); |
| 681 | 690 | ||
| 682 | let mut write_offset = self.dfu.from + offset; | 691 | FirmwareWriter(self.dfu) |
| 692 | .write_block(offset, data, flash, block_size) | ||
| 693 | .await?; | ||
| 694 | |||
| 695 | Ok(()) | ||
| 696 | } | ||
| 697 | |||
| 698 | /// Prepare for an incoming DFU update by erasing the entire DFU area and | ||
| 699 | /// returning a `FirmwareWriter`. | ||
| 700 | /// | ||
| 701 | /// Using this instead of `write_firmware` allows for an optimized API in | ||
| 702 | /// exchange for added complexity. | ||
| 703 | pub async fn prepare_update<F: AsyncNorFlash>(&mut self, flash: &mut F) -> Result<FirmwareWriter, F::Error> { | ||
| 704 | flash.erase((self.dfu.from) as u32, (self.dfu.to) as u32).await?; | ||
| 705 | |||
| 706 | trace!("Erased from {} to {}", self.dfu.from, self.dfu.to); | ||
| 707 | |||
| 708 | Ok(FirmwareWriter(self.dfu)) | ||
| 709 | } | ||
| 710 | |||
| 711 | // | ||
| 712 | // Blocking API | ||
| 713 | // | ||
| 714 | |||
| 715 | /// Obtain the current state. | ||
| 716 | /// | ||
| 717 | /// This is useful to check if the bootloader has just done a swap, in order | ||
| 718 | /// to do verifications and self-tests of the new image before calling | ||
| 719 | /// `mark_booted`. | ||
| 720 | pub fn get_state_blocking<F: NorFlash>(&mut self, flash: &mut F, aligned: &mut [u8]) -> Result<State, F::Error> { | ||
| 721 | flash.read(self.state.from as u32, aligned)?; | ||
| 722 | |||
| 723 | if !aligned.iter().any(|&b| b != SWAP_MAGIC) { | ||
| 724 | Ok(State::Swap) | ||
| 725 | } else { | ||
| 726 | Ok(State::Boot) | ||
| 727 | } | ||
| 728 | } | ||
| 729 | |||
| 730 | /// Mark to trigger firmware swap on next boot. | ||
| 731 | /// | ||
| 732 | /// # Safety | ||
| 733 | /// | ||
| 734 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. | ||
| 735 | pub fn mark_updated_blocking<F: NorFlash>(&mut self, flash: &mut F, aligned: &mut [u8]) -> Result<(), F::Error> { | ||
| 736 | assert_eq!(aligned.len(), F::WRITE_SIZE); | ||
| 737 | self.set_magic_blocking(aligned, SWAP_MAGIC, flash) | ||
| 738 | } | ||
| 739 | |||
| 740 | /// Mark firmware boot successful and stop rollback on reset. | ||
| 741 | /// | ||
| 742 | /// # Safety | ||
| 743 | /// | ||
| 744 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. | ||
| 745 | pub fn mark_booted_blocking<F: NorFlash>(&mut self, flash: &mut F, aligned: &mut [u8]) -> Result<(), F::Error> { | ||
| 746 | assert_eq!(aligned.len(), F::WRITE_SIZE); | ||
| 747 | self.set_magic_blocking(aligned, BOOT_MAGIC, flash) | ||
| 748 | } | ||
| 749 | |||
| 750 | fn set_magic_blocking<F: NorFlash>( | ||
| 751 | &mut self, | ||
| 752 | aligned: &mut [u8], | ||
| 753 | magic: u8, | ||
| 754 | flash: &mut F, | ||
| 755 | ) -> Result<(), F::Error> { | ||
| 756 | flash.read(self.state.from as u32, aligned)?; | ||
| 757 | |||
| 758 | if aligned.iter().any(|&b| b != magic) { | ||
| 759 | aligned.fill(0); | ||
| 760 | |||
| 761 | flash.write(self.state.from as u32, aligned)?; | ||
| 762 | flash.erase(self.state.from as u32, self.state.to as u32)?; | ||
| 763 | |||
| 764 | aligned.fill(magic); | ||
| 765 | flash.write(self.state.from as u32, aligned)?; | ||
| 766 | } | ||
| 767 | Ok(()) | ||
| 768 | } | ||
| 769 | |||
| 770 | /// Write data to a flash page. | ||
| 771 | /// | ||
| 772 | /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. | ||
| 773 | /// | ||
| 774 | /// # Safety | ||
| 775 | /// | ||
| 776 | /// Failing to meet alignment and size requirements may result in a panic. | ||
| 777 | pub fn write_firmware_blocking<F: NorFlash>( | ||
| 778 | &mut self, | ||
| 779 | offset: usize, | ||
| 780 | data: &[u8], | ||
| 781 | flash: &mut F, | ||
| 782 | block_size: usize, | ||
| 783 | ) -> Result<(), F::Error> { | ||
| 784 | assert!(data.len() >= F::ERASE_SIZE); | ||
| 785 | |||
| 786 | flash.erase( | ||
| 787 | (self.dfu.from + offset) as u32, | ||
| 788 | (self.dfu.from + offset + data.len()) as u32, | ||
| 789 | )?; | ||
| 790 | |||
| 791 | trace!( | ||
| 792 | "Erased from {} to {}", | ||
| 793 | self.dfu.from + offset, | ||
| 794 | self.dfu.from + offset + data.len() | ||
| 795 | ); | ||
| 796 | |||
| 797 | FirmwareWriter(self.dfu).write_block_blocking(offset, data, flash, block_size)?; | ||
| 798 | |||
| 799 | Ok(()) | ||
| 800 | } | ||
| 801 | |||
| 802 | /// Prepare for an incoming DFU update by erasing the entire DFU area and | ||
| 803 | /// returning a `FirmwareWriter`. | ||
| 804 | /// | ||
| 805 | /// Using this instead of `write_firmware_blocking` allows for an optimized | ||
| 806 | /// API in exchange for added complexity. | ||
| 807 | pub fn prepare_update_blocking<F: NorFlash>(&mut self, flash: &mut F) -> Result<FirmwareWriter, F::Error> { | ||
| 808 | flash.erase((self.dfu.from) as u32, (self.dfu.to) as u32)?; | ||
| 809 | |||
| 810 | trace!("Erased from {} to {}", self.dfu.from, self.dfu.to); | ||
| 811 | |||
| 812 | Ok(FirmwareWriter(self.dfu)) | ||
| 813 | } | ||
| 814 | } | ||
| 815 | |||
| 816 | /// FirmwareWriter allows writing blocks to an already erased flash. | ||
| 817 | pub struct FirmwareWriter(Partition); | ||
| 818 | |||
| 819 | impl FirmwareWriter { | ||
| 820 | /// Write data to a flash page. | ||
| 821 | /// | ||
| 822 | /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. | ||
| 823 | /// | ||
| 824 | /// # Safety | ||
| 825 | /// | ||
| 826 | /// Failing to meet alignment and size requirements may result in a panic. | ||
| 827 | pub async fn write_block<F: AsyncNorFlash>( | ||
| 828 | &mut self, | ||
| 829 | offset: usize, | ||
| 830 | data: &[u8], | ||
| 831 | flash: &mut F, | ||
| 832 | block_size: usize, | ||
| 833 | ) -> Result<(), F::Error> { | ||
| 834 | trace!( | ||
| 835 | "Writing firmware at offset 0x{:x} len {}", | ||
| 836 | self.0.from + offset, | ||
| 837 | data.len() | ||
| 838 | ); | ||
| 839 | |||
| 840 | let mut write_offset = self.0.from + offset; | ||
| 683 | for chunk in data.chunks(block_size) { | 841 | for chunk in data.chunks(block_size) { |
| 684 | trace!("Wrote chunk at {}: {:?}", write_offset, chunk); | 842 | trace!("Wrote chunk at {}: {:?}", write_offset, chunk); |
| 685 | flash.write(write_offset as u32, chunk).await?; | 843 | flash.write(write_offset as u32, chunk).await?; |
| @@ -702,6 +860,50 @@ impl FirmwareUpdater { | |||
| 702 | 860 | ||
| 703 | Ok(()) | 861 | Ok(()) |
| 704 | } | 862 | } |
| 863 | |||
| 864 | /// Write data to a flash page. | ||
| 865 | /// | ||
| 866 | /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. | ||
| 867 | /// | ||
| 868 | /// # Safety | ||
| 869 | /// | ||
| 870 | /// Failing to meet alignment and size requirements may result in a panic. | ||
| 871 | pub fn write_block_blocking<F: NorFlash>( | ||
| 872 | &mut self, | ||
| 873 | offset: usize, | ||
| 874 | data: &[u8], | ||
| 875 | flash: &mut F, | ||
| 876 | block_size: usize, | ||
| 877 | ) -> Result<(), F::Error> { | ||
| 878 | trace!( | ||
| 879 | "Writing firmware at offset 0x{:x} len {}", | ||
| 880 | self.0.from + offset, | ||
| 881 | data.len() | ||
| 882 | ); | ||
| 883 | |||
| 884 | let mut write_offset = self.0.from + offset; | ||
| 885 | for chunk in data.chunks(block_size) { | ||
| 886 | trace!("Wrote chunk at {}: {:?}", write_offset, chunk); | ||
| 887 | flash.write(write_offset as u32, chunk)?; | ||
| 888 | write_offset += chunk.len(); | ||
| 889 | } | ||
| 890 | /* | ||
| 891 | trace!("Wrote data, reading back for verification"); | ||
| 892 | |||
| 893 | let mut buf: [u8; 4096] = [0; 4096]; | ||
| 894 | let mut data_offset = 0; | ||
| 895 | let mut read_offset = self.dfu.from + offset; | ||
| 896 | for chunk in buf.chunks_mut(block_size) { | ||
| 897 | flash.read(read_offset as u32, chunk).await?; | ||
| 898 | trace!("Read chunk at {}: {:?}", read_offset, chunk); | ||
| 899 | assert_eq!(&data[data_offset..data_offset + block_size], chunk); | ||
| 900 | read_offset += chunk.len(); | ||
| 901 | data_offset += chunk.len(); | ||
| 902 | } | ||
| 903 | */ | ||
| 904 | |||
| 905 | Ok(()) | ||
| 906 | } | ||
| 705 | } | 907 | } |
| 706 | 908 | ||
| 707 | #[cfg(test)] | 909 | #[cfg(test)] |
diff --git a/embassy-lora/src/stm32wl/mod.rs b/embassy-lora/src/stm32wl/mod.rs index e28fa2c1a..8d5d19531 100644 --- a/embassy-lora/src/stm32wl/mod.rs +++ b/embassy-lora/src/stm32wl/mod.rs | |||
| @@ -234,15 +234,15 @@ fn configure_radio(radio: &mut SubGhz<'_, NoDma, NoDma>, config: SubGhzRadioConf | |||
| 234 | Ok(()) | 234 | Ok(()) |
| 235 | } | 235 | } |
| 236 | 236 | ||
| 237 | impl<RS: RadioSwitch> PhyRxTx for SubGhzRadio<'static, RS> { | 237 | impl<'d, RS: RadioSwitch> PhyRxTx for SubGhzRadio<'d, RS> { |
| 238 | type PhyError = RadioError; | 238 | type PhyError = RadioError; |
| 239 | 239 | ||
| 240 | type TxFuture<'m> = impl Future<Output = Result<u32, Self::PhyError>> + 'm where RS: 'm; | 240 | type TxFuture<'m> = impl Future<Output = Result<u32, Self::PhyError>> + 'm where Self: 'm; |
| 241 | fn tx<'m>(&'m mut self, config: TxConfig, buf: &'m [u8]) -> Self::TxFuture<'m> { | 241 | fn tx<'m>(&'m mut self, config: TxConfig, buf: &'m [u8]) -> Self::TxFuture<'m> { |
| 242 | async move { self.do_tx(config, buf).await } | 242 | async move { self.do_tx(config, buf).await } |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | type RxFuture<'m> = impl Future<Output = Result<(usize, RxQuality), Self::PhyError>> + 'm where RS: 'm; | 245 | type RxFuture<'m> = impl Future<Output = Result<(usize, RxQuality), Self::PhyError>> + 'm where Self: 'm; |
| 246 | fn rx<'m>(&'m mut self, config: RfConfig, buf: &'m mut [u8]) -> Self::RxFuture<'m> { | 246 | fn rx<'m>(&'m mut self, config: RfConfig, buf: &'m mut [u8]) -> Self::RxFuture<'m> { |
| 247 | async move { self.do_rx(config, buf).await } | 247 | async move { self.do_rx(config, buf).await } |
| 248 | } | 248 | } |
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 6fbbc8d9b..d80281fa3 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml | |||
| @@ -18,10 +18,10 @@ flavors = [ | |||
| 18 | 18 | ||
| 19 | time = ["dep:embassy-time"] | 19 | time = ["dep:embassy-time"] |
| 20 | 20 | ||
| 21 | defmt = ["dep:defmt", "embassy-executor/defmt", "embassy-sync/defmt", "embassy-usb?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"] | 21 | defmt = ["dep:defmt", "embassy-executor/defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"] |
| 22 | 22 | ||
| 23 | # Enable nightly-only features | 23 | # Enable nightly-only features |
| 24 | nightly = ["embedded-hal-1", "embedded-hal-async", "embassy-usb", "embedded-storage-async", "dep:embedded-io", "embassy-embedded-hal/nightly"] | 24 | nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io", "embassy-embedded-hal/nightly"] |
| 25 | 25 | ||
| 26 | # Reexport the PAC for the currently enabled chip at `embassy_nrf::pac`. | 26 | # Reexport the PAC for the currently enabled chip at `embassy_nrf::pac`. |
| 27 | # This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version. | 27 | # This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version. |
| @@ -70,7 +70,7 @@ embassy-sync = { version = "0.1.0", path = "../embassy-sync" } | |||
| 70 | embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-3"]} | 70 | embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-3"]} |
| 71 | embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } | 71 | embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } |
| 72 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } | 72 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } |
| 73 | embassy-usb = {version = "0.1.0", path = "../embassy-usb", optional=true } | 73 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true } |
| 74 | 74 | ||
| 75 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 75 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 76 | embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true} | 76 | embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true} |
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index fec875cb8..6e85a159f 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs | |||
| @@ -26,7 +26,7 @@ use embassy_sync::waitqueue::WakerRegistration; | |||
| 26 | // Re-export SVD variants to allow user to directly set values | 26 | // Re-export SVD variants to allow user to directly set values |
| 27 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; | 27 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; |
| 28 | 28 | ||
| 29 | use crate::gpio::Pin as GpioPin; | 29 | use crate::gpio::{self, Pin as GpioPin}; |
| 30 | use crate::interrupt::InterruptExt; | 30 | use crate::interrupt::InterruptExt; |
| 31 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; | 31 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; |
| 32 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | 32 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; |
| @@ -428,21 +428,23 @@ impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> { | |||
| 428 | fn drop(&mut self) { | 428 | fn drop(&mut self) { |
| 429 | let r = U::regs(); | 429 | let r = U::regs(); |
| 430 | 430 | ||
| 431 | // TODO this probably deadlocks. do like Uarte instead. | ||
| 432 | |||
| 433 | self.timer.stop(); | 431 | self.timer.stop(); |
| 434 | if let RxState::Receiving = self.rx_state { | 432 | |
| 435 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | 433 | r.inten.reset(); |
| 436 | } | 434 | r.events_rxto.reset(); |
| 437 | if let TxState::Transmitting(_) = self.tx_state { | 435 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); |
| 438 | r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | 436 | r.events_txstopped.reset(); |
| 439 | } | 437 | r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); |
| 440 | if let RxState::Receiving = self.rx_state { | 438 | |
| 441 | low_power_wait_until(|| r.events_endrx.read().bits() == 1); | 439 | while r.events_txstopped.read().bits() == 0 {} |
| 442 | } | 440 | while r.events_rxto.read().bits() == 0 {} |
| 443 | if let TxState::Transmitting(_) = self.tx_state { | 441 | |
| 444 | low_power_wait_until(|| r.events_endtx.read().bits() == 1); | 442 | r.enable.write(|w| w.enable().disabled()); |
| 445 | } | 443 | |
| 444 | gpio::deconfigure_pin(r.psel.rxd.read().bits()); | ||
| 445 | gpio::deconfigure_pin(r.psel.txd.read().bits()); | ||
| 446 | gpio::deconfigure_pin(r.psel.rts.read().bits()); | ||
| 447 | gpio::deconfigure_pin(r.psel.cts.read().bits()); | ||
| 446 | } | 448 | } |
| 447 | } | 449 | } |
| 448 | 450 | ||
| @@ -548,13 +550,3 @@ impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for StateInner<'a, | |||
| 548 | trace!("irq: end"); | 550 | trace!("irq: end"); |
| 549 | } | 551 | } |
| 550 | } | 552 | } |
| 551 | |||
| 552 | /// Low power blocking wait loop using WFE/SEV. | ||
| 553 | fn low_power_wait_until(mut condition: impl FnMut() -> bool) { | ||
| 554 | while !condition() { | ||
| 555 | // WFE might "eat" an event that would have otherwise woken the executor. | ||
| 556 | cortex_m::asm::wfe(); | ||
| 557 | } | ||
| 558 | // Retrigger an event to be transparent to the executor. | ||
| 559 | cortex_m::asm::sev(); | ||
| 560 | } | ||
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs index 0685d419c..00da5c9dd 100644 --- a/embassy-nrf/src/usb.rs +++ b/embassy-nrf/src/usb.rs | |||
| @@ -9,9 +9,8 @@ use core::task::Poll; | |||
| 9 | use cortex_m::peripheral::NVIC; | 9 | use cortex_m::peripheral::NVIC; |
| 10 | use embassy_hal_common::{into_ref, PeripheralRef}; | 10 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 11 | use embassy_sync::waitqueue::AtomicWaker; | 11 | use embassy_sync::waitqueue::AtomicWaker; |
| 12 | pub use embassy_usb; | 12 | use embassy_usb_driver as driver; |
| 13 | use embassy_usb::driver::{self, EndpointError, Event, Unsupported}; | 13 | use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported}; |
| 14 | use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; | ||
| 15 | use pac::usbd::RegisterBlock; | 14 | use pac::usbd::RegisterBlock; |
| 16 | 15 | ||
| 17 | use crate::interrupt::{Interrupt, InterruptExt}; | 16 | use crate::interrupt::{Interrupt, InterruptExt}; |
| @@ -243,7 +242,7 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P> | |||
| 243 | interval: u8, | 242 | interval: u8, |
| 244 | ) -> Result<Self::EndpointIn, driver::EndpointAllocError> { | 243 | ) -> Result<Self::EndpointIn, driver::EndpointAllocError> { |
| 245 | let index = self.alloc_in.allocate(ep_type)?; | 244 | let index = self.alloc_in.allocate(ep_type)?; |
| 246 | let ep_addr = EndpointAddress::from_parts(index, UsbDirection::In); | 245 | let ep_addr = EndpointAddress::from_parts(index, Direction::In); |
| 247 | Ok(Endpoint::new(EndpointInfo { | 246 | Ok(Endpoint::new(EndpointInfo { |
| 248 | addr: ep_addr, | 247 | addr: ep_addr, |
| 249 | ep_type, | 248 | ep_type, |
| @@ -259,7 +258,7 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P> | |||
| 259 | interval: u8, | 258 | interval: u8, |
| 260 | ) -> Result<Self::EndpointOut, driver::EndpointAllocError> { | 259 | ) -> Result<Self::EndpointOut, driver::EndpointAllocError> { |
| 261 | let index = self.alloc_out.allocate(ep_type)?; | 260 | let index = self.alloc_out.allocate(ep_type)?; |
| 262 | let ep_addr = EndpointAddress::from_parts(index, UsbDirection::Out); | 261 | let ep_addr = EndpointAddress::from_parts(index, Direction::Out); |
| 263 | Ok(Endpoint::new(EndpointInfo { | 262 | Ok(Endpoint::new(EndpointInfo { |
| 264 | addr: ep_addr, | 263 | addr: ep_addr, |
| 265 | ep_type, | 264 | ep_type, |
| @@ -428,8 +427,8 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { | |||
| 428 | let regs = T::regs(); | 427 | let regs = T::regs(); |
| 429 | let i = ep_addr.index(); | 428 | let i = ep_addr.index(); |
| 430 | match ep_addr.direction() { | 429 | match ep_addr.direction() { |
| 431 | UsbDirection::Out => regs.halted.epout[i].read().getstatus().is_halted(), | 430 | Direction::Out => regs.halted.epout[i].read().getstatus().is_halted(), |
| 432 | UsbDirection::In => regs.halted.epin[i].read().getstatus().is_halted(), | 431 | Direction::In => regs.halted.epin[i].read().getstatus().is_halted(), |
| 433 | } | 432 | } |
| 434 | } | 433 | } |
| 435 | 434 | ||
| @@ -442,7 +441,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { | |||
| 442 | debug!("endpoint_set_enabled {:?} {}", ep_addr, enabled); | 441 | debug!("endpoint_set_enabled {:?} {}", ep_addr, enabled); |
| 443 | 442 | ||
| 444 | match ep_addr.direction() { | 443 | match ep_addr.direction() { |
| 445 | UsbDirection::In => { | 444 | Direction::In => { |
| 446 | let mut was_enabled = false; | 445 | let mut was_enabled = false; |
| 447 | regs.epinen.modify(|r, w| { | 446 | regs.epinen.modify(|r, w| { |
| 448 | let mut bits = r.bits(); | 447 | let mut bits = r.bits(); |
| @@ -466,7 +465,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { | |||
| 466 | 465 | ||
| 467 | In::waker(i).wake(); | 466 | In::waker(i).wake(); |
| 468 | } | 467 | } |
| 469 | UsbDirection::Out => { | 468 | Direction::Out => { |
| 470 | regs.epouten.modify(|r, w| { | 469 | regs.epouten.modify(|r, w| { |
| 471 | let mut bits = r.bits(); | 470 | let mut bits = r.bits(); |
| 472 | if enabled { | 471 | if enabled { |
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index ce78acd3c..a7c2daa56 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml | |||
| @@ -12,7 +12,7 @@ flavors = [ | |||
| 12 | ] | 12 | ] |
| 13 | 13 | ||
| 14 | [features] | 14 | [features] |
| 15 | defmt = ["dep:defmt", "embassy-usb?/defmt"] | 15 | defmt = ["dep:defmt", "embassy-usb-driver?/defmt"] |
| 16 | 16 | ||
| 17 | # Reexport the PAC for the currently enabled chip at `embassy_rp::pac`. | 17 | # Reexport the PAC for the currently enabled chip at `embassy_rp::pac`. |
| 18 | # This is unstable because semver-minor (non-breaking) releases of embassy-rp may major-bump (breaking) the PAC version. | 18 | # This is unstable because semver-minor (non-breaking) releases of embassy-rp may major-bump (breaking) the PAC version. |
| @@ -23,11 +23,11 @@ unstable-pac = [] | |||
| 23 | time-driver = [] | 23 | time-driver = [] |
| 24 | 24 | ||
| 25 | rom-func-cache = [] | 25 | rom-func-cache = [] |
| 26 | disable-intrinsics = [] | 26 | intrinsics = [] |
| 27 | rom-v2-intrinsics = [] | 27 | rom-v2-intrinsics = [] |
| 28 | 28 | ||
| 29 | # Enable nightly-only features | 29 | # Enable nightly-only features |
| 30 | nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb"] | 30 | nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"] |
| 31 | 31 | ||
| 32 | # Implement embedded-hal 1.0 alpha traits. | 32 | # Implement embedded-hal 1.0 alpha traits. |
| 33 | # Implement embedded-hal-async traits if `nightly` is set as well. | 33 | # Implement embedded-hal-async traits if `nightly` is set as well. |
| @@ -41,7 +41,7 @@ embassy-futures = { version = "0.1.0", path = "../embassy-futures" } | |||
| 41 | embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]} | 41 | embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]} |
| 42 | embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } | 42 | embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } |
| 43 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } | 43 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } |
| 44 | embassy-usb = {version = "0.1.0", path = "../embassy-usb", optional = true } | 44 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } |
| 45 | atomic-polyfill = "1.0.1" | 45 | atomic-polyfill = "1.0.1" |
| 46 | defmt = { version = "0.3", optional = true } | 46 | defmt = { version = "0.3", optional = true } |
| 47 | log = { version = "0.4.14", optional = true } | 47 | log = { version = "0.4.14", optional = true } |
| @@ -53,6 +53,7 @@ critical-section = "1.1" | |||
| 53 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 53 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 54 | chrono = { version = "0.4", default-features = false, optional = true } | 54 | chrono = { version = "0.4", default-features = false, optional = true } |
| 55 | embedded-storage = { version = "0.3" } | 55 | embedded-storage = { version = "0.3" } |
| 56 | embedded-io = { version = "0.3.0", features = ["async"], optional = true } | ||
| 56 | 57 | ||
| 57 | rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } | 58 | rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } |
| 58 | #rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } | 59 | #rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } |
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs new file mode 100644 index 000000000..9596d661d --- /dev/null +++ b/embassy-rp/src/i2c.rs | |||
| @@ -0,0 +1,556 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy_hal_common::{into_ref, PeripheralRef}; | ||
| 4 | use pac::i2c; | ||
| 5 | |||
| 6 | use crate::dma::AnyChannel; | ||
| 7 | use crate::gpio::sealed::Pin; | ||
| 8 | use crate::gpio::AnyPin; | ||
| 9 | use crate::{pac, peripherals, Peripheral}; | ||
| 10 | |||
| 11 | /// I2C error abort reason | ||
| 12 | #[derive(Debug)] | ||
| 13 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 14 | pub enum AbortReason { | ||
| 15 | /// A bus operation was not acknowledged, e.g. due to the addressed device | ||
| 16 | /// not being available on the bus or the device not being ready to process | ||
| 17 | /// requests at the moment | ||
| 18 | NoAcknowledge, | ||
| 19 | /// The arbitration was lost, e.g. electrical problems with the clock signal | ||
| 20 | ArbitrationLoss, | ||
| 21 | Other(u32), | ||
| 22 | } | ||
| 23 | |||
| 24 | /// I2C error | ||
| 25 | #[derive(Debug)] | ||
| 26 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 27 | pub enum Error { | ||
| 28 | /// I2C abort with error | ||
| 29 | Abort(AbortReason), | ||
| 30 | /// User passed in a read buffer that was 0 length | ||
| 31 | InvalidReadBufferLength, | ||
| 32 | /// User passed in a write buffer that was 0 length | ||
| 33 | InvalidWriteBufferLength, | ||
| 34 | /// Target i2c address is out of range | ||
| 35 | AddressOutOfRange(u16), | ||
| 36 | /// Target i2c address is reserved | ||
| 37 | AddressReserved(u16), | ||
| 38 | } | ||
| 39 | |||
| 40 | #[non_exhaustive] | ||
| 41 | #[derive(Copy, Clone)] | ||
| 42 | pub struct Config { | ||
| 43 | pub frequency: u32, | ||
| 44 | } | ||
| 45 | |||
| 46 | impl Default for Config { | ||
| 47 | fn default() -> Self { | ||
| 48 | Self { frequency: 100_000 } | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | const FIFO_SIZE: u8 = 16; | ||
| 53 | |||
| 54 | pub struct I2c<'d, T: Instance, M: Mode> { | ||
| 55 | _tx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 56 | _rx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 57 | _dma_buf: [u16; 256], | ||
| 58 | phantom: PhantomData<(&'d mut T, M)>, | ||
| 59 | } | ||
| 60 | |||
| 61 | impl<'d, T: Instance> I2c<'d, T, Blocking> { | ||
| 62 | pub fn new_blocking( | ||
| 63 | _peri: impl Peripheral<P = T> + 'd, | ||
| 64 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, | ||
| 65 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, | ||
| 66 | config: Config, | ||
| 67 | ) -> Self { | ||
| 68 | into_ref!(scl, sda); | ||
| 69 | Self::new_inner(_peri, scl.map_into(), sda.map_into(), None, None, config) | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { | ||
| 74 | fn new_inner( | ||
| 75 | _peri: impl Peripheral<P = T> + 'd, | ||
| 76 | scl: PeripheralRef<'d, AnyPin>, | ||
| 77 | sda: PeripheralRef<'d, AnyPin>, | ||
| 78 | _tx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 79 | _rx_dma: Option<PeripheralRef<'d, AnyChannel>>, | ||
| 80 | config: Config, | ||
| 81 | ) -> Self { | ||
| 82 | into_ref!(_peri); | ||
| 83 | |||
| 84 | assert!(config.frequency <= 1_000_000); | ||
| 85 | assert!(config.frequency > 0); | ||
| 86 | |||
| 87 | let p = T::regs(); | ||
| 88 | |||
| 89 | unsafe { | ||
| 90 | p.ic_enable().write(|w| w.set_enable(false)); | ||
| 91 | |||
| 92 | // Select controller mode & speed | ||
| 93 | p.ic_con().modify(|w| { | ||
| 94 | // Always use "fast" mode (<= 400 kHz, works fine for standard | ||
| 95 | // mode too) | ||
| 96 | w.set_speed(i2c::vals::Speed::FAST); | ||
| 97 | w.set_master_mode(true); | ||
| 98 | w.set_ic_slave_disable(true); | ||
| 99 | w.set_ic_restart_en(true); | ||
| 100 | w.set_tx_empty_ctrl(true); | ||
| 101 | }); | ||
| 102 | |||
| 103 | // Set FIFO watermarks to 1 to make things simpler. This is encoded | ||
| 104 | // by a register value of 0. | ||
| 105 | p.ic_tx_tl().write(|w| w.set_tx_tl(0)); | ||
| 106 | p.ic_rx_tl().write(|w| w.set_rx_tl(0)); | ||
| 107 | |||
| 108 | // Configure SCL & SDA pins | ||
| 109 | scl.io().ctrl().write(|w| w.set_funcsel(3)); | ||
| 110 | sda.io().ctrl().write(|w| w.set_funcsel(3)); | ||
| 111 | |||
| 112 | scl.pad_ctrl().write(|w| { | ||
| 113 | w.set_schmitt(true); | ||
| 114 | w.set_ie(true); | ||
| 115 | w.set_od(false); | ||
| 116 | w.set_pue(true); | ||
| 117 | w.set_pde(false); | ||
| 118 | }); | ||
| 119 | sda.pad_ctrl().write(|w| { | ||
| 120 | w.set_schmitt(true); | ||
| 121 | w.set_ie(true); | ||
| 122 | w.set_od(false); | ||
| 123 | w.set_pue(true); | ||
| 124 | w.set_pde(false); | ||
| 125 | }); | ||
| 126 | |||
| 127 | // Configure baudrate | ||
| 128 | |||
| 129 | // There are some subtleties to I2C timing which we are completely | ||
| 130 | // ignoring here See: | ||
| 131 | // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69 | ||
| 132 | let clk_base = crate::clocks::clk_peri_freq(); | ||
| 133 | |||
| 134 | let period = (clk_base + config.frequency / 2) / config.frequency; | ||
| 135 | let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low | ||
| 136 | let hcnt = period - lcnt; // and 2/5 (40%) of the period high | ||
| 137 | |||
| 138 | // Check for out-of-range divisors: | ||
| 139 | assert!(hcnt <= 0xffff); | ||
| 140 | assert!(lcnt <= 0xffff); | ||
| 141 | assert!(hcnt >= 8); | ||
| 142 | assert!(lcnt >= 8); | ||
| 143 | |||
| 144 | // Per I2C-bus specification a device in standard or fast mode must | ||
| 145 | // internally provide a hold time of at least 300ns for the SDA | ||
| 146 | // signal to bridge the undefined region of the falling edge of SCL. | ||
| 147 | // A smaller hold time of 120ns is used for fast mode plus. | ||
| 148 | let sda_tx_hold_count = if config.frequency < 1_000_000 { | ||
| 149 | // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s / | ||
| 150 | // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't | ||
| 151 | // fit in uint. Add 1 to avoid division truncation. | ||
| 152 | ((clk_base * 3) / 10_000_000) + 1 | ||
| 153 | } else { | ||
| 154 | // fast mode plus requires a clk_base > 32MHz | ||
| 155 | assert!(clk_base >= 32_000_000); | ||
| 156 | |||
| 157 | // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s / | ||
| 158 | // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't | ||
| 159 | // fit in uint. Add 1 to avoid division truncation. | ||
| 160 | ((clk_base * 3) / 25_000_000) + 1 | ||
| 161 | }; | ||
| 162 | assert!(sda_tx_hold_count <= lcnt - 2); | ||
| 163 | |||
| 164 | p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16)); | ||
| 165 | p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16)); | ||
| 166 | p.ic_fs_spklen() | ||
| 167 | .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 })); | ||
| 168 | p.ic_sda_hold() | ||
| 169 | .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16)); | ||
| 170 | |||
| 171 | // Enable I2C block | ||
| 172 | p.ic_enable().write(|w| w.set_enable(true)); | ||
| 173 | } | ||
| 174 | |||
| 175 | Self { | ||
| 176 | _tx_dma, | ||
| 177 | _rx_dma, | ||
| 178 | _dma_buf: [0; 256], | ||
| 179 | phantom: PhantomData, | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | fn setup(addr: u16) -> Result<(), Error> { | ||
| 184 | if addr >= 0x80 { | ||
| 185 | return Err(Error::AddressOutOfRange(addr)); | ||
| 186 | } | ||
| 187 | |||
| 188 | if i2c_reserved_addr(addr) { | ||
| 189 | return Err(Error::AddressReserved(addr)); | ||
| 190 | } | ||
| 191 | |||
| 192 | let p = T::regs(); | ||
| 193 | unsafe { | ||
| 194 | p.ic_enable().write(|w| w.set_enable(false)); | ||
| 195 | p.ic_tar().write(|w| w.set_ic_tar(addr)); | ||
| 196 | p.ic_enable().write(|w| w.set_enable(true)); | ||
| 197 | } | ||
| 198 | Ok(()) | ||
| 199 | } | ||
| 200 | |||
| 201 | fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { | ||
| 202 | let p = T::regs(); | ||
| 203 | unsafe { | ||
| 204 | let abort_reason = p.ic_tx_abrt_source().read(); | ||
| 205 | if abort_reason.0 != 0 { | ||
| 206 | // Note clearing the abort flag also clears the reason, and this | ||
| 207 | // instance of flag is clear-on-read! Note also the | ||
| 208 | // IC_CLR_TX_ABRT register always reads as 0. | ||
| 209 | p.ic_clr_tx_abrt().read(); | ||
| 210 | |||
| 211 | let reason = if abort_reason.abrt_7b_addr_noack() | ||
| 212 | | abort_reason.abrt_10addr1_noack() | ||
| 213 | | abort_reason.abrt_10addr2_noack() | ||
| 214 | { | ||
| 215 | AbortReason::NoAcknowledge | ||
| 216 | } else if abort_reason.arb_lost() { | ||
| 217 | AbortReason::ArbitrationLoss | ||
| 218 | } else { | ||
| 219 | AbortReason::Other(abort_reason.0) | ||
| 220 | }; | ||
| 221 | |||
| 222 | Err(Error::Abort(reason)) | ||
| 223 | } else { | ||
| 224 | Ok(()) | ||
| 225 | } | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | fn read_blocking_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> { | ||
| 230 | if buffer.is_empty() { | ||
| 231 | return Err(Error::InvalidReadBufferLength); | ||
| 232 | } | ||
| 233 | |||
| 234 | let p = T::regs(); | ||
| 235 | let lastindex = buffer.len() - 1; | ||
| 236 | for (i, byte) in buffer.iter_mut().enumerate() { | ||
| 237 | let first = i == 0; | ||
| 238 | let last = i == lastindex; | ||
| 239 | |||
| 240 | // NOTE(unsafe) We have &mut self | ||
| 241 | unsafe { | ||
| 242 | // wait until there is space in the FIFO to write the next byte | ||
| 243 | while p.ic_txflr().read().txflr() == FIFO_SIZE {} | ||
| 244 | |||
| 245 | p.ic_data_cmd().write(|w| { | ||
| 246 | w.set_restart(restart && first); | ||
| 247 | w.set_stop(send_stop && last); | ||
| 248 | |||
| 249 | w.set_cmd(true); | ||
| 250 | }); | ||
| 251 | |||
| 252 | while p.ic_rxflr().read().rxflr() == 0 { | ||
| 253 | self.read_and_clear_abort_reason()?; | ||
| 254 | } | ||
| 255 | |||
| 256 | *byte = p.ic_data_cmd().read().dat(); | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | Ok(()) | ||
| 261 | } | ||
| 262 | |||
| 263 | fn write_blocking_internal(&mut self, bytes: &[u8], send_stop: bool) -> Result<(), Error> { | ||
| 264 | if bytes.is_empty() { | ||
| 265 | return Err(Error::InvalidWriteBufferLength); | ||
| 266 | } | ||
| 267 | |||
| 268 | let p = T::regs(); | ||
| 269 | |||
| 270 | for (i, byte) in bytes.iter().enumerate() { | ||
| 271 | let last = i == bytes.len() - 1; | ||
| 272 | |||
| 273 | // NOTE(unsafe) We have &mut self | ||
| 274 | unsafe { | ||
| 275 | p.ic_data_cmd().write(|w| { | ||
| 276 | w.set_stop(send_stop && last); | ||
| 277 | w.set_dat(*byte); | ||
| 278 | }); | ||
| 279 | |||
| 280 | // Wait until the transmission of the address/data from the | ||
| 281 | // internal shift register has completed. For this to function | ||
| 282 | // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The | ||
| 283 | // TX_EMPTY_CTRL flag was set in i2c_init. | ||
| 284 | while !p.ic_raw_intr_stat().read().tx_empty() {} | ||
| 285 | |||
| 286 | let abort_reason = self.read_and_clear_abort_reason(); | ||
| 287 | |||
| 288 | if abort_reason.is_err() || (send_stop && last) { | ||
| 289 | // If the transaction was aborted or if it completed | ||
| 290 | // successfully wait until the STOP condition has occured. | ||
| 291 | |||
| 292 | while !p.ic_raw_intr_stat().read().stop_det() {} | ||
| 293 | |||
| 294 | p.ic_clr_stop_det().read().clr_stop_det(); | ||
| 295 | } | ||
| 296 | |||
| 297 | // Note the hardware issues a STOP automatically on an abort | ||
| 298 | // condition. Note also the hardware clears RX FIFO as well as | ||
| 299 | // TX on abort, ecause we set hwparam | ||
| 300 | // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0. | ||
| 301 | abort_reason?; | ||
| 302 | } | ||
| 303 | } | ||
| 304 | Ok(()) | ||
| 305 | } | ||
| 306 | |||
| 307 | // ========================= | ||
| 308 | // Blocking public API | ||
| 309 | // ========================= | ||
| 310 | |||
| 311 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 312 | Self::setup(address.into())?; | ||
| 313 | self.read_blocking_internal(buffer, true, true) | ||
| 314 | // Automatic Stop | ||
| 315 | } | ||
| 316 | |||
| 317 | pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { | ||
| 318 | Self::setup(address.into())?; | ||
| 319 | self.write_blocking_internal(bytes, true) | ||
| 320 | } | ||
| 321 | |||
| 322 | pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { | ||
| 323 | Self::setup(address.into())?; | ||
| 324 | self.write_blocking_internal(bytes, false)?; | ||
| 325 | self.read_blocking_internal(buffer, true, true) | ||
| 326 | // Automatic Stop | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | mod eh02 { | ||
| 331 | use super::*; | ||
| 332 | |||
| 333 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> { | ||
| 334 | type Error = Error; | ||
| 335 | |||
| 336 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 337 | self.blocking_read(address, buffer) | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, M> { | ||
| 342 | type Error = Error; | ||
| 343 | |||
| 344 | fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { | ||
| 345 | self.blocking_write(address, bytes) | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, M> { | ||
| 350 | type Error = Error; | ||
| 351 | |||
| 352 | fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 353 | self.blocking_write_read(address, bytes, buffer) | ||
| 354 | } | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | #[cfg(feature = "unstable-traits")] | ||
| 359 | mod eh1 { | ||
| 360 | use super::*; | ||
| 361 | |||
| 362 | impl embedded_hal_1::i2c::Error for Error { | ||
| 363 | fn kind(&self) -> embedded_hal_1::i2c::ErrorKind { | ||
| 364 | match *self { | ||
| 365 | Self::Abort(AbortReason::ArbitrationLoss) => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss, | ||
| 366 | Self::Abort(AbortReason::NoAcknowledge) => { | ||
| 367 | embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) | ||
| 368 | } | ||
| 369 | Self::Abort(AbortReason::Other(_)) => embedded_hal_1::i2c::ErrorKind::Other, | ||
| 370 | Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other, | ||
| 371 | Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other, | ||
| 372 | Self::AddressOutOfRange(_) => embedded_hal_1::i2c::ErrorKind::Other, | ||
| 373 | Self::AddressReserved(_) => embedded_hal_1::i2c::ErrorKind::Other, | ||
| 374 | } | ||
| 375 | } | ||
| 376 | } | ||
| 377 | |||
| 378 | impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, T, M> { | ||
| 379 | type Error = Error; | ||
| 380 | } | ||
| 381 | |||
| 382 | impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::blocking::I2c for I2c<'d, T, M> { | ||
| 383 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 384 | self.blocking_read(address, buffer) | ||
| 385 | } | ||
| 386 | |||
| 387 | fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 388 | self.blocking_write(address, buffer) | ||
| 389 | } | ||
| 390 | |||
| 391 | fn write_iter<B>(&mut self, address: u8, bytes: B) -> Result<(), Self::Error> | ||
| 392 | where | ||
| 393 | B: IntoIterator<Item = u8>, | ||
| 394 | { | ||
| 395 | let mut peekable = bytes.into_iter().peekable(); | ||
| 396 | Self::setup(address.into())?; | ||
| 397 | |||
| 398 | while let Some(tx) = peekable.next() { | ||
| 399 | self.write_blocking_internal(&[tx], peekable.peek().is_none())?; | ||
| 400 | } | ||
| 401 | Ok(()) | ||
| 402 | } | ||
| 403 | |||
| 404 | fn write_iter_read<B>(&mut self, address: u8, bytes: B, buffer: &mut [u8]) -> Result<(), Self::Error> | ||
| 405 | where | ||
| 406 | B: IntoIterator<Item = u8>, | ||
| 407 | { | ||
| 408 | let peekable = bytes.into_iter().peekable(); | ||
| 409 | Self::setup(address.into())?; | ||
| 410 | |||
| 411 | for tx in peekable { | ||
| 412 | self.write_blocking_internal(&[tx], false)? | ||
| 413 | } | ||
| 414 | self.read_blocking_internal(buffer, true, true) | ||
| 415 | } | ||
| 416 | |||
| 417 | fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 418 | self.blocking_write_read(address, wr_buffer, rd_buffer) | ||
| 419 | } | ||
| 420 | |||
| 421 | fn transaction<'a>( | ||
| 422 | &mut self, | ||
| 423 | address: u8, | ||
| 424 | operations: &mut [embedded_hal_1::i2c::blocking::Operation<'a>], | ||
| 425 | ) -> Result<(), Self::Error> { | ||
| 426 | Self::setup(address.into())?; | ||
| 427 | for i in 0..operations.len() { | ||
| 428 | let last = i == operations.len() - 1; | ||
| 429 | match &mut operations[i] { | ||
| 430 | embedded_hal_1::i2c::blocking::Operation::Read(buf) => { | ||
| 431 | self.read_blocking_internal(buf, false, last)? | ||
| 432 | } | ||
| 433 | embedded_hal_1::i2c::blocking::Operation::Write(buf) => self.write_blocking_internal(buf, last)?, | ||
| 434 | } | ||
| 435 | } | ||
| 436 | Ok(()) | ||
| 437 | } | ||
| 438 | |||
| 439 | fn transaction_iter<'a, O>(&mut self, address: u8, operations: O) -> Result<(), Self::Error> | ||
| 440 | where | ||
| 441 | O: IntoIterator<Item = embedded_hal_1::i2c::blocking::Operation<'a>>, | ||
| 442 | { | ||
| 443 | Self::setup(address.into())?; | ||
| 444 | let mut peekable = operations.into_iter().peekable(); | ||
| 445 | while let Some(operation) = peekable.next() { | ||
| 446 | let last = peekable.peek().is_none(); | ||
| 447 | match operation { | ||
| 448 | embedded_hal_1::i2c::blocking::Operation::Read(buf) => { | ||
| 449 | self.read_blocking_internal(buf, false, last)? | ||
| 450 | } | ||
| 451 | embedded_hal_1::i2c::blocking::Operation::Write(buf) => self.write_blocking_internal(buf, last)?, | ||
| 452 | } | ||
| 453 | } | ||
| 454 | Ok(()) | ||
| 455 | } | ||
| 456 | } | ||
| 457 | } | ||
| 458 | |||
| 459 | fn i2c_reserved_addr(addr: u16) -> bool { | ||
| 460 | (addr & 0x78) == 0 || (addr & 0x78) == 0x78 | ||
| 461 | } | ||
| 462 | |||
| 463 | mod sealed { | ||
| 464 | use embassy_cortex_m::interrupt::Interrupt; | ||
| 465 | |||
| 466 | pub trait Instance { | ||
| 467 | const TX_DREQ: u8; | ||
| 468 | const RX_DREQ: u8; | ||
| 469 | |||
| 470 | type Interrupt: Interrupt; | ||
| 471 | |||
| 472 | fn regs() -> crate::pac::i2c::I2c; | ||
| 473 | } | ||
| 474 | |||
| 475 | pub trait Mode {} | ||
| 476 | |||
| 477 | pub trait SdaPin<T: Instance> {} | ||
| 478 | pub trait SclPin<T: Instance> {} | ||
| 479 | } | ||
| 480 | |||
| 481 | pub trait Mode: sealed::Mode {} | ||
| 482 | |||
| 483 | macro_rules! impl_mode { | ||
| 484 | ($name:ident) => { | ||
| 485 | impl sealed::Mode for $name {} | ||
| 486 | impl Mode for $name {} | ||
| 487 | }; | ||
| 488 | } | ||
| 489 | |||
| 490 | pub struct Blocking; | ||
| 491 | pub struct Async; | ||
| 492 | |||
| 493 | impl_mode!(Blocking); | ||
| 494 | impl_mode!(Async); | ||
| 495 | |||
| 496 | pub trait Instance: sealed::Instance {} | ||
| 497 | |||
| 498 | macro_rules! impl_instance { | ||
| 499 | ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { | ||
| 500 | impl sealed::Instance for peripherals::$type { | ||
| 501 | const TX_DREQ: u8 = $tx_dreq; | ||
| 502 | const RX_DREQ: u8 = $rx_dreq; | ||
| 503 | |||
| 504 | type Interrupt = crate::interrupt::$irq; | ||
| 505 | |||
| 506 | fn regs() -> pac::i2c::I2c { | ||
| 507 | pac::$type | ||
| 508 | } | ||
| 509 | } | ||
| 510 | impl Instance for peripherals::$type {} | ||
| 511 | }; | ||
| 512 | } | ||
| 513 | |||
| 514 | impl_instance!(I2C0, I2C0_IRQ, 32, 33); | ||
| 515 | impl_instance!(I2C1, I2C1_IRQ, 34, 35); | ||
| 516 | |||
| 517 | pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {} | ||
| 518 | pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {} | ||
| 519 | |||
| 520 | macro_rules! impl_pin { | ||
| 521 | ($pin:ident, $instance:ident, $function:ident) => { | ||
| 522 | impl sealed::$function<peripherals::$instance> for peripherals::$pin {} | ||
| 523 | impl $function<peripherals::$instance> for peripherals::$pin {} | ||
| 524 | }; | ||
| 525 | } | ||
| 526 | |||
| 527 | impl_pin!(PIN_0, I2C0, SdaPin); | ||
| 528 | impl_pin!(PIN_1, I2C0, SclPin); | ||
| 529 | impl_pin!(PIN_2, I2C1, SdaPin); | ||
| 530 | impl_pin!(PIN_3, I2C1, SclPin); | ||
| 531 | impl_pin!(PIN_4, I2C0, SdaPin); | ||
| 532 | impl_pin!(PIN_5, I2C0, SclPin); | ||
| 533 | impl_pin!(PIN_6, I2C1, SdaPin); | ||
| 534 | impl_pin!(PIN_7, I2C1, SclPin); | ||
| 535 | impl_pin!(PIN_8, I2C0, SdaPin); | ||
| 536 | impl_pin!(PIN_9, I2C0, SclPin); | ||
| 537 | impl_pin!(PIN_10, I2C1, SdaPin); | ||
| 538 | impl_pin!(PIN_11, I2C1, SclPin); | ||
| 539 | impl_pin!(PIN_12, I2C0, SdaPin); | ||
| 540 | impl_pin!(PIN_13, I2C0, SclPin); | ||
| 541 | impl_pin!(PIN_14, I2C1, SdaPin); | ||
| 542 | impl_pin!(PIN_15, I2C1, SclPin); | ||
| 543 | impl_pin!(PIN_16, I2C0, SdaPin); | ||
| 544 | impl_pin!(PIN_17, I2C0, SclPin); | ||
| 545 | impl_pin!(PIN_18, I2C1, SdaPin); | ||
| 546 | impl_pin!(PIN_19, I2C1, SclPin); | ||
| 547 | impl_pin!(PIN_20, I2C0, SdaPin); | ||
| 548 | impl_pin!(PIN_21, I2C0, SclPin); | ||
| 549 | impl_pin!(PIN_22, I2C1, SdaPin); | ||
| 550 | impl_pin!(PIN_23, I2C1, SclPin); | ||
| 551 | impl_pin!(PIN_24, I2C0, SdaPin); | ||
| 552 | impl_pin!(PIN_25, I2C0, SclPin); | ||
| 553 | impl_pin!(PIN_26, I2C1, SdaPin); | ||
| 554 | impl_pin!(PIN_27, I2C1, SclPin); | ||
| 555 | impl_pin!(PIN_28, I2C0, SdaPin); | ||
| 556 | impl_pin!(PIN_29, I2C0, SclPin); | ||
diff --git a/embassy-rp/src/intrinsics.rs b/embassy-rp/src/intrinsics.rs index 9e6624cf0..67e8202a4 100644 --- a/embassy-rp/src/intrinsics.rs +++ b/embassy-rp/src/intrinsics.rs | |||
| @@ -1,4 +1,6 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | // Credit: taken from `rp-hal` (also licensed Apache+MIT) | ||
| 3 | // https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/intrinsics.rs | ||
| 2 | 4 | ||
| 3 | /// Generate a series of aliases for an intrinsic function. | 5 | /// Generate a series of aliases for an intrinsic function. |
| 4 | macro_rules! intrinsics_aliases { | 6 | macro_rules! intrinsics_aliases { |
| @@ -14,7 +16,7 @@ macro_rules! intrinsics_aliases { | |||
| 14 | $alias:ident | 16 | $alias:ident |
| 15 | $($rest:ident)* | 17 | $($rest:ident)* |
| 16 | ) => { | 18 | ) => { |
| 17 | #[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))] | 19 | #[cfg(all(target_arch = "arm", feature = "intrinsics"))] |
| 18 | intrinsics! { | 20 | intrinsics! { |
| 19 | extern $abi fn $alias( $($argname: $ty),* ) -> $ret { | 21 | extern $abi fn $alias( $($argname: $ty),* ) -> $ret { |
| 20 | $name($($argname),*) | 22 | $name($($argname),*) |
| @@ -32,7 +34,7 @@ macro_rules! intrinsics_aliases { | |||
| 32 | $alias:ident | 34 | $alias:ident |
| 33 | $($rest:ident)* | 35 | $($rest:ident)* |
| 34 | ) => { | 36 | ) => { |
| 35 | #[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))] | 37 | #[cfg(all(target_arch = "arm", feature = "intrinsics"))] |
| 36 | intrinsics! { | 38 | intrinsics! { |
| 37 | unsafe extern $abi fn $alias( $($argname: $ty),* ) -> $ret { | 39 | unsafe extern $abi fn $alias( $($argname: $ty),* ) -> $ret { |
| 38 | $name($($argname),*) | 40 | $name($($argname),*) |
| @@ -52,7 +54,7 @@ macro_rules! intrinsics_aliases { | |||
| 52 | /// is to abstract anything special that needs to be done to override an | 54 | /// is to abstract anything special that needs to be done to override an |
| 53 | /// intrinsic function. Intrinsic generation is disabled for non-ARM targets | 55 | /// intrinsic function. Intrinsic generation is disabled for non-ARM targets |
| 54 | /// so things like CI and docs generation do not have problems. Additionally | 56 | /// so things like CI and docs generation do not have problems. Additionally |
| 55 | /// they can be disabled with the crate feature `disable-intrinsics` for | 57 | /// they can be disabled by disabling the crate feature `intrinsics` for |
| 56 | /// testing or comparing performance. | 58 | /// testing or comparing performance. |
| 57 | /// | 59 | /// |
| 58 | /// Like the compiler-builtins macro, it accepts a series of functions that | 60 | /// Like the compiler-builtins macro, it accepts a series of functions that |
| @@ -211,13 +213,13 @@ macro_rules! intrinsics { | |||
| 211 | 213 | ||
| 212 | $($rest:tt)* | 214 | $($rest:tt)* |
| 213 | ) => { | 215 | ) => { |
| 214 | #[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))] | 216 | #[cfg(all(target_arch = "arm", feature = "intrinsics"))] |
| 215 | $(#[$($attr)*])* | 217 | $(#[$($attr)*])* |
| 216 | extern $abi fn $name( $($argname: $ty),* ) -> $ret { | 218 | extern $abi fn $name( $($argname: $ty),* ) -> $ret { |
| 217 | $($body)* | 219 | $($body)* |
| 218 | } | 220 | } |
| 219 | 221 | ||
| 220 | #[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))] | 222 | #[cfg(all(target_arch = "arm", feature = "intrinsics"))] |
| 221 | mod $name { | 223 | mod $name { |
| 222 | #[no_mangle] | 224 | #[no_mangle] |
| 223 | $(#[$($attr)*])* | 225 | $(#[$($attr)*])* |
| @@ -228,7 +230,7 @@ macro_rules! intrinsics { | |||
| 228 | 230 | ||
| 229 | // Not exported, but defined so the actual implementation is | 231 | // Not exported, but defined so the actual implementation is |
| 230 | // considered used | 232 | // considered used |
| 231 | #[cfg(not(all(target_arch = "arm", not(feature = "disable-intrinsics"))))] | 233 | #[cfg(not(all(target_arch = "arm", feature = "intrinsics")))] |
| 232 | #[allow(dead_code)] | 234 | #[allow(dead_code)] |
| 233 | fn $name( $($argname: $ty),* ) -> $ret { | 235 | fn $name( $($argname: $ty),* ) -> $ret { |
| 234 | $($body)* | 236 | $($body)* |
| @@ -245,13 +247,13 @@ macro_rules! intrinsics { | |||
| 245 | 247 | ||
| 246 | $($rest:tt)* | 248 | $($rest:tt)* |
| 247 | ) => { | 249 | ) => { |
| 248 | #[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))] | 250 | #[cfg(all(target_arch = "arm", feature = "intrinsics"))] |
| 249 | $(#[$($attr)*])* | 251 | $(#[$($attr)*])* |
| 250 | unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret { | 252 | unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret { |
| 251 | $($body)* | 253 | $($body)* |
| 252 | } | 254 | } |
| 253 | 255 | ||
| 254 | #[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))] | 256 | #[cfg(all(target_arch = "arm", feature = "intrinsics"))] |
| 255 | mod $name { | 257 | mod $name { |
| 256 | #[no_mangle] | 258 | #[no_mangle] |
| 257 | $(#[$($attr)*])* | 259 | $(#[$($attr)*])* |
| @@ -262,7 +264,7 @@ macro_rules! intrinsics { | |||
| 262 | 264 | ||
| 263 | // Not exported, but defined so the actual implementation is | 265 | // Not exported, but defined so the actual implementation is |
| 264 | // considered used | 266 | // considered used |
| 265 | #[cfg(not(all(target_arch = "arm", not(feature = "disable-intrinsics"))))] | 267 | #[cfg(not(all(target_arch = "arm", feature = "intrinsics")))] |
| 266 | #[allow(dead_code)] | 268 | #[allow(dead_code)] |
| 267 | unsafe fn $name( $($argname: $ty),* ) -> $ret { | 269 | unsafe fn $name( $($argname: $ty),* ) -> $ret { |
| 268 | $($body)* | 270 | $($body)* |
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index ce013b09c..445639618 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs | |||
| @@ -8,6 +8,7 @@ mod intrinsics; | |||
| 8 | 8 | ||
| 9 | pub mod dma; | 9 | pub mod dma; |
| 10 | pub mod gpio; | 10 | pub mod gpio; |
| 11 | pub mod i2c; | ||
| 11 | pub mod interrupt; | 12 | pub mod interrupt; |
| 12 | pub mod rom_data; | 13 | pub mod rom_data; |
| 13 | pub mod rtc; | 14 | pub mod rtc; |
| @@ -76,6 +77,9 @@ embassy_hal_common::peripherals! { | |||
| 76 | SPI0, | 77 | SPI0, |
| 77 | SPI1, | 78 | SPI1, |
| 78 | 79 | ||
| 80 | I2C0, | ||
| 81 | I2C1, | ||
| 82 | |||
| 79 | DMA_CH0, | 83 | DMA_CH0, |
| 80 | DMA_CH1, | 84 | DMA_CH1, |
| 81 | DMA_CH2, | 85 | DMA_CH2, |
diff --git a/embassy-rp/src/rom_data.rs b/embassy-rp/src/rom_data.rs index 93a3632a5..8e953dcf2 100644 --- a/embassy-rp/src/rom_data.rs +++ b/embassy-rp/src/rom_data.rs | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | //! > on the device, as well as highly optimized versions of certain key | 7 | //! > on the device, as well as highly optimized versions of certain key |
| 8 | //! > functionality that would otherwise have to take up space in most user | 8 | //! > functionality that would otherwise have to take up space in most user |
| 9 | //! > binaries. | 9 | //! > binaries. |
| 10 | // Credit: taken from `rp-hal` (also licensed Apache+MIT) | ||
| 11 | // https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/rom_data.rs | ||
| 10 | 12 | ||
| 11 | /// A bootrom function table code. | 13 | /// A bootrom function table code. |
| 12 | pub type RomFnTableCode = [u8; 2]; | 14 | pub type RomFnTableCode = [u8; 2]; |
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs new file mode 100644 index 000000000..87e16f0eb --- /dev/null +++ b/embassy-rp/src/uart/buffered.rs | |||
| @@ -0,0 +1,489 @@ | |||
| 1 | use core::future::{poll_fn, Future}; | ||
| 2 | use core::task::{Poll, Waker}; | ||
| 3 | |||
| 4 | use atomic_polyfill::{compiler_fence, Ordering}; | ||
| 5 | use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; | ||
| 6 | use embassy_hal_common::ring_buffer::RingBuffer; | ||
| 7 | use embassy_sync::waitqueue::WakerRegistration; | ||
| 8 | |||
| 9 | use super::*; | ||
| 10 | |||
| 11 | pub struct State<'d, T: Instance>(StateStorage<FullStateInner<'d, T>>); | ||
| 12 | impl<'d, T: Instance> State<'d, T> { | ||
| 13 | pub const fn new() -> Self { | ||
| 14 | Self(StateStorage::new()) | ||
| 15 | } | ||
| 16 | } | ||
| 17 | |||
| 18 | pub struct RxState<'d, T: Instance>(StateStorage<RxStateInner<'d, T>>); | ||
| 19 | impl<'d, T: Instance> RxState<'d, T> { | ||
| 20 | pub const fn new() -> Self { | ||
| 21 | Self(StateStorage::new()) | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | pub struct TxState<'d, T: Instance>(StateStorage<TxStateInner<'d, T>>); | ||
| 26 | impl<'d, T: Instance> TxState<'d, T> { | ||
| 27 | pub const fn new() -> Self { | ||
| 28 | Self(StateStorage::new()) | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | struct RxStateInner<'d, T: Instance> { | ||
| 33 | phantom: PhantomData<&'d mut T>, | ||
| 34 | |||
| 35 | waker: WakerRegistration, | ||
| 36 | buf: RingBuffer<'d>, | ||
| 37 | } | ||
| 38 | |||
| 39 | struct TxStateInner<'d, T: Instance> { | ||
| 40 | phantom: PhantomData<&'d mut T>, | ||
| 41 | |||
| 42 | waker: WakerRegistration, | ||
| 43 | buf: RingBuffer<'d>, | ||
| 44 | } | ||
| 45 | |||
| 46 | struct FullStateInner<'d, T: Instance> { | ||
| 47 | rx: RxStateInner<'d, T>, | ||
| 48 | tx: TxStateInner<'d, T>, | ||
| 49 | } | ||
| 50 | |||
| 51 | unsafe impl<'d, T: Instance> Send for RxStateInner<'d, T> {} | ||
| 52 | unsafe impl<'d, T: Instance> Sync for RxStateInner<'d, T> {} | ||
| 53 | |||
| 54 | unsafe impl<'d, T: Instance> Send for TxStateInner<'d, T> {} | ||
| 55 | unsafe impl<'d, T: Instance> Sync for TxStateInner<'d, T> {} | ||
| 56 | |||
| 57 | unsafe impl<'d, T: Instance> Send for FullStateInner<'d, T> {} | ||
| 58 | unsafe impl<'d, T: Instance> Sync for FullStateInner<'d, T> {} | ||
| 59 | |||
| 60 | pub struct BufferedUart<'d, T: Instance> { | ||
| 61 | inner: PeripheralMutex<'d, FullStateInner<'d, T>>, | ||
| 62 | } | ||
| 63 | |||
| 64 | pub struct BufferedUartRx<'d, T: Instance> { | ||
| 65 | inner: PeripheralMutex<'d, RxStateInner<'d, T>>, | ||
| 66 | } | ||
| 67 | |||
| 68 | pub struct BufferedUartTx<'d, T: Instance> { | ||
| 69 | inner: PeripheralMutex<'d, TxStateInner<'d, T>>, | ||
| 70 | } | ||
| 71 | |||
| 72 | impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} | ||
| 73 | impl<'d, T: Instance> Unpin for BufferedUartRx<'d, T> {} | ||
| 74 | impl<'d, T: Instance> Unpin for BufferedUartTx<'d, T> {} | ||
| 75 | |||
| 76 | impl<'d, T: Instance> BufferedUart<'d, T> { | ||
| 77 | pub fn new<M: Mode>( | ||
| 78 | state: &'d mut State<'d, T>, | ||
| 79 | _uart: Uart<'d, T, M>, | ||
| 80 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 81 | tx_buffer: &'d mut [u8], | ||
| 82 | rx_buffer: &'d mut [u8], | ||
| 83 | ) -> BufferedUart<'d, T> { | ||
| 84 | into_ref!(irq); | ||
| 85 | |||
| 86 | let r = T::regs(); | ||
| 87 | unsafe { | ||
| 88 | r.uartimsc().modify(|w| { | ||
| 89 | w.set_rxim(true); | ||
| 90 | w.set_rtim(true); | ||
| 91 | w.set_txim(true); | ||
| 92 | }); | ||
| 93 | } | ||
| 94 | |||
| 95 | Self { | ||
| 96 | inner: PeripheralMutex::new(irq, &mut state.0, move || FullStateInner { | ||
| 97 | tx: TxStateInner { | ||
| 98 | phantom: PhantomData, | ||
| 99 | waker: WakerRegistration::new(), | ||
| 100 | buf: RingBuffer::new(tx_buffer), | ||
| 101 | }, | ||
| 102 | rx: RxStateInner { | ||
| 103 | phantom: PhantomData, | ||
| 104 | waker: WakerRegistration::new(), | ||
| 105 | buf: RingBuffer::new(rx_buffer), | ||
| 106 | }, | ||
| 107 | }), | ||
| 108 | } | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | impl<'d, T: Instance> BufferedUartRx<'d, T> { | ||
| 113 | pub fn new<M: Mode>( | ||
| 114 | state: &'d mut RxState<'d, T>, | ||
| 115 | _uart: UartRx<'d, T, M>, | ||
| 116 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 117 | rx_buffer: &'d mut [u8], | ||
| 118 | ) -> BufferedUartRx<'d, T> { | ||
| 119 | into_ref!(irq); | ||
| 120 | |||
| 121 | let r = T::regs(); | ||
| 122 | unsafe { | ||
| 123 | r.uartimsc().modify(|w| { | ||
| 124 | w.set_rxim(true); | ||
| 125 | w.set_rtim(true); | ||
| 126 | }); | ||
| 127 | } | ||
| 128 | |||
| 129 | Self { | ||
| 130 | inner: PeripheralMutex::new(irq, &mut state.0, move || RxStateInner { | ||
| 131 | phantom: PhantomData, | ||
| 132 | |||
| 133 | buf: RingBuffer::new(rx_buffer), | ||
| 134 | waker: WakerRegistration::new(), | ||
| 135 | }), | ||
| 136 | } | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | impl<'d, T: Instance> BufferedUartTx<'d, T> { | ||
| 141 | pub fn new<M: Mode>( | ||
| 142 | state: &'d mut TxState<'d, T>, | ||
| 143 | _uart: UartTx<'d, T, M>, | ||
| 144 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 145 | tx_buffer: &'d mut [u8], | ||
| 146 | ) -> BufferedUartTx<'d, T> { | ||
| 147 | into_ref!(irq); | ||
| 148 | |||
| 149 | let r = T::regs(); | ||
| 150 | unsafe { | ||
| 151 | r.uartimsc().modify(|w| { | ||
| 152 | w.set_txim(true); | ||
| 153 | }); | ||
| 154 | } | ||
| 155 | |||
| 156 | Self { | ||
| 157 | inner: PeripheralMutex::new(irq, &mut state.0, move || TxStateInner { | ||
| 158 | phantom: PhantomData, | ||
| 159 | |||
| 160 | buf: RingBuffer::new(tx_buffer), | ||
| 161 | waker: WakerRegistration::new(), | ||
| 162 | }), | ||
| 163 | } | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | impl<'d, T: Instance> PeripheralState for FullStateInner<'d, T> | ||
| 168 | where | ||
| 169 | Self: 'd, | ||
| 170 | { | ||
| 171 | type Interrupt = T::Interrupt; | ||
| 172 | fn on_interrupt(&mut self) { | ||
| 173 | self.rx.on_interrupt(); | ||
| 174 | self.tx.on_interrupt(); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | impl<'d, T: Instance> RxStateInner<'d, T> | ||
| 179 | where | ||
| 180 | Self: 'd, | ||
| 181 | { | ||
| 182 | fn read(&mut self, buf: &mut [u8], waker: &Waker) -> (Poll<Result<usize, Error>>, bool) { | ||
| 183 | // We have data ready in buffer? Return it. | ||
| 184 | let mut do_pend = false; | ||
| 185 | let data = self.buf.pop_buf(); | ||
| 186 | if !data.is_empty() { | ||
| 187 | let len = data.len().min(buf.len()); | ||
| 188 | buf[..len].copy_from_slice(&data[..len]); | ||
| 189 | |||
| 190 | if self.buf.is_full() { | ||
| 191 | do_pend = true; | ||
| 192 | } | ||
| 193 | self.buf.pop(len); | ||
| 194 | |||
| 195 | return (Poll::Ready(Ok(len)), do_pend); | ||
| 196 | } | ||
| 197 | |||
| 198 | self.waker.register(waker); | ||
| 199 | (Poll::Pending, do_pend) | ||
| 200 | } | ||
| 201 | |||
| 202 | fn fill_buf<'a>(&mut self, waker: &Waker) -> Poll<Result<&'a [u8], Error>> { | ||
| 203 | // We have data ready in buffer? Return it. | ||
| 204 | let buf = self.buf.pop_buf(); | ||
| 205 | if !buf.is_empty() { | ||
| 206 | let buf: &[u8] = buf; | ||
| 207 | // Safety: buffer lives as long as uart | ||
| 208 | let buf: &[u8] = unsafe { core::mem::transmute(buf) }; | ||
| 209 | return Poll::Ready(Ok(buf)); | ||
| 210 | } | ||
| 211 | |||
| 212 | self.waker.register(waker); | ||
| 213 | Poll::Pending | ||
| 214 | } | ||
| 215 | |||
| 216 | fn consume(&mut self, amt: usize) -> bool { | ||
| 217 | let full = self.buf.is_full(); | ||
| 218 | self.buf.pop(amt); | ||
| 219 | full | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | impl<'d, T: Instance> PeripheralState for RxStateInner<'d, T> | ||
| 224 | where | ||
| 225 | Self: 'd, | ||
| 226 | { | ||
| 227 | type Interrupt = T::Interrupt; | ||
| 228 | fn on_interrupt(&mut self) { | ||
| 229 | let r = T::regs(); | ||
| 230 | unsafe { | ||
| 231 | let ris = r.uartris().read(); | ||
| 232 | // Clear interrupt flags | ||
| 233 | r.uarticr().modify(|w| { | ||
| 234 | w.set_rxic(true); | ||
| 235 | w.set_rtic(true); | ||
| 236 | }); | ||
| 237 | |||
| 238 | if ris.peris() { | ||
| 239 | warn!("Parity error"); | ||
| 240 | r.uarticr().modify(|w| { | ||
| 241 | w.set_peic(true); | ||
| 242 | }); | ||
| 243 | } | ||
| 244 | if ris.feris() { | ||
| 245 | warn!("Framing error"); | ||
| 246 | r.uarticr().modify(|w| { | ||
| 247 | w.set_feic(true); | ||
| 248 | }); | ||
| 249 | } | ||
| 250 | if ris.beris() { | ||
| 251 | warn!("Break error"); | ||
| 252 | r.uarticr().modify(|w| { | ||
| 253 | w.set_beic(true); | ||
| 254 | }); | ||
| 255 | } | ||
| 256 | if ris.oeris() { | ||
| 257 | warn!("Overrun error"); | ||
| 258 | r.uarticr().modify(|w| { | ||
| 259 | w.set_oeic(true); | ||
| 260 | }); | ||
| 261 | } | ||
| 262 | |||
| 263 | if !r.uartfr().read().rxfe() { | ||
| 264 | let buf = self.buf.push_buf(); | ||
| 265 | if !buf.is_empty() { | ||
| 266 | buf[0] = r.uartdr().read().data(); | ||
| 267 | self.buf.push(1); | ||
| 268 | } else { | ||
| 269 | warn!("RX buffer full, discard received byte"); | ||
| 270 | } | ||
| 271 | |||
| 272 | if self.buf.is_full() { | ||
| 273 | self.waker.wake(); | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | if ris.rtris() { | ||
| 278 | self.waker.wake(); | ||
| 279 | }; | ||
| 280 | } | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | impl<'d, T: Instance> TxStateInner<'d, T> | ||
| 285 | where | ||
| 286 | Self: 'd, | ||
| 287 | { | ||
| 288 | fn write(&mut self, buf: &[u8], waker: &Waker) -> (Poll<Result<usize, Error>>, bool) { | ||
| 289 | let empty = self.buf.is_empty(); | ||
| 290 | let tx_buf = self.buf.push_buf(); | ||
| 291 | if tx_buf.is_empty() { | ||
| 292 | self.waker.register(waker); | ||
| 293 | return (Poll::Pending, empty); | ||
| 294 | } | ||
| 295 | |||
| 296 | let n = core::cmp::min(tx_buf.len(), buf.len()); | ||
| 297 | tx_buf[..n].copy_from_slice(&buf[..n]); | ||
| 298 | self.buf.push(n); | ||
| 299 | |||
| 300 | (Poll::Ready(Ok(n)), empty) | ||
| 301 | } | ||
| 302 | |||
| 303 | fn flush(&mut self, waker: &Waker) -> Poll<Result<(), Error>> { | ||
| 304 | if !self.buf.is_empty() { | ||
| 305 | self.waker.register(waker); | ||
| 306 | return Poll::Pending; | ||
| 307 | } | ||
| 308 | |||
| 309 | Poll::Ready(Ok(())) | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | impl<'d, T: Instance> PeripheralState for TxStateInner<'d, T> | ||
| 314 | where | ||
| 315 | Self: 'd, | ||
| 316 | { | ||
| 317 | type Interrupt = T::Interrupt; | ||
| 318 | fn on_interrupt(&mut self) { | ||
| 319 | let r = T::regs(); | ||
| 320 | unsafe { | ||
| 321 | let buf = self.buf.pop_buf(); | ||
| 322 | if !buf.is_empty() { | ||
| 323 | r.uartimsc().modify(|w| { | ||
| 324 | w.set_txim(true); | ||
| 325 | }); | ||
| 326 | r.uartdr().write(|w| w.set_data(buf[0].into())); | ||
| 327 | self.buf.pop(1); | ||
| 328 | self.waker.wake(); | ||
| 329 | } else { | ||
| 330 | // Disable interrupt until we have something to transmit again | ||
| 331 | r.uartimsc().modify(|w| { | ||
| 332 | w.set_txim(false); | ||
| 333 | }); | ||
| 334 | } | ||
| 335 | } | ||
| 336 | } | ||
| 337 | } | ||
| 338 | |||
| 339 | impl embedded_io::Error for Error { | ||
| 340 | fn kind(&self) -> embedded_io::ErrorKind { | ||
| 341 | embedded_io::ErrorKind::Other | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | impl<'d, T: Instance> embedded_io::Io for BufferedUart<'d, T> { | ||
| 346 | type Error = Error; | ||
| 347 | } | ||
| 348 | |||
| 349 | impl<'d, T: Instance> embedded_io::Io for BufferedUartRx<'d, T> { | ||
| 350 | type Error = Error; | ||
| 351 | } | ||
| 352 | |||
| 353 | impl<'d, T: Instance> embedded_io::Io for BufferedUartTx<'d, T> { | ||
| 354 | type Error = Error; | ||
| 355 | } | ||
| 356 | |||
| 357 | impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> { | ||
| 358 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 359 | where | ||
| 360 | Self: 'a; | ||
| 361 | |||
| 362 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 363 | poll_fn(move |cx| { | ||
| 364 | let (res, do_pend) = self.inner.with(|state| { | ||
| 365 | compiler_fence(Ordering::SeqCst); | ||
| 366 | state.rx.read(buf, cx.waker()) | ||
| 367 | }); | ||
| 368 | |||
| 369 | if do_pend { | ||
| 370 | self.inner.pend(); | ||
| 371 | } | ||
| 372 | |||
| 373 | res | ||
| 374 | }) | ||
| 375 | } | ||
| 376 | } | ||
| 377 | |||
| 378 | impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUartRx<'d, T> { | ||
| 379 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 380 | where | ||
| 381 | Self: 'a; | ||
| 382 | |||
| 383 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 384 | poll_fn(move |cx| { | ||
| 385 | let (res, do_pend) = self.inner.with(|state| { | ||
| 386 | compiler_fence(Ordering::SeqCst); | ||
| 387 | state.read(buf, cx.waker()) | ||
| 388 | }); | ||
| 389 | |||
| 390 | if do_pend { | ||
| 391 | self.inner.pend(); | ||
| 392 | } | ||
| 393 | |||
| 394 | res | ||
| 395 | }) | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> { | ||
| 400 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> | ||
| 401 | where | ||
| 402 | Self: 'a; | ||
| 403 | |||
| 404 | fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> { | ||
| 405 | poll_fn(move |cx| { | ||
| 406 | self.inner.with(|state| { | ||
| 407 | compiler_fence(Ordering::SeqCst); | ||
| 408 | state.rx.fill_buf(cx.waker()) | ||
| 409 | }) | ||
| 410 | }) | ||
| 411 | } | ||
| 412 | |||
| 413 | fn consume(&mut self, amt: usize) { | ||
| 414 | let signal = self.inner.with(|state| state.rx.consume(amt)); | ||
| 415 | if signal { | ||
| 416 | self.inner.pend(); | ||
| 417 | } | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUartRx<'d, T> { | ||
| 422 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> | ||
| 423 | where | ||
| 424 | Self: 'a; | ||
| 425 | |||
| 426 | fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> { | ||
| 427 | poll_fn(move |cx| { | ||
| 428 | self.inner.with(|state| { | ||
| 429 | compiler_fence(Ordering::SeqCst); | ||
| 430 | state.fill_buf(cx.waker()) | ||
| 431 | }) | ||
| 432 | }) | ||
| 433 | } | ||
| 434 | |||
| 435 | fn consume(&mut self, amt: usize) { | ||
| 436 | let signal = self.inner.with(|state| state.consume(amt)); | ||
| 437 | if signal { | ||
| 438 | self.inner.pend(); | ||
| 439 | } | ||
| 440 | } | ||
| 441 | } | ||
| 442 | |||
| 443 | impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> { | ||
| 444 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 445 | where | ||
| 446 | Self: 'a; | ||
| 447 | |||
| 448 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 449 | poll_fn(move |cx| { | ||
| 450 | let (poll, empty) = self.inner.with(|state| state.tx.write(buf, cx.waker())); | ||
| 451 | if empty { | ||
| 452 | self.inner.pend(); | ||
| 453 | } | ||
| 454 | poll | ||
| 455 | }) | ||
| 456 | } | ||
| 457 | |||
| 458 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | ||
| 459 | where | ||
| 460 | Self: 'a; | ||
| 461 | |||
| 462 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | ||
| 463 | poll_fn(move |cx| self.inner.with(|state| state.tx.flush(cx.waker()))) | ||
| 464 | } | ||
| 465 | } | ||
| 466 | |||
| 467 | impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T> { | ||
| 468 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | ||
| 469 | where | ||
| 470 | Self: 'a; | ||
| 471 | |||
| 472 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 473 | poll_fn(move |cx| { | ||
| 474 | let (poll, empty) = self.inner.with(|state| state.write(buf, cx.waker())); | ||
| 475 | if empty { | ||
| 476 | self.inner.pend(); | ||
| 477 | } | ||
| 478 | poll | ||
| 479 | }) | ||
| 480 | } | ||
| 481 | |||
| 482 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | ||
| 483 | where | ||
| 484 | Self: 'a; | ||
| 485 | |||
| 486 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | ||
| 487 | poll_fn(move |cx| self.inner.with(|state| state.flush(cx.waker()))) | ||
| 488 | } | ||
| 489 | } | ||
diff --git a/embassy-rp/src/uart.rs b/embassy-rp/src/uart/mod.rs index 987b716b4..567c79db3 100644 --- a/embassy-rp/src/uart.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -346,6 +346,11 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { | |||
| 346 | w.set_fen(true); | 346 | w.set_fen(true); |
| 347 | }); | 347 | }); |
| 348 | 348 | ||
| 349 | r.uartifls().write(|w| { | ||
| 350 | w.set_rxiflsel(0b000); | ||
| 351 | w.set_txiflsel(0b000); | ||
| 352 | }); | ||
| 353 | |||
| 349 | r.uartcr().write(|w| { | 354 | r.uartcr().write(|w| { |
| 350 | w.set_uarten(true); | 355 | w.set_uarten(true); |
| 351 | w.set_rxe(true); | 356 | w.set_rxe(true); |
| @@ -423,9 +428,11 @@ mod eh02 { | |||
| 423 | 428 | ||
| 424 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> { | 429 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> { |
| 425 | type Error = Error; | 430 | type Error = Error; |
| 431 | |||
| 426 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | 432 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { |
| 427 | self.blocking_write(buffer) | 433 | self.blocking_write(buffer) |
| 428 | } | 434 | } |
| 435 | |||
| 429 | fn bflush(&mut self) -> Result<(), Self::Error> { | 436 | fn bflush(&mut self) -> Result<(), Self::Error> { |
| 430 | self.blocking_flush() | 437 | self.blocking_flush() |
| 431 | } | 438 | } |
| @@ -433,6 +440,7 @@ mod eh02 { | |||
| 433 | 440 | ||
| 434 | impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> { | 441 | impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> { |
| 435 | type Error = Error; | 442 | type Error = Error; |
| 443 | |||
| 436 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { | 444 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { |
| 437 | embedded_hal_02::serial::Read::read(&mut self.rx) | 445 | embedded_hal_02::serial::Read::read(&mut self.rx) |
| 438 | } | 446 | } |
| @@ -440,9 +448,11 @@ mod eh02 { | |||
| 440 | 448 | ||
| 441 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> { | 449 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> { |
| 442 | type Error = Error; | 450 | type Error = Error; |
| 451 | |||
| 443 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | 452 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { |
| 444 | self.blocking_write(buffer) | 453 | self.blocking_write(buffer) |
| 445 | } | 454 | } |
| 455 | |||
| 446 | fn bflush(&mut self) -> Result<(), Self::Error> { | 456 | fn bflush(&mut self) -> Result<(), Self::Error> { |
| 447 | self.blocking_flush() | 457 | self.blocking_flush() |
| 448 | } | 458 | } |
| @@ -475,6 +485,75 @@ mod eh1 { | |||
| 475 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> { | 485 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> { |
| 476 | type Error = Error; | 486 | type Error = Error; |
| 477 | } | 487 | } |
| 488 | |||
| 489 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for UartRx<'d, T, M> { | ||
| 490 | fn read(&mut self) -> nb::Result<u8, Self::Error> { | ||
| 491 | let r = T::regs(); | ||
| 492 | unsafe { | ||
| 493 | let dr = r.uartdr().read(); | ||
| 494 | |||
| 495 | if dr.oe() { | ||
| 496 | Err(nb::Error::Other(Error::Overrun)) | ||
| 497 | } else if dr.be() { | ||
| 498 | Err(nb::Error::Other(Error::Break)) | ||
| 499 | } else if dr.pe() { | ||
| 500 | Err(nb::Error::Other(Error::Parity)) | ||
| 501 | } else if dr.fe() { | ||
| 502 | Err(nb::Error::Other(Error::Framing)) | ||
| 503 | } else if dr.fe() { | ||
| 504 | Ok(dr.data()) | ||
| 505 | } else { | ||
| 506 | Err(nb::Error::WouldBlock) | ||
| 507 | } | ||
| 508 | } | ||
| 509 | } | ||
| 510 | } | ||
| 511 | |||
| 512 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for UartTx<'d, T, M> { | ||
| 513 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 514 | self.blocking_write(buffer) | ||
| 515 | } | ||
| 516 | |||
| 517 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 518 | self.blocking_flush() | ||
| 519 | } | ||
| 520 | } | ||
| 521 | |||
| 522 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for UartTx<'d, T, M> { | ||
| 523 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | ||
| 524 | self.blocking_write(&[char]).map_err(nb::Error::Other) | ||
| 525 | } | ||
| 526 | |||
| 527 | fn flush(&mut self) -> nb::Result<(), Self::Error> { | ||
| 528 | self.blocking_flush().map_err(nb::Error::Other) | ||
| 529 | } | ||
| 530 | } | ||
| 531 | |||
| 532 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for Uart<'d, T, M> { | ||
| 533 | fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { | ||
| 534 | embedded_hal_02::serial::Read::read(&mut self.rx) | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 538 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for Uart<'d, T, M> { | ||
| 539 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 540 | self.blocking_write(buffer) | ||
| 541 | } | ||
| 542 | |||
| 543 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 544 | self.blocking_flush() | ||
| 545 | } | ||
| 546 | } | ||
| 547 | |||
| 548 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for Uart<'d, T, M> { | ||
| 549 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | ||
| 550 | self.blocking_write(&[char]).map_err(nb::Error::Other) | ||
| 551 | } | ||
| 552 | |||
| 553 | fn flush(&mut self) -> nb::Result<(), Self::Error> { | ||
| 554 | self.blocking_flush().map_err(nb::Error::Other) | ||
| 555 | } | ||
| 556 | } | ||
| 478 | } | 557 | } |
| 479 | 558 | ||
| 480 | #[cfg(all( | 559 | #[cfg(all( |
| @@ -532,6 +611,11 @@ mod eha { | |||
| 532 | } | 611 | } |
| 533 | } | 612 | } |
| 534 | 613 | ||
| 614 | #[cfg(feature = "nightly")] | ||
| 615 | mod buffered; | ||
| 616 | #[cfg(feature = "nightly")] | ||
| 617 | pub use buffered::*; | ||
| 618 | |||
| 535 | mod sealed { | 619 | mod sealed { |
| 536 | use super::*; | 620 | use super::*; |
| 537 | 621 | ||
| @@ -541,6 +625,8 @@ mod sealed { | |||
| 541 | const TX_DREQ: u8; | 625 | const TX_DREQ: u8; |
| 542 | const RX_DREQ: u8; | 626 | const RX_DREQ: u8; |
| 543 | 627 | ||
| 628 | type Interrupt: crate::interrupt::Interrupt; | ||
| 629 | |||
| 544 | fn regs() -> pac::uart::Uart; | 630 | fn regs() -> pac::uart::Uart; |
| 545 | } | 631 | } |
| 546 | pub trait TxPin<T: Instance> {} | 632 | pub trait TxPin<T: Instance> {} |
| @@ -572,6 +658,8 @@ macro_rules! impl_instance { | |||
| 572 | const TX_DREQ: u8 = $tx_dreq; | 658 | const TX_DREQ: u8 = $tx_dreq; |
| 573 | const RX_DREQ: u8 = $rx_dreq; | 659 | const RX_DREQ: u8 = $rx_dreq; |
| 574 | 660 | ||
| 661 | type Interrupt = crate::interrupt::$irq; | ||
| 662 | |||
| 575 | fn regs() -> pac::uart::Uart { | 663 | fn regs() -> pac::uart::Uart { |
| 576 | pac::$inst | 664 | pac::$inst |
| 577 | } | 665 | } |
| @@ -580,8 +668,8 @@ macro_rules! impl_instance { | |||
| 580 | }; | 668 | }; |
| 581 | } | 669 | } |
| 582 | 670 | ||
| 583 | impl_instance!(UART0, UART0, 20, 21); | 671 | impl_instance!(UART0, UART0_IRQ, 20, 21); |
| 584 | impl_instance!(UART1, UART1, 22, 23); | 672 | impl_instance!(UART1, UART1_IRQ, 22, 23); |
| 585 | 673 | ||
| 586 | pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} | 674 | pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} |
| 587 | pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} | 675 | pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} |
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs index a7ec5fb79..0a904aab3 100644 --- a/embassy-rp/src/usb.rs +++ b/embassy-rp/src/usb.rs | |||
| @@ -7,8 +7,10 @@ use core::task::Poll; | |||
| 7 | use atomic_polyfill::compiler_fence; | 7 | use atomic_polyfill::compiler_fence; |
| 8 | use embassy_hal_common::into_ref; | 8 | use embassy_hal_common::into_ref; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 10 | use embassy_usb::driver::{self, EndpointAllocError, EndpointError, Event, Unsupported}; | 10 | use embassy_usb_driver as driver; |
| 11 | use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; | 11 | use embassy_usb_driver::{ |
| 12 | Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, | ||
| 13 | }; | ||
| 12 | 14 | ||
| 13 | use crate::interrupt::{Interrupt, InterruptExt}; | 15 | use crate::interrupt::{Interrupt, InterruptExt}; |
| 14 | use crate::{pac, peripherals, Peripheral, RegExt}; | 16 | use crate::{pac, peripherals, Peripheral, RegExt}; |
| @@ -204,8 +206,8 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 204 | ); | 206 | ); |
| 205 | 207 | ||
| 206 | let alloc = match D::dir() { | 208 | let alloc = match D::dir() { |
| 207 | UsbDirection::Out => &mut self.ep_out, | 209 | Direction::Out => &mut self.ep_out, |
| 208 | UsbDirection::In => &mut self.ep_in, | 210 | Direction::In => &mut self.ep_in, |
| 209 | }; | 211 | }; |
| 210 | 212 | ||
| 211 | let index = alloc.iter_mut().enumerate().find(|(i, ep)| { | 213 | let index = alloc.iter_mut().enumerate().find(|(i, ep)| { |
| @@ -254,7 +256,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 254 | }; | 256 | }; |
| 255 | 257 | ||
| 256 | match D::dir() { | 258 | match D::dir() { |
| 257 | UsbDirection::Out => unsafe { | 259 | Direction::Out => unsafe { |
| 258 | T::dpram().ep_out_control(index - 1).write(|w| { | 260 | T::dpram().ep_out_control(index - 1).write(|w| { |
| 259 | w.set_enable(false); | 261 | w.set_enable(false); |
| 260 | w.set_buffer_address(addr); | 262 | w.set_buffer_address(addr); |
| @@ -262,7 +264,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 262 | w.set_endpoint_type(ep_type_reg); | 264 | w.set_endpoint_type(ep_type_reg); |
| 263 | }) | 265 | }) |
| 264 | }, | 266 | }, |
| 265 | UsbDirection::In => unsafe { | 267 | Direction::In => unsafe { |
| 266 | T::dpram().ep_in_control(index - 1).write(|w| { | 268 | T::dpram().ep_in_control(index - 1).write(|w| { |
| 267 | w.set_enable(false); | 269 | w.set_enable(false); |
| 268 | w.set_buffer_address(addr); | 270 | w.set_buffer_address(addr); |
| @@ -429,14 +431,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 429 | 431 | ||
| 430 | let n = ep_addr.index(); | 432 | let n = ep_addr.index(); |
| 431 | match ep_addr.direction() { | 433 | match ep_addr.direction() { |
| 432 | UsbDirection::In => unsafe { | 434 | Direction::In => unsafe { |
| 433 | T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled)); | 435 | T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled)); |
| 434 | T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| { | 436 | T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| { |
| 435 | w.set_pid(0, true); // first packet is DATA0, but PID is flipped before | 437 | w.set_pid(0, true); // first packet is DATA0, but PID is flipped before |
| 436 | }); | 438 | }); |
| 437 | EP_IN_WAKERS[n].wake(); | 439 | EP_IN_WAKERS[n].wake(); |
| 438 | }, | 440 | }, |
| 439 | UsbDirection::Out => unsafe { | 441 | Direction::Out => unsafe { |
| 440 | T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled)); | 442 | T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled)); |
| 441 | 443 | ||
| 442 | T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| { | 444 | T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| { |
| @@ -474,14 +476,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 474 | } | 476 | } |
| 475 | 477 | ||
| 476 | trait Dir { | 478 | trait Dir { |
| 477 | fn dir() -> UsbDirection; | 479 | fn dir() -> Direction; |
| 478 | fn waker(i: usize) -> &'static AtomicWaker; | 480 | fn waker(i: usize) -> &'static AtomicWaker; |
| 479 | } | 481 | } |
| 480 | 482 | ||
| 481 | pub enum In {} | 483 | pub enum In {} |
| 482 | impl Dir for In { | 484 | impl Dir for In { |
| 483 | fn dir() -> UsbDirection { | 485 | fn dir() -> Direction { |
| 484 | UsbDirection::In | 486 | Direction::In |
| 485 | } | 487 | } |
| 486 | 488 | ||
| 487 | #[inline] | 489 | #[inline] |
| @@ -492,8 +494,8 @@ impl Dir for In { | |||
| 492 | 494 | ||
| 493 | pub enum Out {} | 495 | pub enum Out {} |
| 494 | impl Dir for Out { | 496 | impl Dir for Out { |
| 495 | fn dir() -> UsbDirection { | 497 | fn dir() -> Direction { |
| 496 | UsbDirection::Out | 498 | Direction::Out |
| 497 | } | 499 | } |
| 498 | 500 | ||
| 499 | #[inline] | 501 | #[inline] |
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 484496f24..a4a232f51 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -39,7 +39,7 @@ embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = | |||
| 39 | embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } | 39 | embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } |
| 40 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } | 40 | embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } |
| 41 | embassy-net = { version = "0.1.0", path = "../embassy-net", optional = true } | 41 | embassy-net = { version = "0.1.0", path = "../embassy-net", optional = true } |
| 42 | embassy-usb = {version = "0.1.0", path = "../embassy-usb", optional = true } | 42 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } |
| 43 | 43 | ||
| 44 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 44 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 45 | embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true} | 45 | embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true} |
| @@ -73,7 +73,7 @@ quote = "1.0.15" | |||
| 73 | stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]} | 73 | stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]} |
| 74 | 74 | ||
| 75 | [features] | 75 | [features] |
| 76 | defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embedded-io?/defmt", "embassy-usb?/defmt"] | 76 | defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt"] |
| 77 | sdmmc-rs = ["embedded-sdmmc"] | 77 | sdmmc-rs = ["embedded-sdmmc"] |
| 78 | net = ["embassy-net" ] | 78 | net = ["embassy-net" ] |
| 79 | memory-x = ["stm32-metapac/memory-x"] | 79 | memory-x = ["stm32-metapac/memory-x"] |
| @@ -92,7 +92,7 @@ time-driver-tim12 = ["_time-driver"] | |||
| 92 | time-driver-tim15 = ["_time-driver"] | 92 | time-driver-tim15 = ["_time-driver"] |
| 93 | 93 | ||
| 94 | # Enable nightly-only features | 94 | # Enable nightly-only features |
| 95 | nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb", "embassy-embedded-hal/nightly"] | 95 | nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"] |
| 96 | 96 | ||
| 97 | # Reexport stm32-metapac at `embassy_stm32::pac`. | 97 | # Reexport stm32-metapac at `embassy_stm32::pac`. |
| 98 | # This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version. | 98 | # This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version. |
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index c0bd44e0f..bd92b35a0 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs | |||
| @@ -12,6 +12,7 @@ pub struct Can<'d, T: Instance> { | |||
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | impl<'d, T: Instance> Can<'d, T> { | 14 | impl<'d, T: Instance> Can<'d, T> { |
| 15 | /// Creates a new Bxcan instance, blocking for 11 recessive bits to sync with the CAN bus. | ||
| 15 | pub fn new( | 16 | pub fn new( |
| 16 | peri: impl Peripheral<P = T> + 'd, | 17 | peri: impl Peripheral<P = T> + 'd, |
| 17 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 18 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| @@ -31,6 +32,28 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 31 | can: bxcan::Can::builder(BxcanInstance(peri)).enable(), | 32 | can: bxcan::Can::builder(BxcanInstance(peri)).enable(), |
| 32 | } | 33 | } |
| 33 | } | 34 | } |
| 35 | |||
| 36 | /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. | ||
| 37 | /// You must call [Can::enable_non_blocking] to use the peripheral. | ||
| 38 | pub fn new_disabled( | ||
| 39 | peri: impl Peripheral<P = T> + 'd, | ||
| 40 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||
| 41 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | ||
| 42 | ) -> Self { | ||
| 43 | into_ref!(peri, rx, tx); | ||
| 44 | |||
| 45 | unsafe { | ||
| 46 | rx.set_as_af(rx.af_num(), AFType::Input); | ||
| 47 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 48 | } | ||
| 49 | |||
| 50 | T::enable(); | ||
| 51 | T::reset(); | ||
| 52 | |||
| 53 | Self { | ||
| 54 | can: bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(), | ||
| 55 | } | ||
| 56 | } | ||
| 34 | } | 57 | } |
| 35 | 58 | ||
| 36 | impl<'d, T: Instance> Drop for Can<'d, T> { | 59 | impl<'d, T: Instance> Drop for Can<'d, T> { |
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 46c49a997..2a711bc06 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | use core::cell::RefCell; | ||
| 1 | use core::future::{poll_fn, Future}; | 2 | use core::future::{poll_fn, Future}; |
| 2 | use core::task::Poll; | 3 | use core::task::Poll; |
| 3 | 4 | ||
| @@ -29,7 +30,15 @@ unsafe impl<'d, T: BasicInstance> Send for StateInner<'d, T> {} | |||
| 29 | unsafe impl<'d, T: BasicInstance> Sync for StateInner<'d, T> {} | 30 | unsafe impl<'d, T: BasicInstance> Sync for StateInner<'d, T> {} |
| 30 | 31 | ||
| 31 | pub struct BufferedUart<'d, T: BasicInstance> { | 32 | pub struct BufferedUart<'d, T: BasicInstance> { |
| 32 | inner: PeripheralMutex<'d, StateInner<'d, T>>, | 33 | inner: RefCell<PeripheralMutex<'d, StateInner<'d, T>>>, |
| 34 | } | ||
| 35 | |||
| 36 | pub struct BufferedUartTx<'u, 'd, T: BasicInstance> { | ||
| 37 | inner: &'u BufferedUart<'d, T>, | ||
| 38 | } | ||
| 39 | |||
| 40 | pub struct BufferedUartRx<'u, 'd, T: BasicInstance> { | ||
| 41 | inner: &'u BufferedUart<'d, T>, | ||
| 33 | } | 42 | } |
| 34 | 43 | ||
| 35 | impl<'d, T: BasicInstance> Unpin for BufferedUart<'d, T> {} | 44 | impl<'d, T: BasicInstance> Unpin for BufferedUart<'d, T> {} |
| @@ -53,14 +62,124 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 53 | } | 62 | } |
| 54 | 63 | ||
| 55 | Self { | 64 | Self { |
| 56 | inner: PeripheralMutex::new(irq, &mut state.0, move || StateInner { | 65 | inner: RefCell::new(PeripheralMutex::new(irq, &mut state.0, move || StateInner { |
| 57 | phantom: PhantomData, | 66 | phantom: PhantomData, |
| 58 | tx: RingBuffer::new(tx_buffer), | 67 | tx: RingBuffer::new(tx_buffer), |
| 59 | tx_waker: WakerRegistration::new(), | 68 | tx_waker: WakerRegistration::new(), |
| 60 | 69 | ||
| 61 | rx: RingBuffer::new(rx_buffer), | 70 | rx: RingBuffer::new(rx_buffer), |
| 62 | rx_waker: WakerRegistration::new(), | 71 | rx_waker: WakerRegistration::new(), |
| 63 | }), | 72 | })), |
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | pub fn split<'u>(&'u mut self) -> (BufferedUartRx<'u, 'd, T>, BufferedUartTx<'u, 'd, T>) { | ||
| 77 | (BufferedUartRx { inner: self }, BufferedUartTx { inner: self }) | ||
| 78 | } | ||
| 79 | |||
| 80 | async fn inner_read<'a>(&'a self, buf: &'a mut [u8]) -> Result<usize, Error> { | ||
| 81 | poll_fn(move |cx| { | ||
| 82 | let mut do_pend = false; | ||
| 83 | let mut inner = self.inner.borrow_mut(); | ||
| 84 | let res = inner.with(|state| { | ||
| 85 | compiler_fence(Ordering::SeqCst); | ||
| 86 | |||
| 87 | // We have data ready in buffer? Return it. | ||
| 88 | let data = state.rx.pop_buf(); | ||
| 89 | if !data.is_empty() { | ||
| 90 | let len = data.len().min(buf.len()); | ||
| 91 | buf[..len].copy_from_slice(&data[..len]); | ||
| 92 | |||
| 93 | if state.rx.is_full() { | ||
| 94 | do_pend = true; | ||
| 95 | } | ||
| 96 | state.rx.pop(len); | ||
| 97 | |||
| 98 | return Poll::Ready(Ok(len)); | ||
| 99 | } | ||
| 100 | |||
| 101 | state.rx_waker.register(cx.waker()); | ||
| 102 | Poll::Pending | ||
| 103 | }); | ||
| 104 | |||
| 105 | if do_pend { | ||
| 106 | inner.pend(); | ||
| 107 | } | ||
| 108 | |||
| 109 | res | ||
| 110 | }) | ||
| 111 | .await | ||
| 112 | } | ||
| 113 | |||
| 114 | async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result<usize, Error> { | ||
| 115 | poll_fn(move |cx| { | ||
| 116 | let mut inner = self.inner.borrow_mut(); | ||
| 117 | let (poll, empty) = inner.with(|state| { | ||
| 118 | let empty = state.tx.is_empty(); | ||
| 119 | let tx_buf = state.tx.push_buf(); | ||
| 120 | if tx_buf.is_empty() { | ||
| 121 | state.tx_waker.register(cx.waker()); | ||
| 122 | return (Poll::Pending, empty); | ||
| 123 | } | ||
| 124 | |||
| 125 | let n = core::cmp::min(tx_buf.len(), buf.len()); | ||
| 126 | tx_buf[..n].copy_from_slice(&buf[..n]); | ||
| 127 | state.tx.push(n); | ||
| 128 | |||
| 129 | (Poll::Ready(Ok(n)), empty) | ||
| 130 | }); | ||
| 131 | if empty { | ||
| 132 | inner.pend(); | ||
| 133 | } | ||
| 134 | poll | ||
| 135 | }) | ||
| 136 | .await | ||
| 137 | } | ||
| 138 | |||
| 139 | async fn inner_flush<'a>(&'a self) -> Result<(), Error> { | ||
| 140 | poll_fn(move |cx| { | ||
| 141 | self.inner.borrow_mut().with(|state| { | ||
| 142 | if !state.tx.is_empty() { | ||
| 143 | state.tx_waker.register(cx.waker()); | ||
| 144 | return Poll::Pending; | ||
| 145 | } | ||
| 146 | |||
| 147 | Poll::Ready(Ok(())) | ||
| 148 | }) | ||
| 149 | }) | ||
| 150 | .await | ||
| 151 | } | ||
| 152 | |||
| 153 | async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], Error> { | ||
| 154 | poll_fn(move |cx| { | ||
| 155 | self.inner.borrow_mut().with(|state| { | ||
| 156 | compiler_fence(Ordering::SeqCst); | ||
| 157 | |||
| 158 | // We have data ready in buffer? Return it. | ||
| 159 | let buf = state.rx.pop_buf(); | ||
| 160 | if !buf.is_empty() { | ||
| 161 | let buf: &[u8] = buf; | ||
| 162 | // Safety: buffer lives as long as uart | ||
| 163 | let buf: &[u8] = unsafe { core::mem::transmute(buf) }; | ||
| 164 | return Poll::Ready(Ok(buf)); | ||
| 165 | } | ||
| 166 | |||
| 167 | state.rx_waker.register(cx.waker()); | ||
| 168 | Poll::<Result<&[u8], Error>>::Pending | ||
| 169 | }) | ||
| 170 | }) | ||
| 171 | .await | ||
| 172 | } | ||
| 173 | |||
| 174 | fn inner_consume(&self, amt: usize) { | ||
| 175 | let mut inner = self.inner.borrow_mut(); | ||
| 176 | let signal = inner.with(|state| { | ||
| 177 | let full = state.rx.is_full(); | ||
| 178 | state.rx.pop(amt); | ||
| 179 | full | ||
| 180 | }); | ||
| 181 | if signal { | ||
| 182 | inner.pend(); | ||
| 64 | } | 183 | } |
| 65 | } | 184 | } |
| 66 | } | 185 | } |
| @@ -155,41 +274,31 @@ impl<'d, T: BasicInstance> embedded_io::Io for BufferedUart<'d, T> { | |||
| 155 | type Error = Error; | 274 | type Error = Error; |
| 156 | } | 275 | } |
| 157 | 276 | ||
| 277 | impl<'u, 'd, T: BasicInstance> embedded_io::Io for BufferedUartRx<'u, 'd, T> { | ||
| 278 | type Error = Error; | ||
| 279 | } | ||
| 280 | |||
| 281 | impl<'u, 'd, T: BasicInstance> embedded_io::Io for BufferedUartTx<'u, 'd, T> { | ||
| 282 | type Error = Error; | ||
| 283 | } | ||
| 284 | |||
| 158 | impl<'d, T: BasicInstance> embedded_io::asynch::Read for BufferedUart<'d, T> { | 285 | impl<'d, T: BasicInstance> embedded_io::asynch::Read for BufferedUart<'d, T> { |
| 159 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 286 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> |
| 160 | where | 287 | where |
| 161 | Self: 'a; | 288 | Self: 'a; |
| 162 | 289 | ||
| 163 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | 290 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { |
| 164 | poll_fn(move |cx| { | 291 | self.inner_read(buf) |
| 165 | let mut do_pend = false; | 292 | } |
| 166 | let res = self.inner.with(|state| { | 293 | } |
| 167 | compiler_fence(Ordering::SeqCst); | ||
| 168 | |||
| 169 | // We have data ready in buffer? Return it. | ||
| 170 | let data = state.rx.pop_buf(); | ||
| 171 | if !data.is_empty() { | ||
| 172 | let len = data.len().min(buf.len()); | ||
| 173 | buf[..len].copy_from_slice(&data[..len]); | ||
| 174 | |||
| 175 | if state.rx.is_full() { | ||
| 176 | do_pend = true; | ||
| 177 | } | ||
| 178 | state.rx.pop(len); | ||
| 179 | |||
| 180 | return Poll::Ready(Ok(len)); | ||
| 181 | } | ||
| 182 | |||
| 183 | state.rx_waker.register(cx.waker()); | ||
| 184 | Poll::Pending | ||
| 185 | }); | ||
| 186 | 294 | ||
| 187 | if do_pend { | 295 | impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Read for BufferedUartRx<'u, 'd, T> { |
| 188 | self.inner.pend(); | 296 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> |
| 189 | } | 297 | where |
| 298 | Self: 'a; | ||
| 190 | 299 | ||
| 191 | res | 300 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { |
| 192 | }) | 301 | self.inner.inner_read(buf) |
| 193 | } | 302 | } |
| 194 | } | 303 | } |
| 195 | 304 | ||
| @@ -199,34 +308,25 @@ impl<'d, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUart<'d, T> | |||
| 199 | Self: 'a; | 308 | Self: 'a; |
| 200 | 309 | ||
| 201 | fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> { | 310 | fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> { |
| 202 | poll_fn(move |cx| { | 311 | self.inner_fill_buf() |
| 203 | self.inner.with(|state| { | 312 | } |
| 204 | compiler_fence(Ordering::SeqCst); | ||
| 205 | 313 | ||
| 206 | // We have data ready in buffer? Return it. | 314 | fn consume(&mut self, amt: usize) { |
| 207 | let buf = state.rx.pop_buf(); | 315 | self.inner_consume(amt) |
| 208 | if !buf.is_empty() { | 316 | } |
| 209 | let buf: &[u8] = buf; | 317 | } |
| 210 | // Safety: buffer lives as long as uart | ||
| 211 | let buf: &[u8] = unsafe { core::mem::transmute(buf) }; | ||
| 212 | return Poll::Ready(Ok(buf)); | ||
| 213 | } | ||
| 214 | 318 | ||
| 215 | state.rx_waker.register(cx.waker()); | 319 | impl<'u, 'd, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUartRx<'u, 'd, T> { |
| 216 | Poll::<Result<&[u8], Self::Error>>::Pending | 320 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> |
| 217 | }) | 321 | where |
| 218 | }) | 322 | Self: 'a; |
| 323 | |||
| 324 | fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> { | ||
| 325 | self.inner.inner_fill_buf() | ||
| 219 | } | 326 | } |
| 220 | 327 | ||
| 221 | fn consume(&mut self, amt: usize) { | 328 | fn consume(&mut self, amt: usize) { |
| 222 | let signal = self.inner.with(|state| { | 329 | self.inner.inner_consume(amt) |
| 223 | let full = state.rx.is_full(); | ||
| 224 | state.rx.pop(amt); | ||
| 225 | full | ||
| 226 | }); | ||
| 227 | if signal { | ||
| 228 | self.inner.pend(); | ||
| 229 | } | ||
| 230 | } | 330 | } |
| 231 | } | 331 | } |
| 232 | 332 | ||
| @@ -236,26 +336,25 @@ impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> { | |||
| 236 | Self: 'a; | 336 | Self: 'a; |
| 237 | 337 | ||
| 238 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | 338 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { |
| 239 | poll_fn(move |cx| { | 339 | self.inner_write(buf) |
| 240 | let (poll, empty) = self.inner.with(|state| { | 340 | } |
| 241 | let empty = state.tx.is_empty(); | ||
| 242 | let tx_buf = state.tx.push_buf(); | ||
| 243 | if tx_buf.is_empty() { | ||
| 244 | state.tx_waker.register(cx.waker()); | ||
| 245 | return (Poll::Pending, empty); | ||
| 246 | } | ||
| 247 | 341 | ||
| 248 | let n = core::cmp::min(tx_buf.len(), buf.len()); | 342 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> |
| 249 | tx_buf[..n].copy_from_slice(&buf[..n]); | 343 | where |
| 250 | state.tx.push(n); | 344 | Self: 'a; |
| 251 | 345 | ||
| 252 | (Poll::Ready(Ok(n)), empty) | 346 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { |
| 253 | }); | 347 | self.inner_flush() |
| 254 | if empty { | 348 | } |
| 255 | self.inner.pend(); | 349 | } |
| 256 | } | 350 | |
| 257 | poll | 351 | impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Write for BufferedUartTx<'u, 'd, T> { |
| 258 | }) | 352 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> |
| 353 | where | ||
| 354 | Self: 'a; | ||
| 355 | |||
| 356 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 357 | self.inner.inner_write(buf) | ||
| 259 | } | 358 | } |
| 260 | 359 | ||
| 261 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | 360 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> |
| @@ -263,15 +362,6 @@ impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> { | |||
| 263 | Self: 'a; | 362 | Self: 'a; |
| 264 | 363 | ||
| 265 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | 364 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { |
| 266 | poll_fn(move |cx| { | 365 | self.inner.inner_flush() |
| 267 | self.inner.with(|state| { | ||
| 268 | if !state.tx.is_empty() { | ||
| 269 | state.tx_waker.register(cx.waker()); | ||
| 270 | return Poll::Pending; | ||
| 271 | } | ||
| 272 | |||
| 273 | Poll::Ready(Ok(())) | ||
| 274 | }) | ||
| 275 | }) | ||
| 276 | } | 366 | } |
| 277 | } | 367 | } |
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index e5ee1181c..2654f156a 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs | |||
| @@ -9,8 +9,10 @@ use atomic_polyfill::{AtomicBool, AtomicU8}; | |||
| 9 | use embassy_hal_common::into_ref; | 9 | use embassy_hal_common::into_ref; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | 10 | use embassy_sync::waitqueue::AtomicWaker; |
| 11 | use embassy_time::{block_for, Duration}; | 11 | use embassy_time::{block_for, Duration}; |
| 12 | use embassy_usb::driver::{self, EndpointAllocError, EndpointError, Event, Unsupported}; | 12 | use embassy_usb_driver as driver; |
| 13 | use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; | 13 | use embassy_usb_driver::{ |
| 14 | Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, | ||
| 15 | }; | ||
| 14 | use pac::common::{Reg, RW}; | 16 | use pac::common::{Reg, RW}; |
| 15 | use pac::usb::vals::{EpType, Stat}; | 17 | use pac::usb::vals::{EpType, Stat}; |
| 16 | 18 | ||
| @@ -279,8 +281,8 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 279 | } | 281 | } |
| 280 | let used = ep.used_out || ep.used_in; | 282 | let used = ep.used_out || ep.used_in; |
| 281 | let used_dir = match D::dir() { | 283 | let used_dir = match D::dir() { |
| 282 | UsbDirection::Out => ep.used_out, | 284 | Direction::Out => ep.used_out, |
| 283 | UsbDirection::In => ep.used_in, | 285 | Direction::In => ep.used_in, |
| 284 | }; | 286 | }; |
| 285 | !used || (ep.ep_type == ep_type && !used_dir) | 287 | !used || (ep.ep_type == ep_type && !used_dir) |
| 286 | }); | 288 | }); |
| @@ -293,7 +295,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 293 | ep.ep_type = ep_type; | 295 | ep.ep_type = ep_type; |
| 294 | 296 | ||
| 295 | let buf = match D::dir() { | 297 | let buf = match D::dir() { |
| 296 | UsbDirection::Out => { | 298 | Direction::Out => { |
| 297 | assert!(!ep.used_out); | 299 | assert!(!ep.used_out); |
| 298 | ep.used_out = true; | 300 | ep.used_out = true; |
| 299 | 301 | ||
| @@ -312,7 +314,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||
| 312 | _phantom: PhantomData, | 314 | _phantom: PhantomData, |
| 313 | } | 315 | } |
| 314 | } | 316 | } |
| 315 | UsbDirection::In => { | 317 | Direction::In => { |
| 316 | assert!(!ep.used_in); | 318 | assert!(!ep.used_in); |
| 317 | ep.used_in = true; | 319 | ep.used_in = true; |
| 318 | 320 | ||
| @@ -504,7 +506,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 504 | // This can race, so do a retry loop. | 506 | // This can race, so do a retry loop. |
| 505 | let reg = T::regs().epr(ep_addr.index() as _); | 507 | let reg = T::regs().epr(ep_addr.index() as _); |
| 506 | match ep_addr.direction() { | 508 | match ep_addr.direction() { |
| 507 | UsbDirection::In => { | 509 | Direction::In => { |
| 508 | loop { | 510 | loop { |
| 509 | let r = unsafe { reg.read() }; | 511 | let r = unsafe { reg.read() }; |
| 510 | match r.stat_tx() { | 512 | match r.stat_tx() { |
| @@ -523,7 +525,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 523 | } | 525 | } |
| 524 | EP_IN_WAKERS[ep_addr.index()].wake(); | 526 | EP_IN_WAKERS[ep_addr.index()].wake(); |
| 525 | } | 527 | } |
| 526 | UsbDirection::Out => { | 528 | Direction::Out => { |
| 527 | loop { | 529 | loop { |
| 528 | let r = unsafe { reg.read() }; | 530 | let r = unsafe { reg.read() }; |
| 529 | match r.stat_rx() { | 531 | match r.stat_rx() { |
| @@ -549,8 +551,8 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 549 | let regs = T::regs(); | 551 | let regs = T::regs(); |
| 550 | let epr = unsafe { regs.epr(ep_addr.index() as _).read() }; | 552 | let epr = unsafe { regs.epr(ep_addr.index() as _).read() }; |
| 551 | match ep_addr.direction() { | 553 | match ep_addr.direction() { |
| 552 | UsbDirection::In => epr.stat_tx() == Stat::STALL, | 554 | Direction::In => epr.stat_tx() == Stat::STALL, |
| 553 | UsbDirection::Out => epr.stat_rx() == Stat::STALL, | 555 | Direction::Out => epr.stat_rx() == Stat::STALL, |
| 554 | } | 556 | } |
| 555 | } | 557 | } |
| 556 | 558 | ||
| @@ -560,7 +562,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 560 | let reg = T::regs().epr(ep_addr.index() as _); | 562 | let reg = T::regs().epr(ep_addr.index() as _); |
| 561 | trace!("EPR before: {:04x}", unsafe { reg.read() }.0); | 563 | trace!("EPR before: {:04x}", unsafe { reg.read() }.0); |
| 562 | match ep_addr.direction() { | 564 | match ep_addr.direction() { |
| 563 | UsbDirection::In => { | 565 | Direction::In => { |
| 564 | loop { | 566 | loop { |
| 565 | let want_stat = match enabled { | 567 | let want_stat = match enabled { |
| 566 | false => Stat::DISABLED, | 568 | false => Stat::DISABLED, |
| @@ -576,7 +578,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 576 | } | 578 | } |
| 577 | EP_IN_WAKERS[ep_addr.index()].wake(); | 579 | EP_IN_WAKERS[ep_addr.index()].wake(); |
| 578 | } | 580 | } |
| 579 | UsbDirection::Out => { | 581 | Direction::Out => { |
| 580 | loop { | 582 | loop { |
| 581 | let want_stat = match enabled { | 583 | let want_stat = match enabled { |
| 582 | false => Stat::DISABLED, | 584 | false => Stat::DISABLED, |
| @@ -616,14 +618,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { | |||
| 616 | } | 618 | } |
| 617 | 619 | ||
| 618 | trait Dir { | 620 | trait Dir { |
| 619 | fn dir() -> UsbDirection; | 621 | fn dir() -> Direction; |
| 620 | fn waker(i: usize) -> &'static AtomicWaker; | 622 | fn waker(i: usize) -> &'static AtomicWaker; |
| 621 | } | 623 | } |
| 622 | 624 | ||
| 623 | pub enum In {} | 625 | pub enum In {} |
| 624 | impl Dir for In { | 626 | impl Dir for In { |
| 625 | fn dir() -> UsbDirection { | 627 | fn dir() -> Direction { |
| 626 | UsbDirection::In | 628 | Direction::In |
| 627 | } | 629 | } |
| 628 | 630 | ||
| 629 | #[inline] | 631 | #[inline] |
| @@ -634,8 +636,8 @@ impl Dir for In { | |||
| 634 | 636 | ||
| 635 | pub enum Out {} | 637 | pub enum Out {} |
| 636 | impl Dir for Out { | 638 | impl Dir for Out { |
| 637 | fn dir() -> UsbDirection { | 639 | fn dir() -> Direction { |
| 638 | UsbDirection::Out | 640 | Direction::Out |
| 639 | } | 641 | } |
| 640 | 642 | ||
| 641 | #[inline] | 643 | #[inline] |
diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs index b4d99513a..c3c10a8af 100644 --- a/embassy-sync/src/signal.rs +++ b/embassy-sync/src/signal.rs | |||
| @@ -1,9 +1,11 @@ | |||
| 1 | //! A synchronization primitive for passing the latest value to a task. | 1 | //! A synchronization primitive for passing the latest value to a task. |
| 2 | use core::cell::UnsafeCell; | 2 | use core::cell::Cell; |
| 3 | use core::future::{poll_fn, Future}; | 3 | use core::future::{poll_fn, Future}; |
| 4 | use core::mem; | ||
| 5 | use core::task::{Context, Poll, Waker}; | 4 | use core::task::{Context, Poll, Waker}; |
| 6 | 5 | ||
| 6 | use crate::blocking_mutex::raw::RawMutex; | ||
| 7 | use crate::blocking_mutex::Mutex; | ||
| 8 | |||
| 7 | /// Single-slot signaling primitive. | 9 | /// Single-slot signaling primitive. |
| 8 | /// | 10 | /// |
| 9 | /// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except | 11 | /// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except |
| @@ -20,16 +22,20 @@ use core::task::{Context, Poll, Waker}; | |||
| 20 | /// | 22 | /// |
| 21 | /// ``` | 23 | /// ``` |
| 22 | /// use embassy_sync::signal::Signal; | 24 | /// use embassy_sync::signal::Signal; |
| 25 | /// use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 23 | /// | 26 | /// |
| 24 | /// enum SomeCommand { | 27 | /// enum SomeCommand { |
| 25 | /// On, | 28 | /// On, |
| 26 | /// Off, | 29 | /// Off, |
| 27 | /// } | 30 | /// } |
| 28 | /// | 31 | /// |
| 29 | /// static SOME_SIGNAL: Signal<SomeCommand> = Signal::new(); | 32 | /// static SOME_SIGNAL: Signal<CriticalSectionRawMutex, SomeCommand> = Signal::new(); |
| 30 | /// ``` | 33 | /// ``` |
| 31 | pub struct Signal<T> { | 34 | pub struct Signal<M, T> |
| 32 | state: UnsafeCell<State<T>>, | 35 | where |
| 36 | M: RawMutex, | ||
| 37 | { | ||
| 38 | state: Mutex<M, Cell<State<T>>>, | ||
| 33 | } | 39 | } |
| 34 | 40 | ||
| 35 | enum State<T> { | 41 | enum State<T> { |
| @@ -38,24 +44,27 @@ enum State<T> { | |||
| 38 | Signaled(T), | 44 | Signaled(T), |
| 39 | } | 45 | } |
| 40 | 46 | ||
| 41 | unsafe impl<T: Send> Send for Signal<T> {} | 47 | impl<M, T> Signal<M, T> |
| 42 | unsafe impl<T: Send> Sync for Signal<T> {} | 48 | where |
| 43 | 49 | M: RawMutex, | |
| 44 | impl<T> Signal<T> { | 50 | { |
| 45 | /// Create a new `Signal`. | 51 | /// Create a new `Signal`. |
| 46 | pub const fn new() -> Self { | 52 | pub const fn new() -> Self { |
| 47 | Self { | 53 | Self { |
| 48 | state: UnsafeCell::new(State::None), | 54 | state: Mutex::new(Cell::new(State::None)), |
| 49 | } | 55 | } |
| 50 | } | 56 | } |
| 51 | } | 57 | } |
| 52 | 58 | ||
| 53 | impl<T: Send> Signal<T> { | 59 | impl<M, T: Send> Signal<M, T> |
| 60 | where | ||
| 61 | M: RawMutex, | ||
| 62 | { | ||
| 54 | /// Mark this Signal as signaled. | 63 | /// Mark this Signal as signaled. |
| 55 | pub fn signal(&self, val: T) { | 64 | pub fn signal(&self, val: T) { |
| 56 | critical_section::with(|_| unsafe { | 65 | self.state.lock(|cell| { |
| 57 | let state = &mut *self.state.get(); | 66 | let state = cell.replace(State::Signaled(val)); |
| 58 | if let State::Waiting(waker) = mem::replace(state, State::Signaled(val)) { | 67 | if let State::Waiting(waker) = state { |
| 59 | waker.wake(); | 68 | waker.wake(); |
| 60 | } | 69 | } |
| 61 | }) | 70 | }) |
| @@ -63,31 +72,27 @@ impl<T: Send> Signal<T> { | |||
| 63 | 72 | ||
| 64 | /// Remove the queued value in this `Signal`, if any. | 73 | /// Remove the queued value in this `Signal`, if any. |
| 65 | pub fn reset(&self) { | 74 | pub fn reset(&self) { |
| 66 | critical_section::with(|_| unsafe { | 75 | self.state.lock(|cell| cell.set(State::None)); |
| 67 | let state = &mut *self.state.get(); | ||
| 68 | *state = State::None | ||
| 69 | }) | ||
| 70 | } | 76 | } |
| 71 | 77 | ||
| 72 | /// Manually poll the Signal future. | 78 | fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> { |
| 73 | pub fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> { | 79 | self.state.lock(|cell| { |
| 74 | critical_section::with(|_| unsafe { | 80 | let state = cell.replace(State::None); |
| 75 | let state = &mut *self.state.get(); | ||
| 76 | match state { | 81 | match state { |
| 77 | State::None => { | 82 | State::None => { |
| 78 | *state = State::Waiting(cx.waker().clone()); | 83 | cell.set(State::Waiting(cx.waker().clone())); |
| 84 | Poll::Pending | ||
| 85 | } | ||
| 86 | State::Waiting(w) if w.will_wake(cx.waker()) => { | ||
| 87 | cell.set(State::Waiting(w)); | ||
| 79 | Poll::Pending | 88 | Poll::Pending |
| 80 | } | 89 | } |
| 81 | State::Waiting(w) if w.will_wake(cx.waker()) => Poll::Pending, | ||
| 82 | State::Waiting(w) => { | 90 | State::Waiting(w) => { |
| 83 | let w = mem::replace(w, cx.waker().clone()); | 91 | cell.set(State::Waiting(cx.waker().clone())); |
| 84 | w.wake(); | 92 | w.wake(); |
| 85 | Poll::Pending | 93 | Poll::Pending |
| 86 | } | 94 | } |
| 87 | State::Signaled(_) => match mem::replace(state, State::None) { | 95 | State::Signaled(res) => Poll::Ready(res), |
| 88 | State::Signaled(res) => Poll::Ready(res), | ||
| 89 | _ => unreachable!(), | ||
| 90 | }, | ||
| 91 | } | 96 | } |
| 92 | }) | 97 | }) |
| 93 | } | 98 | } |
| @@ -99,6 +104,14 @@ impl<T: Send> Signal<T> { | |||
| 99 | 104 | ||
| 100 | /// non-blocking method to check whether this signal has been signaled. | 105 | /// non-blocking method to check whether this signal has been signaled. |
| 101 | pub fn signaled(&self) -> bool { | 106 | pub fn signaled(&self) -> bool { |
| 102 | critical_section::with(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_))) | 107 | self.state.lock(|cell| { |
| 108 | let state = cell.replace(State::None); | ||
| 109 | |||
| 110 | let res = matches!(state, State::Signaled(_)); | ||
| 111 | |||
| 112 | cell.set(state); | ||
| 113 | |||
| 114 | res | ||
| 115 | }) | ||
| 103 | } | 116 | } |
| 104 | } | 117 | } |
diff --git a/embassy-usb-ncm/Cargo.toml b/embassy-usb-driver/Cargo.toml index 15d3db96f..b525df337 100644 --- a/embassy-usb-ncm/Cargo.toml +++ b/embassy-usb-driver/Cargo.toml | |||
| @@ -1,17 +1,16 @@ | |||
| 1 | [package] | 1 | [package] |
| 2 | name = "embassy-usb-ncm" | 2 | name = "embassy-usb-driver" |
| 3 | version = "0.1.0" | 3 | version = "0.1.0" |
| 4 | edition = "2021" | 4 | edition = "2021" |
| 5 | 5 | ||
| 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
| 7 | |||
| 6 | [package.metadata.embassy_docs] | 8 | [package.metadata.embassy_docs] |
| 7 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-ncm-v$VERSION/embassy-usb-ncm/src/" | 9 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-driver-v$VERSION/embassy-usb/src/" |
| 8 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-ncm/src/" | 10 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-driver/src/" |
| 9 | features = ["defmt"] | 11 | features = ["defmt"] |
| 10 | target = "thumbv7em-none-eabi" | 12 | target = "thumbv7em-none-eabi" |
| 11 | 13 | ||
| 12 | [dependencies] | 14 | [dependencies] |
| 13 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } | ||
| 14 | embassy-usb = { version = "0.1.0", path = "../embassy-usb" } | ||
| 15 | |||
| 16 | defmt = { version = "0.3", optional = true } | 15 | defmt = { version = "0.3", optional = true } |
| 17 | log = { version = "0.4.14", optional = true } | 16 | log = { version = "0.4.14", optional = true } \ No newline at end of file |
diff --git a/embassy-usb/src/driver.rs b/embassy-usb-driver/src/lib.rs index 7888f1639..fc29786fc 100644 --- a/embassy-usb/src/driver.rs +++ b/embassy-usb-driver/src/lib.rs | |||
| @@ -1,6 +1,104 @@ | |||
| 1 | #![no_std] | ||
| 2 | |||
| 1 | use core::future::Future; | 3 | use core::future::Future; |
| 2 | 4 | ||
| 3 | use super::types::*; | 5 | /// Direction of USB traffic. Note that in the USB standard the direction is always indicated from |
| 6 | /// the perspective of the host, which is backward for devices, but the standard directions are used | ||
| 7 | /// for consistency. | ||
| 8 | /// | ||
| 9 | /// The values of the enum also match the direction bit used in endpoint addresses and control | ||
| 10 | /// request types. | ||
| 11 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 12 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 13 | pub enum Direction { | ||
| 14 | /// Host to device (OUT) | ||
| 15 | Out, | ||
| 16 | /// Device to host (IN) | ||
| 17 | In, | ||
| 18 | } | ||
| 19 | |||
| 20 | /// USB endpoint transfer type. The values of this enum can be directly cast into `u8` to get the | ||
| 21 | /// transfer bmAttributes transfer type bits. | ||
| 22 | #[repr(u8)] | ||
| 23 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 24 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 25 | pub enum EndpointType { | ||
| 26 | /// Control endpoint. Used for device management. Only the host can initiate requests. Usually | ||
| 27 | /// used only endpoint 0. | ||
| 28 | Control = 0b00, | ||
| 29 | /// Isochronous endpoint. Used for time-critical unreliable data. Not implemented yet. | ||
| 30 | Isochronous = 0b01, | ||
| 31 | /// Bulk endpoint. Used for large amounts of best-effort reliable data. | ||
| 32 | Bulk = 0b10, | ||
| 33 | /// Interrupt endpoint. Used for small amounts of time-critical reliable data. | ||
| 34 | Interrupt = 0b11, | ||
| 35 | } | ||
| 36 | |||
| 37 | /// Type-safe endpoint address. | ||
| 38 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] | ||
| 39 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 40 | pub struct EndpointAddress(u8); | ||
| 41 | |||
| 42 | impl From<u8> for EndpointAddress { | ||
| 43 | #[inline] | ||
| 44 | fn from(addr: u8) -> EndpointAddress { | ||
| 45 | EndpointAddress(addr) | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | impl From<EndpointAddress> for u8 { | ||
| 50 | #[inline] | ||
| 51 | fn from(addr: EndpointAddress) -> u8 { | ||
| 52 | addr.0 | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | impl EndpointAddress { | ||
| 57 | const INBITS: u8 = Direction::In as u8; | ||
| 58 | |||
| 59 | /// Constructs a new EndpointAddress with the given index and direction. | ||
| 60 | #[inline] | ||
| 61 | pub fn from_parts(index: usize, dir: Direction) -> Self { | ||
| 62 | EndpointAddress(index as u8 | dir as u8) | ||
| 63 | } | ||
| 64 | |||
| 65 | /// Gets the direction part of the address. | ||
| 66 | #[inline] | ||
| 67 | pub fn direction(&self) -> Direction { | ||
| 68 | if (self.0 & Self::INBITS) != 0 { | ||
| 69 | Direction::In | ||
| 70 | } else { | ||
| 71 | Direction::Out | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | /// Returns true if the direction is IN, otherwise false. | ||
| 76 | #[inline] | ||
| 77 | pub fn is_in(&self) -> bool { | ||
| 78 | (self.0 & Self::INBITS) != 0 | ||
| 79 | } | ||
| 80 | |||
| 81 | /// Returns true if the direction is OUT, otherwise false. | ||
| 82 | #[inline] | ||
| 83 | pub fn is_out(&self) -> bool { | ||
| 84 | (self.0 & Self::INBITS) == 0 | ||
| 85 | } | ||
| 86 | |||
| 87 | /// Gets the index part of the endpoint address. | ||
| 88 | #[inline] | ||
| 89 | pub fn index(&self) -> usize { | ||
| 90 | (self.0 & !Self::INBITS) as usize | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 95 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 96 | pub struct EndpointInfo { | ||
| 97 | pub addr: EndpointAddress, | ||
| 98 | pub ep_type: EndpointType, | ||
| 99 | pub max_packet_size: u16, | ||
| 100 | pub interval: u8, | ||
| 101 | } | ||
| 4 | 102 | ||
| 5 | /// Driver for a specific USB peripheral. Implement this to add support for a new hardware | 103 | /// Driver for a specific USB peripheral. Implement this to add support for a new hardware |
| 6 | /// platform. | 104 | /// platform. |
diff --git a/embassy-usb-hid/Cargo.toml b/embassy-usb-hid/Cargo.toml deleted file mode 100644 index 2f7733dc6..000000000 --- a/embassy-usb-hid/Cargo.toml +++ /dev/null | |||
| @@ -1,24 +0,0 @@ | |||
| 1 | [package] | ||
| 2 | name = "embassy-usb-hid" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | |||
| 6 | [package.metadata.embassy_docs] | ||
| 7 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-hid-v$VERSION/embassy-usb-hid/src/" | ||
| 8 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-hid/src/" | ||
| 9 | features = ["defmt"] | ||
| 10 | target = "thumbv7em-none-eabi" | ||
| 11 | |||
| 12 | [features] | ||
| 13 | default = ["usbd-hid"] | ||
| 14 | usbd-hid = ["dep:usbd-hid", "ssmarshal"] | ||
| 15 | |||
| 16 | [dependencies] | ||
| 17 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } | ||
| 18 | embassy-usb = { version = "0.1.0", path = "../embassy-usb" } | ||
| 19 | |||
| 20 | defmt = { version = "0.3", optional = true } | ||
| 21 | log = { version = "0.4.14", optional = true } | ||
| 22 | usbd-hid = { version = "0.6.0", optional = true } | ||
| 23 | ssmarshal = { version = "1.0", default-features = false, optional = true } | ||
| 24 | futures-util = { version = "0.3.21", default-features = false } | ||
diff --git a/embassy-usb-hid/src/fmt.rs b/embassy-usb-hid/src/fmt.rs deleted file mode 100644 index 066970813..000000000 --- a/embassy-usb-hid/src/fmt.rs +++ /dev/null | |||
| @@ -1,225 +0,0 @@ | |||
| 1 | #![macro_use] | ||
| 2 | #![allow(unused_macros)] | ||
| 3 | |||
| 4 | #[cfg(all(feature = "defmt", feature = "log"))] | ||
| 5 | compile_error!("You may not enable both `defmt` and `log` features."); | ||
| 6 | |||
| 7 | macro_rules! assert { | ||
| 8 | ($($x:tt)*) => { | ||
| 9 | { | ||
| 10 | #[cfg(not(feature = "defmt"))] | ||
| 11 | ::core::assert!($($x)*); | ||
| 12 | #[cfg(feature = "defmt")] | ||
| 13 | ::defmt::assert!($($x)*); | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | } | ||
| 17 | |||
| 18 | macro_rules! assert_eq { | ||
| 19 | ($($x:tt)*) => { | ||
| 20 | { | ||
| 21 | #[cfg(not(feature = "defmt"))] | ||
| 22 | ::core::assert_eq!($($x)*); | ||
| 23 | #[cfg(feature = "defmt")] | ||
| 24 | ::defmt::assert_eq!($($x)*); | ||
| 25 | } | ||
| 26 | }; | ||
| 27 | } | ||
| 28 | |||
| 29 | macro_rules! assert_ne { | ||
| 30 | ($($x:tt)*) => { | ||
| 31 | { | ||
| 32 | #[cfg(not(feature = "defmt"))] | ||
| 33 | ::core::assert_ne!($($x)*); | ||
| 34 | #[cfg(feature = "defmt")] | ||
| 35 | ::defmt::assert_ne!($($x)*); | ||
| 36 | } | ||
| 37 | }; | ||
| 38 | } | ||
| 39 | |||
| 40 | macro_rules! debug_assert { | ||
| 41 | ($($x:tt)*) => { | ||
| 42 | { | ||
| 43 | #[cfg(not(feature = "defmt"))] | ||
| 44 | ::core::debug_assert!($($x)*); | ||
| 45 | #[cfg(feature = "defmt")] | ||
| 46 | ::defmt::debug_assert!($($x)*); | ||
| 47 | } | ||
| 48 | }; | ||
| 49 | } | ||
| 50 | |||
| 51 | macro_rules! debug_assert_eq { | ||
| 52 | ($($x:tt)*) => { | ||
| 53 | { | ||
| 54 | #[cfg(not(feature = "defmt"))] | ||
| 55 | ::core::debug_assert_eq!($($x)*); | ||
| 56 | #[cfg(feature = "defmt")] | ||
| 57 | ::defmt::debug_assert_eq!($($x)*); | ||
| 58 | } | ||
| 59 | }; | ||
| 60 | } | ||
| 61 | |||
| 62 | macro_rules! debug_assert_ne { | ||
| 63 | ($($x:tt)*) => { | ||
| 64 | { | ||
| 65 | #[cfg(not(feature = "defmt"))] | ||
| 66 | ::core::debug_assert_ne!($($x)*); | ||
| 67 | #[cfg(feature = "defmt")] | ||
| 68 | ::defmt::debug_assert_ne!($($x)*); | ||
| 69 | } | ||
| 70 | }; | ||
| 71 | } | ||
| 72 | |||
| 73 | macro_rules! todo { | ||
| 74 | ($($x:tt)*) => { | ||
| 75 | { | ||
| 76 | #[cfg(not(feature = "defmt"))] | ||
| 77 | ::core::todo!($($x)*); | ||
| 78 | #[cfg(feature = "defmt")] | ||
| 79 | ::defmt::todo!($($x)*); | ||
| 80 | } | ||
| 81 | }; | ||
| 82 | } | ||
| 83 | |||
| 84 | macro_rules! unreachable { | ||
| 85 | ($($x:tt)*) => { | ||
| 86 | { | ||
| 87 | #[cfg(not(feature = "defmt"))] | ||
| 88 | ::core::unreachable!($($x)*); | ||
| 89 | #[cfg(feature = "defmt")] | ||
| 90 | ::defmt::unreachable!($($x)*); | ||
| 91 | } | ||
| 92 | }; | ||
| 93 | } | ||
| 94 | |||
| 95 | macro_rules! panic { | ||
| 96 | ($($x:tt)*) => { | ||
| 97 | { | ||
| 98 | #[cfg(not(feature = "defmt"))] | ||
| 99 | ::core::panic!($($x)*); | ||
| 100 | #[cfg(feature = "defmt")] | ||
| 101 | ::defmt::panic!($($x)*); | ||
| 102 | } | ||
| 103 | }; | ||
| 104 | } | ||
| 105 | |||
| 106 | macro_rules! trace { | ||
| 107 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 108 | { | ||
| 109 | #[cfg(feature = "log")] | ||
| 110 | ::log::trace!($s $(, $x)*); | ||
| 111 | #[cfg(feature = "defmt")] | ||
| 112 | ::defmt::trace!($s $(, $x)*); | ||
| 113 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 114 | let _ = ($( & $x ),*); | ||
| 115 | } | ||
| 116 | }; | ||
| 117 | } | ||
| 118 | |||
| 119 | macro_rules! debug { | ||
| 120 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 121 | { | ||
| 122 | #[cfg(feature = "log")] | ||
| 123 | ::log::debug!($s $(, $x)*); | ||
| 124 | #[cfg(feature = "defmt")] | ||
| 125 | ::defmt::debug!($s $(, $x)*); | ||
| 126 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 127 | let _ = ($( & $x ),*); | ||
| 128 | } | ||
| 129 | }; | ||
| 130 | } | ||
| 131 | |||
| 132 | macro_rules! info { | ||
| 133 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 134 | { | ||
| 135 | #[cfg(feature = "log")] | ||
| 136 | ::log::info!($s $(, $x)*); | ||
| 137 | #[cfg(feature = "defmt")] | ||
| 138 | ::defmt::info!($s $(, $x)*); | ||
| 139 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 140 | let _ = ($( & $x ),*); | ||
| 141 | } | ||
| 142 | }; | ||
| 143 | } | ||
| 144 | |||
| 145 | macro_rules! warn { | ||
| 146 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 147 | { | ||
| 148 | #[cfg(feature = "log")] | ||
| 149 | ::log::warn!($s $(, $x)*); | ||
| 150 | #[cfg(feature = "defmt")] | ||
| 151 | ::defmt::warn!($s $(, $x)*); | ||
| 152 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 153 | let _ = ($( & $x ),*); | ||
| 154 | } | ||
| 155 | }; | ||
| 156 | } | ||
| 157 | |||
| 158 | macro_rules! error { | ||
| 159 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 160 | { | ||
| 161 | #[cfg(feature = "log")] | ||
| 162 | ::log::error!($s $(, $x)*); | ||
| 163 | #[cfg(feature = "defmt")] | ||
| 164 | ::defmt::error!($s $(, $x)*); | ||
| 165 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 166 | let _ = ($( & $x ),*); | ||
| 167 | } | ||
| 168 | }; | ||
| 169 | } | ||
| 170 | |||
| 171 | #[cfg(feature = "defmt")] | ||
| 172 | macro_rules! unwrap { | ||
| 173 | ($($x:tt)*) => { | ||
| 174 | ::defmt::unwrap!($($x)*) | ||
| 175 | }; | ||
| 176 | } | ||
| 177 | |||
| 178 | #[cfg(not(feature = "defmt"))] | ||
| 179 | macro_rules! unwrap { | ||
| 180 | ($arg:expr) => { | ||
| 181 | match $crate::fmt::Try::into_result($arg) { | ||
| 182 | ::core::result::Result::Ok(t) => t, | ||
| 183 | ::core::result::Result::Err(e) => { | ||
| 184 | ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | }; | ||
| 188 | ($arg:expr, $($msg:expr),+ $(,)? ) => { | ||
| 189 | match $crate::fmt::Try::into_result($arg) { | ||
| 190 | ::core::result::Result::Ok(t) => t, | ||
| 191 | ::core::result::Result::Err(e) => { | ||
| 192 | ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 199 | pub struct NoneError; | ||
| 200 | |||
| 201 | pub trait Try { | ||
| 202 | type Ok; | ||
| 203 | type Error; | ||
| 204 | fn into_result(self) -> Result<Self::Ok, Self::Error>; | ||
| 205 | } | ||
| 206 | |||
| 207 | impl<T> Try for Option<T> { | ||
| 208 | type Ok = T; | ||
| 209 | type Error = NoneError; | ||
| 210 | |||
| 211 | #[inline] | ||
| 212 | fn into_result(self) -> Result<T, NoneError> { | ||
| 213 | self.ok_or(NoneError) | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | impl<T, E> Try for Result<T, E> { | ||
| 218 | type Ok = T; | ||
| 219 | type Error = E; | ||
| 220 | |||
| 221 | #[inline] | ||
| 222 | fn into_result(self) -> Self { | ||
| 223 | self | ||
| 224 | } | ||
| 225 | } | ||
diff --git a/embassy-usb-ncm/src/fmt.rs b/embassy-usb-ncm/src/fmt.rs deleted file mode 100644 index 066970813..000000000 --- a/embassy-usb-ncm/src/fmt.rs +++ /dev/null | |||
| @@ -1,225 +0,0 @@ | |||
| 1 | #![macro_use] | ||
| 2 | #![allow(unused_macros)] | ||
| 3 | |||
| 4 | #[cfg(all(feature = "defmt", feature = "log"))] | ||
| 5 | compile_error!("You may not enable both `defmt` and `log` features."); | ||
| 6 | |||
| 7 | macro_rules! assert { | ||
| 8 | ($($x:tt)*) => { | ||
| 9 | { | ||
| 10 | #[cfg(not(feature = "defmt"))] | ||
| 11 | ::core::assert!($($x)*); | ||
| 12 | #[cfg(feature = "defmt")] | ||
| 13 | ::defmt::assert!($($x)*); | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | } | ||
| 17 | |||
| 18 | macro_rules! assert_eq { | ||
| 19 | ($($x:tt)*) => { | ||
| 20 | { | ||
| 21 | #[cfg(not(feature = "defmt"))] | ||
| 22 | ::core::assert_eq!($($x)*); | ||
| 23 | #[cfg(feature = "defmt")] | ||
| 24 | ::defmt::assert_eq!($($x)*); | ||
| 25 | } | ||
| 26 | }; | ||
| 27 | } | ||
| 28 | |||
| 29 | macro_rules! assert_ne { | ||
| 30 | ($($x:tt)*) => { | ||
| 31 | { | ||
| 32 | #[cfg(not(feature = "defmt"))] | ||
| 33 | ::core::assert_ne!($($x)*); | ||
| 34 | #[cfg(feature = "defmt")] | ||
| 35 | ::defmt::assert_ne!($($x)*); | ||
| 36 | } | ||
| 37 | }; | ||
| 38 | } | ||
| 39 | |||
| 40 | macro_rules! debug_assert { | ||
| 41 | ($($x:tt)*) => { | ||
| 42 | { | ||
| 43 | #[cfg(not(feature = "defmt"))] | ||
| 44 | ::core::debug_assert!($($x)*); | ||
| 45 | #[cfg(feature = "defmt")] | ||
| 46 | ::defmt::debug_assert!($($x)*); | ||
| 47 | } | ||
| 48 | }; | ||
| 49 | } | ||
| 50 | |||
| 51 | macro_rules! debug_assert_eq { | ||
| 52 | ($($x:tt)*) => { | ||
| 53 | { | ||
| 54 | #[cfg(not(feature = "defmt"))] | ||
| 55 | ::core::debug_assert_eq!($($x)*); | ||
| 56 | #[cfg(feature = "defmt")] | ||
| 57 | ::defmt::debug_assert_eq!($($x)*); | ||
| 58 | } | ||
| 59 | }; | ||
| 60 | } | ||
| 61 | |||
| 62 | macro_rules! debug_assert_ne { | ||
| 63 | ($($x:tt)*) => { | ||
| 64 | { | ||
| 65 | #[cfg(not(feature = "defmt"))] | ||
| 66 | ::core::debug_assert_ne!($($x)*); | ||
| 67 | #[cfg(feature = "defmt")] | ||
| 68 | ::defmt::debug_assert_ne!($($x)*); | ||
| 69 | } | ||
| 70 | }; | ||
| 71 | } | ||
| 72 | |||
| 73 | macro_rules! todo { | ||
| 74 | ($($x:tt)*) => { | ||
| 75 | { | ||
| 76 | #[cfg(not(feature = "defmt"))] | ||
| 77 | ::core::todo!($($x)*); | ||
| 78 | #[cfg(feature = "defmt")] | ||
| 79 | ::defmt::todo!($($x)*); | ||
| 80 | } | ||
| 81 | }; | ||
| 82 | } | ||
| 83 | |||
| 84 | macro_rules! unreachable { | ||
| 85 | ($($x:tt)*) => { | ||
| 86 | { | ||
| 87 | #[cfg(not(feature = "defmt"))] | ||
| 88 | ::core::unreachable!($($x)*); | ||
| 89 | #[cfg(feature = "defmt")] | ||
| 90 | ::defmt::unreachable!($($x)*); | ||
| 91 | } | ||
| 92 | }; | ||
| 93 | } | ||
| 94 | |||
| 95 | macro_rules! panic { | ||
| 96 | ($($x:tt)*) => { | ||
| 97 | { | ||
| 98 | #[cfg(not(feature = "defmt"))] | ||
| 99 | ::core::panic!($($x)*); | ||
| 100 | #[cfg(feature = "defmt")] | ||
| 101 | ::defmt::panic!($($x)*); | ||
| 102 | } | ||
| 103 | }; | ||
| 104 | } | ||
| 105 | |||
| 106 | macro_rules! trace { | ||
| 107 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 108 | { | ||
| 109 | #[cfg(feature = "log")] | ||
| 110 | ::log::trace!($s $(, $x)*); | ||
| 111 | #[cfg(feature = "defmt")] | ||
| 112 | ::defmt::trace!($s $(, $x)*); | ||
| 113 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 114 | let _ = ($( & $x ),*); | ||
| 115 | } | ||
| 116 | }; | ||
| 117 | } | ||
| 118 | |||
| 119 | macro_rules! debug { | ||
| 120 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 121 | { | ||
| 122 | #[cfg(feature = "log")] | ||
| 123 | ::log::debug!($s $(, $x)*); | ||
| 124 | #[cfg(feature = "defmt")] | ||
| 125 | ::defmt::debug!($s $(, $x)*); | ||
| 126 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 127 | let _ = ($( & $x ),*); | ||
| 128 | } | ||
| 129 | }; | ||
| 130 | } | ||
| 131 | |||
| 132 | macro_rules! info { | ||
| 133 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 134 | { | ||
| 135 | #[cfg(feature = "log")] | ||
| 136 | ::log::info!($s $(, $x)*); | ||
| 137 | #[cfg(feature = "defmt")] | ||
| 138 | ::defmt::info!($s $(, $x)*); | ||
| 139 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 140 | let _ = ($( & $x ),*); | ||
| 141 | } | ||
| 142 | }; | ||
| 143 | } | ||
| 144 | |||
| 145 | macro_rules! warn { | ||
| 146 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 147 | { | ||
| 148 | #[cfg(feature = "log")] | ||
| 149 | ::log::warn!($s $(, $x)*); | ||
| 150 | #[cfg(feature = "defmt")] | ||
| 151 | ::defmt::warn!($s $(, $x)*); | ||
| 152 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 153 | let _ = ($( & $x ),*); | ||
| 154 | } | ||
| 155 | }; | ||
| 156 | } | ||
| 157 | |||
| 158 | macro_rules! error { | ||
| 159 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 160 | { | ||
| 161 | #[cfg(feature = "log")] | ||
| 162 | ::log::error!($s $(, $x)*); | ||
| 163 | #[cfg(feature = "defmt")] | ||
| 164 | ::defmt::error!($s $(, $x)*); | ||
| 165 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 166 | let _ = ($( & $x ),*); | ||
| 167 | } | ||
| 168 | }; | ||
| 169 | } | ||
| 170 | |||
| 171 | #[cfg(feature = "defmt")] | ||
| 172 | macro_rules! unwrap { | ||
| 173 | ($($x:tt)*) => { | ||
| 174 | ::defmt::unwrap!($($x)*) | ||
| 175 | }; | ||
| 176 | } | ||
| 177 | |||
| 178 | #[cfg(not(feature = "defmt"))] | ||
| 179 | macro_rules! unwrap { | ||
| 180 | ($arg:expr) => { | ||
| 181 | match $crate::fmt::Try::into_result($arg) { | ||
| 182 | ::core::result::Result::Ok(t) => t, | ||
| 183 | ::core::result::Result::Err(e) => { | ||
| 184 | ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | }; | ||
| 188 | ($arg:expr, $($msg:expr),+ $(,)? ) => { | ||
| 189 | match $crate::fmt::Try::into_result($arg) { | ||
| 190 | ::core::result::Result::Ok(t) => t, | ||
| 191 | ::core::result::Result::Err(e) => { | ||
| 192 | ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 199 | pub struct NoneError; | ||
| 200 | |||
| 201 | pub trait Try { | ||
| 202 | type Ok; | ||
| 203 | type Error; | ||
| 204 | fn into_result(self) -> Result<Self::Ok, Self::Error>; | ||
| 205 | } | ||
| 206 | |||
| 207 | impl<T> Try for Option<T> { | ||
| 208 | type Ok = T; | ||
| 209 | type Error = NoneError; | ||
| 210 | |||
| 211 | #[inline] | ||
| 212 | fn into_result(self) -> Result<T, NoneError> { | ||
| 213 | self.ok_or(NoneError) | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | impl<T, E> Try for Result<T, E> { | ||
| 218 | type Ok = T; | ||
| 219 | type Error = E; | ||
| 220 | |||
| 221 | #[inline] | ||
| 222 | fn into_result(self) -> Self { | ||
| 223 | self | ||
| 224 | } | ||
| 225 | } | ||
diff --git a/embassy-usb-serial/Cargo.toml b/embassy-usb-serial/Cargo.toml deleted file mode 100644 index 9788588e9..000000000 --- a/embassy-usb-serial/Cargo.toml +++ /dev/null | |||
| @@ -1,17 +0,0 @@ | |||
| 1 | [package] | ||
| 2 | name = "embassy-usb-serial" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | |||
| 6 | [package.metadata.embassy_docs] | ||
| 7 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-serial-v$VERSION/embassy-usb-serial/src/" | ||
| 8 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-serial/src/" | ||
| 9 | features = ["defmt"] | ||
| 10 | target = "thumbv7em-none-eabi" | ||
| 11 | |||
| 12 | [dependencies] | ||
| 13 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } | ||
| 14 | embassy-usb = { version = "0.1.0", path = "../embassy-usb" } | ||
| 15 | |||
| 16 | defmt = { version = "0.3", optional = true } | ||
| 17 | log = { version = "0.4.14", optional = true } | ||
diff --git a/embassy-usb-serial/src/fmt.rs b/embassy-usb-serial/src/fmt.rs deleted file mode 100644 index 066970813..000000000 --- a/embassy-usb-serial/src/fmt.rs +++ /dev/null | |||
| @@ -1,225 +0,0 @@ | |||
| 1 | #![macro_use] | ||
| 2 | #![allow(unused_macros)] | ||
| 3 | |||
| 4 | #[cfg(all(feature = "defmt", feature = "log"))] | ||
| 5 | compile_error!("You may not enable both `defmt` and `log` features."); | ||
| 6 | |||
| 7 | macro_rules! assert { | ||
| 8 | ($($x:tt)*) => { | ||
| 9 | { | ||
| 10 | #[cfg(not(feature = "defmt"))] | ||
| 11 | ::core::assert!($($x)*); | ||
| 12 | #[cfg(feature = "defmt")] | ||
| 13 | ::defmt::assert!($($x)*); | ||
| 14 | } | ||
| 15 | }; | ||
| 16 | } | ||
| 17 | |||
| 18 | macro_rules! assert_eq { | ||
| 19 | ($($x:tt)*) => { | ||
| 20 | { | ||
| 21 | #[cfg(not(feature = "defmt"))] | ||
| 22 | ::core::assert_eq!($($x)*); | ||
| 23 | #[cfg(feature = "defmt")] | ||
| 24 | ::defmt::assert_eq!($($x)*); | ||
| 25 | } | ||
| 26 | }; | ||
| 27 | } | ||
| 28 | |||
| 29 | macro_rules! assert_ne { | ||
| 30 | ($($x:tt)*) => { | ||
| 31 | { | ||
| 32 | #[cfg(not(feature = "defmt"))] | ||
| 33 | ::core::assert_ne!($($x)*); | ||
| 34 | #[cfg(feature = "defmt")] | ||
| 35 | ::defmt::assert_ne!($($x)*); | ||
| 36 | } | ||
| 37 | }; | ||
| 38 | } | ||
| 39 | |||
| 40 | macro_rules! debug_assert { | ||
| 41 | ($($x:tt)*) => { | ||
| 42 | { | ||
| 43 | #[cfg(not(feature = "defmt"))] | ||
| 44 | ::core::debug_assert!($($x)*); | ||
| 45 | #[cfg(feature = "defmt")] | ||
| 46 | ::defmt::debug_assert!($($x)*); | ||
| 47 | } | ||
| 48 | }; | ||
| 49 | } | ||
| 50 | |||
| 51 | macro_rules! debug_assert_eq { | ||
| 52 | ($($x:tt)*) => { | ||
| 53 | { | ||
| 54 | #[cfg(not(feature = "defmt"))] | ||
| 55 | ::core::debug_assert_eq!($($x)*); | ||
| 56 | #[cfg(feature = "defmt")] | ||
| 57 | ::defmt::debug_assert_eq!($($x)*); | ||
| 58 | } | ||
| 59 | }; | ||
| 60 | } | ||
| 61 | |||
| 62 | macro_rules! debug_assert_ne { | ||
| 63 | ($($x:tt)*) => { | ||
| 64 | { | ||
| 65 | #[cfg(not(feature = "defmt"))] | ||
| 66 | ::core::debug_assert_ne!($($x)*); | ||
| 67 | #[cfg(feature = "defmt")] | ||
| 68 | ::defmt::debug_assert_ne!($($x)*); | ||
| 69 | } | ||
| 70 | }; | ||
| 71 | } | ||
| 72 | |||
| 73 | macro_rules! todo { | ||
| 74 | ($($x:tt)*) => { | ||
| 75 | { | ||
| 76 | #[cfg(not(feature = "defmt"))] | ||
| 77 | ::core::todo!($($x)*); | ||
| 78 | #[cfg(feature = "defmt")] | ||
| 79 | ::defmt::todo!($($x)*); | ||
| 80 | } | ||
| 81 | }; | ||
| 82 | } | ||
| 83 | |||
| 84 | macro_rules! unreachable { | ||
| 85 | ($($x:tt)*) => { | ||
| 86 | { | ||
| 87 | #[cfg(not(feature = "defmt"))] | ||
| 88 | ::core::unreachable!($($x)*); | ||
| 89 | #[cfg(feature = "defmt")] | ||
| 90 | ::defmt::unreachable!($($x)*); | ||
| 91 | } | ||
| 92 | }; | ||
| 93 | } | ||
| 94 | |||
| 95 | macro_rules! panic { | ||
| 96 | ($($x:tt)*) => { | ||
| 97 | { | ||
| 98 | #[cfg(not(feature = "defmt"))] | ||
| 99 | ::core::panic!($($x)*); | ||
| 100 | #[cfg(feature = "defmt")] | ||
| 101 | ::defmt::panic!($($x)*); | ||
| 102 | } | ||
| 103 | }; | ||
| 104 | } | ||
| 105 | |||
| 106 | macro_rules! trace { | ||
| 107 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 108 | { | ||
| 109 | #[cfg(feature = "log")] | ||
| 110 | ::log::trace!($s $(, $x)*); | ||
| 111 | #[cfg(feature = "defmt")] | ||
| 112 | ::defmt::trace!($s $(, $x)*); | ||
| 113 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 114 | let _ = ($( & $x ),*); | ||
| 115 | } | ||
| 116 | }; | ||
| 117 | } | ||
| 118 | |||
| 119 | macro_rules! debug { | ||
| 120 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 121 | { | ||
| 122 | #[cfg(feature = "log")] | ||
| 123 | ::log::debug!($s $(, $x)*); | ||
| 124 | #[cfg(feature = "defmt")] | ||
| 125 | ::defmt::debug!($s $(, $x)*); | ||
| 126 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 127 | let _ = ($( & $x ),*); | ||
| 128 | } | ||
| 129 | }; | ||
| 130 | } | ||
| 131 | |||
| 132 | macro_rules! info { | ||
| 133 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 134 | { | ||
| 135 | #[cfg(feature = "log")] | ||
| 136 | ::log::info!($s $(, $x)*); | ||
| 137 | #[cfg(feature = "defmt")] | ||
| 138 | ::defmt::info!($s $(, $x)*); | ||
| 139 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 140 | let _ = ($( & $x ),*); | ||
| 141 | } | ||
| 142 | }; | ||
| 143 | } | ||
| 144 | |||
| 145 | macro_rules! warn { | ||
| 146 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 147 | { | ||
| 148 | #[cfg(feature = "log")] | ||
| 149 | ::log::warn!($s $(, $x)*); | ||
| 150 | #[cfg(feature = "defmt")] | ||
| 151 | ::defmt::warn!($s $(, $x)*); | ||
| 152 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 153 | let _ = ($( & $x ),*); | ||
| 154 | } | ||
| 155 | }; | ||
| 156 | } | ||
| 157 | |||
| 158 | macro_rules! error { | ||
| 159 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 160 | { | ||
| 161 | #[cfg(feature = "log")] | ||
| 162 | ::log::error!($s $(, $x)*); | ||
| 163 | #[cfg(feature = "defmt")] | ||
| 164 | ::defmt::error!($s $(, $x)*); | ||
| 165 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 166 | let _ = ($( & $x ),*); | ||
| 167 | } | ||
| 168 | }; | ||
| 169 | } | ||
| 170 | |||
| 171 | #[cfg(feature = "defmt")] | ||
| 172 | macro_rules! unwrap { | ||
| 173 | ($($x:tt)*) => { | ||
| 174 | ::defmt::unwrap!($($x)*) | ||
| 175 | }; | ||
| 176 | } | ||
| 177 | |||
| 178 | #[cfg(not(feature = "defmt"))] | ||
| 179 | macro_rules! unwrap { | ||
| 180 | ($arg:expr) => { | ||
| 181 | match $crate::fmt::Try::into_result($arg) { | ||
| 182 | ::core::result::Result::Ok(t) => t, | ||
| 183 | ::core::result::Result::Err(e) => { | ||
| 184 | ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | }; | ||
| 188 | ($arg:expr, $($msg:expr),+ $(,)? ) => { | ||
| 189 | match $crate::fmt::Try::into_result($arg) { | ||
| 190 | ::core::result::Result::Ok(t) => t, | ||
| 191 | ::core::result::Result::Err(e) => { | ||
| 192 | ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 199 | pub struct NoneError; | ||
| 200 | |||
| 201 | pub trait Try { | ||
| 202 | type Ok; | ||
| 203 | type Error; | ||
| 204 | fn into_result(self) -> Result<Self::Ok, Self::Error>; | ||
| 205 | } | ||
| 206 | |||
| 207 | impl<T> Try for Option<T> { | ||
| 208 | type Ok = T; | ||
| 209 | type Error = NoneError; | ||
| 210 | |||
| 211 | #[inline] | ||
| 212 | fn into_result(self) -> Result<T, NoneError> { | ||
| 213 | self.ok_or(NoneError) | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | impl<T, E> Try for Result<T, E> { | ||
| 218 | type Ok = T; | ||
| 219 | type Error = E; | ||
| 220 | |||
| 221 | #[inline] | ||
| 222 | fn into_result(self) -> Self { | ||
| 223 | self | ||
| 224 | } | ||
| 225 | } | ||
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index 8cad4d314..aad54dbaf 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml | |||
| @@ -9,9 +9,20 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb/s | |||
| 9 | features = ["defmt"] | 9 | features = ["defmt"] |
| 10 | target = "thumbv7em-none-eabi" | 10 | target = "thumbv7em-none-eabi" |
| 11 | 11 | ||
| 12 | [features] | ||
| 13 | defmt = ["dep:defmt", "embassy-usb-driver/defmt"] | ||
| 14 | usbd-hid = ["dep:usbd-hid", "dep:ssmarshal"] | ||
| 15 | default = ["usbd-hid"] | ||
| 16 | |||
| 12 | [dependencies] | 17 | [dependencies] |
| 13 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } | 18 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } |
| 19 | embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } | ||
| 20 | embassy-sync = { version = "0.1.0", path = "../embassy-sync" } | ||
| 14 | 21 | ||
| 15 | defmt = { version = "0.3", optional = true } | 22 | defmt = { version = "0.3", optional = true } |
| 16 | log = { version = "0.4.14", optional = true } | 23 | log = { version = "0.4.14", optional = true } |
| 17 | heapless = "0.7.10" \ No newline at end of file | 24 | heapless = "0.7.10" |
| 25 | |||
| 26 | # for HID | ||
| 27 | usbd-hid = { version = "0.6.0", optional = true } | ||
| 28 | ssmarshal = { version = "1.0", default-features = false, optional = true } | ||
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 6be88bc76..87a8333bb 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs | |||
| @@ -1,11 +1,10 @@ | |||
| 1 | use heapless::Vec; | 1 | use heapless::Vec; |
| 2 | 2 | ||
| 3 | use super::control::ControlHandler; | 3 | use crate::control::ControlHandler; |
| 4 | use super::descriptor::{BosWriter, DescriptorWriter}; | 4 | use crate::descriptor::{BosWriter, DescriptorWriter}; |
| 5 | use super::driver::{Driver, Endpoint}; | 5 | use crate::driver::{Driver, Endpoint, EndpointType}; |
| 6 | use super::types::*; | 6 | use crate::types::*; |
| 7 | use super::{DeviceStateHandler, UsbDevice, MAX_INTERFACE_COUNT}; | 7 | use crate::{DeviceStateHandler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; |
| 8 | use crate::{Interface, STRING_INDEX_CUSTOM_START}; | ||
| 9 | 8 | ||
| 10 | #[derive(Debug, Copy, Clone)] | 9 | #[derive(Debug, Copy, Clone)] |
| 11 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 10 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
diff --git a/embassy-usb-serial/src/lib.rs b/embassy-usb/src/class/cdc_acm.rs index 27b536a6b..09bb1cc8d 100644 --- a/embassy-usb-serial/src/lib.rs +++ b/embassy-usb/src/class/cdc_acm.rs | |||
| @@ -1,18 +1,13 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![feature(type_alias_impl_trait)] | ||
| 3 | |||
| 4 | // This mod MUST go first, so that the others see its macros. | ||
| 5 | pub(crate) mod fmt; | ||
| 6 | |||
| 7 | use core::cell::Cell; | 1 | use core::cell::Cell; |
| 8 | use core::mem::{self, MaybeUninit}; | 2 | use core::mem::{self, MaybeUninit}; |
| 9 | use core::sync::atomic::{AtomicBool, Ordering}; | 3 | use core::sync::atomic::{AtomicBool, Ordering}; |
| 10 | 4 | ||
| 11 | use embassy_sync::blocking_mutex::CriticalSectionMutex; | 5 | use embassy_sync::blocking_mutex::CriticalSectionMutex; |
| 12 | use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; | 6 | |
| 13 | use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; | 7 | use crate::control::{self, ControlHandler, InResponse, OutResponse, Request}; |
| 14 | use embassy_usb::types::*; | 8 | use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; |
| 15 | use embassy_usb::Builder; | 9 | use crate::types::*; |
| 10 | use crate::Builder; | ||
| 16 | 11 | ||
| 17 | /// This should be used as `device_class` when building the `UsbDevice`. | 12 | /// This should be used as `device_class` when building the `UsbDevice`. |
| 18 | pub const USB_CLASS_CDC: u8 = 0x02; | 13 | pub const USB_CLASS_CDC: u8 = 0x02; |
| @@ -268,7 +263,7 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { | |||
| 268 | } | 263 | } |
| 269 | 264 | ||
| 270 | /// Number of stop bits for LineCoding | 265 | /// Number of stop bits for LineCoding |
| 271 | #[derive(Copy, Clone, PartialEq, Eq)] | 266 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
| 272 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 267 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 273 | pub enum StopBits { | 268 | pub enum StopBits { |
| 274 | /// 1 stop bit | 269 | /// 1 stop bit |
| @@ -292,7 +287,7 @@ impl From<u8> for StopBits { | |||
| 292 | } | 287 | } |
| 293 | 288 | ||
| 294 | /// Parity for LineCoding | 289 | /// Parity for LineCoding |
| 295 | #[derive(Copy, Clone, PartialEq, Eq)] | 290 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
| 296 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 291 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 297 | pub enum ParityType { | 292 | pub enum ParityType { |
| 298 | None = 0, | 293 | None = 0, |
| @@ -316,7 +311,7 @@ impl From<u8> for ParityType { | |||
| 316 | /// | 311 | /// |
| 317 | /// This is provided by the host for specifying the standard UART parameters such as baud rate. Can | 312 | /// This is provided by the host for specifying the standard UART parameters such as baud rate. Can |
| 318 | /// be ignored if you don't plan to interface with a physical UART. | 313 | /// be ignored if you don't plan to interface with a physical UART. |
| 319 | #[derive(Clone, Copy)] | 314 | #[derive(Clone, Copy, Debug)] |
| 320 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 315 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 321 | pub struct LineCoding { | 316 | pub struct LineCoding { |
| 322 | stop_bits: StopBits, | 317 | stop_bits: StopBits, |
diff --git a/embassy-usb-ncm/src/lib.rs b/embassy-usb/src/class/cdc_ncm.rs index e796af28f..a39b87e9b 100644 --- a/embassy-usb-ncm/src/lib.rs +++ b/embassy-usb/src/class/cdc_ncm.rs | |||
| @@ -1,15 +1,10 @@ | |||
| 1 | #![no_std] | ||
| 2 | |||
| 3 | // This mod MUST go first, so that the others see its macros. | ||
| 4 | pub(crate) mod fmt; | ||
| 5 | |||
| 6 | use core::intrinsics::copy_nonoverlapping; | 1 | use core::intrinsics::copy_nonoverlapping; |
| 7 | use core::mem::{size_of, MaybeUninit}; | 2 | use core::mem::{size_of, MaybeUninit}; |
| 8 | 3 | ||
| 9 | use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; | 4 | use crate::control::{self, ControlHandler, InResponse, OutResponse, Request}; |
| 10 | use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; | 5 | use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; |
| 11 | use embassy_usb::types::*; | 6 | use crate::types::*; |
| 12 | use embassy_usb::Builder; | 7 | use crate::Builder; |
| 13 | 8 | ||
| 14 | /// This should be used as `device_class` when building the `UsbDevice`. | 9 | /// This should be used as `device_class` when building the `UsbDevice`. |
| 15 | pub const USB_CLASS_CDC: u8 = 0x02; | 10 | pub const USB_CLASS_CDC: u8 = 0x02; |
diff --git a/embassy-usb-hid/src/lib.rs b/embassy-usb/src/class/hid.rs index 8b181aec8..4d1fa995f 100644 --- a/embassy-usb-hid/src/lib.rs +++ b/embassy-usb/src/class/hid.rs | |||
| @@ -1,23 +1,16 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![feature(type_alias_impl_trait)] | ||
| 3 | |||
| 4 | //! Implements HID functionality for a usb-device device. | ||
| 5 | |||
| 6 | // This mod MUST go first, so that the others see its macros. | ||
| 7 | pub(crate) mod fmt; | ||
| 8 | |||
| 9 | use core::mem::MaybeUninit; | 1 | use core::mem::MaybeUninit; |
| 10 | use core::ops::Range; | 2 | use core::ops::Range; |
| 11 | use core::sync::atomic::{AtomicUsize, Ordering}; | 3 | use core::sync::atomic::{AtomicUsize, Ordering}; |
| 12 | 4 | ||
| 13 | use embassy_usb::control::{ControlHandler, InResponse, OutResponse, Request, RequestType}; | ||
| 14 | use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; | ||
| 15 | use embassy_usb::Builder; | ||
| 16 | #[cfg(feature = "usbd-hid")] | 5 | #[cfg(feature = "usbd-hid")] |
| 17 | use ssmarshal::serialize; | 6 | use ssmarshal::serialize; |
| 18 | #[cfg(feature = "usbd-hid")] | 7 | #[cfg(feature = "usbd-hid")] |
| 19 | use usbd_hid::descriptor::AsInputReport; | 8 | use usbd_hid::descriptor::AsInputReport; |
| 20 | 9 | ||
| 10 | use crate::control::{ControlHandler, InResponse, OutResponse, Request, RequestType}; | ||
| 11 | use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; | ||
| 12 | use crate::Builder; | ||
| 13 | |||
| 21 | const USB_CLASS_HID: u8 = 0x03; | 14 | const USB_CLASS_HID: u8 = 0x03; |
| 22 | const USB_SUBCLASS_NONE: u8 = 0x00; | 15 | const USB_SUBCLASS_NONE: u8 = 0x00; |
| 23 | const USB_PROTOCOL_NONE: u8 = 0x00; | 16 | const USB_PROTOCOL_NONE: u8 = 0x00; |
| @@ -204,9 +197,9 @@ pub enum ReadError { | |||
| 204 | Sync(Range<usize>), | 197 | Sync(Range<usize>), |
| 205 | } | 198 | } |
| 206 | 199 | ||
| 207 | impl From<embassy_usb::driver::EndpointError> for ReadError { | 200 | impl From<EndpointError> for ReadError { |
| 208 | fn from(val: embassy_usb::driver::EndpointError) -> Self { | 201 | fn from(val: EndpointError) -> Self { |
| 209 | use embassy_usb::driver::EndpointError::*; | 202 | use EndpointError::*; |
| 210 | match val { | 203 | match val { |
| 211 | BufferOverflow => ReadError::BufferOverflow, | 204 | BufferOverflow => ReadError::BufferOverflow, |
| 212 | Disabled => ReadError::Disabled, | 205 | Disabled => ReadError::Disabled, |
| @@ -437,7 +430,7 @@ impl<'d> ControlHandler for Control<'d> { | |||
| 437 | } | 430 | } |
| 438 | } | 431 | } |
| 439 | 432 | ||
| 440 | fn control_out(&mut self, req: embassy_usb::control::Request, data: &[u8]) -> OutResponse { | 433 | fn control_out(&mut self, req: Request, data: &[u8]) -> OutResponse { |
| 441 | trace!("HID control_out {:?} {=[u8]:x}", req, data); | 434 | trace!("HID control_out {:?} {=[u8]:x}", req, data); |
| 442 | if let RequestType::Class = req.request_type { | 435 | if let RequestType::Class = req.request_type { |
| 443 | match req.request { | 436 | match req.request { |
diff --git a/embassy-usb/src/class/mod.rs b/embassy-usb/src/class/mod.rs new file mode 100644 index 000000000..af27577a6 --- /dev/null +++ b/embassy-usb/src/class/mod.rs | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | pub mod cdc_acm; | ||
| 2 | pub mod cdc_ncm; | ||
| 3 | pub mod hid; | ||
diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs index 3e5749a01..d6d0c6565 100644 --- a/embassy-usb/src/control.rs +++ b/embassy-usb/src/control.rs | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | //! USB control data types. | 1 | //! USB control data types. |
| 2 | use core::mem; | 2 | use core::mem; |
| 3 | 3 | ||
| 4 | use super::types::*; | 4 | use crate::driver::Direction; |
| 5 | use crate::types::StringIndex; | ||
| 5 | 6 | ||
| 6 | /// Control request type. | 7 | /// Control request type. |
| 7 | #[repr(u8)] | 8 | #[repr(u8)] |
| @@ -42,7 +43,7 @@ pub enum Recipient { | |||
| 42 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 43 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 43 | pub struct Request { | 44 | pub struct Request { |
| 44 | /// Direction of the request. | 45 | /// Direction of the request. |
| 45 | pub direction: UsbDirection, | 46 | pub direction: Direction, |
| 46 | /// Type of the request. | 47 | /// Type of the request. |
| 47 | pub request_type: RequestType, | 48 | pub request_type: RequestType, |
| 48 | /// Recipient of the request. | 49 | /// Recipient of the request. |
| @@ -105,7 +106,7 @@ impl Request { | |||
| 105 | let recipient = rt & 0b11111; | 106 | let recipient = rt & 0b11111; |
| 106 | 107 | ||
| 107 | Request { | 108 | Request { |
| 108 | direction: rt.into(), | 109 | direction: if rt & 0x80 == 0 { Direction::Out } else { Direction::In }, |
| 109 | request_type: unsafe { mem::transmute((rt >> 5) & 0b11) }, | 110 | request_type: unsafe { mem::transmute((rt >> 5) & 0b11) }, |
| 110 | recipient: if recipient <= 3 { | 111 | recipient: if recipient <= 3 { |
| 111 | unsafe { mem::transmute(recipient) } | 112 | unsafe { mem::transmute(recipient) } |
diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index b94a4b161..497f03196 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | use super::builder::Config; | 1 | use crate::builder::Config; |
| 2 | use super::types::*; | 2 | use crate::driver::EndpointInfo; |
| 3 | use super::CONFIGURATION_VALUE; | 3 | use crate::types::*; |
| 4 | use crate::CONFIGURATION_VALUE; | ||
| 4 | 5 | ||
| 5 | /// Standard descriptor types | 6 | /// Standard descriptor types |
| 6 | #[allow(missing_docs)] | 7 | #[allow(missing_docs)] |
diff --git a/embassy-usb/src/descriptor_reader.rs b/embassy-usb/src/descriptor_reader.rs index 0a12b566c..d64bcb73b 100644 --- a/embassy-usb/src/descriptor_reader.rs +++ b/embassy-usb/src/descriptor_reader.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | use crate::descriptor::descriptor_type; | 1 | use crate::descriptor::descriptor_type; |
| 2 | use crate::types::EndpointAddress; | 2 | use crate::driver::EndpointAddress; |
| 3 | 3 | ||
| 4 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | 4 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] |
| 5 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 5 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index ca7dde627..661b84119 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs | |||
| @@ -4,23 +4,24 @@ | |||
| 4 | // This mod MUST go first, so that the others see its macros. | 4 | // This mod MUST go first, so that the others see its macros. |
| 5 | pub(crate) mod fmt; | 5 | pub(crate) mod fmt; |
| 6 | 6 | ||
| 7 | pub use embassy_usb_driver as driver; | ||
| 8 | |||
| 7 | mod builder; | 9 | mod builder; |
| 10 | pub mod class; | ||
| 8 | pub mod control; | 11 | pub mod control; |
| 9 | pub mod descriptor; | 12 | pub mod descriptor; |
| 10 | mod descriptor_reader; | 13 | mod descriptor_reader; |
| 11 | pub mod driver; | ||
| 12 | pub mod types; | 14 | pub mod types; |
| 13 | 15 | ||
| 14 | use embassy_futures::select::{select, Either}; | 16 | use embassy_futures::select::{select, Either}; |
| 15 | use heapless::Vec; | 17 | use heapless::Vec; |
| 16 | 18 | ||
| 17 | pub use self::builder::{Builder, Config}; | 19 | pub use crate::builder::{Builder, Config}; |
| 18 | use self::control::*; | 20 | use crate::control::*; |
| 19 | use self::descriptor::*; | 21 | use crate::descriptor::*; |
| 20 | use self::driver::{Bus, Driver, Event}; | ||
| 21 | use self::types::*; | ||
| 22 | use crate::descriptor_reader::foreach_endpoint; | 22 | use crate::descriptor_reader::foreach_endpoint; |
| 23 | use crate::driver::ControlPipe; | 23 | use crate::driver::{Bus, ControlPipe, Direction, Driver, EndpointAddress, Event}; |
| 24 | use crate::types::*; | ||
| 24 | 25 | ||
| 25 | /// The global state of the USB device. | 26 | /// The global state of the USB device. |
| 26 | /// | 27 | /// |
| @@ -247,11 +248,11 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { | |||
| 247 | async fn handle_control(&mut self, req: [u8; 8]) { | 248 | async fn handle_control(&mut self, req: [u8; 8]) { |
| 248 | let req = Request::parse(&req); | 249 | let req = Request::parse(&req); |
| 249 | 250 | ||
| 250 | trace!("control request: {:02x}", req); | 251 | trace!("control request: {:?}", req); |
| 251 | 252 | ||
| 252 | match req.direction { | 253 | match req.direction { |
| 253 | UsbDirection::In => self.handle_control_in(req).await, | 254 | Direction::In => self.handle_control_in(req).await, |
| 254 | UsbDirection::Out => self.handle_control_out(req).await, | 255 | Direction::Out => self.handle_control_out(req).await, |
| 255 | } | 256 | } |
| 256 | 257 | ||
| 257 | if self.inner.set_address_pending { | 258 | if self.inner.set_address_pending { |
diff --git a/embassy-usb/src/types.rs b/embassy-usb/src/types.rs index b8717ffa9..aeab063d1 100644 --- a/embassy-usb/src/types.rs +++ b/embassy-usb/src/types.rs | |||
| @@ -1,108 +1,3 @@ | |||
| 1 | /// Direction of USB traffic. Note that in the USB standard the direction is always indicated from | ||
| 2 | /// the perspective of the host, which is backward for devices, but the standard directions are used | ||
| 3 | /// for consistency. | ||
| 4 | /// | ||
| 5 | /// The values of the enum also match the direction bit used in endpoint addresses and control | ||
| 6 | /// request types. | ||
| 7 | #[repr(u8)] | ||
| 8 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 9 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 10 | pub enum UsbDirection { | ||
| 11 | /// Host to device (OUT) | ||
| 12 | Out = 0x00, | ||
| 13 | /// Device to host (IN) | ||
| 14 | In = 0x80, | ||
| 15 | } | ||
| 16 | |||
| 17 | impl From<u8> for UsbDirection { | ||
| 18 | fn from(value: u8) -> Self { | ||
| 19 | unsafe { core::mem::transmute(value & 0x80) } | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | /// USB endpoint transfer type. The values of this enum can be directly cast into `u8` to get the | ||
| 24 | /// transfer bmAttributes transfer type bits. | ||
| 25 | #[repr(u8)] | ||
| 26 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 27 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 28 | pub enum EndpointType { | ||
| 29 | /// Control endpoint. Used for device management. Only the host can initiate requests. Usually | ||
| 30 | /// used only endpoint 0. | ||
| 31 | Control = 0b00, | ||
| 32 | /// Isochronous endpoint. Used for time-critical unreliable data. Not implemented yet. | ||
| 33 | Isochronous = 0b01, | ||
| 34 | /// Bulk endpoint. Used for large amounts of best-effort reliable data. | ||
| 35 | Bulk = 0b10, | ||
| 36 | /// Interrupt endpoint. Used for small amounts of time-critical reliable data. | ||
| 37 | Interrupt = 0b11, | ||
| 38 | } | ||
| 39 | |||
| 40 | /// Type-safe endpoint address. | ||
| 41 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] | ||
| 42 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 43 | pub struct EndpointAddress(u8); | ||
| 44 | |||
| 45 | impl From<u8> for EndpointAddress { | ||
| 46 | #[inline] | ||
| 47 | fn from(addr: u8) -> EndpointAddress { | ||
| 48 | EndpointAddress(addr) | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | impl From<EndpointAddress> for u8 { | ||
| 53 | #[inline] | ||
| 54 | fn from(addr: EndpointAddress) -> u8 { | ||
| 55 | addr.0 | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | impl EndpointAddress { | ||
| 60 | const INBITS: u8 = UsbDirection::In as u8; | ||
| 61 | |||
| 62 | /// Constructs a new EndpointAddress with the given index and direction. | ||
| 63 | #[inline] | ||
| 64 | pub fn from_parts(index: usize, dir: UsbDirection) -> Self { | ||
| 65 | EndpointAddress(index as u8 | dir as u8) | ||
| 66 | } | ||
| 67 | |||
| 68 | /// Gets the direction part of the address. | ||
| 69 | #[inline] | ||
| 70 | pub fn direction(&self) -> UsbDirection { | ||
| 71 | if (self.0 & Self::INBITS) != 0 { | ||
| 72 | UsbDirection::In | ||
| 73 | } else { | ||
| 74 | UsbDirection::Out | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | /// Returns true if the direction is IN, otherwise false. | ||
| 79 | #[inline] | ||
| 80 | pub fn is_in(&self) -> bool { | ||
| 81 | (self.0 & Self::INBITS) != 0 | ||
| 82 | } | ||
| 83 | |||
| 84 | /// Returns true if the direction is OUT, otherwise false. | ||
| 85 | #[inline] | ||
| 86 | pub fn is_out(&self) -> bool { | ||
| 87 | (self.0 & Self::INBITS) == 0 | ||
| 88 | } | ||
| 89 | |||
| 90 | /// Gets the index part of the endpoint address. | ||
| 91 | #[inline] | ||
| 92 | pub fn index(&self) -> usize { | ||
| 93 | (self.0 & !Self::INBITS) as usize | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | ||
| 98 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 99 | pub struct EndpointInfo { | ||
| 100 | pub addr: EndpointAddress, | ||
| 101 | pub ep_type: EndpointType, | ||
| 102 | pub max_packet_size: u16, | ||
| 103 | pub interval: u8, | ||
| 104 | } | ||
| 105 | |||
| 106 | /// A handle for a USB interface that contains its number. | 1 | /// A handle for a USB interface that contains its number. |
| 107 | #[derive(Copy, Clone, Eq, PartialEq)] | 2 | #[derive(Copy, Clone, Eq, PartialEq)] |
| 108 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 3 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs index c08880fb3..77b897b0f 100644 --- a/examples/boot/application/stm32f7/src/bin/a.rs +++ b/examples/boot/application/stm32f7/src/bin/a.rs | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #[cfg(feature = "defmt-rtt")] | 5 | #[cfg(feature = "defmt-rtt")] |
| 6 | use defmt_rtt::*; | 6 | use defmt_rtt::*; |
| 7 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater}; | 7 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater}; |
| 8 | use embassy_embedded_hal::adapter::BlockingAsync; | ||
| 9 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 10 | use embassy_stm32::exti::ExtiInput; | 9 | use embassy_stm32::exti::ExtiInput; |
| 11 | use embassy_stm32::flash::{Flash, WRITE_SIZE}; | 10 | use embassy_stm32::flash::{Flash, WRITE_SIZE}; |
| @@ -17,8 +16,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin"); | |||
| 17 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| 18 | async fn main(_spawner: Spawner) { | 17 | async fn main(_spawner: Spawner) { |
| 19 | let p = embassy_stm32::init(Default::default()); | 18 | let p = embassy_stm32::init(Default::default()); |
| 20 | let flash = Flash::unlock(p.FLASH); | 19 | let mut flash = Flash::unlock(p.FLASH); |
| 21 | let mut flash = BlockingAsync::new(flash); | ||
| 22 | 20 | ||
| 23 | let button = Input::new(p.PC13, Pull::Down); | 21 | let button = Input::new(p.PC13, Pull::Down); |
| 24 | let mut button = ExtiInput::new(button, p.EXTI13); | 22 | let mut button = ExtiInput::new(button, p.EXTI13); |
| @@ -27,16 +25,19 @@ async fn main(_spawner: Spawner) { | |||
| 27 | led.set_high(); | 25 | led.set_high(); |
| 28 | 26 | ||
| 29 | let mut updater = FirmwareUpdater::default(); | 27 | let mut updater = FirmwareUpdater::default(); |
| 28 | let mut writer = updater.prepare_update_blocking(&mut flash).unwrap(); | ||
| 30 | button.wait_for_rising_edge().await; | 29 | button.wait_for_rising_edge().await; |
| 31 | let mut offset = 0; | 30 | let mut offset = 0; |
| 32 | let mut buf: [u8; 256 * 1024] = [0; 256 * 1024]; | 31 | let mut buf = AlignedBuffer([0; 4096]); |
| 33 | for chunk in APP_B.chunks(256 * 1024) { | 32 | for chunk in APP_B.chunks(4096) { |
| 34 | buf[..chunk.len()].copy_from_slice(chunk); | 33 | buf.as_mut()[..chunk.len()].copy_from_slice(chunk); |
| 35 | updater.write_firmware(offset, &buf, &mut flash, 2048).await.unwrap(); | 34 | writer |
| 35 | .write_block_blocking(offset, buf.as_ref(), &mut flash, chunk.len()) | ||
| 36 | .unwrap(); | ||
| 36 | offset += chunk.len(); | 37 | offset += chunk.len(); |
| 37 | } | 38 | } |
| 38 | let mut magic = AlignedBuffer([0; WRITE_SIZE]); | 39 | let mut magic = AlignedBuffer([0; WRITE_SIZE]); |
| 39 | updater.mark_updated(&mut flash, magic.as_mut()).await.unwrap(); | 40 | updater.mark_updated_blocking(&mut flash, magic.as_mut()).unwrap(); |
| 40 | led.set_low(); | 41 | led.set_low(); |
| 41 | cortex_m::peripheral::SCB::sys_reset(); | 42 | cortex_m::peripheral::SCB::sys_reset(); |
| 42 | } | 43 | } |
diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs index f5a8fdb61..0fe598a5d 100644 --- a/examples/boot/application/stm32h7/src/bin/a.rs +++ b/examples/boot/application/stm32h7/src/bin/a.rs | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #[cfg(feature = "defmt-rtt")] | 5 | #[cfg(feature = "defmt-rtt")] |
| 6 | use defmt_rtt::*; | 6 | use defmt_rtt::*; |
| 7 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater}; | 7 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater}; |
| 8 | use embassy_embedded_hal::adapter::BlockingAsync; | ||
| 9 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 10 | use embassy_stm32::exti::ExtiInput; | 9 | use embassy_stm32::exti::ExtiInput; |
| 11 | use embassy_stm32::flash::{Flash, WRITE_SIZE}; | 10 | use embassy_stm32::flash::{Flash, WRITE_SIZE}; |
| @@ -17,8 +16,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin"); | |||
| 17 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| 18 | async fn main(_spawner: Spawner) { | 17 | async fn main(_spawner: Spawner) { |
| 19 | let p = embassy_stm32::init(Default::default()); | 18 | let p = embassy_stm32::init(Default::default()); |
| 20 | let flash = Flash::unlock(p.FLASH); | 19 | let mut flash = Flash::unlock(p.FLASH); |
| 21 | let mut flash = BlockingAsync::new(flash); | ||
| 22 | 20 | ||
| 23 | let button = Input::new(p.PC13, Pull::Down); | 21 | let button = Input::new(p.PC13, Pull::Down); |
| 24 | let mut button = ExtiInput::new(button, p.EXTI13); | 22 | let mut button = ExtiInput::new(button, p.EXTI13); |
| @@ -27,19 +25,20 @@ async fn main(_spawner: Spawner) { | |||
| 27 | led.set_high(); | 25 | led.set_high(); |
| 28 | 26 | ||
| 29 | let mut updater = FirmwareUpdater::default(); | 27 | let mut updater = FirmwareUpdater::default(); |
| 28 | |||
| 29 | let mut writer = updater.prepare_update_blocking(&mut flash).unwrap(); | ||
| 30 | button.wait_for_rising_edge().await; | 30 | button.wait_for_rising_edge().await; |
| 31 | let mut offset = 0; | 31 | let mut offset = 0; |
| 32 | let mut buf = AlignedBuffer([0; 128 * 1024]); | 32 | let mut buf = AlignedBuffer([0; 4096]); |
| 33 | for chunk in APP_B.chunks(128 * 1024) { | 33 | for chunk in APP_B.chunks(4096) { |
| 34 | buf.as_mut()[..chunk.len()].copy_from_slice(chunk); | 34 | buf.as_mut()[..chunk.len()].copy_from_slice(chunk); |
| 35 | updater | 35 | writer |
| 36 | .write_firmware(offset, buf.as_ref(), &mut flash, 2048) | 36 | .write_block_blocking(offset, buf.as_ref(), &mut flash, 4096) |
| 37 | .await | ||
| 38 | .unwrap(); | 37 | .unwrap(); |
| 39 | offset += chunk.len(); | 38 | offset += chunk.len(); |
| 40 | } | 39 | } |
| 41 | let mut magic = AlignedBuffer([0; WRITE_SIZE]); | 40 | let mut magic = AlignedBuffer([0; WRITE_SIZE]); |
| 42 | updater.mark_updated(&mut flash, magic.as_mut()).await.unwrap(); | 41 | updater.mark_updated_blocking(&mut flash, magic.as_mut()).unwrap(); |
| 43 | led.set_low(); | 42 | led.set_low(); |
| 44 | cortex_m::peripheral::SCB::sys_reset(); | 43 | cortex_m::peripheral::SCB::sys_reset(); |
| 45 | } | 44 | } |
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml index dbc659cda..a5d340c69 100644 --- a/examples/nrf/Cargo.toml +++ b/examples/nrf/Cargo.toml | |||
| @@ -5,7 +5,7 @@ version = "0.1.0" | |||
| 5 | 5 | ||
| 6 | [features] | 6 | [features] |
| 7 | default = ["nightly"] | 7 | default = ["nightly"] |
| 8 | nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embassy-usb-serial", "embassy-usb-hid", "embassy-usb-ncm", "embedded-io/async", "embassy-net"] | 8 | nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net"] |
| 9 | 9 | ||
| 10 | [dependencies] | 10 | [dependencies] |
| 11 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 11 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| @@ -15,9 +15,6 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de | |||
| 15 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } | 15 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } |
| 16 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true } | 16 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true } |
| 17 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } | 17 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } |
| 18 | embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"], optional = true } | ||
| 19 | embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"], optional = true } | ||
| 20 | embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"], optional = true } | ||
| 21 | embedded-io = "0.3.0" | 18 | embedded-io = "0.3.0" |
| 22 | 19 | ||
| 23 | defmt = "0.3" | 20 | defmt = "0.3" |
diff --git a/examples/nrf/src/bin/usb_ethernet.rs b/examples/nrf/src/bin/usb_ethernet.rs index 33ca380ff..de93a2b45 100644 --- a/examples/nrf/src/bin/usb_ethernet.rs +++ b/examples/nrf/src/bin/usb_ethernet.rs | |||
| @@ -15,8 +15,8 @@ use embassy_nrf::usb::{Driver, PowerUsb}; | |||
| 15 | use embassy_nrf::{interrupt, pac, peripherals}; | 15 | use embassy_nrf::{interrupt, pac, peripherals}; |
| 16 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | 16 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; |
| 17 | use embassy_sync::channel::Channel; | 17 | use embassy_sync::channel::Channel; |
| 18 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State}; | ||
| 18 | use embassy_usb::{Builder, Config, UsbDevice}; | 19 | use embassy_usb::{Builder, Config, UsbDevice}; |
| 19 | use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State}; | ||
| 20 | use embedded_io::asynch::Write; | 20 | use embedded_io::asynch::Write; |
| 21 | use static_cell::StaticCell; | 21 | use static_cell::StaticCell; |
| 22 | use {defmt_rtt as _, panic_probe as _}; | 22 | use {defmt_rtt as _, panic_probe as _}; |
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs index 70318b78f..76e198719 100644 --- a/examples/nrf/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf/src/bin/usb_hid_keyboard.rs | |||
| @@ -12,10 +12,11 @@ use embassy_futures::select::{select, Either}; | |||
| 12 | use embassy_nrf::gpio::{Input, Pin, Pull}; | 12 | use embassy_nrf::gpio::{Input, Pin, Pull}; |
| 13 | use embassy_nrf::usb::{Driver, PowerUsb}; | 13 | use embassy_nrf::usb::{Driver, PowerUsb}; |
| 14 | use embassy_nrf::{interrupt, pac}; | 14 | use embassy_nrf::{interrupt, pac}; |
| 15 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 15 | use embassy_sync::signal::Signal; | 16 | use embassy_sync::signal::Signal; |
| 17 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; | ||
| 16 | use embassy_usb::control::OutResponse; | 18 | use embassy_usb::control::OutResponse; |
| 17 | use embassy_usb::{Builder, Config, DeviceStateHandler}; | 19 | use embassy_usb::{Builder, Config, DeviceStateHandler}; |
| 18 | use embassy_usb_hid::{HidReaderWriter, ReportId, RequestHandler, State}; | ||
| 19 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | 20 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; |
| 20 | use {defmt_rtt as _, panic_probe as _}; | 21 | use {defmt_rtt as _, panic_probe as _}; |
| 21 | 22 | ||
| @@ -66,7 +67,7 @@ async fn main(_spawner: Spawner) { | |||
| 66 | ); | 67 | ); |
| 67 | 68 | ||
| 68 | // Create classes on the builder. | 69 | // Create classes on the builder. |
| 69 | let config = embassy_usb_hid::Config { | 70 | let config = embassy_usb::class::hid::Config { |
| 70 | report_descriptor: KeyboardReport::desc(), | 71 | report_descriptor: KeyboardReport::desc(), |
| 71 | request_handler: Some(&request_handler), | 72 | request_handler: Some(&request_handler), |
| 72 | poll_ms: 60, | 73 | poll_ms: 60, |
| @@ -77,7 +78,7 @@ async fn main(_spawner: Spawner) { | |||
| 77 | // Build the builder. | 78 | // Build the builder. |
| 78 | let mut usb = builder.build(); | 79 | let mut usb = builder.build(); |
| 79 | 80 | ||
| 80 | let remote_wakeup = Signal::new(); | 81 | let remote_wakeup: Signal<CriticalSectionRawMutex, _> = Signal::new(); |
| 81 | 82 | ||
| 82 | // Run the USB device. | 83 | // Run the USB device. |
| 83 | let usb_fut = async { | 84 | let usb_fut = async { |
diff --git a/examples/nrf/src/bin/usb_hid_mouse.rs b/examples/nrf/src/bin/usb_hid_mouse.rs index 65fbda1cf..4916a38d4 100644 --- a/examples/nrf/src/bin/usb_hid_mouse.rs +++ b/examples/nrf/src/bin/usb_hid_mouse.rs | |||
| @@ -10,9 +10,9 @@ use embassy_futures::join::join; | |||
| 10 | use embassy_nrf::usb::{Driver, PowerUsb}; | 10 | use embassy_nrf::usb::{Driver, PowerUsb}; |
| 11 | use embassy_nrf::{interrupt, pac}; | 11 | use embassy_nrf::{interrupt, pac}; |
| 12 | use embassy_time::{Duration, Timer}; | 12 | use embassy_time::{Duration, Timer}; |
| 13 | use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; | ||
| 13 | use embassy_usb::control::OutResponse; | 14 | use embassy_usb::control::OutResponse; |
| 14 | use embassy_usb::{Builder, Config}; | 15 | use embassy_usb::{Builder, Config}; |
| 15 | use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State}; | ||
| 16 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | 16 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; |
| 17 | use {defmt_rtt as _, panic_probe as _}; | 17 | use {defmt_rtt as _, panic_probe as _}; |
| 18 | 18 | ||
| @@ -59,7 +59,7 @@ async fn main(_spawner: Spawner) { | |||
| 59 | ); | 59 | ); |
| 60 | 60 | ||
| 61 | // Create classes on the builder. | 61 | // Create classes on the builder. |
| 62 | let config = embassy_usb_hid::Config { | 62 | let config = embassy_usb::class::hid::Config { |
| 63 | report_descriptor: MouseReport::desc(), | 63 | report_descriptor: MouseReport::desc(), |
| 64 | request_handler: Some(&request_handler), | 64 | request_handler: Some(&request_handler), |
| 65 | poll_ms: 60, | 65 | poll_ms: 60, |
diff --git a/examples/nrf/src/bin/usb_serial.rs b/examples/nrf/src/bin/usb_serial.rs index a740b4e0a..7c9c4184b 100644 --- a/examples/nrf/src/bin/usb_serial.rs +++ b/examples/nrf/src/bin/usb_serial.rs | |||
| @@ -9,9 +9,9 @@ use embassy_executor::Spawner; | |||
| 9 | use embassy_futures::join::join; | 9 | use embassy_futures::join::join; |
| 10 | use embassy_nrf::usb::{Driver, Instance, PowerUsb, UsbSupply}; | 10 | use embassy_nrf::usb::{Driver, Instance, PowerUsb, UsbSupply}; |
| 11 | use embassy_nrf::{interrupt, pac}; | 11 | use embassy_nrf::{interrupt, pac}; |
| 12 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||
| 12 | use embassy_usb::driver::EndpointError; | 13 | use embassy_usb::driver::EndpointError; |
| 13 | use embassy_usb::{Builder, Config}; | 14 | use embassy_usb::{Builder, Config}; |
| 14 | use embassy_usb_serial::{CdcAcmClass, State}; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 16 | ||
| 17 | #[embassy_executor::main] | 17 | #[embassy_executor::main] |
diff --git a/examples/nrf/src/bin/usb_serial_multitask.rs b/examples/nrf/src/bin/usb_serial_multitask.rs index c646c0bbd..93efc2fe6 100644 --- a/examples/nrf/src/bin/usb_serial_multitask.rs +++ b/examples/nrf/src/bin/usb_serial_multitask.rs | |||
| @@ -8,9 +8,9 @@ use defmt::{info, panic, unwrap}; | |||
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_nrf::usb::{Driver, PowerUsb}; | 9 | use embassy_nrf::usb::{Driver, PowerUsb}; |
| 10 | use embassy_nrf::{interrupt, pac, peripherals}; | 10 | use embassy_nrf::{interrupt, pac, peripherals}; |
| 11 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||
| 11 | use embassy_usb::driver::EndpointError; | 12 | use embassy_usb::driver::EndpointError; |
| 12 | use embassy_usb::{Builder, Config, UsbDevice}; | 13 | use embassy_usb::{Builder, Config, UsbDevice}; |
| 13 | use embassy_usb_serial::{CdcAcmClass, State}; | ||
| 14 | use static_cell::StaticCell; | 14 | use static_cell::StaticCell; |
| 15 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 16 | ||
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 24c3cdd67..3c8f923e7 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml | |||
| @@ -10,9 +10,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature | |||
| 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 10 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 11 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver"] } | 11 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver"] } |
| 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 12 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
| 13 | embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] } | ||
| 14 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } | 13 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } |
| 15 | embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"] } | ||
| 16 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 17 | 15 | ||
| 18 | defmt = "0.3" | 16 | defmt = "0.3" |
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 166ffe175..1057fe7fd 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs | |||
| @@ -13,8 +13,8 @@ use embassy_rp::usb::Driver; | |||
| 13 | use embassy_rp::{interrupt, peripherals}; | 13 | use embassy_rp::{interrupt, peripherals}; |
| 14 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | 14 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; |
| 15 | use embassy_sync::channel::Channel; | 15 | use embassy_sync::channel::Channel; |
| 16 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State}; | ||
| 16 | use embassy_usb::{Builder, Config, UsbDevice}; | 17 | use embassy_usb::{Builder, Config, UsbDevice}; |
| 17 | use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State}; | ||
| 18 | use embedded_io::asynch::Write; | 18 | use embedded_io::asynch::Write; |
| 19 | use static_cell::StaticCell; | 19 | use static_cell::StaticCell; |
| 20 | use {defmt_rtt as _, panic_probe as _}; | 20 | use {defmt_rtt as _, panic_probe as _}; |
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs index bf92a1636..b7d6493b4 100644 --- a/examples/rp/src/bin/usb_serial.rs +++ b/examples/rp/src/bin/usb_serial.rs | |||
| @@ -7,9 +7,9 @@ use embassy_executor::Spawner; | |||
| 7 | use embassy_futures::join::join; | 7 | use embassy_futures::join::join; |
| 8 | use embassy_rp::interrupt; | 8 | use embassy_rp::interrupt; |
| 9 | use embassy_rp::usb::{Driver, Instance}; | 9 | use embassy_rp::usb::{Driver, Instance}; |
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||
| 10 | use embassy_usb::driver::EndpointError; | 11 | use embassy_usb::driver::EndpointError; |
| 11 | use embassy_usb::{Builder, Config}; | 12 | use embassy_usb::{Builder, Config}; |
| 12 | use embassy_usb_serial::{CdcAcmClass, State}; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| 15 | #[embassy_executor::main] | 15 | #[embassy_executor::main] |
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 895e043dd..e6553789a 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml | |||
| @@ -9,7 +9,6 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature | |||
| 9 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 9 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 10 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"] } | 10 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"] } |
| 11 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 11 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
| 12 | embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] } | ||
| 13 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 12 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 14 | 13 | ||
| 15 | defmt = "0.3" | 14 | defmt = "0.3" |
diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs index a14e728ba..ad92cdeb2 100644 --- a/examples/stm32f1/src/bin/usb_serial.rs +++ b/examples/stm32f1/src/bin/usb_serial.rs | |||
| @@ -10,9 +10,9 @@ use embassy_stm32::time::Hertz; | |||
| 10 | use embassy_stm32::usb::{Driver, Instance}; | 10 | use embassy_stm32::usb::{Driver, Instance}; |
| 11 | use embassy_stm32::{interrupt, Config}; | 11 | use embassy_stm32::{interrupt, Config}; |
| 12 | use embassy_time::{Duration, Timer}; | 12 | use embassy_time::{Duration, Timer}; |
| 13 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||
| 13 | use embassy_usb::driver::EndpointError; | 14 | use embassy_usb::driver::EndpointError; |
| 14 | use embassy_usb::Builder; | 15 | use embassy_usb::Builder; |
| 15 | use embassy_usb_serial::{CdcAcmClass, State}; | ||
| 16 | use {defmt_rtt as _, panic_probe as _}; | 16 | use {defmt_rtt as _, panic_probe as _}; |
| 17 | 17 | ||
| 18 | #[embassy_executor::main] | 18 | #[embassy_executor::main] |
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 27f5c260a..f5b0b880c 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml | |||
| @@ -9,8 +9,6 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature | |||
| 9 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 9 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 10 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } | 10 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } |
| 11 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 11 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
| 12 | embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] } | ||
| 13 | embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"] } | ||
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 12 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 15 | 13 | ||
| 16 | defmt = "0.3" | 14 | defmt = "0.3" |
diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs index b9fd20e2b..f6d27c860 100644 --- a/examples/stm32f3/src/bin/usb_serial.rs +++ b/examples/stm32f3/src/bin/usb_serial.rs | |||
| @@ -10,9 +10,9 @@ use embassy_stm32::time::mhz; | |||
| 10 | use embassy_stm32::usb::{Driver, Instance}; | 10 | use embassy_stm32::usb::{Driver, Instance}; |
| 11 | use embassy_stm32::{interrupt, Config}; | 11 | use embassy_stm32::{interrupt, Config}; |
| 12 | use embassy_time::{Duration, Timer}; | 12 | use embassy_time::{Duration, Timer}; |
| 13 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||
| 13 | use embassy_usb::driver::EndpointError; | 14 | use embassy_usb::driver::EndpointError; |
| 14 | use embassy_usb::Builder; | 15 | use embassy_usb::Builder; |
| 15 | use embassy_usb_serial::{CdcAcmClass, State}; | ||
| 16 | use {defmt_rtt as _, panic_probe as _}; | 16 | use {defmt_rtt as _, panic_probe as _}; |
| 17 | 17 | ||
| 18 | #[embassy_executor::main] | 18 | #[embassy_executor::main] |
diff --git a/examples/stm32h7/src/bin/signal.rs b/examples/stm32h7/src/bin/signal.rs index cc3e4e3ca..6d7c168d5 100644 --- a/examples/stm32h7/src/bin/signal.rs +++ b/examples/stm32h7/src/bin/signal.rs | |||
| @@ -4,11 +4,12 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::{info, unwrap}; | 5 | use defmt::{info, unwrap}; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 7 | use embassy_sync::signal::Signal; | 8 | use embassy_sync::signal::Signal; |
| 8 | use embassy_time::{Duration, Timer}; | 9 | use embassy_time::{Duration, Timer}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 11 | ||
| 11 | static SIGNAL: Signal<u32> = Signal::new(); | 12 | static SIGNAL: Signal<CriticalSectionRawMutex, u32> = Signal::new(); |
| 12 | 13 | ||
| 13 | #[embassy_executor::task] | 14 | #[embassy_executor::task] |
| 14 | async fn my_sending_task() { | 15 | async fn my_sending_task() { |
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 05945f6bf..9ebab6476 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml | |||
| @@ -11,9 +11,6 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature | |||
| 11 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 11 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 12 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } | 12 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } |
| 13 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 13 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
| 14 | embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] } | ||
| 15 | embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"] } | ||
| 16 | embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"] } | ||
| 17 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } | 14 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } |
| 18 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 15 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 19 | usbd-hid = "0.6.0" | 16 | usbd-hid = "0.6.0" |
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index c96a83ead..4f36d3f5a 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs | |||
| @@ -15,8 +15,8 @@ use embassy_stm32::usb::Driver; | |||
| 15 | use embassy_stm32::{interrupt, Config}; | 15 | use embassy_stm32::{interrupt, Config}; |
| 16 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | 16 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; |
| 17 | use embassy_sync::channel::Channel; | 17 | use embassy_sync::channel::Channel; |
| 18 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State}; | ||
| 18 | use embassy_usb::{Builder, UsbDevice}; | 19 | use embassy_usb::{Builder, UsbDevice}; |
| 19 | use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State}; | ||
| 20 | use embedded_io::asynch::Write; | 20 | use embedded_io::asynch::Write; |
| 21 | use rand_core::RngCore; | 21 | use rand_core::RngCore; |
| 22 | use static_cell::StaticCell; | 22 | use static_cell::StaticCell; |
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index fa92ceae3..d38ed7496 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs | |||
| @@ -9,9 +9,9 @@ use embassy_stm32::rcc::*; | |||
| 9 | use embassy_stm32::usb::Driver; | 9 | use embassy_stm32::usb::Driver; |
| 10 | use embassy_stm32::{interrupt, Config}; | 10 | use embassy_stm32::{interrupt, Config}; |
| 11 | use embassy_time::{Duration, Timer}; | 11 | use embassy_time::{Duration, Timer}; |
| 12 | use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; | ||
| 12 | use embassy_usb::control::OutResponse; | 13 | use embassy_usb::control::OutResponse; |
| 13 | use embassy_usb::Builder; | 14 | use embassy_usb::Builder; |
| 14 | use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State}; | ||
| 15 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | 15 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; |
| 16 | use {defmt_rtt as _, panic_probe as _}; | 16 | use {defmt_rtt as _, panic_probe as _}; |
| 17 | 17 | ||
| @@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) { | |||
| 55 | ); | 55 | ); |
| 56 | 56 | ||
| 57 | // Create classes on the builder. | 57 | // Create classes on the builder. |
| 58 | let config = embassy_usb_hid::Config { | 58 | let config = embassy_usb::class::hid::Config { |
| 59 | report_descriptor: MouseReport::desc(), | 59 | report_descriptor: MouseReport::desc(), |
| 60 | request_handler: Some(&request_handler), | 60 | request_handler: Some(&request_handler), |
| 61 | poll_ms: 60, | 61 | poll_ms: 60, |
diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs index 7484dc832..7562a4e96 100644 --- a/examples/stm32l5/src/bin/usb_serial.rs +++ b/examples/stm32l5/src/bin/usb_serial.rs | |||
| @@ -8,9 +8,9 @@ use embassy_futures::join::join; | |||
| 8 | use embassy_stm32::rcc::*; | 8 | use embassy_stm32::rcc::*; |
| 9 | use embassy_stm32::usb::{Driver, Instance}; | 9 | use embassy_stm32::usb::{Driver, Instance}; |
| 10 | use embassy_stm32::{interrupt, Config}; | 10 | use embassy_stm32::{interrupt, Config}; |
| 11 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | ||
| 11 | use embassy_usb::driver::EndpointError; | 12 | use embassy_usb::driver::EndpointError; |
| 12 | use embassy_usb::Builder; | 13 | use embassy_usb::Builder; |
| 13 | use embassy_usb_serial::{CdcAcmClass, State}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | 14 | use {defmt_rtt as _, panic_probe as _}; |
| 15 | 15 | ||
| 16 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
diff --git a/examples/stm32wl/src/bin/subghz.rs b/examples/stm32wl/src/bin/subghz.rs index 3c60a8de4..32c8b5515 100644 --- a/examples/stm32wl/src/bin/subghz.rs +++ b/examples/stm32wl/src/bin/subghz.rs | |||
| @@ -12,6 +12,7 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; | |||
| 12 | use embassy_stm32::interrupt; | 12 | use embassy_stm32::interrupt; |
| 13 | use embassy_stm32::interrupt::{Interrupt, InterruptExt}; | 13 | use embassy_stm32::interrupt::{Interrupt, InterruptExt}; |
| 14 | use embassy_stm32::subghz::*; | 14 | use embassy_stm32::subghz::*; |
| 15 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 15 | use embassy_sync::signal::Signal; | 16 | use embassy_sync::signal::Signal; |
| 16 | use {defmt_rtt as _, panic_probe as _}; | 17 | use {defmt_rtt as _, panic_probe as _}; |
| 17 | 18 | ||
| @@ -64,7 +65,7 @@ async fn main(_spawner: Spawner) { | |||
| 64 | let button = Input::new(p.PA0, Pull::Up); | 65 | let button = Input::new(p.PA0, Pull::Up); |
| 65 | let mut pin = ExtiInput::new(button, p.EXTI0); | 66 | let mut pin = ExtiInput::new(button, p.EXTI0); |
| 66 | 67 | ||
| 67 | static IRQ_SIGNAL: Signal<()> = Signal::new(); | 68 | static IRQ_SIGNAL: Signal<CriticalSectionRawMutex, ()> = Signal::new(); |
| 68 | let radio_irq = interrupt::take!(SUBGHZ_RADIO); | 69 | let radio_irq = interrupt::take!(SUBGHZ_RADIO); |
| 69 | radio_irq.set_handler(|_| { | 70 | radio_irq.set_handler(|_| { |
| 70 | IRQ_SIGNAL.signal(()); | 71 | IRQ_SIGNAL.signal(()); |
diff --git a/tests/rp/.cargo/config.toml b/tests/rp/.cargo/config.toml index 0330025e4..9611db3a0 100644 --- a/tests/rp/.cargo/config.toml +++ b/tests/rp/.cargo/config.toml | |||
| @@ -3,7 +3,7 @@ build-std = ["core"] | |||
| 3 | build-std-features = ["panic_immediate_abort"] | 3 | build-std-features = ["panic_immediate_abort"] |
| 4 | 4 | ||
| 5 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | 5 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] |
| 6 | #runner = "teleprobe client run --target bluepill-stm32f103c8 --elf" | 6 | #runner = "teleprobe client run --target rpi-pico --elf" |
| 7 | runner = "teleprobe local run --chip RP2040 --elf" | 7 | runner = "teleprobe local run --chip RP2040 --elf" |
| 8 | 8 | ||
| 9 | rustflags = [ | 9 | rustflags = [ |
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 11ecb9169..503373759 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml | |||
| @@ -7,7 +7,7 @@ version = "0.1.0" | |||
| 7 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } | 7 | embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } |
| 8 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } | 8 | embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } |
| 9 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] } | 9 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] } |
| 10 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits"] } | 10 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver"] } |
| 11 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 11 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 12 | 12 | ||
| 13 | defmt = "0.3.0" | 13 | defmt = "0.3.0" |
| @@ -20,6 +20,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } | |||
| 20 | embedded-hal-async = { version = "0.1.0-alpha.1" } | 20 | embedded-hal-async = { version = "0.1.0-alpha.1" } |
| 21 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } | 21 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } |
| 22 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 22 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 23 | embedded-io = { version = "0.3.0", features = ["async"] } | ||
| 23 | 24 | ||
| 24 | [profile.dev] | 25 | [profile.dev] |
| 25 | debug = 2 | 26 | debug = 2 |
diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs new file mode 100644 index 000000000..9cc20bb98 --- /dev/null +++ b/tests/rp/src/bin/uart_buffered.rs | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::{assert_eq, *}; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_rp::interrupt; | ||
| 8 | use embassy_rp::uart::{BufferedUart, Config, State, Uart}; | ||
| 9 | use embedded_io::asynch::{Read, Write}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) { | ||
| 14 | let p = embassy_rp::init(Default::default()); | ||
| 15 | info!("Hello World!"); | ||
| 16 | |||
| 17 | let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0); | ||
| 18 | |||
| 19 | let config = Config::default(); | ||
| 20 | let uart = Uart::new_blocking(uart, tx, rx, config); | ||
| 21 | |||
| 22 | let irq = interrupt::take!(UART0_IRQ); | ||
| 23 | let tx_buf = &mut [0u8; 16]; | ||
| 24 | let rx_buf = &mut [0u8; 16]; | ||
| 25 | let mut state = State::new(); | ||
| 26 | let mut uart = BufferedUart::new(&mut state, uart, irq, tx_buf, rx_buf); | ||
| 27 | |||
| 28 | // Make sure we send more bytes than fits in the FIFO, to test the actual | ||
| 29 | // bufferedUart. | ||
| 30 | |||
| 31 | let data = [ | ||
| 32 | 1_u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, | ||
| 33 | 30, 31, 32, | ||
| 34 | ]; | ||
| 35 | uart.write_all(&data).await.unwrap(); | ||
| 36 | info!("Done writing"); | ||
| 37 | |||
| 38 | let mut buf = [0; 32]; | ||
| 39 | uart.read_exact(&mut buf).await.unwrap(); | ||
| 40 | assert_eq!(buf, data); | ||
| 41 | |||
| 42 | info!("Test OK"); | ||
| 43 | cortex_m::asm::bkpt(); | ||
| 44 | } | ||
