44
44
//! }
45
45
//! ```
46
46
47
+ #[ cfg( feature = "tokio" ) ]
48
+ extern crate futures;
49
+ #[ cfg( feature = "mio-evented" ) ]
50
+ extern crate mio;
47
51
extern crate nix;
48
52
extern crate regex;
53
+ #[ cfg( feature = "tokio" ) ]
54
+ extern crate tokio_core;
55
+
56
+ #[ cfg( feature = "tokio" ) ]
57
+ use futures:: { Async , Poll , Stream } ;
58
+
59
+ #[ cfg( feature = "mio-evented" ) ]
60
+ use mio:: Evented ;
61
+ #[ cfg( feature = "mio-evented" ) ]
62
+ use mio:: unix:: EventedFd ;
49
63
50
64
use nix:: sys:: epoll:: * ;
51
65
use nix:: unistd:: close;
@@ -57,6 +71,9 @@ use std::fs;
57
71
use std:: fs:: File ;
58
72
use std:: path:: Path ;
59
73
74
+ #[ cfg( feature = "tokio" ) ]
75
+ use tokio_core:: reactor:: { Handle , PollEvented } ;
76
+
60
77
mod error;
61
78
pub use error:: Error ;
62
79
@@ -395,6 +412,44 @@ impl Pin {
395
412
pub fn get_poller ( & self ) -> Result < PinPoller > {
396
413
PinPoller :: new ( self . pin_num )
397
414
}
415
+
416
+ /// Get an AsyncPinPoller object for this pin
417
+ ///
418
+ /// The async pin poller object can be used with the `mio` crate. You should probably call
419
+ /// `set_edge()` before using this.
420
+ ///
421
+ /// This method is only available when the `mio-evented` crate feature is enabled.
422
+ #[ cfg( feature = "mio-evented" ) ]
423
+ pub fn get_async_poller ( & self ) -> Result < AsyncPinPoller > {
424
+ AsyncPinPoller :: new ( self . pin_num )
425
+ }
426
+
427
+ /// Get a Stream of pin interrupts for this pin
428
+ ///
429
+ /// The PinStream object can be used with the `tokio-core` crate. You should probably call
430
+ /// `set_edge()` before using this.
431
+ ///
432
+ /// This method is only available when the `tokio` crate feature is enabled.
433
+ #[ cfg( feature = "tokio" ) ]
434
+ pub fn get_stream ( & self , handle : & Handle ) -> Result < PinStream > {
435
+ PinStream :: init ( self . clone ( ) , handle)
436
+ }
437
+
438
+ /// Get a Stream of pin values for this pin
439
+ ///
440
+ /// The PinStream object can be used with the `tokio-core` crate. You should probably call
441
+ /// `set_edge(Edge::BothEdges)` before using this.
442
+ ///
443
+ /// Note that the values produced are the value of the pin as soon as we get to handling the
444
+ /// interrupt in userspace. Each time this stream produces a value, a change has occurred, but
445
+ /// it could end up producing the same value multiple times if the value has changed back
446
+ /// between when the interrupt occurred and when the value was read.
447
+ ///
448
+ /// This method is only available when the `tokio` crate feature is enabled.
449
+ #[ cfg( feature = "tokio" ) ]
450
+ pub fn get_value_stream ( & self , handle : & Handle ) -> Result < PinValueStream > {
451
+ Ok ( PinValueStream ( try!( PinStream :: init ( self . clone ( ) , handle) ) ) )
452
+ }
398
453
}
399
454
400
455
#[ derive( Debug ) ]
@@ -445,9 +500,9 @@ impl PinPoller {
445
500
/// of interrupts which may result in this call returning
446
501
/// may be configured by calling `set_edge()` prior to
447
502
/// making this call. This call makes use of epoll under the
448
- /// covers. If it is desirable to poll on multiple GPIOs or
449
- /// other event source, you will need to implement that logic
450
- /// yourself .
503
+ /// covers. To poll on multiple GPIOs or other event sources,
504
+ /// poll asynchronously using the integration with either `mio`
505
+ /// or `tokio_core` .
451
506
///
452
507
/// This function will return Some(value) of the pin if a change is
453
508
/// detected or None if a timeout occurs. Note that the value provided
@@ -479,3 +534,108 @@ impl Drop for PinPoller {
479
534
close ( self . epoll_fd ) . unwrap ( ) ; // panic! if close files
480
535
}
481
536
}
537
+
538
+ #[ cfg( feature = "mio-evented" ) ]
539
+ #[ derive( Debug ) ]
540
+ pub struct AsyncPinPoller {
541
+ devfile : File ,
542
+ }
543
+
544
+ #[ cfg( feature = "mio-evented" ) ]
545
+ impl AsyncPinPoller {
546
+ fn new ( pin_num : u64 ) -> Result < Self > {
547
+ let devfile = try!( File :: open ( & format ! ( "/sys/class/gpio/gpio{}/value" , pin_num) ) ) ;
548
+ Ok ( AsyncPinPoller { devfile : devfile } )
549
+ }
550
+ }
551
+
552
+ #[ cfg( feature = "mio-evented" ) ]
553
+ impl Evented for AsyncPinPoller {
554
+ fn register ( & self ,
555
+ poll : & mio:: Poll ,
556
+ token : mio:: Token ,
557
+ interest : mio:: Ready ,
558
+ opts : mio:: PollOpt )
559
+ -> io:: Result < ( ) > {
560
+ EventedFd ( & self . devfile . as_raw_fd ( ) ) . register ( poll, token, interest, opts)
561
+ }
562
+
563
+ fn reregister ( & self ,
564
+ poll : & mio:: Poll ,
565
+ token : mio:: Token ,
566
+ interest : mio:: Ready ,
567
+ opts : mio:: PollOpt )
568
+ -> io:: Result < ( ) > {
569
+ EventedFd ( & self . devfile . as_raw_fd ( ) ) . reregister ( poll, token, interest, opts)
570
+ }
571
+
572
+ fn deregister ( & self , poll : & mio:: Poll ) -> io:: Result < ( ) > {
573
+ EventedFd ( & self . devfile . as_raw_fd ( ) ) . deregister ( poll)
574
+ }
575
+ }
576
+
577
+ #[ cfg( feature = "tokio" ) ]
578
+ pub struct PinStream {
579
+ evented : PollEvented < AsyncPinPoller > ,
580
+ skipped_first_event : bool ,
581
+ }
582
+
583
+ #[ cfg( feature = "tokio" ) ]
584
+ impl PinStream {
585
+ pub fn init ( pin : Pin , handle : & Handle ) -> Result < Self > {
586
+ Ok ( PinStream {
587
+ evented : try!( PollEvented :: new ( try!( pin. get_async_poller ( ) ) , & handle) ) ,
588
+ skipped_first_event : false ,
589
+ } )
590
+ }
591
+ }
592
+
593
+ #[ cfg( feature = "tokio" ) ]
594
+ impl Stream for PinStream {
595
+ type Item = ( ) ;
596
+ type Error = Error ;
597
+
598
+ fn poll ( & mut self ) -> Poll < Option < Self :: Item > , Self :: Error > {
599
+ Ok ( match self . evented . poll_read ( ) {
600
+ Async :: Ready ( ( ) ) => {
601
+ self . evented . need_read ( ) ;
602
+ if self . skipped_first_event {
603
+ Async :: Ready ( Some ( ( ) ) )
604
+ } else {
605
+ self . skipped_first_event = true ;
606
+ Async :: NotReady
607
+ }
608
+ }
609
+ Async :: NotReady => Async :: NotReady ,
610
+ } )
611
+ }
612
+ }
613
+
614
+ #[ cfg( feature = "tokio" ) ]
615
+ pub struct PinValueStream ( PinStream ) ;
616
+
617
+ #[ cfg( feature = "tokio" ) ]
618
+ impl PinValueStream {
619
+ #[ inline]
620
+ fn get_value ( & mut self ) -> Result < u8 > {
621
+ get_value_from_file ( & mut self . 0 . evented . get_mut ( ) . devfile )
622
+ }
623
+ }
624
+
625
+ #[ cfg( feature = "tokio" ) ]
626
+ impl Stream for PinValueStream {
627
+ type Item = u8 ;
628
+ type Error = Error ;
629
+
630
+ fn poll ( & mut self ) -> Poll < Option < Self :: Item > , Self :: Error > {
631
+ match self . 0 . poll ( ) {
632
+ Ok ( Async :: Ready ( Some ( ( ) ) ) ) => {
633
+ let value = try!( self . get_value ( ) ) ;
634
+ Ok ( Async :: Ready ( Some ( value) ) )
635
+ }
636
+ Ok ( Async :: Ready ( None ) ) => Ok ( Async :: Ready ( None ) ) ,
637
+ Ok ( Async :: NotReady ) => Ok ( Async :: NotReady ) ,
638
+ Err ( e) => Err ( e) ,
639
+ }
640
+ }
641
+ }
0 commit comments