Crate embedded_serial [] [src]

Embedded Serial traits

Traits to describe Serial port (UART) functionality.

A serial port is taken here to mean a device which can send and/or receive data one octet at a time, in order. Octets are represented using the u8 type. We are careful here to talk only in octets, not characters (although if you ASCII or UTF-8 encode your strings, they become a sequence of octets).

This crate contains traits that are suitable for embedded development. This allows developers to produce crates that depend upon generic UART functionality (for example, an AT command interface), allowing the application developer to combine the crate with the specific UART available on their board.

It is similar to the C idea of using the functions getc and putc to decouple the IO device from the library, but in a more Rustic fashion.

Here's an example with the MutBlockingTx trait.

use embedded_serial::MutBlockingTx;

struct SomeStruct<T> { uart: T };

impl<T> SomeStruct<T> where T: MutBlockingTx {
    fn new(uart: T) -> SomeStruct<T> {
        SomeStruct { uart: uart }
    }

    fn write_data(&mut self) -> Result<(), <T as MutBlockingTx>::Error> {
        self.uart.puts(b"AT\n").map_err(|e| e.1)?;
        Ok(())
    }
}

Here's an example with the MutBlockingTxWithTimeout trait.

struct SomeStruct<T> { uart: T };

use embedded_serial::MutBlockingTxWithTimeout;

impl<T> SomeStruct<T> where T: MutBlockingTxWithTimeout {
    fn new(uart: T) -> SomeStruct<T> {
        SomeStruct { uart: uart }
    }

    fn write_data(&mut self, timeout: &<T as MutBlockingTxWithTimeout>::Timeout) -> Result<bool, <T as MutBlockingTxWithTimeout>::Error> {
        let len = self.uart.puts_wait(b"AT\n", timeout).map_err(|e| e.1)?;
        Ok(len == 3)
    }
}

Here's an example with the MutNonBlockingTx trait. You would call the write_data function until it returned Ok(true).

use embedded_serial::MutNonBlockingTx;

struct SomeStruct<T> {
    sent: Option<usize>,
    uart: T
};

impl<T> SomeStruct<T> where T: MutNonBlockingTx {

    fn new(uart: T) -> SomeStruct<T> {
        SomeStruct { uart: uart, sent: Some(0) }
    }

    fn write_data(&mut self) -> Result<bool, <T as MutNonBlockingTx>::Error> {
        let data = b"AT\n";
        if let Some(len) = self.sent {
            match self.uart.puts_try(&data[len..]) {
                // Sent some or more of the data
                Ok(sent) => {
                    let total = len + sent;
                    self.sent = if total == data.len() {
                        None
                    } else {
                        Some(total)
                    };
                    Ok(false)
                }
                // Sent some of the data but errored out
                Err((sent, e)) => {
                    let total = len + sent;
                    self.sent = if total == data.len() {
                        None
                    } else {
                        Some(total)
                    };
                    Err(e)
                }
            }
        } else {
            Ok(true)
        }
    }
}

In this example, we read three octets from a blocking serial port.

use embedded_serial::MutBlockingRx;

pub struct SomeStruct<T> { uart: T }

impl<T> SomeStruct<T> where T: MutBlockingRx {
    pub fn new(uart: T) -> SomeStruct<T> {
        SomeStruct { uart: uart }
    }

    pub fn read_response(&mut self) -> Result<(), <T as MutBlockingRx>::Error> {
        let mut buffer = [0u8; 3];
        // If we got an error, we don't care any many we actually received.
        self.uart.gets(&mut buffer).map_err(|e| e.1)?;
        // process data in buffer here
        Ok(())
    }
}

In this example, we read three octets from a blocking serial port, with a timeout.

use embedded_serial::MutBlockingRxWithTimeout;

pub struct SomeStruct<T> { uart: T }

impl<T> SomeStruct<T> where T: MutBlockingRxWithTimeout {
    pub fn new(uart: T) -> SomeStruct<T> {
        SomeStruct { uart: uart }
    }

