195 lines
6.0 KiB
C#
195 lines
6.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Text;
|
|
|
|
namespace bsmd.AISService.AIS
|
|
{
|
|
|
|
/// <summary>
|
|
/// Diese Klasse setzt fragmentierte AIS Telegramme wieder zusammen und decodiert sie
|
|
/// </summary>
|
|
public class AIS_Decoder
|
|
{
|
|
|
|
public delegate void AISMessageHandler(AIS message);
|
|
public event AISMessageHandler AISMessageReceived;
|
|
|
|
#region class AISQueueElement
|
|
|
|
public class AISQueueElement
|
|
{
|
|
public int seq_nr;
|
|
public int total_nr;
|
|
public int? id;
|
|
public string data;
|
|
public string station;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region private members
|
|
|
|
private Queue<AISQueueElement> inputDataQueue = new Queue<AISQueueElement>();
|
|
private Thread decodingThread;
|
|
private bool runDecoder = true;
|
|
private int sleepMS = 250;
|
|
private Dictionary<int, List<AISQueueElement>> fragmentDict = new Dictionary<int, List<AISQueueElement>>();
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
public int QueueSize
|
|
{
|
|
get { return this.inputDataQueue.Count; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public methods
|
|
|
|
public void Decode(string data, int seq_nr, int total_nr, int? id, string station)
|
|
{
|
|
lock (this.inputDataQueue)
|
|
{
|
|
AISQueueElement element = new AISQueueElement();
|
|
element.data = data;
|
|
element.seq_nr = seq_nr;
|
|
element.total_nr = total_nr;
|
|
element.id = id;
|
|
element.station = station;
|
|
|
|
this.inputDataQueue.Enqueue(element);
|
|
}
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
this.decodingThread = new Thread(new ThreadStart(this.Run));
|
|
this.decodingThread.Start();
|
|
}
|
|
|
|
public void Stop()
|
|
{
|
|
this.runDecoder = false;
|
|
if((this.decodingThread != null) &&
|
|
(this.decodingThread.ThreadState == ThreadState.Running))
|
|
this.decodingThread.Join();
|
|
this.inputDataQueue.Clear(); // discard unread elements
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Thread worker method
|
|
/// </summary>
|
|
protected void Run()
|
|
{
|
|
while (this.runDecoder)
|
|
{
|
|
AISQueueElement inputData = null;
|
|
|
|
lock (this.inputDataQueue)
|
|
{
|
|
if (this.inputDataQueue.Count > 0)
|
|
{
|
|
inputData = this.inputDataQueue.Dequeue();
|
|
}
|
|
}
|
|
|
|
if (inputData == null)
|
|
Thread.Sleep(this.sleepMS);
|
|
else
|
|
{
|
|
string aisRawData = null;
|
|
if (inputData.total_nr == 1)
|
|
{
|
|
aisRawData = inputData.data;
|
|
}
|
|
else
|
|
{
|
|
int id = inputData.id ?? -1;
|
|
|
|
if (!this.fragmentDict.ContainsKey(id))
|
|
this.fragmentDict.Add(id, new List<AISQueueElement>());
|
|
this.fragmentDict[id].Add(inputData);
|
|
|
|
// sind alle Fragmente vorhanden?
|
|
if (AIS_Decoder.FragmentsComplete(this.fragmentDict[id]))
|
|
{
|
|
// Fragmente zusammensetzen
|
|
aisRawData = AIS_Decoder.ConcatenateFragments(this.fragmentDict[id]);
|
|
this.fragmentDict.Remove(id);
|
|
}
|
|
|
|
}
|
|
|
|
if (aisRawData != null)
|
|
{
|
|
AIS.Status status = AIS.Status.OK;
|
|
AIS message = AIS.Decode(aisRawData, ref status);
|
|
if (status == AIS.Status.OK)
|
|
{
|
|
message.Station = inputData.station;
|
|
this.OnAISMessageReceived(message);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
#region private helpers
|
|
|
|
/// <summary>
|
|
/// check to see if all fragments are available
|
|
/// </summary>
|
|
private static bool FragmentsComplete(List<AISQueueElement> elements)
|
|
{
|
|
if (elements == null || elements.Count == 0) return false;
|
|
int num = elements[0].total_nr;
|
|
|
|
for (int i = 1; i <= num; i++)
|
|
{
|
|
bool foundElements = false;
|
|
for (int j = 0; j < elements.Count; j++)
|
|
{
|
|
if (elements[j].seq_nr == i)
|
|
foundElements = true;
|
|
}
|
|
if (!foundElements) return false; // etwas fehlt noch
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// assembles message fragments. Care must be taken since fragments can appear
|
|
/// out of order
|
|
/// </summary>
|
|
private static string ConcatenateFragments(List<AISQueueElement> elements)
|
|
{
|
|
if (elements == null || elements.Count == 0) return string.Empty;
|
|
int num = elements[0].total_nr;
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
for (int i = 1; i <= num; i++)
|
|
{
|
|
for (int j = 0; j < elements.Count; j++)
|
|
if (elements[j].seq_nr == i)
|
|
sb.Append(elements[j].data);
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
|
|
#endregion
|
|
|
|
protected void OnAISMessageReceived(AIS message)
|
|
{
|
|
if (this.AISMessageReceived != null)
|
|
this.AISMessageReceived(message);
|
|
}
|
|
|
|
}
|
|
}
|