Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions AprsClientExample/AprsClientExample.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
Expand Down
76 changes: 76 additions & 0 deletions Skyhop.Aprs.Client.Tests/AprsMessageTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using Boerman.Core.Spatial;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Skyhop.Aprs.Client.Enums;
using Skyhop.Aprs.Client.Models;

namespace Boerman.Aprs.Client.Tests
Expand Down Expand Up @@ -30,6 +31,81 @@ public void TestFanetMessageParsing()
Assert.IsTrue(result.StationRoute[2] == "Letzi");
Assert.IsTrue(result.Symbol == Skyhop.Aprs.Client.Enums.Symbol.Glider);
Assert.IsTrue(result.TurnRate == 0);
Assert.AreEqual(AircraftType.Paraglider, result.AircraftType);
}

[TestMethod]
public void TestOGNGliderHB1669LszxMessageParsing()
{
var message = "ICA4B4B2C>APRS,qAS,LSZX:/090803h4710.41N/00902.63E'152/051/A=002129 !W18! id054B4B2C -138fpm -1.6rot 24.0dB 0e -1.8kHz gps2x2";

var result = PacketInfo.Parse(message);

Assert.IsTrue(result != null);
Assert.IsTrue(result.Altitude.FeetAboveSeaLevel == 2129);
Assert.IsTrue(result.Callsign == "ICA4B4B2C");
Assert.IsTrue(result.ClimbRate == -138);
Assert.IsTrue(result.DataType == Skyhop.Aprs.Client.Enums.DataType.PositionWithTimestampNoAprsMessaging);
Assert.IsTrue(result.Direction.Degrees == 152);
Assert.IsTrue(result.Latitude.AbsoluteValue == 47.1735);
Assert.IsTrue(result.Longitude.AbsoluteValue == 9.0438333333333336);
Assert.IsTrue(result.MicEMessageType == Skyhop.Aprs.Client.Enums.MicEMessageType.OffDuty);
Assert.IsTrue(result.Speed.Knots == 51);
Assert.IsTrue(result.StationRoute[0] == "APRS");
Assert.IsTrue(result.StationRoute[1] == "qAS");
Assert.IsTrue(result.StationRoute[2] == "LSZX");
Assert.IsTrue(result.Symbol == Skyhop.Aprs.Client.Enums.Symbol.Aircraft);
Assert.IsTrue(result.TurnRate == -1.6);
Assert.AreEqual(AircraftType.Glider, result.AircraftType);
}

[TestMethod]
public void TestOGNTowAircraftHBEXPLszxMessageParsing()
{
var message = "ICA4B0CF5>APRS,qAS,LSZX:/091131h4710.19N/00902.42E'149/007/A=001355 !W74! id094B0CF5 +020fpm +0.4rot 42.2dB 0e -3.4kHz gps3x3";

var result = PacketInfo.Parse(message);

Assert.IsTrue(result != null);
Assert.IsTrue(result.Altitude.FeetAboveSeaLevel == 1355);
Assert.IsTrue(result.Callsign == "ICA4B0CF5");
Assert.IsTrue(result.ClimbRate == 20);
Assert.IsTrue(result.DataType == Skyhop.Aprs.Client.Enums.DataType.PositionWithTimestampNoAprsMessaging);
Assert.IsTrue(result.Direction.Degrees == 149);
Assert.IsTrue(result.Latitude.AbsoluteValue == 47.16983333333333);
Assert.IsTrue(result.Longitude.AbsoluteValue == 9.0403333333333329);
Assert.IsTrue(result.MicEMessageType == Skyhop.Aprs.Client.Enums.MicEMessageType.OffDuty);
Assert.IsTrue(result.Speed.Knots == 7);
Assert.IsTrue(result.StationRoute[0] == "APRS");
Assert.IsTrue(result.StationRoute[1] == "qAS");
Assert.IsTrue(result.StationRoute[2] == "LSZX");
Assert.IsTrue(result.Symbol == Skyhop.Aprs.Client.Enums.Symbol.Aircraft);
Assert.IsTrue(result.TurnRate == 0.4);
Assert.AreEqual(AircraftType.TowPlane, result.AircraftType);
}

[TestMethod]
public void TestOGNFLRMessageParsing()
{
var message = "ICA4B3CA5>APRS,qAS,LSZX:/165008h4711.09N/00847.94E'054/079/A=004402 !W59! id054B3CA5 -157fpm +0.0rot 13.8dB 0e -1.9kHz gps1x2 +5.3dBm";

var result = PacketInfo.Parse(message);

Assert.IsTrue(result != null);
Assert.IsTrue(result.Altitude.FeetAboveSeaLevel == 4402);
Assert.IsTrue(result.Callsign == "ICA4B3CA5");
Assert.IsTrue(result.ClimbRate == -157);
Assert.IsTrue(result.DataType == Skyhop.Aprs.Client.Enums.DataType.PositionWithTimestampNoAprsMessaging);
Assert.IsTrue(result.Direction.Degrees == 54);
Assert.IsTrue(result.Latitude.AbsoluteValue == 47.18483333333333);
Assert.IsTrue(result.Longitude.AbsoluteValue == 8.799);
Assert.IsTrue(result.MicEMessageType == Skyhop.Aprs.Client.Enums.MicEMessageType.OffDuty);
Assert.IsTrue(result.Speed.Knots == 79);
Assert.IsTrue(result.StationRoute[0] == "APRS");
Assert.IsTrue(result.StationRoute[1] == "qAS");
Assert.IsTrue(result.StationRoute[2] == "LSZX");
Assert.IsTrue(result.Symbol == Skyhop.Aprs.Client.Enums.Symbol.Aircraft);
Assert.IsTrue(result.TurnRate == 0);
}

