161 lines
5.7 KiB
C#
161 lines
5.7 KiB
C#
// Copyright (c) 2022 - schick Informatik
|
|
// bsmd.AIS2Service [AISZoneMonitor.cs]: %UserDisplayName%
|
|
// Description: Background Thread Controller class for comparing AIS Targets
|
|
// to monitor zones
|
|
//
|
|
|
|
using log4net;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Security.Policy;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace bsmd.AIS2Service
|
|
{
|
|
internal class AISZoneMonitor : IAISThread
|
|
{
|
|
|
|
#region Fields
|
|
|
|
ConcurrentDictionary<int, AIS_Target> _sitRepDict;
|
|
AIS_SQLiteStorage _storage;
|
|
private Thread _thread;
|
|
private bool _stopFlag = false;
|
|
private static readonly ILog _log = LogManager.GetLogger(typeof(AISZoneMonitor));
|
|
|
|
#endregion
|
|
|
|
#region Construction
|
|
|
|
public AISZoneMonitor(ConcurrentDictionary<int, AIS_Target> sitRepDict, AIS_SQLiteStorage sqliteStorage)
|
|
{
|
|
_sitRepDict = sitRepDict;
|
|
_storage = sqliteStorage;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region private methods
|
|
|
|
private void Monitor()
|
|
{
|
|
// load zones from storage
|
|
List<MonitorZone> allZones = _storage.LoadMonitorZones();
|
|
Dictionary<int, List<AlarmAssignmentZone>> testDict = new Dictionary<int, List<AlarmAssignmentZone>>();
|
|
// letzte Alarme
|
|
// Dictionary<int, Alarm> currentAlarms = _storage.LoadAlarms();
|
|
|
|
foreach(MonitorZone zone in allZones)
|
|
{
|
|
// load up Zone list for all assignment mmsi's (to check)
|
|
foreach(MonitorAssignment ma in zone.Assignments)
|
|
{
|
|
if(!testDict.ContainsKey(ma.MMSI)) testDict[ma.MMSI] = new List<AlarmAssignmentZone>();
|
|
ma.Alarms.AddRange(_storage.LoadAlarms(ma));
|
|
AlarmAssignmentZone aazone = new AlarmAssignmentZone();
|
|
aazone.Zone = zone;
|
|
aazone.Assignment = ma;
|
|
testDict[ma.MMSI].Add(aazone);
|
|
}
|
|
}
|
|
|
|
// loop
|
|
while(!_stopFlag)
|
|
{
|
|
// check all "current" AIS Targets against the zones
|
|
|
|
foreach(int mmsi in _sitRepDict.Keys)
|
|
{
|
|
if(testDict.ContainsKey(mmsi))
|
|
{
|
|
AIS_Target target = _sitRepDict[mmsi];
|
|
foreach(AlarmAssignmentZone aazone in testDict[mmsi]) {
|
|
if(aazone.Zone.IsPointInPolygon4(target.Position))
|
|
{
|
|
_log.InfoFormat("{0} is in zone {1}", target.ToString(), aazone.Zone.Name);
|
|
Alarm alarm;
|
|
if (aazone.Assignment.Alarms.Count > 0)
|
|
{
|
|
alarm = aazone.Assignment.Alarms[0];
|
|
if(alarm.Timestamp_Last.HasValue &&
|
|
((DateTime.Now - alarm.Timestamp_Last.Value).TotalMinutes > Properties.Settings.Default.MinAlarmIntervalMins))
|
|
{
|
|
// this "old" alarm will be triggered again (overwritten)
|
|
alarm.Acknowledged = null;
|
|
alarm.Timestamp_Last = null;
|
|
alarm.Timestamp_First = DateTime.Now;
|
|
}
|
|
else
|
|
{
|
|
// update the last time the target registered in the zone
|
|
alarm.Timestamp_Last = DateTime.Now;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// create new alarm
|
|
alarm = new Alarm(-1, aazone.Assignment);
|
|
alarm.Timestamp_First = DateTime.Now;
|
|
alarm.ZoneMonitorType = aazone.Assignment.MonitorType;
|
|
aazone.Assignment.Alarms.Add(alarm);
|
|
}
|
|
_storage.Save(alarm);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int currentSaturationSecs = 0; // (DateTime.Now - alarm.FirstDetected).TotalSeconds;
|
|
if(currentSaturationSecs > Properties.Settings.Default.MonitorTargetSaturationSecs)
|
|
{
|
|
// trigger alarm, this thing was "hot" long enough
|
|
|
|
}
|
|
|
|
Thread.Sleep(Properties.Settings.Default.MonitorTestIntervalSecs * 1000);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IAISThread implementation
|
|
|
|
public string Name { get { return "Zone monitor"; } }
|
|
|
|
public event EventHandler FatalErrorOccurred;
|
|
|
|
public void Start()
|
|
{
|
|
if (_thread != null) return; // may not run twice
|
|
ThreadStart runReader = new ThreadStart(this.Monitor);
|
|
_thread = new Thread(runReader);
|
|
_thread.Start();
|
|
}
|
|
|
|
public void Stop()
|
|
{
|
|
if (_thread == null) return;
|
|
_stopFlag = true;
|
|
_thread.Join();
|
|
_thread = null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region class AssignmentZoneAlarm composition
|
|
|
|
private class AlarmAssignmentZone
|
|
{
|
|
public MonitorZone Zone { get; set; }
|
|
public MonitorAssignment Assignment { get; set; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|