• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Provides a way to test clearing and querying the size of the serial output buffer.
3 //
4 // USAGE:
5 //
6 // 1. Connect a serial device to your host computer. E.g. an Arduino could be used. It will be able
7 //    to receive data without any specific sketch loaded.
8 // 2. Run this example
9 // 3. Observe the output - it reports how many bytes are waiting to be sent to the connected device
10 // 4. Press the Return key to make the example clear the output buffer. You should see the number
11 //    of bytes queued to send momentarily drop to 0
12 // 5. Try passing different values for the buffer-size argument to see how that affects the speed
13 //    and saturation point of the output buffer
14 // 6. Press Ctrl+D (Unix) or Ctrl+Z (Win) to quit
15 //
16 
17 use std::error::Error;
18 use std::io::{self, Read};
19 use std::panic::panic_any;
20 use std::sync::mpsc;
21 use std::thread;
22 use std::time::Duration;
23 
24 use clap::{Arg, ArgMatches, Command};
25 
26 use serialport::ClearBuffer;
27 
28 const DEFAULT_BLOCK_SIZE: &str = "128";
29 
main()30 fn main() {
31     let block_size_help = format!(
32         "The size in bytes of the block of data to write to the port (default: {} bytes)",
33         DEFAULT_BLOCK_SIZE
34     );
35 
36     let matches = Command::new("Serialport Example - Clear Output Buffer")
37         .about("Reports how many bytes are waiting to be read and allows the user to clear the output buffer")
38         .disable_version_flag(true)
39         .arg(Arg::new("port")
40              .help("The device path to a serial port")
41              .use_value_delimiter(false)
42              .required(true))
43         .arg(Arg::new("baud")
44              .help("The baud rate to connect at")
45              .use_value_delimiter(false)
46              .required(true))
47         .arg(Arg::new("block-size")
48              .help(Some(block_size_help.as_str()))
49              .use_value_delimiter(false)
50              .default_value(DEFAULT_BLOCK_SIZE))
51         .get_matches();
52 
53     let port_name = matches.value_of("port").unwrap();
54     let baud_rate = matches.value_of("baud").unwrap();
55     let block_size = ArgMatches::value_of_t(&matches, "block-size").unwrap_or_else(|e| e.exit());
56 
57     let exit_code = match run(port_name, baud_rate, block_size) {
58         Ok(_) => 0,
59         Err(e) => {
60             println!("Error: {}", e);
61             1
62         }
63     };
64 
65     std::process::exit(exit_code);
66 }
67 
run(port_name: &str, baud_rate: &str, block_size: usize) -> Result<(), Box<dyn Error>>68 fn run(port_name: &str, baud_rate: &str, block_size: usize) -> Result<(), Box<dyn Error>> {
69     let rate = baud_rate
70         .parse::<u32>()
71         .map_err(|_| format!("Invalid baud rate '{}' specified", baud_rate))?;
72 
73     let mut port = serialport::new(port_name, rate)
74         .timeout(Duration::from_millis(10))
75         .open()
76         .map_err(|ref e| format!("Port '{}' not available: {}", &port_name, e))?;
77 
78     let chan_clear_buf = input_service();
79 
80     println!("Connected to {} at {} baud", &port_name, &baud_rate);
81     println!("Ctrl+D (Unix) or Ctrl+Z (Win) to stop. Press Return to clear the buffer.");
82 
83     let block = vec![0; block_size];
84 
85     // This loop writes the block repeatedly, as fast as possible, to try to saturate the
86     // output buffer. If you don't see much data queued to send, try changing the block size.
87     loop {
88         match port.write_all(&block) {
89             Ok(_) => (),
90             Err(ref e) if e.kind() == io::ErrorKind::TimedOut => (),
91             Err(e) => panic!("Error while writing data to the port: {}", e),
92         };
93 
94         match chan_clear_buf.try_recv() {
95             Ok(_) => {
96                 println!("------------------------- Discarding buffer ------------------------- ");
97                 port.clear(ClearBuffer::Output)
98                     .expect("Failed to discard output buffer")
99             }
100             Err(mpsc::TryRecvError::Empty) => (),
101             Err(mpsc::TryRecvError::Disconnected) => {
102                 println!("Stopping.");
103                 break;
104             }
105         }
106 
107         println!(
108             "Bytes queued to send: {}",
109             port.bytes_to_write().expect("Error calling bytes_to_write")
110         );
111     }
112 
113     Ok(())
114 }
115 
input_service() -> mpsc::Receiver<()>116 fn input_service() -> mpsc::Receiver<()> {
117     let (tx, rx) = mpsc::channel();
118 
119     thread::spawn(move || {
120         let mut buffer = [0; 32];
121         loop {
122             // Block awaiting any user input
123             match io::stdin().read(&mut buffer) {
124                 Ok(0) => {
125                     drop(tx); // EOF, drop the channel and stop the thread
126                     break;
127                 }
128                 Ok(_bytes_read) => tx.send(()).unwrap(), // Signal main to clear the buffer
129                 Err(e) => panic_any(e),
130             }
131         }
132     });
133 
134     rx
135 }
136