mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-08 04:56:43 +00:00
simple end-to-end demo of receiving UDP packets asynchronously
This commit is contained in:
parent
e6643e725d
commit
a8c6e8047f
8 changed files with 153 additions and 15 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -2010,6 +2010,7 @@ dependencies = [
|
|||
"llio",
|
||||
"log",
|
||||
"log-server",
|
||||
"net",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"oqc-test",
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ impl From<IpAddress> for NetIpAddr {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) const UDP_RESPONSE_MAX_LEN: usize = 1800;
|
||||
/// The data field for a UDP response is limited to less than the theoretical
|
||||
/// size of 64k. While UDP allows for a 64k packet, it seems no protoctols
|
||||
/// in practice utilize such a length (about 512 bytes is the biggest), due
|
||||
|
|
@ -84,7 +85,7 @@ pub(crate) struct NetUdpResponse {
|
|||
pub endpoint_ip_addr: NetIpAddr,
|
||||
pub len: u16,
|
||||
pub endpoint_port: u16,
|
||||
pub data: [u8; 1800],
|
||||
pub data: [u8; UDP_RESPONSE_MAX_LEN],
|
||||
}
|
||||
|
||||
#[derive(Debug, Archive, Serialize, Deserialize, Copy, Clone)]
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ pub struct UdpSocket{
|
|||
|
||||
// next steps: build this stub, and figure out how to clean up the error handling code.
|
||||
impl UdpSocket {
|
||||
pub fn bind(maybe_socket: Result<&SocketAddr>, max_payload: Option<u16>) -> Result<UdpSocket> {
|
||||
let socket = maybe_socket?;
|
||||
pub fn bind(socket: SocketAddr, max_payload: Option<u16>) -> Result<UdpSocket> {
|
||||
//let socket = maybe_socket.unwrap();
|
||||
let xns = xous_names::XousNames::new().unwrap();
|
||||
let net = NetConn::new(&xns).unwrap();
|
||||
let cb_sid = xous::create_server().unwrap();
|
||||
|
|
@ -76,8 +76,8 @@ impl UdpSocket {
|
|||
endpoint,
|
||||
data: Vec::new(),
|
||||
};
|
||||
for (&src, dst) in incoming.data.iter().zip(rx.data.iter_mut()) {
|
||||
*dst = src;
|
||||
for &d in incoming.data[..incoming.len as usize].iter() {
|
||||
rx.data.push(d);
|
||||
}
|
||||
rx_buf.lock().unwrap().push(rx);
|
||||
notify.lock().unwrap().notify(); // this will only notify if a destination has been set
|
||||
|
|
@ -96,7 +96,7 @@ impl UdpSocket {
|
|||
});
|
||||
|
||||
let request = NetUdpBind {
|
||||
ip_addr: NetIpAddr::from(*socket),
|
||||
ip_addr: NetIpAddr::from(socket),
|
||||
port: socket.port(),
|
||||
cb_sid: cb_sid.to_array(),
|
||||
max_payload,
|
||||
|
|
@ -110,7 +110,7 @@ impl UdpSocket {
|
|||
Ok(UdpSocket {
|
||||
net,
|
||||
cb_sid,
|
||||
socket_addr: *socket,
|
||||
socket_addr: socket,
|
||||
rx_buf,
|
||||
handle: Some(handle),
|
||||
notify,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use num_traits::*;
|
|||
|
||||
pub mod backend;
|
||||
pub use backend::*;
|
||||
pub use smoltcp::time::Duration;
|
||||
|
||||
/// NetConn is a crate-level structure that just counts the number of connections from this process to
|
||||
/// the Net server. It's not mean to be created by user-facing code, so the visibility is (crate).
|
||||
|
|
|
|||
|
|
@ -97,6 +97,11 @@ enum WaitOp {
|
|||
Quit,
|
||||
}
|
||||
|
||||
pub struct UdpState {
|
||||
handle: SocketHandle,
|
||||
cid: xous::CID,
|
||||
}
|
||||
|
||||
#[xous::xous_main]
|
||||
fn xmain() -> ! {
|
||||
log_server::init_wait().unwrap();
|
||||
|
|
@ -170,7 +175,7 @@ fn xmain() -> ! {
|
|||
let mut net_config: Option<Ipv4Conf> = None;
|
||||
|
||||
// ping-specific storage
|
||||
let ping_remote_addr = IpAddress::from_str("10.0.245.243").expect("invalid address format");
|
||||
let ping_remote_addr = IpAddress::from_str("10.0.245.1").expect("invalid address format");
|
||||
|
||||
let icmp_rx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::EMPTY], vec![0; 256]);
|
||||
let icmp_tx_buffer = IcmpSocketBuffer::new(vec![IcmpPacketMetadata::EMPTY], vec![0; 256]);
|
||||
|
|
@ -178,7 +183,7 @@ fn xmain() -> ! {
|
|||
|
||||
let mut sockets = SocketSet::new(vec![]);
|
||||
let icmp_handle = sockets.add(icmp_socket);
|
||||
let mut udp_handles = HashMap::<u16, SocketHandle>::new();
|
||||
let mut udp_handles = HashMap::<u16, UdpState>::new();
|
||||
|
||||
let mut send_at = Instant::from_millis(0);
|
||||
let mut seq_no = 0;
|
||||
|
|
@ -236,7 +241,11 @@ fn xmain() -> ! {
|
|||
let mut udp_socket = UdpSocket::new(udp_rx_buffer, udp_tx_buffer);
|
||||
match udp_socket.bind(udpspec.port) {
|
||||
Ok(_) => {
|
||||
udp_handles.insert(udpspec.port, sockets.add(udp_socket));
|
||||
let udpstate = UdpState {
|
||||
handle: sockets.add(udp_socket),
|
||||
cid: xous::connect(xous::SID::from_array(udpspec.cb_sid)).unwrap(),
|
||||
};
|
||||
udp_handles.insert(udpspec.port, udpstate);
|
||||
buf.replace(NetMemResponse::Ok).unwrap();
|
||||
}
|
||||
Err(e) => {
|
||||
|
|
@ -250,8 +259,8 @@ fn xmain() -> ! {
|
|||
let mut buf = unsafe{Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap())};
|
||||
let udpspec = buf.to_original::<NetUdpBind, _>().unwrap();
|
||||
match udp_handles.remove(&udpspec.port) {
|
||||
Some(handle) => {
|
||||
sockets.get::<UdpSocket>(handle).close();
|
||||
Some(udpstate) => {
|
||||
sockets.get::<UdpSocket>(udpstate.handle).close();
|
||||
buf.replace(NetMemResponse::Ok).unwrap()
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -358,7 +367,8 @@ fn xmain() -> ! {
|
|||
}
|
||||
|
||||
{
|
||||
for (port, &handle) in udp_handles.iter() {
|
||||
for (port, udpstate) in udp_handles.iter() {
|
||||
let handle = udpstate.handle;
|
||||
let mut socket = sockets.get::<UdpSocket>(handle);
|
||||
match socket.recv() {
|
||||
Ok((data, endpoint)) => {
|
||||
|
|
@ -369,8 +379,17 @@ fn xmain() -> ! {
|
|||
endpoint
|
||||
);
|
||||
// return the data/endpoint tuple to the caller
|
||||
// TODO
|
||||
|
||||
let mut response = NetUdpResponse {
|
||||
endpoint_ip_addr: NetIpAddr::from(endpoint.addr),
|
||||
len: data.len() as u16,
|
||||
endpoint_port: endpoint.port,
|
||||
data: [0; UDP_RESPONSE_MAX_LEN],
|
||||
};
|
||||
for (&src, dst) in data.iter().zip(response.data.iter_mut()) {
|
||||
*dst = src;
|
||||
}
|
||||
let buf = Buffer::into_buf(response).expect("couldn't convert UDP response to memory message");
|
||||
buf.send(udpstate.cid, NetUdpCallback::RxData.to_u32().unwrap()).expect("couldn't send UDP response");
|
||||
}
|
||||
Err(_) => {
|
||||
// do nothing
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ engine-25519 = {path="../engine-25519"}
|
|||
spinor = {path="../spinor"}
|
||||
root-keys = {path="../root-keys"}
|
||||
jtag = {path="../jtag"}
|
||||
net = {path="../net"}
|
||||
|
||||
trng = {path = "../trng"}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ mod memtest; use memtest::*;
|
|||
mod keys; use keys::*;
|
||||
mod wlan; use wlan::*;
|
||||
mod jtag_cmd; use jtag_cmd::*;
|
||||
mod net_cmd; use net_cmd::*;
|
||||
|
||||
//mod fcc; use fcc::*;
|
||||
//mod pds; // dependency of the FCC file
|
||||
|
|
@ -124,6 +125,7 @@ pub struct CmdEnv {
|
|||
memtest_cmd: Memtest,
|
||||
keys_cmd: Keys,
|
||||
jtag_cmd: JtagCmd,
|
||||
net_cmd: NetCmd,
|
||||
|
||||
//fcc_cmd: Fcc,
|
||||
}
|
||||
|
|
@ -176,6 +178,7 @@ impl CmdEnv {
|
|||
memtest_cmd: memtest,
|
||||
keys_cmd: Keys::new(&xns),
|
||||
jtag_cmd: JtagCmd::new(&xns),
|
||||
net_cmd: NetCmd::new(&xns),
|
||||
|
||||
//fcc_cmd: fcc,
|
||||
}
|
||||
|
|
@ -214,6 +217,7 @@ impl CmdEnv {
|
|||
&mut self.keys_cmd,
|
||||
&mut wlan_cmd,
|
||||
&mut self.jtag_cmd,
|
||||
&mut self.net_cmd,
|
||||
|
||||
//&mut self.fcc_cmd,
|
||||
];
|
||||
|
|
|
|||
111
services/shellchat/src/cmds/net_cmd.rs
Normal file
111
services/shellchat/src/cmds/net_cmd.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
use crate::{ShellCmdApi, CommonEnv};
|
||||
use xous_ipc::String;
|
||||
use net::Duration;
|
||||
use xous::MessageEnvelope;
|
||||
use num_traits::*;
|
||||
use std::net::ToSocketAddrs;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NetCmd {
|
||||
udp: Option<net::UdpSocket>,
|
||||
callback_id: Option<u32>,
|
||||
callback_conn: u32,
|
||||
}
|
||||
impl NetCmd {
|
||||
pub fn new(xns: &xous_names::XousNames) -> Self {
|
||||
NetCmd {
|
||||
udp: None,
|
||||
callback_id: None,
|
||||
callback_conn: xns.request_connection_blocking(crate::SERVER_NAME_SHELLCHAT).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, num_derive::FromPrimitive, num_derive::ToPrimitive)]
|
||||
pub(crate) enum NetCmdDispatch {
|
||||
UdpTest1,
|
||||
}
|
||||
|
||||
pub const UDP_TEST_SIZE: usize = 64;
|
||||
impl<'a> ShellCmdApi<'a> for NetCmd {
|
||||
cmd_api!(net); // inserts boilerplate for command API
|
||||
|
||||
fn process(&mut self, args: String::<1024>, env: &mut CommonEnv) -> Result<Option<String::<1024>>, xous::Error> {
|
||||
if self.callback_id.is_none() {
|
||||
let cb_id = env.register_handler(String::<256>::from_str(self.verb()));
|
||||
log::info!("hooking net callback with ID {}", cb_id);
|
||||
self.callback_id = Some(cb_id);
|
||||
}
|
||||
|
||||
use core::fmt::Write;
|
||||
let mut ret = String::<1024>::new();
|
||||
let helpstring = "net [udp]";
|
||||
|
||||
let mut tokens = args.as_str().unwrap().split(' ');
|
||||
|
||||
if let Some(sub_cmd) = tokens.next() {
|
||||
match sub_cmd {
|
||||
"udp" => {
|
||||
if self.udp.is_none() {
|
||||
let mut udp = net::UdpSocket::bind(
|
||||
"127.0.0.1:6969".to_socket_addrs().unwrap().into_iter().next().unwrap(),
|
||||
Some(UDP_TEST_SIZE as u16)
|
||||
).unwrap();
|
||||
udp.set_read_timeout(Some(Duration::from_millis(1000))).unwrap();
|
||||
udp.set_scalar_notification(
|
||||
self.callback_conn,
|
||||
self.callback_id.unwrap() as usize, // this is guaranteed in the prelude
|
||||
[Some(NetCmdDispatch::UdpTest1.to_usize().unwrap()), None, None, None]
|
||||
);
|
||||
self.udp = Some(udp);
|
||||
write!(ret, "Created UDP socket listener on port 6969").unwrap();
|
||||
} else {
|
||||
write!(ret, "Socket listener already installed on 6969").unwrap();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
write!(ret, "{}", helpstring).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
write!(ret, "{}", helpstring).unwrap();
|
||||
}
|
||||
Ok(Some(ret))
|
||||
}
|
||||
|
||||
|
||||
fn callback(&mut self, msg: &MessageEnvelope, _env: &mut CommonEnv) -> Result<Option<String::<1024>>, xous::Error> {
|
||||
use core::fmt::Write;
|
||||
|
||||
log::info!("net callback");
|
||||
let mut ret = String::<1024>::new();
|
||||
xous::msg_scalar_unpack!(msg, dispatch, _, _, _, {
|
||||
match FromPrimitive::from_usize(dispatch) {
|
||||
Some(NetCmdDispatch::UdpTest1) => {
|
||||
if let Some(udp_socket) = &self.udp {
|
||||
let mut pkt: [u8; UDP_TEST_SIZE] = [0; UDP_TEST_SIZE];
|
||||
match udp_socket.recv_from(&mut pkt) {
|
||||
Ok((len, addr)) => {
|
||||
write!(ret, "UDP received {} bytes: {:?}: {}", len, addr, std::str::from_utf8(&pkt[..len]).unwrap()).unwrap();
|
||||
log::info!("UDP received {} bytes: {:?}: {:?}", len, addr, &pkt[..len]);
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Net UDP error: {:?}", e);
|
||||
write!(ret, "UDP receive error: {:?}", e).unwrap();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::error!("Got NetCmd callback from uninitialized socket");
|
||||
write!(ret, "Got NetCmd callback from uninitialized socket").unwrap();
|
||||
}
|
||||
}
|
||||
None => {
|
||||
log::error!("NetCmd callback with unrecognized dispatch ID");
|
||||
write!(ret, "NetCmd callback with unrecognized dispatch ID").unwrap();
|
||||
}
|
||||
}
|
||||
});
|
||||
Ok(Some(ret))
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue