diff --git a/firmware/Cargo.lock b/firmware/Cargo.lock index 59d07b4..e2a4b79 100644 --- a/firmware/Cargo.lock +++ b/firmware/Cargo.lock @@ -1,14 +1,3 @@ -[root] -name = "ionpak-firmware" -version = "1.0.0" -dependencies = [ - "cortex-m 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cortex-m-rt 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smoltcp 0.4.0-pre (git+https://github.com/m-labs/smoltcp?rev=14355e1)", - "tm4c129x 0.5.0 (git+https://github.com/m-labs/dslite2svd?rev=d527f3f)", - "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "aligned" version = "0.1.1" @@ -43,6 +32,17 @@ dependencies = [ "r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ionpak-firmware" +version = "1.0.0" +dependencies = [ + "cortex-m 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cortex-m-rt 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=cb5be48)", + "tm4c129x 0.5.0 (git+https://github.com/m-labs/dslite2svd?rev=d527f3f)", + "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -54,7 +54,7 @@ dependencies = [ [[package]] name = "managed" -version = "0.3.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -73,11 +73,11 @@ dependencies = [ [[package]] name = "smoltcp" -version = "0.4.0-pre" -source = "git+https://github.com/m-labs/smoltcp?rev=14355e1#14355e15d0b0bbc47b79cbb47ea74dda475a6f1b" +version = "0.4.0" +source = "git+https://github.com/m-labs/smoltcp?rev=cb5be48#cb5be4886864ca4c89952945b08b66db90e61d49" dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "managed 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "managed 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -131,10 +131,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cortex-m 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d553ca1f23403c81e6d3d28a64ef6e8eadd7f395195aacda65cbc0dc987738e" "checksum cortex-m-rt 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ec28308ef272803380c9c4e6708bf1d794ddcc8c9d511b9976b31ac3322452e5" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum managed 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61eb783b4fa77e8fa4d27ec400f97ed9168546b8b30341a120b7ba9cc6571aaf" +"checksum managed 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43e2737ecabe4ae36a68061398bf27d2bfd0763f4c3c837a398478459494c4b7" "checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" -"checksum smoltcp 0.4.0-pre (git+https://github.com/m-labs/smoltcp?rev=14355e1)" = "" +"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=cb5be48)" = "" "checksum tm4c129x 0.5.0 (git+https://github.com/m-labs/dslite2svd?rev=d527f3f)" = "" "checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" "checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml index 19dab06..7eb045d 100644 --- a/firmware/Cargo.toml +++ b/firmware/Cargo.toml @@ -17,8 +17,8 @@ features = ["rt"] [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "14355e1" -features = [] +rev = "cb5be48" +features = ["proto-ipv4", "socket-tcp"] default-features = false [profile.release] diff --git a/firmware/src/config.rs b/firmware/src/config.rs index 9528c85..1248945 100644 --- a/firmware/src/config.rs +++ b/firmware/src/config.rs @@ -1,6 +1,6 @@ use eeprom; use crc32; -use smoltcp::wire::IpAddress; +use smoltcp::wire::{IpCidr, IpAddress}; const MAGIC: u8 = 0x54; @@ -29,7 +29,7 @@ impl EepromReader { } true } - + fn read_payload<'a>(&'a mut self) -> Result<&'a [u8], ()> { let mut ok = self.read_payload_block(0); if !ok { @@ -58,32 +58,36 @@ fn write_eeprom_payload(payload: &[u8]) { } pub struct Config { - pub ip: IpAddress, + pub ip: IpCidr, } impl Config { pub fn new() -> Config { Config { - ip: IpAddress::v4(192, 168, 69, 1) + ip: IpCidr::new(IpAddress::v4(192, 168, 69, 1), 24) } } - + pub fn load(&mut self) { let mut reader = EepromReader::new(); let payload = reader.read_payload(); if payload.is_ok() { let payload = payload.unwrap(); - self.ip = IpAddress::v4(payload[0], payload[1], payload[2], payload[3]); + self.ip = IpCidr::new( + IpAddress::v4(payload[0], payload[1], payload[2], payload[3]), + payload[4]) } } - + pub fn save(&self) { - let mut payload: [u8; 4] = [0; 4]; - let ip4 = match self.ip { - IpAddress::Ipv4(x) => x.0, + match self.ip { + IpCidr::Ipv4(ipv4) => { + let mut payload: [u8; 5] = [0; 5]; + payload[0..4].copy_from_slice(&ipv4.address().0); + payload[4] = ipv4.prefix_len(); + write_eeprom_payload(&payload); + } _ => panic!("unsupported network address") }; - payload[0..4].copy_from_slice(&ip4); - write_eeprom_payload(&payload); } } diff --git a/firmware/src/ethmac.rs b/firmware/src/ethmac.rs index 7668b63..3931a82 100644 --- a/firmware/src/ethmac.rs +++ b/firmware/src/ethmac.rs @@ -1,9 +1,10 @@ -use core::slice; +use core::{slice, cmp}; +use core::cell::RefCell; use cortex_m; use tm4c129x; -use smoltcp::Error; +use smoltcp::Result; use smoltcp::wire::EthernetAddress; -use smoltcp::phy::{DeviceLimits, Device}; +use smoltcp::phy; use board; @@ -23,16 +24,17 @@ const EMAC_TDES0_OWN: u32 = 0x80000000; // Indicates that the descriptor is const EMAC_TDES0_LS: u32 = 0x20000000; // Last Segment const EMAC_TDES0_FS: u32 = 0x10000000; // First Segment const EMAC_TDES0_TCH: u32 = 0x00100000; // Second Address Chained +#[allow(dead_code)] const EMAC_TDES1_TBS1: u32 = 0x00001FFF; // Transmit Buffer 1 Size // Receive DMA descriptor flags const EMAC_RDES0_OWN: u32 = 0x80000000; // indicates that the descriptor is owned by the DMA const EMAC_RDES0_FL: u32 = 0x3FFF0000; // Frame Length const EMAC_RDES0_ES: u32 = 0x00008000; // Error Summary -const EMAC_RDES1_RCH: u32 = 0x00004000; // Second Address Chained -const EMAC_RDES1_RBS1: u32 = 0x00001FFF; // Receive Buffer 1 Size const EMAC_RDES0_FS: u32 = 0x00000200; // First Descriptor const EMAC_RDES0_LS: u32 = 0x00000100; // Last Descriptor +const EMAC_RDES1_RCH: u32 = 0x00004000; // Second Address Chained +const EMAC_RDES1_RBS1: u32 = 0x00001FFF; // Receive Buffer 1 Size const ETH_DESC_U32_SIZE: usize = 8; const ETH_TX_BUFFER_COUNT: usize = 2; @@ -97,7 +99,7 @@ fn phy_write_ext(reg_addr: u8, reg_data: u16) { phy_write(EPHY_ADDAR, reg_data); } -pub struct EthernetDevice { +struct DeviceInner { tx_desc_buf: [u32; ETH_TX_BUFFER_COUNT * ETH_DESC_U32_SIZE], rx_desc_buf: [u32; ETH_RX_BUFFER_COUNT * ETH_DESC_U32_SIZE], tx_cur_desc: usize, @@ -108,9 +110,9 @@ pub struct EthernetDevice { rx_pkt_buf: [u8; ETH_RX_BUFFER_COUNT * ETH_RX_BUFFER_SIZE], } -impl EthernetDevice { - pub fn new() -> EthernetDevice { - EthernetDevice { +impl DeviceInner { + fn new() -> DeviceInner { + DeviceInner { tx_desc_buf: [0; ETH_TX_BUFFER_COUNT * ETH_DESC_U32_SIZE], rx_desc_buf: [0; ETH_RX_BUFFER_COUNT * ETH_DESC_U32_SIZE], tx_cur_desc: 0, @@ -122,7 +124,7 @@ impl EthernetDevice { } } - pub fn init(&mut self, mac_addr: EthernetAddress) { + fn init(&mut self, mac_addr: EthernetAddress) { // Initialize TX DMA descriptors for x in 0..ETH_TX_BUFFER_COUNT { let p = x * ETH_DESC_U32_SIZE; @@ -278,7 +280,7 @@ impl EthernetDevice { w.re().bit(true) // Receiver Enable .te().bit(true) // Transmiter Enable ); - + // Manage DMA transmission and reception emac0.dmaopmode.modify(|_, w| w.sr().bit(true) // Start Receive @@ -287,105 +289,51 @@ impl EthernetDevice { }); } - fn release_rx_buf(&mut self) { + // RX buffer functions + + fn rx_buf_owned(&self) -> bool { + self.rx_desc_buf[self.rx_cur_desc + 0] & EMAC_RDES0_OWN == 0 + } + + fn rx_buf_valid(&self) -> bool { + self.rx_desc_buf[self.rx_cur_desc + 0] & + (EMAC_RDES0_FS | EMAC_RDES0_LS | EMAC_RDES0_ES) == + (EMAC_RDES0_FS | EMAC_RDES0_LS) + } + + unsafe fn rx_buf_as_slice<'a>(&self) -> &'a [u8] { + let len = (self.rx_desc_buf[self.rx_cur_desc + 0] & EMAC_RDES0_FL) >> 16; + let len = cmp::max(len as usize, ETH_RX_BUFFER_SIZE); + let addr = self.rx_desc_buf[self.rx_cur_desc + 2] as *const u8; + slice::from_raw_parts(addr, len) + } + + fn rx_buf_release(&mut self) { + self.rx_desc_buf[self.rx_cur_desc + 0] = EMAC_RDES0_OWN; + self.rx_cur_desc += ETH_DESC_U32_SIZE; - if self.rx_cur_desc >= (ETH_RX_BUFFER_COUNT * ETH_DESC_U32_SIZE) { + if self.rx_cur_desc == self.rx_desc_buf.len() { self.rx_cur_desc = 0; } - self.rx_desc_buf[self.rx_cur_desc + 0] = EMAC_RDES0_OWN; // release descriptor - } -} - -impl Device for EthernetDevice { - type RxBuffer = RxBuffer; - type TxBuffer = TxBuffer; - - fn limits(&self) -> DeviceLimits { - let mut limits = DeviceLimits::default(); - limits.max_transmission_unit = 1500; - limits.max_burst_size = Some(ETH_RX_BUFFER_COUNT); - limits + self.rx_counter += 1; } - fn receive(&mut self, _timestamp: u64) -> Result { - if (self.rx_desc_buf[self.rx_cur_desc + 0] & EMAC_RDES0_OWN) == 0 { - // check for the whole packet in the buffer and no any error - if (EMAC_RDES0_FS | EMAC_RDES0_LS) == self.rx_desc_buf[self.rx_cur_desc + 0] & (EMAC_RDES0_FS | EMAC_RDES0_LS | EMAC_RDES0_ES) { - // Retrieve the length of the frame - let mut n = (self.rx_desc_buf[self.rx_cur_desc + 0] & EMAC_RDES0_FL) >> 16; - // Limit the number of data to read - if n > ETH_RX_BUFFER_SIZE as u32 { n = ETH_RX_BUFFER_SIZE as u32; } - let sl = unsafe { - slice::from_raw_parts(self.rx_desc_buf[self.rx_cur_desc + 2] as * mut u8, - n as usize) - }; - Ok(RxBuffer(sl, self)) - } else { - // Ignore invalid frame - self.release_rx_buf(); - Err(Error::Exhausted) - } - } else { - Err(Error::Exhausted) // currently no buffers to process - } + // TX buffer functions + + fn tx_buf_owned(&self) -> bool { + self.tx_desc_buf[self.tx_cur_desc + 0] & EMAC_TDES0_OWN == 0 } - fn transmit(&mut self, _timestamp: u64, length: usize) -> Result { - // Check if the TX DMA buffer released - if (self.tx_desc_buf[self.tx_cur_desc + 0] & EMAC_TDES0_OWN) == 0 { - // Write the number of bytes to send - self.tx_desc_buf[self.tx_cur_desc + 1] = length as u32 & EMAC_TDES1_TBS1; - - let sl = unsafe { - slice::from_raw_parts_mut(self.tx_desc_buf[self.tx_cur_desc + 2] as * mut u8, - length) - }; - Ok(TxBuffer(sl, self)) - } else { - // to do if need: Instruct the DMA to poll the receive descriptor list - Err(Error::Exhausted) - } + unsafe fn tx_buf_as_slice<'a>(&mut self, len: usize) -> &'a mut [u8] { + let len = cmp::max(len, ETH_TX_BUFFER_SIZE); + self.tx_desc_buf[self.tx_cur_desc + 1] = len as u32; + let addr = self.tx_desc_buf[self.tx_cur_desc + 2] as *mut u8; + slice::from_raw_parts_mut(addr, len) } -} -pub struct RxBuffer(*const [u8], *mut EthernetDevice); - -impl AsRef<[u8]> for RxBuffer { - fn as_ref(&self) -> &[u8] { - unsafe { &*self.0 } - } -} - -impl Drop for RxBuffer { - fn drop(&mut self) { - let mut device = unsafe { &mut *self.1 }; - device.release_rx_buf(); - device.rx_counter += 1; - } -} - -pub struct TxBuffer(*mut [u8], *mut EthernetDevice); - -impl AsRef<[u8]> for TxBuffer { - fn as_ref(&self) -> &[u8] { - unsafe { &*self.0 } - } -} - -impl AsMut<[u8]> for TxBuffer { - fn as_mut(&mut self) -> &mut [u8] { - unsafe { &mut *self.0 } - } -} - -impl Drop for TxBuffer { - fn drop(&mut self) { - let mut device = unsafe { &mut *self.1 }; - - // Use chain structure rather than ring structure - // Set LS and FS flags as the data fits in a single buffer and give the ownership of the descriptor to the DMA - device.tx_desc_buf[device.tx_cur_desc + 0] = EMAC_TDES0_LS | EMAC_TDES0_FS | EMAC_TDES0_TCH; - device.tx_desc_buf[device.tx_cur_desc + 0] |= EMAC_TDES0_OWN; // Set ownership for DMA here + fn tx_buf_release(&mut self) { + self.tx_desc_buf[self.tx_cur_desc + 0] = + EMAC_TDES0_OWN | EMAC_TDES0_LS | EMAC_TDES0_FS | EMAC_TDES0_TCH; cortex_m::interrupt::free(|cs| { let emac0 = tm4c129x::EMAC0.borrow(cs); @@ -395,13 +343,85 @@ impl Drop for TxBuffer { unsafe { emac0.txpolld.write(|w| w.tpd().bits(0)); } }); - // Calculate next DMA descriptor offset - let mut tx_next_desc = device.tx_cur_desc + ETH_DESC_U32_SIZE; - if tx_next_desc >= (ETH_TX_BUFFER_COUNT * ETH_DESC_U32_SIZE) { - tx_next_desc = 0; + self.tx_cur_desc += ETH_DESC_U32_SIZE; + if self.tx_cur_desc == self.tx_desc_buf.len() { + self.tx_cur_desc = 0; } - device.tx_cur_desc = tx_next_desc; - - device.tx_counter += 1; + self.tx_counter += 1; + } +} + +pub struct Device(RefCell); + +impl Device { + pub fn new(mac: EthernetAddress) -> Device { + let mut inner = DeviceInner::new(); + inner.init(mac); + Device(RefCell::new(inner)) + } +} + +impl<'a> phy::Device<'a> for Device { + type RxToken = RxToken<'a>; + type TxToken = TxToken<'a>; + + fn capabilities(&self) -> phy::DeviceCapabilities { + let mut capabilities = phy::DeviceCapabilities::default(); + capabilities.max_transmission_unit = 1500; + capabilities.max_burst_size = Some(ETH_RX_BUFFER_COUNT); + capabilities + } + + fn receive(&mut self) -> Option<(RxToken, TxToken)> { + { + let mut device = self.0.borrow_mut(); + + // Skip all queued packets with errors. + while device.rx_buf_owned() && !device.rx_buf_valid() { + device.rx_buf_release() + } + + if !(device.rx_buf_owned() && device.tx_buf_owned()) { + return None + } + } + + Some((RxToken(&self.0), TxToken(&self.0))) + } + + fn transmit(&mut self) -> Option { + { + let device = self.0.borrow_mut(); + + if !device.tx_buf_owned() { + return None + } + } + + Some(TxToken(&self.0)) + } +} + +pub struct RxToken<'a>(&'a RefCell); + +impl<'a> phy::RxToken for RxToken<'a> { + fn consume(self, _timestamp: u64, f: F) -> Result + where F: FnOnce(&[u8]) -> Result { + let mut device = self.0.borrow_mut(); + let result = f(unsafe { device.rx_buf_as_slice() }); + device.rx_buf_release(); + result + } +} + +pub struct TxToken<'a>(&'a RefCell); + +impl<'a> phy::TxToken for TxToken<'a> { + fn consume(self, _timestamp: u64, len: usize, f: F) -> Result + where F: FnOnce(&mut [u8]) -> Result { + let mut device = self.0.borrow_mut(); + let result = f(unsafe { device.tx_buf_as_slice(len) }); + device.tx_buf_release(); + result } } diff --git a/firmware/src/main.rs b/firmware/src/main.rs index fbc378c..c6050b5 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -11,9 +11,8 @@ use core::cell::{Cell, RefCell}; use core::fmt; use cortex_m::interrupt::Mutex; use smoltcp::wire::EthernetAddress; -use smoltcp::iface::{ArpCache, SliceArpCache, EthernetInterface}; -use smoltcp::socket::{AsSocket, SocketSet}; -use smoltcp::socket::{TcpSocket, TcpSocketBuffer}; +use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder}; +use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer}; #[macro_export] macro_rules! print { @@ -160,15 +159,16 @@ fn main() { println!("programmed MAC address is invalid, using default"); hardware_addr = EthernetAddress([0x10, 0xE2, 0xD5, 0x00, 0x03, 0x00]); } - let mut protocol_addrs = [config.ip]; - println!("MAC {} IP {}", hardware_addr, protocol_addrs[0]); - let mut arp_cache_entries: [_; 8] = Default::default(); - let mut arp_cache = SliceArpCache::new(&mut arp_cache_entries[..]); - let mut device = ethmac::EthernetDevice::new(); - device.init(hardware_addr); - let mut iface = EthernetInterface::new( - &mut device, &mut arp_cache as &mut ArpCache, - hardware_addr, &mut protocol_addrs[..]); + let mut ip_addrs = [config.ip]; + println!("MAC {} IP {}", hardware_addr, ip_addrs[0]); + let mut neighbor_cache_storage = [None; 8]; + let neighbor_cache = NeighborCache::new(&mut neighbor_cache_storage[..]); + let device = ethmac::Device::new(hardware_addr); + let mut iface = EthernetInterfaceBuilder::new(device) + .ethernet_addr(hardware_addr) + .neighbor_cache(neighbor_cache) + .ip_addrs(&mut ip_addrs[..]) + .finalize(); create_socket_storage!(tcp_rx_storage0, tcp_tx_storage0); create_socket_storage!(tcp_rx_storage1, tcp_tx_storage1); @@ -211,18 +211,14 @@ fn main() { loop { let time = get_time_ms(); - for &mut(ref mut request, ref tcp_handle) in sessions.iter_mut() { - let socket: &mut TcpSocket = sockets.get_mut(*tcp_handle).as_socket(); + for &mut(ref mut request, tcp_handle) in sessions.iter_mut() { + let socket = &mut *sockets.get::(tcp_handle); if !socket.is_open() { socket.listen(80).unwrap() } if socket.may_recv() { - let request_status = { - let data = socket.recv(TCP_RX_BUFFER_SIZE).unwrap(); - request.input(data) - }; - match request_status { + match socket.recv(|data| (data.len(), request.input(data))).unwrap() { Ok(true) => { if socket.can_send() { pages::serve(socket, &request, &mut config, &LOOP_ANODE, &LOOP_CATHODE, &ELECTROMETER);