use core::marker::PhantomData;
use core::ptr;
use embedded_hal::serial;
use crate::gpio::*;
use crate::units::*;
use esp_idf_sys::*;
const UART_FIFO_SIZE: i32 = 128;
pub mod config {
use crate::units::*;
use esp_idf_sys::*;
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub enum DataBits {
DataBits5,
DataBits6,
DataBits7,
DataBits8,
}
impl From<DataBits> for uart_word_length_t {
fn from(data_bits: DataBits) -> Self {
match data_bits {
DataBits::DataBits5 => uart_word_length_t_UART_DATA_5_BITS,
DataBits::DataBits6 => uart_word_length_t_UART_DATA_6_BITS,
DataBits::DataBits7 => uart_word_length_t_UART_DATA_7_BITS,
DataBits::DataBits8 => uart_word_length_t_UART_DATA_8_BITS,
}
}
}
impl From<uart_word_length_t> for DataBits {
#[allow(non_upper_case_globals)]
fn from(word_length: uart_word_length_t) -> Self {
match word_length {
uart_word_length_t_UART_DATA_5_BITS => DataBits::DataBits5,
uart_word_length_t_UART_DATA_6_BITS => DataBits::DataBits6,
uart_word_length_t_UART_DATA_7_BITS => DataBits::DataBits7,
uart_word_length_t_UART_DATA_8_BITS => DataBits::DataBits8,
_ => unreachable!(),
}
}
}
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub enum FlowControl {
None,
RTS,
CTS,
CTSRTS,
MAX,
}
impl From<FlowControl> for uart_hw_flowcontrol_t {
fn from(flow_control: FlowControl) -> Self {
match flow_control {
FlowControl::None => uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_DISABLE,
FlowControl::RTS => uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_RTS,
FlowControl::CTS => uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_CTS,
FlowControl::CTSRTS => uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_CTS_RTS,
FlowControl::MAX => uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_MAX,
}
}
}
impl From<uart_hw_flowcontrol_t> for FlowControl {
#[allow(non_upper_case_globals)]
fn from(flow_control: uart_hw_flowcontrol_t) -> Self {
match flow_control {
uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_DISABLE => FlowControl::None,
uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_RTS => FlowControl::RTS,
uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_CTS => FlowControl::CTS,
uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_CTS_RTS => FlowControl::CTSRTS,
uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_MAX => FlowControl::MAX,
_ => unreachable!(),
}
}
}
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub enum Parity {
ParityNone,
ParityEven,
ParityOdd,
}
impl From<Parity> for uart_parity_t {
fn from(parity: Parity) -> Self {
match parity {
Parity::ParityNone => uart_parity_t_UART_PARITY_DISABLE,
Parity::ParityEven => uart_parity_t_UART_PARITY_EVEN,
Parity::ParityOdd => uart_parity_t_UART_PARITY_ODD,
}
}
}
impl From<uart_parity_t> for Parity {
#[allow(non_upper_case_globals)]
fn from(parity: uart_parity_t) -> Self {
match parity {
uart_parity_t_UART_PARITY_DISABLE => Parity::ParityNone,
uart_parity_t_UART_PARITY_EVEN => Parity::ParityEven,
uart_parity_t_UART_PARITY_ODD => Parity::ParityOdd,
_ => unreachable!(),
}
}
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum StopBits {
STOP1,
STOP1P5,
STOP2,
}
impl From<StopBits> for uart_stop_bits_t {
fn from(stop_bits: StopBits) -> Self {
match stop_bits {
StopBits::STOP1 => uart_stop_bits_t_UART_STOP_BITS_1,
StopBits::STOP1P5 => uart_stop_bits_t_UART_STOP_BITS_1_5,
StopBits::STOP2 => uart_stop_bits_t_UART_STOP_BITS_2,
}
}
}
impl From<uart_stop_bits_t> for StopBits {
#[allow(non_upper_case_globals)]
fn from(stop_bits: uart_stop_bits_t) -> Self {
match stop_bits {
uart_stop_bits_t_UART_STOP_BITS_1 => StopBits::STOP1,
uart_stop_bits_t_UART_STOP_BITS_1_5 => StopBits::STOP1P5,
uart_stop_bits_t_UART_STOP_BITS_2 => StopBits::STOP2,
_ => unreachable!(),
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct Config {
pub baudrate: Hertz,
pub data_bits: DataBits,
pub parity: Parity,
pub stop_bits: StopBits,
pub flow_control: FlowControl,
}
impl Config {
pub fn baudrate(mut self, baudrate: Hertz) -> Self {
self.baudrate = baudrate;
self
}
pub fn parity_none(mut self) -> Self {
self.parity = Parity::ParityNone;
self
}
pub fn parity_even(mut self) -> Self {
self.parity = Parity::ParityEven;
self
}
pub fn parity_odd(mut self) -> Self {
self.parity = Parity::ParityOdd;
self
}
pub fn data_bits(mut self, data_bits: DataBits) -> Self {
self.data_bits = data_bits;
self
}
pub fn stop_bits(mut self, stop_bits: StopBits) -> Self {
self.stop_bits = stop_bits;
self
}
pub fn flow_control(mut self, flow_control: FlowControl) -> Self {
self.flow_control = flow_control;
self
}
}
impl Default for Config {
fn default() -> Config {
Config {
baudrate: Hertz(19_200),
data_bits: DataBits::DataBits8,
parity: Parity::ParityNone,
stop_bits: StopBits::STOP1,
flow_control: FlowControl::None,
}
}
}
}
pub struct Pins<
TX: OutputPin,
RX: InputPin,
CTS: InputPin = crate::gpio::Gpio1<crate::gpio::Input>,
RTS: OutputPin = crate::gpio::Gpio2<crate::gpio::Output>,
> {
pub tx: TX,
pub rx: RX,
pub cts: Option<CTS>,
pub rts: Option<RTS>,
}
pub trait Uart {
fn port() -> uart_port_t;
}
pub struct Serial<
UART: Uart,
TX: OutputPin,
RX: InputPin,
CTS: InputPin = crate::gpio::Gpio1<crate::gpio::Input>,
RTS: OutputPin = crate::gpio::Gpio2<crate::gpio::Output>,
> {
uart: UART,
pins: Pins<TX, RX, CTS, RTS>,
rx: Rx<UART>,
tx: Tx<UART>,
}
pub struct Rx<UART: Uart> {
_uart: PhantomData<UART>,
}
pub struct Tx<UART: Uart> {
_uart: PhantomData<UART>,
}
impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin>
Serial<UART, TX, RX, CTS, RTS>
{
pub fn new(
uart: UART,
pins: Pins<TX, RX, CTS, RTS>,
config: config::Config,
) -> Result<Self, EspError> {
let uart_config = uart_config_t {
baud_rate: config.baudrate.0 as i32,
data_bits: config.data_bits.into(),
parity: config.parity.into(),
stop_bits: config.stop_bits.into(),
flow_ctrl: config.flow_control.into(),
..Default::default()
};
esp!(unsafe { uart_param_config(UART::port(), &uart_config) })?;
esp!(unsafe {
uart_set_pin(
UART::port(),
TX::pin(),
RX::pin(),
if pins.rts.is_some() { RTS::pin() } else { -1 },
if pins.cts.is_some() { CTS::pin() } else { -1 },
)
})?;
esp!(unsafe {
uart_driver_install(
UART::port(),
UART_FIFO_SIZE * 2,
UART_FIFO_SIZE * 2,
0,
ptr::null_mut(),
0,
)
})?;
Ok(Self {
uart,
pins,
rx: Rx { _uart: PhantomData },
tx: Tx { _uart: PhantomData },
})
}
pub fn change_stop_bits(&mut self, stop_bits: config::StopBits) -> Result<&mut Self, EspError> {
esp_result!(
unsafe { uart_set_stop_bits(UART::port(), stop_bits.into()) },
self
)
}
pub fn stop_bits(&self) -> Result<config::StopBits, EspError> {
let mut stop_bits: uart_stop_bits_t = 0;
esp_result!(
unsafe { uart_get_stop_bits(UART::port(), &mut stop_bits) },
stop_bits.into()
)
}
pub fn change_data_bits(&mut self, data_bits: config::DataBits) -> Result<&mut Self, EspError> {
esp_result!(
unsafe { uart_set_word_length(UART::port(), data_bits.into()) },
self
)
}
pub fn data_bits(&self) -> Result<config::DataBits, EspError> {
let mut data_bits: uart_word_length_t = 0;
esp_result!(
unsafe { uart_get_word_length(UART::port(), &mut data_bits) },
data_bits.into()
)
}
pub fn change_parity(&mut self, parity: config::Parity) -> Result<&mut Self, EspError> {
esp_result!(
unsafe { uart_set_parity(UART::port(), parity.into()) },
self
)
}
pub fn parity(&self) -> Result<config::Parity, EspError> {
let mut parity: uart_parity_t = 0;
esp_result!(
unsafe { uart_get_parity(UART::port(), &mut parity) },
parity.into()
)
}
pub fn change_baudrate<T: Into<Hertz> + Copy>(
&mut self,
baudrate: T,
) -> Result<&mut Self, EspError> {
esp_result!(
unsafe { uart_set_baudrate(UART::port(), baudrate.into().into()) },
self
)
}
pub fn baudrate(&self) -> Result<Hertz, EspError> {
let mut baudrate: u32 = 0;
esp_result!(
unsafe { uart_get_baudrate(UART::port(), &mut baudrate) },
baudrate.into()
)
}
pub fn split(self) -> (Tx<UART>, Rx<UART>) {
(self.tx, self.rx)
}
#[allow(clippy::type_complexity)]
pub fn release(self) -> Result<(UART, Pins<TX, RX, CTS, RTS>), EspError> {
esp!(unsafe { uart_driver_delete(UART::port()) })?;
Ok((self.uart, self.pins))
}
}
impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin> serial::Read<u8>
for Serial<UART, TX, RX, CTS, RTS>
{
type Error = EspError;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.rx.read()
}
}
impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin> serial::Write<u8>
for Serial<UART, TX, RX, CTS, RTS>
{
type Error = EspError;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.tx.flush()
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
self.tx.write(byte)
}
}
impl<UART: Uart, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin> core::fmt::Write
for Serial<UART, TX, RX, CTS, RTS>
{
fn write_str(&mut self, s: &str) -> core::fmt::Result {
use embedded_hal::serial::Write;
s.as_bytes()
.iter()
.try_for_each(|c| nb::block!(self.write(*c)))
.map_err(|_| core::fmt::Error)
}
}
impl<UART: Uart> Rx<UART> {
pub fn count(&self) -> Result<u8, EspError> {
let mut size = 0_u32;
esp_result!(
unsafe { uart_get_buffered_data_len(UART::port(), &mut size) },
size as u8
)
}
}
impl<UART: Uart> serial::Read<u8> for Rx<UART> {
type Error = EspError;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
let mut buf: u8 = 0;
match unsafe { uart_read_bytes(UART::port(), &mut buf as *mut u8 as *mut _, 1, 0) } {
1 => Ok(buf),
0 => Err(nb::Error::WouldBlock),
err => Err(nb::Error::Other(EspError::from(err as i32).unwrap())),
}
}
}
impl<UART: Uart> serial::Write<u8> for Tx<UART> {
type Error = EspError;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
match unsafe { uart_wait_tx_done(UART::port(), 0) } as u32 {
ESP_OK => Ok(()),
ESP_ERR_TIMEOUT => Err(nb::Error::WouldBlock),
_ => unreachable!(),
}
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
match unsafe { uart_write_bytes(UART::port(), &byte as *const u8 as *const _, 1) } {
1 => Ok(()),
err => Err(nb::Error::Other(EspError::from(err as i32).unwrap())),
}
}
}
impl<UART: Uart> core::fmt::Write for Tx<UART>
where
Tx<UART>: embedded_hal::serial::Write<u8>,
{
fn write_str(&mut self, s: &str) -> core::fmt::Result {
use embedded_hal::serial::Write;
s.as_bytes()
.iter()
.try_for_each(|c| nb::block!(self.write(*c)))
.map_err(|_| core::fmt::Error)
}
}
macro_rules! impl_uart {
($uart:ident: $port:expr) => {
pub struct $uart;
impl $uart {
pub unsafe fn new() -> Self {
$uart {}
}
}
impl Uart for $uart {
fn port() -> uart_port_t {
$port
}
}
};
}
impl_uart!(UART0: 0);
impl_uart!(UART1: 1);
#[cfg(esp32)]
impl_uart!(UART2: 2);