public async Task Should_Accept( bool isConfirmed, bool hasMacInUpstream, bool hasMacInC2D, bool isTooLongForUpstreamMacCommandInAnswer, bool isSendingInRx2, [CombinatorialValues("SF10BW125", "SF9BW125", "SF8BW125", "SF7BW125")] string datr) { const int InitialDeviceFcntUp = 9; const int InitialDeviceFcntDown = 20; // This scenario makes no sense if (hasMacInUpstream && isTooLongForUpstreamMacCommandInAnswer) { return; } var simulatedDevice = new SimulatedDevice( TestDeviceInfo.CreateABPDevice(1, gatewayID: ServerConfiguration.GatewayID), frmCntUp: InitialDeviceFcntUp, frmCntDown: InitialDeviceFcntDown); var loraDevice = CreateLoRaDevice(simulatedDevice); var(radioMetaData, loraPayload) = CreateUpstreamMessage(isConfirmed, hasMacInUpstream, LoRaDataRate.Parse(datr), simulatedDevice); if (!hasMacInUpstream) { LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); } var euRegion = TestUtils.TestRegion; var c2dMessageMacCommand = new DevStatusRequest(); var c2dMessageMacCommandSize = hasMacInC2D ? c2dMessageMacCommand.Length : 0; var upstreamMessageMacCommandSize = 0; DataRateIndex expectedDownlinkDatr; if (hasMacInUpstream && !isTooLongForUpstreamMacCommandInAnswer) { upstreamMessageMacCommandSize = new LinkCheckAnswer(1, 1).Length; } expectedDownlinkDatr = isSendingInRx2 ? euRegion.GetDefaultRX2ReceiveWindow(default).DataRate
public async Task Should_Abandon( bool isConfirmed, bool hasMacInUpstream, bool hasMacInC2D, [CombinatorialValues("SF9BW125", "SF8BW125", "SF7BW125")] string datr) { const int InitialDeviceFcntUp = 9; const int InitialDeviceFcntDown = 20; var simulatedDevice = new SimulatedDevice( TestDeviceInfo.CreateABPDevice(1, gatewayID: ServerConfiguration.GatewayID), frmCntUp: InitialDeviceFcntUp, frmCntDown: InitialDeviceFcntDown); var loraDevice = CreateLoRaDevice(simulatedDevice); var msgPayload = "1234567890"; var confirmedMessagePayload = simulatedDevice.CreateConfirmedDataUpMessage(msgPayload, isHexPayload: true, fport: 0); var(radioMetaData, loraPayload) = CreateUpstreamMessage(isConfirmed, hasMacInUpstream, LoRaDataRate.Parse(datr), simulatedDevice); if (!hasMacInUpstream) { LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); } var euRegion = RegionManager.EU868; var c2dMessageMacCommand = new DevStatusRequest(); var c2dMessageMacCommandSize = hasMacInC2D ? c2dMessageMacCommand.Length : 0; DataRateIndex expectedDownlinkDatr; expectedDownlinkDatr = euRegion.GetDataRateIndex(euRegion.DRtoConfiguration[euRegion.GetDefaultRX2ReceiveWindow(default).DataRate].DataRate);
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); } }
public async Task Should_Reject( bool isConfirmed, bool hasMacInUpstream, bool hasMacInC2D, [CombinatorialValues("SF10BW125", "SF9BW125", "SF8BW125", "SF7BW125")] string datr) { const int InitialDeviceFcntUp = 9; const int InitialDeviceFcntDown = 20; var simulatedDevice = new SimulatedDevice( TestDeviceInfo.CreateABPDevice(1, gatewayID: ServerConfiguration.GatewayID), frmCntUp: InitialDeviceFcntUp, frmCntDown: InitialDeviceFcntDown); var loraDevice = CreateLoRaDevice(simulatedDevice); var(radioMetaData, loraPayload) = CreateUpstreamMessage(isConfirmed, hasMacInUpstream, LoRaDataRate.Parse(datr), simulatedDevice); if (!hasMacInUpstream) { LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); } var region = TestUtils.TestRegion; var c2dMessageMacCommand = new DevStatusRequest(); var c2dMessageMacCommandSize = hasMacInC2D ? c2dMessageMacCommand.Length : 0; var expectedDownlinkDatr = region.GetDataRateIndex(LoRaDataRate.Parse(datr)); var c2dPayloadSize = region.GetMaxPayloadSize(expectedDownlinkDatr) - c2dMessageMacCommandSize + 1 // make message too long on purpose - Constants.LoraProtocolOverheadSize; var c2dMessagePayload = TestUtils.GeneratePayload("123457890", (int)c2dPayloadSize); var c2dMessage = new ReceivedLoRaCloudToDeviceMessage() { Payload = c2dMessagePayload, Fport = FramePorts.App1, }; if (hasMacInC2D) { c2dMessage.MacCommands.Add(c2dMessageMacCommand); } using var cloudToDeviceMessage = c2dMessage.CreateMessage(); LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsAny <TimeSpan>())) .ReturnsAsync(cloudToDeviceMessage); LoRaDeviceClient.Setup(x => x.RejectAsync(cloudToDeviceMessage)) .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); using var request = CreateWaitableRequest(radioMetaData, loraPayload, constantElapsedTime: TimeSpan.Zero); messageProcessor.DispatchRequest(request); // Expectations // 1. Message was sent to IoT Hub Assert.True(await request.WaitCompleteAsync()); Assert.True(request.ProcessingSucceeded); var shouldHaveADownlink = isConfirmed || hasMacInUpstream; // 2. Return is downstream message ONLY // if is confirmed or had Mac commands in upstream message if (shouldHaveADownlink) { Assert.NotNull(request.ResponseDownlink); // TODO CHANGE THIS WHEN MOVING RXPK in #1086 // Assert.Equal(expectedDownlinkDatr, request.ResponseDownlink.Txpk.Datr); var downlinkMessage = DownstreamMessageSender.DownlinkMessages[0]; var payloadDataDown = new LoRaPayloadData(downlinkMessage.Data); payloadDataDown.Serialize(loraDevice.AppSKey.Value); Assert.Equal(payloadDataDown.DevAddr, loraDevice.DevAddr); Assert.Equal(MacMessageType.UnconfirmedDataDown, payloadDataDown.MessageType); if (hasMacInUpstream) { Assert.Equal(new LinkCheckAnswer(1, 1).Length, payloadDataDown.Frmpayload.Length); Assert.Equal(FramePort.MacCommand, payloadDataDown.Fport); } } else { Assert.Null(request.ResponseDownlink); } LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.VerifyAll(); }