public async Task Test_ABP_Mismatch_NwkSKey_And_AppSKey_Fails_Mic_Validation() { var device = TestFixtureCi.Device7_ABP; LogTestStart(device); var appSKeyToUse = AppSessionKey.Parse("000102030405060708090A0B0C0D0E0F"); var nwkSKeyToUse = NetworkSessionKey.Parse("01020304050607080910111213141516"); Assert.NotEqual(appSKeyToUse, device.AppSKey); Assert.NotEqual(nwkSKeyToUse, device.NwkSKey); await ArduinoDevice.setDeviceModeAsync(LoRaArduinoSerial._device_mode_t.LWABP); await ArduinoDevice.setIdAsync(device.DevAddr, device.DeviceID, null); await ArduinoDevice.setKeyAsync(nwkSKeyToUse, appSKeyToUse, null); await ArduinoDevice.SetupLora(TestFixtureCi.Configuration); await ArduinoDevice.transferPacketAsync(GeneratePayloadMessage(), 10); // wait for serial logs to be ready await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_SENDING_PACKET); // After transferPacket: Expectation from serial // +MSG: Done // await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", this.lora.SerialLogs); // 0000000000000005: with devAddr 0028B1B0 check MIC failed. Device will be ignored from now on await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DevAddr}: with devAddr {device.DevAddr} check MIC failed"); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); TestFixtureCi.ClearLogs(); // Try with confirmed message await ArduinoDevice.transferPacketWithConfirmedAsync(GeneratePayloadMessage(), 10); await Task.Delay(Constants.DELAY_FOR_SERIAL_AFTER_SENDING_PACKET); // 0000000000000005: with devAddr 0028B1B0 check MIC failed await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DevAddr}: with devAddr {device.DevAddr} check MIC failed"); // wait until arduino stops trying to send confirmed msg await ArduinoDevice.WaitForIdleAsync(); }
public async Task Test_ABP_Invalid_NwkSKey_Fails_With_Mic_Error() { var device = TestFixtureCi.Device8_ABP; LogTestStart(device); var nwkSKeyToUse = NetworkSessionKey.Parse("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); Assert.NotEqual(nwkSKeyToUse, device.NwkSKey); await ArduinoDevice.setDeviceModeAsync(LoRaArduinoSerial._device_mode_t.LWABP); await ArduinoDevice.setIdAsync(device.DevAddr, device.DeviceID, null); await ArduinoDevice.setKeyAsync(nwkSKeyToUse, device.AppSKey, null); await ArduinoDevice.SetupLora(TestFixtureCi.Configuration); await ArduinoDevice.transferPacketAsync(GeneratePayloadMessage(), 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); // After transferPacket: Expectation from serial // +MSG: Done await AssertUtils.ContainsWithRetriesAsync("+MSG: Done", ArduinoDevice.SerialLogs); // 0000000000000008: with devAddr 0028B1B3 check MIC failed. Device will be ignored from now on await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DevAddr}: with devAddr {device.DevAddr} check MIC failed"); TestFixtureCi.ClearLogs(); // Try with confirmed message await ArduinoDevice.transferPacketWithConfirmedAsync(GeneratePayloadMessage(), 10); await Task.Delay(Constants.DELAY_BETWEEN_MESSAGES); // 0000000000000008: with devAddr 0028B1B3 check MIC failed. await TestFixtureCi.AssertNetworkServerModuleLogStartsWithAsync($"{device.DevAddr}: with devAddr {device.DevAddr} check MIC failed"); // Before starting new test, wait until Lora drivers stops sending/receiving data await ArduinoDevice.WaitForIdleAsync(); }
public async Task When_OTAA_Join_Then_Sends_Upstream_DirectMethod_Should_Send_Downstream(string deviceGatewayID) { var simDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, deviceClassType: 'c', gatewayID: deviceGatewayID)); LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(simDevice.CreateOTAATwin()); AppSessionKey? savedAppSKey = null; NetworkSessionKey?savedNwkSKey = null; var savedDevAddr = string.Empty; LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .ReturnsAsync(true) .Callback <TwinCollection, CancellationToken>((t, _) => { savedAppSKey = AppSessionKey.Parse(t[TwinProperty.AppSKey].Value); savedNwkSKey = NetworkSessionKey.Parse(t[TwinProperty.NwkSKey].Value); savedDevAddr = t[TwinProperty.DevAddr]; }); LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync((Message)null); if (deviceGatewayID == null) { LoRaDeviceApi.Setup(x => x.ExecuteFunctionBundlerAsync(simDevice.DevEUI, It.IsNotNull <FunctionBundlerRequest>())) .ReturnsAsync(new FunctionBundlerResult()); } LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(ServerConfiguration.GatewayID, simDevice.DevEUI, It.IsAny <DevNonce>())) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(simDevice.DevAddr, simDevice.DevEUI, "123").AsList())); using var cache = NewMemoryCache(); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); using var messageDispatcher = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); var payloadata = simDevice.CreateJoinRequest(); using var joinRequest = CreateWaitableRequest(payloadata); joinRequest.SetStationEui(new StationEui(ulong.MaxValue)); messageDispatcher.DispatchRequest(joinRequest); Assert.True(await joinRequest.WaitCompleteAsync()); Assert.True(joinRequest.ProcessingSucceeded); Assert.NotNull(savedAppSKey); Assert.NotNull(savedNwkSKey); Assert.NotEmpty(savedDevAddr); simDevice.SetupJoin(savedAppSKey.Value, savedNwkSKey.Value, DevAddr.Parse(savedDevAddr)); using var request = CreateWaitableRequest(simDevice.CreateUnconfirmedDataUpMessage("1")); request.SetStationEui(new StationEui(ulong.MaxValue)); messageDispatcher.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.True(request.ProcessingSucceeded); var classCSender = new DefaultClassCDevicesMessageSender( ServerConfiguration, deviceRegistry, DownstreamMessageSender, FrameCounterUpdateStrategyProvider, new TestOutputLogger <DefaultClassCDevicesMessageSender>(this.testOutputHelper), TestMeter.Instance); var c2d = new ReceivedLoRaCloudToDeviceMessage() { DevEUI = simDevice.DevEUI, MessageId = Guid.NewGuid().ToString(), Payload = "aaaa", Fport = FramePorts.App14, }; if (string.IsNullOrEmpty(deviceGatewayID)) { LoRaDeviceApi.Setup(x => x.NextFCntDownAsync(simDevice.DevEUI, simDevice.FrmCntDown, 0, ServerConfiguration.GatewayID)) .ReturnsAsync((ushort)(simDevice.FrmCntDown + 1)); } Assert.True(await classCSender.SendAsync(c2d)); Assert.Equal(2, DownstreamMessageSender.DownlinkMessages.Count); var downstreamMsg = DownstreamMessageSender.DownlinkMessages[1]; TestLogger.Log($"appSKey: {simDevice.AppSKey}, nwkSKey: {simDevice.NwkSKey}"); var downstreamPayloadBytes = downstreamMsg.Data; var downstreamPayload = new LoRaPayloadData(downstreamPayloadBytes); Assert.Equal(1, downstreamPayload.Fcnt); Assert.Equal(c2d.Fport, downstreamPayload.Fport); Assert.Equal(downstreamPayload.DevAddr, DevAddr.Parse(savedDevAddr)); var decryptedPayload = downstreamPayload.GetDecryptedPayload(simDevice.AppSKey.Value); Assert.Equal(c2d.Payload, Encoding.UTF8.GetString(decryptedPayload)); LoRaDeviceApi.VerifyAll(); LoRaDeviceClient.VerifyAll(); }
private NetworkSessionKey GetNetworkSessionKey(int value) => NetworkSessionKey.Parse(GetKeyString(value));
public async Task When_Join_Fails_Due_To_Timeout_Second_Try_Should_Reuse_Cached_Device_Twin(string deviceGatewayID) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var joinRequestPayload1 = simulatedDevice.CreateJoinRequest(); var devAddr = (DevAddr?)null; var devEui = simulatedDevice.LoRaDevice.DevEui; // Device twin will be queried twice, 1st time will take 7 seconds, 2nd time 0.1 second var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEui.ToString(); twin.Properties.Desired[TwinProperty.AppEui] = simulatedDevice.LoRaDevice.AppEui?.ToString(); twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey?.ToString(); if (deviceGatewayID != null) { twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; } twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(twin); // Device twin will be updated AppSessionKey? afterJoinAppSKey = null; NetworkSessionKey?afterJoinNwkSKey = null; string afterJoinDevAddr = null; LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Callback <TwinCollection, CancellationToken>((updatedTwin, _) => { afterJoinAppSKey = AppSessionKey.Parse(updatedTwin[TwinProperty.AppSKey].Value); afterJoinNwkSKey = NetworkSessionKey.Parse(updatedTwin[TwinProperty.NwkSKey].Value); afterJoinDevAddr = updatedTwin[TwinProperty.DevAddr]; }) .ReturnsAsync(true); // Lora device api will be search by devices with matching deveui, LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(ServerConfiguration.GatewayID, devEui, joinRequestPayload1.DevNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEui, "aabb").AsList())); using var memoryCache = new MemoryCache(new MemoryCacheOptions()); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, memoryCache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); // 1st join request // Should fail using var joinRequest1 = CreateWaitableRequest(joinRequestPayload1, constantElapsedTime: TimeSpan.FromSeconds(7)); messageProcessor.DispatchRequest(joinRequest1); Assert.True(await joinRequest1.WaitCompleteAsync()); Assert.True(joinRequest1.ProcessingFailed); Assert.Null(joinRequest1.ResponseDownlink); Assert.Equal(LoRaDeviceRequestFailedReason.ReceiveWindowMissed, joinRequest1.ProcessingFailedReason); // 2nd attempt var joinRequestPayload2 = simulatedDevice.CreateJoinRequest(); // setup response to this device search LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(ServerConfiguration.GatewayID, devEui, joinRequestPayload2.DevNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEui, "aabb").AsList())); using var joinRequest2 = CreateWaitableRequest(joinRequestPayload2); messageProcessor.DispatchRequest(joinRequest2); Assert.True(await joinRequest2.WaitCompleteAsync()); Assert.True(joinRequest2.ProcessingSucceeded); Assert.NotNull(joinRequest2.ResponseDownlink); Assert.Single(DownstreamMessageSender.DownlinkMessages); var joinRequestDownlinkMessage = DownstreamMessageSender.DownlinkMessages[0]; var joinAccept = new LoRaPayloadJoinAccept(joinRequestDownlinkMessage.Data, simulatedDevice.LoRaDevice.AppKey.Value); Assert.Equal(joinAccept.DevAddr.ToString(), afterJoinDevAddr); Assert.True(DeviceCache.TryGetByDevEui(devEui, out var loRaDevice)); Assert.Equal(simulatedDevice.AppKey, loRaDevice.AppKey); Assert.Equal(simulatedDevice.AppEui, loRaDevice.AppEui); Assert.Equal(afterJoinAppSKey, loRaDevice.AppSKey); Assert.Equal(afterJoinNwkSKey, loRaDevice.NwkSKey); Assert.Equal(joinAccept.DevAddr, loRaDevice.DevAddr); if (deviceGatewayID == null) { Assert.Null(loRaDevice.GatewayID); } else { Assert.Equal(deviceGatewayID, loRaDevice.GatewayID); } // fcnt is restarted Assert.Equal(0U, loRaDevice.FCntUp); Assert.Equal(0U, loRaDevice.FCntDown); Assert.False(loRaDevice.HasFrameCountChanges); // searching the device should happen twice LoRaDeviceApi.Verify(x => x.SearchAndLockForJoinAsync(ServerGatewayID, devEui, It.IsAny <DevNonce>()), Times.Exactly(2)); // getting the device twin should happens once LoRaDeviceClient.Verify(x => x.GetTwinAsync(CancellationToken.None), Times.Once()); LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.VerifyAll(); }
public static bool TryRead <T>(this TwinCollection twinCollection, string property, ILogger?logger, [NotNullWhen(true)] out T?value) { _ = twinCollection ?? throw new ArgumentNullException(nameof(twinCollection)); value = default; if (!twinCollection.Contains(property)) { return(false); } // cast to object to avoid dynamic code to be generated var some = (object)twinCollection[property]; // quick path for values that can be directly converted if (some is Newtonsoft.Json.Linq.JValue someJValue) { if (someJValue.Value is T someT) { value = someT; return(true); } } try { var t = typeof(T); var tPrime = Nullable.GetUnderlyingType(t) ?? t; // For 100% case coverage we should handle the case where type T is nullable and the token is null. // Since this is not possible in IoT hub, we do not handle the null cases exhaustively. if (tPrime == StationEuiType) { value = (T)(object)StationEui.Parse(some.ToString()); } else if (tPrime == DevNonceType) { value = (T)(object)new DevNonce(Convert.ToUInt16(some, CultureInfo.InvariantCulture)); } else if (tPrime == DevAddrType) { value = (T)(object)DevAddr.Parse(some.ToString()); } else if (tPrime == AppSessionKeyType) { value = (T)(object)AppSessionKey.Parse(some.ToString()); } else if (tPrime == AppKeyType) { value = (T)(object)AppKey.Parse(some.ToString()); } else if (tPrime == NetworkSessionKeyType) { value = (T)(object)NetworkSessionKey.Parse(some.ToString()); } else if (tPrime == JoinEuiType) { value = (T)(object)JoinEui.Parse(some.ToString()); } else if (tPrime == NetIdType) { value = (T)(object)NetId.Parse(some.ToString()); } else { value = (T)Convert.ChangeType(some, t, CultureInfo.InvariantCulture); } if (t.IsEnum && !t.IsEnumDefined(value)) { LogParsingError(logger, property, some); return(false); } } catch (Exception ex) when(ex is ArgumentException or InvalidCastException or FormatException or OverflowException or Newtonsoft.Json.JsonSerializationException) { LogParsingError(logger, property, some, ex); return(false); } return(true); }
private async Task Join_With_Subsequent_Unconfirmed_And_Confirmed_Messages(string deviceGatewayID, uint initialFcntUp, uint initialFcntDown, uint startingPayloadFcnt, int netId, Region region) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var joinRequestPayload = simulatedDevice.CreateJoinRequest(); var devAddr = (DevAddr?)null; var devEui = simulatedDevice.LoRaDevice.DevEui; ServerConfiguration.NetId = new NetId(netId); // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEui.ToString(); twin.Properties.Desired[TwinProperty.AppEui] = simulatedDevice.LoRaDevice.AppEui?.ToString(); twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey?.ToString(); if (deviceGatewayID != null) { twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; } twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; twin.Properties.Reported[TwinProperty.FCntUp] = initialFcntUp; twin.Properties.Reported[TwinProperty.FCntDown] = initialFcntDown; LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)).ReturnsAsync(twin); // Device twin will be updated AppSessionKey? afterJoinAppSKey = null; NetworkSessionKey?afterJoinNwkSKey = null; string afterJoinDevAddr = null; uint afterJoinFcntDown = 0; uint afterJoinFcntUp = 0; TwinCollection actualSavedTwin = null; LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Callback <TwinCollection, CancellationToken>((updatedTwin, _) => { if (updatedTwin.Contains(TwinProperty.AppSKey)) { afterJoinAppSKey = AppSessionKey.Parse(updatedTwin[TwinProperty.AppSKey].Value); } if (updatedTwin.Contains(TwinProperty.NwkSKey)) { afterJoinNwkSKey = NetworkSessionKey.Parse(updatedTwin[TwinProperty.NwkSKey].Value); } if (updatedTwin.Contains(TwinProperty.DevAddr)) { afterJoinDevAddr = updatedTwin[TwinProperty.DevAddr]; } afterJoinFcntDown = updatedTwin[TwinProperty.FCntDown]; afterJoinFcntUp = updatedTwin[TwinProperty.FCntUp]; actualSavedTwin = updatedTwin; }) .ReturnsAsync(true); // message will be sent var sentTelemetry = new List <LoRaDeviceTelemetry>(); LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((t, _) => sentTelemetry.Add(t)) .ReturnsAsync(true); // C2D message will be checked LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync((Message)null); // Lora device api will be search by devices with matching deveui, LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(ServerConfiguration.GatewayID, devEui, joinRequestPayload.DevNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEui, "aabb").AsList())); // multi gateway will request a next frame count down from the lora device api, prepare it if (string.IsNullOrEmpty(deviceGatewayID)) { LoRaDeviceApi.Setup(x => x.NextFCntDownAsync(devEui, 0, startingPayloadFcnt + 1, ServerConfiguration.GatewayID)) .ReturnsAsync((ushort)1); LoRaDeviceApi .Setup(x => x.ExecuteFunctionBundlerAsync(devEui, It.IsAny <FunctionBundlerRequest>())) .ReturnsAsync(() => new FunctionBundlerResult { AdrResult = new LoRaTools.ADR.LoRaADRResult { CanConfirmToDevice = false, FCntDown = 1, NbRepetition = 1, TxPower = 0 }, NextFCntDown = 1 }); } // using factory to create mock of using var memoryCache = new MemoryCache(new MemoryCacheOptions()); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, memoryCache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); // Send to message processor using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); // Create a join request and join with the device. using var joinRequest = CreateWaitableRequest(joinRequestPayload, constantElapsedTime: TimeSpan.FromMilliseconds(300), region: region); messageProcessor.DispatchRequest(joinRequest); Assert.True(await joinRequest.WaitCompleteAsync()); Assert.True(joinRequest.ProcessingSucceeded, $"Failed due to '{joinRequest.ProcessingFailedReason}'."); Assert.NotNull(joinRequest.ResponseDownlink); Assert.Single(DownstreamMessageSender.DownlinkMessages); var downlinkJoinAcceptMessage = DownstreamMessageSender.DownlinkMessages[0]; var joinAccept = new LoRaPayloadJoinAccept(downlinkJoinAcceptMessage.Data, simulatedDevice.LoRaDevice.AppKey.Value); Assert.Equal(joinAccept.DevAddr.ToString(), afterJoinDevAddr); // check that the device is in cache Assert.True(DeviceCache.TryGetByDevEui(devEui, out var loRaDevice)); Assert.Equal(afterJoinAppSKey, loRaDevice.AppSKey); Assert.Equal(afterJoinNwkSKey, loRaDevice.NwkSKey); Assert.Equal(afterJoinDevAddr, loRaDevice.DevAddr.ToString()); var netIdBytes = BitConverter.GetBytes(netId); Assert.Equal(netIdBytes[0] & 0b01111111, DevAddr.Parse(afterJoinDevAddr).NetworkId); if (deviceGatewayID == null) { Assert.Null(loRaDevice.GatewayID); } else { Assert.Equal(deviceGatewayID, loRaDevice.GatewayID); } // Assert that after a join the fcnt is restarted Assert.Equal(0U, afterJoinFcntDown); Assert.Equal(0U, afterJoinFcntUp); Assert.Equal(0U, loRaDevice.FCntUp); Assert.Equal(0U, loRaDevice.FCntDown); Assert.False(loRaDevice.HasFrameCountChanges); simulatedDevice.LoRaDevice.AppSKey = afterJoinAppSKey; simulatedDevice.LoRaDevice.NwkSKey = afterJoinNwkSKey; simulatedDevice.LoRaDevice.DevAddr = DevAddr.Parse(afterJoinDevAddr); // sends unconfirmed message with a given starting frame counter var unconfirmedMessagePayload = simulatedDevice.CreateUnconfirmedDataUpMessage("100", fcnt: startingPayloadFcnt); var radioMetadata = TestUtils.GenerateTestRadioMetadata(); using var unconfirmedRequest = CreateWaitableRequest(radioMetadata, unconfirmedMessagePayload, constantElapsedTime: TimeSpan.FromMilliseconds(300)); messageProcessor.DispatchRequest(unconfirmedRequest); Assert.True(await unconfirmedRequest.WaitCompleteAsync()); Assert.Null(unconfirmedRequest.ResponseDownlink); Assert.True(unconfirmedRequest.ProcessingSucceeded); // fcnt up was updated Assert.Equal(startingPayloadFcnt, loRaDevice.FCntUp); Assert.Equal(0U, loRaDevice.FCntDown); // If the starting payload was not 0, it is expected that it updates the framecounter char // The device will perform the frame counter update and at this point in time it will have the same frame counter as the desired // Therefore savechangesasync will set the hasframcounter change to false // if (startingPayloadFcnt != 0) // { // // Frame change flag will be set, only saving every 10 messages // Assert.True(loRaDevice.HasFrameCountChanges); // } Assert.Single(sentTelemetry); // sends confirmed message var confirmedMessagePayload = simulatedDevice.CreateConfirmedDataUpMessage("200", fcnt: startingPayloadFcnt + 1); using var confirmedRequest = CreateWaitableRequest(confirmedMessagePayload, constantElapsedTime: TimeSpan.FromMilliseconds(300), region: region); messageProcessor.DispatchRequest(confirmedRequest); Assert.True(await confirmedRequest.WaitCompleteAsync()); Assert.True(confirmedRequest.ProcessingSucceeded); Assert.NotNull(confirmedRequest.ResponseDownlink); Assert.Equal(2, DownstreamMessageSender.DownlinkMessages.Count); Assert.Equal(2, sentTelemetry.Count); var downstreamMessage = DownstreamMessageSender.DownlinkMessages[1]; // validates txpk according to region DeviceJoinInfo deviceJoinInfo = null; if (region is RegionCN470RP2 cnRegion && cnRegion.TryGetJoinChannelIndex(confirmedRequest.RadioMetadata.Frequency, out var channelIndex)) { deviceJoinInfo = new DeviceJoinInfo(channelIndex); } Assert.True(region.TryGetDownstreamChannelFrequency(confirmedRequest.RadioMetadata.Frequency, confirmedRequest.RadioMetadata.DataRate, deviceJoinInfo, downstreamFrequency: out var frequency)); Assert.Equal(frequency, downstreamMessage.Rx1?.Frequency); var rx2Freq = region.GetDownstreamRX2Freq(null, deviceJoinInfo, NullLogger.Instance); Assert.Equal(rx2Freq, downstreamMessage.Rx2.Frequency); var rx2DataRate = region.GetDownstreamRX2DataRate(null, null, deviceJoinInfo, NullLogger.Instance); Assert.Equal(rx2DataRate, downstreamMessage.Rx2.DataRate); // fcnt up was updated Assert.Equal(startingPayloadFcnt + 1, loRaDevice.FCntUp); Assert.Equal(1U, loRaDevice.FCntDown); // Frame change flag will be set, only saving every 10 messages Assert.True(loRaDevice.HasFrameCountChanges); // C2D message will be checked twice (for AS923 only once, since we use the first C2D message to send the dwell time MAC command) var numberOfC2DMessageChecks = region is RegionAS923 ? 1 : 2; LoRaDeviceClient.Verify(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>()), Times.Exactly(numberOfC2DMessageChecks)); // has telemetry with both fcnt Assert.Single(sentTelemetry, (t) => t.Fcnt == startingPayloadFcnt); Assert.Single(sentTelemetry, (t) => t.Fcnt == (startingPayloadFcnt + 1)); // should not save class C device properties Assert.False(actualSavedTwin.Contains(TwinProperty.Region)); Assert.False(actualSavedTwin.Contains(TwinProperty.PreferredGatewayID)); LoRaDeviceClient.VerifyAll(); }
public NetworkSessionKey GetNetworkSessionKey(int deviceId, bool multiGw = false) => NetworkSessionKey.Parse(GetKey32(deviceId, multiGw));
public async Task When_Getting_Custom_RX2_DR_From_Twin_Returns_JoinAccept_With_Correct_Settings_And_Behaves_Correctly(DataRateIndex rx2datarate) { var deviceGatewayID = ServerGatewayID; var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var joinRequest = simulatedDevice.CreateJoinRequest(); AppSessionKey? afterJoinAppSKey = null; NetworkSessionKey?afterJoinNwkSKey = null; string afterJoinDevAddr = null; var afterJoinFcntDown = -1; var afterJoinFcntUp = -1; uint startingPayloadFcnt = 0; var devAddr = (DevAddr?)null; var devEui = simulatedDevice.LoRaDevice.DevEui; // message will be sent var sentTelemetry = new List <LoRaDeviceTelemetry>(); LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((t, _) => sentTelemetry.Add(t)) .ReturnsAsync(true); // C2D message will be checked LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync((Message)null); // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEui.ToString(); twin.Properties.Desired[TwinProperty.AppEui] = simulatedDevice.LoRaDevice.AppEui?.ToString(); twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey?.ToString(); twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; twin.Properties.Desired[TwinProperty.RX2DataRate] = rx2datarate; twin.Properties.Desired[TwinProperty.PreferredWindow] = 2; LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)).ReturnsAsync(twin); LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Callback <TwinCollection, CancellationToken>((updatedTwin, _) => { afterJoinAppSKey = AppSessionKey.Parse(updatedTwin[TwinProperty.AppSKey].Value); afterJoinNwkSKey = NetworkSessionKey.Parse(updatedTwin[TwinProperty.NwkSKey].Value); afterJoinDevAddr = updatedTwin[TwinProperty.DevAddr].Value; afterJoinFcntDown = updatedTwin[TwinProperty.FCntDown].Value; afterJoinFcntUp = updatedTwin[TwinProperty.FCntUp].Value; }) .ReturnsAsync(true); // Lora device api will be search by devices with matching deveui, LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(ServerConfiguration.GatewayID, devEui, joinRequest.DevNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEui, "aabb").AsList())); using var memoryCache = new MemoryCache(new MemoryCacheOptions()); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, memoryCache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); // Send to message processor using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); using var request = CreateWaitableRequest(TestUtils.GenerateTestRadioMetadata(), joinRequest); messageProcessor.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.NotNull(request.ResponseDownlink); Assert.Single(DownstreamMessageSender.DownlinkMessages); var downlinkMessage = DownstreamMessageSender.DownlinkMessages[0]; var joinAccept = new LoRaPayloadJoinAccept(downlinkMessage.Data, simulatedDevice.LoRaDevice.AppKey.Value); if (rx2datarate is > DR0 and < DR8) { Assert.Equal(rx2datarate, joinAccept.Rx2Dr); }
public async Task When_Getting_Device_Information_From_Twin_Returns_JoinAccept(string deviceGatewayID) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var joinRequest = simulatedDevice.CreateJoinRequest(); var devAddr = (DevAddr?)null; var devEui = simulatedDevice.LoRaDevice.DevEui; // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEui.ToString(); twin.Properties.Desired[TwinProperty.AppEui] = simulatedDevice.LoRaDevice.AppEui?.ToString(); twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey?.ToString(); if (deviceGatewayID != null) { twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; } twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)).ReturnsAsync(twin); // Device twin will be updated AppSessionKey? afterJoinAppSKey = null; NetworkSessionKey?afterJoinNwkSKey = null; string afterJoinDevAddr = null; LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Callback <TwinCollection, CancellationToken>((updatedTwin, _) => { afterJoinAppSKey = AppSessionKey.Parse(updatedTwin[TwinProperty.AppSKey].Value); afterJoinNwkSKey = NetworkSessionKey.Parse(updatedTwin[TwinProperty.NwkSKey].Value); afterJoinDevAddr = updatedTwin[TwinProperty.DevAddr]; }) .ReturnsAsync(true); // Lora device api will be search by devices with matching deveui, LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(ServerConfiguration.GatewayID, devEui, joinRequest.DevNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEui, "aabb").AsList())); using var memoryCache = new MemoryCache(new MemoryCacheOptions()); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, memoryCache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); // Send to message processor using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); using var request = CreateWaitableRequest(TestUtils.GenerateTestRadioMetadata(), joinRequest); messageProcessor.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.NotNull(request.ResponseDownlink); Assert.Single(DownstreamMessageSender.DownlinkMessages); var downlinkMessage = DownstreamMessageSender.DownlinkMessages[0]; var joinAccept = new LoRaPayloadJoinAccept(downlinkMessage.Data, simulatedDevice.LoRaDevice.AppKey.Value); Assert.Equal(joinAccept.DevAddr.ToString(), afterJoinDevAddr); // check that the device is in cache Assert.True(DeviceCache.HasRegistrations(joinAccept.DevAddr)); Assert.True(DeviceCache.TryGetByDevEui(devEui, out var cachedDevice)); Assert.Equal(afterJoinAppSKey, cachedDevice.AppSKey); Assert.Equal(afterJoinNwkSKey, cachedDevice.NwkSKey); Assert.Equal(joinAccept.DevAddr, cachedDevice.DevAddr); Assert.True(cachedDevice.IsOurDevice); if (deviceGatewayID == null) { Assert.Null(cachedDevice.GatewayID); } else { Assert.Equal(deviceGatewayID, cachedDevice.GatewayID); } // fcnt is restarted Assert.Equal(0U, cachedDevice.FCntUp); Assert.Equal(0U, cachedDevice.FCntDown); Assert.False(cachedDevice.HasFrameCountChanges); }