Browse Source

Implémentation de la connexion série.

Paul Florence 11 months ago
parent
commit
1349ab9ec0

+ 4
- 0
.cargo/config View File

@@ -0,0 +1,4 @@
1
+[target.x86_64-pc-windows-gnu]
2
+linker = "x86_64-w64-mingw32-gcc"
3
+ar = "x86_64-w64-mingw32-gcc-ar"
4
+rustflags = ["-L /opt/gtkwin/lib"]

+ 2
- 0
.gitignore View File

@@ -5,6 +5,8 @@
5 5
 *.rlib
6 6
 *.dll
7 7
 *.json
8
+*.zip
9
+/windows_release/
8 10
 
9 11
 # Executables
10 12
 *.exe

robot_debugger/make_release.sh → make_release.sh View File


+ 1
- 1
robot_core/Cargo.toml View File

@@ -9,5 +9,5 @@ slog-stdlog="3.0"
9 9
 bufstream = "0.1"
10 10
 serde = "1.0"
11 11
 serde_derive ="1.0"
12
-serialport = { git = "https://gitlab.com/gbip/serialport-rs" }
12
+serialport = { path = "/home/paul/repos/contributions/serialport-rs" }
13 13
 lazy_static = "1.0.0"

+ 47
- 24
robot_core/src/communication.rs View File

@@ -19,9 +19,6 @@ use slog::Drain;
19 19
 use serialport;
20 20
 use serialport::prelude::*;
21 21
 
22
-
23
-use serialport::posix::TTYPort;
24
-
25 22
 use bufstream::BufStream;
26 23
 
27 24
 use slog::Logger;
@@ -48,6 +45,15 @@ impl ClonableStream for TcpStream {
48 45
     }
49 46
 }
50 47
 
48
+impl ClonableStream for Box<SerialPort> {
49
+    fn try_clone_c(&self) -> Result<Box<SerialPort>, Box<Error>> {
50
+        match self.try_clone() {
51
+            Ok(val) => Ok(val),
52
+            Err(e) => Err(e.into()),
53
+        }
54
+    }
55
+}
56
+
51 57
 impl<T> ClonableStream for BufStream<T>
52 58
 where
53 59
     T: Read + Write + ClonableStream,
