1
- use std:: io:: Cursor ;
2
1
use std:: sync:: { Arc , Mutex } ;
3
2
use std:: thread:: sleep;
4
3
use std:: time:: Duration ;
5
4
6
5
use anyhow:: Result ;
7
6
use async_trait:: async_trait;
8
- use chirpstack_api:: gw ;
7
+ use chirpstack_api:: { gw , prost :: Message } ;
9
8
use log:: { debug, error, info, trace, warn} ;
10
- use prost:: Message ;
11
9
use tokio:: task;
12
10
13
11
use super :: Backend as BackendTrait ;
14
12
use crate :: config:: Configuration ;
15
13
use crate :: metadata;
16
- use crate :: mqtt:: { send_gateway_stats, send_mesh_heartbeat , send_tx_ack, send_uplink_frame} ;
14
+ use crate :: mqtt:: { send_gateway_stats, send_mesh_event , send_tx_ack, send_uplink_frame} ;
17
15
18
16
pub struct Backend {
19
17
gateway_id : String ,
@@ -45,26 +43,31 @@ impl Backend {
45
43
46
44
info ! ( "Reading gateway id" ) ;
47
45
48
- // send 'gateway_id' command with empty payload.
49
- cmd_sock. send ( "gateway_id" , zmq:: SNDMORE ) ?;
50
- cmd_sock. send ( "" , 0 ) ?;
46
+ // Request Gateway ID.
47
+ let req = gw:: Command {
48
+ command : Some ( gw:: command:: Command :: GetGatewayId (
49
+ gw:: GetGatewayIdRequest { } ,
50
+ ) ) ,
51
+ } ;
52
+ cmd_sock. send ( req. encode_to_vec ( ) , 0 ) ?;
51
53
52
54
// set poller so that we can timeout after 100ms
53
55
let mut items = [ cmd_sock. as_poll_item ( zmq:: POLLIN ) ] ;
54
56
zmq:: poll ( & mut items, 100 ) ?;
55
57
if !items[ 0 ] . is_readable ( ) {
56
58
return Err ( anyhow ! ( "Could not read gateway id" ) ) ;
57
59
}
58
- let gateway_id = cmd_sock. recv_bytes ( 0 ) ?;
59
- if gateway_id. len ( ) != 8 {
60
+
61
+ // Read response.
62
+ let resp = cmd_sock. recv_bytes ( 0 ) ?;
63
+ let resp = gw:: GetGatewayIdResponse :: decode ( resp. as_slice ( ) ) ?;
64
+ if resp. gateway_id . len ( ) != 16 {
60
65
return Err ( anyhow ! (
61
- "Invalid gateway id, expected 8 bytes, received {}" ,
62
- gateway_id . len ( )
66
+ "Invalid Gateway ID length, gateway_id: {}" ,
67
+ resp . gateway_id
63
68
) ) ;
64
69
}
65
- let gateway_id = hex:: encode ( gateway_id) ;
66
-
67
- info ! ( "Received gateway id, gateway_id: {}" , gateway_id) ;
70
+ info ! ( "Received gateway id, gateway_id: {}" , resp. gateway_id) ;
68
71
69
72
tokio:: spawn ( {
70
73
let forward_crc_ok = conf. backend . filters . forward_crc_ok ;
@@ -88,18 +91,17 @@ impl Backend {
88
91
} ) ;
89
92
90
93
Ok ( Backend {
91
- gateway_id,
94
+ gateway_id : resp . gateway_id ,
92
95
ctx : zmq_ctx,
93
96
cmd_url : conf. backend . concentratord . command_url . clone ( ) ,
94
97
cmd_sock : Mutex :: new ( cmd_sock) ,
95
98
} )
96
99
}
97
100
98
- fn send_command ( & self , cmd : & str , b : & [ u8 ] ) -> Result < Vec < u8 > > {
101
+ fn send_command ( & self , cmd : gw :: Command ) -> Result < Vec < u8 > > {
99
102
let res = || -> Result < Vec < u8 > > {
100
103
let cmd_sock = self . cmd_sock . lock ( ) . unwrap ( ) ;
101
- cmd_sock. send ( cmd, zmq:: SNDMORE ) ?;
102
- cmd_sock. send ( b, 0 ) ?;
104
+ cmd_sock. send ( cmd. encode_to_vec ( ) , 0 ) ?;
103
105
104
106
// set poller so that we can timeout after 100ms
105
107
let mut items = [ cmd_sock. as_poll_item ( zmq:: POLLIN ) ] ;
@@ -109,8 +111,8 @@ impl Backend {
109
111
}
110
112
111
113
// red tx ack response
112
- let resp_b: & [ u8 ] = & cmd_sock. recv_bytes ( 0 ) ?;
113
- Ok ( resp_b. to_vec ( ) )
114
+ let resp_b = cmd_sock. recv_bytes ( 0 ) ?;
115
+ Ok ( resp_b)
114
116
} ( ) ;
115
117
116
118
if res. is_err ( ) {
@@ -153,13 +155,16 @@ impl BackendTrait for Backend {
153
155
Ok ( self . gateway_id . clone ( ) )
154
156
}
155
157
156
- async fn send_downlink_frame ( & self , pl : & gw:: DownlinkFrame ) -> Result < ( ) > {
158
+ async fn send_downlink_frame ( & self , pl : gw:: DownlinkFrame ) -> Result < ( ) > {
157
159
info ! ( "Sending downlink frame, downlink_id: {}" , pl. downlink_id) ;
160
+ let downlink_id = pl. downlink_id ;
158
161
159
162
let tx_ack = {
160
- let b = pl. encode_to_vec ( ) ;
161
- let resp_b = self . send_command ( "down" , & b) ?;
162
- gw:: DownlinkTxAck :: decode ( & mut Cursor :: new ( resp_b) ) ?
163
+ let cmd = gw:: Command {
164
+ command : Some ( gw:: command:: Command :: SendDownlinkFrame ( pl) ) ,
165
+ } ;
166
+ let resp_b = self . send_command ( cmd) ?;
167
+ gw:: DownlinkTxAck :: decode ( resp_b. as_slice ( ) ) ?
163
168
} ;
164
169
165
170
let ack_items: Vec < String > = tx_ack
@@ -170,17 +175,30 @@ impl BackendTrait for Backend {
170
175
171
176
info ! (
172
177
"Received ack, items: {:?}, downlink_id: {}" ,
173
- ack_items, pl . downlink_id
178
+ ack_items, downlink_id
174
179
) ;
175
180
176
181
send_tx_ack ( & tx_ack) . await
177
182
}
178
183
179
- async fn send_configuration_command ( & self , pl : & gw:: GatewayConfiguration ) -> Result < ( ) > {
184
+ async fn send_configuration_command ( & self , pl : gw:: GatewayConfiguration ) -> Result < ( ) > {
180
185
info ! ( "Sending configuration command, version: {}" , pl. version) ;
181
186
182
- let b = pl. encode_to_vec ( ) ;
183
- let _ = self . send_command ( "config" , & b) ?;
187
+ let cmd = gw:: Command {
188
+ command : Some ( gw:: command:: Command :: SetGatewayConfiguration ( pl) ) ,
189
+ } ;
190
+ let _ = self . send_command ( cmd) ?;
191
+
192
+ Ok ( ( ) )
193
+ }
194
+
195
+ async fn send_mesh_command ( & self , pl : gw:: MeshCommand ) -> Result < ( ) > {
196
+ info ! ( "Sending mesh command" ) ;
197
+
198
+ let cmd = gw:: Command {
199
+ command : Some ( gw:: command:: Command :: Mesh ( pl) ) ,
200
+ } ;
201
+ let _ = self . send_command ( cmd) ?;
184
202
185
203
Ok ( ( ) )
186
204
}
@@ -197,37 +215,37 @@ async fn event_loop(
197
215
let event_sock = Arc :: new ( Mutex :: new ( event_sock) ) ;
198
216
199
217
loop {
200
- let res = task:: spawn_blocking ( {
218
+ let event = task:: spawn_blocking ( {
201
219
let event_sock = event_sock. clone ( ) ;
202
220
203
- move || -> Result < Vec < Vec < u8 > > > {
221
+ move || -> Result < Option < gw :: Event > > {
204
222
let event_sock = event_sock. lock ( ) . unwrap ( ) ;
205
223
206
224
// set poller so that we can timeout after 100ms
207
225
let mut items = [ event_sock. as_poll_item ( zmq:: POLLIN ) ] ;
208
226
zmq:: poll ( & mut items, 100 ) ?;
209
227
if !items[ 0 ] . is_readable ( ) {
210
- return Ok ( vec ! [ ] ) ;
228
+ return Ok ( None ) ;
211
229
}
212
230
213
- let msg = event_sock. recv_multipart ( 0 ) ?;
214
- if msg. len ( ) != 2 {
215
- return Err ( anyhow ! ( "Event must have two frames" ) ) ;
216
- }
217
- Ok ( msg)
231
+ let msg = event_sock. recv_bytes ( 0 ) ?;
232
+ Ok ( Some ( gw:: Event :: decode ( msg. as_slice ( ) ) ?) )
218
233
}
219
234
} )
220
235
. await ;
221
236
222
- match res {
223
- Ok ( Ok ( msg) ) => {
224
- if msg. len ( ) != 2 {
225
- continue ;
226
- }
237
+ let event = match event {
238
+ Ok ( v) => v,
239
+ Err ( e) => {
240
+ error ! ( "Task error: {}" , e) ;
241
+ continue ;
242
+ }
243
+ } ;
227
244
245
+ match event {
246
+ Ok ( Some ( v) ) => {
228
247
if let Err ( err) = handle_event_msg (
229
- & msg[ 0 ] ,
230
- & msg[ 1 ] ,
248
+ v,
231
249
& filters,
232
250
forward_crc_ok,
233
251
forward_crc_invalid,
@@ -239,72 +257,60 @@ async fn event_loop(
239
257
continue ;
240
258
}
241
259
}
242
- Ok ( Err ( err) ) => {
243
- error ! ( "Receive event error, error: {}" , err) ;
244
- continue ;
245
- }
246
- Err ( err) => {
247
- error ! ( "{}" , err) ;
260
+ Ok ( None ) => continue ,
261
+ Err ( e) => {
262
+ error ! ( "Error reading event, error: {}" , e) ;
248
263
continue ;
249
264
}
250
265
}
251
266
}
252
267
}
253
268
254
269
async fn handle_event_msg (
255
- event : & [ u8 ] ,
256
- pl : & [ u8 ] ,
270
+ event : gw:: Event ,
257
271
filters : & lrwn_filters:: Filters ,
258
272
forward_crc_ok : bool ,
259
273
forward_crc_invalid : bool ,
260
274
forward_crc_missing : bool ,
261
275
) -> Result < ( ) > {
262
- let event = String :: from_utf8 ( event. to_vec ( ) ) ?;
263
- let pl = Cursor :: new ( pl. to_vec ( ) ) ;
264
-
265
- match event. as_str ( ) {
266
- "up" => {
267
- let pl = gw:: UplinkFrame :: decode ( pl) ?;
268
- if let Some ( rx_info) = & pl. rx_info {
276
+ match event. event {
277
+ Some ( gw:: event:: Event :: UplinkFrame ( v) ) => {
278
+ if let Some ( rx_info) = & v. rx_info {
269
279
if !( ( rx_info. crc_status ( ) == gw:: CrcStatus :: CrcOk && forward_crc_ok)
270
280
|| ( rx_info. crc_status ( ) == gw:: CrcStatus :: BadCrc && forward_crc_invalid)
271
281
|| ( rx_info. crc_status ( ) == gw:: CrcStatus :: NoCrc && forward_crc_missing) )
272
282
{
273
283
debug ! (
274
284
"Ignoring uplink frame because of forward_crc_ flags, uplink_id: {}" ,
275
- pl . rx_info. as_ref( ) . map( |v| v. uplink_id) . unwrap_or_default( ) ,
285
+ v . rx_info. as_ref( ) . map( |v| v. uplink_id) . unwrap_or_default( ) ,
276
286
) ;
277
287
return Ok ( ( ) ) ;
278
288
}
279
289
}
280
290
281
- if lrwn_filters:: matches ( & pl . phy_payload , filters) {
291
+ if lrwn_filters:: matches ( & v . phy_payload , filters) {
282
292
info ! (
283
293
"Received uplink frame, uplink_id: {}" ,
284
- pl . rx_info. as_ref( ) . map( |v| v. uplink_id) . unwrap_or_default( ) ,
294
+ v . rx_info. as_ref( ) . map( |v| v. uplink_id) . unwrap_or_default( ) ,
285
295
) ;
286
- send_uplink_frame ( & pl ) . await ?;
296
+ send_uplink_frame ( & v ) . await ?;
287
297
} else {
288
298
debug ! (
289
299
"Ignoring uplink frame because of dev_addr and join_eui filters, uplink_id: {}" ,
290
- pl . rx_info. as_ref( ) . map( |v| v. uplink_id) . unwrap_or_default( )
300
+ v . rx_info. as_ref( ) . map( |v| v. uplink_id) . unwrap_or_default( )
291
301
) ;
292
302
}
293
303
}
294
- "stats" => {
295
- let mut pl = gw:: GatewayStats :: decode ( pl) ?;
296
- info ! ( "Received gateway stats" ) ;
297
- pl. metadata . extend ( metadata:: get ( ) . await ?) ;
298
- send_gateway_stats ( & pl) . await ?;
299
- }
300
- "mesh_heartbeat" => {
301
- let pl = gw:: MeshHeartbeat :: decode ( pl) ?;
302
- info ! ( "Received mesh heartbeat" ) ;
303
- send_mesh_heartbeat ( & pl) . await ?;
304
+ Some ( gw:: event:: Event :: GatewayStats ( mut v) ) => {
305
+ info ! ( "received gateway stats" ) ;
306
+ v. metadata . extend ( metadata:: get ( ) . await ?) ;
307
+ send_gateway_stats ( & v) . await ?;
304
308
}
305
- _ => {
306
- return Err ( anyhow ! ( "Unexpected event: {}" , event) ) ;
309
+ Some ( gw:: event:: Event :: Mesh ( v) ) => {
310
+ info ! ( "Received mesh event" ) ;
311
+ send_mesh_event ( & v) . await ?;
307
312
}
313
+ None => { }
308
314
}
309
315
310
316
Ok ( ( ) )
0 commit comments