forked from M-Labs/thermostat
new flash-based ipv4 config with additional mask_len, gateway
This commit is contained in:
parent
383ebcd8e4
commit
880a887c40
|
@ -39,8 +39,15 @@ serde-json-core = "0.1"
|
||||||
sfkv = "0.1"
|
sfkv = "0.1"
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
stm32f4xx-hal = { git = "https://github.com/stm32-rs/stm32f4xx-hal.git" }
|
# smoltcp = { path = "../smoltcp" }
|
||||||
|
# # TODO: pending https://github.com/stm32-rs/stm32f4xx-hal/pull/125
|
||||||
|
# stm32f4xx-hal = { git = "https://github.com/thalesfragoso/stm32f4xx-hal", branch = "pwm-impl" }
|
||||||
|
#stm32f4xx-hal = { git = "https://github.com/stm32-rs/stm32f4xx-hal.git" }
|
||||||
|
stm32f4xx-hal = { path = "../../stm32f4/stm32f4xx-hal" }
|
||||||
|
sfkv = { path = "../sfkv" }
|
||||||
|
|
||||||
|
# [patch."https://github.com/stm32-rs/stm32-eth.git"]
|
||||||
|
# stm32-eth = { path = "../../stm32f4/stm32-eth" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
semihosting = ["panic-semihosting", "cortex-m-log/semihosting"]
|
semihosting = ["panic-semihosting", "cortex-m-log/semihosting"]
|
||||||
|
|
|
@ -85,6 +85,13 @@ impl fmt::Display for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Ipv4Config {
|
||||||
|
pub address: [u8; 4],
|
||||||
|
pub mask_len: u8,
|
||||||
|
pub gateway: Option<[u8; 4]>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum ShowCommand {
|
pub enum ShowCommand {
|
||||||
Input,
|
Input,
|
||||||
|
@ -139,7 +146,7 @@ pub enum Command {
|
||||||
channel: Option<usize>,
|
channel: Option<usize>,
|
||||||
},
|
},
|
||||||
Reset,
|
Reset,
|
||||||
Ipv4([u8; 4]),
|
Ipv4(Ipv4Config),
|
||||||
Show(ShowCommand),
|
Show(ShowCommand),
|
||||||
Reporting(bool),
|
Reporting(bool),
|
||||||
/// PWM parameter setting
|
/// PWM parameter setting
|
||||||
|
@ -473,9 +480,7 @@ fn save(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
Ok((input, result))
|
Ok((input, result))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ipv4(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
fn ipv4_addr(input: &[u8]) -> IResult<&[u8], Result<[u8; 4], Error>> {
|
||||||
let (input, _) = tag("ipv4")(input)?;
|
|
||||||
let (input, _) = whitespace(input)?;
|
|
||||||
let (input, a) = unsigned(input)?;
|
let (input, a) = unsigned(input)?;
|
||||||
let (input, _) = tag(".")(input)?;
|
let (input, _) = tag(".")(input)?;
|
||||||
let (input, b) = unsigned(input)?;
|
let (input, b) = unsigned(input)?;
|
||||||
|
@ -483,12 +488,33 @@ fn ipv4(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
let (input, c) = unsigned(input)?;
|
let (input, c) = unsigned(input)?;
|
||||||
let (input, _) = tag(".")(input)?;
|
let (input, _) = tag(".")(input)?;
|
||||||
let (input, d) = unsigned(input)?;
|
let (input, d) = unsigned(input)?;
|
||||||
end(input)?;
|
let address = move || Ok([a? as u8, b? as u8, c? as u8, d? as u8]);
|
||||||
|
Ok((input, address()))
|
||||||
|
}
|
||||||
|
|
||||||
let result = a.and_then(|a| b.and_then(|b| c.and_then(|c| d.map(|d|
|
fn ipv4(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
Command::Ipv4([a as u8, b as u8, c as u8, d as u8])
|
let (input, _) = tag("ipv4")(input)?;
|
||||||
))));
|
let (input, _) = whitespace(input)?;
|
||||||
Ok((input, result))
|
let (input, address) = ipv4_addr(input)?;
|
||||||
|
let (input, _) = tag("/")(input)?;
|
||||||
|
let (input, mask_len) = unsigned(input)?;
|
||||||
|
let (input, gateway) = alt((
|
||||||
|
|input| {
|
||||||
|
let (input, _) = whitespace(input)?;
|
||||||
|
let (input, gateway) = ipv4_addr(input)?;
|
||||||
|
Ok((input, gateway.map(Some)))
|
||||||
|
},
|
||||||
|
value(Ok(None), end),
|
||||||
|
))(input)?;
|
||||||
|
|
||||||
|
let result = move || {
|
||||||
|
Ok(Command::Ipv4(Ipv4Config {
|
||||||
|
address: address?,
|
||||||
|
mask_len: mask_len? as u8,
|
||||||
|
gateway: gateway?,
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
Ok((input, result()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn command(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
fn command(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
|
@ -555,8 +581,22 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_ipv4() {
|
fn parse_ipv4() {
|
||||||
let command = Command::parse(b"ipv4 192.168.1.26");
|
let command = Command::parse(b"ipv4 192.168.1.26/24");
|
||||||
assert_eq!(command, Ok(Command::Ipv4([192, 168, 1, 26])));
|
assert_eq!(command, Ok(Command::Ipv4(Ipv4Config {
|
||||||
|
address: [192, 168, 1, 26],
|
||||||
|
mask_len: 24,
|
||||||
|
gateway: None,
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_ipv4_and_gateway() {
|
||||||
|
let command = Command::parse(b"ipv4 10.42.0.126/8 10.1.0.1");
|
||||||
|
assert_eq!(command, Ok(Command::Ipv4(Ipv4Config {
|
||||||
|
address: [10, 42, 0, 126],
|
||||||
|
mask_len: 8,
|
||||||
|
gateway: Some([10, 1, 0, 1]),
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use smoltcp::wire::Ipv4Address;
|
|
||||||
use uom::si::{
|
use uom::si::{
|
||||||
electric_potential::volt,
|
electric_potential::volt,
|
||||||
electric_current::ampere,
|
electric_current::ampere,
|
||||||
|
|
46
src/main.rs
46
src/main.rs
|
@ -17,14 +17,14 @@ use cortex_m_rt::entry;
|
||||||
use stm32f4xx_hal::{
|
use stm32f4xx_hal::{
|
||||||
hal::watchdog::{WatchdogEnable, Watchdog},
|
hal::watchdog::{WatchdogEnable, Watchdog},
|
||||||
rcc::RccExt,
|
rcc::RccExt,
|
||||||
watchdog::IndependentWatchdog,
|
|
||||||
time::{U32Ext, MegaHertz},
|
|
||||||
stm32::{CorePeripherals, Peripherals, SCB},
|
stm32::{CorePeripherals, Peripherals, SCB},
|
||||||
|
time::{U32Ext, MegaHertz},
|
||||||
|
watchdog::IndependentWatchdog,
|
||||||
};
|
};
|
||||||
use smoltcp::{
|
use smoltcp::{
|
||||||
time::Instant,
|
time::Instant,
|
||||||
socket::TcpSocket,
|
socket::TcpSocket,
|
||||||
wire::{EthernetAddress, Ipv4Address},
|
wire::EthernetAddress,
|
||||||
};
|
};
|
||||||
use uom::{
|
use uom::{
|
||||||
si::{
|
si::{
|
||||||
|
@ -55,7 +55,7 @@ use server::Server;
|
||||||
mod session;
|
mod session;
|
||||||
use session::{Session, SessionInput};
|
use session::{Session, SessionInput};
|
||||||
mod command_parser;
|
mod command_parser;
|
||||||
use command_parser::{Command, ShowCommand, PwmPin};
|
use command_parser::{Command, Ipv4Config, PwmPin, ShowCommand};
|
||||||
mod timer;
|
mod timer;
|
||||||
mod pid;
|
mod pid;
|
||||||
mod steinhart_hart;
|
mod steinhart_hart;
|
||||||
|
@ -75,7 +75,6 @@ const WATCHDOG_INTERVAL: u32 = 30_000;
|
||||||
|
|
||||||
const CHANNEL_CONFIG_KEY: [&str; 2] = ["ch0", "ch1"];
|
const CHANNEL_CONFIG_KEY: [&str; 2] = ["ch0", "ch1"];
|
||||||
|
|
||||||
pub const DEFAULT_IPV4_ADDRESS: Ipv4Address = Ipv4Address([192, 168, 1, 26]);
|
|
||||||
const TCP_PORT: u16 = 23;
|
const TCP_PORT: u16 = 23;
|
||||||
|
|
||||||
|
|
||||||
|
@ -174,8 +173,19 @@ fn main() -> ! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ipv4_address = DEFAULT_IPV4_ADDRESS;
|
// default net config:
|
||||||
info!("IPv4 address: {}", ipv4_address);
|
let mut ipv4_config = Ipv4Config {
|
||||||
|
address: [192, 168, 1, 26],
|
||||||
|
mask_len: 24,
|
||||||
|
gateway: None,
|
||||||
|
};
|
||||||
|
match store.read_value("ipv4") {
|
||||||
|
Ok(Some(config)) =>
|
||||||
|
ipv4_config = config,
|
||||||
|
Ok(None) => {}
|
||||||
|
Err(e) =>
|
||||||
|
error!("cannot read ipv4 config: {:?}", e),
|
||||||
|
}
|
||||||
|
|
||||||
// EEPROM ships with a read-only EUI-48 identifier
|
// EEPROM ships with a read-only EUI-48 identifier
|
||||||
let mut eui48 = [0; 6];
|
let mut eui48 = [0; 6];
|
||||||
|
@ -183,12 +193,12 @@ fn main() -> ! {
|
||||||
let hwaddr = EthernetAddress(eui48);
|
let hwaddr = EthernetAddress(eui48);
|
||||||
info!("EEPROM MAC address: {}", hwaddr);
|
info!("EEPROM MAC address: {}", hwaddr);
|
||||||
|
|
||||||
net::run(clocks, dp.ETHERNET_MAC, dp.ETHERNET_DMA, eth_pins, hwaddr, ipv4_address, |iface| {
|
net::run(clocks, dp.ETHERNET_MAC, dp.ETHERNET_DMA, eth_pins, hwaddr, ipv4_config, |iface| {
|
||||||
let mut new_ipv4_address = None;
|
|
||||||
Server::<Session>::run(iface, |server| {
|
Server::<Session>::run(iface, |server| {
|
||||||
leds.r1.off();
|
leds.r1.off();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
let mut new_ipv4_config = None;
|
||||||
let instant = Instant::from_millis(i64::from(timer::now()));
|
let instant = Instant::from_millis(i64::from(timer::now()));
|
||||||
let updated_channel = channels.poll_adc(instant);
|
let updated_channel = channels.poll_adc(instant);
|
||||||
if let Some(channel) = updated_channel {
|
if let Some(channel) = updated_channel {
|
||||||
|
@ -368,14 +378,15 @@ fn main() -> ! {
|
||||||
let config = ChannelConfig::new(&mut channels, c);
|
let config = ChannelConfig::new(&mut channels, c);
|
||||||
let _ = store
|
let _ = store
|
||||||
.write_value(CHANNEL_CONFIG_KEY[c], &config, &mut store_value_buf)
|
.write_value(CHANNEL_CONFIG_KEY[c], &config, &mut store_value_buf)
|
||||||
.map_err(
|
.map_err(|e| error!("unable to save channel {} config to flash: {:?}", c, e));
|
||||||
|e| error!("unable to save config to flash: {:?}", e)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Command::Ipv4(address) => {
|
Command::Ipv4(config) => {
|
||||||
new_ipv4_address = Some(Ipv4Address::from_bytes(&address));
|
let _ = store
|
||||||
|
.write_value("ipv4", &config, [0; 16])
|
||||||
|
.map_err(|e| error!("unable to save ipv4 config to flash: {:?}", e));
|
||||||
|
new_ipv4_config = Some(config);
|
||||||
}
|
}
|
||||||
Command::Reset => {
|
Command::Reset => {
|
||||||
for i in 0..CHANNELS {
|
for i in 0..CHANNELS {
|
||||||
|
@ -401,11 +412,8 @@ fn main() -> ! {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Apply new IPv4 address
|
// Apply new IPv4 address/gateway
|
||||||
new_ipv4_address.map(|new_ipv4_address| {
|
new_ipv4_config.map(|config| server.set_ipv4_config(config));
|
||||||
server.set_ipv4_address(ipv4_address);
|
|
||||||
ipv4_address = new_ipv4_address;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update watchdog
|
// Update watchdog
|
||||||
wd.feed();
|
wd.feed();
|
||||||
|
|
26
src/net.rs
26
src/net.rs
|
@ -7,9 +7,13 @@ use stm32f4xx_hal::{
|
||||||
rcc::Clocks,
|
rcc::Clocks,
|
||||||
stm32::{interrupt, Peripherals, ETHERNET_MAC, ETHERNET_DMA},
|
stm32::{interrupt, Peripherals, ETHERNET_MAC, ETHERNET_DMA},
|
||||||
};
|
};
|
||||||
use smoltcp::wire::{EthernetAddress, IpCidr, Ipv4Address};
|
use smoltcp::wire::{EthernetAddress, Ipv4Address, Ipv4Cidr};
|
||||||
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, EthernetInterface};
|
use smoltcp::iface::{
|
||||||
|
EthernetInterfaceBuilder, EthernetInterface,
|
||||||
|
NeighborCache, Routes,
|
||||||
|
};
|
||||||
use stm32_eth::{Eth, RingEntry, PhyAddress, RxDescriptor, TxDescriptor};
|
use stm32_eth::{Eth, RingEntry, PhyAddress, RxDescriptor, TxDescriptor};
|
||||||
|
use crate::command_parser::Ipv4Config;
|
||||||
use crate::pins::EthernetPins;
|
use crate::pins::EthernetPins;
|
||||||
|
|
||||||
/// Not on the stack so that stack can be placed in CCMRAM (which the
|
/// Not on the stack so that stack can be placed in CCMRAM (which the
|
||||||
|
@ -29,7 +33,7 @@ pub fn run<F>(
|
||||||
ethernet_mac: ETHERNET_MAC, ethernet_dma: ETHERNET_DMA,
|
ethernet_mac: ETHERNET_MAC, ethernet_dma: ETHERNET_DMA,
|
||||||
eth_pins: EthernetPins,
|
eth_pins: EthernetPins,
|
||||||
ethernet_addr: EthernetAddress,
|
ethernet_addr: EthernetAddress,
|
||||||
local_addr: Ipv4Address,
|
ipv4_config: Ipv4Config,
|
||||||
f: F
|
f: F
|
||||||
) where
|
) where
|
||||||
F: FnOnce(EthernetInterface<&mut stm32_eth::Eth<'static, 'static>>),
|
F: FnOnce(EthernetInterface<&mut stm32_eth::Eth<'static, 'static>>),
|
||||||
|
@ -51,15 +55,18 @@ pub fn run<F>(
|
||||||
eth_dev.enable_interrupt();
|
eth_dev.enable_interrupt();
|
||||||
|
|
||||||
// IP stack
|
// IP stack
|
||||||
// Netmask 0 means we expect any IP address on the local segment.
|
let (ipv4_cidr, gateway) = split_ipv4_config(ipv4_config);
|
||||||
// No routing.
|
let mut ip_addrs = [ipv4_cidr.into()];
|
||||||
let mut ip_addrs = [IpCidr::new(local_addr.into(), 0)];
|
|
||||||
let mut neighbor_storage = [None; 16];
|
let mut neighbor_storage = [None; 16];
|
||||||
let neighbor_cache = NeighborCache::new(&mut neighbor_storage[..]);
|
let neighbor_cache = NeighborCache::new(&mut neighbor_storage[..]);
|
||||||
|
let mut routes_storage = [None; 1];
|
||||||
|
let mut routes = Routes::new(&mut routes_storage[..]);
|
||||||
|
gateway.map(|gateway| routes.add_default_ipv4_route(gateway).unwrap());
|
||||||
let iface = EthernetInterfaceBuilder::new(&mut eth_dev)
|
let iface = EthernetInterfaceBuilder::new(&mut eth_dev)
|
||||||
.ethernet_addr(ethernet_addr)
|
.ethernet_addr(ethernet_addr)
|
||||||
.ip_addrs(&mut ip_addrs[..])
|
.ip_addrs(&mut ip_addrs[..])
|
||||||
.neighbor_cache(neighbor_cache)
|
.neighbor_cache(neighbor_cache)
|
||||||
|
.routes(routes)
|
||||||
.finalize();
|
.finalize();
|
||||||
|
|
||||||
f(iface);
|
f(iface);
|
||||||
|
@ -90,3 +97,10 @@ pub fn clear_pending(cs: &CriticalSection) {
|
||||||
*NET_PENDING.borrow(cs)
|
*NET_PENDING.borrow(cs)
|
||||||
.borrow_mut() = false;
|
.borrow_mut() = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// utility for destructuring into smoltcp types
|
||||||
|
pub fn split_ipv4_config(config: Ipv4Config) -> (Ipv4Cidr, Option<Ipv4Address>) {
|
||||||
|
let cidr = Ipv4Cidr::new(Ipv4Address(config.address), config.mask_len);
|
||||||
|
let gateway = config.gateway.map(Ipv4Address);
|
||||||
|
(cidr, gateway)
|
||||||
|
}
|
||||||
|
|
|
@ -3,9 +3,10 @@ use smoltcp::{
|
||||||
iface::EthernetInterface,
|
iface::EthernetInterface,
|
||||||
socket::{SocketSet, SocketHandle, TcpSocket, TcpSocketBuffer, SocketRef},
|
socket::{SocketSet, SocketHandle, TcpSocket, TcpSocketBuffer, SocketRef},
|
||||||
time::Instant,
|
time::Instant,
|
||||||
wire::{IpCidr, Ipv4Address, Ipv4Cidr},
|
wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr},
|
||||||
};
|
};
|
||||||
|
use crate::command_parser::Ipv4Config;
|
||||||
|
use crate::net::split_ipv4_config;
|
||||||
|
|
||||||
pub struct SocketState<S> {
|
pub struct SocketState<S> {
|
||||||
handle: SocketHandle,
|
handle: SocketHandle,
|
||||||
|
@ -85,12 +86,12 @@ impl<'a, 'b, S: Default> Server<'a, 'b, S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_ipv4_address(&mut self, ipv4_address: Ipv4Address) {
|
fn set_ipv4_address(&mut self, ipv4_address: Ipv4Cidr) {
|
||||||
self.net.update_ip_addrs(|addrs| {
|
self.net.update_ip_addrs(|addrs| {
|
||||||
for addr in addrs.iter_mut() {
|
for addr in addrs.iter_mut() {
|
||||||
match addr {
|
match addr {
|
||||||
IpCidr::Ipv4(_) => {
|
IpCidr::Ipv4(_) => {
|
||||||
*addr = IpCidr::Ipv4(Ipv4Cidr::new(ipv4_address, 0));
|
*addr = IpCidr::Ipv4(ipv4_address);
|
||||||
// done
|
// done
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -101,4 +102,23 @@ impl<'a, 'b, S: Default> Server<'a, 'b, S> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_gateway(&mut self, gateway: Option<Ipv4Address>) {
|
||||||
|
let routes = self.net.routes_mut();
|
||||||
|
match gateway {
|
||||||
|
None =>
|
||||||
|
routes.update(|routes_storage| {
|
||||||
|
routes_storage.remove(&IpCidr::new(IpAddress::v4(0, 0, 0, 0), 0));
|
||||||
|
}),
|
||||||
|
Some(gateway) => {
|
||||||
|
routes.add_default_ipv4_route(gateway).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_ipv4_config(&mut self, config: Ipv4Config) {
|
||||||
|
let (address, gateway) = split_ipv4_config(config);
|
||||||
|
self.set_ipv4_address(address);
|
||||||
|
self.set_gateway(gateway);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue