Exemplo n.º 1
0
        private void _txChar_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
        {
            // enqueue new data
            var data = new byte[args.CharacteristicValue.Length];

            DataReader.FromBuffer(args.CharacteristicValue).ReadBytes(data);
            _rxData.AddRange(data);

            // try parsing
            int             consumedBytes = 0;
            DownlinkMessage msg           = null;

            using (var stream = new MemoryStream(_rxData.ToArray()))
            {
                msg           = DownlinkMessage.Parser.ParseDelimitedFrom(stream);
                consumedBytes = (int)stream.Position;
            }

            // publish
            if (msg != null)
            {
                _rxData.RemoveRange(0, consumedBytes);
                DownlinkMessageReceived?.Invoke(this, msg);
            }
        }
Exemplo n.º 2
0
        private static DownlinkMessage BuildDownstreamMessage(LoRaDevice loRaDevice,
                                                              StationEui stationEUI,
                                                              ILogger logger,
                                                              ulong xTime,
                                                              ReceiveWindow?rx1,
                                                              ReceiveWindow rx2,
                                                              RxDelay lnsRxDelay,
                                                              LoRaPayloadData loRaMessage,
                                                              LoRaDeviceClassType deviceClassType,
                                                              uint?antennaPreference = null)
        {
            var messageBytes    = loRaMessage.Serialize(loRaDevice.AppSKey.Value, loRaDevice.NwkSKey.Value);
            var downlinkMessage = new DownlinkMessage(
                messageBytes,
                xTime,
                rx1, rx2,
                loRaDevice.DevEUI,
                lnsRxDelay,
                deviceClassType,
                stationEUI,
                antennaPreference
                );

            if (logger.IsEnabled(LogLevel.Debug))
            {
                logger.LogDebug($"{loRaMessage.MessageType} {JsonConvert.SerializeObject(downlinkMessage)}");
            }
            return(downlinkMessage);
        }
        public override void NotifySucceeded(LoRaDevice loRaDevice, DownlinkMessage downlink)
        {
            base.NotifySucceeded(loRaDevice, downlink);

            ResponseDownlink    = downlink;
            ProcessingSucceeded = true;
            this.complete.Release();
        }
Exemplo n.º 4
0
        public async Task When_Sending_Message_Should_Send_Downlink_To_DownstreamMessageSender(string deviceGatewayID)
        {
            var simDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, deviceClassType: 'c', gatewayID: deviceGatewayID));
            var devEUI    = simDevice.DevEUI;

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

            var twin = simDevice.CreateABPTwin(reportedProperties: new Dictionary <string, object>
            {
                { TwinProperty.Region, LoRaRegionType.EU868.ToString() },
                { TwinProperty.LastProcessingStationEui, new StationEui(ulong.MaxValue).ToString() }
            });

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

            if (string.IsNullOrEmpty(deviceGatewayID))
            {
                // will update the fcnt down
                this.deviceApi.Setup(x => x.NextFCntDownAsync(devEUI, simDevice.FrmCntDown, 0, this.serverConfiguration.GatewayID))
                .ReturnsAsync((ushort)(simDevice.FrmCntDown + 1));
            }

            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);

            this.downstreamMessageSender.VerifyAll();
            this.deviceApi.VerifyAll();
            this.deviceClient.VerifyAll();
        }
Exemplo n.º 5
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));
        }
Exemplo n.º 6
0
        private static void EnsureDownlinkIsCorrect(DownlinkMessage downlink, SimulatedDevice simDevice, ReceivedLoRaCloudToDeviceMessage sentMessage)
        {
            Assert.NotNull(downlink);
            Assert.False(downlink.Data.IsEmpty);

            var downstreamPayloadBytes = downlink.Data;
            var downstreamPayload      = new LoRaPayloadData(downstreamPayloadBytes);

            Assert.Equal(sentMessage.Fport, downstreamPayload.Fport);
            Assert.Equal(downstreamPayload.DevAddr, simDevice.DevAddr);
            var decryptedPayload = downstreamPayload.GetDecryptedPayload(simDevice.AppSKey.Value);

            Assert.Equal(sentMessage.Payload, Encoding.UTF8.GetString(decryptedPayload));
        }
