Update to newer smoltcp.

This also fixes a bug where RX descriptors would be first advanced
and then released.
pull/1/head
whitequark 2018-01-26 13:03:04 +00:00
parent fe088d7bba
commit 8491394a50
5 changed files with 178 additions and 158 deletions

34
firmware/Cargo.lock generated
View File

@ -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)" = "<none>"
"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=cb5be48)" = "<none>"
"checksum tm4c129x 0.5.0 (git+https://github.com/m-labs/dslite2svd?rev=d527f3f)" = "<none>"
"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"

View File

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

View File

@ -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);
}
}

View File

@ -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<Self::RxBuffer, Error> {
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<Self::TxBuffer, Error> {
// 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<DeviceInner>);
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<TxToken> {
{
let device = self.0.borrow_mut();
if !device.tx_buf_owned() {
return None
}
}
Some(TxToken(&self.0))
}
}
pub struct RxToken<'a>(&'a RefCell<DeviceInner>);
impl<'a> phy::RxToken for RxToken<'a> {
fn consume<R, F>(self, _timestamp: u64, f: F) -> Result<R>
where F: FnOnce(&[u8]) -> Result<R> {
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<DeviceInner>);
impl<'a> phy::TxToken for TxToken<'a> {
fn consume<R, F>(self, _timestamp: u64, len: usize, f: F) -> Result<R>
where F: FnOnce(&mut [u8]) -> Result<R> {
let mut device = self.0.borrow_mut();
let result = f(unsafe { device.tx_buf_as_slice(len) });
device.tx_buf_release();
result
}
}

View File

@ -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::<TcpSocket>(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);