File: clear_output_buffer.rs

package info (click to toggle)
rust-serialport 4.8.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 844 kB
  • sloc: makefile: 2
file content (135 lines) | stat: -rw-r--r-- 4,605 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//
// Provides a way to test clearing and querying the size of the serial output buffer.
//
// USAGE:
//
// 1. Connect a serial device to your host computer. E.g. an Arduino could be used. It will be able
//    to receive data without any specific sketch loaded.
// 2. Run this example
// 3. Observe the output - it reports how many bytes are waiting to be sent to the connected device
// 4. Press the Return key to make the example clear the output buffer. You should see the number
//    of bytes queued to send momentarily drop to 0
// 5. Try passing different values for the buffer-size argument to see how that affects the speed
//    and saturation point of the output buffer
// 6. Press Ctrl+D (Unix) or Ctrl+Z (Win) to quit
//

use std::error::Error;
use std::io::{self, Read};
use std::panic::panic_any;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use clap::{Arg, ArgMatches, Command};

use serialport::ClearBuffer;

const DEFAULT_BLOCK_SIZE: &str = "128";

fn main() {
    let block_size_help = format!(
        "The size in bytes of the block of data to write to the port (default: {} bytes)",
        DEFAULT_BLOCK_SIZE
    );

    let matches = Command::new("Serialport Example - Clear Output Buffer")
        .about("Reports how many bytes are waiting to be read and allows the user to clear the output buffer")
        .disable_version_flag(true)
        .arg(Arg::new("port")
             .help("The device path to a serial port")
             .use_value_delimiter(false)
             .required(true))
        .arg(Arg::new("baud")
             .help("The baud rate to connect at")
             .use_value_delimiter(false)
             .required(true))
        .arg(Arg::new("block-size")
             .help(Some(block_size_help.as_str()))
             .use_value_delimiter(false)
             .default_value(DEFAULT_BLOCK_SIZE))
        .get_matches();

    let port_name = matches.value_of("port").unwrap();
    let baud_rate = matches.value_of("baud").unwrap();
    let block_size = ArgMatches::value_of_t(&matches, "block-size").unwrap_or_else(|e| e.exit());

    let exit_code = match run(port_name, baud_rate, block_size) {
        Ok(_) => 0,
        Err(e) => {
            println!("Error: {}", e);
            1
        }
    };

    std::process::exit(exit_code);
}

fn run(port_name: &str, baud_rate: &str, block_size: usize) -> Result<(), Box<dyn Error>> {
    let rate = baud_rate
        .parse::<u32>()
        .map_err(|_| format!("Invalid baud rate '{}' specified", baud_rate))?;

    let mut port = serialport::new(port_name, rate)
        .timeout(Duration::from_millis(10))
        .open()
        .map_err(|ref e| format!("Port '{}' not available: {}", &port_name, e))?;

    let chan_clear_buf = input_service();

    println!("Connected to {} at {} baud", &port_name, &baud_rate);
    println!("Ctrl+D (Unix) or Ctrl+Z (Win) to stop. Press Return to clear the buffer.");

    let block = vec![0; block_size];

    // This loop writes the block repeatedly, as fast as possible, to try to saturate the
    // output buffer. If you don't see much data queued to send, try changing the block size.
    loop {
        match port.write_all(&block) {
            Ok(_) => (),
            Err(ref e) if e.kind() == io::ErrorKind::TimedOut => (),
            Err(e) => panic!("Error while writing data to the port: {}", e),
        };

        match chan_clear_buf.try_recv() {
            Ok(_) => {
                println!("------------------------- Discarding buffer ------------------------- ");
                port.clear(ClearBuffer::Output)
                    .expect("Failed to discard output buffer")
            }
            Err(mpsc::TryRecvError::Empty) => (),
            Err(mpsc::TryRecvError::Disconnected) => {
                println!("Stopping.");
                break;
            }
        }

        println!(
            "Bytes queued to send: {}",
            port.bytes_to_write().expect("Error calling bytes_to_write")
        );
    }

    Ok(())
}

fn input_service() -> mpsc::Receiver<()> {
    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        let mut buffer = [0; 32];
        loop {
            // Block awaiting any user input
            match io::stdin().read(&mut buffer) {
                Ok(0) => {
                    drop(tx); // EOF, drop the channel and stop the thread
                    break;
                }
                Ok(_bytes_read) => tx.send(()).unwrap(), // Signal main to clear the buffer
                Err(e) => panic_any(e),
            }
        }
    });

    rx
}