private static WaitableLoRaRequest Create(RadioMetadata radioMetadata, IEnumerable <TimeSpan> elapsedTimes, IDownstreamMessageSender downstreamMessageSender = null, TimeSpan?startTimeOffset = null, bool useRealTimer = false, LoRaPayload loRaPayload = null, Region region = null) { var request = new WaitableLoRaRequest(radioMetadata, downstreamMessageSender ?? new TestDownstreamMessageSender(), DateTime.UtcNow.Subtract(startTimeOffset ?? TimeSpan.Zero)); var effectiveRegion = region ?? TestUtils.TestRegion; request.SetRegion(effectiveRegion); if (loRaPayload is not null) { request.SetPayload(loRaPayload); } if (!useRealTimer) { var timeWatcher = new TestLoRaOperationTimeWatcher(effectiveRegion, elapsedTimes); request.UseTimeWatcher(timeWatcher); } return(request); }
/// <summary> /// Creates a WaitableLoRaRequest that uses a deterministic time handler. /// </summary> /// <param name="rxpk">Rxpk instance.</param> /// <param name="downstreamMessageSender">DownstreamMessageSender instance.</param> /// <param name="startTimeOffset">Is subtracted from the current time to determine the start time for the deterministic time watcher. Default is TimeSpan.Zero.</param> /// <param name="constantElapsedTime">Controls how much time is elapsed when querying the time watcher. Default is TimeSpan.Zero.</param> /// <param name="useRealTimer">Allows you to opt-in to use a real, non-deterministic time watcher.</param> public static WaitableLoRaRequest Create(RadioMetadata radioMetadata, LoRaPayload loRaPayload, IDownstreamMessageSender downstreamMessageSender = null, TimeSpan?startTimeOffset = null, TimeSpan?constantElapsedTime = null, bool useRealTimer = false, Region region = null) => Create(radioMetadata, LoRaEnumerable.RepeatInfinite(constantElapsedTime ?? TimeSpan.Zero), downstreamMessageSender, startTimeOffset, useRealTimer, loRaPayload, region: region);
public LoRaRequest( RadioMetadata radioMetadata, IDownstreamMessageSender downstreamMessageSender, DateTime startTime) { RadioMetadata = radioMetadata; DownstreamMessageSender = downstreamMessageSender; StartTime = startTime; }
public JoinRequestFrame(MacHeader mHdr, JoinEui joinEui, DevEui devEui, DevNonce devNonce, Mic mic, RadioMetadata radioMetadata) { MacHeader = mHdr; JoinEui = joinEui; DevEui = devEui; DevNonce = devNonce; Mic = mic; RadioMetadata = radioMetadata; }
/// <summary> /// Creates a WwaitableLoRaRequest that is configured to miss certain receive windows. /// </summary> /// <param name="rxpk">Rxpk instance.</param> /// <param name="downstreamMessageSender">DownstreamMessageSender instance.</param> /// <param name="inTimeForC2DMessageCheck">If set to true it ensures that processing is fast enough that C2D messages can be checked.</param> /// <param name="inTimeForAdditionalMessageCheck">If set to true it ensures that processing is fast enough that additional C2D messages can be checked.</param> /// <param name="inTimeForDownlinkDelivery">If set to true it ensures that processing is fast enough that C2D messages can be checked.</param> public static WaitableLoRaRequest Create(RadioMetadata radioMetadata, IDownstreamMessageSender downstreamMessageSender, bool inTimeForC2DMessageCheck, bool inTimeForAdditionalMessageCheck, bool inTimeForDownlinkDelivery, LoRaPayloadData loRaPayloadData = null) { var c2dMessageCheckTimeSpan = inTimeForC2DMessageCheck ? TimeSpan.FromMilliseconds(10) : TimeSpan.FromSeconds(10); var additionalMessageCheckTimeSpan = inTimeForAdditionalMessageCheck ? TimeSpan.FromMilliseconds(10) : TimeSpan.FromSeconds(10); var downlinkDeliveryTimeSpan = inTimeForDownlinkDelivery ? TimeSpan.FromMilliseconds(10) : TimeSpan.FromSeconds(10); return(Create(radioMetadata, new[] { c2dMessageCheckTimeSpan, c2dMessageCheckTimeSpan, additionalMessageCheckTimeSpan, downlinkDeliveryTimeSpan }, downstreamMessageSender: downstreamMessageSender, loRaPayload: loRaPayloadData)); }
public UpstreamDataFrame(MacHeader macHeader, DevAddr devAddress, FrameControlFlags fctrlFlags, ushort counter, string options, FramePort?port, string payload, Mic mic, RadioMetadata radioMetadata) { MacHeader = macHeader; DevAddr = devAddress; FrameControlFlags = fctrlFlags; Counter = counter; Options = options; Port = port; Payload = payload; Mic = mic; RadioMetadata = radioMetadata; }
public async System.Threading.Tasks.Task TestADRAsync(string testName, DevEui devEUI, IList <LoRaADRTableEntry> tableEntries, RadioMetadata radioMetadata, bool expectDefaultAnswer, LoRaADRResult expectedResult) { this.output.WriteLine($"Starting test {testName}"); var region = TestUtils.TestRegion; ILoRaADRStrategyProvider provider = new LoRaADRStrategyProvider(NullLoggerFactory.Instance); using var inMemoryStore = new LoRaADRInMemoryStore(); var loRaADRManager = new Mock <LoRaADRManagerBase>(MockBehavior.Loose, inMemoryStore, provider, NullLogger <LoRaADRManagerBase> .Instance) { CallBase = true }; _ = loRaADRManager.Setup(x => x.NextFCntDown(It.IsAny <DevEui>(), It.IsAny <string>(), It.IsAny <uint>(), It.IsAny <uint>())).ReturnsAsync(1U); // If the test does not expect a default answer we trigger default reset before if (!expectDefaultAnswer) { _ = await loRaADRManager.Object.CalculateADRResultAndAddEntryAsync(devEUI, string.Empty, 1, 1, (float)region.RequiredSnr(radioMetadata.DataRate), radioMetadata.DataRate, region.TXPowertoMaxEIRP.Count - 1, region.MaxADRDataRate, new LoRaADRTableEntry() { Snr = 0, FCnt = 1, DevEUI = devEUI, GatewayCount = 1, GatewayId = "gateway" }); } for (var i = 0; i < tableEntries.Count; i++) { await loRaADRManager.Object.StoreADREntryAsync(tableEntries[i]); } var adrResult = await loRaADRManager.Object.CalculateADRResultAndAddEntryAsync(devEUI, string.Empty, 1, 1, (float)region.RequiredSnr(radioMetadata.DataRate), radioMetadata.DataRate, region.TXPowertoMaxEIRP.Count - 1, region.MaxADRDataRate); Assert.Equal(expectedResult.DataRate, adrResult.DataRate); Assert.Equal(expectedResult.NbRepetition, adrResult.NbRepetition); Assert.Equal(expectedResult.TxPower, adrResult.TxPower); Assert.Equal(expectedResult.FCntDown, adrResult.FCntDown); loRaADRManager.Verify(x => x.NextFCntDown(It.IsAny <DevEui>(), It.IsAny <string>(), It.IsAny <uint>(), It.IsAny <uint>()), Times.AtLeastOnce, "NextFCntDown"); this.output.WriteLine($"Test {testName} finished"); }
public async Task Perform_NbRep_Adaptation_When_Needed() { uint deviceId = 31; var currentDR = LoRaDataRate.SF8BW125; var currentLsnr = -20; var messageCount = 20; uint payloadFcnt = 0; const uint InitialDeviceFcntUp = 1; const uint ExpectedDeviceFcntDown = 4; var simulatedDevice = new SimulatedDevice( TestDeviceInfo.CreateABPDevice(deviceId, gatewayID: ServerConfiguration.GatewayID), frmCntUp: InitialDeviceFcntUp); var loraDevice = CreateLoRaDevice(simulatedDevice); LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync((Message)null); var reportedNbRep = 0; LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Callback <TwinCollection, CancellationToken>((t, _) => { if (t.Contains(TwinProperty.NbRep)) { reportedNbRep = (int)t[TwinProperty.NbRep]; } }) .ReturnsAsync(true); using var cache = EmptyMemoryCache(); using var loraDeviceCache = CreateDeviceCache(loraDevice); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, loraDeviceCache); // Send to message processor using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); payloadFcnt = await InitializeCacheToDefaultValuesAsync(payloadFcnt, simulatedDevice, messageProcessor); // **************************************************** // First part send messages with spaces in fcnt to simulate wrong network connectivity // **************************************************** // send a message with a fcnt every 4. for (var i = 0; i < messageCount; i++) { payloadFcnt = await SendMessage(currentLsnr, currentDR, payloadFcnt + 3, simulatedDevice, messageProcessor, FrameControlFlags.Adr); } var payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234", fcnt: payloadFcnt, fctrlFlags: FrameControlFlags.AdrAckReq | FrameControlFlags.Adr); var radioMetadata = new RadioMetadata(TestUtils.TestRegion.GetDataRateIndex(currentDR), Hertz.Mega(868.1), new RadioMetadataUpInfo(0, 0, 0, 0, currentLsnr)); using var request = CreateWaitableRequest(radioMetadata, payload); messageProcessor.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); // Expectations // 1. Message was sent to IoT Hub LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.VerifyAll(); Assert.True(request.ProcessingSucceeded); Assert.NotNull(request.ResponseDownlink); Assert.Equal(2, DownstreamMessageSender.DownlinkMessages.Count); var downlinkMessage = DownstreamMessageSender.DownlinkMessages[1]; var payloadDataDown = new LoRaPayloadData(downlinkMessage.Data); // We expect a mac command in the payload Assert.Equal(5, payloadDataDown.Frmpayload.Span.Length); var decryptedPayload = payloadDataDown.Serialize(simulatedDevice.NwkSKey.Value); Assert.Equal(FramePort.MacCommand, payloadDataDown.Fport); Assert.Equal((byte)Cid.LinkADRCmd, decryptedPayload[0]); var linkAdr = new LinkADRRequest(decryptedPayload); Assert.Equal(3, reportedNbRep); Assert.Equal(3, linkAdr.NbRep); Assert.Equal(3, loraDevice.NbRep); // **************************************************** // Second part send normal messages to decrease NbRep // **************************************************** // send a message with a fcnt every 1 for (var i = 0; i < messageCount; i++) { payloadFcnt = await SendMessage(currentLsnr, currentDR, payloadFcnt, simulatedDevice, messageProcessor, FrameControlFlags.Adr); } payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234", fcnt: payloadFcnt, fctrlFlags: FrameControlFlags.AdrAckReq | FrameControlFlags.Adr); using var secondRequest = CreateWaitableRequest(radioMetadata, payload); messageProcessor.DispatchRequest(secondRequest); Assert.True(await secondRequest.WaitCompleteAsync()); // Expectations // 1. Message was sent to IoT Hub LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.VerifyAll(); Assert.True(secondRequest.ProcessingSucceeded); Assert.NotNull(secondRequest.ResponseDownlink); Assert.Equal(3, DownstreamMessageSender.DownlinkMessages.Count); downlinkMessage = DownstreamMessageSender.DownlinkMessages[2]; payloadDataDown = new LoRaPayloadData(downlinkMessage.Data); // We expect a mac command in the payload Assert.Equal(5, payloadDataDown.Frmpayload.Span.Length); decryptedPayload = payloadDataDown.Serialize(simulatedDevice.NwkSKey.Value); Assert.Equal(FramePort.MacCommand, payloadDataDown.Fport); Assert.Equal((byte)Cid.LinkADRCmd, decryptedPayload[0]); linkAdr = new LinkADRRequest(decryptedPayload); Assert.Equal(2, reportedNbRep); Assert.Equal(2, linkAdr.NbRep); Assert.Equal(2, loraDevice.NbRep); // in case no payload the mac is in the FRMPayload and is decrypted with NwkSKey Assert.Equal(payloadDataDown.DevAddr, loraDevice.DevAddr); Assert.False(payloadDataDown.IsConfirmed); Assert.Equal(MacMessageType.UnconfirmedDataDown, payloadDataDown.MessageType); // 4. Frame counter up was updated Assert.Equal(payloadFcnt, loraDevice.FCntUp); // **************************************************** // Third part send normal messages to decrease NbRep to 1 // **************************************************** // send a message with a fcnt every 1 for (var i = 0; i < messageCount; i++) { payloadFcnt = await SendMessage(currentLsnr, currentDR, payloadFcnt, simulatedDevice, messageProcessor, FrameControlFlags.Adr); } payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234", fcnt: payloadFcnt, fctrlFlags: FrameControlFlags.AdrAckReq | FrameControlFlags.Adr); using var thirdRequest = CreateWaitableRequest(radioMetadata, payload); messageProcessor.DispatchRequest(thirdRequest); Assert.True(await thirdRequest.WaitCompleteAsync()); // Expectations // 1. Message was sent to IoT Hub LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.VerifyAll(); Assert.True(thirdRequest.ProcessingSucceeded); Assert.NotNull(thirdRequest.ResponseDownlink); Assert.Equal(4, DownstreamMessageSender.DownlinkMessages.Count); downlinkMessage = DownstreamMessageSender.DownlinkMessages[3]; payloadDataDown = new LoRaPayloadData(downlinkMessage.Data); // We expect a mac command in the payload Assert.Equal(5, payloadDataDown.Frmpayload.Span.Length); decryptedPayload = payloadDataDown.Serialize(simulatedDevice.NwkSKey.Value); Assert.Equal(FramePort.MacCommand, payloadDataDown.Fport); Assert.Equal((byte)Cid.LinkADRCmd, decryptedPayload[0]); linkAdr = new LinkADRRequest(decryptedPayload); Assert.Equal(1, reportedNbRep); Assert.Equal(1, linkAdr.NbRep); Assert.Equal(1, loraDevice.NbRep); // 5. Frame counter down is updated Assert.Equal(ExpectedDeviceFcntDown, loraDevice.FCntDown); Assert.Equal(ExpectedDeviceFcntDown, payloadDataDown.Fcnt); }
public async Task Perform_TXPower_Adaptation_When_Needed() { uint deviceId = 44; var messageCount = 21; uint payloadFcnt = 0; const uint InitialDeviceFcntUp = 9; const uint InitialDeviceFcntDown = 0; var simulatedDevice = new SimulatedDevice( TestDeviceInfo.CreateABPDevice(deviceId, gatewayID: ServerConfiguration.GatewayID), frmCntUp: InitialDeviceFcntUp); var loraDevice = CreateLoRaDevice(simulatedDevice); LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync((Message)null); var reportedDR = DR0; var reportedTxPower = 0; LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Callback <TwinCollection, CancellationToken>((t, _) => { if (t.Contains(TwinProperty.DataRate)) { reportedDR = (DataRateIndex)(int)(object)t[TwinProperty.DataRate].Value; } if (t.Contains(TwinProperty.TxPower)) { reportedTxPower = t[TwinProperty.TxPower].Value; } }) .ReturnsAsync(true); using var cache = EmptyMemoryCache(); using var loraDeviceCache = CreateDeviceCache(loraDevice); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, loraDeviceCache); // Send to message processor using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); payloadFcnt = await InitializeCacheToDefaultValuesAsync(payloadFcnt, simulatedDevice, messageProcessor); // **************************************************** // First part gives very good connectivity and ensure we set power to minimum and DR increase to 5 // **************************************************** // set to very good lsnr and DR3 float currentLsnr = 20; var currentDR = LoRaDataRate.SF9BW125; // todo add case without buffer for (var i = 0; i < messageCount; i++) { payloadFcnt = await SendMessage(currentLsnr, currentDR, payloadFcnt, simulatedDevice, messageProcessor, FrameControlFlags.Adr); } var payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234", fcnt: payloadFcnt, fctrlFlags: FrameControlFlags.AdrAckReq | FrameControlFlags.Adr); var radioMetadata = new RadioMetadata(TestUtils.TestRegion.GetDataRateIndex(currentDR), Hertz.Mega(868.1), new RadioMetadataUpInfo(0, 0, 0, 0, currentLsnr)); using var request = CreateWaitableRequest(radioMetadata, payload); messageProcessor.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.NotNull(request.ResponseDownlink); Assert.Equal(2, DownstreamMessageSender.DownlinkMessages.Count); var downlinkMessage = DownstreamMessageSender.DownlinkMessages[1]; var payloadDataDown = new LoRaPayloadData(downlinkMessage.Data); // We expect a mac command in the payload Assert.Equal(5, payloadDataDown.Frmpayload.Span.Length); var decryptedPayload = payloadDataDown.Serialize(simulatedDevice.NwkSKey.Value); Assert.Equal(FramePort.MacCommand, payloadDataDown.Fport); Assert.Equal((byte)Cid.LinkADRCmd, decryptedPayload[0]); var linkAdr = new LinkADRRequest(decryptedPayload); Assert.Equal(DR5, linkAdr.DataRate); Assert.Equal(DR5, loraDevice.DataRate); Assert.Equal(DR5, reportedDR); Assert.Equal(7, linkAdr.TxPower); Assert.Equal(7, loraDevice.TxPower); Assert.Equal(7, reportedTxPower); Assert.Equal(payloadDataDown.DevAddr, loraDevice.DevAddr); Assert.False(payloadDataDown.IsConfirmed); Assert.Equal(MacMessageType.UnconfirmedDataDown, payloadDataDown.MessageType); // 4. Frame counter up was updated Assert.Equal(payloadFcnt, loraDevice.FCntUp); // 5. Frame counter down is updated Assert.Equal(InitialDeviceFcntDown + 1, loraDevice.FCntDown); Assert.Equal(InitialDeviceFcntDown + 1, payloadDataDown.Fcnt); // **************************************************** // Second part reduce connectivity and verify the DR stay to 5 and power set to max // **************************************************** currentLsnr = -50; // DR5 currentDR = LoRaDataRate.SF7BW125; // todo add case without buffer for (var i = 0; i < messageCount; i++) { payloadFcnt = await SendMessage(currentLsnr, currentDR, payloadFcnt, simulatedDevice, messageProcessor, FrameControlFlags.Adr); } payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234", fcnt: payloadFcnt, fctrlFlags: FrameControlFlags.AdrAckReq | FrameControlFlags.Adr); var radioMetadataWithDatr5 = new RadioMetadata(TestUtils.TestRegion.GetDataRateIndex(currentDR), Hertz.Mega(868.1), new RadioMetadataUpInfo(0, 0, 0, 0, currentLsnr)); using var secondRequest = CreateWaitableRequest(radioMetadataWithDatr5, payload); messageProcessor.DispatchRequest(secondRequest); Assert.True(await secondRequest.WaitCompleteAsync()); Assert.NotNull(secondRequest.ResponseDownlink); Assert.Equal(3, DownstreamMessageSender.DownlinkMessages.Count); downlinkMessage = DownstreamMessageSender.DownlinkMessages[2]; payloadDataDown = new LoRaPayloadData(downlinkMessage.Data); // We expect a mac command in the payload Assert.Equal(5, payloadDataDown.Frmpayload.Span.Length); decryptedPayload = payloadDataDown.Serialize(simulatedDevice.NwkSKey.Value); Assert.Equal(FramePort.MacCommand, payloadDataDown.Fport); Assert.Equal((byte)Cid.LinkADRCmd, decryptedPayload[0]); linkAdr = new LinkADRRequest(decryptedPayload); Assert.Equal(DR5, linkAdr.DataRate); Assert.Equal(DR5, loraDevice.DataRate); Assert.Equal(DR5, reportedDR); Assert.Equal(0, linkAdr.TxPower); Assert.Equal(0, loraDevice.TxPower); Assert.Equal(0, reportedTxPower); Assert.Equal(payloadDataDown.DevAddr, loraDevice.DevAddr); Assert.False(payloadDataDown.IsConfirmed); Assert.Equal(MacMessageType.UnconfirmedDataDown, payloadDataDown.MessageType); // 4. Frame counter up was updated Assert.Equal(payloadFcnt, loraDevice.FCntUp); // 5. Frame counter down is updated Assert.Equal(InitialDeviceFcntDown + 2, loraDevice.FCntDown); Assert.Equal(InitialDeviceFcntDown + 2, payloadDataDown.Fcnt); // Expectations // 1. Message was sent to IoT Hub LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.VerifyAll(); Assert.True(secondRequest.ProcessingSucceeded); }
public async Task Perform_DR_Adaptation_When_Needed(uint deviceId, float currentLsnr, string currentDRString, DataRateIndex expectedDR, int expectedTxPower) { var currentDR = LoRaDataRate.Parse(currentDRString); var messageCount = 21; uint payloadFcnt = 0; const uint InitialDeviceFcntUp = 9; const uint ExpectedDeviceFcntDown = 0; var simulatedDevice = new SimulatedDevice( TestDeviceInfo.CreateABPDevice(deviceId, gatewayID: ServerConfiguration.GatewayID), frmCntUp: InitialDeviceFcntUp); var loraDevice = CreateLoRaDevice(simulatedDevice); LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync((Message)null); var twinDR = DR0; var twinTxPower = 0; LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Callback <TwinCollection, CancellationToken>((t, _) => { if (t.Contains(TwinProperty.DataRate)) { twinDR = t[TwinProperty.DataRate]; } if (t.Contains(TwinProperty.TxPower)) { twinTxPower = (int)t[TwinProperty.TxPower]; } }) .ReturnsAsync(true); using var cache = EmptyMemoryCache(); using var loraDeviceCache = CreateDeviceCache(loraDevice); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, loraDeviceCache); // Send to message processor using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); payloadFcnt = await InitializeCacheToDefaultValuesAsync(payloadFcnt, simulatedDevice, messageProcessor); for (var i = 0; i < messageCount; i++) { payloadFcnt = await SendMessage(currentLsnr, currentDR, payloadFcnt, simulatedDevice, messageProcessor, FrameControlFlags.Adr); } var payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234", fcnt: payloadFcnt, fctrlFlags: FrameControlFlags.AdrAckReq | FrameControlFlags.Adr); var radioMetadata = new RadioMetadata(TestUtils.TestRegion.GetDataRateIndex(currentDR), Hertz.Mega(868.1), new RadioMetadataUpInfo(0, 0, 0, 0, currentLsnr)); using var request = CreateWaitableRequest(radioMetadata, payload); messageProcessor.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); // Expectations // 1. Message was sent to IoT Hub LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.VerifyAll(); Assert.True(request.ProcessingSucceeded); Assert.NotNull(request.ResponseDownlink); var downlinkMessage = DownstreamMessageSender.DownlinkMessages[1]; var payloadDataDown = new LoRaPayloadData(downlinkMessage.Data); // We expect a mac command in the payload if (deviceId == 221) { // In this case, no ADR adaptation is performed, so the message should be empty Assert.Equal(0, payloadDataDown.Frmpayload.Span.Length); Assert.Equal(0, payloadDataDown.Fopts.Span.Length); } else { Assert.Equal(5, payloadDataDown.Frmpayload.Span.Length); var decryptedPayload = payloadDataDown.Serialize(simulatedDevice.NwkSKey.Value); Assert.Equal(FramePort.MacCommand, payloadDataDown.Fport); Assert.Equal((byte)Cid.LinkADRCmd, decryptedPayload[0]); var linkAdr = new LinkADRRequest(decryptedPayload); Assert.Equal(expectedDR, linkAdr.DataRate); Assert.Equal(expectedDR, loraDevice.DataRate); Assert.Equal(expectedDR, twinDR); Assert.Equal(expectedTxPower, linkAdr.TxPower); Assert.Equal(expectedTxPower, loraDevice.TxPower); Assert.Equal(expectedTxPower, twinTxPower); // in case no payload the mac is in the FRMPayload and is decrypted with NwkSKey Assert.Equal(payloadDataDown.DevAddr, loraDevice.DevAddr); Assert.False(payloadDataDown.IsConfirmed); Assert.Equal(MacMessageType.UnconfirmedDataDown, payloadDataDown.MessageType); // 4. Frame counter up was updated Assert.Equal(payloadFcnt, loraDevice.FCntUp); // 5. Frame counter down is updated Assert.Equal(ExpectedDeviceFcntDown + 1, loraDevice.FCntDown); Assert.Equal(ExpectedDeviceFcntDown + 1, payloadDataDown.Fcnt); } }
private WaitableLoRaRequest(RadioMetadata radioMetadata, IDownstreamMessageSender downstreamMessageSender, DateTime startTime) : base(radioMetadata, downstreamMessageSender, startTime) { }