[TestMethod]
Expand Down
4 changes: 2 additions & 2 deletions Skyhop.Aprs.Client.Tests/Skyhop.Aprs.Client.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>
Expand Down
14 changes: 14 additions & 0 deletions Skyhop.Aprs.Client/Enums/AddressType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Skyhop.Aprs.Client.Enums
{
public enum AddressType
{
Random = 0x0,
ICAO = 0x1,
Flarm = 0x2,
OGN = 0x3
}
}
26 changes: 26 additions & 0 deletions Skyhop.Aprs.Client/Enums/AircraftType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Skyhop.Aprs.Client.Enums
{
public enum AircraftType
{
Unknown = 0x0,
Glider = 0x1,
TowPlane = 0x2,
Helicopter = 0x3,
Skydiver = 0x4,
DropPlane = 0x5,
Hangglider = 0x6,
Paraglider = 0x7,
PoweredPiston = 0x8,
PoweredJet = 0x9,
Unknown2 = 0xA,
Balloon = 0xB,
Airship = 0xC,
UAV = 0xD,
Unknown3 = 0xE,
Static = 0xF
}
}
13 changes: 13 additions & 0 deletions Skyhop.Aprs.Client/Models/AprsMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ public static AprsMessage Parse(string message)
public MicEMessageType MicEMessageType { get; internal set; }
public DateTime ReceivedDate { get; internal set; }

public string DeviceId { get; internal set; }

public AircraftType AircraftType { get; internal set; }

public AddressType AddressType { get; internal set; }

public bool StealthMode { get; internal set; }

public bool NoTrackingFlag { get; internal set; }

// This is specifically for OGN flavored APRS
public int ClimbRate { get; internal set; }
public double TurnRate { get; internal set; }
Expand All @@ -54,6 +64,9 @@ public override string ToString()
sb.AppendLine($"{(nameof(Speed).SplitCamelCase().PadLeft(padding))}: {Speed}");
sb.AppendLine($"{(nameof(SymbolTable).SplitCamelCase().PadLeft(padding))}: {SymbolTable}");
sb.AppendLine($"{(nameof(Symbol).SplitCamelCase().PadLeft(padding))}: {Symbol}");
sb.AppendLine($"{(nameof(DeviceId).SplitCamelCase().PadLeft(padding))}: {DeviceId}");
sb.AppendLine($"{(nameof(AircraftType).SplitCamelCase().PadLeft(padding))}: {AircraftType}");
sb.AppendLine($"{(nameof(AddressType).SplitCamelCase().PadLeft(padding))}: {AddressType}");

if (DataType == DataType.CurrentMicE)
sb.AppendLine($"{(nameof(MicEMessageType).SplitCamelCase().PadLeft(padding))}: {MicEMessageType}");
Expand Down
27 changes: 27 additions & 0 deletions Skyhop.Aprs.Client/Models/PacketInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
Expand Down Expand Up @@ -37,6 +38,32 @@ public static AprsMessage Parse(string rawData)

if (string.IsNullOrEmpty(rawData)) return null;

// -- id bits and mask ----------------------------------------------------------------
// according: http://wiki.glidernet.org/wiki:subscribe-to-ogn-data
// and: http://www.ediatec.ch/pdf/FLARM%20Data%20Port%20Specification%20v7.00.pdf
// idXXYYYYYY => XX encoding, YY address

try
{
var matchAircraft = Regex.Match(rawData, @"(?:\sid)([a-fA-F0-9]{8})(?:\s)");

if (matchAircraft.Success)
{
aprsMessage.DeviceId = matchAircraft.Groups[1].Value.Substring(2);
var aircraftId = ulong.Parse(matchAircraft.Groups[1].Value.Trim(), NumberStyles.HexNumber);
byte addressTypeAndFlagsByte = (byte)((aircraftId & 0xFF000000) >> 24);
aprsMessage.AddressType = (AddressType)(addressTypeAndFlagsByte & 0x03);
aprsMessage.AircraftType = (AircraftType)((addressTypeAndFlagsByte & 0x3C) >> 2);
aprsMessage.StealthMode = (addressTypeAndFlagsByte & 0x80) > 0;
aprsMessage.NoTrackingFlag = (addressTypeAndFlagsByte & 0x40) > 0;
//uint aircraftAddress = (uint)(aircraftId & 0x00FFFFFF);
}
}
catch
{

}

DataType dataType;

if (!Constants.Maps.DataTypeMap.TryGetValue(Convert.ToByte(rawData[0]), out dataType))
Expand Down