use atsamd_hal_macros::hal_cfg;
use super::{
BaudMode, BitOrder, Capability, CharSize, CharSizeEnum, DataReg, DynCharSize, EightBit,
FixedCharSize, Parity, Registers, StopBits, Uart, ValidConfig, ValidPads,
};
use crate::{
pac,
sercom::Sercom,
time::Hertz,
typelevel::{Is, NoneT, Sealed},
};
use core::marker::PhantomData;
use num_traits::{AsPrimitive, PrimInt};
pub struct Config<P, C = EightBit>
where
P: ValidPads,
C: CharSize,
{
pub(super) registers: Registers<P::Sercom>,
pads: P,
chsize: PhantomData<C>,
freq: Hertz,
}
#[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
pub type Clock = pac::Pm;
#[hal_cfg("sercom0-d5x")]
pub type Clock = pac::Mclk;
impl<P: ValidPads> Config<P> {
#[inline]
pub fn new(clk: &Clock, mut sercom: P::Sercom, pads: P, freq: impl Into<Hertz>) -> Self {
sercom.enable_apb_clock(clk);
Self::default(sercom, pads, freq).bit_order(BitOrder::LsbFirst)
}
#[inline]
fn default(sercom: P::Sercom, pads: P, freq: impl Into<Hertz>) -> Self {
let mut registers = Registers::new(sercom);
registers.swrst();
registers.configure_mode();
registers.configure_pads(P::RXPO, P::TXPO);
registers.set_char_size(EightBit::SIZE);
Self {
registers,
pads,
chsize: PhantomData,
freq: freq.into(),
}
}
}
impl<P, C> Config<P, C>
where
P: ValidPads,
C: CharSize,
{
#[inline]
fn change<C2>(self) -> Config<P, C2>
where
C2: CharSize,
{
Config {
registers: self.registers,
pads: self.pads,
chsize: PhantomData,
freq: self.freq,
}
}
#[inline]
pub fn reset(self) -> Config<P> {
Config::default(self.registers.free(), self.pads, self.freq)
}
#[inline]
pub fn free(mut self) -> (P::Sercom, P) {
self.registers.swrst();
(self.registers.free(), self.pads)
}
#[inline]
pub fn char_size<C2: FixedCharSize>(mut self) -> Config<P, C2> {
self.registers.set_char_size(C2::SIZE);
self.change()
}
#[inline]
pub fn dyn_char_size(mut self) -> Config<P, DynCharSize> {
self.registers.set_char_size(CharSizeEnum::EightBit);
self.change()
}
#[inline]
pub fn bit_order(mut self, bit_order: BitOrder) -> Self {
self.set_bit_order(bit_order);
self
}
#[inline]
pub fn set_bit_order(&mut self, bit_order: BitOrder) {
self.registers.set_bit_order(bit_order);
}
#[inline]
pub fn get_bit_order(&self) -> BitOrder {
self.registers.get_bit_order()
}
#[inline]
pub fn parity(mut self, parity: Parity) -> Self {
self.set_parity(parity);
self
}
#[inline]
pub fn set_parity(&mut self, parity: Parity) {
self.registers.set_parity(parity);
}
#[inline]
pub fn get_parity(&self) -> Parity {
self.registers.get_parity()
}
#[inline]
pub fn stop_bits(mut self, stop_bits: StopBits) -> Self {
self.set_stop_bits(stop_bits);
self
}
#[inline]
pub fn set_stop_bits(&mut self, stop_bits: StopBits) {
self.registers.set_stop_bits(stop_bits);
}
#[inline]
pub fn get_stop_bits(&self) -> StopBits {
self.registers.get_stop_bits()
}
#[inline]
pub fn start_of_frame_detection(mut self, enabled: bool) -> Self {
self.set_start_of_frame_detection(enabled);
self
}
#[inline]
pub fn set_start_of_frame_detection(&mut self, enabled: bool) {
self.registers.set_start_of_frame_detection(enabled);
}
#[inline]
pub fn get_start_of_frame_detection(&self) -> bool {
self.registers.get_start_of_frame_detection()
}
#[inline]
pub fn collision_detection(mut self, enabled: bool) -> Self {
self.set_collision_detection(enabled);
self
}
#[inline]
pub fn set_collision_detection(&mut self, enabled: bool) {
self.registers.set_collision_detection(enabled);
}
#[inline]
pub fn get_collision_detection(&self) -> bool {
self.registers.get_collision_detection()
}
#[inline]
pub fn baud(mut self, baud: Hertz, mode: BaudMode) -> Self {
self.set_baud(baud, mode);
self
}
#[inline]
pub fn set_baud(&mut self, baud: Hertz, mode: BaudMode) {
self.registers.set_baud(self.freq, baud, mode);
}
#[inline]
pub fn get_baud(&self) -> (u16, BaudMode) {
self.registers.get_baud()
}
#[inline]
pub fn immediate_overflow_notification(mut self, set: bool) -> Self {
self.set_immediate_overflow_notification(set);
self
}
#[inline]
pub fn set_immediate_overflow_notification(&mut self, set: bool) {
self.registers.set_immediate_overflow_notification(set);
}
#[inline]
pub fn get_immediate_overflow_notification(&self) -> bool {
self.registers.get_immediate_overflow_notification()
}
#[inline]
pub fn run_in_standby(mut self, set: bool) -> Self {
self.set_run_in_standby(set);
self
}
#[inline]
pub fn set_run_in_standby(&mut self, set: bool) {
self.registers.set_run_in_standby(set);
}
#[inline]
pub fn get_run_in_standby(&self) -> bool {
self.registers.get_run_in_standby()
}
#[inline]
pub fn irda_encoding(mut self, pulse_length: Option<u8>) -> Self {
self.set_irda_encoding(pulse_length);
self
}
#[inline]
pub fn set_irda_encoding(&mut self, pulse_length: Option<u8>) {
self.registers.set_irda_encoding(pulse_length);
}
#[inline]
pub fn get_irda_encoding(&self) -> Option<u8> {
self.registers.get_irda_encoding()
}
}
impl<P: ValidPads> Config<P, DynCharSize> {
#[inline]
pub fn set_dyn_char_size(&mut self, char_size: CharSizeEnum) {
self.registers.set_char_size(char_size);
}
pub fn get_dyn_char_size(&self) -> CharSizeEnum {
self.registers.get_char_size()
}
}
impl<P, C> Config<P, C>
where
P: ValidPads,
C: CharSize,
Self: ValidConfig,
{
#[inline]
pub fn enable(mut self) -> Uart<Self, P::Capability> {
self.registers
.enable(P::Capability::RXEN, P::Capability::TXEN);
Uart {
config: self,
capability: PhantomData,
rx_channel: NoneT,
tx_channel: NoneT,
}
}
}
pub trait AnyConfig: Sealed + Is<Type = SpecificConfig<Self>> {
type Sercom: Sercom;
type Pads: ValidPads<Sercom = Self::Sercom>;
type Word: 'static + PrimInt + AsPrimitive<DataReg>;
type CharSize: CharSize<Word = Self::Word>;
}
pub type SpecificConfig<C> = Config<<C as AnyConfig>::Pads, <C as AnyConfig>::CharSize>;
pub type ConfigSercom<C> = <C as AnyConfig>::Sercom;
impl<P, C> AsRef<Self> for Config<P, C>
where
P: ValidPads,
C: CharSize,
{
#[inline]
fn as_ref(&self) -> &Self {
self
}
}
impl<P, C> AsMut<Self> for Config<P, C>
where
P: ValidPads,
C: CharSize,
{
#[inline]
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl<P, C> Sealed for Config<P, C>
where
P: ValidPads,
C: CharSize,
{
}
impl<P, C> AnyConfig for Config<P, C>
where
P: ValidPads,
C: CharSize,
{
type Sercom = P::Sercom;
type Word = C::Word;
type Pads = P;
type CharSize = C;
}