Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added further properties to AprsMessage to get aircraft type, address type and stealth mode, etc. #8

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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