1
0
forked from M-Labs/kirdy

Support controls from multiple TCP Socket Clients

This commit is contained in:
linuswck 2024-03-06 16:29:02 +08:00
parent eff8adc184
commit 7f6a385e1d
3 changed files with 123 additions and 98 deletions

View File

@ -144,41 +144,44 @@ fn main() -> ! {
thermostat.set_pid_engaged(false); thermostat.set_pid_engaged(false);
thermostat.power_down(); thermostat.power_down();
} }
if net::net::eth_is_socket_active() { net::net::for_each(|mut socket| {
if device_settings.report_readings { if net::net::eth_is_socket_active(socket) {
unsafe { if device_settings.report_readings {
net::cmd_handler::send_status_report(&mut ETH_DATA_BUFFER, &mut laser, &mut thermostat); unsafe {
net::cmd_handler::send_status_report(&mut ETH_DATA_BUFFER, &mut laser, &mut thermostat, &mut socket);
}
} }
} }
} });
} }
net::net::for_each(|mut socket| {
if net::net::eth_is_socket_active() { if net::net::eth_is_socket_active(socket) {
cortex_m::interrupt::free(|cs| cortex_m::interrupt::free(|cs|
{ {
eth_is_pending = net::net::is_pending(cs); eth_is_pending = net::net::is_pending(cs);
} }
); );
if eth_is_pending { if eth_is_pending {
unsafe{ unsafe{
cortex_m::interrupt::free(|cs| { cortex_m::interrupt::free(|cs| {
net::net::clear_pending(cs); net::net::clear_pending(cs);
}); });
let bytes = net::net::eth_recv(&mut ETH_DATA_BUFFER); let bytes = net::net::eth_recv(&mut ETH_DATA_BUFFER, socket);
if bytes != 0 { if bytes != 0 {
info!("Ts: {:?}", sys_timer::now()); info!("Ts: {:?}", sys_timer::now());
debug!("Number of bytes recv: {:?}", bytes); debug!("Number of bytes recv: {:?}", bytes);
// State Transition // State Transition
(laser, thermostat, state, device_settings) = net::cmd_handler::execute_cmd(&mut ETH_DATA_BUFFER, bytes, laser, thermostat, state, device_settings); 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::SaveFlashSettings => {
// State Transition // State Transition
@ -220,10 +223,12 @@ fn main() -> ! {
laser.power_down(); laser.power_down();
thermostat.power_down(); thermostat.power_down();
let mut any_socket_alive = false; let mut any_socket_alive = false;
if net::net::eth_is_socket_active() { net::net::for_each(|socket| {
net::net::eth_close_socket(); if net::net::eth_is_socket_active(socket) {
any_socket_alive = true; 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, // 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. // 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 crate::device::{dfu, sys_timer};
use log::info; use log::info;
use crate::{DeviceSettings, State, IpSettings}; use crate::{DeviceSettings, State, IpSettings};
use smoltcp::iface::SocketHandle;
#[derive(Deserialize, Serialize, Copy, Clone, Default, Debug)] #[derive(Deserialize, Serialize, Copy, Clone, Default, Debug)]
enum DeviceCmd { enum DeviceCmd {
@ -127,7 +128,7 @@ pub struct SettingsSummaryObj {
json: SettingsSummary 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 { let settings_summary = SettingsSummaryObj {
json: SettingsSummary { json: SettingsSummary {
laser: laser.get_settings_summary(), 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(); 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 { let status_report = StatusReportObj {
json: StatusReport { json: StatusReport {
ts: sys_timer::now(), 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(); 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 // 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. /// 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 /// 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. /// 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 { let mut cmd = TecSetICmd {
json: TecSetICmdJson::default() json: TecSetICmdJson::default()
}; };
match cmd.set_json("/json", &buffer[0..buffer_size]){ match cmd.set_json("/json", &buffer[0..buffer_size]){
Ok(_) => { Ok(_) => {
tec.set_i(ElectricCurrent::new::<milliampere>(cmd.json.tec_set_i)); tec.set_i(ElectricCurrent::new::<milliampere>(cmd.json.tec_set_i));
return (laser, tec, state, device_settings); return;
} }
Err(_) => { /* Do Nothing */} Err(_) => { /* Do Nothing */}
} }
@ -213,19 +214,19 @@ pub fn execute_cmd(buffer: &mut [u8], buffer_size: usize, mut laser: LdDrive, mu
} }
} }
Some(DeviceCmd::GetStatusReport) => { Some(DeviceCmd::GetStatusReport) => {
send_status_report(buffer, &mut laser, &mut tec); send_status_report(buffer, laser, tec, socket);
} }
Some(DeviceCmd::GetSettingsSummary) => { Some(DeviceCmd::GetSettingsSummary) => {
send_settings_summary(buffer, &mut laser, &mut tec); send_settings_summary(buffer, laser, tec, socket);
} }
Some(DeviceCmd::SaveFlashSettings) => { Some(DeviceCmd::SaveFlashSettings) => {
state = State::SaveFlashSettings; *state = State::SaveFlashSettings;
} }
Some(DeviceCmd::LoadFlashSettings) => { Some(DeviceCmd::LoadFlashSettings) => {
state = State::LoadFlashSettings; *state = State::LoadFlashSettings;
} }
Some(DeviceCmd::HardReset) => { Some(DeviceCmd::HardReset) => {
state = State::HardReset; *state = State::HardReset;
} }
None => { /* Do Nothing */} 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); info!("Invalid Command: {:?}", err);
} }
} }
(laser, tec, state, device_settings)
} }

View File

@ -1,14 +1,12 @@
use crate::device::sys_timer; use crate::device::sys_timer;
use core::mem::{self, MaybeUninit};
use core::cell::RefCell; use core::cell::RefCell;
use cortex_m::interrupt::{CriticalSection, Mutex}; use cortex_m::interrupt::{CriticalSection, Mutex};
use log::{debug, info}; use log::{debug, info};
use smoltcp::{ use smoltcp::{
iface::{ iface::{
self, Interface, SocketHandle, SocketSet, SocketStorage self, Interface, SocketHandle, SocketSet, SocketStorage
}, }, socket::tcp::{Socket, SocketBuffer, State}, time::Instant, wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr}
socket::tcp::{State, SocketBuffer, Socket},
wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr},
time::Instant,
}; };
use stm32_eth::{ use stm32_eth::{
Parts, EthPins, PartsIn, Parts, EthPins, PartsIn,
@ -34,7 +32,7 @@ pub struct IpSettings {
impl Default for IpSettings { impl Default for IpSettings {
fn default() -> Self { fn default() -> Self {
IpSettings { IpSettings {
addr: [192, 168, 1, 132], addr: [192, 168, 1, 128],
port: 1337, port: 1337,
prefix_len: 24, prefix_len: 24,
gateway: [192, 168, 1, 1] gateway: [192, 168, 1, 1]
@ -47,7 +45,7 @@ impl Default for IpSettings {
static NET_PENDING: Mutex<RefCell<bool>> = Mutex::new(RefCell::new(false)); static NET_PENDING: Mutex<RefCell<bool>> = Mutex::new(RefCell::new(false));
pub struct ServerHandle { pub struct ServerHandle {
socket_handle: SocketHandle, socket_handles: [SocketHandle; NUM_OF_SOCKETS],
socket_set: SocketSet<'static>, socket_set: SocketSet<'static>,
socket_addr: (IpAddress, u16), socket_addr: (IpAddress, u16),
iface: EthInterface, iface: EthInterface,
@ -63,26 +61,11 @@ pub struct EthernetMgmtPins {
} }
pub type EthInterface = Interface; 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 RX_RING: Option<[RxRingEntry; 8]> = None;
static mut TX_RING: Option<[TxRingEntry; 2]> = None; static mut TX_RING: Option<[TxRingEntry; 2]> = None;
static mut SOCKET_STORAGE: Option<[SocketStorage<'static>; 1]> = None; static mut SOCKET_STORAGE: Option<[SocketStorage<'static>; NUM_OF_SOCKETS]> = 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],
}
}
}
fn now_fn() -> smoltcp::time::Instant { fn now_fn() -> smoltcp::time::Instant {
Instant::from_millis(i64::from(sys_timer::now())) Instant::from_millis(i64::from(sys_timer::now()))
@ -100,8 +83,7 @@ impl ServerHandle {
) { ) {
let rx_ring = unsafe { RX_RING.get_or_insert(Default::default()) }; let rx_ring = unsafe { RX_RING.get_or_insert(Default::default()) };
let tx_ring = unsafe { TX_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; NUM_OF_SOCKETS]) };
let socket_storage = unsafe { SOCKET_STORAGE.get_or_insert([SocketStorage::EMPTY; 1]) };
let Parts { let Parts {
mut dma, mut dma,
@ -138,10 +120,6 @@ impl ServerHandle {
.ok(); .ok();
dma.enable_interrupt(); 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 config = iface::Config::new(EthernetAddress::from_bytes(&mac_addr).into());
let mut iface = Interface::new(config, &mut &mut dma, smoltcp::time::Instant::ZERO); let mut iface = Interface::new(config, &mut &mut dma, smoltcp::time::Instant::ZERO);
iface.set_hardware_addr(EthernetAddress(mac_addr).into()); iface.set_hardware_addr(EthernetAddress(mac_addr).into());
@ -151,11 +129,40 @@ impl ServerHandle {
addr.push(ip_init).unwrap(); addr.push(ip_init).unwrap();
}); });
let mut sockets = SocketSet::new(&mut socket_storage[..]); let mut socket_set = SocketSet::new(&mut socket_storage[..]);
let tcp_handle = sockets.add(socket);
let socket = sockets.get_mut::<Socket>(tcp_handle); let tcp_handles = {
socket.listen(socket_addr).ok(); // Do not use NUM_OF_SOCKETS to define array size to
iface.poll(Instant::from_millis(i64::from(sys_timer::now())), &mut &mut dma, &mut sockets); // 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) { if let Ok(mut phy) = EthernetPhy::from_miim(mac, 0) {
info!( info!(
@ -166,8 +173,8 @@ impl ServerHandle {
phy.phy_init(); phy.phy_init();
let server = ServerHandle { let server = ServerHandle {
socket_handle: tcp_handle, socket_handles: tcp_handles,
socket_set: sockets, socket_set: socket_set,
socket_addr: socket_addr, socket_addr: socket_addr,
iface: iface, iface: iface,
dma: dma, dma: dma,
@ -200,15 +207,15 @@ impl ServerHandle {
self.link_was_up = self.phy.phy_link_up(); 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); 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) socket.recv_slice(buffer)
} }
pub fn send(&mut self, buffer: &mut [u8], num_bytes: usize) { pub fn send(&mut self, buffer: &mut [u8], num_bytes: usize, socket_handles: SocketHandle) {
let socket = self.socket_set.get_mut::<Socket>(self.socket_handle); let socket = self.socket_set.get_mut::<Socket>(socket_handles);
if num_bytes > 0 { if num_bytes > 0 {
socket.send_slice(&buffer[..num_bytes]).ok(); socket.send_slice(&buffer[..num_bytes]).ok();
info!("Sent {} bytes.", num_bytes); info!("Sent {} bytes.", num_bytes);
@ -218,8 +225,8 @@ impl ServerHandle {
self.iface.poll(now_fn(), &mut &mut self.dma, &mut self.socket_set); self.iface.poll(now_fn(), &mut &mut self.dma, &mut self.socket_set);
} }
pub fn poll_socket_status(&mut self)-> bool { pub fn poll_socket_status(&mut self, socket_handles: SocketHandle)-> bool {
let socket = self.socket_set.get_mut::<Socket>(self.socket_handle); let socket = self.socket_set.get_mut::<Socket>(socket_handles);
if !socket.is_listening() && !socket.is_open() || socket.state() == State::CloseWait { if !socket.is_listening() && !socket.is_open() || socket.state() == State::CloseWait {
socket.abort(); socket.abort();
socket.listen(self.socket_addr).ok(); socket.listen(self.socket_addr).ok();
@ -231,8 +238,8 @@ impl ServerHandle {
return true; return true;
} }
pub fn close_socket(&mut self) { pub fn close_socket(&mut self, socket_handles: SocketHandle) {
let socket = self.socket_set.get_mut::<Socket>(self.socket_handle); let socket = self.socket_set.get_mut::<Socket>(socket_handles);
socket.abort(); socket.abort();
} }
} }
@ -350,10 +357,10 @@ pub fn eth_poll_and_update_link_speed() {
} }
} }
pub fn eth_send(buffer: &mut [u8], num_bytes: usize) { pub fn eth_send(buffer: &mut [u8], num_bytes: usize, socket_handles: SocketHandle) {
unsafe { unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE { if let Some(ref mut server_handle ) = SERVER_HANDLE {
server_handle.send(buffer, num_bytes); server_handle.send(buffer, num_bytes, socket_handles);
} }
else { else {
panic!("eth_send is called before init"); panic!("eth_send is called before init");
@ -361,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 { unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE { 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} Ok(recv_bytes) => {return recv_bytes}
Err(err) => { Err(err) => {
debug!("TCP Recv Error: {}", err); debug!("TCP Recv Error: {}", err);
@ -378,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 { unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE { if let Some(ref mut server_handle ) = SERVER_HANDLE {
server_handle.poll_socket_status() server_handle.poll_socket_status(socket_handles)
} }
else { else {
panic!("eth_is_socket_active is called before init"); panic!("eth_is_socket_active is called before init");
@ -389,10 +396,23 @@ pub fn eth_is_socket_active() -> bool {
} }
} }
pub fn eth_close_socket() { pub fn eth_close_socket(socket_handles: SocketHandle) {
unsafe { unsafe {
if let Some(ref mut server_handle ) = SERVER_HANDLE { 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 { else {
panic!("eth_close_socket is called before init"); panic!("eth_close_socket is called before init");