diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-05-23 03:50:43 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-05-25 19:56:22 +0200 |
| commit | a5aea995a802fea8fc1b3e4b5fe47bd6d1fca2a4 (patch) | |
| tree | 0fcb4c01914347eff5b3be44b284aa9432e28678 /embassy-net/src/stack.rs | |
| parent | 36a1f203648dcb402727ea3eb5d30cf1f6993795 (diff) | |
WIP embassy-net v2
Diffstat (limited to 'embassy-net/src/stack.rs')
| -rw-r--r-- | embassy-net/src/stack.rs | 393 |
1 files changed, 226 insertions, 167 deletions
diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs index 9461f832f..e28370df8 100644 --- a/embassy-net/src/stack.rs +++ b/embassy-net/src/stack.rs | |||
| @@ -1,13 +1,18 @@ | |||
| 1 | use core::cell::RefCell; | 1 | use core::cell::UnsafeCell; |
| 2 | use core::future::Future; | 2 | use core::future::Future; |
| 3 | use core::task::Context; | 3 | use core::task::Context; |
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | use embassy::blocking_mutex::ThreadModeMutex; | ||
| 6 | use embassy::time::{Instant, Timer}; | 5 | use embassy::time::{Instant, Timer}; |
| 7 | use embassy::waitqueue::WakerRegistration; | 6 | use embassy::waitqueue::WakerRegistration; |
| 7 | use futures::future::poll_fn; | ||
| 8 | use futures::pin_mut; | 8 | use futures::pin_mut; |
| 9 | use smoltcp::iface::InterfaceBuilder; | 9 | use heapless::Vec; |
| 10 | use smoltcp::iface::SocketStorage; | 10 | #[cfg(feature = "dhcpv4")] |
| 11 | use smoltcp::iface::SocketHandle; | ||
| 12 | use smoltcp::iface::{Interface, InterfaceBuilder}; | ||
| 13 | use smoltcp::iface::{SocketSet, SocketStorage}; | ||
| 14 | #[cfg(feature = "dhcpv4")] | ||
| 15 | use smoltcp::socket::dhcpv4; | ||
| 11 | use smoltcp::time::Instant as SmolInstant; | 16 | use smoltcp::time::Instant as SmolInstant; |
| 12 | use smoltcp::wire::{IpCidr, Ipv4Address, Ipv4Cidr}; | 17 | use smoltcp::wire::{IpCidr, Ipv4Address, Ipv4Cidr}; |
| 13 | 18 | ||
| @@ -18,10 +23,7 @@ use smoltcp::phy::{Device as _, Medium}; | |||
| 18 | #[cfg(feature = "medium-ethernet")] | 23 | #[cfg(feature = "medium-ethernet")] |
| 19 | use smoltcp::wire::{EthernetAddress, HardwareAddress, IpAddress}; | 24 | use smoltcp::wire::{EthernetAddress, HardwareAddress, IpAddress}; |
| 20 | 25 | ||
| 21 | use crate::config::Configurator; | ||
| 22 | use crate::config::Event; | ||
| 23 | use crate::device::{Device, DeviceAdapter, LinkState}; | 26 | use crate::device::{Device, DeviceAdapter, LinkState}; |
| 24 | use crate::{Config, Interface}; | ||
| 25 | 27 | ||
| 26 | const LOCAL_PORT_MIN: u16 = 1025; | 28 | const LOCAL_PORT_MIN: u16 = 1025; |
| 27 | const LOCAL_PORT_MAX: u16 = 65535; | 29 | const LOCAL_PORT_MAX: u16 = 65535; |
| @@ -51,24 +53,144 @@ impl<const ADDR: usize, const SOCK: usize, const NEIGHBOR: usize> | |||
| 51 | } | 53 | } |
| 52 | } | 54 | } |
| 53 | 55 | ||
| 54 | static STACK: ThreadModeMutex<RefCell<Option<Stack>>> = ThreadModeMutex::new(RefCell::new(None)); | 56 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 57 | pub struct Config { | ||
| 58 | pub address: Ipv4Cidr, | ||
| 59 | pub gateway: Option<Ipv4Address>, | ||
| 60 | pub dns_servers: Vec<Ipv4Address, 3>, | ||
| 61 | } | ||
| 62 | |||
| 63 | pub enum ConfigStrategy { | ||
| 64 | Static(Config), | ||
| 65 | #[cfg(feature = "dhcpv4")] | ||
| 66 | Dhcp, | ||
| 67 | } | ||
| 55 | 68 | ||
| 56 | pub(crate) struct Stack { | 69 | pub struct Stack<D: Device> { |
| 57 | pub iface: Interface, | 70 | pub(crate) socket: UnsafeCell<SocketStack>, |
| 71 | inner: UnsafeCell<Inner<D>>, | ||
| 72 | } | ||
| 73 | |||
| 74 | struct Inner<D: Device> { | ||
| 75 | device: DeviceAdapter<D>, | ||
| 58 | link_up: bool, | 76 | link_up: bool, |
| 59 | config: Option<Config>, | 77 | config: Option<Config>, |
| 78 | #[cfg(feature = "dhcpv4")] | ||
| 79 | dhcp_socket: Option<SocketHandle>, | ||
| 80 | } | ||
| 81 | |||
| 82 | pub(crate) struct SocketStack { | ||
| 83 | pub(crate) sockets: SocketSet<'static>, | ||
| 84 | pub(crate) iface: Interface<'static>, | ||
| 85 | pub(crate) waker: WakerRegistration, | ||
| 60 | next_local_port: u16, | 86 | next_local_port: u16, |
| 61 | configurator: &'static mut dyn Configurator, | ||
| 62 | waker: WakerRegistration, | ||
| 63 | } | 87 | } |
| 64 | 88 | ||
| 65 | impl Stack { | 89 | unsafe impl<D: Device> Send for Stack<D> {} |
| 66 | pub(crate) fn with<R>(f: impl FnOnce(&mut Stack) -> R) -> R { | 90 | |
| 67 | let mut stack = STACK.borrow().borrow_mut(); | 91 | impl<D: Device + 'static> Stack<D> { |
| 68 | let stack = stack.as_mut().unwrap(); | 92 | pub fn new<const ADDR: usize, const SOCK: usize, const NEIGH: usize>( |
| 69 | f(stack) | 93 | device: D, |
| 94 | config: ConfigStrategy, | ||
| 95 | resources: &'static mut StackResources<ADDR, SOCK, NEIGH>, | ||
| 96 | random_seed: u64, | ||
| 97 | ) -> Self { | ||
| 98 | #[cfg(feature = "medium-ethernet")] | ||
| 99 | let medium = device.capabilities().medium; | ||
| 100 | |||
| 101 | #[cfg(feature = "medium-ethernet")] | ||
| 102 | let ethernet_addr = if medium == Medium::Ethernet { | ||
| 103 | device.ethernet_address() | ||
| 104 | } else { | ||
| 105 | [0, 0, 0, 0, 0, 0] | ||
| 106 | }; | ||
| 107 | |||
| 108 | let mut device = DeviceAdapter::new(device); | ||
| 109 | |||
| 110 | let mut b = InterfaceBuilder::new(); | ||
| 111 | b = b.ip_addrs(&mut resources.addresses[..]); | ||
| 112 | b = b.random_seed(random_seed); | ||
| 113 | |||
| 114 | #[cfg(feature = "medium-ethernet")] | ||
| 115 | if medium == Medium::Ethernet { | ||
| 116 | b = b.hardware_addr(HardwareAddress::Ethernet(EthernetAddress(ethernet_addr))); | ||
| 117 | b = b.neighbor_cache(NeighborCache::new(&mut resources.neighbor_cache[..])); | ||
| 118 | b = b.routes(Routes::new(&mut resources.routes[..])); | ||
| 119 | } | ||
| 120 | |||
| 121 | let iface = b.finalize(&mut device); | ||
| 122 | |||
| 123 | let sockets = SocketSet::new(&mut resources.sockets[..]); | ||
| 124 | |||
| 125 | let next_local_port = | ||
| 126 | (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN; | ||
| 127 | |||
| 128 | let mut inner = Inner { | ||
| 129 | device, | ||
| 130 | link_up: false, | ||
| 131 | config: None, | ||
| 132 | #[cfg(feature = "dhcpv4")] | ||
| 133 | dhcp_socket: None, | ||
| 134 | }; | ||
| 135 | let mut socket = SocketStack { | ||
| 136 | sockets, | ||
| 137 | iface, | ||
| 138 | waker: WakerRegistration::new(), | ||
| 139 | next_local_port, | ||
| 140 | }; | ||
| 141 | |||
| 142 | match config { | ||
| 143 | ConfigStrategy::Static(config) => inner.apply_config(&mut socket, config), | ||
| 144 | #[cfg(feature = "dhcpv4")] | ||
| 145 | ConfigStrategy::Dhcp => { | ||
| 146 | let handle = socket.sockets.add(smoltcp::socket::dhcpv4::Socket::new()); | ||
| 147 | inner.dhcp_socket = Some(handle); | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | Self { | ||
| 152 | socket: UnsafeCell::new(socket), | ||
| 153 | inner: UnsafeCell::new(inner), | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | /// SAFETY: must not call reentrantly. | ||
| 158 | unsafe fn with<R>(&self, f: impl FnOnce(&SocketStack, &Inner<D>) -> R) -> R { | ||
| 159 | f(&*self.socket.get(), &*self.inner.get()) | ||
| 160 | } | ||
| 161 | |||
| 162 | /// SAFETY: must not call reentrantly. | ||
| 163 | unsafe fn with_mut<R>(&self, f: impl FnOnce(&mut SocketStack, &mut Inner<D>) -> R) -> R { | ||
| 164 | f(&mut *self.socket.get(), &mut *self.inner.get()) | ||
| 165 | } | ||
| 166 | |||
| 167 | pub fn ethernet_address(&self) -> [u8; 6] { | ||
| 168 | unsafe { self.with(|_s, i| i.device.device.ethernet_address()) } | ||
| 169 | } | ||
| 170 | |||
| 171 | pub fn is_link_up(&self) -> bool { | ||
| 172 | unsafe { self.with(|_s, i| i.link_up) } | ||
| 173 | } | ||
| 174 | |||
| 175 | pub fn is_config_up(&self) -> bool { | ||
| 176 | unsafe { self.with(|_s, i| i.config.is_some()) } | ||
| 177 | } | ||
| 178 | |||
| 179 | pub fn config(&self) -> Option<Config> { | ||
| 180 | unsafe { self.with(|_s, i| i.config.clone()) } | ||
| 181 | } | ||
| 182 | |||
| 183 | pub async fn run(&self) -> ! { | ||
| 184 | poll_fn(|cx| { | ||
| 185 | unsafe { self.with_mut(|s, i| i.poll(cx, s)) } | ||
| 186 | Poll::<()>::Pending | ||
| 187 | }) | ||
| 188 | .await; | ||
| 189 | unreachable!() | ||
| 70 | } | 190 | } |
| 191 | } | ||
| 71 | 192 | ||
| 193 | impl SocketStack { | ||
| 72 | #[allow(clippy::absurd_extreme_comparisons)] | 194 | #[allow(clippy::absurd_extreme_comparisons)] |
| 73 | pub fn get_local_port(&mut self) -> u16 { | 195 | pub fn get_local_port(&mut self) -> u16 { |
| 74 | let res = self.next_local_port; | 196 | let res = self.next_local_port; |
| @@ -79,60 +201,68 @@ impl Stack { | |||
| 79 | }; | 201 | }; |
| 80 | res | 202 | res |
| 81 | } | 203 | } |
| 204 | } | ||
| 205 | |||
| 206 | impl<D: Device + 'static> Inner<D> { | ||
| 207 | fn apply_config(&mut self, s: &mut SocketStack, config: Config) { | ||
| 208 | #[cfg(feature = "medium-ethernet")] | ||
| 209 | let medium = self.device.capabilities().medium; | ||
| 210 | |||
| 211 | debug!("Acquired IP configuration:"); | ||
| 82 | 212 | ||
| 83 | pub(crate) fn wake(&mut self) { | 213 | debug!(" IP address: {}", config.address); |
| 84 | self.waker.wake() | 214 | self.set_ipv4_addr(s, config.address); |
| 215 | |||
| 216 | #[cfg(feature = "medium-ethernet")] | ||
| 217 | if medium == Medium::Ethernet { | ||
| 218 | if let Some(gateway) = config.gateway { | ||
| 219 | debug!(" Default gateway: {}", gateway); | ||
| 220 | s.iface | ||
| 221 | .routes_mut() | ||
| 222 | .add_default_ipv4_route(gateway) | ||
| 223 | .unwrap(); | ||
| 224 | } else { | ||
| 225 | debug!(" Default gateway: None"); | ||
| 226 | s.iface.routes_mut().remove_default_ipv4_route(); | ||
| 227 | } | ||
| 228 | } | ||
| 229 | for (i, s) in config.dns_servers.iter().enumerate() { | ||
| 230 | debug!(" DNS server {}: {}", i, s); | ||
| 231 | } | ||
| 232 | |||
| 233 | self.config = Some(config) | ||
| 85 | } | 234 | } |
| 86 | 235 | ||
| 87 | fn poll_configurator(&mut self, timestamp: SmolInstant) { | 236 | #[allow(unused)] // used only with dhcp |
| 237 | fn unapply_config(&mut self, s: &mut SocketStack) { | ||
| 88 | #[cfg(feature = "medium-ethernet")] | 238 | #[cfg(feature = "medium-ethernet")] |
| 89 | let medium = self.iface.device().capabilities().medium; | 239 | let medium = self.device.capabilities().medium; |
| 90 | |||
| 91 | match self.configurator.poll(&mut self.iface, timestamp) { | ||
| 92 | Event::NoChange => {} | ||
| 93 | Event::Configured(config) => { | ||
| 94 | debug!("Acquired IP configuration:"); | ||
| 95 | |||
| 96 | debug!(" IP address: {}", config.address); | ||
| 97 | set_ipv4_addr(&mut self.iface, config.address); | ||
| 98 | |||
| 99 | #[cfg(feature = "medium-ethernet")] | ||
| 100 | if medium == Medium::Ethernet { | ||
| 101 | if let Some(gateway) = config.gateway { | ||
| 102 | debug!(" Default gateway: {}", gateway); | ||
| 103 | self.iface | ||
| 104 | .routes_mut() | ||
| 105 | .add_default_ipv4_route(gateway) | ||
| 106 | .unwrap(); | ||
| 107 | } else { | ||
| 108 | debug!(" Default gateway: None"); | ||
| 109 | self.iface.routes_mut().remove_default_ipv4_route(); | ||
| 110 | } | ||
| 111 | } | ||
| 112 | for (i, s) in config.dns_servers.iter().enumerate() { | ||
| 113 | debug!(" DNS server {}: {}", i, s); | ||
| 114 | } | ||
| 115 | 240 | ||
| 116 | self.config = Some(config) | 241 | debug!("Lost IP configuration"); |
| 117 | } | 242 | self.set_ipv4_addr(s, Ipv4Cidr::new(Ipv4Address::UNSPECIFIED, 0)); |
| 118 | Event::Deconfigured => { | 243 | #[cfg(feature = "medium-ethernet")] |
| 119 | debug!("Lost IP configuration"); | 244 | if medium == Medium::Ethernet { |
| 120 | set_ipv4_addr(&mut self.iface, Ipv4Cidr::new(Ipv4Address::UNSPECIFIED, 0)); | 245 | s.iface.routes_mut().remove_default_ipv4_route(); |
| 121 | #[cfg(feature = "medium-ethernet")] | ||
| 122 | if medium == Medium::Ethernet { | ||
| 123 | self.iface.routes_mut().remove_default_ipv4_route(); | ||
| 124 | } | ||
| 125 | self.config = None | ||
| 126 | } | ||
| 127 | } | 246 | } |
| 247 | self.config = None | ||
| 248 | } | ||
| 249 | |||
| 250 | fn set_ipv4_addr(&mut self, s: &mut SocketStack, cidr: Ipv4Cidr) { | ||
| 251 | s.iface.update_ip_addrs(|addrs| { | ||
| 252 | let dest = addrs.iter_mut().next().unwrap(); | ||
| 253 | *dest = IpCidr::Ipv4(cidr); | ||
| 254 | }); | ||
| 128 | } | 255 | } |
| 129 | 256 | ||
| 130 | fn poll(&mut self, cx: &mut Context<'_>) { | 257 | fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { |
| 131 | self.iface.device_mut().device.register_waker(cx.waker()); | 258 | self.device.device.register_waker(cx.waker()); |
| 132 | self.waker.register(cx.waker()); | 259 | s.waker.register(cx.waker()); |
| 133 | 260 | ||
| 134 | let timestamp = instant_to_smoltcp(Instant::now()); | 261 | let timestamp = instant_to_smoltcp(Instant::now()); |
| 135 | if self.iface.poll(timestamp).is_err() { | 262 | if s.iface |
| 263 | .poll(timestamp, &mut self.device, &mut s.sockets) | ||
| 264 | .is_err() | ||
| 265 | { | ||
| 136 | // If poll() returns error, it may not be done yet, so poll again later. | 266 | // If poll() returns error, it may not be done yet, so poll again later. |
| 137 | cx.waker().wake_by_ref(); | 267 | cx.waker().wake_by_ref(); |
| 138 | return; | 268 | return; |
| @@ -140,18 +270,49 @@ impl Stack { | |||
| 140 | 270 | ||
| 141 | // Update link up | 271 | // Update link up |
| 142 | let old_link_up = self.link_up; | 272 | let old_link_up = self.link_up; |
| 143 | self.link_up = self.iface.device_mut().device.link_state() == LinkState::Up; | 273 | self.link_up = self.device.device.link_state() == LinkState::Up; |
| 144 | 274 | ||
| 145 | // Print when changed | 275 | // Print when changed |
| 146 | if old_link_up != self.link_up { | 276 | if old_link_up != self.link_up { |
| 147 | info!("link_up = {:?}", self.link_up); | 277 | info!("link_up = {:?}", self.link_up); |
| 148 | } | 278 | } |
| 149 | 279 | ||
| 150 | if old_link_up || self.link_up { | 280 | #[cfg(feature = "dhcpv4")] |
| 151 | self.poll_configurator(timestamp) | 281 | if let Some(dhcp_handle) = self.dhcp_socket { |
| 282 | let socket = s.sockets.get_mut::<dhcpv4::Socket>(dhcp_handle); | ||
| 283 | |||
| 284 | if self.link_up { | ||
| 285 | match socket.poll() { | ||
| 286 | None => {} | ||
| 287 | Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s), | ||
| 288 | Some(dhcpv4::Event::Configured(config)) => { | ||
| 289 | let mut dns_servers = Vec::new(); | ||
| 290 | for s in &config.dns_servers { | ||
| 291 | if let Some(addr) = s { | ||
| 292 | dns_servers.push(addr.clone()).unwrap(); | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | self.apply_config( | ||
| 297 | s, | ||
| 298 | Config { | ||
| 299 | address: config.address, | ||
| 300 | gateway: config.router, | ||
| 301 | dns_servers, | ||
| 302 | }, | ||
| 303 | ) | ||
| 304 | } | ||
| 305 | } | ||
| 306 | } else if old_link_up { | ||
| 307 | socket.reset(); | ||
| 308 | self.unapply_config(s); | ||
| 309 | } | ||
| 152 | } | 310 | } |
| 311 | //if old_link_up || self.link_up { | ||
| 312 | // self.poll_configurator(timestamp) | ||
| 313 | //} | ||
| 153 | 314 | ||
| 154 | if let Some(poll_at) = self.iface.poll_at(timestamp) { | 315 | if let Some(poll_at) = s.iface.poll_at(timestamp, &mut s.sockets) { |
| 155 | let t = Timer::at(instant_from_smoltcp(poll_at)); | 316 | let t = Timer::at(instant_from_smoltcp(poll_at)); |
| 156 | pin_mut!(t); | 317 | pin_mut!(t); |
| 157 | if t.poll(cx).is_ready() { | 318 | if t.poll(cx).is_ready() { |
| @@ -161,100 +322,6 @@ impl Stack { | |||
| 161 | } | 322 | } |
| 162 | } | 323 | } |
| 163 | 324 | ||
| 164 | fn set_ipv4_addr(iface: &mut Interface, cidr: Ipv4Cidr) { | ||
| 165 | iface.update_ip_addrs(|addrs| { | ||
| 166 | let dest = addrs.iter_mut().next().unwrap(); | ||
| 167 | *dest = IpCidr::Ipv4(cidr); | ||
| 168 | }); | ||
| 169 | } | ||
| 170 | |||
| 171 | /// Initialize embassy_net. | ||
| 172 | /// This function must be called from thread mode. | ||
| 173 | pub fn init<const ADDR: usize, const SOCK: usize, const NEIGH: usize>( | ||
| 174 | device: &'static mut dyn Device, | ||
| 175 | configurator: &'static mut dyn Configurator, | ||
| 176 | resources: &'static mut StackResources<ADDR, SOCK, NEIGH>, | ||
| 177 | ) { | ||
| 178 | #[cfg(feature = "medium-ethernet")] | ||
| 179 | let medium = device.capabilities().medium; | ||
| 180 | |||
| 181 | #[cfg(feature = "medium-ethernet")] | ||
| 182 | let ethernet_addr = if medium == Medium::Ethernet { | ||
| 183 | device.ethernet_address() | ||
| 184 | } else { | ||
| 185 | [0, 0, 0, 0, 0, 0] | ||
| 186 | }; | ||
| 187 | |||
| 188 | let mut b = InterfaceBuilder::new(DeviceAdapter::new(device), &mut resources.sockets[..]); | ||
| 189 | b = b.ip_addrs(&mut resources.addresses[..]); | ||
| 190 | |||
| 191 | #[cfg(feature = "medium-ethernet")] | ||
| 192 | if medium == Medium::Ethernet { | ||
| 193 | b = b.hardware_addr(HardwareAddress::Ethernet(EthernetAddress(ethernet_addr))); | ||
| 194 | b = b.neighbor_cache(NeighborCache::new(&mut resources.neighbor_cache[..])); | ||
| 195 | b = b.routes(Routes::new(&mut resources.routes[..])); | ||
| 196 | } | ||
| 197 | |||
| 198 | let iface = b.finalize(); | ||
| 199 | |||
| 200 | let local_port = loop { | ||
| 201 | let mut res = [0u8; 2]; | ||
| 202 | rand(&mut res); | ||
| 203 | let port = u16::from_le_bytes(res); | ||
| 204 | if (LOCAL_PORT_MIN..=LOCAL_PORT_MAX).contains(&port) { | ||
| 205 | break port; | ||
| 206 | } | ||
| 207 | }; | ||
| 208 | |||
| 209 | let stack = Stack { | ||
| 210 | iface, | ||
| 211 | link_up: false, | ||
| 212 | config: None, | ||
| 213 | configurator, | ||
| 214 | next_local_port: local_port, | ||
| 215 | waker: WakerRegistration::new(), | ||
| 216 | }; | ||
| 217 | |||
| 218 | *STACK.borrow().borrow_mut() = Some(stack); | ||
| 219 | } | ||
| 220 | |||
| 221 | pub fn ethernet_address() -> [u8; 6] { | ||
| 222 | STACK | ||
| 223 | .borrow() | ||
| 224 | .borrow() | ||
| 225 | .as_ref() | ||
| 226 | .unwrap() | ||
| 227 | .iface | ||
| 228 | .device() | ||
| 229 | .device | ||
| 230 | .ethernet_address() | ||
| 231 | } | ||
| 232 | |||
| 233 | pub fn is_init() -> bool { | ||
| 234 | STACK.borrow().borrow().is_some() | ||
| 235 | } | ||
| 236 | |||
| 237 | pub fn is_link_up() -> bool { | ||
| 238 | STACK.borrow().borrow().as_ref().unwrap().link_up | ||
| 239 | } | ||
| 240 | |||
| 241 | pub fn is_config_up() -> bool { | ||
| 242 | STACK.borrow().borrow().as_ref().unwrap().config.is_some() | ||
| 243 | } | ||
| 244 | |||
| 245 | pub fn config() -> Option<Config> { | ||
| 246 | STACK.borrow().borrow().as_ref().unwrap().config.clone() | ||
| 247 | } | ||
| 248 | |||
| 249 | pub async fn run() -> ! { | ||
| 250 | futures::future::poll_fn(|cx| { | ||
| 251 | Stack::with(|stack| stack.poll(cx)); | ||
| 252 | Poll::<()>::Pending | ||
| 253 | }) | ||
| 254 | .await; | ||
| 255 | unreachable!() | ||
| 256 | } | ||
| 257 | |||
| 258 | fn instant_to_smoltcp(instant: Instant) -> SmolInstant { | 325 | fn instant_to_smoltcp(instant: Instant) -> SmolInstant { |
| 259 | SmolInstant::from_millis(instant.as_millis() as i64) | 326 | SmolInstant::from_millis(instant.as_millis() as i64) |
| 260 | } | 327 | } |
| @@ -262,11 +329,3 @@ fn instant_to_smoltcp(instant: Instant) -> SmolInstant { | |||
| 262 | fn instant_from_smoltcp(instant: SmolInstant) -> Instant { | 329 | fn instant_from_smoltcp(instant: SmolInstant) -> Instant { |
| 263 | Instant::from_millis(instant.total_millis() as u64) | 330 | Instant::from_millis(instant.total_millis() as u64) |
| 264 | } | 331 | } |
| 265 | |||
| 266 | extern "Rust" { | ||
| 267 | fn _embassy_rand(buf: &mut [u8]); | ||
| 268 | } | ||
| 269 | |||
| 270 | fn rand(buf: &mut [u8]) { | ||
| 271 | unsafe { _embassy_rand(buf) } | ||
| 272 | } | ||
