From c1337e31341f5d72e75701523207f40a2d64b385 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Wed, 12 Oct 2022 09:27:13 +0200 Subject: [PATCH] SitRep Liste wird mit pos. und stat. Daten (A-Targets) aktualisiert --- AIS/bsmd.AIS2Service/AISDecoder.cs | 2 +- AIS/bsmd.AIS2Service/AISManager.cs | 26 +- AIS/bsmd.AIS2Service/AIS_BaseStationReport.cs | 23 +- AIS/bsmd.AIS2Service/AIS_ClassBStatic.cs | 5 - AIS/bsmd.AIS2Service/AIS_PosReport.cs | 8 +- AIS/bsmd.AIS2Service/AIS_StaticData.cs | 139 +------ AIS/bsmd.AIS2Service/AIS_Target.cs | 372 ++++++++---------- AIS/bsmd.AIS2Service/App.config | 3 + AIS/bsmd.AIS2Service/Lookup.cs | 164 ++++++++ .../Properties/Settings.Designer.cs | 9 + .../Properties/Settings.settings | 3 + AIS/bsmd.AIS2Service/SitRep.cs | 111 ++++++ AIS/bsmd.AIS2Service/bsmd.AIS2Service.csproj | 2 + 13 files changed, 505 insertions(+), 362 deletions(-) create mode 100644 AIS/bsmd.AIS2Service/Lookup.cs create mode 100644 AIS/bsmd.AIS2Service/SitRep.cs diff --git a/AIS/bsmd.AIS2Service/AISDecoder.cs b/AIS/bsmd.AIS2Service/AISDecoder.cs index 2bc5ee33..867d77d5 100644 --- a/AIS/bsmd.AIS2Service/AISDecoder.cs +++ b/AIS/bsmd.AIS2Service/AISDecoder.cs @@ -119,7 +119,7 @@ namespace bsmd.AIS2Service if(aisStatus == AISClass.Status.OK) { _outputAISClasses.Enqueue(decodedClass); - _log.DebugFormat("Enqueuing {0} message for MMSI {1}", decodedClass.MessageType, decodedClass.MMSI); + // _log.DebugFormat("Enqueuing {0} message for MMSI {1}", decodedClass.MessageType, decodedClass.MMSI); } else { diff --git a/AIS/bsmd.AIS2Service/AISManager.cs b/AIS/bsmd.AIS2Service/AISManager.cs index 739a8ee1..c74e39b8 100644 --- a/AIS/bsmd.AIS2Service/AISManager.cs +++ b/AIS/bsmd.AIS2Service/AISManager.cs @@ -4,6 +4,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; namespace bsmd.AIS2Service @@ -14,18 +15,41 @@ namespace bsmd.AIS2Service private static readonly ConcurrentQueue _inputLines = new ConcurrentQueue(); private static readonly ConcurrentQueue _decodedClasses = new ConcurrentQueue(); private static readonly ILog _log = LogManager.GetLogger(typeof(AISManager)); - private static readonly List _sitRepList = new List(); + private static readonly ConcurrentDictionary _sitRepList = new ConcurrentDictionary(); + private static Timer _staleTargetTimer; public static void Start() { _tasks.Add(new SerialTCPReader(Properties.Settings.Default.DataSourceHost, Properties.Settings.Default.DataSourcePort, _inputLines)); _tasks.Add(new AISDecoder(_inputLines, _decodedClasses)); + _tasks.Add(new SitRep(_decodedClasses, _sitRepList)); foreach (var task in _tasks) { task.Start(); _log.InfoFormat("{0} started", task.Name); } + + _staleTargetTimer = new Timer(staleTimerCheck, null, 0, 60000); // check every minute + + } + + private static void staleTimerCheck(object state) + { + List removeKeyList = new List(); + foreach (int key in _sitRepList.Keys) + { + if (!_sitRepList[key].LastUpdate.HasValue) { removeKeyList.Add(key); } + else + { + if ((DateTime.Now - _sitRepList[key].LastUpdate.Value).TotalMinutes > Properties.Settings.Default.StaleTargetTimeoutMins) + removeKeyList.Add(key); + } + } + foreach(int key in removeKeyList) + { + _sitRepList.TryRemove(key, out _); + } } public static void Stop() diff --git a/AIS/bsmd.AIS2Service/AIS_BaseStationReport.cs b/AIS/bsmd.AIS2Service/AIS_BaseStationReport.cs index 4d3fb972..0ea9d860 100644 --- a/AIS/bsmd.AIS2Service/AIS_BaseStationReport.cs +++ b/AIS/bsmd.AIS2Service/AIS_BaseStationReport.cs @@ -70,17 +70,23 @@ namespace bsmd.AIS2Service { Status result = Status.OK; BitArray bits = DecodeBinary(_data); + uint year = 0; + uint month = 0; + uint day = 0; + uint hour = 0; + uint minute = 0; + uint second = 0; try { _repeatIndicator = GetUInt(bits, 6, 7); _mmsi = GetInt(bits, 8, 37); - uint year = GetUInt(bits, 38, 51); - uint month = GetUInt(bits, 52, 55); - uint day = GetUInt(bits, 56, 60); - uint hour = GetUInt(bits, 61, 65); - uint minute = GetUInt(bits, 66, 71); - uint second = GetUInt(bits, 72, 77); + year = GetUInt(bits, 38, 51); + month = GetUInt(bits, 52, 55); + day = GetUInt(bits, 56, 60); + hour = GetUInt(bits, 61, 65); + minute = GetUInt(bits, 66, 71); + second = GetUInt(bits, 72, 77); _utcTimestamp = new DateTime((int) year, (int) month, (int) day, (int) hour, (int) minute, (int) second, DateTimeKind.Utc); _accuracy = GetInt(bits, 78, 78) == 1; _longitude = GetInt(bits, 79, 106); @@ -90,6 +96,11 @@ namespace bsmd.AIS2Service _raim = GetInt(bits, 148, 148) == 1; _radio = GetUInt(bits, 149, 167); } + catch(ArgumentOutOfRangeException) + { + _log.WarnFormat("Year: {0} Month: {1} Day: {2} Hour: {3} Minute: {4} Second: {5}", year, month, day, hour, minute, second); + result = Status.PARSE_ERROR; + } catch (Exception e) { _log.WarnFormat("Error decoding AIS base station report: {0}", e.Message); diff --git a/AIS/bsmd.AIS2Service/AIS_ClassBStatic.cs b/AIS/bsmd.AIS2Service/AIS_ClassBStatic.cs index 01be35f8..3c2e1915 100644 --- a/AIS/bsmd.AIS2Service/AIS_ClassBStatic.cs +++ b/AIS/bsmd.AIS2Service/AIS_ClassBStatic.cs @@ -36,11 +36,6 @@ namespace bsmd.AIS2Service public string Name { get { return this.name; } - } - - public string ShipType - { - get { return AIS_StaticData.GetShipType(this.shipType); } } public string VendorId diff --git a/AIS/bsmd.AIS2Service/AIS_PosReport.cs b/AIS/bsmd.AIS2Service/AIS_PosReport.cs index 475d4f6e..e7b6f25c 100644 --- a/AIS/bsmd.AIS2Service/AIS_PosReport.cs +++ b/AIS/bsmd.AIS2Service/AIS_PosReport.cs @@ -18,7 +18,7 @@ namespace bsmd.AIS2Service private int trueheading; private DateTime timestamp; private int utcTimeSecond; - private int reserved; + private int maneuver_indicator; private int spare; private int raim; private int commstate; @@ -104,7 +104,7 @@ namespace bsmd.AIS2Service } } - public int Reserved { get { return this.reserved; } } + public int ManeuverIndicator { get { return this.maneuver_indicator; } } public int Spare { get { return this.spare; } } @@ -173,8 +173,8 @@ namespace bsmd.AIS2Service this.cog = GetInt(bits, 116, 127); this.trueheading = GetInt(bits, 128, 136); this.utcTimeSecond = GetInt(bits, 137, 142); - this.reserved = GetInt(bits, 143, 146); - this.spare = GetInt(bits, 147, 147); + this.maneuver_indicator = GetInt(bits, 143, 144); + this.spare = GetInt(bits, 145, 147); this.raim = GetInt(bits, 148, 148); this.commstate = GetInt(bits, 149, 167); } diff --git a/AIS/bsmd.AIS2Service/AIS_StaticData.cs b/AIS/bsmd.AIS2Service/AIS_StaticData.cs index 764d4317..dac61dd5 100644 --- a/AIS/bsmd.AIS2Service/AIS_StaticData.cs +++ b/AIS/bsmd.AIS2Service/AIS_StaticData.cs @@ -38,9 +38,7 @@ namespace bsmd.AIS2Service #endregion - #region Properties - - public int ShipTypeVal { get { return this.shiptype; } } + #region Properties public string Callsign { @@ -95,9 +93,9 @@ namespace bsmd.AIS2Service } } - public int Draught + public double Draught { - get { return this.maxpresetstaticdraught; } + get { return this.maxpresetstaticdraught / 10.0; } } public int Breadth @@ -114,21 +112,13 @@ namespace bsmd.AIS2Service { return this.a + this.b; } - } + } - public string ShipType - { - get - { - return AIS_StaticData.GetShipType(this.shiptype); - } - } + public int ShipType { get { return this.shiptype; } } - public int DBShipType { get { return this.shiptype; } } + public int Dimension { get { return this.dimension; } } - public int DBDimension { get { return this.dimension; } } - - public int DBTypeOfDevice { get { return this.typeofdevice; } } + public int TypeOfDevice { get { return this.typeofdevice; } } public int DTE { get { return this.dte; } } @@ -149,6 +139,8 @@ namespace bsmd.AIS2Service } } + public int Version { get { return ais_version; } } + #endregion #region abstract method implementation @@ -251,118 +243,7 @@ namespace bsmd.AIS2Service return string.Format("{0} - {1} [{2}]", base.ToString(), this.MMSI, this.Name); } - #endregion - - #region public static methods - - public static string GetShipType(int shiptype) - { - if (shiptype > 199) return "preserved for future use"; - if (shiptype > 99) return "preserved for regional use"; - int dig1, dig2; - switch (shiptype) - { - case 50: - return "Pilot vessel"; - case 51: - return "SAR vessel"; - case 52: - return "Tug"; - case 53: - return "Port tender"; - case 54: - return "Vessel with anti-pollution facility or equipment"; - case 55: - return "Law enforcment vessel"; - case 56: - return "Spare [local vessel]"; - case 57: - return "Spare [local vessel]"; - case 58: - return "Medical transport"; - case 59: - return "Ship according to Resolution No. 18 (Mob-83)"; - default: - { - string comb = ""; - dig1 = shiptype / 10; - dig2 = shiptype % 10; - switch (dig1) - { - case 1: - comb += "reserved for future use"; - break; - case 2: - comb += "WIG"; - break; - case 3: - comb += "Vessel"; - switch (dig2) - { - case 0: - comb += " Fishing"; break; - case 1: - comb += " Towing"; break; - case 2: - comb += " Towing and length of tow exceeds 200m or breadth exceeds 25m"; break; - case 3: - comb += " Engaged in dredging or underwater operations"; break; - case 4: - comb += " Engaged in diving operations"; break; - case 5: - comb += " Engaged in military operations"; break; - case 6: - comb += " Sailing"; break; - case 7: - comb += " Pleasure craft"; break; - default: - comb += " reserved for future use"; - break; - } - return comb; - case 4: - comb += "HSC"; - break; - case 6: - comb += "Passenger ship"; - break; - case 7: - comb += "Cargo ship"; - break; - case 8: - comb += "Tanker"; - break; - default: - case 9: - comb += "other"; - break; - } - switch (dig2) - { - case 0: break; - case 1: - comb += " carrying DG, HS or MP IMO hazard or pollutant category A"; break; - case 2: - comb += " carrying DG, HS or MP IMO hazard or pollutant category B"; break; - case 3: - comb += " carrying DG, HS or MP IMO hazard or pollutant category C"; break; - case 4: - comb += " carrying DG, HS or MP IMO hazard or pollutant category D"; break; - case 5: - case 6: - case 7: - case 8: - comb += " reserved for future use"; break; - case 9: - comb += " no additional information"; break; - } - return comb; - } - } - } - - - #endregion + #endregion } } diff --git a/AIS/bsmd.AIS2Service/AIS_Target.cs b/AIS/bsmd.AIS2Service/AIS_Target.cs index 99bb284b..52b83296 100644 --- a/AIS/bsmd.AIS2Service/AIS_Target.cs +++ b/AIS/bsmd.AIS2Service/AIS_Target.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace bsmd.AIS2Service { @@ -8,25 +6,35 @@ namespace bsmd.AIS2Service { #region private members + + private int _mmsi; + private bool? _isClassB = false; + private DateTime? _lastUpdate; + private string _name; + private string _callSign; + private double? _latitude; + private double? _longitude; + private int? _heading; + private double? _cog; + private int? _rot; + private double? _sog; + private bool? _accuracy; + private int? _maneuverIndicator; + private bool? _raim; + private int? _radio; + private int? _imo; + private int? _shipType; + private int? _aisVersion; + private int? _breadth; + private int? _length; + private int? _typeOfDevice; + private DateTime? _eta; + private double? _draught; + private string _destination; + private bool? _dte; - public static TimeSpan dbUpdateInterval = new TimeSpan(0, 2, 0); // neue Position in DB schreiben (min Interval) - private int mmsi; - private bool isClassB = false; - private bool? isWatchkeeper = null; - private DateTime? lastUpdate; - private bool updateDB = false; - private string name; - private string station; - private string lastDBName; - private string callSign; - private bool selected = false; - - private AISClass staticInfo; - private AISClass posReport; - private AISClass lastAdditionalData; - - private AIS_Target.Type type = Type.OTHER; - private AIS_Target.NavStatus navStatus = AIS_Target.NavStatus.UNKNOWN; + private AIS_Target.Type _type = Type.OTHER; + private int _navStatus = 15; // not defined #endregion @@ -42,17 +50,7 @@ namespace bsmd.AIS2Service TUG, YACHT, OTHER - } - - /// - /// vereinfacht - /// - public enum NavStatus - { - UNKNOWN, - UNDERWAY, - MOORED - } + } #endregion @@ -60,7 +58,7 @@ namespace bsmd.AIS2Service public AIS_Target(int mmsi) { - this.mmsi = mmsi; + this._mmsi = mmsi; } #endregion @@ -69,239 +67,181 @@ namespace bsmd.AIS2Service public int MMSI { - get { return this.mmsi; } + get { return this._mmsi; } } public DateTime? LastUpdate { - get { return this.lastUpdate; } + get { return this._lastUpdate; } private set { this._lastUpdate = value; } } public string Name { - get { - if ((this.name == null) || (this.name.Length == 0)) - return this.LastDBName; - return this.name; - } - set { this.name = value; } + get { return this._name; } + private set { this._name = value; } } public string Callsign { - get { return this.callSign; } - set { this.callSign = value; } - } - - public string LastDBName - { - get { return this.lastDBName; } - set { this.lastDBName = value; } - } - - public string ReceivedFrom - { - get { return this.station; } - } - - internal AISClass LastPosReport - { - get { return this.posReport; } - } - - internal AISClass LastStaticData - { - get { return this.staticInfo; } - } + get { return this._callSign; } + private set { this._callSign = value; } + } public double? Latitude { - get - { - if (this.LastPosReport == null) return null; - if (this.LastPosReport is AIS_PosReport) - return ((AIS_PosReport)this.LastPosReport).Latitude; - if (this.LastPosReport is AIS_ClassB) - return ((AIS_ClassB)this.LastPosReport).Latitude; - if (this.LastPosReport is AIS_ClassBExt) - return ((AIS_ClassBExt)this.LastPosReport).Latitude; - return null; - } - } - - public Type TargetType - { - get { return this.type; } - set { this.type = value; } - } - - public NavStatus TargetNavStatus - { - get { return this.navStatus; } + get { return this._latitude; } private set { this._latitude = value; } } public double? Longitude { - get - { - if (this.LastPosReport == null) return null; - if (this.LastPosReport is AIS_PosReport) - return ((AIS_PosReport)this.LastPosReport).Longitude; - if (this.LastPosReport is AIS_ClassB) - return ((AIS_ClassB)this.LastPosReport).Longitude; - if (this.LastPosReport is AIS_ClassBExt) - return ((AIS_ClassBExt)this.LastPosReport).Longitude; - return null; - } + get { return this._longitude; } private set { this._longitude = value; } } + public Type TargetType + { + get { return this._type; } + set { this._type = value; } + } + + public int NavStatus + { + get { return this._navStatus; } private set { this._navStatus = value; } + } + public bool? IsClassB { - get - { - return this.isClassB; - } + get { return this._isClassB; } + private set { this._isClassB = value; } } public int? Heading { - get - { - if (this.LastPosReport == null) return null; - if (this.LastPosReport is AIS_PosReport) - return ((AIS_PosReport)this.LastPosReport).TrueHeading; - if (this.LastPosReport is AIS_ClassB) - return ((AIS_ClassB)this.LastPosReport).TrueHeading; - if (this.LastPosReport is AIS_ClassBExt) - return ((AIS_ClassBExt)this.LastPosReport).TrueHeading; - return null; - } + get { return _heading; } private set { _heading = value; } } - public int? COG + public double? COG { - get - { - if (this.LastPosReport == null) return null; - if (this.LastPosReport is AIS_PosReport) - return (int)((AIS_PosReport)this.LastPosReport).COG; - if (this.LastPosReport is AIS_ClassB) - return (int)((AIS_ClassB)this.LastPosReport).Cog; - if (this.LastPosReport is AIS_ClassBExt) - return (int) ((AIS_ClassBExt)this.LastPosReport).Cog; - return null; - } + get { return _cog; } private set { _cog = value; } + } + + public int? ROT + { + get { return _rot; } private set { _rot = value; } } - public bool? IsWatchkeeperShip + public double? SOG { - get { return this.isWatchkeeper; } - set { this.isWatchkeeper = value; } + get { return _sog; } private set { _sog = value; } } - public bool Selected + public bool? Accuracy { - get { return this.selected; } - set { this.selected = value; } + get { return _accuracy; } private set { _accuracy = value; } } - public string Station + public int? ManeuverIndicator { - get { return this.station; } - set { this.station = value; } + get { return _maneuverIndicator; } private set { _maneuverIndicator = value; } + } + + public bool? RAIM + { + get { return _raim; } private set { _raim = value; } + } + + public int? Radio + { + get { return _radio; } private set { _radio = value; } + } + + public int? AISVersion + { + get { return _aisVersion; } private set { _aisVersion = value; } + } + + public int? IMO + { + get { return _imo; } private set { _imo = value; } + } + + public int? ShipType + { + get { return _shipType; } private set { _shipType = value; } + } + + public int? Breadth + { + get { return _breadth; } private set { _breadth = value; } + } + + public int? Length + { + get { return _length; } private set { _length = value; } + } + + public int? TypeOfDevice + { + get { return _typeOfDevice; } private set { _typeOfDevice = value; } + } + + public DateTime? ETA + { + get { return _eta; } private set { _eta = value; } + } + + public double? Draught + { + get { return _draught; } private set { _draught = value; } + } + + public string Destination + { + get { return _destination; } private set { _destination = value; } + } + + public bool? DTE + { + get { return _dte; } private set { _dte = value; } } #endregion #region public methods - public static AIS_Target.NavStatus GetCurrentNavstatus(int status) + internal void Update(AIS_PosReport posReport) { - AIS_Target.NavStatus result = NavStatus.UNKNOWN; - switch (status) - { - case 0: - case 8: - result = NavStatus.UNDERWAY; - break; - default: - result = NavStatus.MOORED; - break; - } - return result; + this.NavStatus = posReport.NavStatusVal; + this.ROT = posReport.ROT; + this.SOG = posReport.SOG; + this.Accuracy = (posReport.Accuracy == 1); + this.Latitude = posReport.Latitude; + this.Longitude = posReport.Longitude; + this.COG = posReport.COG; + this.Heading = posReport.TrueHeading; + this.ManeuverIndicator = posReport.ManeuverIndicator; + this.RAIM = posReport.Raim == 1; + this.Radio = posReport.CommState; + + this.LastUpdate = DateTime.Now; } - internal void Update(AISClass message) - { + internal void Update(AIS_StaticData staticData) + { + this.AISVersion = staticData.Version; + this.IMO = staticData.IMONumber; + this.Callsign = staticData.Callsign; + this.Name = staticData.Name; + this.ShipType = staticData.ShipType; + this.Breadth = staticData.Breadth; + this.Length = staticData.Length; + this.TypeOfDevice = staticData.TypeOfDevice; + this.ETA = staticData.ETA; + this.Draught = staticData.Draught; + this.Destination = staticData.Destination; + this.DTE = staticData.DTE == 0; - switch (message.MessageType) - { - case AISClass.AISType.POSITION_REPORT: - case AISClass.AISType.POSITION_REPORT_ASSIGNED: - case AISClass.AISType.POSITION_REPORT_SPECIAL: - if ((this.lastUpdate.HasValue && - (((AIS_PosReport)message).Timestamp - this.lastUpdate.Value) > AIS_Target.dbUpdateInterval) - || (!this.lastUpdate.HasValue)) - { - this.updateDB = true; - this.lastUpdate = ((AIS_PosReport)message).Timestamp; - } - this.posReport = message; - this.navStatus = AIS_Target.GetCurrentNavstatus(((AIS_PosReport)message).NavStatusVal); - // System.Diagnostics.Trace.WriteLine(string.Format("pos report at {0}", this.lastUpdate)); - break; - case AISClass.AISType.POSITION_REPORT_B_EQUIP: - if ((this.lastUpdate.HasValue && - (((AIS_ClassB)message).Timestamp - this.lastUpdate.Value) > AIS_Target.dbUpdateInterval) - || (!this.lastUpdate.HasValue)) - { - this.updateDB = true; - this.lastUpdate = ((AIS_ClassB)message).Timestamp; - this.isClassB = true; - this.type = Type.YACHT; - this.navStatus = NavStatus.UNDERWAY; - } - this.posReport = message; - break; - case AISClass.AISType.POSITION_REPORT_B_EQUIP_EXT: - if ((this.lastUpdate.HasValue && - (((AIS_ClassBExt)message).Timestamp - this.lastUpdate.Value) > AIS_Target.dbUpdateInterval) - || (!this.lastUpdate.HasValue)) - { - this.updateDB = true; - this.lastUpdate = ((AIS_ClassBExt)message).Timestamp; - this.isClassB = true; - this.type = Type.YACHT; - this.navStatus = NavStatus.UNDERWAY; - } - this.posReport = message; - break; - case AISClass.AISType.STATIC_VOYAGE_DATA: - this.staticInfo = message; - this.name = ((AIS_StaticData)message).Name; - this.callSign = ((AIS_StaticData)message).Callsign; - //this.type = AIS_StaticData.GetShipTypeSimple(((AIS_StaticData)message).ShipTypeVal); - - break; - case AISClass.AISType.CLASS_B_STATIC_DATA: - if (((AIS_ClassBStatic)message).IsPartA) - { - this.name = ((AIS_ClassBStatic)message).Name; - } - else - { - this.callSign = ((AIS_ClassBStatic)message).Callsign; - } - this.staticInfo = message; - this.type = Type.YACHT; - this.isClassB = true; - break; - default: - this.lastAdditionalData = message; - break; - } - - } + this.LastUpdate = DateTime.Now; + } #endregion diff --git a/AIS/bsmd.AIS2Service/App.config b/AIS/bsmd.AIS2Service/App.config index 5aa8e79d..bbd0d78b 100644 --- a/AIS/bsmd.AIS2Service/App.config +++ b/AIS/bsmd.AIS2Service/App.config @@ -40,6 +40,9 @@ 32100 + + 60 + \ No newline at end of file diff --git a/AIS/bsmd.AIS2Service/Lookup.cs b/AIS/bsmd.AIS2Service/Lookup.cs new file mode 100644 index 00000000..21ac114b --- /dev/null +++ b/AIS/bsmd.AIS2Service/Lookup.cs @@ -0,0 +1,164 @@ + +using System.Collections.Generic; + +namespace bsmd.AIS2Service +{ + + /// + /// Class contains static AIS lookup tables (not likely to change..) + /// + internal static class Lookup + { + + #region Ship types + + public static readonly Dictionary ShipTypes = new Dictionary + { + {0, "not available" }, + {1, "reserved" }, + {2, "reserved" }, + {3, "reserved" }, + {4, "reserved" }, + {5, "reserved" }, + {6, "reserved" }, + {7, "reserved" }, + {8, "reserved" }, + {9, "reserved" }, + {10, "reserved" }, + {11, "reserved" }, + {12, "reserved" }, + {13, "reserved" }, + {14, "reserved" }, + {15, "reserved" }, + {16, "reserved" }, + {17, "reserved" }, + {18, "reserved" }, + {19, "reserved" }, + {20, "WIG all types" }, + {21, "WIG Hazardous category A" }, + {22, "WIG Hazardous category B" }, + {23, "WIG Hazardous category C" }, + {24, "WIG Hazardous category D" }, + {25, "WIG reserved" }, + {26, "WIG reserved" }, + {27, "WIG reserved" }, + {28, "WIG reserved" }, + {29, "WIG reserved" }, + {30, "Fishing" }, + {31, "Towing" }, + {32, "Towing: Length>200m or Breadth>25m" }, + {33, "Dredging or underwater ops" }, + {34, "Diving ops" }, + {35, "Military ops" }, + {36, "Sailing" }, + {37, "Pleasure craft" }, + {38, "reserved" }, + {39, "reserved" }, + {40, "HSC, all types" }, + {41, "HSC Hazardous category A" }, + {42, "HSC Hazardous category B" }, + {43, "HSC Hazardous category C" }, + {44, "HSC Hazardous category D" }, + {45, "HSC reserved" }, + {46, "HSC reserved" }, + {47, "HSC reserved" }, + {48, "HSC reserved" }, + {49, "HSC no additional info" }, + {50, "Pilot" }, + {51, "SAR" }, + {52, "Tug" }, + {53, "Port tender" }, + {54, "Anti-pollution equipment" }, + {55, "Law enforcement" }, + {56, "Spare - local vessel" }, + {57, "Spare - local vessel" }, + {58, "Medical transport" }, + {59, "Noncombatant ship acc. Res. No. 18" }, + {60, "Passenger, all types" }, + {61, "Passenger Hazardous category A" }, + {62, "Passenger Hazardous category B" }, + {63, "Passenger Hazardous category C" }, + {64, "Passenger Hazardous category D" }, + {65, "Passenger reserved" }, + {66, "Passenger reserved" }, + {67, "Passenger reserved" }, + {68, "Passenger reserved" }, + {69, "Passenger no additional info" }, + {70, "Cargo, all types" }, + {71, "Cargo Hazardous category A" }, + {72, "Cargo Hazardous category B" }, + {73, "Cargo Hazardous category C" }, + {74, "Cargo Hazardous category D" }, + {75, "Cargo reserved" }, + {76, "Cargo reserved" }, + {77, "Cargo reserved" }, + {78, "Cargo reserved" }, + {79, "Cargo no additional info" }, + {80, "Tanker, all types" }, + {81, "Tanker Hazardous category A" }, + {82, "Tanker Hazardous category B" }, + {83, "Tanker Hazardous category C" }, + {84, "Tanker Hazardous category D" }, + {85, "Tanker reserved" }, + {86, "Tanker reserved" }, + {87, "Tanker reserved" }, + {88, "Tanker reserved" }, + {89, "Tanker no additional info" }, + {90, "Other type, all types" }, + {91, "Other type Hazardous category A" }, + {92, "Other type Hazardous category B" }, + {93, "Other type Hazardous category C" }, + {94, "Other type Hazardous category D" }, + {95, "Other type reserved" }, + {96, "Other type reserved" }, + {97, "Other type reserved" }, + {98, "Other type reserved" }, + {99, "Other type no additional info" }, + }; + + #endregion + + #region Navigation status + + public static readonly Dictionary NavStatus = new Dictionary + { + {0, "Under way using engine" }, + {1, "At anchor" }, + {2, "Not under command" }, + {3, "Restricted manoeuverability" }, + {4, "Constrained by her draught" }, + {5, "Moored" }, + {6, "Aground" }, + {7, "Engaged in fishing" }, + {8, "Under way sailing" }, + {9, "Reserved for future amendment of Navigational Status for HSC" }, + {10, "Reserved for future amendment of Navigational Status for WIG" }, + {11, "Reserved for future use" }, + {12, "Reserved for future use" }, + {13, "Reserved for future use" }, + {14, "AIS-SART is active" }, + {15, "Not defined" } + }; + + + #endregion + + #region Type of device + + public static readonly Dictionary DeviceTypes = new Dictionary + { + {0, "Undefined" }, + {1, "GPS" }, + {2, "GLONASS" }, + {3, "Combined GPS/GLONASS" }, + {4, "Loran-C" }, + {5, "Chayka" }, + {6, "Integrated navigation system" }, + {7, "Surveyed" }, + {8, "Galileo" } + }; + + #endregion + + } +} diff --git a/AIS/bsmd.AIS2Service/Properties/Settings.Designer.cs b/AIS/bsmd.AIS2Service/Properties/Settings.Designer.cs index 9e308f68..d9597042 100644 --- a/AIS/bsmd.AIS2Service/Properties/Settings.Designer.cs +++ b/AIS/bsmd.AIS2Service/Properties/Settings.Designer.cs @@ -40,5 +40,14 @@ namespace bsmd.AIS2Service.Properties { return ((uint)(this["DataSourcePort"])); } } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("60")] + public uint StaleTargetTimeoutMins { + get { + return ((uint)(this["StaleTargetTimeoutMins"])); + } + } } } diff --git a/AIS/bsmd.AIS2Service/Properties/Settings.settings b/AIS/bsmd.AIS2Service/Properties/Settings.settings index 7da83a50..273d1c24 100644 --- a/AIS/bsmd.AIS2Service/Properties/Settings.settings +++ b/AIS/bsmd.AIS2Service/Properties/Settings.settings @@ -8,5 +8,8 @@ 32100 + + 60 + \ No newline at end of file diff --git a/AIS/bsmd.AIS2Service/SitRep.cs b/AIS/bsmd.AIS2Service/SitRep.cs new file mode 100644 index 00000000..eb742ab6 --- /dev/null +++ b/AIS/bsmd.AIS2Service/SitRep.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +using log4net; + +namespace bsmd.AIS2Service +{ + + /// + /// Manager / Thread Klasse um die "aktuelle" Situation zu aktualisieren und die Daten + /// in die (Sqlite-Zwischen-) Datenbank zu schieben + /// + internal class SitRep : IAISThread + { + private Thread _thread; + private bool _stopFlag = false; + private static readonly ILog _log = LogManager.GetLogger(typeof(SitRep)); + private readonly ConcurrentQueue _inputQueue; + private readonly ConcurrentDictionary _sitRep; + private const int sleepMS = 250; + + public SitRep(ConcurrentQueue inputQueue, ConcurrentDictionary sitRep) + { + _inputQueue = inputQueue; _sitRep = sitRep; + } + + private void ReadMessages() + { + try + { + while (!_stopFlag) + { + if(_inputQueue.TryDequeue(out AISClass aisMessage)) + { + switch(aisMessage.MessageType) + { + case AISClass.AISType.POSITION_REPORT: + case AISClass.AISType.POSITION_REPORT_ASSIGNED: + case AISClass.AISType.POSITION_REPORT_SPECIAL: + { + AIS_PosReport posReport = aisMessage as AIS_PosReport; + if(!_sitRep.ContainsKey(posReport.MMSI)) + { + AIS_Target target = new AIS_Target(posReport.MMSI); + _sitRep[posReport.MMSI] = target; + } + _sitRep[posReport.MMSI].Update(posReport); + } + break; + case AISClass.AISType.STATIC_VOYAGE_DATA: + { + AIS_StaticData staticData = aisMessage as AIS_StaticData; + if(!_sitRep.ContainsKey(staticData.MMSI)) + { + AIS_Target target = new AIS_Target(staticData.MMSI); + _sitRep[staticData.MMSI] = target; + } + _sitRep[staticData.MMSI].Update(staticData); + } + break; + default: + _log.InfoFormat("currently discarding AIS message {0}", aisMessage.MessageType); + break; + } + } + else + { + Thread.Sleep(sleepMS); + _log.DebugFormat("Targets: {0}", _sitRep.Count); + } + } + } + + catch (Exception ex) + { + _log.ErrorFormat("Something bad has happened: {0}", ex.Message); + this.FatalErrorOccurred?.Invoke(this, new EventArgs()); + } + } + + #region IAISThread implementation + + public string Name { get { return "Sit rep"; } } + + public event EventHandler FatalErrorOccurred; + + public void Start() + { + if (_thread != null) return; // may not run twice + ThreadStart runReader = new ThreadStart(this.ReadMessages); + _thread = new Thread(runReader); + _thread.Start(); + } + + public void Stop() + { + if (_thread == null) return; + _stopFlag = true; + _thread.Join(); + _thread = null; + } + + #endregion + + } +} diff --git a/AIS/bsmd.AIS2Service/bsmd.AIS2Service.csproj b/AIS/bsmd.AIS2Service/bsmd.AIS2Service.csproj index 59647bfb..1078704a 100644 --- a/AIS/bsmd.AIS2Service/bsmd.AIS2Service.csproj +++ b/AIS/bsmd.AIS2Service/bsmd.AIS2Service.csproj @@ -71,6 +71,7 @@ + @@ -82,6 +83,7 @@ Settings.settings +