private static List <Rxpk> GenerateRxpk(string datr, double freq) { string jsonUplink = @"{ ""rxpk"":[ { ""time"":""2013-03-31T16:21:17.528002Z"", ""tmst"":3512348611, ""chan"":2, ""rfch"":0, ""freq"":" + freq + @", ""stat"":1, ""modu"":""LORA"", ""datr"":""" + datr + @""", ""codr"":""4/6"", ""rssi"":-35, ""lsnr"":5.1, ""size"":32, ""data"":""AAQDAgEEAwIBBQQDAgUEAwItEGqZDhI="" }]}"; var multiRxpkInput = Encoding.Default.GetBytes(jsonUplink); byte[] physicalUpstreamPyld = new byte[12]; physicalUpstreamPyld[0] = 2; List <Rxpk> rxpk = Rxpk.CreateRxpk(physicalUpstreamPyld.Concat(multiRxpkInput).ToArray()); return(rxpk); }
public void CheckEUValidUpstreamRxpk(double frequency, string datr, string expectedDatr) { string jsonUplink = "{\"rxpk\":[{\"time\":\"2013-03-31T16:21:17.528002Z\"," + "\"tmst\":3512348611," + "\"chan\":2," + "\"rfch\":0," + $"\"freq\": {frequency}," + "\"stat\":1," + "\"modu\":\"LORA\"," + $"\"datr\":\"{datr}\"," + "\"codr\":\"4/6\"," + "\"rssi\":-35," + "\"lsnr\":5.1," + "\"size\":32," + "\"data\":\"AAQDAgEEAwIBBQQDAgUEAwItEGqZDhI=\"," + "\"custom_prop_a\":\"a\"," + "\"custom_prop_b\":10" + " }]}"; byte[] physicalUpstreamPyld = new byte[12]; physicalUpstreamPyld[0] = 2; var request = Encoding.Default.GetBytes(jsonUplink); var rxpks = Rxpk.CreateRxpk(physicalUpstreamPyld.Concat(request).ToArray()); var downstream = RegionManager.EU868.GetDownstreamDR(rxpks[0]); Assert.Equal(expectedDatr, downstream); }
public void When_Creating_From_Json_With_Custom_Elements_Has_Correct_Value() { string jsonUplink = @"{ ""rxpk"":[ { ""time"":""2013-03-31T16:21:17.528002Z"", ""tmst"":3512348611, ""chan"":2, ""rfch"":0, ""freq"":866.349812, ""stat"":1, ""modu"":""LORA"", ""datr"":""SF7BW125"", ""codr"":""4/6"", ""rssi"":-35, ""lsnr"":5.1, ""size"":32, ""data"":""AAQDAgEEAwIBBQQDAgUEAwItEGqZDhI="", ""custom_prop_a"":""a"", ""custom_prop_b"":10 }]}"; byte[] physicalUpstreamPyld = new byte[12]; physicalUpstreamPyld[0] = 2; var request = Encoding.Default.GetBytes(jsonUplink); var rxpks = Rxpk.CreateRxpk(physicalUpstreamPyld.Concat(request).ToArray()); Assert.Single(rxpks); Assert.Equal(2, rxpks[0].ExtraData.Count); Assert.Contains("custom_prop_a", rxpks[0].ExtraData.Keys); Assert.Contains("custom_prop_b", rxpks[0].ExtraData.Keys); Assert.Equal("a", rxpks[0].ExtraData["custom_prop_a"]); Assert.Equal(10L, rxpks[0].ExtraData["custom_prop_b"]); }
public void TestJoinRequest() { byte[] physicalUpstreamPyld = new byte[12]; physicalUpstreamPyld[0] = 2; string jsonUplink = @"{ ""rxpk"":[ { ""time"":""2013-03-31T16:21:17.528002Z"", ""tmst"":3512348611, ""chan"":2, ""rfch"":0, ""freq"":866.349812, ""stat"":1, ""modu"":""LORA"", ""datr"":""SF7BW125"", ""codr"":""4/6"", ""rssi"":-35, ""lsnr"":5.1, ""size"":32, ""data"":""AAQDAgEEAwIBBQQDAgUEAwItEGqZDhI="" }]}"; var joinRequestInput = Encoding.Default.GetBytes(jsonUplink); List <Rxpk> rxpk = Rxpk.CreateRxpk(physicalUpstreamPyld.Concat(joinRequestInput).ToArray()); TestRxpk(rxpk[0]); }
public void Multiple_Rxpk_Are_Detected_Correctly() { string jsonUplink = @"{""rxpk"":[{""tmst"":373051724,""time"":""2020-02-19T04:08:57.265951Z"",""chan"":0,""rfch"":0,""freq"":923.200000,""stat"":1,""modu"":""LORA"",""datr"":""SF9BW125"",""codr"":""4/5"",""lsnr"":12.5,""rssi"":-47,""size"":21,""data"":""gAMAABKgmAAIAvEgIbhjS0LBeM/d""},{""tmst"":373053772,""time"":""2020-02-19T04:08:57.265951Z"",""chan"":6,""rfch"":0,""freq"":923.000000,""stat"":-1,""modu"":""LORA"",""datr"":""SF9BW125"",""codr"":""4/5"",""lsnr"":-13.0,""rssi"":-97,""size"":21,""data"":""gJni7n4+wQBUl/E0sO4vB4gFePx7""}]}"; byte[] physicalUpstreamPyld = new byte[12]; physicalUpstreamPyld[0] = 2; var request = Encoding.Default.GetBytes(jsonUplink); var rxpks = Rxpk.CreateRxpk(physicalUpstreamPyld.Concat(request).ToArray()); Assert.Equal(2, rxpks.Count); }
public void TestUnconfirmedUplink() { string jsonUplinkUnconfirmedDataUp = @"{ ""rxpk"":[ { ""time"":""2013-03-31T16:21:17.528002Z"", ""tmst"":3512348611, ""chan"":2, ""rfch"":0, ""freq"":866.349812, ""stat"":1, ""modu"":""LORA"", ""datr"":""SF7BW125"", ""codr"":""4/6"", ""rssi"":-35, ""lsnr"":5.1, ""size"":32, ""data"":""QAQDAgGAAQABppRkJhXWw7WC"" }]}"; byte[] physicalUpstreamPyld = new byte[12]; physicalUpstreamPyld[0] = 2; var jsonUplinkUnconfirmedDataUpBytes = Encoding.Default.GetBytes(jsonUplinkUnconfirmedDataUp); List <Rxpk> rxpk = Rxpk.CreateRxpk(physicalUpstreamPyld.Concat(jsonUplinkUnconfirmedDataUpBytes).ToArray()); Assert.True(LoRaPayload.TryCreateLoRaPayload(rxpk[0], out LoRaPayload loRaPayload)); Assert.Equal(LoRaMessageType.UnconfirmedDataUp, loRaPayload.LoRaMessageType); LoRaPayloadData loRaPayloadUplinkObj = (LoRaPayloadData)loRaPayload; Assert.True(loRaPayloadUplinkObj.Fcnt.Span.SequenceEqual(new byte[2] { 1, 0 })); Assert.True(loRaPayloadUplinkObj.DevAddr.Span.SequenceEqual(new byte[4] { 1, 2, 3, 4 })); byte[] loRaPayloadUplinkNwkKey = new byte[16] { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; Assert.True(loRaPayloadUplinkObj.CheckMic(ConversionHelper.ByteArrayToString(loRaPayloadUplinkNwkKey))); byte[] loRaPayloadUplinkAppKey = new byte[16] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; var key = ConversionHelper.ByteArrayToString(loRaPayloadUplinkAppKey); Assert.Equal("hello", Encoding.ASCII.GetString(loRaPayloadUplinkObj.PerformEncryption(key))); }
private void DispatchMessages(byte[] buffer, DateTime startTimeProcessing) { try { List <Rxpk> messageRxpks = Rxpk.CreateRxpk(buffer); if (messageRxpks != null) { foreach (var rxpk in messageRxpks) { this.messageDispatcher.DispatchRequest(new LoRaRequest(rxpk, this, startTimeProcessing)); } } } catch (Exception ex) { Logger.Log("UDP", $"failed to dispatch messages: {ex.Message}", LogLevel.Error); } }
public void TestKeys() { // create random message string jsonUplink = @"{ ""rxpk"":[ { ""time"":""2013-03-31T16:21:17.528002Z"", ""tmst"":3512348611, ""chan"":2, ""rfch"":0, ""freq"":866.349812, ""stat"":1, ""modu"":""LORA"", ""datr"":""SF7BW125"", ""codr"":""4/6"", ""rssi"":-35, ""lsnr"":5.1, ""size"":32, ""data"":""AAQDAgEEAwIBBQQDAgUEAwItEGqZDhI="" }]}"; var joinRequestInput = Encoding.Default.GetBytes(jsonUplink); byte[] physicalUpstreamPyld = new byte[12]; physicalUpstreamPyld[0] = 2; List <Rxpk> rxpk = Rxpk.CreateRxpk(physicalUpstreamPyld.Concat(joinRequestInput).ToArray()); Assert.True(LoRaPayload.TryCreateLoRaPayload(rxpk[0], out LoRaPayload loRaPayload)); Assert.Equal(LoRaMessageType.JoinRequest, loRaPayload.LoRaMessageType); var joinReq = (LoRaPayloadJoinRequest)loRaPayload; joinReq.DevAddr = new byte[4] { 4, 3, 2, 1, }; joinReq.DevEUI = new byte[8] { 8, 7, 6, 5, 4, 3, 2, 1, }; joinReq.DevNonce = new byte[2] { 2, 1, }; joinReq.AppEUI = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8, }; byte[] appNonce = new byte[3] { 0, 0, 1, }; byte[] netId = new byte[3] { 3, 2, 1, }; byte[] appKey = new byte[16] { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, }; var key = joinReq.CalculateKey(LoRaPayloadKeyType.NwkSkey, appNonce, netId, joinReq.DevNonce.ToArray(), appKey); Assert.Equal( key, new byte[16] { 223, 83, 195, 95, 48, 52, 204, 206, 208, 255, 53, 76, 112, 222, 4, 223, }); }
async Task RunUdpListener() { IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, PORT); this.udpClient = new UdpClient(endPoint); Logger.LogAlways($"LoRaWAN server started on port {PORT}"); while (true) { UdpReceiveResult receivedResults = await this.udpClient.ReceiveAsync(); var startTimeProcessing = DateTime.UtcNow; // Logger.LogAlways($"UDP message received ({receivedResults.Buffer[3]}) from port: {receivedResults.RemoteEndPoint.Port} and IP: {receivedResults.RemoteEndPoint.Address.ToString()}"); switch (PhysicalPayload.GetIdentifierFromPayload(receivedResults.Buffer)) { // In this case we have a keep-alive PULL_DATA packet we don't need to start the engine and can return immediately a response to the challenge case PhysicalIdentifier.PULL_DATA: if (this.pullAckRemoteLoRaAggregatorPort == 0) { this.pullAckRemoteLoRaAggregatorPort = receivedResults.RemoteEndPoint.Port; } this.SendAcknowledgementMessage(receivedResults, (int)PhysicalIdentifier.PULL_ACK, receivedResults.RemoteEndPoint); break; // This is a PUSH_DATA (upstream message). case PhysicalIdentifier.PUSH_DATA: this.SendAcknowledgementMessage(receivedResults, (int)PhysicalIdentifier.PUSH_ACK, receivedResults.RemoteEndPoint); // Message processing runs in the background var remoteEndPointAddress = receivedResults.RemoteEndPoint.Address.ToString(); _ = Task.Run(async() => { List <Rxpk> messageRxpks = Rxpk.CreateRxpk(receivedResults.Buffer); if (messageRxpks != null) { if (messageRxpks.Count == 1) { await this.ProcessRxpkAsync(receivedResults.RemoteEndPoint.Address.ToString(), messageRxpks[0], startTimeProcessing); } else if (messageRxpks.Count > 1) { Task toWait = null; for (int i = 0; i < messageRxpks.Count; i++) { var t = this.ProcessRxpkAsync(remoteEndPointAddress, messageRxpks[i], startTimeProcessing); if (toWait == null) { toWait = t; } } await toWait; } } }); break; // This is a ack to a transmission we did previously case PhysicalIdentifier.TX_ACK: if (receivedResults.Buffer.Length == 12) { Logger.Log( "UDP", $"Packet with id {ConversionHelper.ByteArrayToString(receivedResults.Buffer.RangeSubset(1, 2))} successfully transmitted by the aggregator", LogLevel.Debug); } else { var logMsg = string.Format( "Packet with id {0} had a problem to be transmitted over the air :{1}", receivedResults.Buffer.Length > 2 ? ConversionHelper.ByteArrayToString(receivedResults.Buffer.RangeSubset(1, 2)) : string.Empty, receivedResults.Buffer.Length > 12 ? Encoding.UTF8.GetString(receivedResults.Buffer.RangeSubset(12, receivedResults.Buffer.Length - 12)) : string.Empty); Logger.Log("UDP", logMsg, LogLevel.Error); } break; default: Logger.Log("UDP", "Unknown packet type or length being received", LogLevel.Error); break; } } }