Git Product home page Git Product logo

hadusos-protocol's Introduction

Hadusos - A half-duplex session over serial protocol.

The client should provide a serial device instance and a timer instance, which respectively implements the Serial and Timer trait. Then, a session layer instance can be constructed.

The Session supports half-duplex data transmission, i.e., a client operates as either the sender or the receiver at a time. When operating as the sender, the client should call send to send data. When operating as the receiver, the client should call listen to learn the incoming data length to allocate a buffer, and subsequently call receive to receive the data. The receiver may also call reject if it does not want to proceed to receiving the data after listen.

Below shows an example.

use crossbeam::channel::{self, Receiver, RecvError, SendError, Sender};
use hadusos::{Serial, SerialError, Session, Timer};
use std::{
    sync::Arc,
    thread,
    time::{Duration, SystemTime, UNIX_EPOCH},
};

fn main() {
    // Create a pair of connected serial devices.
    let (serial0, serial1) = MockSerial::new_pair();

    // Create two timers.
    let (timer0, timer1) = (MockTimer, MockTimer);

    const TIMEOUT: u32 = 1000;

    // Start a thread what will echo back whatever it receives.
    let thread_echo = thread::spawn(|| {
        // Create a session layer instance using the serial device and timer.
        let mut sess = Session::<_, _, 50, 3>::new(serial0, timer0);

        // Listen for incoming data.
        let data_len = sess.listen(TIMEOUT).unwrap();

        // Allocate a buffer and receive incoming data.
        let mut buffer = vec![0u8; data_len as usize].into_boxed_slice();
        sess.receive(&mut buffer, TIMEOUT).unwrap();

        // Echo the data back.
        sess.send(&buffer, TIMEOUT).unwrap();
    });

    // Start a thread that will send "hello world!" over the serial and verify
    // the echoed data.
    let thread_check = thread::spawn(|| {
        // Create a session layer instance using the serial device and timer.
        let mut sess = Session::<_, _, 50, 3>::new(serial1, timer1);

        // Send "hello world!".
        sess.send("hello world!".as_bytes(), TIMEOUT).unwrap();

        // Listen for echoed data.
        let data_len = sess.listen(TIMEOUT).unwrap();

        // Allocate a buffer and receive echoed data.
        let mut buffer = vec![0u8; data_len as usize].into_boxed_slice();
        sess.receive(&mut buffer, TIMEOUT).unwrap();

        // Verify echoed data.
        assert!(buffer.as_ref() == "hello world!".as_bytes());
    });

    thread_echo.join().unwrap();
    thread_check.join().unwrap();
}

/// Simulated timer.
struct MockTimer;

impl Timer for MockTimer {
    /// Get the timestamp from the std library.
    fn get_timestamp_ms(&mut self) -> u32 {
        SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_millis() as u32
    }
}

/// Simulated serial device. It is simulated with `crossbeam`'s MPMC queues.
struct MockSerial {
    send: Arc<Sender<u8>>,
    recv: Arc<Receiver<u8>>,
}

impl MockSerial {
    /// Get a pair of connected serial devices.
    fn new_pair() -> (Self, Self) {
        // Create channels to send in both directions.
        let (send0, recv0) = channel::unbounded();
        let (send1, recv1) = channel::unbounded();

        // Wrap the endpoints in `Arc`s.
        let send0 = Arc::new(send0);
        let send1 = Arc::new(send1);
        let recv0 = Arc::new(recv0);
        let recv1 = Arc::new(recv1);

        // Deliberately keep the reference counts to be always positive, so
        // that the channels will always be kept alive, otherwise we will get
        // channel disconnection errors.
        std::mem::forget(Arc::clone(&send0));
        std::mem::forget(Arc::clone(&send1));
        std::mem::forget(Arc::clone(&recv0));
        std::mem::forget(Arc::clone(&recv1));

        (
            Self {
                send: send0,
                recv: recv1,
            },
            Self {
                send: send1,
                recv: recv0,
            },
        )
    }
}

impl Serial for MockSerial {
    type ReadError = RecvError;
    type WriteError = SendError<u8>;

    /// Read a byte from the channel with a timeout.
    fn read_byte_with_timeout(
        &mut self,
        timeout_ms: u32,
    ) -> Result<u8, SerialError<Self::ReadError, Self::WriteError>> {
        // Read byte from the channel. MUST map the timeout error to the
        // specific `SerialError` variant because the protocol stack treats
        // timeout error in a special way as it is sometimes recoverable.
        self.recv
            .recv_timeout(Duration::from_millis(timeout_ms as u64))
            .map_err(|e| match e {
                channel::RecvTimeoutError::Timeout => SerialError::Timeout,
                channel::RecvTimeoutError::Disconnected => SerialError::ReadError(RecvError),
            })
    }

    /// Write a byte to the channel.
    fn write_byte(
        &mut self,
        byte: u8,
    ) -> Result<(), SerialError<Self::ReadError, Self::WriteError>> {
        self.send.send(byte).map_err(|e| SerialError::WriteError(e))
    }
}

hadusos-protocol's People

Contributors

ouhznehc avatar zhiyaoma98 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.