Beispiel #1
0
        // Creates a new instance of NetworkServerConfiguration by reading values from environment variables
        public static NetworkServerConfiguration CreateFromEnvironmentVariables()
        {
            var config = new NetworkServerConfiguration();

            // Create case insensitive dictionary from environment variables
            var envVars = new CaseInsensitiveEnvironmentVariables(Environment.GetEnvironmentVariables());

            config.RunningAsIoTEdgeModule = !string.IsNullOrEmpty(envVars.GetEnvVar("IOTEDGE_APIVERSION", string.Empty));
            config.IoTHubHostName         = envVars.GetEnvVar("IOTEDGE_IOTHUBHOSTNAME", string.Empty);
            config.GatewayHostName        = envVars.GetEnvVar("IOTEDGE_GATEWAYHOSTNAME", string.Empty);
            config.EnableGateway          = envVars.GetEnvVar("ENABLE_GATEWAY", config.EnableGateway);
            config.GatewayID    = envVars.GetEnvVar("IOTEDGE_DEVICEID", string.Empty);
            config.HttpsProxy   = envVars.GetEnvVar("HTTPS_PROXY", string.Empty);
            config.Rx2DataRate  = envVars.GetEnvVar("RX2_DATR", -1) is var datrNum && (DataRateIndex)datrNum is var datr && Enum.IsDefined(datr) ? datr : null;
            config.Rx2Frequency = envVars.GetEnvVar("RX2_FREQ") is { } someFreq?Hertz.Mega(someFreq) : null;

            config.IoTEdgeTimeout = envVars.GetEnvVar("IOTEDGE_TIMEOUT", config.IoTEdgeTimeout);

            // facadeurl is allowed to be null as the value is coming from the twin in production.
            var facadeUrl = envVars.GetEnvVar("FACADE_SERVER_URL", string.Empty);

            config.FacadeServerUrl     = string.IsNullOrEmpty(facadeUrl) ? null : new Uri(envVars.GetEnvVar("FACADE_SERVER_URL", string.Empty));
            config.FacadeAuthCode      = envVars.GetEnvVar("FACADE_AUTH_CODE", string.Empty);
            config.LogLevel            = envVars.GetEnvVar("LOG_LEVEL", config.LogLevel);
            config.LogToConsole        = envVars.GetEnvVar("LOG_TO_CONSOLE", config.LogToConsole);
            config.LogToTcp            = envVars.GetEnvVar("LOG_TO_TCP", config.LogToTcp);
            config.LogToHub            = envVars.GetEnvVar("LOG_TO_HUB", config.LogToHub);
            config.LogToTcpAddress     = envVars.GetEnvVar("LOG_TO_TCP_ADDRESS", string.Empty);
            config.LogToTcpPort        = envVars.GetEnvVar("LOG_TO_TCP_PORT", config.LogToTcpPort);
            config.NetId               = new NetId(envVars.GetEnvVar("NETID", config.NetId.NetworkId));
            config.AllowedDevAddresses = envVars.GetEnvVar("AllowedDevAddresses", string.Empty)
                                         .Split(";")
                                         .Select(s => DevAddr.TryParse(s, out var devAddr) ? (true, Value: devAddr) : default)
 public static RadioMetadata GenerateTestRadioMetadata(
     DataRateIndex dataRate = DataRateIndex.DR2,
     Hertz?frequency        = null,
     uint antennaPreference = 1,
     ulong xtime            = 100000,
     uint gpstime           = 100000,
     double rssi            = 2.0,
     float snr = 0.1f) =>
 new RadioMetadata(dataRate, frequency ?? Hertz.Mega(868.3),
                   new RadioMetadataUpInfo(antennaPreference, xtime, gpstime, rssi, snr));
Beispiel #3
0
        public async Task When_Has_Custom_RX2DR_Should_Send_Correctly()
        {
            var devAddr   = new DevAddr(0x023637F8);
            var appSKey   = TestKeys.CreateAppSessionKey(0xABC0200000000000, 0x09);
            var nwkSKey   = TestKeys.CreateNetworkSessionKey(0xABC0200000000000, 0x09);
            var simDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, deviceClassType: 'c', gatewayID: ServerGatewayID));
            var devEUI    = simDevice.DevEUI;

            simDevice.SetupJoin(appSKey, nwkSKey, devAddr);

            this.deviceApi.Setup(x => x.GetPrimaryKeyByEuiAsync(devEUI))
            .ReturnsAsync("123");

            var twin = simDevice.CreateOTAATwin(
                desiredProperties: new Dictionary <string, object>
            {
                { TwinProperty.RX2DataRate, "10" }
            },
                reportedProperties: new Dictionary <string, object>
            {
                { TwinProperty.RX2DataRate, 10 },
                { TwinProperty.Region, LoRaRegionType.US915.ToString() },
                // OTAA device, already joined
                { TwinProperty.DevAddr, devAddr.ToString() },
                { TwinProperty.AppSKey, appSKey.ToString() },
                { TwinProperty.NwkSKey, nwkSKey.ToString() },
                { TwinProperty.LastProcessingStationEui, new StationEui(ulong.MaxValue).ToString() }
            });

            this.deviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None))
            .ReturnsAsync(twin);

            var c2dToDeviceMessage = new ReceivedLoRaCloudToDeviceMessage()
            {
                Payload   = "hello",
                DevEUI    = devEUI,
                Fport     = TestPort,
                MessageId = Guid.NewGuid().ToString(),
            };

            DownlinkMessage receivedDownlinkMessage = null;

            this.downstreamMessageSender.Setup(x => x.SendDownstreamAsync(It.IsNotNull <DownlinkMessage>()))
            .Returns(Task.CompletedTask)
            .Callback <DownlinkMessage>(d => receivedDownlinkMessage = d);

            var target = new DefaultClassCDevicesMessageSender(
                this.serverConfiguration,
                this.loRaDeviceRegistry,
                this.downstreamMessageSender.Object,
                this.frameCounterStrategyProvider,
                NullLogger <DefaultClassCDevicesMessageSender> .Instance,
                TestMeter.Instance);

            Assert.True(await target.SendAsync(c2dToDeviceMessage));

            this.downstreamMessageSender.Verify(x => x.SendDownstreamAsync(It.IsNotNull <DownlinkMessage>()), Times.Once());

            EnsureDownlinkIsCorrect(receivedDownlinkMessage, simDevice, c2dToDeviceMessage);
            Assert.Equal(DataRateIndex.DR10, receivedDownlinkMessage.Rx2.DataRate);
            Assert.Equal(Hertz.Mega(923.3), receivedDownlinkMessage.Rx2.Frequency);

            this.downstreamMessageSender.VerifyAll();
            this.deviceApi.VerifyAll();
            this.deviceClient.VerifyAll();
        }
