1
1
use crate :: {
2
2
coordinator:: { AddressMode , Coordinator , CoordinatorError , LedStatus , ResetType } ,
3
+ serial:: { simple_serial_port:: SimpleSerialPort , SimpleSerial } ,
4
+ subscription:: { Predicate , Subscription , SubscriptionService } ,
3
5
unpi:: {
4
- commands:: { get_command_by_name, ParameterValue , ParametersValueMap } ,
5
- LenTypeInfo , MessageType , Subsystem , UnpiPacket , MAX_FRAME_SIZE ,
6
+ commands:: { get_command_by_name, ParameterValue } ,
7
+ LenTypeInfo , MessageType , Subsystem , UnpiPacket ,
6
8
} ,
7
- utils:: { log, warnn } ,
9
+ utils:: log,
8
10
} ;
9
- use futures:: lock:: Mutex ;
10
- use serialport:: SerialPort ;
11
- use std:: { path:: PathBuf , sync:: Arc , time:: Duration } ;
11
+ use futures:: {
12
+ channel:: oneshot:: { self , Receiver , Sender } ,
13
+ lock:: Mutex ,
14
+ } ;
15
+ use std:: { path:: PathBuf , sync:: Arc } ;
12
16
13
17
//TODO: fix this
14
18
const MAXIMUM_ZIGBEE_PAYLOAD_SIZE : usize = 255 ;
15
19
16
- pub struct CC2531X {
20
+ type Container = Vec < u8 > ;
21
+
22
+ pub struct CC253X < S : SimpleSerial > {
17
23
_supports_led : Option < bool > ,
18
- read : Arc < Mutex < Box < dyn SerialPort > > > ,
19
- write : Arc < Mutex < Box < dyn SerialPort > > > ,
24
+ subscriptions : Arc < Mutex < SubscriptionService < UnpiPacket < Container > > > > ,
25
+ serial : Arc < Mutex < S > > ,
20
26
}
21
27
22
- impl CC2531X {
28
+ impl CC253X < SimpleSerialPort > {
23
29
pub fn from_path ( path : PathBuf , baud_rate : u32 ) -> Result < Self , CoordinatorError > {
24
- let serial = serialport:: new ( path. to_str ( ) . unwrap ( ) , baud_rate)
25
- . timeout ( Duration :: from_millis ( 10 ) )
26
- . open ( )
27
- . map_err ( |_e| CoordinatorError :: SerialOpen ) ?;
30
+ let mut serial = SimpleSerialPort :: new (
31
+ path. to_str ( )
32
+ . ok_or ( CoordinatorError :: Io ( "not a path" . to_string ( ) ) ) ?,
33
+ baud_rate,
34
+ ) ?;
35
+ serial. start ( ) ?;
36
+ let subscriptions = SubscriptionService :: new ( ) ;
28
37
Ok ( Self {
29
- read : Arc :: new ( Mutex :: new (
30
- serial. try_clone ( ) . map_err ( |_e| CoordinatorError :: Io ) ?,
31
- ) ) ,
32
- write : Arc :: new ( Mutex :: new ( serial) ) ,
38
+ serial : Arc :: new ( Mutex :: new ( serial) ) ,
33
39
_supports_led : None ,
40
+ subscriptions : Arc :: new ( Mutex :: new ( subscriptions) ) ,
34
41
} )
35
42
}
43
+ }
36
44
45
+ impl < S : SimpleSerial > CC253X < S > {
37
46
pub async fn wait_for (
38
47
& self ,
39
48
name : & str ,
40
49
message_type : MessageType ,
41
50
subsystem : Subsystem ,
42
51
_timeout : Option < std:: time:: Duration > ,
43
- ) -> Result < ParametersValueMap , CoordinatorError > {
52
+ ) -> Result < UnpiPacket < Container > , CoordinatorError > {
44
53
log ! ( "waiting for {:?}" , name) ;
45
54
let command =
46
55
get_command_by_name ( & subsystem, name) . ok_or ( CoordinatorError :: NoCommandWithName ) ?;
47
- let mut buffer = [ 0 ; MAX_FRAME_SIZE ] ;
48
- let lock = self . read . lock ( ) ;
49
- let len = lock
56
+ let subscriptions = self . subscriptions . clone ( ) ;
57
+ let ( tx, rx) : (
58
+ Sender < UnpiPacket < Container > > ,
59
+ Receiver < UnpiPacket < Container > > ,
60
+ ) = oneshot:: channel ( ) ;
61
+ let packet = rx. await . map_err ( |_| CoordinatorError :: SubscriptionError ) ?;
62
+ subscriptions
63
+ . lock ( )
50
64
. await
51
- . read ( & mut buffer)
52
- . map_err ( |_e| CoordinatorError :: Io ) ?;
53
- let packet = UnpiPacket :: from_payload (
54
- ( & buffer[ ..len] , LenTypeInfo :: OneByte ) ,
55
- ( message_type, subsystem) ,
56
- command. id ,
57
- ) ?;
58
- log ! ( "<<< {:?}" , packet) ;
59
- if packet. type_subsystem == ( message_type, subsystem) && packet. command == command. id {
60
- let response = command. read_and_fill ( packet. payload ) ?;
61
- Ok ( response)
62
- } else {
63
- warnn ! ( "rejecting packet: {:?}" , packet) ;
64
- Err ( CoordinatorError :: Io )
65
- }
65
+ . subscribe ( Subscription :: SingleShot (
66
+ Predicate ( Box :: new ( move |packet : & UnpiPacket < Container > | {
67
+ packet. type_subsystem == ( message_type, subsystem)
68
+ && packet. command == command. id
69
+ } ) ) ,
70
+ tx,
71
+ ) ) ;
72
+ Ok ( packet)
66
73
}
67
74
}
68
75
69
- impl Coordinator for CC2531X {
76
+ impl < S : SimpleSerial > Coordinator for CC253X < S > {
70
77
type ZclFrame = psila_data:: cluster_library:: ClusterLibraryHeader ;
71
78
72
79
type ZclPayload < ' a > = ( [ u8 ; MAXIMUM_ZIGBEE_PAYLOAD_SIZE ] , usize ) ;
@@ -92,20 +99,21 @@ impl Coordinator for CC2531X {
92
99
async fn version ( & self ) -> Result < Option < ParameterValue > , CoordinatorError > {
93
100
let command = get_command_by_name ( & Subsystem :: Sys , "version" )
94
101
. ok_or ( CoordinatorError :: NoCommandWithName ) ?;
102
+ let serial = self . serial . clone ( ) ;
95
103
let send = async {
96
- let mut lock = self . write . lock ( ) . await ;
97
- UnpiPacket :: from_command_to_serial_async (
98
- command. id ,
99
- command,
100
- & [ ] ,
104
+ let packet = UnpiPacket :: from_command_owned (
105
+ LenTypeInfo :: OneByte ,
101
106
( MessageType :: SREQ , Subsystem :: Sys ) ,
102
- & mut * * lock,
103
- )
104
- . await
107
+ & [ ] ,
108
+ command,
109
+ ) ?;
110
+ serial. lock ( ) . await . write ( & packet) . await ?;
111
+ Ok :: < ( ) , CoordinatorError > ( ( ) )
105
112
} ;
106
113
let wait = self . wait_for ( "version" , MessageType :: SRESP , Subsystem :: Sys , None ) ;
107
- let r = futures:: try_join!( send, wait) ?;
108
- Ok ( r. 1 . get ( & "majorrel" ) . cloned ( ) )
114
+ let ( _, packet) = futures:: try_join!( send, wait) ?;
115
+ let r = command. read_and_fill ( packet. payload . as_slice ( ) ) ?;
116
+ Ok ( r. get ( & "majorrel" ) . cloned ( ) )
109
117
}
110
118
111
119
async fn reset ( & self , reset_type : ResetType ) -> Result < ( ) , CoordinatorError > {
@@ -116,24 +124,23 @@ impl Coordinator for CC2531X {
116
124
ResetType :: Hard => & [ ( "type" , ParameterValue :: U8 ( 0 ) ) ] ,
117
125
} ;
118
126
119
- let mut lock = self . write . lock ( ) . await ;
120
- UnpiPacket :: from_command_to_serial (
121
- command . id ,
122
- command ,
127
+ let serial = self . serial . clone ( ) ;
128
+ let packet = UnpiPacket :: from_command_owned (
129
+ LenTypeInfo :: OneByte ,
130
+ ( MessageType :: SREQ , Subsystem :: Sys ) ,
123
131
parameters,
124
- ( MessageType :: SREQ , Subsystem :: Util ) ,
125
- & mut * * lock,
132
+ command,
126
133
) ?;
127
-
128
- Ok ( ( ) )
134
+ serial . lock ( ) . await . write ( & packet ) . await ? ;
135
+ Ok :: < ( ) , CoordinatorError > ( ( ) )
129
136
}
130
137
131
138
async fn set_led ( & self , led_status : LedStatus ) -> Result < ( ) , CoordinatorError > {
132
139
let command = get_command_by_name ( & Subsystem :: Util , "led_control" )
133
140
. ok_or ( CoordinatorError :: NoCommandWithName ) ?;
134
141
//TODO: const firmwareControlsLed = parseInt(this.version.revision) >= 20211029;
135
142
let firmware_controls_led = true ;
136
- let mut lock = self . write . lock ( ) . await ;
143
+
137
144
let parameters = match led_status {
138
145
LedStatus :: Disable => {
139
146
if firmware_controls_led {
@@ -158,14 +165,14 @@ impl Coordinator for CC2531X {
158
165
] ,
159
166
} ;
160
167
161
- UnpiPacket :: from_command_to_serial (
162
- command. id ,
163
- command,
164
- parameters,
168
+ let serial = self . serial . clone ( ) ;
169
+ let packet = UnpiPacket :: from_command_owned (
170
+ LenTypeInfo :: OneByte ,
165
171
( MessageType :: SREQ , Subsystem :: Util ) ,
166
- & mut * * lock,
172
+ parameters,
173
+ command,
167
174
) ?;
168
-
175
+ serial . lock ( ) . await . write ( & packet ) . await ? ;
169
176
Ok ( ( ) )
170
177
}
171
178
@@ -192,14 +199,15 @@ impl Coordinator for CC2531X {
192
199
193
200
let command = get_command_by_name ( & Subsystem :: Zdo , "management_network_update_request" )
194
201
. ok_or ( CoordinatorError :: NoCommandWithName ) ?;
195
- let mut lock = self . write . lock ( ) . await ;
196
- UnpiPacket :: from_command_to_serial (
197
- command. id ,
198
- command,
199
- parameters,
202
+
203
+ let serial = self . serial . clone ( ) ;
204
+ let packet = UnpiPacket :: from_command_owned (
205
+ LenTypeInfo :: OneByte ,
200
206
( MessageType :: SREQ , Subsystem :: Zdo ) ,
201
- & mut * * lock,
207
+ parameters,
208
+ command,
202
209
) ?;
210
+ serial. lock ( ) . await . write ( & packet) . await ?;
203
211
204
212
Ok ( ( ) )
205
213
}
@@ -212,14 +220,15 @@ impl Coordinator for CC2531X {
212
220
213
221
let command = get_command_by_name ( & Subsystem :: Zdo , "stack_tune" )
214
222
. ok_or ( CoordinatorError :: NoCommandWithName ) ?;
215
- let mut lock = self . write . lock ( ) . await ;
216
- UnpiPacket :: from_command_to_serial (
217
- command. id ,
218
- command,
219
- parameters,
223
+
224
+ let serial = self . serial . clone ( ) ;
225
+ let packet = UnpiPacket :: from_command_owned (
226
+ LenTypeInfo :: OneByte ,
220
227
( MessageType :: SREQ , Subsystem :: Zdo ) ,
221
- & mut * * lock,
228
+ parameters,
229
+ command,
222
230
) ?;
231
+ serial. lock ( ) . await . write ( & packet) . await ?;
223
232
Ok ( ( ) )
224
233
}
225
234
0 commit comments