arduino_threads/
arduino_threads.rs

1extern crate std_semaphore;
2extern crate serial;
3extern crate robust_arduino_serial;
4use std::io::ErrorKind;
5use std::env;
6use std::time::Duration;
7use std::thread;
8use std::sync::{Arc, Mutex};
9use std::sync::mpsc;
10use std_semaphore::Semaphore;
11use serial::prelude::*;
12use robust_arduino_serial::*;
13
14// Default settings of Arduino
15// see: https://www.arduino.cc/en/Serial/Begin
16const SETTINGS: serial::PortSettings = serial::PortSettings {
17    baud_rate:    serial::Baud115200,
18    char_size:    serial::Bits8,
19    parity:       serial::ParityNone,
20    stop_bits:    serial::Stop1,
21    flow_control: serial::FlowNone,
22};
23
24
25fn main() {
26
27    let args: Vec<String> = env::args().skip(1).collect();
28
29    if args.len() < 1
30    {
31        panic!("Please provide a serial port as argument (ex: /dev/ttyACM0)");
32    }
33    let serial_port = &args[0];
34
35    println!("Opening port: {:?}", serial_port);
36    let mut port = serial::open(&serial_port).unwrap();
37    port.configure(&SETTINGS).unwrap();
38    // timeout of 1ms
39    port.set_timeout(Duration::from_millis(1)).unwrap();
40
41    loop
42    {
43        println!("Waiting for Arduino...");
44        write_order(&mut port, Order::HELLO).unwrap();
45        let received_order = match read_i8(&mut port) {
46            Ok(order) => Order::from_i8(order).unwrap(),
47            Err(ref e) if e.kind() == ErrorKind::TimedOut => {
48                // If we have a read timeout, wait a bit
49                thread::sleep(Duration::from_secs(2));
50                continue
51                }
52            Err(e) => {
53                    panic!("An error occured reading serial port: {}", e)
54                }
55
56        };
57
58        if received_order == Order::ALREADY_CONNECTED
59        {
60            break;
61        }
62        thread::sleep(Duration::from_secs(1));
63    }
64
65    println!("Connected to Arduino");
66
67    // Channel to send and receive commands
68    let (command_sender, command_receiver) = mpsc::channel();
69    let command_queue = mpsc::Sender::clone(&command_sender);
70
71    // Wrap the serial to use it in the threads
72    let serial_arc = Arc::new(Mutex::new(port));
73    let serial_command = serial_arc.clone();
74
75    // Exit event to notify thread when they should exit
76    let exit_event = false;
77    // Wrap the boolean to use it in the threads
78    let exit_arc = Arc::new(Mutex::new(exit_event));
79    let exit_listener = exit_arc.clone();
80    let exit_command = exit_arc.clone();
81
82    // Semaphore to avoid Arduino buffer overflow:
83    // Do not send new order if the Arduino did not aknowledge
84    // the previous message
85    let n_allowed_messages = 2;
86    let semaphore = Arc::new(Semaphore::new(n_allowed_messages));
87    let semaphore_command = semaphore.clone();
88
89    let mut threads = vec![];
90
91    // Command thread listen to the command Channel
92    // and send orders to the Arduino
93    let command_thread = thread::spawn(move || {
94        let mut exit = false;
95        while !exit
96        {
97            // Decrement the semaphore counter
98            // each time we send an order
99            semaphore.acquire();
100            let (order, num) = command_receiver.recv().unwrap();
101
102            println!("Sending: {:?}, {}", order, num);
103
104            // Acquire lock on the buffer
105            let mut buffer = serial_command.lock().unwrap();
106
107            write_order(&mut *buffer, order).unwrap();
108            match order {
109                Order::MOTOR => write_i8(&mut *buffer, num as i8).unwrap(),
110                Order::SERVO => write_i16(&mut *buffer, num as i16).unwrap(),
111                _ => 0  // Write 0 bytes
112            };
113            exit = *exit_command.lock().unwrap();
114        }
115        println!("Command Thread exiting...");
116    });
117
118    threads.push(command_thread);
119
120    // Listener thread listens to the Arduino
121    // it release the semaphore when an aknowledgement is received
122    let listener_thread = thread::spawn(move || {
123
124        let mut exit = false;
125        let mut wait = false;
126        while !exit
127        {
128            // Wait a bit so the command thread can acquire the lock
129            if wait
130            {
131                thread::sleep(Duration::from_millis(100));
132            }
133
134            // Acquire lock on the serial object
135            let mut buffer = serial_arc.lock().unwrap();
136
137            // Receive order from arduino
138            let received_order = match read_i8(&mut *buffer) {
139                Ok(order) => Order::from_i8(order).unwrap(),
140                Err(_) => {
141                        wait = true;
142                        continue
143                    }
144
145            };
146            wait = false;
147
148            println!("Received: {:?}", received_order);
149
150            match received_order {
151                Order::RECEIVED => semaphore_command.release(),
152                _ => ()
153            }
154
155            exit = *exit_listener.lock().unwrap();
156        }
157        println!("Listener Thread exiting...");
158    });
159
160    threads.push(listener_thread);
161
162    thread::sleep(Duration::from_secs(1));
163    // Send Orders to the Arduino
164    command_queue.send((Order::MOTOR, 42_i32)).unwrap();
165    command_queue.send((Order::SERVO, 120_i32)).unwrap();
166
167    // Wait a bit before shutting down the threads
168    thread::sleep(Duration::from_secs(2));
169
170    // Stop the motor
171    command_queue.send((Order::MOTOR, 0_i32)).unwrap();
172
173
174    // Notify the threads that they should exit
175    {
176        *exit_arc.lock().unwrap() = true;
177    }
178
179    // Send dummy orders to exit the command thread
180    command_queue.send((Order::HELLO, 0_i32)).unwrap();
181
182    for t in threads
183    {
184        t.join().unwrap();
185    }
186}