Merge pull request #1746 from embassy-rs/enc28j60-v2
wip: enc28j60 driver.
This commit is contained in:
		
						commit
						03576b9e83
					
				
							
								
								
									
										18
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							@ -6,16 +6,21 @@
 | 
				
			|||||||
  "rust-analyzer.check.allTargets": false,
 | 
					  "rust-analyzer.check.allTargets": false,
 | 
				
			||||||
  "rust-analyzer.check.noDefaultFeatures": true,
 | 
					  "rust-analyzer.check.noDefaultFeatures": true,
 | 
				
			||||||
  "rust-analyzer.cargo.noDefaultFeatures": true,
 | 
					  "rust-analyzer.cargo.noDefaultFeatures": true,
 | 
				
			||||||
  "rust-analyzer.cargo.target": "thumbv7m-none-eabi",
 | 
					  "rust-analyzer.showUnlinkedFileNotification": false,
 | 
				
			||||||
 | 
					  // uncomment the target of your chip.
 | 
				
			||||||
 | 
					  //"rust-analyzer.cargo.target": "thumbv6m-none-eabi",
 | 
				
			||||||
 | 
					  //"rust-analyzer.cargo.target": "thumbv7m-none-eabi",
 | 
				
			||||||
 | 
					  "rust-analyzer.cargo.target": "thumbv7em-none-eabi",
 | 
				
			||||||
  //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
 | 
					  //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
 | 
				
			||||||
  "rust-analyzer.cargo.features": [
 | 
					  "rust-analyzer.cargo.features": [
 | 
				
			||||||
    ///"nightly",
 | 
					    // Uncomment if the example has a "nightly" feature.
 | 
				
			||||||
 | 
					    "nightly",
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "rust-analyzer.linkedProjects": [
 | 
					  "rust-analyzer.linkedProjects": [
 | 
				
			||||||
    // Declare for the target you wish to develop
 | 
					    // Uncomment ONE line for the chip you want to work on.
 | 
				
			||||||
    // "embassy-executor/Cargo.toml",
 | 
					    // This makes rust-analyzer work on the example crate and all its dependencies.
 | 
				
			||||||
    // "embassy-sync/Cargo.toml",
 | 
					    "examples/nrf52840/Cargo.toml",
 | 
				
			||||||
    "examples/stm32wl/Cargo.toml",
 | 
					    // "examples/nrf52840-rtic/Cargo.toml",
 | 
				
			||||||
    // "examples/nrf5340/Cargo.toml",
 | 
					    // "examples/nrf5340/Cargo.toml",
 | 
				
			||||||
    // "examples/nrf-rtos-trace/Cargo.toml",
 | 
					    // "examples/nrf-rtos-trace/Cargo.toml",
 | 
				
			||||||
    // "examples/rp/Cargo.toml",
 | 
					    // "examples/rp/Cargo.toml",
 | 
				
			||||||
@ -41,5 +46,4 @@
 | 
				
			|||||||
    // "examples/stm32wl/Cargo.toml",
 | 
					    // "examples/stm32wl/Cargo.toml",
 | 
				
			||||||
    // "examples/wasm/Cargo.toml",
 | 
					    // "examples/wasm/Cargo.toml",
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "rust-analyzer.showUnlinkedFileNotification": false,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								embassy-net-enc28j60/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								embassy-net-enc28j60/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "embassy-net-enc28j60"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					description = "embassy-net driver for the ENC28J60 ethernet chip"
 | 
				
			||||||
 | 
					keywords = ["embedded", "enc28j60", "embassy-net", "embedded-hal-async", "ethernet", "async"]
 | 
				
			||||||
 | 
					categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
 | 
				
			||||||
 | 
					license = "MIT OR Apache-2.0"
 | 
				
			||||||
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					embedded-hal = { version = "1.0.0-alpha.11" }
 | 
				
			||||||
 | 
					embedded-hal-async = { version = "=0.2.0-alpha.2" }
 | 
				
			||||||
 | 
					embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
 | 
				
			||||||
 | 
					embassy-time = { version = "0.1.2", path = "../embassy-time" }
 | 
				
			||||||
 | 
					embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defmt = { version = "0.3", optional = true }
 | 
				
			||||||
 | 
					log = { version = "0.4.14", optional = true }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[package.metadata.embassy_docs]
 | 
				
			||||||
 | 
					src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-enc28j60-v$VERSION/embassy-net-enc28j60/src/"
 | 
				
			||||||
 | 
					src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-enc28j60/src/"
 | 
				
			||||||
 | 
					target = "thumbv7em-none-eabi"
 | 
				
			||||||
							
								
								
									
										19
									
								
								embassy-net-enc28j60/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								embassy-net-enc28j60/README.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					# `embassy-net-enc28j60`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[`embassy-net`](https://crates.io/crates/embassy-net) integration for the Microchip ENC28J60 Ethernet chip.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Based on [@japaric](https://github.com/japaric)'s [`enc28j60`](https://github.com/japaric/enc28j60) crate.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Interoperability
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This crate can run on any executor.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This work is licensed under either of
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
 | 
				
			||||||
 | 
					  http://www.apache.org/licenses/LICENSE-2.0)
 | 
				
			||||||
 | 
					- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					at your option.
 | 
				
			||||||
							
								
								
									
										69
									
								
								embassy-net-enc28j60/src/bank0.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								embassy-net-enc28j60/src/bank0.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					#[allow(dead_code)]
 | 
				
			||||||
 | 
					#[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					pub enum Register {
 | 
				
			||||||
 | 
					    ERDPTL = 0x00,
 | 
				
			||||||
 | 
					    ERDPTH = 0x01,
 | 
				
			||||||
 | 
					    EWRPTL = 0x02,
 | 
				
			||||||
 | 
					    EWRPTH = 0x03,
 | 
				
			||||||
 | 
					    ETXSTL = 0x04,
 | 
				
			||||||
 | 
					    ETXSTH = 0x05,
 | 
				
			||||||
 | 
					    ETXNDL = 0x06,
 | 
				
			||||||
 | 
					    ETXNDH = 0x07,
 | 
				
			||||||
 | 
					    ERXSTL = 0x08,
 | 
				
			||||||
 | 
					    ERXSTH = 0x09,
 | 
				
			||||||
 | 
					    ERXNDL = 0x0a,
 | 
				
			||||||
 | 
					    ERXNDH = 0x0b,
 | 
				
			||||||
 | 
					    ERXRDPTL = 0x0c,
 | 
				
			||||||
 | 
					    ERXRDPTH = 0x0d,
 | 
				
			||||||
 | 
					    ERXWRPTL = 0x0e,
 | 
				
			||||||
 | 
					    ERXWRPTH = 0x0f,
 | 
				
			||||||
 | 
					    EDMASTL = 0x10,
 | 
				
			||||||
 | 
					    EDMASTH = 0x11,
 | 
				
			||||||
 | 
					    EDMANDL = 0x12,
 | 
				
			||||||
 | 
					    EDMANDH = 0x13,
 | 
				
			||||||
 | 
					    EDMADSTL = 0x14,
 | 
				
			||||||
 | 
					    EDMADSTH = 0x15,
 | 
				
			||||||
 | 
					    EDMACSL = 0x16,
 | 
				
			||||||
 | 
					    EDMACSH = 0x17,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Register {
 | 
				
			||||||
 | 
					    pub(crate) fn addr(&self) -> u8 {
 | 
				
			||||||
 | 
					        *self as u8
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub(crate) fn is_eth_register(&self) -> bool {
 | 
				
			||||||
 | 
					        match *self {
 | 
				
			||||||
 | 
					            Register::ERDPTL => true,
 | 
				
			||||||
 | 
					            Register::ERDPTH => true,
 | 
				
			||||||
 | 
					            Register::EWRPTL => true,
 | 
				
			||||||
 | 
					            Register::EWRPTH => true,
 | 
				
			||||||
 | 
					            Register::ETXSTL => true,
 | 
				
			||||||
 | 
					            Register::ETXSTH => true,
 | 
				
			||||||
 | 
					            Register::ETXNDL => true,
 | 
				
			||||||
 | 
					            Register::ETXNDH => true,
 | 
				
			||||||
 | 
					            Register::ERXSTL => true,
 | 
				
			||||||
 | 
					            Register::ERXSTH => true,
 | 
				
			||||||
 | 
					            Register::ERXNDL => true,
 | 
				
			||||||
 | 
					            Register::ERXNDH => true,
 | 
				
			||||||
 | 
					            Register::ERXRDPTL => true,
 | 
				
			||||||
 | 
					            Register::ERXRDPTH => true,
 | 
				
			||||||
 | 
					            Register::ERXWRPTL => true,
 | 
				
			||||||
 | 
					            Register::ERXWRPTH => true,
 | 
				
			||||||
 | 
					            Register::EDMASTL => true,
 | 
				
			||||||
 | 
					            Register::EDMASTH => true,
 | 
				
			||||||
 | 
					            Register::EDMANDL => true,
 | 
				
			||||||
 | 
					            Register::EDMANDH => true,
 | 
				
			||||||
 | 
					            Register::EDMADSTL => true,
 | 
				
			||||||
 | 
					            Register::EDMADSTH => true,
 | 
				
			||||||
 | 
					            Register::EDMACSL => true,
 | 
				
			||||||
 | 
					            Register::EDMACSH => true,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Into<super::Register> for Register {
 | 
				
			||||||
 | 
					    fn into(self) -> super::Register {
 | 
				
			||||||
 | 
					        super::Register::Bank0(self)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										84
									
								
								embassy-net-enc28j60/src/bank1.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								embassy-net-enc28j60/src/bank1.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					#[allow(dead_code)]
 | 
				
			||||||
 | 
					#[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					pub enum Register {
 | 
				
			||||||
 | 
					    EHT0 = 0x00,
 | 
				
			||||||
 | 
					    EHT1 = 0x01,
 | 
				
			||||||
 | 
					    EHT2 = 0x02,
 | 
				
			||||||
 | 
					    EHT3 = 0x03,
 | 
				
			||||||
 | 
					    EHT4 = 0x04,
 | 
				
			||||||
 | 
					    EHT5 = 0x05,
 | 
				
			||||||
 | 
					    EHT6 = 0x06,
 | 
				
			||||||
 | 
					    EHT7 = 0x07,
 | 
				
			||||||
 | 
					    EPMM0 = 0x08,
 | 
				
			||||||
 | 
					    EPMM1 = 0x09,
 | 
				
			||||||
 | 
					    EPMM2 = 0x0a,
 | 
				
			||||||
 | 
					    EPMM3 = 0x0b,
 | 
				
			||||||
 | 
					    EPMM4 = 0x0c,
 | 
				
			||||||
 | 
					    EPMM5 = 0x0d,
 | 
				
			||||||
 | 
					    EPMM6 = 0x0e,
 | 
				
			||||||
 | 
					    EPMM7 = 0x0f,
 | 
				
			||||||
 | 
					    EPMCSL = 0x10,
 | 
				
			||||||
 | 
					    EPMCSH = 0x11,
 | 
				
			||||||
 | 
					    EPMOL = 0x14,
 | 
				
			||||||
 | 
					    EPMOH = 0x15,
 | 
				
			||||||
 | 
					    ERXFCON = 0x18,
 | 
				
			||||||
 | 
					    EPKTCNT = 0x19,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Register {
 | 
				
			||||||
 | 
					    pub(crate) fn addr(&self) -> u8 {
 | 
				
			||||||
 | 
					        *self as u8
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub(crate) fn is_eth_register(&self) -> bool {
 | 
				
			||||||
 | 
					        match *self {
 | 
				
			||||||
 | 
					            Register::EHT0 => true,
 | 
				
			||||||
 | 
					            Register::EHT1 => true,
 | 
				
			||||||
 | 
					            Register::EHT2 => true,
 | 
				
			||||||
 | 
					            Register::EHT3 => true,
 | 
				
			||||||
 | 
					            Register::EHT4 => true,
 | 
				
			||||||
 | 
					            Register::EHT5 => true,
 | 
				
			||||||
 | 
					            Register::EHT6 => true,
 | 
				
			||||||
 | 
					            Register::EHT7 => true,
 | 
				
			||||||
 | 
					            Register::EPMM0 => true,
 | 
				
			||||||
 | 
					            Register::EPMM1 => true,
 | 
				
			||||||
 | 
					            Register::EPMM2 => true,
 | 
				
			||||||
 | 
					            Register::EPMM3 => true,
 | 
				
			||||||
 | 
					            Register::EPMM4 => true,
 | 
				
			||||||
 | 
					            Register::EPMM5 => true,
 | 
				
			||||||
 | 
					            Register::EPMM6 => true,
 | 
				
			||||||
 | 
					            Register::EPMM7 => true,
 | 
				
			||||||
 | 
					            Register::EPMCSL => true,
 | 
				
			||||||
 | 
					            Register::EPMCSH => true,
 | 
				
			||||||
 | 
					            Register::EPMOL => true,
 | 
				
			||||||
 | 
					            Register::EPMOH => true,
 | 
				
			||||||
 | 
					            Register::ERXFCON => true,
 | 
				
			||||||
 | 
					            Register::EPKTCNT => true,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Into<super::Register> for Register {
 | 
				
			||||||
 | 
					    fn into(self) -> super::Register {
 | 
				
			||||||
 | 
					        super::Register::Bank1(self)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register!(ERXFCON, 0b1010_0001, u8, {
 | 
				
			||||||
 | 
					    #[doc = "Broadcast Filter Enable bit"]
 | 
				
			||||||
 | 
					    bcen @ 0,
 | 
				
			||||||
 | 
					    #[doc = "Multicast Filter Enable bit"]
 | 
				
			||||||
 | 
					    mcen @ 1,
 | 
				
			||||||
 | 
					    #[doc = "Hash Table Filter Enable bit"]
 | 
				
			||||||
 | 
					    hten @ 2,
 | 
				
			||||||
 | 
					    #[doc = "Magic Packet™ Filter Enable bit"]
 | 
				
			||||||
 | 
					    mpen @ 3,
 | 
				
			||||||
 | 
					    #[doc = "Pattern Match Filter Enable bit"]
 | 
				
			||||||
 | 
					    pmen @ 4,
 | 
				
			||||||
 | 
					    #[doc = "Post-Filter CRC Check Enable bit"]
 | 
				
			||||||
 | 
					    crcen @ 5,
 | 
				
			||||||
 | 
					    #[doc = "AND/OR Filter Select bit"]
 | 
				
			||||||
 | 
					    andor @ 6,
 | 
				
			||||||
 | 
					    #[doc = "Unicast Filter Enable bit"]
 | 
				
			||||||
 | 
					    ucen @ 7,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										86
									
								
								embassy-net-enc28j60/src/bank2.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								embassy-net-enc28j60/src/bank2.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					#[allow(dead_code)]
 | 
				
			||||||
 | 
					#[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					pub enum Register {
 | 
				
			||||||
 | 
					    MACON1 = 0x00,
 | 
				
			||||||
 | 
					    MACON3 = 0x02,
 | 
				
			||||||
 | 
					    MACON4 = 0x03,
 | 
				
			||||||
 | 
					    MABBIPG = 0x04,
 | 
				
			||||||
 | 
					    MAIPGL = 0x06,
 | 
				
			||||||
 | 
					    MAIPGH = 0x07,
 | 
				
			||||||
 | 
					    MACLCON1 = 0x08,
 | 
				
			||||||
 | 
					    MACLCON2 = 0x09,
 | 
				
			||||||
 | 
					    MAMXFLL = 0x0a,
 | 
				
			||||||
 | 
					    MAMXFLH = 0x0b,
 | 
				
			||||||
 | 
					    MICMD = 0x12,
 | 
				
			||||||
 | 
					    MIREGADR = 0x14,
 | 
				
			||||||
 | 
					    MIWRL = 0x16,
 | 
				
			||||||
 | 
					    MIWRH = 0x17,
 | 
				
			||||||
 | 
					    MIRDL = 0x18,
 | 
				
			||||||
 | 
					    MIRDH = 0x19,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Register {
 | 
				
			||||||
 | 
					    pub(crate) fn addr(&self) -> u8 {
 | 
				
			||||||
 | 
					        *self as u8
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub(crate) fn is_eth_register(&self) -> bool {
 | 
				
			||||||
 | 
					        match *self {
 | 
				
			||||||
 | 
					            Register::MACON1 => false,
 | 
				
			||||||
 | 
					            Register::MACON3 => false,
 | 
				
			||||||
 | 
					            Register::MACON4 => false,
 | 
				
			||||||
 | 
					            Register::MABBIPG => false,
 | 
				
			||||||
 | 
					            Register::MAIPGL => false,
 | 
				
			||||||
 | 
					            Register::MAIPGH => false,
 | 
				
			||||||
 | 
					            Register::MACLCON1 => false,
 | 
				
			||||||
 | 
					            Register::MACLCON2 => false,
 | 
				
			||||||
 | 
					            Register::MAMXFLL => false,
 | 
				
			||||||
 | 
					            Register::MAMXFLH => false,
 | 
				
			||||||
 | 
					            Register::MICMD => false,
 | 
				
			||||||
 | 
					            Register::MIREGADR => false,
 | 
				
			||||||
 | 
					            Register::MIWRL => false,
 | 
				
			||||||
 | 
					            Register::MIWRH => false,
 | 
				
			||||||
 | 
					            Register::MIRDL => false,
 | 
				
			||||||
 | 
					            Register::MIRDH => false,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Into<super::Register> for Register {
 | 
				
			||||||
 | 
					    fn into(self) -> super::Register {
 | 
				
			||||||
 | 
					        super::Register::Bank2(self)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register!(MACON1, 0, u8, {
 | 
				
			||||||
 | 
					    #[doc = "Enable packets to be received by the MAC"]
 | 
				
			||||||
 | 
					    marxen @ 0,
 | 
				
			||||||
 | 
					    #[doc = "Control frames will be discarded after being processed by the MAC"]
 | 
				
			||||||
 | 
					    passall @ 1,
 | 
				
			||||||
 | 
					    #[doc = "Inhibit transmissions when pause control frames are received"]
 | 
				
			||||||
 | 
					    rxpaus @ 2,
 | 
				
			||||||
 | 
					    #[doc = "Allow the MAC to transmit pause control frames"]
 | 
				
			||||||
 | 
					    txpaus @ 3,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register!(MACON3, 0, u8, {
 | 
				
			||||||
 | 
					    #[doc = "MAC will operate in Full-Duplex mode"]
 | 
				
			||||||
 | 
					    fuldpx @ 0,
 | 
				
			||||||
 | 
					    #[doc = "The type/length field of transmitted and received frames will be checked"]
 | 
				
			||||||
 | 
					    frmlnen @ 1,
 | 
				
			||||||
 | 
					    #[doc = "Frames bigger than MAMXFL will be aborted when transmitted or received"]
 | 
				
			||||||
 | 
					    hfrmen @ 2,
 | 
				
			||||||
 | 
					    #[doc = "No proprietary header is present"]
 | 
				
			||||||
 | 
					    phdren @ 3,
 | 
				
			||||||
 | 
					    #[doc = "MAC will append a valid CRC to all frames transmitted regardless of PADCFG bit"]
 | 
				
			||||||
 | 
					    txcrcen @ 4,
 | 
				
			||||||
 | 
					    #[doc = "All short frames will be zero-padded to 64 bytes and a valid CRC will then be appended"]
 | 
				
			||||||
 | 
					    padcfg @ 5..7,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register!(MICMD, 0, u8, {
 | 
				
			||||||
 | 
					    #[doc = "MII Read Enable bit"]
 | 
				
			||||||
 | 
					    miird @ 0,
 | 
				
			||||||
 | 
					    #[doc = "MII Scan Enable bit"]
 | 
				
			||||||
 | 
					    miiscan @ 1,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										53
									
								
								embassy-net-enc28j60/src/bank3.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								embassy-net-enc28j60/src/bank3.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					#[allow(dead_code)]
 | 
				
			||||||
 | 
					#[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					pub enum Register {
 | 
				
			||||||
 | 
					    MAADR5 = 0x00,
 | 
				
			||||||
 | 
					    MAADR6 = 0x01,
 | 
				
			||||||
 | 
					    MAADR3 = 0x02,
 | 
				
			||||||
 | 
					    MAADR4 = 0x03,
 | 
				
			||||||
 | 
					    MAADR1 = 0x04,
 | 
				
			||||||
 | 
					    MAADR2 = 0x05,
 | 
				
			||||||
 | 
					    EBSTSD = 0x06,
 | 
				
			||||||
 | 
					    EBSTCON = 0x07,
 | 
				
			||||||
 | 
					    EBSTCSL = 0x08,
 | 
				
			||||||
 | 
					    EBSTCSH = 0x09,
 | 
				
			||||||
 | 
					    MISTAT = 0x0a,
 | 
				
			||||||
 | 
					    EREVID = 0x12,
 | 
				
			||||||
 | 
					    ECOCON = 0x15,
 | 
				
			||||||
 | 
					    EFLOCON = 0x17,
 | 
				
			||||||
 | 
					    EPAUSL = 0x18,
 | 
				
			||||||
 | 
					    EPAUSH = 0x19,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Register {
 | 
				
			||||||
 | 
					    pub(crate) fn addr(&self) -> u8 {
 | 
				
			||||||
 | 
					        *self as u8
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub(crate) fn is_eth_register(&self) -> bool {
 | 
				
			||||||
 | 
					        match *self {
 | 
				
			||||||
 | 
					            Register::MAADR5 => false,
 | 
				
			||||||
 | 
					            Register::MAADR6 => false,
 | 
				
			||||||
 | 
					            Register::MAADR3 => false,
 | 
				
			||||||
 | 
					            Register::MAADR4 => false,
 | 
				
			||||||
 | 
					            Register::MAADR1 => false,
 | 
				
			||||||
 | 
					            Register::MAADR2 => false,
 | 
				
			||||||
 | 
					            Register::EBSTSD => true,
 | 
				
			||||||
 | 
					            Register::EBSTCON => true,
 | 
				
			||||||
 | 
					            Register::EBSTCSL => true,
 | 
				
			||||||
 | 
					            Register::EBSTCSH => true,
 | 
				
			||||||
 | 
					            Register::MISTAT => false,
 | 
				
			||||||
 | 
					            Register::EREVID => true,
 | 
				
			||||||
 | 
					            Register::ECOCON => true,
 | 
				
			||||||
 | 
					            Register::EFLOCON => true,
 | 
				
			||||||
 | 
					            Register::EPAUSL => true,
 | 
				
			||||||
 | 
					            Register::EPAUSH => true,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Into<super::Register> for Register {
 | 
				
			||||||
 | 
					    fn into(self) -> super::Register {
 | 
				
			||||||
 | 
					        super::Register::Bank3(self)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										106
									
								
								embassy-net-enc28j60/src/common.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								embassy-net-enc28j60/src/common.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					#[allow(dead_code)]
 | 
				
			||||||
 | 
					#[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					pub enum Register {
 | 
				
			||||||
 | 
					    ECON1 = 0x1f,
 | 
				
			||||||
 | 
					    ECON2 = 0x1e,
 | 
				
			||||||
 | 
					    EIE = 0x1b,
 | 
				
			||||||
 | 
					    EIR = 0x1c,
 | 
				
			||||||
 | 
					    ESTAT = 0x1d,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Register {
 | 
				
			||||||
 | 
					    pub(crate) fn addr(&self) -> u8 {
 | 
				
			||||||
 | 
					        *self as u8
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub(crate) fn is_eth_register(&self) -> bool {
 | 
				
			||||||
 | 
					        match *self {
 | 
				
			||||||
 | 
					            Register::ECON1 => true,
 | 
				
			||||||
 | 
					            Register::ECON2 => true,
 | 
				
			||||||
 | 
					            Register::EIE => true,
 | 
				
			||||||
 | 
					            Register::EIR => true,
 | 
				
			||||||
 | 
					            Register::ESTAT => true,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Into<super::Register> for Register {
 | 
				
			||||||
 | 
					    fn into(self) -> super::Register {
 | 
				
			||||||
 | 
					        super::Register::Common(self)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register!(EIE, 0, u8, {
 | 
				
			||||||
 | 
					    #[doc = "Receive Error Interrupt Enable bit"]
 | 
				
			||||||
 | 
					    rxerie @ 0,
 | 
				
			||||||
 | 
					    #[doc = "Transmit Error Interrupt Enable bit"]
 | 
				
			||||||
 | 
					    txerie @ 1,
 | 
				
			||||||
 | 
					    #[doc = "Transmit Enable bit"]
 | 
				
			||||||
 | 
					    txie @ 3,
 | 
				
			||||||
 | 
					    #[doc = "Link Status Change Interrupt Enable bit"]
 | 
				
			||||||
 | 
					    linkie @ 4,
 | 
				
			||||||
 | 
					    #[doc = "DMA Interrupt Enable bit"]
 | 
				
			||||||
 | 
					    dmaie @ 5,
 | 
				
			||||||
 | 
					    #[doc = "Receive Packet Pending Interrupt Enable bit"]
 | 
				
			||||||
 | 
					    pktie @ 6,
 | 
				
			||||||
 | 
					    #[doc = "Global INT Interrupt Enable bit"]
 | 
				
			||||||
 | 
					    intie @ 7,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register!(EIR, 0, u8, {
 | 
				
			||||||
 | 
					    #[doc = "Receive Error Interrupt Flag bit"]
 | 
				
			||||||
 | 
					    rxerif @ 0,
 | 
				
			||||||
 | 
					    #[doc = "Transmit Error Interrupt Flag bit"]
 | 
				
			||||||
 | 
					    txerif @ 1,
 | 
				
			||||||
 | 
					    #[doc = "Transmit Interrupt Flag bit"]
 | 
				
			||||||
 | 
					    txif @ 3,
 | 
				
			||||||
 | 
					    #[doc = "Link Change Interrupt Flag bit"]
 | 
				
			||||||
 | 
					    linkif @ 4,
 | 
				
			||||||
 | 
					    #[doc = "DMA Interrupt Flag bit"]
 | 
				
			||||||
 | 
					    dmaif @ 5,
 | 
				
			||||||
 | 
					    #[doc = "Receive Packet Pending Interrupt Flag bit"]
 | 
				
			||||||
 | 
					    pktif @ 6,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register!(ESTAT, 0, u8, {
 | 
				
			||||||
 | 
					    #[doc = "Clock Ready bit"]
 | 
				
			||||||
 | 
					    clkrdy @ 0,
 | 
				
			||||||
 | 
					    #[doc = "Transmit Abort Error bit"]
 | 
				
			||||||
 | 
					    txabrt @ 1,
 | 
				
			||||||
 | 
					    #[doc = "Receive Busy bit"]
 | 
				
			||||||
 | 
					    rxbusy @ 2,
 | 
				
			||||||
 | 
					    #[doc = "Late Collision Error bit"]
 | 
				
			||||||
 | 
					    latecol @ 4,
 | 
				
			||||||
 | 
					    #[doc = "Ethernet Buffer Error Status bit"]
 | 
				
			||||||
 | 
					    bufer @ 6,
 | 
				
			||||||
 | 
					    #[doc = "INT Interrupt Flag bit"]
 | 
				
			||||||
 | 
					    int @ 7,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register!(ECON2, 0b1000_0000, u8, {
 | 
				
			||||||
 | 
					    #[doc = "Voltage Regulator Power Save Enable bit"]
 | 
				
			||||||
 | 
					    vrps @ 3,
 | 
				
			||||||
 | 
					    #[doc = "Power Save Enable bit"]
 | 
				
			||||||
 | 
					    pwrsv @ 5,
 | 
				
			||||||
 | 
					    #[doc = "Packet Decrement bit"]
 | 
				
			||||||
 | 
					    pktdec @ 6,
 | 
				
			||||||
 | 
					    #[doc = "Automatic Buffer Pointer Increment Enable bit"]
 | 
				
			||||||
 | 
					    autoinc @ 7,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register!(ECON1, 0, u8, {
 | 
				
			||||||
 | 
					    #[doc = "Bank Select bits"]
 | 
				
			||||||
 | 
					    bsel @ 0..1,
 | 
				
			||||||
 | 
					    #[doc = "Receive Enable bi"]
 | 
				
			||||||
 | 
					    rxen @ 2,
 | 
				
			||||||
 | 
					    #[doc = "Transmit Request to Send bit"]
 | 
				
			||||||
 | 
					    txrts @ 3,
 | 
				
			||||||
 | 
					    #[doc = "DMA Checksum Enable bit"]
 | 
				
			||||||
 | 
					    csumen @ 4,
 | 
				
			||||||
 | 
					    #[doc = "DMA Start and Busy Status bit"]
 | 
				
			||||||
 | 
					    dmast @ 5,
 | 
				
			||||||
 | 
					    #[doc = "Receive Logic Reset bit"]
 | 
				
			||||||
 | 
					    rxrst @ 6,
 | 
				
			||||||
 | 
					    #[doc = "Transmit Logic Reset bit"]
 | 
				
			||||||
 | 
					    txrst @ 7,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										225
									
								
								embassy-net-enc28j60/src/fmt.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								embassy-net-enc28j60/src/fmt.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,225 @@
 | 
				
			|||||||
 | 
					#![macro_use]
 | 
				
			||||||
 | 
					#![allow(unused_macros)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(all(feature = "defmt", feature = "log"))]
 | 
				
			||||||
 | 
					compile_error!("You may not enable both `defmt` and `log` features.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! assert {
 | 
				
			||||||
 | 
					    ($($x:tt)*) => {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            #[cfg(not(feature = "defmt"))]
 | 
				
			||||||
 | 
					            ::core::assert!($($x)*);
 | 
				
			||||||
 | 
					            #[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					            ::defmt::assert!($($x)*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! assert_eq {
 | 
				
			||||||
 | 
					    ($($x:tt)*) => {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            #[cfg(not(feature = "defmt"))]
 | 
				
			||||||
 | 
					            ::core::assert_eq!($($x)*);
 | 
				
			||||||
 | 
					            #[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					            ::defmt::assert_eq!($($x)*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! assert_ne {
 | 
				
			||||||
 | 
					    ($($x:tt)*) => {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            #[cfg(not(feature = "defmt"))]
 | 
				
			||||||
 | 
					            ::core::assert_ne!($($x)*);
 | 
				
			||||||
 | 
					            #[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					            ::defmt::assert_ne!($($x)*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! debug_assert {
 | 
				
			||||||
 | 
					    ($($x:tt)*) => {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            #[cfg(not(feature = "defmt"))]
 | 
				
			||||||
 | 
					            ::core::debug_assert!($($x)*);
 | 
				
			||||||
 | 
					            #[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					            ::defmt::debug_assert!($($x)*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! debug_assert_eq {
 | 
				
			||||||
 | 
					    ($($x:tt)*) => {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            #[cfg(not(feature = "defmt"))]
 | 
				
			||||||
 | 
					            ::core::debug_assert_eq!($($x)*);
 | 
				
			||||||
 | 
					            #[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					            ::defmt::debug_assert_eq!($($x)*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! debug_assert_ne {
 | 
				
			||||||
 | 
					    ($($x:tt)*) => {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            #[cfg(not(feature = "defmt"))]
 | 
				
			||||||
 | 
					            ::core::debug_assert_ne!($($x)*);
 | 
				
			||||||
 | 
					            #[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					            ::defmt::debug_assert_ne!($($x)*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! todo {
 | 
				
			||||||
 | 
					    ($($x:tt)*) => {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            #[cfg(not(feature = "defmt"))]
 | 
				
			||||||
 | 
					            ::core::todo!($($x)*);
 | 
				
			||||||
 | 
					            #[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					            ::defmt::todo!($($x)*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! unreachable {
 | 
				
			||||||
 | 
					    ($($x:tt)*) => {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            #[cfg(not(feature = "defmt"))]
 | 
				
			||||||
 | 
					            ::core::unreachable!($($x)*);
 | 
				
			||||||
 | 
					            #[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					            ::defmt::unreachable!($($x)*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! panic {
 | 
				
			||||||
 | 
					    ($($x:tt)*) => {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            #[cfg(not(feature = "defmt"))]
 | 
				
			||||||
 | 
					            ::core::panic!($($x)*);
 | 
				
			||||||
 | 
					            #[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					            ::defmt::panic!($($x)*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! trace {
 | 
				
			||||||
 | 
					    ($s:literal $(, $x:expr)* $(,)?) => {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            #[cfg(feature = "log")]
 | 
				
			||||||
 | 
					            ::log::trace!($s $(, $x)*);
 | 
				
			||||||
 | 
					            #[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					            ::defmt::trace!($s $(, $x)*);
 | 
				
			||||||
 | 
					            #[cfg(not(any(feature = "log", feature="defmt")))]
 | 
				
			||||||
 | 
					            let _ = ($( & $x ),*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! debug {
 | 
				
			||||||
 | 
					    ($s:literal $(, $x:expr)* $(,)?) => {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            #[cfg(feature = "log")]
 | 
				
			||||||
 | 
					            ::log::debug!($s $(, $x)*);
 | 
				
			||||||
 | 
					            #[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					            ::defmt::debug!($s $(, $x)*);
 | 
				
			||||||
 | 
					            #[cfg(not(any(feature = "log", feature="defmt")))]
 | 
				
			||||||
 | 
					            let _ = ($( & $x ),*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! info {
 | 
				
			||||||
 | 
					    ($s:literal $(, $x:expr)* $(,)?) => {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            #[cfg(feature = "log")]
 | 
				
			||||||
 | 
					            ::log::info!($s $(, $x)*);
 | 
				
			||||||
 | 
					            #[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					            ::defmt::info!($s $(, $x)*);
 | 
				
			||||||
 | 
					            #[cfg(not(any(feature = "log", feature="defmt")))]
 | 
				
			||||||
 | 
					            let _ = ($( & $x ),*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! warn {
 | 
				
			||||||
 | 
					    ($s:literal $(, $x:expr)* $(,)?) => {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            #[cfg(feature = "log")]
 | 
				
			||||||
 | 
					            ::log::warn!($s $(, $x)*);
 | 
				
			||||||
 | 
					            #[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					            ::defmt::warn!($s $(, $x)*);
 | 
				
			||||||
 | 
					            #[cfg(not(any(feature = "log", feature="defmt")))]
 | 
				
			||||||
 | 
					            let _ = ($( & $x ),*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! error {
 | 
				
			||||||
 | 
					    ($s:literal $(, $x:expr)* $(,)?) => {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            #[cfg(feature = "log")]
 | 
				
			||||||
 | 
					            ::log::error!($s $(, $x)*);
 | 
				
			||||||
 | 
					            #[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					            ::defmt::error!($s $(, $x)*);
 | 
				
			||||||
 | 
					            #[cfg(not(any(feature = "log", feature="defmt")))]
 | 
				
			||||||
 | 
					            let _ = ($( & $x ),*);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(feature = "defmt")]
 | 
				
			||||||
 | 
					macro_rules! unwrap {
 | 
				
			||||||
 | 
					    ($($x:tt)*) => {
 | 
				
			||||||
 | 
					        ::defmt::unwrap!($($x)*)
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(not(feature = "defmt"))]
 | 
				
			||||||
 | 
					macro_rules! unwrap {
 | 
				
			||||||
 | 
					    ($arg:expr) => {
 | 
				
			||||||
 | 
					        match $crate::fmt::Try::into_result($arg) {
 | 
				
			||||||
 | 
					            ::core::result::Result::Ok(t) => t,
 | 
				
			||||||
 | 
					            ::core::result::Result::Err(e) => {
 | 
				
			||||||
 | 
					                ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    ($arg:expr, $($msg:expr),+ $(,)? ) => {
 | 
				
			||||||
 | 
					        match $crate::fmt::Try::into_result($arg) {
 | 
				
			||||||
 | 
					            ::core::result::Result::Ok(t) => t,
 | 
				
			||||||
 | 
					            ::core::result::Result::Err(e) => {
 | 
				
			||||||
 | 
					                ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Copy, Clone, Eq, PartialEq)]
 | 
				
			||||||
 | 
					pub struct NoneError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub trait Try {
 | 
				
			||||||
 | 
					    type Ok;
 | 
				
			||||||
 | 
					    type Error;
 | 
				
			||||||
 | 
					    fn into_result(self) -> Result<Self::Ok, Self::Error>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T> Try for Option<T> {
 | 
				
			||||||
 | 
					    type Ok = T;
 | 
				
			||||||
 | 
					    type Error = NoneError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
 | 
					    fn into_result(self) -> Result<T, NoneError> {
 | 
				
			||||||
 | 
					        self.ok_or(NoneError)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T, E> Try for Result<T, E> {
 | 
				
			||||||
 | 
					    type Ok = T;
 | 
				
			||||||
 | 
					    type Error = E;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
 | 
					    fn into_result(self) -> Self {
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								embassy-net-enc28j60/src/header.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								embassy-net-enc28j60/src/header.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					register!(RxStatus, 0, u32, {
 | 
				
			||||||
 | 
					    #[doc = "Indicates length of the received frame"]
 | 
				
			||||||
 | 
					    byte_count @ 0..15,
 | 
				
			||||||
 | 
					    #[doc = "Indicates a packet over 50,000 bit times occurred or that a packet was dropped since the last receive"]
 | 
				
			||||||
 | 
					    long_event @ 16,
 | 
				
			||||||
 | 
					    #[doc = "Indicates that at some time since the last receive, a carrier event was detected"]
 | 
				
			||||||
 | 
					    carrier_event @ 18,
 | 
				
			||||||
 | 
					    #[doc = "Indicates that frame CRC field value does not match the CRC calculated by the MAC"]
 | 
				
			||||||
 | 
					    crc_error @ 20,
 | 
				
			||||||
 | 
					    #[doc = "Indicates that frame length field value in the packet does not match the actual data byte length and specifies a valid length"]
 | 
				
			||||||
 | 
					    length_check_error @ 21,
 | 
				
			||||||
 | 
					    #[doc = "Indicates that frame type/length field was larger than 1500 bytes (type field)"]
 | 
				
			||||||
 | 
					    length_out_of_range @ 22,
 | 
				
			||||||
 | 
					    #[doc = "Indicates that at the packet had a valid CRC and no symbol errors"]
 | 
				
			||||||
 | 
					    received_ok @ 23,
 | 
				
			||||||
 | 
					    #[doc = "Indicates packet received had a valid Multicast address"]
 | 
				
			||||||
 | 
					    multicast @ 24,
 | 
				
			||||||
 | 
					    #[doc = "Indicates packet received had a valid Broadcast address."]
 | 
				
			||||||
 | 
					    broadcast @ 25,
 | 
				
			||||||
 | 
					    #[doc = "Indicates that after the end of this packet, an additional 1 to 7 bits were received"]
 | 
				
			||||||
 | 
					    dribble_nibble @ 26,
 | 
				
			||||||
 | 
					    #[doc = "Current frame was recognized as a control frame for having a valid type/length designating it as a control frame"]
 | 
				
			||||||
 | 
					    receive_control_frame @ 27,
 | 
				
			||||||
 | 
					    #[doc = "Current frame was recognized as a control frame containing a valid pause frame opcode and a valid destination address"]
 | 
				
			||||||
 | 
					    receive_pause_control_frame @ 28,
 | 
				
			||||||
 | 
					    #[doc = "Current frame was recognized as a control frame but it contained an unknown opcode"]
 | 
				
			||||||
 | 
					    receive_unknown_opcode @ 29,
 | 
				
			||||||
 | 
					    #[doc = "Current frame was recognized as a VLAN tagged frame"]
 | 
				
			||||||
 | 
					    receive_vlan_type_detected @ 30,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										707
									
								
								embassy-net-enc28j60/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										707
									
								
								embassy-net-enc28j60/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,707 @@
 | 
				
			|||||||
 | 
					#![no_std]
 | 
				
			||||||
 | 
					#![doc = include_str!("../README.md")]
 | 
				
			||||||
 | 
					#![warn(missing_docs)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// must go first.
 | 
				
			||||||
 | 
					mod fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[macro_use]
 | 
				
			||||||
 | 
					mod macros;
 | 
				
			||||||
 | 
					mod bank0;
 | 
				
			||||||
 | 
					mod bank1;
 | 
				
			||||||
 | 
					mod bank2;
 | 
				
			||||||
 | 
					mod bank3;
 | 
				
			||||||
 | 
					mod common;
 | 
				
			||||||
 | 
					mod header;
 | 
				
			||||||
 | 
					mod phy;
 | 
				
			||||||
 | 
					mod traits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use core::cmp;
 | 
				
			||||||
 | 
					use core::convert::TryInto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use embassy_net_driver::{Capabilities, HardwareAddress, LinkState, Medium};
 | 
				
			||||||
 | 
					use embassy_time::Duration;
 | 
				
			||||||
 | 
					use embedded_hal::digital::OutputPin;
 | 
				
			||||||
 | 
					use embedded_hal::spi::{Operation, SpiDevice};
 | 
				
			||||||
 | 
					use traits::U16Ext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Total buffer size (see section 3.2)
 | 
				
			||||||
 | 
					const BUF_SZ: u16 = 8 * 1024;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Maximum frame length
 | 
				
			||||||
 | 
					const MAX_FRAME_LENGTH: u16 = 1518; // value recommended in the data sheet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Size of the Frame check sequence (32-bit CRC)
 | 
				
			||||||
 | 
					const CRC_SZ: u16 = 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// define the boundaries of the TX and RX buffers
 | 
				
			||||||
 | 
					// to workaround errata #5 we do the opposite of what section 6.1 of the data sheet
 | 
				
			||||||
 | 
					// says: we place the RX buffer at address 0 and the TX buffer after it
 | 
				
			||||||
 | 
					const RXST: u16 = 0x0000;
 | 
				
			||||||
 | 
					const RXND: u16 = 0x19ff;
 | 
				
			||||||
 | 
					const TXST: u16 = 0x1a00;
 | 
				
			||||||
 | 
					const _TXND: u16 = 0x1fff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const MTU: usize = 1514; // 1500 IP + 14 ethernet header
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// ENC28J60 embassy-net driver
 | 
				
			||||||
 | 
					pub struct Enc28j60<S, O> {
 | 
				
			||||||
 | 
					    mac_addr: [u8; 6],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    spi: S,
 | 
				
			||||||
 | 
					    rst: Option<O>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bank: Bank,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // address of the next packet in buffer memory
 | 
				
			||||||
 | 
					    next_packet: u16,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<S, O> Enc28j60<S, O>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    S: SpiDevice,
 | 
				
			||||||
 | 
					    O: OutputPin,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// Create a new ENC28J60 driver instance.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// The RST pin is optional. If None, reset will be done with a SPI
 | 
				
			||||||
 | 
					    /// soft reset command, instead of via the RST pin.
 | 
				
			||||||
 | 
					    pub fn new(spi: S, rst: Option<O>, mac_addr: [u8; 6]) -> Self {
 | 
				
			||||||
 | 
					        let mut res = Self {
 | 
				
			||||||
 | 
					            mac_addr,
 | 
				
			||||||
 | 
					            spi,
 | 
				
			||||||
 | 
					            rst,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            bank: Bank::Bank0,
 | 
				
			||||||
 | 
					            next_packet: RXST,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        res.init();
 | 
				
			||||||
 | 
					        res
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn init(&mut self) {
 | 
				
			||||||
 | 
					        if let Some(rst) = &mut self.rst {
 | 
				
			||||||
 | 
					            rst.set_low().unwrap();
 | 
				
			||||||
 | 
					            embassy_time::block_for(Duration::from_millis(5));
 | 
				
			||||||
 | 
					            rst.set_high().unwrap();
 | 
				
			||||||
 | 
					            embassy_time::block_for(Duration::from_millis(5));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            embassy_time::block_for(Duration::from_millis(5));
 | 
				
			||||||
 | 
					            self.soft_reset();
 | 
				
			||||||
 | 
					            embassy_time::block_for(Duration::from_millis(5));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        debug!(
 | 
				
			||||||
 | 
					            "enc28j60: erevid {=u8:x}",
 | 
				
			||||||
 | 
					            self.read_control_register(bank3::Register::EREVID)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        debug!("enc28j60: waiting for clk");
 | 
				
			||||||
 | 
					        while common::ESTAT(self.read_control_register(common::Register::ESTAT)).clkrdy() == 0 {}
 | 
				
			||||||
 | 
					        debug!("enc28j60: clk ok");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.read_control_register(bank3::Register::EREVID) == 0 {
 | 
				
			||||||
 | 
					            panic!("ErevidIsZero");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // disable CLKOUT output
 | 
				
			||||||
 | 
					        self.write_control_register(bank3::Register::ECOCON, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // RX start
 | 
				
			||||||
 | 
					        // "It is recommended that the ERXST Pointer be programmed with an even address"
 | 
				
			||||||
 | 
					        self.write_control_register(bank0::Register::ERXSTL, RXST.low());
 | 
				
			||||||
 | 
					        self.write_control_register(bank0::Register::ERXSTH, RXST.high());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // RX read pointer
 | 
				
			||||||
 | 
					        // NOTE Errata #14 so we are using an *odd* address here instead of ERXST
 | 
				
			||||||
 | 
					        self.write_control_register(bank0::Register::ERXRDPTL, RXND.low());
 | 
				
			||||||
 | 
					        self.write_control_register(bank0::Register::ERXRDPTH, RXND.high());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // RX end
 | 
				
			||||||
 | 
					        self.write_control_register(bank0::Register::ERXNDL, RXND.low());
 | 
				
			||||||
 | 
					        self.write_control_register(bank0::Register::ERXNDH, RXND.high());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // TX start
 | 
				
			||||||
 | 
					        // "It is recommended that an even address be used for ETXST"
 | 
				
			||||||
 | 
					        debug_assert_eq!(TXST % 2, 0);
 | 
				
			||||||
 | 
					        self.write_control_register(bank0::Register::ETXSTL, TXST.low());
 | 
				
			||||||
 | 
					        self.write_control_register(bank0::Register::ETXSTH, TXST.high());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // TX end is set in `transmit`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // MAC initialization (see section 6.5)
 | 
				
			||||||
 | 
					        // 1. Set the MARXEN bit in MACON1 to enable the MAC to receive frames.
 | 
				
			||||||
 | 
					        self.write_control_register(
 | 
				
			||||||
 | 
					            bank2::Register::MACON1,
 | 
				
			||||||
 | 
					            bank2::MACON1::default().marxen(1).passall(0).rxpaus(1).txpaus(1).bits(),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 2. Configure the PADCFG, TXCRCEN and FULDPX bits of MACON3.
 | 
				
			||||||
 | 
					        self.write_control_register(
 | 
				
			||||||
 | 
					            bank2::Register::MACON3,
 | 
				
			||||||
 | 
					            bank2::MACON3::default().frmlnen(1).txcrcen(1).padcfg(0b001).bits(),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 4. Program the MAMXFL registers with the maximum frame length to be permitted to be
 | 
				
			||||||
 | 
					        // received or transmitted
 | 
				
			||||||
 | 
					        self.write_control_register(bank2::Register::MAMXFLL, MAX_FRAME_LENGTH.low());
 | 
				
			||||||
 | 
					        self.write_control_register(bank2::Register::MAMXFLH, MAX_FRAME_LENGTH.high());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 5. Configure the Back-to-Back Inter-Packet Gap register, MABBIPG.
 | 
				
			||||||
 | 
					        // Use recommended value of 0x12
 | 
				
			||||||
 | 
					        self.write_control_register(bank2::Register::MABBIPG, 0x12);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 6. Configure the Non-Back-to-Back Inter-Packet Gap register low byte, MAIPGL.
 | 
				
			||||||
 | 
					        // Use recommended value of 0x12
 | 
				
			||||||
 | 
					        self.write_control_register(bank2::Register::MAIPGL, 0x12);
 | 
				
			||||||
 | 
					        self.write_control_register(bank2::Register::MAIPGH, 0x0c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 9. Program the local MAC address into the MAADR1:MAADR6 registers
 | 
				
			||||||
 | 
					        self.write_control_register(bank3::Register::MAADR1, self.mac_addr[0]);
 | 
				
			||||||
 | 
					        self.write_control_register(bank3::Register::MAADR2, self.mac_addr[1]);
 | 
				
			||||||
 | 
					        self.write_control_register(bank3::Register::MAADR3, self.mac_addr[2]);
 | 
				
			||||||
 | 
					        self.write_control_register(bank3::Register::MAADR4, self.mac_addr[3]);
 | 
				
			||||||
 | 
					        self.write_control_register(bank3::Register::MAADR5, self.mac_addr[4]);
 | 
				
			||||||
 | 
					        self.write_control_register(bank3::Register::MAADR6, self.mac_addr[5]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set the PHCON2.HDLDIS bit to prevent automatic loopback of the data which is transmitted
 | 
				
			||||||
 | 
					        self.write_phy_register(phy::Register::PHCON2, phy::PHCON2::default().hdldis(1).bits());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Globally enable interrupts
 | 
				
			||||||
 | 
					        //self.bit_field_set(common::Register::EIE, common::EIE::mask().intie());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set the per packet control byte; we'll always use the value 0
 | 
				
			||||||
 | 
					        self.write_buffer_memory(Some(TXST), &mut [0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // decrease the packet count to 0
 | 
				
			||||||
 | 
					        while self.read_control_register(bank1::Register::EPKTCNT) != 0 {
 | 
				
			||||||
 | 
					            self.bit_field_set(common::Register::ECON2, common::ECON2::mask().pktdec());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Enable reception
 | 
				
			||||||
 | 
					        self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Flushes the transmit buffer, ensuring all pending transmissions have completed
 | 
				
			||||||
 | 
					    /// NOTE: The returned packet *must* be `read` or `ignore`-d, otherwise this method will always
 | 
				
			||||||
 | 
					    /// return `None` on subsequent invocations
 | 
				
			||||||
 | 
					    pub fn receive<'a>(&mut self, buf: &'a mut [u8]) -> Option<&'a mut [u8]> {
 | 
				
			||||||
 | 
					        if self.pending_packets() == 0 {
 | 
				
			||||||
 | 
					            // Errata #6: we can't rely on PKTIF so we check PKTCNT
 | 
				
			||||||
 | 
					            return None;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let curr_packet = self.next_packet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // read out the first 6 bytes
 | 
				
			||||||
 | 
					        let mut temp_buf = [0; 6];
 | 
				
			||||||
 | 
					        self.read_buffer_memory(Some(curr_packet), &mut temp_buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // next packet pointer
 | 
				
			||||||
 | 
					        let next_packet = u16::from_parts(temp_buf[0], temp_buf[1]);
 | 
				
			||||||
 | 
					        if next_packet > RXND {
 | 
				
			||||||
 | 
					            panic!("CorruptRxBuffer");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // status vector
 | 
				
			||||||
 | 
					        let status = header::RxStatus(u32::from_le_bytes(temp_buf[2..].try_into().unwrap()));
 | 
				
			||||||
 | 
					        let len = status.byte_count() as u16 - CRC_SZ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len > RXND {
 | 
				
			||||||
 | 
					            panic!("CorruptRxBuffer 2");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.read_buffer_memory(None, &mut buf[..len as usize]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // update ERXRDPT
 | 
				
			||||||
 | 
					        // due to Errata #14 we must write an odd address to ERXRDPT
 | 
				
			||||||
 | 
					        // we know that ERXST = 0, that ERXND is odd and that next_packet is even
 | 
				
			||||||
 | 
					        let rxrdpt = if self.next_packet < 1 || self.next_packet > RXND + 1 {
 | 
				
			||||||
 | 
					            RXND
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            self.next_packet - 1
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        // "To move ERXRDPT, the host controller must write to ERXRDPTL first."
 | 
				
			||||||
 | 
					        self.write_control_register(bank0::Register::ERXRDPTL, rxrdpt.low());
 | 
				
			||||||
 | 
					        self.write_control_register(bank0::Register::ERXRDPTH, rxrdpt.high());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // decrease the packet count
 | 
				
			||||||
 | 
					        self.bit_field_set(common::Register::ECON2, common::ECON2::mask().pktdec());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.next_packet = next_packet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Some(&mut buf[..len as usize])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn wait_tx_ready(&mut self) {
 | 
				
			||||||
 | 
					        for _ in 0u32..10000 {
 | 
				
			||||||
 | 
					            if common::ECON1(self.read_control_register(common::Register::ECON1)).txrts() == 0 {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // work around errata #12 by resetting the transmit logic before every new
 | 
				
			||||||
 | 
					        // transmission
 | 
				
			||||||
 | 
					        self.bit_field_set(common::Register::ECON1, common::ECON1::mask().txrst());
 | 
				
			||||||
 | 
					        self.bit_field_clear(common::Register::ECON1, common::ECON1::mask().txrst());
 | 
				
			||||||
 | 
					        //self.bit_field_clear(common::Register::EIR, {
 | 
				
			||||||
 | 
					        //    let mask = common::EIR::mask();
 | 
				
			||||||
 | 
					        //    mask.txerif() | mask.txif()
 | 
				
			||||||
 | 
					        //});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Starts the transmission of `bytes`
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// It's up to the caller to ensure that `bytes` is a valid Ethernet frame. The interface will
 | 
				
			||||||
 | 
					    /// take care of appending a (4 byte) CRC to the frame and of padding the frame to the minimum
 | 
				
			||||||
 | 
					    /// size allowed by the Ethernet specification (64 bytes, or 46 bytes of payload).
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// NOTE This method will flush any previous transmission that's in progress
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Panics
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// If `bytes` length is greater than 1514, the maximum frame length allowed by the interface,
 | 
				
			||||||
 | 
					    /// or greater than the transmit buffer
 | 
				
			||||||
 | 
					    pub fn transmit(&mut self, bytes: &[u8]) {
 | 
				
			||||||
 | 
					        assert!(bytes.len() <= self.mtu() as usize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.wait_tx_ready();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // NOTE the plus one is to not overwrite the per packet control byte
 | 
				
			||||||
 | 
					        let wrpt = TXST + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 1. ETXST was set during initialization
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 2. write the frame to the IC memory
 | 
				
			||||||
 | 
					        self.write_buffer_memory(Some(wrpt), bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let txnd = wrpt + bytes.len() as u16 - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 3. Set the end address of the transmit buffer
 | 
				
			||||||
 | 
					        self.write_control_register(bank0::Register::ETXNDL, txnd.low());
 | 
				
			||||||
 | 
					        self.write_control_register(bank0::Register::ETXNDH, txnd.high());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 4. reset interrupt flag
 | 
				
			||||||
 | 
					        //self.bit_field_clear(common::Register::EIR, common::EIR::mask().txif());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 5. start transmission
 | 
				
			||||||
 | 
					        self.bit_field_set(common::Register::ECON1, common::ECON1::mask().txrts());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Wait until transmission finishes
 | 
				
			||||||
 | 
					        //while common::ECON1(self.read_control_register(common::Register::ECON1)).txrts() == 1 {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					        // read the transmit status vector
 | 
				
			||||||
 | 
					        let mut tx_stat = [0; 7];
 | 
				
			||||||
 | 
					        self.read_buffer_memory(None, &mut tx_stat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let stat = common::ESTAT(self.read_control_register(common::Register::ESTAT));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if stat.txabrt() == 1 {
 | 
				
			||||||
 | 
					            // work around errata #12 by reading the transmit status vector
 | 
				
			||||||
 | 
					            if stat.latecol() == 1 || (tx_stat[2] & (1 << 5)) != 0 {
 | 
				
			||||||
 | 
					                panic!("LateCollision")
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                panic!("TransmitAbort")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }*/
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Get whether the link is up
 | 
				
			||||||
 | 
					    pub fn is_link_up(&mut self) -> bool {
 | 
				
			||||||
 | 
					        let bits = self.read_phy_register(phy::Register::PHSTAT2);
 | 
				
			||||||
 | 
					        phy::PHSTAT2(bits).lstat() == 1
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Returns the interface Maximum Transmission Unit (MTU)
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// The value returned by this function will never exceed 1514 bytes. The actual value depends
 | 
				
			||||||
 | 
					    /// on the memory assigned to the transmission buffer when initializing the device
 | 
				
			||||||
 | 
					    pub fn mtu(&self) -> u16 {
 | 
				
			||||||
 | 
					        cmp::min(BUF_SZ - RXND - 1, MAX_FRAME_LENGTH - CRC_SZ)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Miscellaneous */
 | 
				
			||||||
 | 
					    /// Returns the number of packets that have been received but have not been processed yet
 | 
				
			||||||
 | 
					    pub fn pending_packets(&mut self) -> u8 {
 | 
				
			||||||
 | 
					        self.read_control_register(bank1::Register::EPKTCNT)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Adjusts the receive filter to *accept* these packet types
 | 
				
			||||||
 | 
					    pub fn accept(&mut self, packets: &[Packet]) {
 | 
				
			||||||
 | 
					        let mask = bank1::ERXFCON::mask();
 | 
				
			||||||
 | 
					        let mut val = 0;
 | 
				
			||||||
 | 
					        for packet in packets {
 | 
				
			||||||
 | 
					            match packet {
 | 
				
			||||||
 | 
					                Packet::Broadcast => val |= mask.bcen(),
 | 
				
			||||||
 | 
					                Packet::Multicast => val |= mask.mcen(),
 | 
				
			||||||
 | 
					                Packet::Unicast => val |= mask.ucen(),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.bit_field_set(bank1::Register::ERXFCON, val)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Adjusts the receive filter to *ignore* these packet types
 | 
				
			||||||
 | 
					    pub fn ignore(&mut self, packets: &[Packet]) {
 | 
				
			||||||
 | 
					        let mask = bank1::ERXFCON::mask();
 | 
				
			||||||
 | 
					        let mut val = 0;
 | 
				
			||||||
 | 
					        for packet in packets {
 | 
				
			||||||
 | 
					            match packet {
 | 
				
			||||||
 | 
					                Packet::Broadcast => val |= mask.bcen(),
 | 
				
			||||||
 | 
					                Packet::Multicast => val |= mask.mcen(),
 | 
				
			||||||
 | 
					                Packet::Unicast => val |= mask.ucen(),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.bit_field_clear(bank1::Register::ERXFCON, val)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Private */
 | 
				
			||||||
 | 
					    /* Read */
 | 
				
			||||||
 | 
					    fn read_control_register<R>(&mut self, register: R) -> u8
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        R: Into<Register>,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        self._read_control_register(register.into())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn _read_control_register(&mut self, register: Register) -> u8 {
 | 
				
			||||||
 | 
					        self.change_bank(register);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if register.is_eth_register() {
 | 
				
			||||||
 | 
					            let mut buffer = [Instruction::RCR.opcode() | register.addr(), 0];
 | 
				
			||||||
 | 
					            self.spi.transfer_in_place(&mut buffer).unwrap();
 | 
				
			||||||
 | 
					            buffer[1]
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // MAC, MII regs need a dummy byte.
 | 
				
			||||||
 | 
					            let mut buffer = [Instruction::RCR.opcode() | register.addr(), 0, 0];
 | 
				
			||||||
 | 
					            self.spi.transfer_in_place(&mut buffer).unwrap();
 | 
				
			||||||
 | 
					            buffer[2]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn read_phy_register(&mut self, register: phy::Register) -> u16 {
 | 
				
			||||||
 | 
					        embassy_time::block_for(Duration::from_millis(1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // set PHY register address
 | 
				
			||||||
 | 
					        self.write_control_register(bank2::Register::MIREGADR, register.addr());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // start read operation
 | 
				
			||||||
 | 
					        self.write_control_register(bank2::Register::MICMD, bank2::MICMD::default().miird(1).bits());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // wait until the read operation finishes
 | 
				
			||||||
 | 
					        while self.read_control_register(bank3::Register::MISTAT) & 0b1 != 0 {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.write_control_register(bank2::Register::MICMD, bank2::MICMD::default().miird(0).bits());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let l = self.read_control_register(bank2::Register::MIRDL);
 | 
				
			||||||
 | 
					        let h = self.read_control_register(bank2::Register::MIRDH);
 | 
				
			||||||
 | 
					        (l as u16) | (h as u16) << 8
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Write */
 | 
				
			||||||
 | 
					    fn _write_control_register(&mut self, register: Register, value: u8) {
 | 
				
			||||||
 | 
					        self.change_bank(register);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let buffer = [Instruction::WCR.opcode() | register.addr(), value];
 | 
				
			||||||
 | 
					        self.spi.write(&buffer).unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_control_register<R>(&mut self, register: R, value: u8)
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        R: Into<Register>,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        self._write_control_register(register.into(), value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_phy_register(&mut self, register: phy::Register, value: u16) {
 | 
				
			||||||
 | 
					        // set PHY register address
 | 
				
			||||||
 | 
					        self.write_control_register(bank2::Register::MIREGADR, register.addr());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.write_control_register(bank2::Register::MIWRL, (value & 0xff) as u8);
 | 
				
			||||||
 | 
					        // this starts the write operation
 | 
				
			||||||
 | 
					        self.write_control_register(bank2::Register::MIWRH, (value >> 8) as u8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // wait until the write operation finishes
 | 
				
			||||||
 | 
					        while self.read_control_register(bank3::Register::MISTAT) & 0b1 != 0 {}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* RMW */
 | 
				
			||||||
 | 
					    fn modify_control_register<R, F>(&mut self, register: R, f: F)
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        F: FnOnce(u8) -> u8,
 | 
				
			||||||
 | 
					        R: Into<Register>,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        self._modify_control_register(register.into(), f)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn _modify_control_register<F>(&mut self, register: Register, f: F)
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        F: FnOnce(u8) -> u8,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let r = self._read_control_register(register);
 | 
				
			||||||
 | 
					        self._write_control_register(register, f(r))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Auxiliary */
 | 
				
			||||||
 | 
					    fn change_bank(&mut self, register: Register) {
 | 
				
			||||||
 | 
					        let bank = register.bank();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(bank) = bank {
 | 
				
			||||||
 | 
					            if self.bank == bank {
 | 
				
			||||||
 | 
					                // already on the register bank
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // change bank
 | 
				
			||||||
 | 
					            self.bank = bank;
 | 
				
			||||||
 | 
					            match bank {
 | 
				
			||||||
 | 
					                Bank::Bank0 => self.bit_field_clear(common::Register::ECON1, 0b11),
 | 
				
			||||||
 | 
					                Bank::Bank1 => self.modify_control_register(common::Register::ECON1, |r| (r & !0b11) | 0b01),
 | 
				
			||||||
 | 
					                Bank::Bank2 => self.modify_control_register(common::Register::ECON1, |r| (r & !0b11) | 0b10),
 | 
				
			||||||
 | 
					                Bank::Bank3 => self.bit_field_set(common::Register::ECON1, 0b11),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // common register
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Primitive operations */
 | 
				
			||||||
 | 
					    fn bit_field_clear<R>(&mut self, register: R, mask: u8)
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        R: Into<Register>,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        self._bit_field_clear(register.into(), mask)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn _bit_field_clear(&mut self, register: Register, mask: u8) {
 | 
				
			||||||
 | 
					        debug_assert!(register.is_eth_register());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.change_bank(register);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.spi
 | 
				
			||||||
 | 
					            .write(&[Instruction::BFC.opcode() | register.addr(), mask])
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn bit_field_set<R>(&mut self, register: R, mask: u8)
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        R: Into<Register>,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        self._bit_field_set(register.into(), mask)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn _bit_field_set(&mut self, register: Register, mask: u8) {
 | 
				
			||||||
 | 
					        debug_assert!(register.is_eth_register());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.change_bank(register);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.spi
 | 
				
			||||||
 | 
					            .write(&[Instruction::BFS.opcode() | register.addr(), mask])
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn read_buffer_memory(&mut self, addr: Option<u16>, buf: &mut [u8]) {
 | 
				
			||||||
 | 
					        if let Some(addr) = addr {
 | 
				
			||||||
 | 
					            self.write_control_register(bank0::Register::ERDPTL, addr.low());
 | 
				
			||||||
 | 
					            self.write_control_register(bank0::Register::ERDPTH, addr.high());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.spi
 | 
				
			||||||
 | 
					            .transaction(&mut [Operation::Write(&[Instruction::RBM.opcode()]), Operation::Read(buf)])
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn soft_reset(&mut self) {
 | 
				
			||||||
 | 
					        self.spi.write(&[Instruction::SRC.opcode()]).unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_buffer_memory(&mut self, addr: Option<u16>, buffer: &[u8]) {
 | 
				
			||||||
 | 
					        if let Some(addr) = addr {
 | 
				
			||||||
 | 
					            self.write_control_register(bank0::Register::EWRPTL, addr.low());
 | 
				
			||||||
 | 
					            self.write_control_register(bank0::Register::EWRPTH, addr.high());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.spi
 | 
				
			||||||
 | 
					            .transaction(&mut [Operation::Write(&[Instruction::WBM.opcode()]), Operation::Write(buffer)])
 | 
				
			||||||
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, PartialEq)]
 | 
				
			||||||
 | 
					enum Bank {
 | 
				
			||||||
 | 
					    Bank0,
 | 
				
			||||||
 | 
					    Bank1,
 | 
				
			||||||
 | 
					    Bank2,
 | 
				
			||||||
 | 
					    Bank3,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					enum Instruction {
 | 
				
			||||||
 | 
					    /// Read Control Register
 | 
				
			||||||
 | 
					    RCR = 0b000_00000,
 | 
				
			||||||
 | 
					    /// Read Buffer Memory
 | 
				
			||||||
 | 
					    RBM = 0b001_11010,
 | 
				
			||||||
 | 
					    /// Write Control Register
 | 
				
			||||||
 | 
					    WCR = 0b010_00000,
 | 
				
			||||||
 | 
					    /// Write Buffer Memory
 | 
				
			||||||
 | 
					    WBM = 0b011_11010,
 | 
				
			||||||
 | 
					    /// Bit Field Set
 | 
				
			||||||
 | 
					    BFS = 0b100_00000,
 | 
				
			||||||
 | 
					    /// Bit Field Clear
 | 
				
			||||||
 | 
					    BFC = 0b101_00000,
 | 
				
			||||||
 | 
					    /// System Reset Command
 | 
				
			||||||
 | 
					    SRC = 0b111_11111,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Instruction {
 | 
				
			||||||
 | 
					    fn opcode(&self) -> u8 {
 | 
				
			||||||
 | 
					        *self as u8
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					enum Register {
 | 
				
			||||||
 | 
					    Bank0(bank0::Register),
 | 
				
			||||||
 | 
					    Bank1(bank1::Register),
 | 
				
			||||||
 | 
					    Bank2(bank2::Register),
 | 
				
			||||||
 | 
					    Bank3(bank3::Register),
 | 
				
			||||||
 | 
					    Common(common::Register),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Register {
 | 
				
			||||||
 | 
					    fn addr(&self) -> u8 {
 | 
				
			||||||
 | 
					        match *self {
 | 
				
			||||||
 | 
					            Register::Bank0(r) => r.addr(),
 | 
				
			||||||
 | 
					            Register::Bank1(r) => r.addr(),
 | 
				
			||||||
 | 
					            Register::Bank2(r) => r.addr(),
 | 
				
			||||||
 | 
					            Register::Bank3(r) => r.addr(),
 | 
				
			||||||
 | 
					            Register::Common(r) => r.addr(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn bank(&self) -> Option<Bank> {
 | 
				
			||||||
 | 
					        Some(match *self {
 | 
				
			||||||
 | 
					            Register::Bank0(_) => Bank::Bank0,
 | 
				
			||||||
 | 
					            Register::Bank1(_) => Bank::Bank1,
 | 
				
			||||||
 | 
					            Register::Bank2(_) => Bank::Bank2,
 | 
				
			||||||
 | 
					            Register::Bank3(_) => Bank::Bank3,
 | 
				
			||||||
 | 
					            Register::Common(_) => return None,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn is_eth_register(&self) -> bool {
 | 
				
			||||||
 | 
					        match *self {
 | 
				
			||||||
 | 
					            Register::Bank0(r) => r.is_eth_register(),
 | 
				
			||||||
 | 
					            Register::Bank1(r) => r.is_eth_register(),
 | 
				
			||||||
 | 
					            Register::Bank2(r) => r.is_eth_register(),
 | 
				
			||||||
 | 
					            Register::Bank3(r) => r.is_eth_register(),
 | 
				
			||||||
 | 
					            Register::Common(r) => r.is_eth_register(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Packet type, used to configure receive filters
 | 
				
			||||||
 | 
					#[non_exhaustive]
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, Eq, PartialEq)]
 | 
				
			||||||
 | 
					pub enum Packet {
 | 
				
			||||||
 | 
					    /// Broadcast packets
 | 
				
			||||||
 | 
					    Broadcast,
 | 
				
			||||||
 | 
					    /// Multicast packets
 | 
				
			||||||
 | 
					    Multicast,
 | 
				
			||||||
 | 
					    /// Unicast packets
 | 
				
			||||||
 | 
					    Unicast,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static mut TX_BUF: [u8; MTU] = [0; MTU];
 | 
				
			||||||
 | 
					static mut RX_BUF: [u8; MTU] = [0; MTU];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<S, O> embassy_net_driver::Driver for Enc28j60<S, O>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    S: SpiDevice,
 | 
				
			||||||
 | 
					    O: OutputPin,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    type RxToken<'a> = RxToken<'a>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        Self: 'a;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    type TxToken<'a> = TxToken<'a, S, O>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        Self: 'a;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
 | 
				
			||||||
 | 
					        let rx_buf = unsafe { &mut RX_BUF };
 | 
				
			||||||
 | 
					        let tx_buf = unsafe { &mut TX_BUF };
 | 
				
			||||||
 | 
					        if let Some(pkt) = self.receive(rx_buf) {
 | 
				
			||||||
 | 
					            let n = pkt.len();
 | 
				
			||||||
 | 
					            Some((RxToken { buf: &mut pkt[..n] }, TxToken { buf: tx_buf, eth: self }))
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            cx.waker().wake_by_ref();
 | 
				
			||||||
 | 
					            None
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn transmit(&mut self, _cx: &mut core::task::Context) -> Option<Self::TxToken<'_>> {
 | 
				
			||||||
 | 
					        let tx_buf = unsafe { &mut TX_BUF };
 | 
				
			||||||
 | 
					        Some(TxToken { buf: tx_buf, eth: self })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn link_state(&mut self, cx: &mut core::task::Context) -> LinkState {
 | 
				
			||||||
 | 
					        cx.waker().wake_by_ref();
 | 
				
			||||||
 | 
					        match self.is_link_up() {
 | 
				
			||||||
 | 
					            true => LinkState::Up,
 | 
				
			||||||
 | 
					            false => LinkState::Down,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn capabilities(&self) -> Capabilities {
 | 
				
			||||||
 | 
					        let mut caps = Capabilities::default();
 | 
				
			||||||
 | 
					        caps.max_transmission_unit = MTU;
 | 
				
			||||||
 | 
					        caps.medium = Medium::Ethernet;
 | 
				
			||||||
 | 
					        caps
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn hardware_address(&self) -> HardwareAddress {
 | 
				
			||||||
 | 
					        HardwareAddress::Ethernet(self.mac_addr)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// embassy-net RX token.
 | 
				
			||||||
 | 
					pub struct RxToken<'a> {
 | 
				
			||||||
 | 
					    buf: &'a mut [u8],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> embassy_net_driver::RxToken for RxToken<'a> {
 | 
				
			||||||
 | 
					    fn consume<R, F>(self, f: F) -> R
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        F: FnOnce(&mut [u8]) -> R,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        f(self.buf)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// embassy-net TX token.
 | 
				
			||||||
 | 
					pub struct TxToken<'a, S, O>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    S: SpiDevice,
 | 
				
			||||||
 | 
					    O: OutputPin,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    eth: &'a mut Enc28j60<S, O>,
 | 
				
			||||||
 | 
					    buf: &'a mut [u8],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a, S, O> embassy_net_driver::TxToken for TxToken<'a, S, O>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    S: SpiDevice,
 | 
				
			||||||
 | 
					    O: OutputPin,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fn consume<R, F>(self, len: usize, f: F) -> R
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        F: FnOnce(&mut [u8]) -> R,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert!(len <= self.buf.len());
 | 
				
			||||||
 | 
					        let r = f(&mut self.buf[..len]);
 | 
				
			||||||
 | 
					        self.eth.transmit(&self.buf[..len]);
 | 
				
			||||||
 | 
					        r
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										89
									
								
								embassy-net-enc28j60/src/macros.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								embassy-net-enc28j60/src/macros.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					macro_rules! register {
 | 
				
			||||||
 | 
					    ($REGISTER:ident, $reset_value:expr, $uxx:ty, {
 | 
				
			||||||
 | 
					        $(#[$($attr:tt)*] $bitfield:ident @ $range:expr,)+
 | 
				
			||||||
 | 
					    }) => {
 | 
				
			||||||
 | 
					        #[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					        pub(crate) struct $REGISTER<MODE> {
 | 
				
			||||||
 | 
					            bits: $uxx,
 | 
				
			||||||
 | 
					            _mode: ::core::marker::PhantomData<MODE>,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl $REGISTER<super::traits::Mask> {
 | 
				
			||||||
 | 
					            #[allow(dead_code)]
 | 
				
			||||||
 | 
					            pub(crate) fn mask() -> $REGISTER<super::traits::Mask> {
 | 
				
			||||||
 | 
					                $REGISTER { bits: 0, _mode: ::core::marker::PhantomData }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $(
 | 
				
			||||||
 | 
					                #[allow(dead_code)]
 | 
				
			||||||
 | 
					                pub(crate) fn $bitfield(&self) -> $uxx {
 | 
				
			||||||
 | 
					                    use super::traits::OffsetSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    let size = $range.size();
 | 
				
			||||||
 | 
					                    let offset = $range.offset();
 | 
				
			||||||
 | 
					                    ((1 << size) - 1) << offset
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            )+
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl ::core::default::Default for $REGISTER<super::traits::W> {
 | 
				
			||||||
 | 
					            fn default() -> Self {
 | 
				
			||||||
 | 
					                $REGISTER { bits: $reset_value, _mode: ::core::marker::PhantomData }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #[allow(non_snake_case)]
 | 
				
			||||||
 | 
					        #[allow(dead_code)]
 | 
				
			||||||
 | 
					        pub(crate) fn $REGISTER(bits: $uxx) -> $REGISTER<super::traits::R> {
 | 
				
			||||||
 | 
					            $REGISTER { bits, _mode: ::core::marker::PhantomData }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl $REGISTER<super::traits::R> {
 | 
				
			||||||
 | 
					            #[allow(dead_code)]
 | 
				
			||||||
 | 
					            pub(crate) fn modify(self) -> $REGISTER<super::traits::W> {
 | 
				
			||||||
 | 
					                $REGISTER { bits: self.bits, _mode: ::core::marker::PhantomData }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $(
 | 
				
			||||||
 | 
					                #[$($attr)*]
 | 
				
			||||||
 | 
					                #[allow(dead_code)]
 | 
				
			||||||
 | 
					                pub(crate) fn $bitfield(&self) -> $uxx {
 | 
				
			||||||
 | 
					                    use super::traits::OffsetSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    let offset = $range.offset();
 | 
				
			||||||
 | 
					                    let size = $range.size();
 | 
				
			||||||
 | 
					                    let mask = (1 << size) - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    (self.bits >> offset) & mask
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            )+
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        impl $REGISTER<super::traits::W> {
 | 
				
			||||||
 | 
					            #[allow(dead_code)]
 | 
				
			||||||
 | 
					            pub(crate) fn bits(self) -> $uxx {
 | 
				
			||||||
 | 
					                self.bits
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $(
 | 
				
			||||||
 | 
					                #[$($attr)*]
 | 
				
			||||||
 | 
					                #[allow(dead_code)]
 | 
				
			||||||
 | 
					                pub(crate) fn $bitfield(&mut self, mut bits: $uxx) -> &mut Self {
 | 
				
			||||||
 | 
					                    use super::traits::OffsetSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    let offset = $range.offset();
 | 
				
			||||||
 | 
					                    let size = $range.size();
 | 
				
			||||||
 | 
					                    let mask = (1 << size) - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    debug_assert!(bits <= mask);
 | 
				
			||||||
 | 
					                    bits &= mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    self.bits &= !(mask << offset);
 | 
				
			||||||
 | 
					                    self.bits |= bits << offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    self
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            )+
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								embassy-net-enc28j60/src/phy.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								embassy-net-enc28j60/src/phy.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					#[allow(dead_code)]
 | 
				
			||||||
 | 
					#[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					pub enum Register {
 | 
				
			||||||
 | 
					    PHCON1 = 0x00,
 | 
				
			||||||
 | 
					    PHSTAT1 = 0x01,
 | 
				
			||||||
 | 
					    PHID1 = 0x02,
 | 
				
			||||||
 | 
					    PHID2 = 0x03,
 | 
				
			||||||
 | 
					    PHCON2 = 0x10,
 | 
				
			||||||
 | 
					    PHSTAT2 = 0x11,
 | 
				
			||||||
 | 
					    PHIE = 0x12,
 | 
				
			||||||
 | 
					    PHIR = 0x13,
 | 
				
			||||||
 | 
					    PHLCON = 0x14,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Register {
 | 
				
			||||||
 | 
					    pub(crate) fn addr(&self) -> u8 {
 | 
				
			||||||
 | 
					        *self as u8
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register!(PHCON2, 0, u16, {
 | 
				
			||||||
 | 
					    #[doc = "PHY Half-Duplex Loopback Disable bit"]
 | 
				
			||||||
 | 
					    hdldis @ 8,
 | 
				
			||||||
 | 
					    #[doc = "Jabber Correction Disable bit"]
 | 
				
			||||||
 | 
					    jabber @ 10,
 | 
				
			||||||
 | 
					    #[doc = "Twisted-Pair Transmitter Disable bit"]
 | 
				
			||||||
 | 
					    txdis @ 13,
 | 
				
			||||||
 | 
					    #[doc = "PHY Force Linkup bit"]
 | 
				
			||||||
 | 
					    frclnk @ 14,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					register!(PHSTAT2, 0, u16, {
 | 
				
			||||||
 | 
					    #[doc = "Link Status bit"]
 | 
				
			||||||
 | 
					    lstat @ 10,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										57
									
								
								embassy-net-enc28j60/src/traits.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								embassy-net-enc28j60/src/traits.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					use core::ops::Range;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub(crate) trait OffsetSize {
 | 
				
			||||||
 | 
					    fn offset(self) -> u8;
 | 
				
			||||||
 | 
					    fn size(self) -> u8;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl OffsetSize for u8 {
 | 
				
			||||||
 | 
					    fn offset(self) -> u8 {
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn size(self) -> u8 {
 | 
				
			||||||
 | 
					        1
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl OffsetSize for Range<u8> {
 | 
				
			||||||
 | 
					    fn offset(self) -> u8 {
 | 
				
			||||||
 | 
					        self.start
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn size(self) -> u8 {
 | 
				
			||||||
 | 
					        self.end - self.start
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub(crate) trait U16Ext {
 | 
				
			||||||
 | 
					    fn from_parts(low: u8, high: u8) -> Self;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn low(self) -> u8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn high(self) -> u8;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl U16Ext for u16 {
 | 
				
			||||||
 | 
					    fn from_parts(low: u8, high: u8) -> u16 {
 | 
				
			||||||
 | 
					        ((high as u16) << 8) + low as u16
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn low(self) -> u8 {
 | 
				
			||||||
 | 
					        (self & 0xff) as u8
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn high(self) -> u8 {
 | 
				
			||||||
 | 
					        (self >> 8) as u8
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					pub struct Mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					pub struct R;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					pub struct W;
 | 
				
			||||||
@ -12,6 +12,7 @@ nightly = [
 | 
				
			|||||||
    "embassy-nrf/nightly",
 | 
					    "embassy-nrf/nightly",
 | 
				
			||||||
    "embassy-net/nightly",
 | 
					    "embassy-net/nightly",
 | 
				
			||||||
    "embassy-net-esp-hosted",
 | 
					    "embassy-net-esp-hosted",
 | 
				
			||||||
 | 
					    "embassy-net-enc28j60",
 | 
				
			||||||
    "embassy-nrf/unstable-traits",
 | 
					    "embassy-nrf/unstable-traits",
 | 
				
			||||||
    "embassy-time/nightly",
 | 
					    "embassy-time/nightly",
 | 
				
			||||||
    "embassy-time/unstable-traits",
 | 
					    "embassy-time/unstable-traits",
 | 
				
			||||||
@ -40,6 +41,7 @@ lora-phy = { version = "1", optional = true }
 | 
				
			|||||||
lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true }
 | 
					lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true }
 | 
				
			||||||
lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true }
 | 
					lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true }
 | 
				
			||||||
embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"], optional = true }
 | 
					embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"], optional = true }
 | 
				
			||||||
 | 
					embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"], optional = true }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defmt = "0.3"
 | 
					defmt = "0.3"
 | 
				
			||||||
defmt-rtt = "0.4"
 | 
					defmt-rtt = "0.4"
 | 
				
			||||||
@ -54,7 +56,9 @@ rand = { version = "0.8.4", default-features = false }
 | 
				
			|||||||
embedded-storage = "0.3.0"
 | 
					embedded-storage = "0.3.0"
 | 
				
			||||||
usbd-hid = "0.6.0"
 | 
					usbd-hid = "0.6.0"
 | 
				
			||||||
serde = { version = "1.0.136", default-features = false }
 | 
					serde = { version = "1.0.136", default-features = false }
 | 
				
			||||||
 | 
					embedded-hal = { version = "1.0.0-alpha.11" }
 | 
				
			||||||
embedded-hal-async = { version = "0.2.0-alpha.2", optional = true }
 | 
					embedded-hal-async = { version = "0.2.0-alpha.2", optional = true }
 | 
				
			||||||
 | 
					embedded-hal-bus = { version = "0.1.0-alpha.3" }
 | 
				
			||||||
num-integer = { version = "0.1.45", default-features = false }
 | 
					num-integer = { version = "0.1.45", default-features = false }
 | 
				
			||||||
microfft = "0.5.0"
 | 
					microfft = "0.5.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										124
									
								
								examples/nrf52840/src/bin/ethernet_enc28j60.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								examples/nrf52840/src/bin/ethernet_enc28j60.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,124 @@
 | 
				
			|||||||
 | 
					#![no_std]
 | 
				
			||||||
 | 
					#![no_main]
 | 
				
			||||||
 | 
					#![feature(type_alias_impl_trait)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use defmt::*;
 | 
				
			||||||
 | 
					use embassy_executor::Spawner;
 | 
				
			||||||
 | 
					use embassy_net::tcp::TcpSocket;
 | 
				
			||||||
 | 
					use embassy_net::{Stack, StackResources};
 | 
				
			||||||
 | 
					use embassy_net_enc28j60::Enc28j60;
 | 
				
			||||||
 | 
					use embassy_nrf::gpio::{Level, Output, OutputDrive};
 | 
				
			||||||
 | 
					use embassy_nrf::rng::Rng;
 | 
				
			||||||
 | 
					use embassy_nrf::spim::Spim;
 | 
				
			||||||
 | 
					use embassy_nrf::{bind_interrupts, peripherals, spim};
 | 
				
			||||||
 | 
					use embassy_time::Delay;
 | 
				
			||||||
 | 
					use embedded_hal_bus::spi::ExclusiveDevice;
 | 
				
			||||||
 | 
					use embedded_io_async::Write;
 | 
				
			||||||
 | 
					use static_cell::make_static;
 | 
				
			||||||
 | 
					use {defmt_rtt as _, panic_probe as _};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bind_interrupts!(struct Irqs {
 | 
				
			||||||
 | 
					    SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
 | 
				
			||||||
 | 
					    RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[embassy_executor::task]
 | 
				
			||||||
 | 
					async fn net_task(
 | 
				
			||||||
 | 
					    stack: &'static Stack<
 | 
				
			||||||
 | 
					        Enc28j60<
 | 
				
			||||||
 | 
					            ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_15>, Delay>,
 | 
				
			||||||
 | 
					            Output<'static, peripherals::P0_13>,
 | 
				
			||||||
 | 
					        >,
 | 
				
			||||||
 | 
					    >,
 | 
				
			||||||
 | 
					) -> ! {
 | 
				
			||||||
 | 
					    stack.run().await
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[embassy_executor::main]
 | 
				
			||||||
 | 
					async fn main(spawner: Spawner) {
 | 
				
			||||||
 | 
					    let p = embassy_nrf::init(Default::default());
 | 
				
			||||||
 | 
					    info!("running!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let eth_sck = p.P0_20;
 | 
				
			||||||
 | 
					    let eth_mosi = p.P0_22;
 | 
				
			||||||
 | 
					    let eth_miso = p.P0_24;
 | 
				
			||||||
 | 
					    let eth_cs = p.P0_15;
 | 
				
			||||||
 | 
					    let eth_rst = p.P0_13;
 | 
				
			||||||
 | 
					    let _eth_irq = p.P0_12;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut config = spim::Config::default();
 | 
				
			||||||
 | 
					    config.frequency = spim::Frequency::M16;
 | 
				
			||||||
 | 
					    let spi = spim::Spim::new(p.SPI3, Irqs, eth_sck, eth_miso, eth_mosi, config);
 | 
				
			||||||
 | 
					    let cs = Output::new(eth_cs, Level::High, OutputDrive::Standard);
 | 
				
			||||||
 | 
					    let spi = ExclusiveDevice::new(spi, cs, Delay);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let rst = Output::new(eth_rst, Level::High, OutputDrive::Standard);
 | 
				
			||||||
 | 
					    let mac_addr = [2, 3, 4, 5, 6, 7];
 | 
				
			||||||
 | 
					    let device = Enc28j60::new(spi, Some(rst), mac_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let config = embassy_net::Config::dhcpv4(Default::default());
 | 
				
			||||||
 | 
					    // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
 | 
				
			||||||
 | 
					    //    address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
 | 
				
			||||||
 | 
					    //    dns_servers: Vec::new(),
 | 
				
			||||||
 | 
					    //    gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
 | 
				
			||||||
 | 
					    // });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Generate random seed
 | 
				
			||||||
 | 
					    let mut rng = Rng::new(p.RNG, Irqs);
 | 
				
			||||||
 | 
					    let mut seed = [0; 8];
 | 
				
			||||||
 | 
					    rng.blocking_fill_bytes(&mut seed);
 | 
				
			||||||
 | 
					    let seed = u64::from_le_bytes(seed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Init network stack
 | 
				
			||||||
 | 
					    let stack = &*make_static!(Stack::new(
 | 
				
			||||||
 | 
					        device,
 | 
				
			||||||
 | 
					        config,
 | 
				
			||||||
 | 
					        make_static!(StackResources::<2>::new()),
 | 
				
			||||||
 | 
					        seed
 | 
				
			||||||
 | 
					    ));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unwrap!(spawner.spawn(net_task(stack)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // And now we can use it!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut rx_buffer = [0; 4096];
 | 
				
			||||||
 | 
					    let mut tx_buffer = [0; 4096];
 | 
				
			||||||
 | 
					    let mut buf = [0; 4096];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loop {
 | 
				
			||||||
 | 
					        let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
 | 
				
			||||||
 | 
					        socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        info!("Listening on TCP:1234...");
 | 
				
			||||||
 | 
					        if let Err(e) = socket.accept(1234).await {
 | 
				
			||||||
 | 
					            warn!("accept error: {:?}", e);
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        info!("Received connection from {:?}", socket.remote_endpoint());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        loop {
 | 
				
			||||||
 | 
					            let n = match socket.read(&mut buf).await {
 | 
				
			||||||
 | 
					                Ok(0) => {
 | 
				
			||||||
 | 
					                    warn!("read EOF");
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Ok(n) => n,
 | 
				
			||||||
 | 
					                Err(e) => {
 | 
				
			||||||
 | 
					                    warn!("read error: {:?}", e);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            info!("rxd {:02x}", &buf[..n]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            match socket.write_all(&buf[..n]).await {
 | 
				
			||||||
 | 
					                Ok(()) => {}
 | 
				
			||||||
 | 
					                Err(e) => {
 | 
				
			||||||
 | 
					                    warn!("write error: {:?}", e);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user