Be able to IP, Subnet, Gateway and Mac; and send udp packets

This commit is contained in:
Michael Watzko 2018-03-11 14:17:44 +01:00
commit f28b948dac
4 changed files with 532 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/target
**/*.rs.bk

31
Cargo.lock generated Normal file
View file

@ -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"

9
Cargo.toml Normal file
View file

@ -0,0 +1,9 @@
[package]
name = "w5500"
version = "0.1.0"
authors = ["Michael Watzko <michael@watzko.de>"]
[dependencies]
byteorder = { version = "1.2.1", default-features = false }
embedded-hal = "0.1.2"
nb = "0.1.1"

489
src/lib.rs Normal file
View file

@ -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<E, S: FullDuplex<u8, Error=E> + Sized, O: OutputPin> {
spi: S,
cs: O,
}
impl<E, S: FullDuplex<u8, Error=E> + Sized, O: OutputPin> W5500<E, S, O> {
pub fn new(spi: S, cs: O) -> Result<W5500<E, S, O>, E> {
W5500 {
spi,
cs,
}.init()
}
fn init(mut self) -> Result<Self, E> {
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<MacAddress, E> {
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<u8, E> {
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,
}
}
}