diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessage.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessage.cs
index 1be37c8..2b1a6db 100644
--- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessage.cs
+++ b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessage.cs
@@ -4,7 +4,7 @@
namespace Ais.Net.Models.Abstractions
{
- public interface IAisMessage : IVesselIdentity, IAisMessageType
+ public interface IAisMessage : IVesselIdentity, IAisMessageType, ITimestamp
{
}
}
\ No newline at end of file
diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType27.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType27.cs
new file mode 100644
index 0000000..5d9b04c
--- /dev/null
+++ b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType27.cs
@@ -0,0 +1,17 @@
+namespace Ais.Net.Models.Abstractions
+{
+ public interface IAisMessageType27
+ {
+ float? CourseOverGroundDegrees { get; }
+
+ bool NotGnssPosition { get; }
+
+ NavigationStatus NavigationStatus { get; }
+
+ Position? Position { get; }
+
+ bool PositionAccuracy { get; }
+
+ float? SpeedOverGround { get; }
+ }
+}
\ No newline at end of file
diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ITimestamp.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ITimestamp.cs
new file mode 100644
index 0000000..861a541
--- /dev/null
+++ b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ITimestamp.cs
@@ -0,0 +1,6 @@
+namespace Ais.Net.Models.Abstractions;
+
+public interface ITimestamp
+{
+ public long? UnixTimestamp { get; }
+}
\ No newline at end of file
diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/Position.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/Position.cs
index 443423f..0b7a46b 100644
--- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/Position.cs
+++ b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/Position.cs
@@ -8,5 +8,7 @@ public record Position(double Latitude, double Longitude)
{
public static Position From10000thMins(int latitude, int longitude) =>
new (latitude.From10000thMinsToDegrees(), longitude.From10000thMinsToDegrees());
+ public static Position From10thMins(int latitude, int longitude) =>
+ new (latitude.From10thMinsToDegrees(), longitude.From10thMinsToDegrees());
}
}
\ No newline at end of file
diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageBase.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageBase.cs
index f3dadf5..5420ac9 100644
--- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageBase.cs
+++ b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageBase.cs
@@ -6,5 +6,5 @@ namespace Ais.Net.Models
{
using Ais.Net.Models.Abstractions;
- public record AisMessageBase(int MessageType, uint Mmsi) : IAisMessage;
+ public record AisMessageBase(int MessageType, uint Mmsi, long? UnixTimestamp) : IAisMessage;
}
\ No newline at end of file
diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageExtensions.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageExtensions.cs
index d85a1a2..07dea59 100644
--- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageExtensions.cs
+++ b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageExtensions.cs
@@ -14,6 +14,11 @@ public static double From10000thMinsToDegrees(this int value)
{
return value / 600000.0;
}
+
+ public static double From10thMinsToDegrees(this int value)
+ {
+ return value / 600.0;
+ }
public static float? FromTenths(this uint value)
{
diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType18.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType18.cs
index d5ec527..6e6295f 100644
--- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType18.cs
+++ b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType18.cs
@@ -24,8 +24,9 @@ public record AisMessageType18(
uint RepeatIndicator,
float? SpeedOverGround,
uint TimeStampSecond,
- uint TrueHeadingDegrees) :
- AisMessageBase(MessageType: 18, Mmsi),
+ uint TrueHeadingDegrees,
+ long? UnixTimestamp) :
+ AisMessageBase(MessageType: 18, Mmsi, UnixTimestamp),
IAisMessageType18,
IAisIsAssigned,
IRaimFlag,
diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType19.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType19.cs
index 45f2796..b06d98c 100644
--- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType19.cs
+++ b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType19.cs
@@ -27,8 +27,9 @@ public record AisMessageType19(
uint Spare308,
float? SpeedOverGround,
uint TimeStampSecond,
- uint TrueHeadingDegrees) :
- AisMessageBase(MessageType: 19, Mmsi),
+ uint TrueHeadingDegrees,
+ long? UnixTimestamp) :
+ AisMessageBase(MessageType: 19, Mmsi, UnixTimestamp),
IAisMessageType19,
IAisIsAssigned,
IAisIsDteNotReady,
diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType1Through3.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType1Through3.cs
index 718431c..2e975df 100644
--- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType1Through3.cs
+++ b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType1Through3.cs
@@ -23,8 +23,9 @@ public record AisMessageType1Through3(
uint SpareBits145,
float? SpeedOverGround,
uint TimeStampSecond,
- uint TrueHeadingDegrees) :
- AisMessageBase(MessageType, Mmsi),
+ uint TrueHeadingDegrees,
+ long? UnixTimestamp) :
+ AisMessageBase(MessageType, Mmsi, UnixTimestamp),
IAisMessageType1to3,
IRaimFlag,
IRepeatIndicator,
diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part0.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part0.cs
index d57748b..3e9cf1b 100644
--- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part0.cs
+++ b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part0.cs
@@ -10,8 +10,9 @@ public record AisMessageType24Part0(
uint Mmsi,
uint PartNumber,
uint RepeatIndicator,
- uint Spare160) :
- AisMessageBase(MessageType: 24, Mmsi),
+ uint Spare160,
+ long? UnixTimestamp) :
+ AisMessageBase(MessageType: 24, Mmsi, UnixTimestamp),
IAisMultipartMessage,
IRepeatIndicator,
IAisMessageType24Part0;
diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part1.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part1.cs
index 86bc85d..fcdcdb7 100644
--- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part1.cs
+++ b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part1.cs
@@ -21,8 +21,9 @@ public record AisMessageType24Part1(
ShipType ShipType,
uint UnitModelCode,
string VendorIdRev3,
- string VendorIdRev4) :
- AisMessageBase(MessageType: 24, Mmsi),
+ string VendorIdRev4,
+ long? UnixTimestamp) :
+ AisMessageBase(MessageType: 24, Mmsi, UnixTimestamp),
IAisMessageType24Part1,
IAisMultipartMessage,
ICallSign,
diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType27.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType27.cs
new file mode 100644
index 0000000..10d81e7
--- /dev/null
+++ b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType27.cs
@@ -0,0 +1,24 @@
+//
+// Copyright (c) Endjin Limited. All rights reserved.
+//
+
+namespace Ais.Net.Models
+{
+ using Ais.Net.Models.Abstractions;
+
+ public record AisMessageType27(
+ float? CourseOverGroundDegrees,
+ bool NotGnssPosition,
+ uint Mmsi,
+ NavigationStatus NavigationStatus,
+ Position? Position,
+ bool PositionAccuracy,
+ bool RaimFlag,
+ uint RepeatIndicator,
+ float? SpeedOverGround,
+ long? UnixTimestamp) :
+ AisMessageBase(MessageType: 27, Mmsi, UnixTimestamp),
+ IAisMessageType27,
+ IRaimFlag,
+ IRepeatIndicator;
+}
\ No newline at end of file
diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType5.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType5.cs
index a9c2d19..ca4db07 100644
--- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType5.cs
+++ b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType5.cs
@@ -26,8 +26,9 @@ public record AisMessageType5(
uint RepeatIndicator,
ShipType ShipType,
uint Spare423,
- string VesselName) :
- AisMessageBase(MessageType: 5, Mmsi),
+ string VesselName,
+ long? UnixTimestamp) :
+ AisMessageBase(MessageType: 5, Mmsi, UnixTimestamp),
IAisMessageType5,
IAisIsDteNotReady,
IAisPositionFixType,
diff --git a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Parser/NmeaToAisMessageTypeProcessor.cs b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Parser/NmeaToAisMessageTypeProcessor.cs
index 8799176..2c56111 100644
--- a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Parser/NmeaToAisMessageTypeProcessor.cs
+++ b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Parser/NmeaToAisMessageTypeProcessor.cs
@@ -30,31 +30,37 @@ public void OnNext(in NmeaLineParser parsedLine, in ReadOnlySpan asciiPayl
{
case >= 1 and <= 3:
{
- this.ParseMessageTypes1Through3(asciiPayload, padding, messageType);
+ this.ParseMessageTypes1Through3(parsedLine, asciiPayload, padding, messageType);
return;
}
case 5:
{
- this.ParseMessageType5(asciiPayload, padding);
+ this.ParseMessageType5(parsedLine, asciiPayload, padding);
return;
}
case 18:
{
- this.ParseMessageType18(asciiPayload, padding);
+ this.ParseMessageType18(parsedLine, asciiPayload, padding);
return;
}
case 19:
{
- this.ParseMessageType19(asciiPayload, padding);
+ this.ParseMessageType19(parsedLine, asciiPayload, padding);
return;
}
case 24:
{
- this.ParseMessageType24(asciiPayload, padding);
+ this.ParseMessageType24(parsedLine, asciiPayload, padding);
+ return;
+ }
+
+ case 27:
+ {
+ this.ParseMessageType27(parsedLine, asciiPayload, padding);
return;
}
}
@@ -87,7 +93,7 @@ public void Progress(
throw new NotImplementedException();
}
- private void ParseMessageTypes1Through3(ReadOnlySpan asciiPayload, uint padding, int messageType)
+ private void ParseMessageTypes1Through3(NmeaLineParser nmeaLineParser, ReadOnlySpan asciiPayload, uint padding, int messageType)
{
var parser = new NmeaAisPositionReportClassAParser(asciiPayload, padding);
@@ -108,12 +114,13 @@ private void ParseMessageTypes1Through3(ReadOnlySpan asciiPayload, uint pa
SpareBits145: parser.SpareBits145,
SpeedOverGround: parser.SpeedOverGroundTenths.FromTenths(),
TimeStampSecond: parser.TimeStampSecond,
- TrueHeadingDegrees: parser.TrueHeadingDegrees);
+ TrueHeadingDegrees: parser.TrueHeadingDegrees,
+ UnixTimestamp: nmeaLineParser.TagBlock.UnixTimestamp);
this.messages.OnNext(message);
}
- private void ParseMessageType5(ReadOnlySpan asciiPayload, uint padding)
+ private void ParseMessageType5(NmeaLineParser nmeaLineParser, ReadOnlySpan asciiPayload, uint padding)
{
var parser = new NmeaAisStaticAndVoyageRelatedDataParser(asciiPayload, padding);
@@ -137,12 +144,13 @@ private void ParseMessageType5(ReadOnlySpan asciiPayload, uint padding)
DimensionToStern: parser.DimensionToStern,
Draught10thMetres: parser.Draught10thMetres,
Spare423: parser.Spare423,
- PositionFixType: parser.PositionFixType);
+ PositionFixType: parser.PositionFixType,
+ UnixTimestamp: nmeaLineParser.TagBlock.UnixTimestamp);
this.messages.OnNext(message);
}
- private void ParseMessageType18(ReadOnlySpan asciiPayload, uint padding)
+ private void ParseMessageType18(NmeaLineParser nmeaLineParser, ReadOnlySpan asciiPayload, uint padding)
{
var parser = new NmeaAisPositionReportClassBParser(asciiPayload, padding);
@@ -164,12 +172,13 @@ private void ParseMessageType18(ReadOnlySpan asciiPayload, uint padding)
TrueHeadingDegrees: parser.TrueHeadingDegrees,
IsAssigned: parser.IsAssigned,
RaimFlag: parser.RaimFlag,
- RepeatIndicator: parser.RepeatIndicator);
+ RepeatIndicator: parser.RepeatIndicator,
+ UnixTimestamp: nmeaLineParser.TagBlock.UnixTimestamp);
this.messages.OnNext(message);
}
- private void ParseMessageType19(ReadOnlySpan asciiPayload, uint padding)
+ private void ParseMessageType19(NmeaLineParser nmeaLineParser, ReadOnlySpan asciiPayload, uint padding)
{
var parser = new NmeaAisPositionReportExtendedClassBParser(asciiPayload, padding);
@@ -197,12 +206,13 @@ private void ParseMessageType19(ReadOnlySpan asciiPayload, uint padding)
SpeedOverGround: parser.SpeedOverGroundTenths.FromTenths(),
TimeStampSecond: parser.TimeStampSecond,
TrueHeadingDegrees: parser.TrueHeadingDegrees,
- Position: Position.From10000thMins(parser.Latitude10000thMins, parser.Longitude10000thMins));
+ Position: Position.From10000thMins(parser.Latitude10000thMins, parser.Longitude10000thMins),
+ UnixTimestamp: nmeaLineParser.TagBlock.UnixTimestamp);
this.messages.OnNext(message);
}
- private void ParseMessageType24(ReadOnlySpan asciiPayload, uint padding)
+ private void ParseMessageType24(NmeaLineParser nmeaLineParser, ReadOnlySpan asciiPayload, uint padding)
{
uint part = NmeaAisStaticDataReportParser.GetPartNumber(asciiPayload, padding);
@@ -219,7 +229,8 @@ private void ParseMessageType24(ReadOnlySpan asciiPayload, uint padding)
Mmsi: parser.Mmsi,
PartNumber: parser.PartNumber,
RepeatIndicator: parser.RepeatIndicator,
- Spare160: parser.Spare160);
+ Spare160: parser.Spare160,
+ UnixTimestamp: nmeaLineParser.TagBlock.UnixTimestamp);
this.messages.OnNext(message);
break;
@@ -253,12 +264,32 @@ private void ParseMessageType24(ReadOnlySpan asciiPayload, uint padding)
Spare162: parser.Spare162,
UnitModelCode: parser.UnitModelCode,
VendorIdRev3: vendorIdRev3Ascii.GetString(),
- VendorIdRev4: vendorIdRev4Ascii.GetString());
+ VendorIdRev4: vendorIdRev4Ascii.GetString(),
+ UnixTimestamp: nmeaLineParser.TagBlock.UnixTimestamp);
this.messages.OnNext(message);
break;
}
}
}
+
+ private void ParseMessageType27(NmeaLineParser nmeaLineParser, ReadOnlySpan asciiPayload, uint padding)
+ {
+ var parser = new NmeaAisLongRangeAisBroadcastParser(asciiPayload, padding);
+
+ var message = new AisMessageType27(
+ Mmsi: parser.Mmsi,
+ Position: Position.From10thMins(parser.Latitude10thMins, parser.Longitude10thMins),
+ CourseOverGroundDegrees: parser.CourseOverGroundDegrees,
+ PositionAccuracy: parser.PositionAccuracy,
+ SpeedOverGround: parser.SpeedOverGroundTenths.FromTenths(),
+ RaimFlag: parser.RaimFlag,
+ RepeatIndicator: parser.RepeatIndicator,
+ NotGnssPosition: parser.NotGnssPosition,
+ NavigationStatus: parser.NavigationStatus,
+ UnixTimestamp: nmeaLineParser.TagBlock.UnixTimestamp);
+
+ this.messages.OnNext(message);
+ }
}
}
\ No newline at end of file