Returns the gateway to use for downlink. It will filter out private gateways (gateways from a different tenant ID, that do not allow downlinks). The result will be sorted based on SNR / RSSI. The returned value is: A random item from the elements with an SNR > minSNR The first item of the sorted slice (failing the above) An error in case no gateways are available
(
tenant_id: Option<Uuid>,
region_config_id: &str,
min_snr_margin: f32,
history: &[internal::GatewayRxInfoHistory],
use_only_last_uplink: bool,
)
| 20 | // * The first item of the sorted slice (failing the above) |
| 21 | // * An error in case no gateways are available |
| 22 | pub fn select_downlink_gateway( |
| 23 | tenant_id: Option<Uuid>, |
| 24 | region_config_id: &str, |
| 25 | min_snr_margin: f32, |
| 26 | history: &[internal::GatewayRxInfoHistory], |
| 27 | use_only_last_uplink: bool, |
| 28 | ) -> Result<internal::DownlinkGateway> { |
| 29 | let region_conf = region::get(region_config_id)?; |
| 30 | let tenant_id_bytes = tenant_id.map(|v| v.as_bytes().to_vec()).unwrap_or_default(); |
| 31 | |
| 32 | // In case of Class-A and OTAA, we only use the last item from the list, as this contains the context |
| 33 | // blobs related to the Class-A uplink. We need this context blob as it contains the uplink |
| 34 | // timestamp info. |
| 35 | let mut history = if use_only_last_uplink { |
| 36 | if let Some(h) = history.last() { |
| 37 | vec![h.clone()] |
| 38 | } else { |
| 39 | vec![] |
| 40 | } |
| 41 | } else { |
| 42 | history.to_vec() |
| 43 | }; |
| 44 | |
| 45 | // Filter out private gateways that are not ours. |
| 46 | for h in &mut history { |
| 47 | h.items.retain(|rx_info| { |
| 48 | if tenant_id_bytes.is_empty() { |
| 49 | !rx_info.is_private_down |
| 50 | } else if tenant_id_bytes == rx_info.tenant_id { |
| 51 | true |
| 52 | } else { |
| 53 | !rx_info.is_private_down |
| 54 | } |
| 55 | }); |
| 56 | } |
| 57 | |
| 58 | // Filter out empty history records. |
| 59 | history.retain(|h| !h.items.is_empty()); |
| 60 | |
| 61 | if history.is_empty() { |
| 62 | return Err(anyhow!( |
| 63 | "gateway rx history is empty after filtering, no downlink path available" |
| 64 | )); |
| 65 | } |
| 66 | |
| 67 | #[derive(Debug, Default, Clone)] |
| 68 | struct GatewayStats { |
| 69 | gateway_id: Vec<u8>, |
| 70 | count: usize, |
| 71 | total_snr: f32, |
| 72 | total_rssi: i32, |
| 73 | total_link_margin: f32, |
| 74 | board: u32, |
| 75 | antenna: u32, |
| 76 | context: Vec<u8>, |
| 77 | gateway_downlink_priority: usize, |
| 78 | } |
| 79 |