/// T.30 session state machine for Group 3 fax. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum T30State { Idle, Dialing, HandshakeTransmitting, // Phase B - sending DIS/DCS HandshakeReceiving, // Phase B - receiving DIS/DCS DcsSent, // DCS has been sent, waiting for CFR CfrReceived, // Received CFR, ready to send pages PageTransmitting, // Phase C - sending page data PageReceiving, PostPageHandshake, // Phase D - MCF, EOP, MPS Disconnecting, // Phase E - DCN Completed, Error, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum T30Event { Connected, DisReceived, DisSent, DcsReceived, DcsSent, TcfSent, TcfReceived, CfrReceived, CfrSent, PageSent, PageReceived, McfReceived, McfSent, EopReceived, EopSent, DcnReceived, DcnSent, Timeout, Error, Retrain, } pub struct T30Session { state: T30State, retry_count: u8, max_retries: u8, } impl T30Session { pub fn new() -> Self { Self { state: T30State::Idle, retry_count: 0, max_retries: 3, } } pub fn state(&self) -> T30State { self.state } pub fn start_receive(&mut self) { self.state = T30State::HandshakeReceiving; } pub fn transition(&mut self, event: T30Event) { match (self.state, event) { // Send flow (T30State::Idle, T30Event::Connected) => { // Default to transmitting; caller can override with start_receive() self.state = T30State::HandshakeTransmitting; } (T30State::HandshakeTransmitting, T30Event::DisReceived) => { self.state = T30State::DcsSent; } (T30State::DcsSent, T30Event::CfrReceived) => self.state = T30State::PageTransmitting, (T30State::PageTransmitting, T30Event::PageSent) => self.state = T30State::PostPageHandshake, (T30State::PostPageHandshake, T30Event::McfReceived) => self.state = T30State::Disconnecting, (T30State::PostPageHandshake, T30Event::EopReceived) => self.state = T30State::Disconnecting, (T30State::Disconnecting, T30Event::DcnSent) => self.state = T30State::Completed, // Receive flow (T30State::HandshakeReceiving, T30Event::DcsReceived) => self.state = T30State::PageReceiving, (T30State::PageReceiving, T30Event::PageReceived) => self.state = T30State::PostPageHandshake, (T30State::PostPageHandshake, T30Event::McfSent) => self.state = T30State::Disconnecting, (T30State::Disconnecting, T30Event::DcnReceived) => self.state = T30State::Completed, // Error handling (_, T30Event::Timeout) | (_, T30Event::Error) => { if self.retry_count < self.max_retries { self.retry_count += 1; // Stay in same state for retry } else { self.state = T30State::Error; } } _ => { // Unexpected transition - log and set error self.state = T30State::Error; } } } }