@@ -65,9 +71,15 @@ fn open_stream<T: AsRef<str>, L: Into<Option<Logger>>>(
65 71
     receiver: Receiver<Trame>,
66 72
 ) -> Result<(), Box<Error>> {
67 73
     if let Ok(tcp_stream) = TcpStream::connect(path.as_ref()) {
68
-        Ok(stream::open(tcp_stream, logger, handlers, receiver))
69
-    } else if let Ok(_) = serialport::open(path.as_ref()) {
70
-        Err(From::from("Serial connection is not supported yet."))
74
+        match stream::open(tcp_stream, logger, handlers, receiver) {
75
+            Ok(_) => Ok(()),
76
+            Err(e) => Err(e.into()),
77
+        }
78
+    } else if let Ok(serial_stream) = serialport::open(path.as_ref()) {
79
+        match stream::open(serial_stream, logger, handlers, receiver) {
80
+            Ok(_) => Ok(()),
81
+            Err(e) => Err(e.into()),
82
+        }
71 83
     } else {
72 84
         Err(From::from("Failed to open connection."))
73 85
     }
@@ -177,10 +189,14 @@ impl ConnectionBuilder {
177 189
 
178 190
     /// Consomme un `ConnectionBuilder` et un stream pour créer une nouvelle connection.
179 191
     pub fn open_from_stream<T>(self, stream: T)
192
+        -> Result<(),Box<Error>>
180 193
     where
181 194
         T: Read + Write + ClonableStream + Send + Sync + 'static,
182 195
     {
183
-        stream::open(stream, self.logger, self.handlers, self.receiver);
196
+        match stream::open(stream, self.logger, self.handlers, self.receiver) {
197
+            Ok(_) => Ok(()),
198
+            Err(e) => Err(e.into()),
199
+        }
184 200
     }
185 201
 
186 202
     /// Consomme un `ConnectionBuilder` et essaie d'ouvrir une connection série ou une connection
@@ -207,7 +223,7 @@ mod stream {
207 223
         logger: L,
208 224
         handlers: Vec<Arc<TrameHandler + Send + Sync>>,
209 225
         receiver: Receiver<Trame>,
210
-    ) where
226
+    ) -> Result<(),String> where
211 227
         T: Read + Write + ClonableStream + Send + 'static,
212 228
     {
213 229
         let stream = BufStream::new(stream);
@@ -215,18 +231,25 @@ mod stream {
215 231
         let log = logger.into().unwrap_or_else(|| {
216 232
             Logger::root(slog_stdlog::StdLog.fuse(), o!())
217 233
         });
218
-        start_listening_loop(
219
-            stream.try_clone_c().unwrap(),
220
-            Arc::clone(&stop),
221
-            handlers,
222
-            log.clone(),
223
-        );
224
-        start_writing_loop(
225
-            stream.try_clone_c().unwrap(),
226
-            Arc::clone(&stop),
227
-            receiver,
228
-            log.clone(),
229
-        );
234
+
235
+        match stream.try_clone_c() {
236
+            Ok(stream_clone) => {
237
+                start_listening_loop(
238
+                    stream_clone,
239
+                    Arc::clone(&stop),
240
+                    handlers,
241
+                    log.clone(),
242
+                    );
243
+                start_writing_loop(
244
+                    stream,
245
+                    Arc::clone(&stop),
246
+                    receiver,
247
+                    log.clone(),
248
+                    );
249
+                Ok(())
250
+            }
251
+            Err(e) => Err(format!("Failed to enable duplex : {}",e.description())),
252
+        }
230 253
     }
231 254
 
232 255
     /// Fonction bloquante qui lis une trame depuis le stream.
@@ -383,7 +406,7 @@ impl StandardStream {
383 406
     }
384 407
 
385 408
     /// Permet de créer un `StandardStream` à partir d'un stream existant.
386
-    pub fn new_from_stream<T, L: Into<Option<Logger>>>(stream: T, logger: L) -> StandardStream
409
+    pub fn new_from_stream<T, L: Into<Option<Logger>>>(stream: T, logger: L) -> Result<StandardStream,Box<Error>>
387 410
     where
388 411
         T: Read + Write + ClonableStream + Send + Sync + 'static,
389 412
     {
@@ -391,14 +414,14 @@ impl StandardStream {
391 414
         let mut builder = ConnectionBuilder::new();
392 415
         builder.register_handler(Arc::new(DefaultHandler::new(Arc::clone(&vec))));
393 416
         let connection = builder.get_sender();
394
-        builder.open_from_stream(stream);
395
-        StandardStream {
417
+        builder.open_from_stream(stream)?;
418
+        Ok(StandardStream {
396 419
             connection: connection,
397 420
             trames: vec,
398 421
             log: logger.into().unwrap_or_else(|| {
399 422
                 Logger::root(slog_stdlog::StdLog.fuse(), o!())
400 423
             }),
401
-        }
424
+        })
402 425
     }
403 426
 
404 427
     /// Fonction non bloquante qui permet de récupérer une trame.

+ 2
- 0
robot_core/src/robot_modules/mod.rs View File

@@ -0,0 +1,2 @@
1
+pub mod servo;
2
+pub mod modules;

+ 82
- 0
robot_core/src/robot_modules/modules.rs View File

@@ -0,0 +1,82 @@
1
+use std::sync::{Arc, Mutex};
2
+use std::sync::atomic::{AtomicBool, Ordering};
3
+use std::sync::mpsc::Sender;
4
+use std::error::Error;
5
+
6
+use slog_stdlog;
7
+use slog::{Drain, Logger};
8
+
9
+use trame::Trame;
10
+
11
+/// Représente des modules gérant des trames.
12
+pub trait TrameHandler {
13
+    /// Cette fonction est appellée pour qu'un module s'occupe d'une `Trame`.
14
+    fn handle(&self, trame: &Trame);
15
+}
16
+
17
+impl<T> TrameHandler for Mutex<T>
18
+where
19
+    T: TrameHandler,
20
+{
21
+    fn handle(&self, trame: &Trame) {
22
+        self.lock().unwrap().handle(trame);
23
+    }
24
+}
25
+
26
+/// Un module de base qui implémente le ping et l'envoie de trame.
27
+/// Est conçu pour être réutilisé par composition dans d'autres modules.
28
+pub struct StandardModule {
29
+    has_pong: AtomicBool,
30
+    sender: Sender<Trame>,
31
+    id: u8,
32
+    logger: Logger,
33
+}
34
+
35
+impl TrameHandler for StandardModule {
36
+    fn handle(&self, trame: &Trame) {
37
+        if trame.id == self.id {
38
+            if trame.cmd == 0xaa && !self.has_pong.load(Ordering::Relaxed) {
39
+                self.has_pong.store(true, Ordering::Relaxed)
40
+            }
41
+        }
42
+    }
43
+}
44
+
45
+impl StandardModule {
46
+    /// Envoie une trame.
47
+    ///
48
+    /// # Erreur
49
+    ///
50
+    /// Renvoie une erreur quand la connection à été fermée.
51
+    pub fn send_trame(&self, trame: Trame) -> Result<(), Box<Error>> {
52
+        if let Err(e) = self.sender.send(trame) {
53
+            Err(From::from(e))
54
+        } else {
55
+            Ok(())
56
+        }
57
+    }
58
+
59
+    /// Envoie un message de ping.
60
+    pub fn ping(&self) {
61
+        if let Err(_) = self.send_trame(Trame::new_ping(self.id)) {
62
+            warn!(
63
+                self.logger,
64
+                "Impossible d'envoyer la trame car la connection a été fermée"
65
+            );
66
+        }
67
+    }
68
+
69
+    pub(crate) fn new_from_sender(
70
+        id: u8,
71
+        sender: Sender<Trame>,
72
+        logger: Option<Logger>,
73
+    ) -> Arc<Mutex<StandardModule>> {
74
+        let result = StandardModule {
75
+            sender: sender,
76
+            id: id,
77
+            logger: logger.unwrap_or_else(|| Logger::root(slog_stdlog::StdLog.fuse(), o!())),
78
+            has_pong: AtomicBool::new(false),
79
+        };
80
+        Arc::new(Mutex::new(result))
81
+    }
82
+}

+ 106
- 0
robot_core/src/robot_modules/servo.rs View File

@@ -0,0 +1,106 @@
1
+use std::sync::atomic::{AtomicBool, Ordering};
2
+use std::sync::Mutex;
3
+
4
+use angular_units;
5
+use angular_units::{Angle, FromAngle};
6
+
7
+use num::Zero;
8
+
9
+use slog::Logger;
10
+
11
+use robot_modules::modules::StandardModule;
12
+use trame::Trame;
13
+use Rad;
14
+
15
+
16
+const NUMBER_OF_SERVO: usize = 8;
17
+const ID_SERVO: u8 = 42;
18
+
19
+/// Le comportement d'un servomoteur quand il rencontre un obstacle.
20
+pub enum BlockingBehavior {
21
+    /// Le servomoteur va forcer pour maintenir la pression.
22
+    HoldOnBlock,
23
+    /// Le servomoteur va relâcher la pression.
24
+    NoBlock,
25
+}
26
+
27
+/// Indique si une position est à jour ou non.
28
+/// Si une position n'est pas à jour, il faut la demander à la carte.
29
+#[derive(Clone, Copy)]
30
+enum PositionStatus {
31
+    UpToDate,
32
+    NeedRefresh,
33
+}
34
+
35
+/// La structure de donnée qui contiens l'état d'un servo.
36
+struct ServoStatus {
37
+    done: AtomicBool,
38
+    blocked: AtomicBool,
39
+    position_status: Mutex<PositionStatus>,
40
+    position: Mutex<Rad>,
41
+}
42
+
43
+impl ServoStatus {
44
+    fn set_status(&self, status: bool) {
45
+        self.done.store(status, Ordering::Relaxed);
46
+    }
47
+
48
+    fn set_blocked(&self, blocked: bool) {
49
+        self.blocked.store(blocked, Ordering::Relaxed);
50
+    }
51
+
52
+    fn set_position_status(&self, status: PositionStatus) {
53
+        *self.position_status.lock().unwrap() = status;
54
+    }
55
+
56
+    fn set_position<T>(&self, position: T)
57
+    where
58
+        Rad: FromAngle<T>,
59
+        T: Angle,
60
+    {
61
+        *self.position.lock().unwrap() = Rad::from_angle(position);
62
+    }
63
+
64
+    fn get_status(&self) -> bool {
65
+        self.done.load(Ordering::Relaxed)
66
+    }
67
+
68
+    fn get_blocked(&self) -> bool {
69
+        self.blocked.load(Ordering::Relaxed)
70
+    }
71
+
72
+    fn get_position_status(&self) -> PositionStatus {
73
+        *self.position_status.lock().unwrap()
74
+    }
75
+
76
+    fn get_position(&self) -> Rad {
77
+        *self.position.lock().unwrap()
78
+    }
79
+}
80
+
81
+impl Default for ServoStatus {
82
+    fn default() -> Self {
83
+        ServoStatus {
84
+            done: AtomicBool::new(true),
85
+            blocked: AtomicBool::new(false),
86
+            position_status: Mutex::new(PositionStatus::UpToDate),
87
+            position: Mutex::new(Rad::zero()),
88
+        }
89
+    }
90
+}
91
+
92
+pub struct Servo {
93
+    communicator: StandardModule,
94
+    status: [ServoStatus; NUMBER_OF_SERVO],
95
+    logger: Logger,
96
+}
97
+
98
+impl Servo {
99
+    fn new<L: Into<Option<Logger>>>(sender: Sender<Trame>, logger: L) -> Servo {
100
+        Servo {
101
+            logger: logger.unwrap_or_else(|| Logger::root(slog_stdlog::StdLog.fuse(), o!())),
102
+            communicator: StandardModule::new_from_sender(sender),
103
+            status: [ServoStatus::default; 8],
104
+        }
105
+    }
106
+}

Loading…
Cancel
Save