use crate::manager::Manager;
use crate::transfer::Xfer;
mod dns;
#[cfg(feature = "ethernet")]
mod ethernet;
#[cfg(feature = "flash-rw")]
mod flash;
#[cfg(feature = "experimental-ota")]
mod ota;
mod prng;
#[cfg(feature = "ssl")]
mod ssl;
mod tcp_stack;
mod udp_stack;
mod wifi_module;
pub use crate::stack::StackError;
pub use crate::stack::socket_callbacks::ClientSocketOp;
use crate::stack::socket_callbacks::SocketCallbacks;
pub use crate::stack::socket_callbacks::{Handle, PingResult};
pub struct WincClient<'a, X: Xfer> {
manager: Manager<X>,
poll_loop_delay_us: u32,
callbacks: SocketCallbacks,
next_session_id: u16,
boot: Option<crate::manager::BootState>,
operation_countdown: u32,
dns_op: Option<crate::net_ops::dns::DnsOp>,
phantom: core::marker::PhantomData<&'a ()>,
#[cfg(test)]
debug_callback: Option<&'a mut dyn FnMut(&mut SocketCallbacks)>,
}
impl<X: Xfer> WincClient<'_, X> {
const TCP_SOCKET_BACKLOG: u8 = 4;
const LISTEN_TIMEOUT: u32 = 100;
const BIND_TIMEOUT: u32 = 100;
const DNS_TIMEOUT: u32 = 1000;
const POLL_LOOP_DELAY_US: u32 = 100;
pub fn new(transfer: X) -> Self {
let manager = Manager::from_xfer(transfer);
Self {
manager,
callbacks: SocketCallbacks::new(),
poll_loop_delay_us: Self::POLL_LOOP_DELAY_US,
next_session_id: 0,
boot: None,
operation_countdown: 0,
dns_op: None,
phantom: core::marker::PhantomData,
#[cfg(test)]
debug_callback: None,
}
}
fn delay_us(&mut self, delay: u32) {
self.manager.delay_us(delay)
}
fn get_next_session_id(&mut self) -> u16 {
let ret = self.next_session_id;
self.next_session_id += 1;
ret
}
fn test_hook(&mut self) {
#[cfg(test)]
if let Some(callback) = &mut self.debug_callback {
callback(&mut self.callbacks);
}
}
fn dispatch_events(&mut self) -> Result<(), StackError> {
self.test_hook();
self.manager
.dispatch_events_new(&mut self.callbacks)
.map_err(StackError::DispatchError)
}
fn dispatch_events_may_wait(&mut self) -> Result<(), StackError> {
self.test_hook();
self.manager
.dispatch_events_may_wait(&mut self.callbacks)
.map_err(StackError::DispatchError)
}
fn wait_with_timeout<F, T>(
&mut self,
timeout: u32,
mut check_complete: F,
) -> Result<T, StackError>
where
F: FnMut(&mut Self, u32) -> Option<Result<T, StackError>>,
{
self.dispatch_events()?;
let mut timeout = timeout as i32;
let mut elapsed = 0;
loop {
if timeout <= 0 {
return Err(StackError::GeneralTimeout);
}
if let Some(result) = check_complete(self, elapsed) {
return result;
}
self.delay_us(self.poll_loop_delay_us);
self.dispatch_events()?;
timeout -= self.poll_loop_delay_us as i32;
elapsed += self.poll_loop_delay_us;
}
}
}
#[cfg(test)]
mod test_shared {
use super::*;
pub(crate) struct MockTransfer {}
impl Default for MockTransfer {
fn default() -> Self {
Self {}
}
}
impl Xfer for MockTransfer {
fn recv(&mut self, _: &mut [u8]) -> Result<(), crate::errors::CommError> {
Ok(())
}
fn send(&mut self, _: &[u8]) -> Result<(), crate::errors::CommError> {
Ok(())
}
}
pub(crate) fn make_test_client<'a>() -> WincClient<'a, MockTransfer> {
let mut client = WincClient::new(MockTransfer::default());
client.manager.set_unit_test_mode();
client
}
}
#[cfg(test)]
mod tests {
pub(crate) fn compute_crc16(input: &[u8]) -> u16 {
use crc_any::CRC;
let mut crc = CRC::crc16aug_ccitt();
crc.digest(&[0x99, 0xc0]); crc.digest(input);
crc.get_crc() as u16
}
pub(crate) fn generate_test_pattern(buffer: &mut [u8]) {
assert!(buffer.len() % 4 == 0, "Buffer size must be a multiple of 4");
let mut val: u32 = 0;
for chunk in buffer.chunks_mut(4) {
chunk.copy_from_slice(&val.to_be_bytes());
val = val.wrapping_add(1);
}
}
#[test]
fn test_winc_client() {}
}