This returns the mac-commands which must be sent back to the device as response and a bool indicating if a downlink must be sent. For some mac-commands, no mac-command answer is required, but the device expects a downlink as confirmation, even if the downlink frame is empty.
(
uplink_frame_set: &UplinkFrameSet,
cmds: &lrwn::MACCommandSet,
tenant: &tenant::Tenant,
app: &application::Application,
dp: &device_profile::DeviceProfile,
dev: &mut device::
| 35 | // indicating if a downlink must be sent. For some mac-commands, no mac-command answer is required, |
| 36 | // but the device expects a downlink as confirmation, even if the downlink frame is empty. |
| 37 | pub async fn handle_uplink( |
| 38 | uplink_frame_set: &UplinkFrameSet, |
| 39 | cmds: &lrwn::MACCommandSet, |
| 40 | tenant: &tenant::Tenant, |
| 41 | app: &application::Application, |
| 42 | dp: &device_profile::DeviceProfile, |
| 43 | dev: &mut device::Device, |
| 44 | region_conf: Arc<Box<dyn lrwn::region::Region + Send + Sync>>, |
| 45 | ) -> Result<(Vec<lrwn::MACCommandSet>, bool)> { |
| 46 | let conf = config::get(); |
| 47 | if conf.network.mac_commands_disabled { |
| 48 | return Ok((Vec::new(), false)); |
| 49 | } |
| 50 | |
| 51 | let mut cids: Vec<lrwn::CID> = Vec::new(); // to maintain the CID order |
| 52 | let mut blocks: HashMap<lrwn::CID, lrwn::MACCommandSet> = HashMap::new(); |
| 53 | |
| 54 | // Group mac-commands in blocks. |
| 55 | for cmd in &**cmds { |
| 56 | let cid = cmd.cid(); |
| 57 | match blocks.get_mut(&cid) { |
| 58 | Some(v) => { |
| 59 | v.push(cmd.clone()); |
| 60 | } |
| 61 | None => { |
| 62 | cids.push(cid); |
| 63 | blocks.insert(cid, lrwn::MACCommandSet::new(vec![cmd.clone()])); |
| 64 | } |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | // Some mac-commands require a downlink response (not mac-command answer) to confirm that the |
| 69 | // uplink has been received. |
| 70 | let mut must_respond_with_downlink = false; |
| 71 | let mut out: Vec<lrwn::MACCommandSet> = Vec::new(); |
| 72 | |
| 73 | // Iterate over mac-commands in order of CID. |
| 74 | for cid in cids { |
| 75 | must_respond_with_downlink = must_respond_with_downlink |
| 76 | || matches!( |
| 77 | cid, |
| 78 | lrwn::CID::RxTimingSetupAns | lrwn::CID::RxParamSetupAns |
| 79 | ); |
| 80 | |
| 81 | // Get pending mac-command block, this could return None. |
| 82 | let pending = match mac_command::get_pending(dev.get_device_session_mut()?, cid).await { |
| 83 | Ok(v) => v, |
| 84 | Err(e) => { |
| 85 | error!(dev_eui = %dev.dev_eui, cid = %cid, error = %e, "Get pending mac-command block error"); |
| 86 | continue; |
| 87 | } |
| 88 | }; |
| 89 | |
| 90 | // Handle the mac-command, which might return a block to answer the uplink mac-command |
| 91 | // request. |
| 92 | let res = match handle( |
| 93 | uplink_frame_set, |
| 94 | cid, |