Beispiel #4
0
        private async Task <uint> SendMessage(float currentLsnr, LoRaDataRate currentDR, uint payloadFcnt, SimulatedDevice simulatedDevice, MessageDispatcher messageProcessor, FrameControlFlags fctrl)
        {
            var payloadInt = simulatedDevice.CreateUnconfirmedDataUpMessage("1234", fcnt: payloadFcnt, fctrlFlags: fctrl);

            using var requestInt = CreateWaitableRequest(new RadioMetadata(TestUtils.TestRegion.GetDataRateIndex(currentDR), Hertz.Mega(868.1), new RadioMetadataUpInfo(0, 0, 0, 0, currentLsnr)), payloadInt);
            messageProcessor.DispatchRequest(requestInt);
            Assert.True(await requestInt.WaitCompleteAsync(-1));
            payloadFcnt++;
            return(payloadFcnt);
        }
Beispiel #5
0
        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);
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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);
            }
        }
Beispiel #8
0
        public async Task SendDownstreamAsync_Succeeds_WithValidDownlinkMessage_ClassADevice(bool rfchHasValue)
        {
            // arrange
            var downlinkMessage = new DownlinkMessage(this.loraDataByteArray,
                                                      123456,
                                                      new ReceiveWindow(DataRateIndex.DR5, Hertz.Mega(868.5)),
                                                      new ReceiveWindow(DataRateIndex.DR0, Hertz.Mega(869.5)),
                                                      this.devEui,
                                                      RxDelay1,
                                                      LoRaDeviceClassType.A,
                                                      this.stationEui,
                                                      rfchHasValue ? 1 : null);

            var actualMessage = string.Empty;

            this.webSocketWriter.Setup(s => s.SendAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Callback <string, CancellationToken>((message, _) =>
            {
                actualMessage = message;
            });
            // act
            await downlinkSender.SendDownstreamAsync(downlinkMessage);

            // assert
            Assert.NotEmpty(actualMessage);
            Assert.Contains(@"""msgtype"":""dnmsg""", actualMessage, StringComparison.InvariantCulture);
            Assert.Contains(@"""DevEui"":""FFFFFFFFFFFFFFFF"",", actualMessage, StringComparison.InvariantCulture);
            Assert.Contains(@"""dC"":0", actualMessage, StringComparison.InvariantCulture);
            Assert.Contains(@"""pdu"":""5245465551513D3D"",", actualMessage, StringComparison.InvariantCulture);
            Assert.Contains(@"""RxDelay"":1,", actualMessage, StringComparison.InvariantCulture);
            Assert.Contains(@"""RX1DR"":5,", actualMessage, StringComparison.InvariantCulture);
            Assert.Contains(@"""RX1Freq"":868500000,", actualMessage, StringComparison.InvariantCulture);
            Assert.Contains(@"""RX2DR"":0,", actualMessage, StringComparison.InvariantCulture);
            Assert.Contains(@"""RX2Freq"":869500000,", actualMessage, StringComparison.InvariantCulture);
            Assert.Contains(@"""xtime"":123456,", actualMessage, StringComparison.InvariantCulture);

            Assert.Contains(@"""priority"":0", actualMessage, StringComparison.InvariantCulture);

            if (rfchHasValue)
            {
                Assert.Contains(@"""rctx"":1", actualMessage, StringComparison.InvariantCulture);
            }
            else
            {
                Assert.DoesNotContain("rctx", actualMessage, StringComparison.InvariantCulture);
            }
        }
Beispiel #9
0
        public async Task SendDownstreamAsync_Fails_WithNonNullMessage_ButDefaultStationEui()
        {
            // arrange
            var downlinkMessage = new DownlinkMessage(this.loraDataByteArray,
                                                      0,
                                                      new ReceiveWindow(DataRateIndex.DR5, Hertz.Mega(868.5)),
                                                      new ReceiveWindow(DataRateIndex.DR0, Hertz.Mega(868.5)),
                                                      this.devEui,
                                                      RxDelay0,
                                                      LoRaDeviceClassType.C);

            // act and assert
            await Assert.ThrowsAsync <ArgumentException>(() => this.downlinkSender.SendDownstreamAsync(downlinkMessage));
        }