Compare commits

...

3 Commits

Author SHA1 Message Date
linuswck 7f6a385e1d Support controls from multiple TCP Socket Clients 2024-03-06 16:30:31 +08:00
linuswck eff8adc184 Update Eth Link Speed with the detected Speed
- adds support to Half/FullDuplexBase10T, HalfDuplexBase100Tx Eth Speed
- fix a bug which Kirdy requires link to up to enter main loop
2024-03-06 12:15:08 +08:00
linuswck a579e5c5d5 Add default gateway into IpSettings 2024-03-06 10:34:57 +08:00
3 changed files with 165 additions and 118 deletions

View File

@ -67,6 +67,8 @@ fn main() -> ! {
loop {
wd.feed();
net::net::eth_poll_and_update_link_speed();
match state {
State::LoadFlashSettings => {
// State Transition
@ -142,41 +144,44 @@ fn main() -> ! {
thermostat.set_pid_engaged(false);
thermostat.power_down();
}
if net::net::eth_is_socket_active() {
if device_settings.report_readings {
unsafe {
net::cmd_handler::send_status_report(&mut ETH_DATA_BUFFER, &mut laser, &mut thermostat);
net::net::for_each(|mut socket| {
if net::net::eth_is_socket_active(socket) {
if device_settings.report_readings {
unsafe {
net::cmd_handler::send_status_report(&mut ETH_DATA_BUFFER, &mut laser, &mut thermostat, &mut socket);
}
}
}
}
});
}
if net::net::eth_is_socket_active() {
cortex_m::interrupt::free(|cs|
{
eth_is_pending = net::net::is_pending(cs);
}
);
if eth_is_pending {
unsafe{
cortex_m::interrupt::free(|cs| {
net::net::clear_pending(cs);
});
let bytes = net::net::eth_recv(&mut ETH_DATA_BUFFER);
if bytes != 0 {
info!("Ts: {:?}", sys_timer::now());
debug!("Number of bytes recv: {:?}", bytes);
// State Transition
(laser, thermostat, state, device_settings) = net::cmd_handler::execute_cmd(&mut ETH_DATA_BUFFER, bytes, laser, thermostat, state, device_settings);
net::net::for_each(|mut socket| {
if net::net::eth_is_socket_active(socket) {
cortex_m::interrupt::free(|cs|
{
eth_is_pending = net::net::is_pending(cs);
}
);
if eth_is_pending {
unsafe{
cortex_m::interrupt::free(|cs| {
net::net::clear_pending(cs);
});
let bytes = net::net::eth_recv(&mut ETH_DATA_BUFFER, socket);
if bytes != 0 {
info!("Ts: {:?}", sys_timer::now());
debug!("Number of bytes recv: {:?}", bytes);
// State Transition
net::cmd_handler::execute_cmd(&mut ETH_DATA_BUFFER, bytes, &mut socket, &mut laser, &mut thermostat, &mut state, &mut device_settings);
}
}
}
if has_temp_reading {
thermostat.start_tec_readings_conversion();
}
}
if has_temp_reading {
thermostat.start_tec_readings_conversion();
}
}
});
}
State::SaveFlashSettings => {
// State Transition
@ -218,10 +223,12 @@ fn main() -> ! {
laser.power_down();
thermostat.power_down();
let mut any_socket_alive = false;
if net::net::eth_is_socket_active() {
net::net::eth_close_socket();
any_socket_alive = true;
}
net::net::for_each(|socket| {
if net::net::eth_is_socket_active(socket) {
net::net::eth_close_socket(socket);
any_socket_alive = true;
}
});
// Must let loop run for one more cycle to poll server for RST to be sent,
// this makes sure system does not reset right after socket.abort() is called.

View File

@ -20,6 +20,7 @@ use crate::thermostat::pid_state::PidSettings::*;
use crate::device::{dfu, sys_timer};
use log::info;
use crate::{DeviceSettings, State, IpSettings};
use smoltcp::iface::SocketHandle;
#[derive(Deserialize, Serialize, Copy, Clone, Default, Debug)]
enum DeviceCmd {
@ -127,7 +128,7 @@ pub struct SettingsSummaryObj {
json: SettingsSummary
}
pub fn send_settings_summary(buffer: &mut [u8], laser: &mut LdDrive, tec: &mut Thermostat){
pub fn send_settings_summary(buffer: &mut [u8], laser: &mut LdDrive, tec: &mut Thermostat, socket: &mut SocketHandle){
let settings_summary = SettingsSummaryObj {
json: SettingsSummary {
laser: laser.get_settings_summary(),
@ -135,11 +136,11 @@ pub fn send_settings_summary(buffer: &mut [u8], laser: &mut LdDrive, tec: &mut T
}
};
let num_bytes = settings_summary.get_json("/json", buffer).unwrap();
net::eth_send(buffer, num_bytes);
net::eth_send(buffer, num_bytes, *socket);
}
pub fn send_status_report(buffer: &mut [u8], laser: &mut LdDrive, tec: &mut Thermostat){
pub fn send_status_report(buffer: &mut [u8], laser: &mut LdDrive, tec: &mut Thermostat, socket: &mut SocketHandle){
let status_report = StatusReportObj {
json: StatusReport {
ts: sys_timer::now(),
@ -148,7 +149,7 @@ pub fn send_status_report(buffer: &mut [u8], laser: &mut LdDrive, tec: &mut Ther
}
};
let num_bytes = status_report.get_json("/json", buffer).unwrap();
net::eth_send(buffer, num_bytes);
net::eth_send(buffer, num_bytes, *socket);
}
// Use a minimal struct for high speed cmd ctrl to reduce processing overhead
@ -165,14 +166,14 @@ pub struct TecSetICmd {
/// Make sure kirdy's firmware is flashed with release builds.
/// The received message must contain only one json cmd. TCP client should set TCP_NODELAY or equivalent flag in its TCP Socket
/// Settings to avoid unwanted buffering on TX Data and minimize TX latency.
pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, mut laser: LdDrive, mut tec: Thermostat, mut state: State, mut device_settings: DeviceSettings)->(LdDrive, Thermostat, State, DeviceSettings){
pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, socket: &mut SocketHandle, laser: &mut LdDrive, tec: &mut Thermostat, state: &mut State, device_settings: &mut DeviceSettings){
let mut cmd = TecSetICmd {
json: TecSetICmdJson::default()
};
match cmd.set_json("/json", &buffer[0..buffer_size]){
Ok(_) => {
tec.set_i(ElectricCurrent::new::<milliampere>(cmd.json.tec_set_i));
return (laser, tec, state, device_settings);
return;
}
Err(_) => { /* Do Nothing */}
}
@ -213,19 +214,19 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, mut laser: LdDrive, mu
}
}
Some(DeviceCmd::GetStatusReport) => {
send_status_report(buffer, &mut laser, &mut tec);
send_status_report(buffer, laser, tec, socket);
}
Some(DeviceCmd::GetSettingsSummary) => {
send_settings_summary(buffer, &mut laser, &mut tec);
send_settings_summary(buffer, laser, tec, socket);
}
Some(DeviceCmd::SaveFlashSettings) => {
state = State::SaveFlashSettings;
*state = State::SaveFlashSettings;
}
Some(DeviceCmd::LoadFlashSettings) => {
state = State::LoadFlashSettings;
*state = State::LoadFlashSettings;
}
Some(DeviceCmd::HardReset) => {
state = State::HardReset;
*state = State::HardReset;
}
None => { /* Do Nothing */}
_ => {
@ -557,5 +558,4 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, mut laser: LdDrive, mu
info!("Invalid Command: {:?}", err);
}
}
(laser, tec, state, device_settings)
}

View File

@ -1,23 +1,21 @@
use crate::device::sys_timer;
use core::mem::{self, MaybeUninit};
use core::cell::RefCell;
use cortex_m::interrupt::{CriticalSection, Mutex};
use log::{debug, info};
use smoltcp::{
iface::{
self, Interface, SocketHandle, SocketSet, SocketStorage
},
socket::tcp::{State, SocketBuffer, Socket},
wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr},
time::Instant,
}, socket::tcp::{Socket, SocketBuffer, State}, time::Instant, wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}
};
use stm32_eth::{
Parts, EthPins, PartsIn,
mac::Speed,
mac::{Speed, EthernetMACWithMii},
dma::{
TxRingEntry, RxRingEntry, EthernetDMA
}};
use stm32f4xx_hal::{
gpio::{gpioa::*, gpiob::*, gpioc::*, Alternate, Input},
gpio::{gpioa::*, gpiob::*, gpioc::*, Alternate, Input, Pin},
rcc::Clocks,
interrupt,
};
@ -28,14 +26,16 @@ pub struct IpSettings {
addr: [u8; 4],
port: u16,
prefix_len: u8,
gateway: [u8; 4],
}
impl Default for IpSettings {
fn default() -> Self {
IpSettings {
addr: [192, 168, 1, 132],
addr: [192, 168, 1, 128],
port: 1337,
prefix_len: 24,
gateway: [192, 168, 1, 1]
}
}
}
@ -45,11 +45,13 @@ impl Default for IpSettings {
static NET_PENDING: Mutex<RefCell<bool>> = Mutex::new(RefCell::new(false));
pub struct ServerHandle {
socket_handle: SocketHandle,
socket_handles: [SocketHandle; NUM_OF_SOCKETS],
socket_set: SocketSet<'static>,
socket_addr: (IpAddress, u16),
iface: EthInterface,
dma: EthernetDMA<'static, 'static>,
phy: EthernetPhy<EthernetMACWithMii<Pin<'A', 2, Alternate<11>>, Pin<'C', 1, Alternate<11>>>>,
link_was_up: bool,
}
pub type EthernetPins =
EthPins<PA1<Input>, PA7<Input>, PB11<Input>, PB12<Input>, PB13<Input>, PC4<Input>, PC5<Input>>;
@ -59,26 +61,11 @@ pub struct EthernetMgmtPins {
}
pub type EthInterface = Interface;
const NUM_OF_SOCKETS : usize = 4;
const TCP_BUFFER_SIZE: usize = 2048;
static mut RX_RING: Option<[RxRingEntry; 8]> = None;
static mut TX_RING: Option<[TxRingEntry; 2]> = None;
static mut SOCKET_STORAGE: Option<[SocketStorage<'static>; 1]> = None;
static mut TCP_SOCKET_STORAGE : Option<TcpSocketStorage> = None;
#[derive(Copy, Clone)]
pub struct TcpSocketStorage {
rx_storage: [u8; 2048],
tx_storage: [u8; 2048],
}
impl TcpSocketStorage {
const fn new() -> Self {
Self {
rx_storage: [0; 2048],
tx_storage: [0; 2048],
}
}
}
static mut SOCKET_STORAGE: Option<[SocketStorage<'static>; NUM_OF_SOCKETS]> = None;
fn now_fn() -> smoltcp::time::Instant {
Instant::from_millis(i64::from(sys_timer::now()))
@ -96,8 +83,7 @@ impl ServerHandle {
) {
let rx_ring = unsafe { RX_RING.get_or_insert(Default::default()) };
let tx_ring = unsafe { TX_RING.get_or_insert(Default::default()) };
let tcp_socket_storage = unsafe { TCP_SOCKET_STORAGE.get_or_insert(TcpSocketStorage::new()) };
let socket_storage = unsafe { SOCKET_STORAGE.get_or_insert([SocketStorage::EMPTY; 1]) };
let socket_storage = unsafe { SOCKET_STORAGE.get_or_insert([SocketStorage::EMPTY; NUM_OF_SOCKETS]) };
let Parts {
mut dma,
@ -130,14 +116,10 @@ impl ServerHandle {
let mut routes = smoltcp::iface::Routes::new();
routes
.add_default_ipv4_route(Ipv4Address::new(192, 168, 1, 1))
.add_default_ipv4_route(Ipv4Address::new(ip_settings.gateway[0], ip_settings.gateway[1], ip_settings.gateway[2], ip_settings.gateway[3]))
.ok();
dma.enable_interrupt();
let rx_buffer = SocketBuffer::new(&mut tcp_socket_storage.rx_storage[..]);
let tx_buffer = SocketBuffer::new(&mut tcp_socket_storage.tx_storage[..]);
let socket = Socket::new(rx_buffer, tx_buffer);
let config = iface::Config::new(EthernetAddress::from_bytes(&mac_addr).into());
let mut iface = Interface::new(config, &mut &mut dma, smoltcp::time::Instant::ZERO);
iface.set_hardware_addr(EthernetAddress(mac_addr).into());
@ -147,20 +129,41 @@ impl ServerHandle {
addr.push(ip_init).unwrap();
});
let mut sockets = SocketSet::new(&mut socket_storage[..]);
let tcp_handle = sockets.add(socket);
let socket = sockets.get_mut::<Socket>(tcp_handle);
socket.listen(socket_addr).ok();
iface.poll(Instant::from_millis(i64::from(sys_timer::now())), &mut &mut dma, &mut sockets);
let server = ServerHandle {
socket_handle: tcp_handle,
socket_set: sockets,
socket_addr: socket_addr,
iface: iface,
dma: dma,
};
let mut socket_set = SocketSet::new(&mut socket_storage[..]);
let tcp_handles = {
// Do not use NUM_OF_SOCKETS to define array size to
// remind developers to create/remove tcp_handles accordingly after changing NUM_OF_SOCKETS
let mut tcp_handles: [MaybeUninit<SocketHandle>; 4]= unsafe {
MaybeUninit::uninit().assume_init()
};
macro_rules! create_tcp_handle {
($rx_storage:ident, $tx_storage:ident, $handle:expr) => {
static mut $rx_storage : [u8; TCP_BUFFER_SIZE] = [0; TCP_BUFFER_SIZE];
static mut $tx_storage : [u8; TCP_BUFFER_SIZE] = [0; TCP_BUFFER_SIZE];
unsafe {
let rx_buffer = SocketBuffer::new(&mut $rx_storage[..]);
let tx_buffer = SocketBuffer::new(&mut $tx_storage[..]);
$handle.write(socket_set.add(Socket::new(rx_buffer, tx_buffer)));
}
}
}
create_tcp_handle!(RX_STORAGE0, TX_STORAGE0, tcp_handles[0]);
create_tcp_handle!(RX_STORAGE1, TX_STORAGE1, tcp_handles[1]);
create_tcp_handle!(RX_STORAGE2, TX_STORAGE2, tcp_handles[2]);
create_tcp_handle!(RX_STORAGE3, TX_STORAGE3, tcp_handles[3]);
unsafe { mem::transmute::<_, [SocketHandle; 4]>(tcp_handles) }
};
for i in 0..NUM_OF_SOCKETS {
let socket = socket_set.get_mut::<Socket>(tcp_handles[i]);
socket.listen(socket_addr).ok();
}
iface.poll(Instant::from_millis(i64::from(sys_timer::now())), &mut &mut dma, &mut socket_set);
if let Ok(mut phy) = EthernetPhy::from_miim(mac, 0) {
info!(
"Resetting PHY as an extra step. Type: {}",
@ -168,38 +171,51 @@ impl ServerHandle {
);
phy.phy_init();
while !phy.phy_link_up() {}
let server = ServerHandle {
socket_handles: tcp_handles,
socket_set: socket_set,
socket_addr: socket_addr,
iface: iface,
dma: dma,
phy: phy,
link_was_up: false,
};
unsafe {
SERVER_HANDLE = Some(server);
}
} else {
panic!("Ethernet Phy is not supported");
}
}
if let Some(speed) = phy.speed().map(|s| match s {
pub fn update_link_speed(&mut self) {
if !self.link_was_up & self.phy.phy_link_up() {
if let Some(speed) = self.phy.speed().map(|s| match s {
PhySpeed::HalfDuplexBase10T => Speed::HalfDuplexBase10T,
PhySpeed::FullDuplexBase10T => Speed::FullDuplexBase10T,
PhySpeed::HalfDuplexBase100Tx => Speed::HalfDuplexBase100Tx,
PhySpeed::FullDuplexBase100Tx => Speed::FullDuplexBase100Tx,
}) {
phy.get_miim().set_speed(speed);
info!("Detected link speed: {:?}", speed);
info!("New eth link is up. Setting detected PhySpeed: {:?}", speed);
self.phy.get_miim().set_speed(speed);
} else {
debug!("Failed to detect link speed.");
}
} else {
info!("Not resetting unsupported PHY.");
}
unsafe {
SERVER_HANDLE = Some(server);
}
self.link_was_up = self.phy.phy_link_up();
}
pub fn recv(&mut self, buffer: &mut [u8])-> Result<usize, smoltcp::socket::tcp::RecvError> {
pub fn recv(&mut self, buffer: &mut [u8], socket_handles: SocketHandle)-> Result<usize, smoltcp::socket::tcp::RecvError> {
self.iface.poll(now_fn(), &mut &mut self.dma, &mut self.socket_set);
let socket = self.socket_set.get_mut::<Socket>(self.socket_handle);
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
socket.recv_slice(buffer)
}
pub fn send(&mut self, buffer: &mut [u8], num_bytes: usize) {
let socket = self.socket_set.get_mut::<Socket>(self.socket_handle);
pub fn send(&mut self, buffer: &mut [u8], num_bytes: usize, socket_handles: SocketHandle) {
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
if num_bytes > 0 {
socket.send_slice(&buffer[..num_bytes]).ok();
info!("Sent {} bytes.", num_bytes);
@ -209,8 +225,8 @@ impl ServerHandle {
self.iface.poll(now_fn(), &mut &mut self.dma, &mut self.socket_set);
}
pub fn poll_socket_status(&mut self)-> bool {
let socket = self.socket_set.get_mut::<Socket>(self.socket_handle);
pub fn poll_socket_status(&mut self, socket_handles: SocketHandle)-> bool {
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
if !socket.is_listening() && !socket.is_open() || socket.state() == State::CloseWait {
socket.abort();
socket.listen(self.socket_addr).ok();
@ -222,8 +238,8 @@ impl ServerHandle {
return true;
}
pub fn close_socket(&mut self) {
let socket = self.socket_set.get_mut::<Socket>(self.socket_handle);
pub fn close_socket(&mut self, socket_handles: SocketHandle) {
let socket = self.socket_set.get_mut::<Socket>(socket_handles);
socket.abort();
}
}
@ -330,10 +346,21 @@ impl<M: Miim> EthernetPhy<M> {
}
}
pub fn eth_send(buffer: &mut [u8], num_bytes: usize) {
pub fn eth_poll_and_update_link_speed() {
unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE {
server_handle.send(buffer, num_bytes);
server_handle.update_link_speed();
}
else {
panic!("eth_poll_and_update_link_speed is called before init");
}
}
}
pub fn eth_send(buffer: &mut [u8], num_bytes: usize, socket_handles: SocketHandle) {
unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE {
server_handle.send(buffer, num_bytes, socket_handles);
}
else {
panic!("eth_send is called before init");
@ -341,10 +368,10 @@ pub fn eth_send(buffer: &mut [u8], num_bytes: usize) {
}
}
pub fn eth_recv(buffer: &mut [u8])-> usize{
pub fn eth_recv(buffer: &mut [u8], socket_handles: SocketHandle)-> usize{
unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE {
match server_handle.recv(buffer){
match server_handle.recv(buffer, socket_handles){
Ok(recv_bytes) => {return recv_bytes}
Err(err) => {
debug!("TCP Recv Error: {}", err);
@ -358,10 +385,10 @@ pub fn eth_recv(buffer: &mut [u8])-> usize{
}
}
pub fn eth_is_socket_active() -> bool {
pub fn eth_is_socket_active(socket_handles: SocketHandle) -> bool {
unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE {
server_handle.poll_socket_status()
server_handle.poll_socket_status(socket_handles)
}
else {
panic!("eth_is_socket_active is called before init");
@ -369,10 +396,23 @@ pub fn eth_is_socket_active() -> bool {
}
}
pub fn eth_close_socket() {
pub fn eth_close_socket(socket_handles: SocketHandle) {
unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE {
server_handle.close_socket()
server_handle.close_socket(socket_handles)
}
else {
panic!("eth_close_socket is called before init");
}
}
}
pub fn for_each<F: FnMut(SocketHandle)>(mut callback: F) {
unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE {
for i in 0..NUM_OF_SOCKETS {
callback(server_handle.socket_handles[i]);
}
}
else {
panic!("eth_close_socket is called before init");