// Copyright (c) 2022 - schick Informatik // bsmd.AIS2Service [SitRep.cs]: Daniel Schick // Description: Current, memory-mapped situation of what the receiver "sees" // using System; using System.Collections.Concurrent; using System.Collections.Generic; 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 { #region Fields 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 readonly Dictionary _baseStations = new Dictionary(); private readonly ConcurrentQueue _dbQueue; #endregion #region Construction public SitRep(ConcurrentQueue inputQueue, ConcurrentDictionary sitRep, ConcurrentQueue dbQueue) { _inputQueue = inputQueue; _sitRep = sitRep; _dbQueue = dbQueue; } #endregion #region Properties public Dictionary BaseStations { get { return _baseStations; } } #endregion #region mainloop thread 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; } DateTime? lastUpdate = _sitRep[posReport.MMSI].LastUpdate; _sitRep[posReport.MMSI].Update(posReport); if (!lastUpdate.HasValue || ((DateTime.Now - lastUpdate.Value).TotalSeconds > Properties.Settings.Default.PosReportMinTimeDiffSecs)) _dbQueue.Enqueue(_sitRep[posReport.MMSI]); } 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); _dbQueue.Enqueue(_sitRep[staticData.MMSI]); } break; case AISClass.AISType.CLASS_B_STATIC_DATA: { AIS_ClassBStatic bStaticData = aisMessage as AIS_ClassBStatic; if(!_sitRep.ContainsKey(bStaticData.MMSI)) { AIS_Target target = new AIS_Target(bStaticData.MMSI); _sitRep[bStaticData.MMSI] = target; } _sitRep[bStaticData.MMSI].Update(bStaticData); _dbQueue.Enqueue(_sitRep[bStaticData.MMSI]); } break; case AISClass.AISType.POSITION_REPORT_B_EQUIP: { AIS_ClassB bPos = aisMessage as AIS_ClassB; if(!_sitRep.ContainsKey(bPos.MMSI)) { AIS_Target target = new AIS_Target(bPos.MMSI); _sitRep[bPos.MMSI] = target; } _sitRep[bPos.MMSI].Update(bPos); _dbQueue.Enqueue(_sitRep[bPos.MMSI]); } break; case AISClass.AISType.POSITION_REPORT_B_EQUIP_EXT: { AIS_ClassBExt bPosExt = aisMessage as AIS_ClassBExt; if (!_sitRep.ContainsKey(bPosExt.MMSI)) { AIS_Target target = new AIS_Target(bPosExt.MMSI); _sitRep[bPosExt.MMSI] = target; } _sitRep[bPosExt.MMSI].Update(bPosExt); _dbQueue.Enqueue(_sitRep[bPosExt.MMSI]); } break; case AISClass.AISType.BASE_STATION_REPORT: { AIS_BaseStationReport bsr = aisMessage as AIS_BaseStationReport; if(!_baseStations.ContainsKey(bsr.MMSI)) { AIS_BaseStation baseStation = new AIS_BaseStation(bsr.MMSI); _baseStations[bsr.MMSI] = baseStation; } _baseStations[bsr.MMSI].Update(bsr); } break; default: _log.InfoFormat("currently discarding AIS message {0}", aisMessage.MessageType); break; } } else { Thread.Sleep(Properties.Settings.Default.ThreadSleepMS); } } } catch (Exception ex) { _log.ErrorFormat("Something bad has happened: {0}", ex.Message); this.FatalErrorOccurred?.Invoke(this, new EventArgs()); } } #endregion #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 } }