@@ -7,7 +7,8 @@ use crate::models;
7
7
pub type Ws2812SpiDevice = Rewriter < Ws2812SpiImpl > ;
8
8
9
9
pub struct Ws2812SpiImpl {
10
- dev : Spidev ,
10
+ dev : ImplState ,
11
+ notified_error : bool ,
11
12
buf : Vec < u8 > ,
12
13
}
13
14
@@ -16,30 +17,78 @@ const SPI_BYTES_PER_COLOUR: usize = 4;
16
17
const SPI_FRAME_END_LATCH_BYTES : usize = 116 ;
17
18
const BITPAIR_TO_BYTE : [ u8 ; 4 ] = [ 0b10001000 , 0b10001100 , 0b11001000 , 0b11001100 ] ;
18
19
20
+ enum ImplState {
21
+ Pending ( models:: Ws2812Spi ) ,
22
+ Ready ( Spidev ) ,
23
+ }
24
+
25
+ impl ImplState {
26
+ fn as_dev ( & self ) -> Option < & Spidev > {
27
+ match self {
28
+ ImplState :: Ready ( dev) => Some ( dev) ,
29
+ _ => None ,
30
+ }
31
+ }
32
+
33
+ fn try_init ( & mut self ) -> Result < & Spidev , DeviceError > {
34
+ match self {
35
+ ImplState :: Pending ( config) => {
36
+ // Initialize SPI device
37
+ let mut dev = Spidev :: open ( & config. output ) ?;
38
+ let options = SpidevOptions :: new ( )
39
+ . bits_per_word ( 8 )
40
+ . max_speed_hz ( config. rate as _ )
41
+ . mode ( SpiModeFlags :: SPI_MODE_0 )
42
+ . build ( ) ;
43
+ dev. configure ( & options) ?;
44
+
45
+ info ! ( path = %config. output, "initialized SPI device" ) ;
46
+
47
+ * self = Self :: from ( dev) ;
48
+ Ok ( self . as_dev ( ) . unwrap ( ) )
49
+ }
50
+
51
+ ImplState :: Ready ( dev) => Ok ( dev) ,
52
+ }
53
+ }
54
+ }
55
+
56
+ impl From < & models:: Ws2812Spi > for ImplState {
57
+ fn from ( value : & models:: Ws2812Spi ) -> Self {
58
+ Self :: Pending ( value. clone ( ) )
59
+ }
60
+ }
61
+
62
+ impl From < Spidev > for ImplState {
63
+ fn from ( value : Spidev ) -> Self {
64
+ Self :: Ready ( value)
65
+ }
66
+ }
67
+
19
68
#[ async_trait]
20
69
impl WritingDevice for Ws2812SpiImpl {
21
70
type Config = models:: Ws2812Spi ;
22
71
23
72
fn new ( config : & models:: Ws2812Spi ) -> Result < Self , DeviceError > {
24
- // Initialize SPI device
25
- let mut dev = Spidev :: open ( & config. output ) ?;
26
- let options = SpidevOptions :: new ( )
27
- . bits_per_word ( 8 )
28
- . max_speed_hz ( config. rate as _ )
29
- . mode ( SpiModeFlags :: SPI_MODE_0 )
30
- . build ( ) ;
31
- dev. configure ( & options) ?;
32
-
33
73
// Buffer for SPI tranfers
34
74
let buf = vec ! [
35
75
0 ;
36
76
config. hardware_led_count as usize * SPI_BYTES_PER_LED
37
77
+ SPI_FRAME_END_LATCH_BYTES
38
78
] ;
39
79
40
- info ! ( path = %config. output, "initialized SPI device" ) ;
80
+ let mut dev = ImplState :: from ( config) ;
81
+
82
+ // Try to open the device early
83
+ if let Err ( error) = dev. try_init ( ) {
84
+ warn ! ( %error, path = %config. output, "failed to initialize SPI device, will try again later" ) ;
85
+ }
41
86
42
- Ok ( Self { dev, buf } )
87
+ Ok ( Self {
88
+ dev,
89
+ notified_error : false ,
90
+ buf,
91
+ } )
43
92
}
44
93
45
94
async fn set_let_data (
@@ -77,7 +126,21 @@ impl WritingDevice for Ws2812SpiImpl {
77
126
async fn write ( & mut self ) -> Result < ( ) , DeviceError > {
78
127
// Perform SPI transfer
79
128
let mut transfer = SpidevTransfer :: write ( & self . buf ) ;
80
- self . dev . transfer ( & mut transfer) ?;
129
+
130
+ // Try writing to the device
131
+ match self . dev . try_init ( ) {
132
+ Ok ( dev) => {
133
+ self . notified_error = false ;
134
+ dev. transfer ( & mut transfer) ?;
135
+ }
136
+ Err ( err) => {
137
+ if !self . notified_error {
138
+ self . notified_error = true ;
139
+ error ! ( error = %err, "failed to initialize SPI device" ) ;
140
+ }
141
+ }
142
+ }
143
+
81
144
Ok ( ( ) )
82
145
}
83
146
}
0 commit comments