Exemplo n.º 7
0
        public async Task SendDownstreamAsync_Succeeds_WithValidDownlinkMessage_ClassCDevice(bool rfchHasValue)
        {
            // arrange
            var downlinkMessage = new DownlinkMessage(this.loraDataByteArray,
                                                      0,
                                                      new ReceiveWindow(DataRateIndex.DR5, Hertz.Mega(868.5)),
                                                      new ReceiveWindow(DataRateIndex.DR0, Hertz.Mega(869.5)),
                                                      this.devEui,
                                                      RxDelay0,
                                                      LoRaDeviceClassType.C,
                                                      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"":2,", actualMessage, StringComparison.InvariantCulture);
            Assert.Contains(@"""pdu"":""5245465551513D3D"",", actualMessage, StringComparison.InvariantCulture);
            // Will select DR0 as it is the second DR.
            Assert.Contains(@"""RX2DR"":0,", actualMessage, StringComparison.InvariantCulture);
            Assert.Contains(@"""RX2Freq"":869500000,", actualMessage, StringComparison.InvariantCulture);

            Assert.Contains(@"""priority"":0", actualMessage, StringComparison.InvariantCulture);
            Assert.DoesNotContain("RxDelay", actualMessage, StringComparison.InvariantCulture);
            Assert.DoesNotContain("RX1DR", actualMessage, StringComparison.InvariantCulture);
            Assert.DoesNotContain("RX1Freq", actualMessage, StringComparison.InvariantCulture);
            Assert.DoesNotContain(@"""xtime"":123456", actualMessage, StringComparison.InvariantCulture);

            if (rfchHasValue)
            {
                Assert.Contains(@"""rctx"":1,", actualMessage, StringComparison.InvariantCulture);
            }
            else
            {
                Assert.DoesNotContain("rctx", actualMessage, StringComparison.InvariantCulture);
            }
        }
        private string Message(DownlinkMessage message)
        {
            using var ms     = new MemoryStream();
            using var writer = new Utf8JsonWriter(ms);

            writer.WriteStartObject();

            writer.WriteString("msgtype", LnsMessageType.DownlinkMessage.ToBasicStationString());
            writer.WriteString("DevEui", message.DevEui.ToString());

            writer.WriteNumber("dC", message.DeviceClassType switch
            {
                LoRaDeviceClassType.A => 0,
                LoRaDeviceClassType.B => 1,
                LoRaDeviceClassType.C => 2,
                _ => throw new SwitchExpressionException(),
            });
        public async Task SendDownstreamAsync(DownlinkMessage message)
        {
            if (message is null)
            {
                throw new ArgumentNullException(nameof(message));
            }
            if (message.StationEui == default)
            {
                throw new ArgumentException($"A proper StationEui needs to be set. Received '{message.StationEui}'.");
            }

            if (this.socketWriterRegistry.TryGetHandle(message.StationEui, out var webSocketWriterHandle))
            {
                var payload = Message(message);
                await webSocketWriterHandle.SendAsync(payload, CancellationToken.None);
            }
            else
            {
                this.logger.LogWarning("Could not retrieve an active connection for Station with EUI '{StationEui}'. The payload '{Payload}' will be dropped.", message.StationEui, message.Data.ToHex());
            }
        }
        internal void OnUartTx(byte[] data, ushort length)
        {
            // enqueue new data
            _rxData.AddRange(data);

            // try parsing
            int             consumedBytes = 0;
            DownlinkMessage msg           = null;

            using (var stream = new MemoryStream(_rxData.ToArray()))
            {
                msg           = DownlinkMessage.Parser.ParseDelimitedFrom(stream);
                consumedBytes = (int)stream.Position;
            }

            // publish
            if (msg != null)
            {
                _rxData.RemoveRange(0, consumedBytes);
                DownlinkMessageReceived?.Invoke(this, msg);
            }
        }
Exemplo n.º 11
0
 public override void NotifySucceeded(LoRaDevice loRaDevice, DownlinkMessage downlink)
 {
     this.wrappedRequest.NotifySucceeded(loRaDevice, downlink);
     TrackProcessingTime();
 }
Exemplo n.º 12
0
 internal DownlinkMessageBuilderResponse(DownlinkMessage downlinkMessage, bool isMessageTooLong, ReceiveWindowNumber?receiveWindow)
 {
     DownlinkMessage  = downlinkMessage;
     IsMessageTooLong = isMessageTooLong;
     ReceiveWindow    = receiveWindow;
 }
Exemplo n.º 13
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();
        }
 public LoRaDeviceRequestProcessResult(LoRaDevice loRaDevice, LoRaRequest request, DownlinkMessage downlinkMessage = null)
 {
     LoRaDevice      = loRaDevice;
     Request         = request;
     DownlinkMessage = downlinkMessage;
 }
        internal async Task ProcessJoinRequestAsync(LoRaRequest request)
        {
            LoRaDevice loRaDevice = null;
            var        loraRegion = request.Region;

            try
            {
                var timeWatcher       = request.GetTimeWatcher();
                var processingTimeout = timeWatcher.GetRemainingTimeToJoinAcceptSecondWindow() - TimeSpan.FromMilliseconds(100);
                using var joinAcceptCancellationToken = new CancellationTokenSource(processingTimeout > TimeSpan.Zero ? processingTimeout : TimeSpan.Zero);

                var joinReq = (LoRaPayloadJoinRequest)request.Payload;

                var devEui = joinReq.DevEUI;

                using var scope = this.logger.BeginDeviceScope(devEui);

                this.logger.LogInformation("join request received");

                if (this.concentratorDeduplication.CheckDuplicateJoin(request) is ConcentratorDeduplicationResult.Duplicate)
                {
                    request.NotifyFailed(loRaDevice, LoRaDeviceRequestFailedReason.DeduplicationDrop);
                    // we do not log here as the concentratorDeduplication service already does more detailed logging
                    return;
                }

                loRaDevice = await this.deviceRegistry.GetDeviceForJoinRequestAsync(devEui, joinReq.DevNonce);

                if (loRaDevice == null)
                {
                    request.NotifyFailed(devEui.ToString(), LoRaDeviceRequestFailedReason.UnknownDevice);
                    // we do not log here as we assume that the deviceRegistry does a more informed logging if returning null
                    return;
                }

                if (loRaDevice.AppKey is null)
                {
                    this.logger.LogError("join refused: missing AppKey for OTAA device");
                    request.NotifyFailed(loRaDevice, LoRaDeviceRequestFailedReason.InvalidJoinRequest);
                    return;
                }

                var appKey = loRaDevice.AppKey.Value;

                this.joinRequestCounter?.Add(1);

                if (loRaDevice.AppEui != joinReq.AppEui)
                {
                    this.logger.LogError("join refused: AppEUI for OTAA does not match device");
                    request.NotifyFailed(loRaDevice, LoRaDeviceRequestFailedReason.InvalidJoinRequest);
                    return;
                }

                if (!joinReq.CheckMic(appKey))
                {
                    this.logger.LogError("join refused: invalid MIC");
                    request.NotifyFailed(loRaDevice, LoRaDeviceRequestFailedReason.JoinMicCheckFailed);
                    return;
                }

                // Make sure that is a new request and not a replay
                if (loRaDevice.DevNonce is { } devNonce&& devNonce == joinReq.DevNonce)
                {
                    if (string.IsNullOrEmpty(loRaDevice.GatewayID))
                    {
                        this.logger.LogInformation("join refused: join already processed by another gateway");
                    }
                    else
                    {
                        this.logger.LogError("join refused: DevNonce already used by this device");
                    }

                    request.NotifyFailed(loRaDevice, LoRaDeviceRequestFailedReason.JoinDevNonceAlreadyUsed);
                    return;
                }

                // Check that the device is joining through the linked gateway and not another
                if (!loRaDevice.IsOurDevice)
                {
                    this.logger.LogInformation("join refused: trying to join not through its linked gateway, ignoring join request");
                    request.NotifyFailed(loRaDevice, LoRaDeviceRequestFailedReason.HandledByAnotherGateway);
                    return;
                }

                var netId    = this.configuration.NetId;
                var appNonce = new AppNonce(RandomNumberGenerator.GetInt32(toExclusive: AppNonce.MaxValue + 1));
                var appSKey  = OTAAKeysGenerator.CalculateAppSessionKey(appNonce, netId, joinReq.DevNonce, appKey);
                var nwkSKey  = OTAAKeysGenerator.CalculateNetworkSessionKey(appNonce, netId, joinReq.DevNonce, appKey);
                var address  = RandomNumberGenerator.GetInt32(toExclusive: DevAddr.MaxNetworkAddress + 1);
                // The 7 LBS of the NetID become the NwkID of a DevAddr:
                var devAddr = new DevAddr(unchecked ((byte)netId.NetworkId), address);

                var oldDevAddr = loRaDevice.DevAddr;

                if (!timeWatcher.InTimeForJoinAccept())
                {
                    this.receiveWindowMisses?.Add(1);
                    // in this case it's too late, we need to break and avoid saving twins
                    this.logger.LogInformation("join refused: processing of the join request took too long, sending no message");
                    request.NotifyFailed(loRaDevice, LoRaDeviceRequestFailedReason.ReceiveWindowMissed);
                    return;
                }

                var updatedProperties = new LoRaDeviceJoinUpdateProperties
                {
                    DevAddr            = devAddr,
                    NwkSKey            = nwkSKey,
                    AppSKey            = appSKey,
                    AppNonce           = appNonce,
                    DevNonce           = joinReq.DevNonce,
                    NetId              = netId,
                    Region             = request.Region.LoRaRegion,
                    PreferredGatewayID = this.configuration.GatewayID,
                };

                if (loRaDevice.ClassType == LoRaDeviceClassType.C)
                {
                    updatedProperties.SavePreferredGateway = true;
                    updatedProperties.SaveRegion           = true;
                    updatedProperties.StationEui           = request.StationEui;
                }

                DeviceJoinInfo deviceJoinInfo = null;
                if (request.Region.LoRaRegion == LoRaRegionType.CN470RP2)
                {
                    if (request.Region.TryGetJoinChannelIndex(request.RadioMetadata.Frequency, out var channelIndex))
                    {
                        updatedProperties.CN470JoinChannel = channelIndex;
                        deviceJoinInfo = new DeviceJoinInfo(channelIndex);
                    }
                    else
                    {
                        this.logger.LogError("failed to retrieve the join channel index for device");
                    }
                }

                var deviceUpdateSucceeded = await loRaDevice.UpdateAfterJoinAsync(updatedProperties, joinAcceptCancellationToken.Token);

                if (!deviceUpdateSucceeded)
                {
                    this.logger.LogError("join refused: join request could not save twin");
                    request.NotifyFailed(loRaDevice, LoRaDeviceRequestFailedReason.IoTHubProblem);
                    return;
                }

                var windowToUse = timeWatcher.ResolveJoinAcceptWindowToUse();
                if (windowToUse is null)
                {
                    this.receiveWindowMisses?.Add(1);
                    this.logger.LogInformation("join refused: processing of the join request took too long, sending no message");
                    request.NotifyFailed(loRaDevice, LoRaDeviceRequestFailedReason.ReceiveWindowMissed);
                    return;
                }

                this.deviceRegistry.UpdateDeviceAfterJoin(loRaDevice, oldDevAddr);

                // Build join accept downlink message

                // Build the DlSettings fields that is a superposition of RX2DR and RX1DROffset field
                var dlSettings = new byte[1];

                if (loRaDevice.DesiredRX2DataRate.HasValue)
                {
                    if (request.Region.DRtoConfiguration.ContainsKey(loRaDevice.DesiredRX2DataRate.Value))
                    {
                        dlSettings[0] = (byte)((byte)loRaDevice.DesiredRX2DataRate & 0b00001111);
                    }
                    else
                    {
                        this.logger.LogError("twin RX2 DR value is not within acceptable values");
                    }
                }

                if (request.Region.IsValidRX1DROffset(loRaDevice.DesiredRX1DROffset))
                {
                    var rx1droffset = (byte)(loRaDevice.DesiredRX1DROffset << 4);
                    dlSettings[0] = (byte)(dlSettings[0] + rx1droffset);
                }
                else
                {
                    this.logger.LogError("twin RX1 offset DR value is not within acceptable values");
                }

                // The following DesiredRxDelay is different than the RxDelay to be passed to Serialize function
                // This one is a delay between TX and RX for any message to be processed by joining device
                // The field accepted by Serialize method is an indication of the delay (compared to receive time of join request)
                // of when the message Join Accept message should be sent
                var loraSpecDesiredRxDelay = RxDelay.RxDelay0;
                if (Enum.IsDefined(loRaDevice.DesiredRXDelay))
                {
                    loraSpecDesiredRxDelay = loRaDevice.DesiredRXDelay;
                }
                else
                {
                    this.logger.LogError("twin RX delay value is not within acceptable values");
                }

                var loRaPayloadJoinAccept = new LoRaPayloadJoinAccept(
                    netId,   // NETID 0 / 1 is default test
                    devAddr, // todo add device address management
                    appNonce,
                    dlSettings,
                    loraSpecDesiredRxDelay,
                    null);

                if (!loraRegion.TryGetDownstreamChannelFrequency(request.RadioMetadata.Frequency, upstreamDataRate: request.RadioMetadata.DataRate, deviceJoinInfo: deviceJoinInfo, downstreamFrequency: out var freq))
                {
                    this.logger.LogError("could not resolve DR and/or frequency for downstream");
                    request.NotifyFailed(loRaDevice, LoRaDeviceRequestFailedReason.InvalidUpstreamMessage);
                    return;
                }

                var joinAcceptBytes = loRaPayloadJoinAccept.Serialize(appKey);

                var rx1 = windowToUse is not ReceiveWindow2
                        ? new ReceiveWindow(loraRegion.GetDownstreamDataRate(request.RadioMetadata.DataRate, loRaDevice.ReportedRX1DROffset), freq)
                        : (ReceiveWindow?)null;

                var rx2 = new ReceiveWindow(loraRegion.GetDownstreamRX2DataRate(this.configuration.Rx2DataRate, null, deviceJoinInfo, this.logger),
                                            loraRegion.GetDownstreamRX2Freq(this.configuration.Rx2Frequency, deviceJoinInfo, this.logger));

                var downlinkMessage = new DownlinkMessage(joinAcceptBytes,
                                                          request.RadioMetadata.UpInfo.Xtime,
                                                          rx1,
                                                          rx2,
                                                          loRaDevice.DevEUI,
                                                          loraRegion.JoinAcceptDelay1,
                                                          loRaDevice.ClassType,
                                                          request.StationEui,
                                                          request.RadioMetadata.UpInfo.AntennaPreference);

                this.receiveWindowHits?.Add(1, KeyValuePair.Create(MetricRegistry.ReceiveWindowTagName, (object)windowToUse));
                _ = request.DownstreamMessageSender.SendDownstreamAsync(downlinkMessage);
                request.NotifySucceeded(loRaDevice, downlinkMessage);

                if (this.logger.IsEnabled(LogLevel.Debug))
                {
                    var jsonMsg = JsonConvert.SerializeObject(downlinkMessage);
                    this.logger.LogDebug($"{MacMessageType.JoinAccept} {jsonMsg}");
                }
                else
                {
                    this.logger.LogInformation("join accepted");
                }
            }
            catch (Exception ex) when
                (ExceptionFilterUtility.True(() => this.logger.LogError(ex, $"failed to handle join request. {ex.Message}", LogLevel.Error),
                                             () => this.unhandledExceptionCount?.Add(1)))
            {
                request.NotifyFailed(loRaDevice, ex);
                throw;
            }
        }
        private void _bluetera_DownlinkMessageReceived(IBlueteraDevice sender, DownlinkMessage args)
        {
            Dispatcher.Invoke(() =>
            {
                // update data rate UI
                //DataRate = _dataRateMeter.DataRate;
                switch (args.PayloadCase)
                {
                case DownlinkMessage.PayloadOneofCase.Quaternion:
                    {
                        // log
                        _dataLogger.Info(args.Quaternion.ToString());

                        // update rate meter
                        _dataRateMeter.Update(args.Quaternion.Timestamp);
                        DataRate = _dataRateMeter.DataRate;

                        // raw Bluetera quaternion
                        var qRaw = new Quaternion(args.Quaternion.X, args.Quaternion.Y, args.Quaternion.Z, args.Quaternion.W);

                        // transform to WPF model coordinates
                        _qt = new Quaternion(-qRaw.X, -qRaw.Y, qRaw.Z, qRaw.W);

                        // capture the first quanternion as q0
                        if (_q0.IsIdentity)
                        {
                            _q0 = _qt.Inverse();
                        }


                        // apply IMU-to-Body transform
                        var qBody       = _q0 * _qt * _qbm;
                        model.Transform = new RotateTransform3D(new QuaternionRotation3D(qBody));

                        // update Euler angles
                        var angles = qBody.GetEuelerAngles();
                        Roll       = angles[0];
                        Pitch      = angles[1];
                        Yaw        = angles[2];
                    }
                    break;

                case DownlinkMessage.PayloadOneofCase.Acceleration:

                    // log
                    _dataLogger.Info(args.Acceleration.ToString());

                    //// update rate meter
                    //_dataRateMeter.Update(args.Acceleration.Timestamp);
                    //DataRate = _dataRateMeter.DataRate;

                    // Update chart
                    AccX = args.Acceleration.X;
                    AccelerationValues_X.Add(AccX);
                    if (AccelerationValues_X.Count > 100)
                    {
                        AccelerationValues_X.RemoveAt(0);
                    }

                    AccY = args.Acceleration.Y;
                    AccelerationValues_Y.Add(AccY);
                    if (AccelerationValues_Y.Count > 100)
                    {
                        AccelerationValues_Y.RemoveAt(0);
                    }

                    AccZ = args.Acceleration.Z;
                    AccelerationValues_Z.Add(AccZ);
                    if (AccelerationValues_Z.Count > 100)
                    {
                        AccelerationValues_Z.RemoveAt(0);
                    }
                    break;

                default:
                    /* Currently ignore all other message types */
                    break;
                }
            });
        }
Exemplo n.º 17
0
 private static void Device_DownlinkMessageReceived(IBlueteraDevice sender, DownlinkMessage args)
 {
     Console.WriteLine($"Recevied message: {args.ToString()}");
 }
Exemplo n.º 18
0
 public virtual void NotifySucceeded(LoRaDevice loRaDevice, DownlinkMessage downlink)
 {
 }
Exemplo n.º 19
0
 public Task SendDownstreamAsync(DownlinkMessage message)
 {
     DownlinkMessages.Add(message);
     return(Task.FromResult(0));
 }