commit f28b948daca173591a7392c15ebebf59423afe57 Author: Michael Watzko Date: Sun Mar 11 14:17:44 2018 +0100 Be able to IP, Subnet, Gateway and Mac; and send udp packets diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..70e3cae --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ + +/target +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..6343720 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,31 @@ +[[package]] +name = "byteorder" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "embedded-hal" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nb" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "w5500" +version = "0.1.0" +dependencies = [ + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "embedded-hal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "nb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" +"checksum embedded-hal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "684b1fa3196f78342296d04edc2a6e5d053729d1b64a819dcb072810d706e267" +"checksum nb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "69f380b5fe9fab8c0d7a6a99cda23e2cc0463bedb2cbc3aada0813b98496ecdc" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f4b9822 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "w5500" +version = "0.1.0" +authors = ["Michael Watzko "] + +[dependencies] +byteorder = { version = "1.2.1", default-features = false } +embedded-hal = "0.1.2" +nb = "0.1.1" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..9115ce1 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,489 @@ +#![no_std] +#![allow(unused)] +#![feature(const_fn)] + +extern crate byteorder; +extern crate embedded_hal as hal; + +#[macro_use(block)] +extern crate nb; + +use hal::digital::OutputPin; +use hal::spi::FullDuplex; + +use byteorder::ByteOrder; +use byteorder::BigEndian; + + +const COMMAND_READ : u8 = 0x00 << 2; +const COMMAND_WRITE : u8 = 0x01 << 2; + +const VARIABLE_DATA_LENGTH : u8 = 0b_00; +const FIXED_DATA_LENGTH_1_BYTE : u8 = 0b_01; +const FIXED_DATA_LENGTH_2_BYTES : u8 = 0b_10; +const FIXED_DATA_LENGTH_4_BYTES : u8 = 0b_11; + +#[derive(Copy, Clone, PartialOrd, PartialEq, Default, Debug)] +pub struct IpAddress { + address: [u8; 4] +} + +impl IpAddress { + pub fn new(a0: u8, a1: u8, a2: u8, a3: u8) -> IpAddress { + IpAddress { + address: [a0, a1, a2, a3] + } + } +} + +impl ::core::fmt::Display for IpAddress { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}.{}.{}.{}", + self.address[0], + self.address[1], + self.address[2], + self.address[3], + ) + } +} + + +#[derive(Copy, Clone, PartialOrd, PartialEq, Default, Debug)] +pub struct MacAddress { + address: [u8; 6] +} + +impl MacAddress { + pub fn new(a0: u8, a1: u8, a2: u8, a3: u8, a4: u8, a5: u8) -> MacAddress { + MacAddress { + address: [a0, a1, a2, a3, a4, a5] + } + } +} + +impl ::core::fmt::Display for MacAddress { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", + self.address[0], + self.address[1], + self.address[2], + self.address[3], + self.address[4], + self.address[5], + ) + } +} + + +pub struct W5500 + Sized, O: OutputPin> { + spi: S, + cs: O, +} + +impl + Sized, O: OutputPin> W5500 { + + pub fn new(spi: S, cs: O) -> Result, E> { + W5500 { + spi, + cs, + }.init() + } + + fn init(mut self) -> Result { + self.reset()?; + self.set_mode(false, false, false, false)?; + + self.set_mac(&MacAddress::new(0x00, 0x08, 0xDC, 0x01, 0x02, 0x03))?; + + + self.set_ip(&IpAddress::new(192, 168, 3, 222))?; + self.set_subnet(&IpAddress::new(255, 255, 255, 0))?; + self.set_gateway(&IpAddress::new(192, 168, 3, 1))?; + + // socket 0 with udp + + self.write_to( + Register::Socket0Register(0x00_00), + &[ + 0b0000_0010, // UDP + 0x01 // OPEN / initialize + ] + ); + self.write_to( + Register::Socket0Register(0x00_04), + &[ + 0, 50, // local port u16 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // destination mac + 192, 168, 3, 55, // target IP + 0x14, 0xEA, // destination port (5354) + ] + )?; + + self.write_to( + Register::Socket0Register(0x00_01), + &[ + 0x20 // SEND + ] + )?; + Ok(self) + } + + pub fn reset(&mut self) -> Result<(), E> { + self.write_to( + Register::CommonRegister(0x00_00_u16), + &[ + 0b1000_0000, // Mode Register (force reset) + ] + ) + } + + pub fn set_mode(&mut self, wol: bool, ping_block: bool, ppoe: bool, force_arp: bool) -> Result<(), E> { + + let mut mode = 0x00; + + if wol { + mode |= (1 << 5); + } + + if ping_block { + mode |= (1 << 4); + } + + if ppoe { + mode |= (1 << 3); + } + + if force_arp { + mode |= (1 << 1); + } + + self.write_to( + Register::CommonRegister(0x00_00_u16), + &[mode] + ) + } + + pub fn set_gateway(&mut self, gateway: &IpAddress) -> Result<(), E> { + self.write_to( + Register::CommonRegister(0x00_01_u16), + &gateway.address + ) + } + + pub fn set_subnet(&mut self, subnet: &IpAddress) -> Result<(), E> { + self.write_to( + Register::CommonRegister(0x00_05_u16), + &subnet.address + ) + } + + pub fn set_mac(&mut self, mac: &MacAddress) -> Result<(), E> { + self.write_to( + Register::CommonRegister(0x00_09_u16), + &mac.address + ) + } + + pub fn get_mac(&mut self) -> Result { + let mut mac = MacAddress::default(); + self.read_from( + Register::CommonRegister(0x00_09_u16), + &mut mac.address + )?; + Ok(mac) + } + + pub fn set_ip(&mut self, ip: &IpAddress) -> Result<(), E> { + self.write_to( + Register::CommonRegister(0x00_0F_u16), + &ip.address + ) + } + + pub fn send_udp(&mut self, socket: Socket, local_port: u16, host: &IpAddress, host_port: u16, data: &[u8]) -> Result<(), E> { + // TODO not always socket 0 + // TODO check if in use + + + self.write_to( + socket.register_at(0x00_00), + &[ + 0b0000_0010, // UDP + 0x01 // OPEN / initialize + ] + ); + + { + let local_port = u16_to_be_bytes(local_port); + let host_port = u16_to_be_bytes(host_port); + + self.write_to( + socket.register_at(0x00_04), + &[ + local_port[0], local_port[1], // local port u16 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // destination mac + host.address[0], host.address[1], host.address[2], host.address[3], // target IP + host_port[0], host_port[1], // destination port (5354) + ] + )?; + } + + + let data_length = data.len() as u16; + { + let data_length = u16_to_be_bytes(data_length); + + self.write_to( + socket.register_at(0x00_22), + &[ + 0x00, 0x00, + data_length[0], data_length[1], + ] + ); + } + + + self.write_to( + socket.tx_register_at(0x00_00), + &data[..data_length as usize] + ); + + self.write_to( + socket.register_at(0x00_01), + &[ + 0x20 // SEND + ] + ) + } + + pub fn read_from(&mut self, register: Register, target: &mut [u8]) -> Result<(), E> { + self.chip_select(); + let mut request = [0_u8, 0_u8, register.control_byte() | COMMAND_READ | VARIABLE_DATA_LENGTH]; + BigEndian::write_u16(&mut request[..2], register.address()); + let result = self + .write_bytes(&request) + .and_then(|_| self.read_bytes(target)); + self.chip_deselect(); + result + } + + pub fn write_to(&mut self, register: Register, data: &[u8]) -> Result<(), E> { + self.chip_select(); + let mut request = [0_u8, 0_u8, register.control_byte() | COMMAND_WRITE | VARIABLE_DATA_LENGTH]; + BigEndian::write_u16(&mut request[..2], register.address()); + let result = self + .write_bytes(&request) + .and_then(|_| self.write_bytes(data)); + self.chip_deselect(); + result + } + + fn read_bytes(&mut self, bytes: &mut [u8]) -> Result<(), E> { + for i in 0..bytes.len() { + bytes[i] = self.read()?; + } + Ok(()) + } + + fn read(&mut self) -> Result { + block!(self.spi.send(0x00))?; + let result = block!(self.spi.read()); + result + } + + fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), E> { + for b in bytes { + self.write(*b)?; + } + Ok(()) + } + + fn write(&mut self, byte: u8) -> Result<(), E> { + block!(self.spi.send(byte))?; + block!(self.spi.read())?; + Ok(()) + } + + fn chip_select(&mut self) { + self.cs.set_low() + } + + fn chip_deselect(&mut self) { + self.cs.set_high() + } + +} + +fn u16_to_be_bytes(u16: u16) -> [u8; 2] { + let mut bytes = [0u8; 2]; + BigEndian::write_u16(&mut bytes, u16); + bytes +} + +#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] +pub enum Socket { + Socket0, + Socket1, + Socket2, + Socket3, + Socket4, + Socket5, + Socket6, + Socket7, +} + +impl Socket { + fn tx_register_at(&self, address: u16) -> Register { + match *self { + Socket::Socket0 => Register::Socket0TxBuffer(address), + Socket::Socket1 => Register::Socket1TxBuffer(address), + Socket::Socket2 => Register::Socket2TxBuffer(address), + Socket::Socket3 => Register::Socket3TxBuffer(address), + Socket::Socket4 => Register::Socket4TxBuffer(address), + Socket::Socket5 => Register::Socket5TxBuffer(address), + Socket::Socket6 => Register::Socket6TxBuffer(address), + Socket::Socket7 => Register::Socket7TxBuffer(address), + } + } + + fn rx_register_at(&self, address: u16) -> Register { + match *self { + Socket::Socket0 => Register::Socket0RxBuffer(address), + Socket::Socket1 => Register::Socket1RxBuffer(address), + Socket::Socket2 => Register::Socket2RxBuffer(address), + Socket::Socket3 => Register::Socket3RxBuffer(address), + Socket::Socket4 => Register::Socket4RxBuffer(address), + Socket::Socket5 => Register::Socket5RxBuffer(address), + Socket::Socket6 => Register::Socket6RxBuffer(address), + Socket::Socket7 => Register::Socket7RxBuffer(address), + } + } + + fn register_at(&self, address: u16) -> Register { + match *self { + Socket::Socket0 => Register::Socket0Register(address), + Socket::Socket1 => Register::Socket1Register(address), + Socket::Socket2 => Register::Socket2Register(address), + Socket::Socket3 => Register::Socket3Register(address), + Socket::Socket4 => Register::Socket4Register(address), + Socket::Socket5 => Register::Socket5Register(address), + Socket::Socket6 => Register::Socket6Register(address), + Socket::Socket7 => Register::Socket7Register(address), + } + } +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum Register { + CommonRegister(u16), + + Socket0Register(u16), + Socket0TxBuffer(u16), + Socket0RxBuffer(u16), + + Socket1Register(u16), + Socket1TxBuffer(u16), + Socket1RxBuffer(u16), + + Socket2Register(u16), + Socket2TxBuffer(u16), + Socket2RxBuffer(u16), + + Socket3Register(u16), + Socket3TxBuffer(u16), + Socket3RxBuffer(u16), + + Socket4Register(u16), + Socket4TxBuffer(u16), + Socket4RxBuffer(u16), + + Socket5Register(u16), + Socket5TxBuffer(u16), + Socket5RxBuffer(u16), + + Socket6Register(u16), + Socket6TxBuffer(u16), + Socket6RxBuffer(u16), + + Socket7Register(u16), + Socket7TxBuffer(u16), + Socket7RxBuffer(u16), +} + +impl Register { + fn control_byte(&self) -> u8 { + match *self { + Register::CommonRegister(_) => 0b00000_000, + + Register::Socket0Register(_) => 0b00001_000, + Register::Socket0TxBuffer(_) => 0b00010_000, + Register::Socket0RxBuffer(_) => 0b00011_000, + + Register::Socket1Register(_) => 0b00101_000, + Register::Socket1TxBuffer(_) => 0b00110_000, + Register::Socket1RxBuffer(_) => 0b00111_000, + + Register::Socket2Register(_) => 0b01001_000, + Register::Socket2TxBuffer(_) => 0b01010_000, + Register::Socket2RxBuffer(_) => 0b01011_000, + + Register::Socket3Register(_) => 0b01101_000, + Register::Socket3TxBuffer(_) => 0b01110_000, + Register::Socket3RxBuffer(_) => 0b01111_000, + + Register::Socket4Register(_) => 0b10001_000, + Register::Socket4TxBuffer(_) => 0b10010_000, + Register::Socket4RxBuffer(_) => 0b10011_000, + + Register::Socket5Register(_) => 0b10101_000, + Register::Socket5TxBuffer(_) => 0b10110_000, + Register::Socket5RxBuffer(_) => 0b10111_000, + + Register::Socket6Register(_) => 0b11001_000, + Register::Socket6TxBuffer(_) => 0b11010_000, + Register::Socket6RxBuffer(_) => 0b11011_000, + + Register::Socket7Register(_) => 0b11101_000, + Register::Socket7TxBuffer(_) => 0b11110_000, + Register::Socket7RxBuffer(_) => 0b11111_000, + } + } + + fn address(&self) -> u16 { + match *self { + Register::CommonRegister(address) => address, + + Register::Socket0Register(address) => address, + Register::Socket0TxBuffer(address) => address, + Register::Socket0RxBuffer(address) => address, + + Register::Socket1Register(address) => address, + Register::Socket1TxBuffer(address) => address, + Register::Socket1RxBuffer(address) => address, + + Register::Socket2Register(address) => address, + Register::Socket2TxBuffer(address) => address, + Register::Socket2RxBuffer(address) => address, + + Register::Socket3Register(address) => address, + Register::Socket3TxBuffer(address) => address, + Register::Socket3RxBuffer(address) => address, + + Register::Socket4Register(address) => address, + Register::Socket4TxBuffer(address) => address, + Register::Socket4RxBuffer(address) => address, + + Register::Socket5Register(address) => address, + Register::Socket5TxBuffer(address) => address, + Register::Socket5RxBuffer(address) => address, + + Register::Socket6Register(address) => address, + Register::Socket6TxBuffer(address) => address, + Register::Socket6RxBuffer(address) => address, + + Register::Socket7Register(address) => address, + Register::Socket7TxBuffer(address) => address, + Register::Socket7RxBuffer(address) => address, + } + } +}