    pub fn read_response(&mut self, timeout: &<T as MutBlockingRxWithTimeout>::Timeout) -> Result<bool, <T as MutBlockingRxWithTimeout>::Error> {
        let mut buffer = [0u8; 3];
        // If we got an error, we don't care any many we actually received.
        let len = self.uart.gets_wait(&mut buffer, timeout).map_err(|e| e.1)?;
        // process data in buffer here
        Ok(len == buffer.len())
    }
}

In this example, we read 16 octets from a non-blocking serial port into a vector which grows to contain exactly as much as we have read so far. You would call the read_data function until it returned Ok(true). This differs from the other examples in that we have an immutable reference to our UART instead of owning it.

use embedded_serial::ImmutNonBlockingRx;

struct SomeStruct<'a, T> where T: 'a {
    buffer: Vec<u8>,
    uart: &'a T
};

const CHUNK_SIZE: usize = 4;
const WANTED: usize = 16;

impl<'a, T> SomeStruct<'a, T> where T: ImmutNonBlockingRx {

    fn new(uart: &T) -> SomeStruct<T> {
        SomeStruct { uart: uart, buffer: Vec::new() }
    }

    fn read_data(&mut self) -> Result<bool, <T as ImmutNonBlockingRx>::Error> {
        let mut buffer = [0u8; CHUNK_SIZE];
        if self.buffer.len() < WANTED {
            let needed = WANTED - self.buffer.len();
            let this_time = if needed < CHUNK_SIZE { needed } else { CHUNK_SIZE };
            match self.uart.gets_try(&mut buffer[0..needed]) {
                // Read some or more of the data
                Ok(read) => {
                    self.buffer.extend(&buffer[0..read]);
                    Ok(self.buffer.len() == WANTED)
                }
                // Sent some of the data but errored out
                Err((read, e)) => {
                    self.buffer.extend(&buffer[0..read]);
                    Err(e)
                }
            }
        } else {
            Ok(true)
        }
    }
}

Reexports

pub use MutBlockingTx as BlockingTx;
pub use MutBlockingTxWithTimeout as BlockingTxWithTimeout;
pub use MutNonBlockingTx as NonBlockingTx;
pub use MutBlockingRx as BlockingRx;
pub use MutBlockingRxWithTimeout as BlockingRxWithTimeout;
pub use MutNonBlockingRx as NonBlockingRx;

Traits

ImmutBlockingRx

Implementors of this trait offer octet based serial data reception using a blocking API and requiring a mutable reference to self.

ImmutBlockingRxWithTimeout

Implementors of this trait offer octet based serial data reception using a blocking API with an upper bound on blocking time, and requiring a mutable reference to self.

ImmutBlockingTx

Implementors of this trait offer octet based serial data transmission using a blocking API and only requiring an immutable reference to self.

ImmutBlockingTxWithTimeout

Implementors of this trait offer octet based serial data transmission using a blocking API with an upper bound on blocking time, and requiring a mutable reference to self.

ImmutNonBlockingRx

Implementors of this trait offer octet based serial data reception using a non-blocking API, and requiring a mutable reference to self.

ImmutNonBlockingTx

Implementors of this trait offer octet based serial data transmission using a non-blocking API and requiring a mutable reference to self.

MutBlockingRx

Implementors of this trait offer octet based serial data reception using a blocking API and requiring a mutable reference to self.

MutBlockingRxWithTimeout

Implementors of this trait offer octet based serial data reception using a blocking API with an upper bound on blocking time, and requiring a mutable reference to self.

MutBlockingTx

Implementors of this trait offer octet based serial data transmission using a blocking API and requiring a mutable reference to self.

MutBlockingTxWithTimeout

Implementors of this trait offer octet based serial data transmission using a blocking API with an upper bound on blocking time, and requiring a mutable reference to self.

MutNonBlockingRx

Implementors of this trait offer octet based serial data reception using a non-blocking API, and requiring a mutable reference to self.

MutNonBlockingTx

Implementors of this trait offer octet based serial data transmission using a non-blocking API and requiring a mutable reference to self.