use crate::uart::{
ConfigError,
CtsConfig,
HwFlowControl,
RegisterBlock,
RtsConfig,
StopBits,
SwFlowControl,
low_level::Info,
};
#[inline(always)]
pub(crate) fn enable_register_sync(_register_block: &RegisterBlock) {}
#[inline(always)]
pub(crate) fn sync_regs(register_block: &RegisterBlock) {
let update_reg = register_block.reg_update();
update_reg.write(|w| w.reg_update().set_bit());
while update_reg.read().reg_update().bit_is_set() {
core::hint::spin_loop();
}
}
pub(super) fn set_rx_timeout(
info: &Info,
timeout: Option<u8>,
symbol_len: u8,
) -> Result<(), ConfigError> {
const MAX_THRHD: u16 = 0x3FF;
let register_block = info.regs();
if let Some(timeout) = timeout {
let timeout_reg = timeout as u16 * symbol_len as u16;
if timeout_reg > MAX_THRHD {
return Err(ConfigError::TimeoutTooLong);
}
register_block
.tout_conf()
.modify(|_, w| unsafe { w.rx_tout_thrhd().bits(timeout_reg) });
}
register_block
.tout_conf()
.modify(|_, w| w.rx_tout_en().bit(timeout.is_some()));
info.sync_regs();
Ok(())
}
pub(super) fn rx_timeout_enabled(info: &Info) -> bool {
info.regs().tout_conf().read().rx_tout_en().bit_is_set()
}
pub(super) fn is_tx_idle(info: &Info) -> bool {
info.regs().fsm_status().read().st_utx_out().bits() == 0x0
}
pub(super) fn change_stop_bits(info: &Info, stop_bits: StopBits) {
info.regs()
.conf0()
.modify(|_, w| unsafe { w.stop_bit_num().bits(stop_bits as u8 + 1) });
}
pub(super) fn change_flow_control(
info: &Info,
sw_flow_ctrl: SwFlowControl,
hw_flow_ctrl: HwFlowControl,
) {
match sw_flow_ctrl {
SwFlowControl::Enabled {
xon_char,
xoff_char,
xon_threshold,
xoff_threshold,
} => {
info.regs()
.swfc_conf0()
.modify(|_, w| w.xonoff_del().set_bit().sw_flow_con_en().set_bit());
info.regs().swfc_conf1().modify(|_, w| unsafe {
w.xon_threshold().bits(xon_threshold);
w.xoff_threshold().bits(xoff_threshold)
});
info.regs()
.swfc_conf0()
.modify(|_, w| unsafe { w.xon_char().bits(xon_char).xoff_char().bits(xoff_char) });
}
SwFlowControl::Disabled => {
let reg = info.regs().swfc_conf0();
reg.modify(|_, w| w.sw_flow_con_en().clear_bit());
reg.modify(|_, w| w.xonoff_del().clear_bit());
}
}
info.regs().conf0().modify(|_, w| {
w.tx_flow_en()
.bit(matches!(hw_flow_ctrl.cts, CtsConfig::Enabled))
});
match hw_flow_ctrl.rts {
RtsConfig::Enabled(threshold) => configure_rts_flow_ctrl(info, true, Some(threshold)),
RtsConfig::Disabled => configure_rts_flow_ctrl(info, false, None),
}
sync_regs(info.regs());
}
#[cfg(sleep_driver_supported)]
pub(super) fn suspend(info: &Info, en: bool) {
info.regs().swfc_conf0().modify(|_, w| {
w.force_xon().bit(!en);
w.sw_flow_con_en().bit(en);
w.force_xoff().bit(en)
});
sync_regs(info.regs());
if !en {
info.regs()
.swfc_conf0()
.modify(|_, w| w.force_xon().bit(false));
sync_regs(info.regs());
}
}
#[cfg(sleep_driver_supported)]
pub(super) fn set_wakeup_edge_threshold(info: &Info, threshold: u16) {
info.regs().sleep_conf2().modify(|_, w| unsafe {
w.wk_mode_sel().bits(0);
w.active_threshold().bits(threshold)
});
}
#[cfg(sleep_driver_supported)]
pub(super) fn wait_for_suspended(info: &Info) {
const FSM_IDLE: u8 = 0;
const FSM_TX_WAIT_SEND: u8 = 0x0F;
loop {
let bits = info.regs().fsm_status().read().st_utx_out().bits();
if [FSM_TX_WAIT_SEND, FSM_IDLE].contains(&bits) {
return;
}
}
}
fn configure_rts_flow_ctrl(info: &Info, enable: bool, threshold: Option<u8>) {
if let Some(threshold) = threshold {
info.regs()
.hwfc_conf()
.modify(|_, w| unsafe { w.rx_flow_thrhd().bits(threshold) });
}
info.regs()
.hwfc_conf()
.modify(|_, w| w.rx_flow_en().bit(enable));
}
pub(super) fn current_symbol_length(info: &Info) -> u8 {
let conf0 = info.regs().conf0().read();
let data_bits = conf0.bit_num().bits() + 5; let parity = conf0.parity_en().bit() as u8;
let mut stop_bits = conf0.stop_bit_num().bits();
match stop_bits {
1 => {}
_ => stop_bits = 2,
}
1 + data_bits + parity + stop_bits
}
pub(super) fn read_next_from_fifo(info: &Info) -> u8 {
info.regs().fifo().read().rxfifo_rd_byte().bits()
}
#[allow(clippy::unnecessary_cast)]
pub(super) fn rx_fifo_count(info: &Info) -> u16 {
info.regs().status().read().rxfifo_cnt().bits() as u16
}