Initialer Stand von AIS nach BSMD portiert, bisher ohne Testing
This commit is contained in:
parent
8296296463
commit
061f3e1213
266
AIS/bsmd.AISService/AIS/AIS.cs
Normal file
266
AIS/bsmd.AISService/AIS/AIS.cs
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
// ship details suchbar hier: http://www.itu.int/cgi-bin/htsh/mars/ship_search.sh
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
public abstract class AIS
|
||||||
|
{
|
||||||
|
protected const double ERAD = 6378.135;
|
||||||
|
protected const double DE2RA = 0.01745329252;
|
||||||
|
protected const double AVG_ERAD = 6371.0;
|
||||||
|
|
||||||
|
|
||||||
|
#region enumerations
|
||||||
|
|
||||||
|
public enum Status
|
||||||
|
{
|
||||||
|
OK,
|
||||||
|
UNKNOWN_TYPE,
|
||||||
|
UNSUPPORTED,
|
||||||
|
ILLEGAL_ARGUMENT,
|
||||||
|
PARSE_ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AISType
|
||||||
|
{
|
||||||
|
AIS_NONE = 0,
|
||||||
|
POSITION_REPORT,
|
||||||
|
POSITION_REPORT_ASSIGNED,
|
||||||
|
POSITION_REPORT_SPECIAL,
|
||||||
|
BASE_STATION_REPORT,
|
||||||
|
STATIC_VOYAGE_DATA,
|
||||||
|
BINARY_ADDR_MSG,
|
||||||
|
BINARY_ACK,
|
||||||
|
BINARY_BCAST,
|
||||||
|
SAR_AIRCRAFT,
|
||||||
|
UTC_INQUIRY,
|
||||||
|
UTC_RESPONSE,
|
||||||
|
SAFETY_RELATED_MSG,
|
||||||
|
SAFETY_RELATED_ACK,
|
||||||
|
SAFETY_RELATED_BCAST,
|
||||||
|
INTERROGATION,
|
||||||
|
ASSIGN_MODE_CMD,
|
||||||
|
DGNSS_BCAST,
|
||||||
|
POSITION_REPORT_B_EQUIP,
|
||||||
|
POSITION_REPORT_B_EQUIP_EXT,
|
||||||
|
DATA_LINK_MAN,
|
||||||
|
AIDS_TO_NAV_REPORT,
|
||||||
|
CHANNEL_MNGNT,
|
||||||
|
GROUP_ASSIGNMENT,
|
||||||
|
CLASS_B_STATIC_DATA
|
||||||
|
};
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region private members
|
||||||
|
|
||||||
|
private AISType type = AISType.AIS_NONE;
|
||||||
|
protected int userId;
|
||||||
|
protected string data;
|
||||||
|
private string station;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public AISType MessageType
|
||||||
|
{
|
||||||
|
get { return this.type; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int MMSI
|
||||||
|
{
|
||||||
|
get { return this.userId; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Station
|
||||||
|
{
|
||||||
|
get { return this.station; }
|
||||||
|
set { this.station = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region abstract method signatures
|
||||||
|
|
||||||
|
protected abstract Status Decode();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region static methods
|
||||||
|
|
||||||
|
internal static AIS Decode(string data, ref Status status)
|
||||||
|
{
|
||||||
|
AIS result = null;
|
||||||
|
|
||||||
|
if (data == null || data.Length == 0)
|
||||||
|
{
|
||||||
|
status = Status.ILLEGAL_ARGUMENT;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
BitArray bits = AIS.DecodeChar(data[0]);
|
||||||
|
int type = AIS.GetInt(bits, 0, 5);
|
||||||
|
|
||||||
|
result = AIS.CreateMessage(type);
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
result.data = data;
|
||||||
|
status = result.Decode();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = Status.UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Factory method to create messages based on the message type
|
||||||
|
/// </summary>
|
||||||
|
protected static AIS CreateMessage(int type)
|
||||||
|
{
|
||||||
|
AIS result = null;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
result = new AIS_PosReport();
|
||||||
|
result.type = AISType.POSITION_REPORT;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
result = new AIS_PosReport();
|
||||||
|
result.type = AISType.POSITION_REPORT_ASSIGNED;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
result = new AIS_PosReport();
|
||||||
|
result.type = AISType.POSITION_REPORT_SPECIAL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
result = new AIS_StaticData();
|
||||||
|
result.type = AISType.STATIC_VOYAGE_DATA;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 18:
|
||||||
|
result = new AIS_ClassB();
|
||||||
|
result.type = AISType.POSITION_REPORT_B_EQUIP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 19:
|
||||||
|
result = new AIS_ClassBExt();
|
||||||
|
result.type = AISType.POSITION_REPORT_B_EQUIP_EXT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 24:
|
||||||
|
result = new AIS_ClassBStatic();
|
||||||
|
result.type = AISType.CLASS_B_STATIC_DATA;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region static helpers
|
||||||
|
|
||||||
|
protected static BitArray DecodeChar(char c)
|
||||||
|
{
|
||||||
|
Byte b = Convert.ToByte(c);
|
||||||
|
return DecodeByte(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static BitArray DecodeByte(byte c)
|
||||||
|
{
|
||||||
|
c += 40;
|
||||||
|
if (c > 128) c += 32;
|
||||||
|
else c += 40;
|
||||||
|
|
||||||
|
c &= 63;
|
||||||
|
|
||||||
|
BitArray b = new BitArray(6);
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
b[i] = ((c >> (5-i)) & 1) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static BitArray DecodeBinary(string data)
|
||||||
|
{
|
||||||
|
BitArray result = new BitArray(data.Length * 6, false);
|
||||||
|
|
||||||
|
for (int i = 0; i < data.Length; i++)
|
||||||
|
{
|
||||||
|
BitArray charBits = DecodeChar(data[i]);
|
||||||
|
|
||||||
|
for (int j = 0; j < charBits.Count; j++)
|
||||||
|
result[i * 6 + j] = charBits[j];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int GetInt(BitArray bits, int lo, int hi)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
int test = 1;
|
||||||
|
|
||||||
|
for (int i = hi; i >= lo; i--, test <<= 1)
|
||||||
|
{
|
||||||
|
if (bits[i]) result |= test;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static char GetAISChar(int val)
|
||||||
|
{
|
||||||
|
if(val < 32) return Convert.ToChar(val + 64);
|
||||||
|
if(val < 64) return Convert.ToChar(val);
|
||||||
|
return ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public static helpers
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// mehr dazu hier:
|
||||||
|
/// http://www.codeguru.com/cpp/cpp/algorithms/general/article.php/c5115/
|
||||||
|
/// </summary>
|
||||||
|
public static double GetDistance(double lat1, double lon1, double lat2, double lon2)
|
||||||
|
{
|
||||||
|
lat1 *= AIS.DE2RA;
|
||||||
|
lon1 *= AIS.DE2RA;
|
||||||
|
lat2 *= AIS.DE2RA;
|
||||||
|
lon2 *= AIS.DE2RA;
|
||||||
|
double d = Math.Sin(lat1) * Math.Sin(lat2) + Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(lon1 -lon2);
|
||||||
|
return (AIS.AVG_ERAD * Math.Acos(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region overrides
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Enum.GetName(typeof(AIS.AISType), this.MessageType);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
128
AIS/bsmd.AISService/AIS/AIS_ClassB.cs
Normal file
128
AIS/bsmd.AISService/AIS/AIS_ClassB.cs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Text;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
public class AIS_ClassB : AIS
|
||||||
|
{
|
||||||
|
#region private members
|
||||||
|
|
||||||
|
private int repeatIndicator;
|
||||||
|
private int reserved;
|
||||||
|
private int sog;
|
||||||
|
private int accuracy;
|
||||||
|
private int longitude;
|
||||||
|
private int latitude;
|
||||||
|
private int cog;
|
||||||
|
private int trueHeading;
|
||||||
|
private int utcTimestampSecs;
|
||||||
|
private DateTime timestamp;
|
||||||
|
private int reservedRegional;
|
||||||
|
private int spare;
|
||||||
|
private int assignedModeFlag;
|
||||||
|
private int raimFlag;
|
||||||
|
private int commStateSelectedFlag;
|
||||||
|
private int commState;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public int CogVal { get { return this.cog; } }
|
||||||
|
public int SogVal { get { return this.sog; } }
|
||||||
|
public int LatitudeVal { get { return this.latitude; } }
|
||||||
|
public int LongitudeVal { get { return this.longitude; } }
|
||||||
|
|
||||||
|
public string DBTimestamp
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return string.Format("{0}-{1}-{2} {3}:{4}:{5}",
|
||||||
|
this.timestamp.Year, this.timestamp.Month, this.timestamp.Day,
|
||||||
|
this.timestamp.Hour, this.timestamp.Minute, this.timestamp.Second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public double Cog
|
||||||
|
{
|
||||||
|
get { return this.cog / 10.0f; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Sog
|
||||||
|
{
|
||||||
|
get { return this.sog / 10.0f; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Latitude
|
||||||
|
{
|
||||||
|
get { return this.latitude / 600000.0f; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Longitude
|
||||||
|
{
|
||||||
|
get { return this.longitude / 600000.0f; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime Timestamp
|
||||||
|
{
|
||||||
|
get { return this.timestamp; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? TrueHeading
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.trueHeading == 511) return null;
|
||||||
|
return this.trueHeading;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
protected override AIS.Status Decode()
|
||||||
|
{
|
||||||
|
BitArray bits = AIS.DecodeBinary(this.data);
|
||||||
|
Status result = Status.OK;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int type = AIS.GetInt(bits, 0, 5);
|
||||||
|
if (type != 18)
|
||||||
|
{
|
||||||
|
result = Status.ILLEGAL_ARGUMENT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.repeatIndicator = AIS.GetInt(bits, 6, 7);
|
||||||
|
this.userId = AIS.GetInt(bits, 8, 37);
|
||||||
|
this.reserved = AIS.GetInt(bits, 38, 45);
|
||||||
|
this.sog = AIS.GetInt(bits, 46, 55);
|
||||||
|
this.accuracy = AIS.GetInt(bits, 56, 56);
|
||||||
|
this.longitude = AIS.GetInt(bits, 57, 84);
|
||||||
|
this.latitude = AIS.GetInt(bits, 85, 111);
|
||||||
|
this.cog = AIS.GetInt(bits, 112, 123);
|
||||||
|
this.trueHeading = AIS.GetInt(bits, 124, 132);
|
||||||
|
this.utcTimestampSecs = AIS.GetInt(bits, 133,138);
|
||||||
|
this.timestamp = DateTime.Now;
|
||||||
|
this.reservedRegional = AIS.GetInt(bits, 139, 140);
|
||||||
|
this.spare = AIS.GetInt(bits, 141, 145);
|
||||||
|
this.assignedModeFlag = AIS.GetInt(bits, 146, 146);
|
||||||
|
this.raimFlag = AIS.GetInt(bits, 147, 147);
|
||||||
|
this.commStateSelectedFlag = AIS.GetInt(bits, 148, 148);
|
||||||
|
this.commState = AIS.GetInt(bits, 149, 167);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Trace.WriteLine(string.Format("Error decoding AIS class B posreport: {0}", e.Message));
|
||||||
|
result = Status.PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
130
AIS/bsmd.AISService/AIS/AIS_ClassBExt.cs
Normal file
130
AIS/bsmd.AISService/AIS/AIS_ClassBExt.cs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Text;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Diese Nachricht wird normalerweise von Class B Geräten nicht verschickt.
|
||||||
|
/// Sie wird nur als Antwort auf einen sog. "Base station poll" gesendet.
|
||||||
|
/// Wir lesen sie trotzdem ;)
|
||||||
|
/// </summary>
|
||||||
|
// Todo
|
||||||
|
public class AIS_ClassBExt : AIS
|
||||||
|
{
|
||||||
|
#region private members
|
||||||
|
|
||||||
|
private int repeatIndicator;
|
||||||
|
private int spare1;
|
||||||
|
private int sog;
|
||||||
|
private int accuracy;
|
||||||
|
private int longitude;
|
||||||
|
private int latitude;
|
||||||
|
private int cog;
|
||||||
|
private int trueHeading;
|
||||||
|
private int utcTimestampSecond;
|
||||||
|
private DateTime timestamp;
|
||||||
|
private int spare2;
|
||||||
|
private string name;
|
||||||
|
private int shipType;
|
||||||
|
private int dimension;
|
||||||
|
private int typeofDevice;
|
||||||
|
private int raimFlag;
|
||||||
|
private int dte;
|
||||||
|
private int assignedMode;
|
||||||
|
private int spare3;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return this.name; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime Timestamp
|
||||||
|
{
|
||||||
|
get { return this.timestamp; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Latitude
|
||||||
|
{
|
||||||
|
get { return this.latitude / 600000.0f; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Longitude
|
||||||
|
{
|
||||||
|
get { return this.longitude / 600000.0f; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int TrueHeading
|
||||||
|
{
|
||||||
|
get { return this.trueHeading; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Cog
|
||||||
|
{
|
||||||
|
get { return (double)this.cog / 10.0f; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
protected override AIS.Status Decode()
|
||||||
|
{
|
||||||
|
BitArray bits = AIS.DecodeBinary(this.data);
|
||||||
|
Status result = Status.OK;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int type = AIS.GetInt(bits, 0, 5);
|
||||||
|
if (type != 19)
|
||||||
|
{
|
||||||
|
result = Status.ILLEGAL_ARGUMENT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.repeatIndicator = AIS.GetInt(bits, 6, 7);
|
||||||
|
this.userId = AIS.GetInt(bits, 8, 37);
|
||||||
|
this.spare1 = AIS.GetInt(bits, 38, 45);
|
||||||
|
this.sog = AIS.GetInt(bits, 46, 55);
|
||||||
|
this.accuracy = AIS.GetInt(bits, 56, 56);
|
||||||
|
this.longitude = AIS.GetInt(bits, 57, 84);
|
||||||
|
this.latitude = AIS.GetInt(bits, 85, 111);
|
||||||
|
this.cog = AIS.GetInt(bits, 112, 123);
|
||||||
|
this.trueHeading = AIS.GetInt(bits, 124, 132);
|
||||||
|
this.utcTimestampSecond = AIS.GetInt(bits, 133, 138);
|
||||||
|
this.timestamp = DateTime.Now;
|
||||||
|
this.spare2 = AIS.GetInt(bits, 139, 142);
|
||||||
|
|
||||||
|
StringBuilder sb_name = new StringBuilder(20);
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
int cval = AIS.GetInt(bits, 143 + (6 * i), 148 + (6 * i));
|
||||||
|
char ch = AIS.GetAISChar(cval);
|
||||||
|
if (ch == '@') ch = ' ';
|
||||||
|
sb_name.Append(ch);
|
||||||
|
}
|
||||||
|
this.name = sb_name.ToString().Trim();
|
||||||
|
|
||||||
|
this.shipType = AIS.GetInt(bits, 263, 270);
|
||||||
|
this.dimension = AIS.GetInt(bits, 271, 300);
|
||||||
|
this.typeofDevice = AIS.GetInt(bits, 301, 304);
|
||||||
|
this.raimFlag = AIS.GetInt(bits, 305, 305);
|
||||||
|
this.dte = AIS.GetInt(bits, 306, 306);
|
||||||
|
this.assignedMode = AIS.GetInt(bits, 307, 307);
|
||||||
|
this.spare3 = AIS.GetInt(bits, 308, 311);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Trace.WriteLine(string.Format("Error decoding AIS class B Ext posreport: {0}", e.Message));
|
||||||
|
result = Status.PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
130
AIS/bsmd.AISService/AIS/AIS_ClassBStatic.cs
Normal file
130
AIS/bsmd.AISService/AIS/AIS_ClassBStatic.cs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Text;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
public class AIS_ClassBStatic : AIS
|
||||||
|
{
|
||||||
|
#region private members
|
||||||
|
|
||||||
|
private int repeatIndicator;
|
||||||
|
private int partNumber;
|
||||||
|
private string name;
|
||||||
|
private int shipType;
|
||||||
|
private string vendorId;
|
||||||
|
private string callsign;
|
||||||
|
private int dimension;
|
||||||
|
private int spare;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public bool IsPartA
|
||||||
|
{
|
||||||
|
get { return this.partNumber == 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPartB
|
||||||
|
{
|
||||||
|
get { return this.partNumber == 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return this.name; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ShipType
|
||||||
|
{
|
||||||
|
get { return AIS_StaticData.GetShipType(this.shipType); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string VendorId
|
||||||
|
{
|
||||||
|
get { return this.vendorId; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Callsign
|
||||||
|
{
|
||||||
|
get { return this.callsign; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ShipTypeVal
|
||||||
|
{
|
||||||
|
get { return this.shipType; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Todo: Dimensions..
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
protected override AIS.Status Decode()
|
||||||
|
{
|
||||||
|
BitArray bits = AIS.DecodeBinary(this.data);
|
||||||
|
Status result = Status.OK;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int type = AIS.GetInt(bits, 0, 5);
|
||||||
|
if (type != 24)
|
||||||
|
{
|
||||||
|
result = Status.ILLEGAL_ARGUMENT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.repeatIndicator = AIS.GetInt(bits, 6, 7);
|
||||||
|
this.userId = AIS.GetInt(bits, 8, 37);
|
||||||
|
this.partNumber = AIS.GetInt(bits, 38, 39);
|
||||||
|
if (this.IsPartA)
|
||||||
|
{
|
||||||
|
StringBuilder sb_name = new StringBuilder(20);
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
int cval = AIS.GetInt(bits, 40 + (6 * i), 45 + (6 * i));
|
||||||
|
char ch = AIS.GetAISChar(cval);
|
||||||
|
if (ch == '@') ch = ' ';
|
||||||
|
sb_name.Append(ch);
|
||||||
|
}
|
||||||
|
this.name = sb_name.ToString().Trim();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.shipType = AIS.GetInt(bits, 40, 47);
|
||||||
|
|
||||||
|
StringBuilder sb_vendor = new StringBuilder(7);
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
int cval = AIS.GetInt(bits, 48 + (6 * i), 53 + (6 * i));
|
||||||
|
char ch = AIS.GetAISChar(cval);
|
||||||
|
if (ch == '@') ch = ' ';
|
||||||
|
sb_vendor.Append(ch);
|
||||||
|
}
|
||||||
|
this.vendorId = sb_vendor.ToString().Trim();
|
||||||
|
|
||||||
|
StringBuilder sb_callsign = new StringBuilder(7);
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
int cval = AIS.GetInt(bits, 90 + (6 * i), 95 + (6 * i));
|
||||||
|
char ch = AIS.GetAISChar(cval);
|
||||||
|
if (ch == '@') ch = ' ';
|
||||||
|
sb_callsign.Append(ch);
|
||||||
|
}
|
||||||
|
this.callsign = sb_callsign.ToString().Trim();
|
||||||
|
this.dimension = AIS.GetInt(bits, 141, 161);
|
||||||
|
this.spare = AIS.GetInt(bits, 162, 167);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Trace.WriteLine(string.Format("Error decoding AIS class B static data: {0}", e.Message));
|
||||||
|
result = Status.PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
162
AIS/bsmd.AISService/AIS/AIS_Configuration.cs
Normal file
162
AIS/bsmd.AISService/AIS/AIS_Configuration.cs
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class AIS_Configuration
|
||||||
|
{
|
||||||
|
private string filename;
|
||||||
|
private string dbConnectionString;
|
||||||
|
private int dbUpdateInterval = 500; // milliseconds
|
||||||
|
private int dbMinPosReportTimeDifference = 120; // seconds
|
||||||
|
private int stationIsOfflineTimeDifferenceSecs = 180; // seconds
|
||||||
|
private int targetStaleMins = 31; // minutes
|
||||||
|
|
||||||
|
public List<SerialPort> SerialPorts = new List<SerialPort>();
|
||||||
|
public List<TelnetConnection> TelnetConnections = new List<TelnetConnection>();
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public string Configuration_Path
|
||||||
|
{
|
||||||
|
get { return this.filename; }
|
||||||
|
set { this.filename = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DBConnectionString
|
||||||
|
{
|
||||||
|
get { return this.dbConnectionString; }
|
||||||
|
set { this.dbConnectionString = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// timer interval for database updates
|
||||||
|
/// </summary>
|
||||||
|
public int DBUpdateInterval
|
||||||
|
{
|
||||||
|
get { return this.dbUpdateInterval; }
|
||||||
|
set { this.dbUpdateInterval = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// minimum amount of minutes between two position reports to be
|
||||||
|
/// written to database
|
||||||
|
/// </summary>
|
||||||
|
public int DBMinPosReportTimeDifference
|
||||||
|
{
|
||||||
|
get { return this.dbMinPosReportTimeDifference; }
|
||||||
|
set { this.dbMinPosReportTimeDifference = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// number of seconds after which a station is marked offline since
|
||||||
|
/// sending the last pos report
|
||||||
|
/// </summary>
|
||||||
|
public int StationIsOfflineTimeDifferenceSecs
|
||||||
|
{
|
||||||
|
get { return this.stationIsOfflineTimeDifferenceSecs; }
|
||||||
|
set { this.stationIsOfflineTimeDifferenceSecs = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// if last update is older than this value then the target ist removed from
|
||||||
|
/// the current target queue (target went offline or out of range)
|
||||||
|
/// </summary>
|
||||||
|
public int TargetStaleMins
|
||||||
|
{
|
||||||
|
get { return this.targetStaleMins; }
|
||||||
|
set { this.targetStaleMins = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Root path to where Viewer stores OSM tiles
|
||||||
|
/// </summary>
|
||||||
|
public string TilePath { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// full path to logfile
|
||||||
|
/// </summary>
|
||||||
|
public string LogfilePath { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// outputs assembly version
|
||||||
|
/// </summary>
|
||||||
|
public static string VersionInfo
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
Version version = Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
|
return version.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Load/Save
|
||||||
|
|
||||||
|
public static AIS_Configuration Load(string filename)
|
||||||
|
{
|
||||||
|
if (!File.Exists(filename)) return null;
|
||||||
|
|
||||||
|
// Create an instance of the XmlSerializer specifying type and namespace.
|
||||||
|
XmlSerializer serializer = new XmlSerializer(typeof(AIS_Configuration));
|
||||||
|
|
||||||
|
// A FileStream is needed to read the XML document.
|
||||||
|
FileStream fs = new FileStream(filename, FileMode.Open);
|
||||||
|
XmlReader reader = new XmlTextReader(fs);
|
||||||
|
|
||||||
|
AIS_Configuration configuration = serializer.Deserialize(reader) as AIS_Configuration;
|
||||||
|
reader.Close();
|
||||||
|
configuration.filename = filename;
|
||||||
|
|
||||||
|
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Save()
|
||||||
|
{
|
||||||
|
bool retval = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
XmlSerializer serializer = new XmlSerializer(typeof(AIS_Configuration));
|
||||||
|
Stream fs = new FileStream(this.filename, FileMode.Create);
|
||||||
|
XmlWriter writer = new XmlTextWriter(fs, new UTF8Encoding());
|
||||||
|
serializer.Serialize(writer, this);
|
||||||
|
writer.Close();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.Write("Error during Serialize: " + e.ToString());
|
||||||
|
retval = false;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region internal classes
|
||||||
|
|
||||||
|
public class SerialPort
|
||||||
|
{
|
||||||
|
public string station;
|
||||||
|
public string ComPort;
|
||||||
|
public int BaudRate = 9600;
|
||||||
|
public bool enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TelnetConnection
|
||||||
|
{
|
||||||
|
public string ipAddress;
|
||||||
|
public int port;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
194
AIS/bsmd.AISService/AIS/AIS_Decoder.cs
Normal file
194
AIS/bsmd.AISService/AIS/AIS_Decoder.cs
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
187
AIS/bsmd.AISService/AIS/AIS_PosReport.cs
Normal file
187
AIS/bsmd.AISService/AIS/AIS_PosReport.cs
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
public class AIS_PosReport : AIS
|
||||||
|
{
|
||||||
|
private int navstatus;
|
||||||
|
private int rot;
|
||||||
|
private int sog;
|
||||||
|
private int accur;
|
||||||
|
private int longitude;
|
||||||
|
private int latitude;
|
||||||
|
private int cog;
|
||||||
|
private int trueheading;
|
||||||
|
private DateTime timestamp;
|
||||||
|
private int utcTimeSecond;
|
||||||
|
private int reserved;
|
||||||
|
private int spare;
|
||||||
|
private int raim;
|
||||||
|
private int commstate;
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public int NavStatusVal { get { return this.navstatus; } }
|
||||||
|
public int ROTVal { get { return this.rot; } }
|
||||||
|
public int SOGVal { get { return this.sog; } }
|
||||||
|
public int COGVal { get { return this.cog; } }
|
||||||
|
public int Accuracy { get { return this.accur; } }
|
||||||
|
public int LatitudeVal { get { return this.latitude; } }
|
||||||
|
public int LongitudeVal { get { return this.longitude; } }
|
||||||
|
public string DBTimestamp
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return string.Format("{0}-{1}-{2} {3}:{4}:{5}",
|
||||||
|
this.timestamp.Year, this.timestamp.Month, this.timestamp.Day,
|
||||||
|
this.timestamp.Hour, this.timestamp.Minute, this.timestamp.Second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double SOG
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ((double)this.sog) / 10.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double COG
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ((double)this.cog) / 10.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ROT
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (int)((double)(this.rot * this.rot) / 22.401289);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Latitude
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ((double)this.latitude) / 600000.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Longitude
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ((double)this.longitude) / 600000.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public string NavStatus
|
||||||
|
{
|
||||||
|
get { return GetNavStatus(this.navstatus); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime Timestamp
|
||||||
|
{
|
||||||
|
get { return this.timestamp; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? TrueHeading
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.trueheading == 511) return null;
|
||||||
|
return this.trueheading;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region static methods
|
||||||
|
|
||||||
|
public static string GetNavStatus(int navstatus)
|
||||||
|
{
|
||||||
|
switch (navstatus)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return "under way using engine";
|
||||||
|
case 1:
|
||||||
|
return "at anchor";
|
||||||
|
case 2:
|
||||||
|
return "not under command";
|
||||||
|
case 3:
|
||||||
|
return "restricted manoeuvrability";
|
||||||
|
case 4:
|
||||||
|
return "contrained by her draught";
|
||||||
|
case 5:
|
||||||
|
return "moored";
|
||||||
|
case 6:
|
||||||
|
return "aground";
|
||||||
|
case 7:
|
||||||
|
return "engaged in fishing";
|
||||||
|
case 8:
|
||||||
|
return "under way sailing";
|
||||||
|
case 9:
|
||||||
|
return "reserved for future amendment of Navigational Status for HSC";
|
||||||
|
case 10:
|
||||||
|
return "reserved for future amendment of Navigational Status for WIG";
|
||||||
|
case 11:
|
||||||
|
case 12:
|
||||||
|
case 13:
|
||||||
|
case 14:
|
||||||
|
return "reserved for future use";
|
||||||
|
default:
|
||||||
|
return "not defined";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region overrides
|
||||||
|
|
||||||
|
protected override Status Decode()
|
||||||
|
{
|
||||||
|
Status result = Status.OK;
|
||||||
|
BitArray bits = AIS.DecodeBinary(this.data);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.userId = AIS.GetInt(bits, 8, 37);
|
||||||
|
this.navstatus = AIS.GetInt(bits, 38, 41);
|
||||||
|
this.rot = AIS.GetInt(bits, 42, 49);
|
||||||
|
this.sog = AIS.GetInt(bits, 50, 59);
|
||||||
|
this.accur = AIS.GetInt(bits, 60, 60);
|
||||||
|
this.longitude = AIS.GetInt(bits, 61, 88);
|
||||||
|
this.latitude = AIS.GetInt(bits, 89, 115);
|
||||||
|
this.cog = AIS.GetInt(bits, 116, 127);
|
||||||
|
this.trueheading = AIS.GetInt(bits, 128, 136);
|
||||||
|
this.utcTimeSecond = AIS.GetInt(bits, 137, 142);
|
||||||
|
this.reserved = AIS.GetInt(bits, 143, 146);
|
||||||
|
this.spare = AIS.GetInt(bits, 147, 147);
|
||||||
|
this.raim = AIS.GetInt(bits, 148, 148);
|
||||||
|
this.commstate = AIS.GetInt(bits, 149, 167);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Trace.WriteLine(string.Format("Error decoding AIS pos report: {0}", e.Message));
|
||||||
|
result = Status.PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.timestamp = DateTime.Now;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("{0} - MMSI {1}", base.ToString(), this.MMSI);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
218
AIS/bsmd.AISService/AIS/AIS_QueueManager.cs
Normal file
218
AIS/bsmd.AISService/AIS/AIS_QueueManager.cs
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Timers;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Hier laufen die Fäden zusammen. Diese Klasse enthält alle Objekte und kann direkt von
|
||||||
|
/// Konsolen / services und Windowsprogrammen verwendet werden
|
||||||
|
/// </summary>
|
||||||
|
public class AIS_QueueManager
|
||||||
|
{
|
||||||
|
|
||||||
|
public delegate void AISQueueChangedHandler(AIS_Target target);
|
||||||
|
public event AISQueueChangedHandler AISQueueChanged;
|
||||||
|
public event AISQueueChangedHandler DBUpdateRequired;
|
||||||
|
|
||||||
|
private Dictionary<int, AIS_Target> activeTargets = new Dictionary<int, AIS_Target>();
|
||||||
|
private List<AIS_Target> activeTargetList = new List<AIS_Target>();
|
||||||
|
private List<AIS_Target> databaseTargets = new List<AIS_Target>();
|
||||||
|
private List<AIS_Target> watchkeeperTargets = new List<AIS_Target>();
|
||||||
|
private AIS_Configuration configuration;
|
||||||
|
private List<SerialDataHandler> serialHandlerList = new List<SerialDataHandler>();
|
||||||
|
private List<TelnetDataHandler> telnetHandlerList = new List<TelnetDataHandler>();
|
||||||
|
private List<AIS_Target> dbUpdateQueue = new List<AIS_Target>();
|
||||||
|
private Timer dbUpdateTimer = new Timer();
|
||||||
|
private bool isStarted = false;
|
||||||
|
|
||||||
|
#region Construction
|
||||||
|
|
||||||
|
public AIS_QueueManager(AIS_Configuration configuration, List<Serial_IO> serialIOs, List<AIS_Telnet> ais_Telnets)
|
||||||
|
{
|
||||||
|
this.configuration = configuration;
|
||||||
|
|
||||||
|
foreach (Serial_IO serialIO in serialIOs)
|
||||||
|
{
|
||||||
|
AIS_Decoder decoder = new AIS_Decoder();
|
||||||
|
decoder.AISMessageReceived += new AIS_Decoder.AISMessageHandler(this.decoder_AISMessageReceived);
|
||||||
|
SerialDataHandler handler = new SerialDataHandler(serialIO, decoder);
|
||||||
|
this.serialHandlerList.Add(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (AIS_Telnet aisTelnet in ais_Telnets)
|
||||||
|
{
|
||||||
|
AIS_Decoder decoder = new AIS_Decoder();
|
||||||
|
decoder.AISMessageReceived += new AIS_Decoder.AISMessageHandler(this.decoder_AISMessageReceived);
|
||||||
|
TelnetDataHandler tdn = new TelnetDataHandler(aisTelnet, decoder);
|
||||||
|
this.telnetHandlerList.Add(tdn);
|
||||||
|
}
|
||||||
|
|
||||||
|
AIS_Target.dbUpdateInterval = new TimeSpan(0, 0, configuration.DBMinPosReportTimeDifference);
|
||||||
|
this.dbUpdateTimer.Interval = configuration.DBUpdateInterval;
|
||||||
|
this.dbUpdateTimer.Elapsed += new ElapsedEventHandler(dbUpdateTimer_Elapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public List<AIS_Target> ActiveTargets
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.activeTargetList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsStarted
|
||||||
|
{
|
||||||
|
get { return this.isStarted; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region event handler
|
||||||
|
|
||||||
|
void dbUpdateTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
while (this.dbUpdateQueue.Count > 0)
|
||||||
|
{
|
||||||
|
AIS_Target currentTarget = null;
|
||||||
|
lock (this.dbUpdateQueue)
|
||||||
|
{
|
||||||
|
// Trace.WriteLine(string.Format("Update queue size: {0}", this.dbUpdateQueue.Count));
|
||||||
|
currentTarget = this.dbUpdateQueue[0];
|
||||||
|
this.dbUpdateQueue.RemoveAt(0);
|
||||||
|
}
|
||||||
|
this.OnDBUpdateRequired(currentTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove stale targets
|
||||||
|
lock (this.activeTargetList)
|
||||||
|
{
|
||||||
|
|
||||||
|
for(int i=0;i<this.activeTargetList.Count; i++)
|
||||||
|
{
|
||||||
|
if (!this.activeTargetList[i].LastUpdate.HasValue)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int diffmin = (int) (DateTime.Now - this.activeTargetList[i].LastUpdate.Value).TotalMinutes;
|
||||||
|
|
||||||
|
if (diffmin > this.configuration.TargetStaleMins)
|
||||||
|
{
|
||||||
|
this.activeTargetList.RemoveAt(i);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void decoder_AISMessageReceived(AIS message)
|
||||||
|
{
|
||||||
|
lock (this.activeTargets)
|
||||||
|
{
|
||||||
|
// Trace.WriteLine(string.Format("Queue manager: AIS message received, queue size: {0}", activeTargets.Count));
|
||||||
|
if (!this.activeTargets.ContainsKey(message.MMSI))
|
||||||
|
{
|
||||||
|
AIS_Target target = new AIS_Target(message.MMSI);
|
||||||
|
this.activeTargets.Add(message.MMSI, target);
|
||||||
|
lock (this.activeTargetList)
|
||||||
|
{
|
||||||
|
this.activeTargetList.Add(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.activeTargets[message.MMSI].Update(message);
|
||||||
|
this.OnAISQueueChanged(this.activeTargets[message.MMSI]);
|
||||||
|
|
||||||
|
if (this.activeTargets[message.MMSI].UpdateDB)
|
||||||
|
{
|
||||||
|
lock (this.dbUpdateQueue)
|
||||||
|
{
|
||||||
|
if (!this.dbUpdateQueue.Contains(this.activeTargets[message.MMSI]))
|
||||||
|
this.dbUpdateQueue.Add(this.activeTargets[message.MMSI]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public methods
|
||||||
|
|
||||||
|
public bool Start(ref string message)
|
||||||
|
{
|
||||||
|
bool retval = true;
|
||||||
|
if (this.isStarted)
|
||||||
|
{
|
||||||
|
message = "Queue manager already started";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (SerialDataHandler sdh in this.serialHandlerList)
|
||||||
|
{
|
||||||
|
string messagePart = "";
|
||||||
|
retval &= sdh.Start(ref messagePart);
|
||||||
|
if (!retval)
|
||||||
|
message += messagePart + Environment.NewLine;
|
||||||
|
if(retval) sdh.AIS_Decoder.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (TelnetDataHandler tdh in this.telnetHandlerList)
|
||||||
|
{
|
||||||
|
string messagePart = "";
|
||||||
|
retval &= tdh.Start(ref messagePart);
|
||||||
|
if (!retval)
|
||||||
|
message += messagePart + Environment.NewLine;
|
||||||
|
if (retval) tdh.AIS_Decoder.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval)
|
||||||
|
this.dbUpdateTimer.Start();
|
||||||
|
|
||||||
|
if (retval) this.isStarted = true;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
if (this.isStarted)
|
||||||
|
{
|
||||||
|
foreach (SerialDataHandler sdh in this.serialHandlerList)
|
||||||
|
{
|
||||||
|
sdh.Stop();
|
||||||
|
sdh.AIS_Decoder.Stop();
|
||||||
|
}
|
||||||
|
foreach (TelnetDataHandler tdh in this.telnetHandlerList)
|
||||||
|
{
|
||||||
|
tdh.Stop();
|
||||||
|
tdh.AIS_Decoder.Stop();
|
||||||
|
}
|
||||||
|
this.dbUpdateTimer.Stop();
|
||||||
|
this.isStarted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region OnEvent methods
|
||||||
|
|
||||||
|
protected void OnAISQueueChanged(AIS_Target target)
|
||||||
|
{
|
||||||
|
if (this.AISQueueChanged != null) this.AISQueueChanged(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void OnDBUpdateRequired(AIS_Target target)
|
||||||
|
{
|
||||||
|
if (this.DBUpdateRequired != null) this.DBUpdateRequired(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
381
AIS/bsmd.AISService/AIS/AIS_StaticData.cs
Normal file
381
AIS/bsmd.AISService/AIS/AIS_StaticData.cs
Normal file
@ -0,0 +1,381 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
public class AIS_StaticData : AIS
|
||||||
|
{
|
||||||
|
#region private members
|
||||||
|
|
||||||
|
private int ais_version;
|
||||||
|
private int imoNumber;
|
||||||
|
private string callsign;
|
||||||
|
private string name;
|
||||||
|
private int shiptype;
|
||||||
|
private int dimension;
|
||||||
|
private int a;
|
||||||
|
private int b;
|
||||||
|
private int c;
|
||||||
|
private int d;
|
||||||
|
|
||||||
|
private int typeofdevice;
|
||||||
|
private int etamonth;
|
||||||
|
private int etaday;
|
||||||
|
private int etahour;
|
||||||
|
private int etaminute;
|
||||||
|
private DateTime? eta;
|
||||||
|
|
||||||
|
private int maxpresetstaticdraught;
|
||||||
|
private string destination;
|
||||||
|
private int dte;
|
||||||
|
private int spare;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public int ShipTypeVal { get { return this.shiptype; } }
|
||||||
|
|
||||||
|
public string Callsign
|
||||||
|
{
|
||||||
|
get { return this.callsign; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return this.name; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime? ETA
|
||||||
|
{
|
||||||
|
get { return this.eta; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Destination
|
||||||
|
{
|
||||||
|
get { return this.destination; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IMONumber
|
||||||
|
{
|
||||||
|
get { return this.imoNumber; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DeviceName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (typeofdevice)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
return "GPS";
|
||||||
|
case 2:
|
||||||
|
return "GLONASS";
|
||||||
|
case 3:
|
||||||
|
return "Combined GPS/GLONASS";
|
||||||
|
case 4:
|
||||||
|
return "Loran-C";
|
||||||
|
case 5:
|
||||||
|
return "Chayka";
|
||||||
|
case 6:
|
||||||
|
return "Integrated Navigation System";
|
||||||
|
case 7:
|
||||||
|
return "surveyed";
|
||||||
|
case 8:
|
||||||
|
return "Galileo";
|
||||||
|
default:
|
||||||
|
return "undefined";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Draught
|
||||||
|
{
|
||||||
|
get { return this.maxpresetstaticdraught; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Breadth
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.c + this.d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Length
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.a + this.b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ShipType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return AIS_StaticData.GetShipType(this.shiptype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DBETA
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.eta.HasValue)
|
||||||
|
{
|
||||||
|
return string.Format("{0}-{1}-{2} {3}:{4}:{5}",
|
||||||
|
this.eta.Value.Year, this.eta.Value.Month, this.eta.Value.Day,
|
||||||
|
this.eta.Value.Hour, this.eta.Value.Minute, this.eta.Value.Second);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region abstract method implementation
|
||||||
|
|
||||||
|
protected override Status Decode()
|
||||||
|
{
|
||||||
|
BitArray bits = AIS.DecodeBinary(this.data);
|
||||||
|
Status result = Status.OK;
|
||||||
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int type = AIS.GetInt(bits, 0, 5);
|
||||||
|
if (type != 5)
|
||||||
|
{
|
||||||
|
result = Status.ILLEGAL_ARGUMENT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.userId = AIS.GetInt(bits, 6, 37);
|
||||||
|
this.ais_version = AIS.GetInt(bits, 38, 39);
|
||||||
|
this.imoNumber = AIS.GetInt(bits, 40, 69);
|
||||||
|
|
||||||
|
StringBuilder sb_callsign = new StringBuilder(7);
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
int cval = AIS.GetInt(bits, 70 + (6 * i), 75 + (6 * i));
|
||||||
|
char ch = AIS.GetAISChar(cval);
|
||||||
|
if (ch == '@') ch = ' ';
|
||||||
|
sb_callsign.Append(ch);
|
||||||
|
}
|
||||||
|
this.callsign = sb_callsign.ToString().Trim();
|
||||||
|
|
||||||
|
StringBuilder sb_name = new StringBuilder(20);
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
int cval = AIS.GetInt(bits, 112 + (6 * i), 117 + (6 * i));
|
||||||
|
char ch = AIS.GetAISChar(cval);
|
||||||
|
if (ch == '@') ch = ' ';
|
||||||
|
sb_name.Append(ch);
|
||||||
|
}
|
||||||
|
this.name = sb_name.ToString().Trim();
|
||||||
|
|
||||||
|
this.shiptype = AIS.GetInt(bits, 232, 239);
|
||||||
|
this.dimension = AIS.GetInt(bits, 240, 269);
|
||||||
|
this.a = AIS.GetInt(bits, 240, 248);
|
||||||
|
this.b = AIS.GetInt(bits, 249, 257);
|
||||||
|
this.c = AIS.GetInt(bits, 258, 263);
|
||||||
|
this.d = AIS.GetInt(bits, 264, 269);
|
||||||
|
this.typeofdevice = AIS.GetInt(bits, 270, 273);
|
||||||
|
this.etamonth = AIS.GetInt(bits, 274, 277);
|
||||||
|
this.etaday = AIS.GetInt(bits, 278, 282);
|
||||||
|
this.etahour = AIS.GetInt(bits, 283, 287);
|
||||||
|
this.etaminute = AIS.GetInt(bits, 288, 293);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if ((this.etahour < 24) && (this.etaday > 0) && (this.etaminute < 60) && (this.etamonth > 0))
|
||||||
|
{
|
||||||
|
this.eta = new DateTime(DateTime.Now.Year, this.etamonth, this.etaday, this.etahour, this.etaminute, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception) {
|
||||||
|
Trace.WriteLine("ERROR creating ETA timestamp");
|
||||||
|
}
|
||||||
|
this.maxpresetstaticdraught = AIS.GetInt(bits, 294, 301);
|
||||||
|
|
||||||
|
StringBuilder sb_destination = new StringBuilder(20);
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
int cval = AIS.GetInt(bits, 302 + (6 * i), 307 + (6 * i));
|
||||||
|
char ch = AIS.GetAISChar(cval);
|
||||||
|
if (ch == '@') ch = ' ';
|
||||||
|
sb_destination.Append(ch);
|
||||||
|
}
|
||||||
|
this.destination = sb_destination.ToString().Trim();
|
||||||
|
|
||||||
|
this.dte = AIS.GetInt(bits, 422, 422);
|
||||||
|
this.spare = AIS.GetInt(bits, 423, 423);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Trace.WriteLine(string.Format("Error decoding AIS static data: {0}", e.Message));
|
||||||
|
result = Status.PARSE_ERROR;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("{0} - {1} [{2}]", base.ToString(), this.MMSI, this.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public static methods
|
||||||
|
|
||||||
|
public static AIS_Target.Type GetShipTypeSimple(int shiptype)
|
||||||
|
{
|
||||||
|
switch (shiptype)
|
||||||
|
{
|
||||||
|
case 50:
|
||||||
|
case 51:
|
||||||
|
case 52:
|
||||||
|
case 53:
|
||||||
|
case 54:
|
||||||
|
case 55:
|
||||||
|
case 56:
|
||||||
|
case 57:
|
||||||
|
return AIS_Target.Type.TUG;
|
||||||
|
default:
|
||||||
|
int d1 = shiptype / 10;
|
||||||
|
switch (d1)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
return AIS_Target.Type.WIG;
|
||||||
|
case 3:
|
||||||
|
return AIS_Target.Type.OTHER;
|
||||||
|
case 4:
|
||||||
|
return AIS_Target.Type.HSC;
|
||||||
|
case 6:
|
||||||
|
return AIS_Target.Type.PASSENGER;
|
||||||
|
case 7:
|
||||||
|
return AIS_Target.Type.CARGO;
|
||||||
|
case 8:
|
||||||
|
return AIS_Target.Type.TANKER;
|
||||||
|
}
|
||||||
|
return AIS_Target.Type.OTHER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
327
AIS/bsmd.AISService/AIS/AIS_Target.cs
Normal file
327
AIS/bsmd.AISService/AIS/AIS_Target.cs
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
public class AIS_Target
|
||||||
|
{
|
||||||
|
|
||||||
|
#region private members
|
||||||
|
|
||||||
|
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 AIS staticInfo;
|
||||||
|
private AIS posReport;
|
||||||
|
private AIS lastAdditionalData;
|
||||||
|
|
||||||
|
private AIS_Target.Type type = Type.OTHER;
|
||||||
|
private AIS_Target.NavStatus navStatus = AIS_Target.NavStatus.UNKNOWN;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public defs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public enum Type
|
||||||
|
{
|
||||||
|
PASSENGER,
|
||||||
|
CARGO,
|
||||||
|
TANKER,
|
||||||
|
HSC,
|
||||||
|
WIG,
|
||||||
|
TUG,
|
||||||
|
YACHT,
|
||||||
|
OTHER
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// vereinfacht
|
||||||
|
/// </summary>
|
||||||
|
public enum NavStatus
|
||||||
|
{
|
||||||
|
UNKNOWN,
|
||||||
|
UNDERWAY,
|
||||||
|
MOORED
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Construction
|
||||||
|
|
||||||
|
public AIS_Target(int mmsi)
|
||||||
|
{
|
||||||
|
this.mmsi = mmsi;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public bool UpdateDB
|
||||||
|
{
|
||||||
|
get { return this.updateDB; }
|
||||||
|
set { this.updateDB = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int MMSI
|
||||||
|
{
|
||||||
|
get { return this.mmsi; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime? LastUpdate
|
||||||
|
{
|
||||||
|
get { return this.lastUpdate; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get {
|
||||||
|
if ((this.name == null) || (this.name.Length == 0))
|
||||||
|
return this.LastDBName;
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public AIS LastPosReport
|
||||||
|
{
|
||||||
|
get { return this.posReport; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public AIS LastStaticData
|
||||||
|
{
|
||||||
|
get { return this.staticInfo; }
|
||||||
|
}
|
||||||
|
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool? IsClassB
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.isClassB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool? IsWatchkeeperShip
|
||||||
|
{
|
||||||
|
get { return this.isWatchkeeper; }
|
||||||
|
set { this.isWatchkeeper = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Selected
|
||||||
|
{
|
||||||
|
get { return this.selected; }
|
||||||
|
set { this.selected = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Station
|
||||||
|
{
|
||||||
|
get { return this.station; }
|
||||||
|
set { this.station = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public methods
|
||||||
|
|
||||||
|
public static AIS_Target.NavStatus GetCurrentNavstatus(int status)
|
||||||
|
{
|
||||||
|
AIS_Target.NavStatus result = NavStatus.UNKNOWN;
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 8:
|
||||||
|
result = NavStatus.UNDERWAY;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = NavStatus.MOORED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(AIS message)
|
||||||
|
{
|
||||||
|
this.station = message.Station;
|
||||||
|
|
||||||
|
switch (message.MessageType)
|
||||||
|
{
|
||||||
|
case AIS.AISType.POSITION_REPORT:
|
||||||
|
case AIS.AISType.POSITION_REPORT_ASSIGNED:
|
||||||
|
case AIS.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 AIS.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 AIS.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 AIS.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 AIS.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region overrides
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("{0} [{1}]", this.Name, this.MMSI);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
104
AIS/bsmd.AISService/AIS/AIS_Target_Comparer.cs
Normal file
104
AIS/bsmd.AISService/AIS/AIS_Target_Comparer.cs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
public class AIS_Target_Comparer : IComparer<AIS_Target>
|
||||||
|
{
|
||||||
|
private SortPropertyEnum sortProperty = SortPropertyEnum.NAME;
|
||||||
|
private ListSortDirection sortDirection = ListSortDirection.Ascending;
|
||||||
|
|
||||||
|
public enum SortPropertyEnum
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
MMSI,
|
||||||
|
NAME,
|
||||||
|
CALLSIGN,
|
||||||
|
LASTUPDATE,
|
||||||
|
STATION
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public ListSortDirection SortDirection
|
||||||
|
{
|
||||||
|
get { return this.sortDirection; }
|
||||||
|
set { this.sortDirection = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public SortPropertyEnum SortProperty
|
||||||
|
{
|
||||||
|
get { return this.sortProperty; }
|
||||||
|
set { this.sortProperty = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IComparer<AIS_Target> Members
|
||||||
|
|
||||||
|
public int Compare(AIS_Target x, AIS_Target y)
|
||||||
|
{
|
||||||
|
switch (this.sortProperty)
|
||||||
|
{
|
||||||
|
case SortPropertyEnum.NONE:
|
||||||
|
return 0;
|
||||||
|
case SortPropertyEnum.NAME:
|
||||||
|
{
|
||||||
|
string xName = x.LastDBName;
|
||||||
|
if (xName == null) xName = "";
|
||||||
|
string yName = y.LastDBName;
|
||||||
|
if (yName == null) yName = "";
|
||||||
|
if (this.sortDirection == ListSortDirection.Ascending)
|
||||||
|
return xName.CompareTo(yName);
|
||||||
|
else
|
||||||
|
return yName.CompareTo(xName);
|
||||||
|
}
|
||||||
|
case SortPropertyEnum.CALLSIGN:
|
||||||
|
{
|
||||||
|
string xCallsign = x.Callsign;
|
||||||
|
if (xCallsign == null) xCallsign = "";
|
||||||
|
string yCallsign = y.Callsign;
|
||||||
|
if (yCallsign == null) yCallsign = "";
|
||||||
|
if (this.sortDirection == ListSortDirection.Ascending)
|
||||||
|
return xCallsign.CompareTo(yCallsign);
|
||||||
|
else
|
||||||
|
return yCallsign.CompareTo(xCallsign);
|
||||||
|
}
|
||||||
|
case SortPropertyEnum.LASTUPDATE:
|
||||||
|
{
|
||||||
|
DateTime xTime = x.LastUpdate ?? DateTime.MinValue;
|
||||||
|
DateTime yTime = y.LastUpdate ?? DateTime.MinValue;
|
||||||
|
if (this.sortDirection == ListSortDirection.Ascending)
|
||||||
|
return xTime.CompareTo(yTime);
|
||||||
|
else
|
||||||
|
return yTime.CompareTo(xTime);
|
||||||
|
}
|
||||||
|
case SortPropertyEnum.MMSI:
|
||||||
|
{
|
||||||
|
if (this.sortDirection == ListSortDirection.Ascending)
|
||||||
|
return x.MMSI.CompareTo(y.MMSI);
|
||||||
|
else
|
||||||
|
return y.MMSI.CompareTo(x.MMSI);
|
||||||
|
}
|
||||||
|
case SortPropertyEnum.STATION:
|
||||||
|
{
|
||||||
|
if (this.sortDirection == ListSortDirection.Ascending)
|
||||||
|
return x.ReceivedFrom.CompareTo(y.ReceivedFrom);
|
||||||
|
else
|
||||||
|
return y.ReceivedFrom.CompareTo(x.ReceivedFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
150
AIS/bsmd.AISService/AIS/AIS_Telnet.cs
Normal file
150
AIS/bsmd.AISService/AIS/AIS_Telnet.cs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
//
|
||||||
|
// Class: AIS_Telnet
|
||||||
|
// Current CLR: 4.0.30319.296
|
||||||
|
// System: Microsoft Visual Studio 10.0
|
||||||
|
// Author: dani
|
||||||
|
// Created: 3/16/2013 12:58:03 PM
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013 Informatikbüro Daniel Schick. All rights reserved.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
public class AIS_Telnet
|
||||||
|
{
|
||||||
|
|
||||||
|
#region private fields
|
||||||
|
|
||||||
|
private const int BFSIZE = 1024;
|
||||||
|
|
||||||
|
private NetworkStream tcpStream;
|
||||||
|
private TcpClient tcpSocket;
|
||||||
|
private string currentString = "";
|
||||||
|
private string hostname;
|
||||||
|
private int port;
|
||||||
|
private DateTime? lastRead;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public AIS_Telnet(string theHostname, int thePort)
|
||||||
|
{
|
||||||
|
this.port = thePort;
|
||||||
|
this.hostname = theHostname;
|
||||||
|
this.Connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public bool IsConnected
|
||||||
|
{
|
||||||
|
get { return tcpSocket.Connected; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Hostname { get { return this.hostname; } }
|
||||||
|
|
||||||
|
public int Port { get { return this.port; } }
|
||||||
|
|
||||||
|
public string StationName { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public methods
|
||||||
|
|
||||||
|
private string ReadCurrentUptoNewline()
|
||||||
|
{
|
||||||
|
int newlineIndex = currentString.IndexOf('\n');
|
||||||
|
string result = this.currentString.Substring(0, newlineIndex);
|
||||||
|
if (currentString.Length > (newlineIndex + 1))
|
||||||
|
currentString = currentString.Substring(newlineIndex + 1);
|
||||||
|
else
|
||||||
|
currentString = "";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ReadLine()
|
||||||
|
{
|
||||||
|
|
||||||
|
string result = "";
|
||||||
|
if (currentString.IndexOf('\n') >= 0)
|
||||||
|
return ReadCurrentUptoNewline();
|
||||||
|
|
||||||
|
|
||||||
|
byte[] inputBuffer = new byte[1024];
|
||||||
|
|
||||||
|
if ((tcpSocket == null) || (!tcpSocket.Connected) || !this.tcpStream.CanRead)
|
||||||
|
this.Connect();
|
||||||
|
if ((tcpSocket == null) || !tcpSocket.Connected)
|
||||||
|
{
|
||||||
|
System.Threading.Thread.Sleep(30000); // wait 5 mins if connect is unsuccessful
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (this.tcpStream.DataAvailable)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int bytesRead = this.tcpStream.Read(inputBuffer, 0, 1024);
|
||||||
|
if (bytesRead > 0)
|
||||||
|
{
|
||||||
|
this.lastRead = DateTime.Now;
|
||||||
|
this.currentString += Encoding.ASCII.GetString(inputBuffer, 0, bytesRead);
|
||||||
|
if (currentString.IndexOf('\n') >= 0)
|
||||||
|
return ReadCurrentUptoNewline();
|
||||||
|
if (this.currentString.Length > 1024) this.currentString = ""; // truncate to avoid overflow for wrong client data flow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Trace.WriteLine(string.Format("exception reading from tcp stream: {0}", ex.Message));
|
||||||
|
result = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// wenn die Verbindung wegkracht ist immer noch connected true, aber DataAvailable false
|
||||||
|
// es gibt anscheinend keinen richtig guten Workaround. Hard case: Nach einer Stunde Inaktivität schließt der Client hier die
|
||||||
|
// Verbindung und versucht reconnects. Das bekommt der LS100PortProxy aber nicht immer mit.. Folge sind dann die "stehengebliebenen"
|
||||||
|
// Verbindungen
|
||||||
|
if (lastRead == null) lastRead = DateTime.Now;
|
||||||
|
if ((DateTime.Now - lastRead.Value).TotalSeconds > 600)
|
||||||
|
{
|
||||||
|
this.tcpSocket.Close();
|
||||||
|
this.tcpSocket = null;
|
||||||
|
System.Diagnostics.Trace.WriteLine("closing inactive TcpClient");
|
||||||
|
this.lastRead = DateTime.Now; // reset timer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
if (this.tcpStream != null) this.tcpStream.Close();
|
||||||
|
this.tcpSocket.Close();
|
||||||
|
this.tcpStream.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public void Connect()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if ((this.tcpSocket != null) && (this.tcpSocket.Connected)) return;
|
||||||
|
this.tcpSocket = new TcpClient(this.hostname, this.port);
|
||||||
|
this.tcpStream = tcpSocket.GetStream();
|
||||||
|
System.Diagnostics.Trace.WriteLine(string.Format("TCP stream connected ({0}:{1})", this.hostname, this.port));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Trace.WriteLine(
|
||||||
|
string.Format("AIS_Telnet: cannot connect to ({0}:{1}) : {2}", this.hostname, this.port, ex.Message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
116
AIS/bsmd.AISService/AIS/NMEA.cs
Normal file
116
AIS/bsmd.AISService/AIS/NMEA.cs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
internal abstract class NMEA
|
||||||
|
{
|
||||||
|
protected string type = "";
|
||||||
|
protected string data;
|
||||||
|
protected string[] elements = null;
|
||||||
|
|
||||||
|
public enum Status
|
||||||
|
{
|
||||||
|
OK,
|
||||||
|
UNKNOWN_TYPE,
|
||||||
|
CHECKSUM,
|
||||||
|
ILLEGAL_ARGUMENT
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void Decode();
|
||||||
|
|
||||||
|
public static NMEA Decode(string data, ref Status status)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (data == null)
|
||||||
|
{
|
||||||
|
status = Status.ILLEGAL_ARGUMENT;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[0] != '$' && data[0] != '!')
|
||||||
|
{
|
||||||
|
status = Status.ILLEGAL_ARGUMENT;
|
||||||
|
return null; // no NMEA sentence
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] elements = data.Trim().Substring(1).Split(',');
|
||||||
|
|
||||||
|
NMEA sentence = NMEA.CreateNMEAElement(elements[0]);
|
||||||
|
if (sentence == null)
|
||||||
|
{
|
||||||
|
status = Status.UNKNOWN_TYPE;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
sentence.elements = elements;
|
||||||
|
sentence.data = data.Trim(); ;
|
||||||
|
|
||||||
|
if (!sentence.IsChecksumOK)
|
||||||
|
{
|
||||||
|
status = Status.CHECKSUM;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
sentence.Decode();
|
||||||
|
|
||||||
|
return sentence;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Trace.WriteLine(string.Format("Error decoding sentence: {0}, {1}", ex.Message, ex.StackTrace));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Factory method for nmea types
|
||||||
|
/// </summary>
|
||||||
|
protected static NMEA CreateNMEAElement(string type)
|
||||||
|
{
|
||||||
|
NMEA result = null;
|
||||||
|
|
||||||
|
switch (type.ToUpper())
|
||||||
|
{
|
||||||
|
case "AIVDM":
|
||||||
|
result = new NMEA_AIS_Sentence();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "PNMLS":
|
||||||
|
result = new NMEA_PNMLS_Sentence();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
result.type = type.ToUpper();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool IsChecksumOK
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.data.Substring(this.data.IndexOf('*') + 1) == this.CalculateChecksum();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string CalculateChecksum()
|
||||||
|
{
|
||||||
|
int checksum = Convert.ToByte(this.data[1]);
|
||||||
|
for (int i = 2; i < this.data.IndexOf('*'); i++)
|
||||||
|
{
|
||||||
|
checksum ^= Convert.ToByte(this.data[i]);
|
||||||
|
}
|
||||||
|
return checksum.ToString("X2");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
86
AIS/bsmd.AISService/AIS/NMEA_AIS_Sentence.cs
Normal file
86
AIS/bsmd.AISService/AIS/NMEA_AIS_Sentence.cs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
internal class NMEA_AIS_Sentence : NMEA
|
||||||
|
{
|
||||||
|
private int total_sentence_nr;
|
||||||
|
private int msg_sentence_nr;
|
||||||
|
private int? seq_message_ident;
|
||||||
|
private string ais_channel_nr;
|
||||||
|
private string ais_message;
|
||||||
|
private int fillbits;
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 1-based total number of sentences for this ais message
|
||||||
|
/// </summary>
|
||||||
|
public int Total_Sentence_Nr
|
||||||
|
{
|
||||||
|
get { return this.total_sentence_nr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 1-based fragment number of sentences
|
||||||
|
/// </summary>
|
||||||
|
public int Msg_Sentence_Nr
|
||||||
|
{
|
||||||
|
get { return this.msg_sentence_nr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// sequential message id for multi-sentence messages (can be empty)
|
||||||
|
/// </summary>
|
||||||
|
public int? Seq_Message_Ident
|
||||||
|
{
|
||||||
|
get { return this.seq_message_ident; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 'A' = 161.975Mhz (87B),
|
||||||
|
/// 'B' = 162.025Mhz (88B)
|
||||||
|
/// </summary>
|
||||||
|
public string AIS_Channel_nr
|
||||||
|
{
|
||||||
|
get { return this.ais_channel_nr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// AIS message data
|
||||||
|
/// </summary>
|
||||||
|
public string AIS_Message
|
||||||
|
{
|
||||||
|
get { return this.ais_message; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int FillBits
|
||||||
|
{
|
||||||
|
get { return this.fillbits; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
protected override void Decode()
|
||||||
|
{
|
||||||
|
this.total_sentence_nr = Convert.ToInt32(this.elements[1]);
|
||||||
|
this.msg_sentence_nr = Convert.ToInt32(this.elements[2]);
|
||||||
|
if (this.elements[3].Length > 0)
|
||||||
|
this.seq_message_ident = Convert.ToInt32(this.elements[3]);
|
||||||
|
this.ais_channel_nr = this.elements[4];
|
||||||
|
this.ais_message = this.elements[5];
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string fillbits_string = this.elements[6].Substring(0, this.elements[6].IndexOf('*'));
|
||||||
|
if(!Int32.TryParse(fillbits_string, out this.fillbits))
|
||||||
|
System.Diagnostics.Trace.WriteLine("AIS_Sentence.Decode(): fillbits are no integer");
|
||||||
|
}
|
||||||
|
catch (ArgumentOutOfRangeException)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Trace.WriteLine("AIS_Sentence.Decode(): split() problem, trouble decoding fillbits");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
AIS/bsmd.AISService/AIS/NMEA_PNMLS_Sentence.cs
Normal file
58
AIS/bsmd.AISService/AIS/NMEA_PNMLS_Sentence.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// NMEA PNMLS sentence
|
||||||
|
/// sentence shows signal level for preceding message
|
||||||
|
/// </summary>
|
||||||
|
class NMEA_PNMLS_Sentence : NMEA
|
||||||
|
{
|
||||||
|
private int signal_level;
|
||||||
|
private int detection_threshold;
|
||||||
|
private int interval;
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public int Signal_Level
|
||||||
|
{
|
||||||
|
get { return this.signal_level; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Detection_Threshold
|
||||||
|
{
|
||||||
|
get { return this.detection_threshold; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Interval
|
||||||
|
{
|
||||||
|
get { return this.interval; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region decode func
|
||||||
|
|
||||||
|
protected override void Decode()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.signal_level = Convert.ToInt32(this.elements[1]);
|
||||||
|
this.detection_threshold = Convert.ToInt32(this.elements[2]);
|
||||||
|
|
||||||
|
string interval_string = this.elements[3].Substring(0, this.elements[3].IndexOf('*'));
|
||||||
|
this.interval = Convert.ToInt32(interval_string);
|
||||||
|
}
|
||||||
|
catch (FormatException)
|
||||||
|
{
|
||||||
|
Trace.WriteLine("NMEA [PNMLS] input format error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
69
AIS/bsmd.AISService/AIS/SerialDataHandler.cs
Normal file
69
AIS/bsmd.AISService/AIS/SerialDataHandler.cs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
public class SerialDataHandler
|
||||||
|
{
|
||||||
|
private Serial_IO serial_IO;
|
||||||
|
private AIS_Decoder decoder;
|
||||||
|
|
||||||
|
public SerialDataHandler(Serial_IO io, AIS_Decoder decoder)
|
||||||
|
{
|
||||||
|
this.serial_IO = io;
|
||||||
|
this.decoder = decoder;
|
||||||
|
this.serial_IO.LineRead += new Serial_IO.LineReadHandler(serial_IO_LineRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Serial_IO Serial_IO
|
||||||
|
{
|
||||||
|
get { return this.serial_IO; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public AIS_Decoder AIS_Decoder
|
||||||
|
{
|
||||||
|
get { return this.decoder; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Start(ref string message)
|
||||||
|
{
|
||||||
|
return this.serial_IO.Open(ref message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
this.serial_IO.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void serial_IO_LineRead(string data)
|
||||||
|
{
|
||||||
|
NMEA.Status nmea_Status = NMEA.Status.OK;
|
||||||
|
if (data == null || data.Length == 0) return;
|
||||||
|
|
||||||
|
NMEA decodedSentence = NMEA.Decode(data, ref nmea_Status);
|
||||||
|
if (decodedSentence != null)
|
||||||
|
{
|
||||||
|
if (decodedSentence is NMEA_AIS_Sentence)
|
||||||
|
{
|
||||||
|
NMEA_AIS_Sentence aisSentence = decodedSentence as NMEA_AIS_Sentence;
|
||||||
|
this.decoder.Decode(aisSentence.AIS_Message, aisSentence.Msg_Sentence_Nr,
|
||||||
|
aisSentence.Total_Sentence_Nr, aisSentence.Seq_Message_Ident, this.Serial_IO.StationName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Trace.WriteLine("Serial data handler: NMEA decoder returned null sentence");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("Serial AIS Receiver {0} on {1}",
|
||||||
|
this.serial_IO.StationName,
|
||||||
|
this.serial_IO.ComPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
117
AIS/bsmd.AISService/AIS/Serial_IO.cs
Normal file
117
AIS/bsmd.AISService/AIS/Serial_IO.cs
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.IO.Ports;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
public class Serial_IO
|
||||||
|
{
|
||||||
|
#region private fields
|
||||||
|
private string stationName;
|
||||||
|
private SerialPort port;
|
||||||
|
private bool runReader = true;
|
||||||
|
private Thread readerThread = null;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
// event fired if input line is available
|
||||||
|
public delegate void LineReadHandler(string data);
|
||||||
|
public event LineReadHandler LineRead;
|
||||||
|
|
||||||
|
|
||||||
|
public Serial_IO()
|
||||||
|
{
|
||||||
|
this.port = new SerialPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Open(ref string message)
|
||||||
|
{
|
||||||
|
bool retval = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.port.Open();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
message = ex.Message;
|
||||||
|
retval = false;
|
||||||
|
}
|
||||||
|
if (retval)
|
||||||
|
{
|
||||||
|
this.readerThread = new Thread(new ThreadStart(this.Read));
|
||||||
|
this.runReader = true;
|
||||||
|
this.readerThread.Start();
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
this.runReader = false;
|
||||||
|
if(readerThread != null)
|
||||||
|
if(readerThread.ThreadState == ThreadState.Running)
|
||||||
|
this.readerThread.Join();
|
||||||
|
if (this.port.IsOpen)
|
||||||
|
{
|
||||||
|
this.port.BaseStream.Flush();
|
||||||
|
this.port.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] GetComPorts()
|
||||||
|
{
|
||||||
|
return SerialPort.GetPortNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public int BaudRate
|
||||||
|
{
|
||||||
|
get { return this.port.BaudRate; }
|
||||||
|
set { this.port.BaudRate = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ComPort
|
||||||
|
{
|
||||||
|
get { return this.port.PortName; }
|
||||||
|
set { this.port.PortName = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StationName
|
||||||
|
{
|
||||||
|
get { return this.stationName; }
|
||||||
|
set { this.stationName = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region protected methods
|
||||||
|
|
||||||
|
protected void Read()
|
||||||
|
{
|
||||||
|
while (runReader)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string line = this.port.ReadLine();
|
||||||
|
this.OnInputLineRead(line);
|
||||||
|
//System.Diagnostics.Trace.WriteLine(line);
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void OnInputLineRead(string line)
|
||||||
|
{
|
||||||
|
if (this.LineRead != null)
|
||||||
|
this.LineRead(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
112
AIS/bsmd.AISService/AIS/TelnetDataHandler.cs
Normal file
112
AIS/bsmd.AISService/AIS/TelnetDataHandler.cs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
//
|
||||||
|
// Class: TelnetDataHandler
|
||||||
|
// Current CLR: 4.0.30319.296
|
||||||
|
// System: Microsoft Visual Studio 10.0
|
||||||
|
// Author: dani
|
||||||
|
// Created: 3/16/2013 2:12:35 PM
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013 Informatikbüro Daniel Schick. All rights reserved.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.AIS
|
||||||
|
{
|
||||||
|
public class TelnetDataHandler
|
||||||
|
{
|
||||||
|
AIS_Telnet aisTelnet;
|
||||||
|
AIS_Decoder decoder;
|
||||||
|
Thread readerThread;
|
||||||
|
bool requestStop;
|
||||||
|
|
||||||
|
public TelnetDataHandler(AIS_Telnet telnetConnection, AIS_Decoder aisDecoder)
|
||||||
|
{
|
||||||
|
this.aisTelnet = telnetConnection;
|
||||||
|
this.decoder = aisDecoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AIS_Decoder AIS_Decoder
|
||||||
|
{
|
||||||
|
get { return this.decoder; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("Telnet AIS Receiver {0}:{1}",
|
||||||
|
this.aisTelnet.Hostname,
|
||||||
|
this.aisTelnet.Port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Start(ref string message)
|
||||||
|
{
|
||||||
|
if (readerThread != null) return true; // already running
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.readerThread = new Thread(new ThreadStart(this.ReaderThread));
|
||||||
|
readerThread.Start();
|
||||||
|
this.requestStop = false;
|
||||||
|
message = "reader thread started";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
message = ex.Message;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
if (readerThread.IsAlive)
|
||||||
|
{
|
||||||
|
this.requestStop = true;
|
||||||
|
readerThread.Join();
|
||||||
|
}
|
||||||
|
this.readerThread = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReaderThread()
|
||||||
|
{
|
||||||
|
NMEA.Status nmea_Status = NMEA.Status.OK;
|
||||||
|
System.Diagnostics.Trace.WriteLine("starting telnet reader thread");
|
||||||
|
while (!requestStop)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
string data = this.aisTelnet.ReadLine();
|
||||||
|
// Trace.WriteLine(data);
|
||||||
|
if (data != null && data.Length > 0)
|
||||||
|
{
|
||||||
|
NMEA decodedSentence = NMEA.Decode(data, ref nmea_Status);
|
||||||
|
if (decodedSentence != null)
|
||||||
|
{
|
||||||
|
if (decodedSentence is NMEA_AIS_Sentence)
|
||||||
|
{
|
||||||
|
NMEA_AIS_Sentence aisSentence = decodedSentence as NMEA_AIS_Sentence;
|
||||||
|
this.decoder.Decode(aisSentence.AIS_Message, aisSentence.Msg_Sentence_Nr,
|
||||||
|
aisSentence.Total_Sentence_Nr, aisSentence.Seq_Message_Ident, this.aisTelnet.StationName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Trace.WriteLine("Serial data handler: NMEA decoder returned null/empty sentence");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var st = new StackTrace(ex, true);
|
||||||
|
var frame = st.GetFrame(0);
|
||||||
|
var line = frame.GetFileLineNumber();
|
||||||
|
Trace.WriteLine(string.Format("Exception in telnet reader thread: {0}, top frame ln {1}", ex.Message, line));
|
||||||
|
Trace.WriteLine(ex.StackTrace);
|
||||||
|
}
|
||||||
|
Thread.Sleep(100);
|
||||||
|
}
|
||||||
|
aisTelnet.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
AIS/bsmd.AISService/AISService.Designer.cs
generated
Normal file
37
AIS/bsmd.AISService/AISService.Designer.cs
generated
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
namespace bsmd.AISService
|
||||||
|
{
|
||||||
|
partial class AISService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Component Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
components = new System.ComponentModel.Container();
|
||||||
|
this.ServiceName = "Service1";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
93
AIS/bsmd.AISService/AISService.cs
Normal file
93
AIS/bsmd.AISService/AISService.cs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// Copyright (c) 2008-2018 schick Informatik
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.ServiceProcess;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using bsmd.AISService.AIS;
|
||||||
|
using bsmd.AISService.DB;
|
||||||
|
|
||||||
|
using log4net;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace bsmd.AISService
|
||||||
|
{
|
||||||
|
public partial class AISService : ServiceBase
|
||||||
|
{
|
||||||
|
private const string config_filename = "ais_config.xml";
|
||||||
|
private ILog _log = LogManager.GetLogger(typeof(AISService));
|
||||||
|
private AIS_QueueManager qManager;
|
||||||
|
|
||||||
|
public AISService()
|
||||||
|
{
|
||||||
|
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStart(string[] args)
|
||||||
|
{
|
||||||
|
string errorMessage = "";
|
||||||
|
|
||||||
|
this.EventLog.Source = this.ServiceName;
|
||||||
|
this.EventLog.Log = "Application";
|
||||||
|
this.Init(args);
|
||||||
|
if (qManager.Start(ref errorMessage))
|
||||||
|
{
|
||||||
|
this.EventLog.WriteEntry("BSMD AIS Service started.", EventLogEntryType.Information);
|
||||||
|
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
|
||||||
|
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
|
||||||
|
string version = fvi.FileVersion;
|
||||||
|
_log.InfoFormat("Starting AIS Service. v.{0} -------------- ", version);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
_log.ErrorFormat("AIS Service start failed: {0}", errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStop()
|
||||||
|
{
|
||||||
|
this.qManager.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void Init(string[] args)
|
||||||
|
{
|
||||||
|
AIS_Configuration configuration = AIS_Configuration.Load(config_filename);
|
||||||
|
|
||||||
|
if (configuration == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine(string.Format("cannot read configuration {0}", config_filename));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBConnector dbConnector = new DBConnector();
|
||||||
|
dbConnector.ConnectionString = configuration.DBConnectionString;
|
||||||
|
if (!dbConnector.Open())
|
||||||
|
{
|
||||||
|
Console.WriteLine("Error connecting to database");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<AISStation> stationList = AISStation.LoadStations(dbConnector);
|
||||||
|
|
||||||
|
this.qManager = new AIS_QueueManager(configuration, AISStation.CreateSerial_IOs(stationList), AISStation.CreateAIS_Telnets(stationList));
|
||||||
|
qManager.DBUpdateRequired += new AIS_QueueManager.AISQueueChangedHandler(dbConnector.Update);
|
||||||
|
qManager.AISQueueChanged += new AIS_QueueManager.AISQueueChangedHandler(aisDecoder_AISMessageReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void aisDecoder_AISMessageReceived(AIS_Target target)
|
||||||
|
{
|
||||||
|
Console.WriteLine(string.Format("{0}: {1} Pos:{2} {3} at {4}", target.Station, target.Name, target.Latitude, target.Longitude, target.LastUpdate));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
18
AIS/bsmd.AISService/App.config
Normal file
18
AIS/bsmd.AISService/App.config
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<configSections>
|
||||||
|
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||||
|
<section name="bsmd.AISService.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
|
||||||
|
</sectionGroup>
|
||||||
|
</configSections>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||||
|
</startup>
|
||||||
|
<applicationSettings>
|
||||||
|
<bsmd.AISService.Properties.Settings>
|
||||||
|
<setting name="ConnectionString" serializeAs="String">
|
||||||
|
<value />
|
||||||
|
</setting>
|
||||||
|
</bsmd.AISService.Properties.Settings>
|
||||||
|
</applicationSettings>
|
||||||
|
</configuration>
|
||||||
79
AIS/bsmd.AISService/DB/AISPosReport.cs
Normal file
79
AIS/bsmd.AISService/DB/AISPosReport.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using bsmd.AISService.AIS;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.DB
|
||||||
|
{
|
||||||
|
|
||||||
|
internal class AISPosReport
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Saves a (class A or B) position report
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">target to save</param>
|
||||||
|
/// <returns>id of insert operation (to update hotposition table)</returns>
|
||||||
|
public static int? Save(AIS_Target target, DBConnector con, AISStation aisStation)
|
||||||
|
{
|
||||||
|
if (target.LastPosReport == null) return null;
|
||||||
|
|
||||||
|
if (target.LastPosReport is AIS_PosReport)
|
||||||
|
{
|
||||||
|
// Trace.WriteLine("saving class A pos report");
|
||||||
|
AIS_PosReport pr = target.LastPosReport as AIS_PosReport;
|
||||||
|
|
||||||
|
if (aisStation != null)
|
||||||
|
{
|
||||||
|
aisStation.UpdateWithPositionReport(pr.MMSI, pr.Latitude, pr.Longitude, pr.Timestamp);
|
||||||
|
aisStation.LastPosTimestamp = pr.Timestamp;
|
||||||
|
aisStation.OnAir = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string query = string.Format("INSERT INTO aisposreport (mmsi, navstatus, rot, cog, sog, accur, longitude, latitude, heading, timestamp, stationid) VALUES ({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, '{9}', {10})",
|
||||||
|
pr.MMSI, pr.NavStatusVal, pr.ROTVal, pr.COGVal, pr.SOGVal, pr.Accuracy,
|
||||||
|
pr.LongitudeVal, pr.LatitudeVal, pr.TrueHeading ?? 511, pr.DBTimestamp,
|
||||||
|
(aisStation != null) ? aisStation.Id : 0);
|
||||||
|
|
||||||
|
con.ExecuteNonQuery(query);
|
||||||
|
|
||||||
|
object result = con.ExecuteScalar("SELECT LAST_INSERT_ID()");
|
||||||
|
if (result == null) return null;
|
||||||
|
int pid = Convert.ToInt32(result);
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.LastPosReport is AIS_ClassB)
|
||||||
|
{
|
||||||
|
// Trace.WriteLine("saving class B pos report");
|
||||||
|
AIS_ClassB pr = target.LastPosReport as AIS_ClassB;
|
||||||
|
aisStation.UpdateWithPositionReport(pr.MMSI, pr.Latitude, pr.Longitude, pr.Timestamp);
|
||||||
|
|
||||||
|
string query = string.Format("INSERT INTO aisposreport (mmsi, navstatus, rot, cog, sog, accur, longitude, latitude, heading, timestamp, stationid) VALUES ({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, '{9}', {10})",
|
||||||
|
pr.MMSI, 0, 0, pr.CogVal, pr.SogVal, 0, pr.LongitudeVal, pr.LatitudeVal,
|
||||||
|
pr.TrueHeading ?? 511, pr.DBTimestamp, (aisStation != null) ? aisStation.Id : 0);
|
||||||
|
|
||||||
|
con.ExecuteNonQuery(query);
|
||||||
|
|
||||||
|
object result = con.ExecuteScalar("SELECT LAST_INSERT_ID()");
|
||||||
|
if (result == null) return null;
|
||||||
|
int pid = Convert.ToInt32(result);
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.LastPosReport is AIS_ClassBExt)
|
||||||
|
{
|
||||||
|
Trace.WriteLine("AIS class B ext not supported (yet)");
|
||||||
|
// TODO: Import ClassB Extended report!
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Trace.WriteLine(string.Format("save pos report: we should not be here.. class type: {0}", target));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
521
AIS/bsmd.AISService/DB/AISStaticData.cs
Normal file
521
AIS/bsmd.AISService/DB/AISStaticData.cs
Normal file
@ -0,0 +1,521 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Data;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
using bsmd.AISService.AIS;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.DB
|
||||||
|
{
|
||||||
|
|
||||||
|
public class AISStaticData
|
||||||
|
{
|
||||||
|
|
||||||
|
public enum DisplayStringType
|
||||||
|
{
|
||||||
|
NAME,
|
||||||
|
MMSI,
|
||||||
|
CALLSIGN
|
||||||
|
}
|
||||||
|
|
||||||
|
private const string LoadDBShipsQuery = "SELECT aisposreport.MMSI, aisposreport.timestamp, aisposreport.latitude, aisposreport.longitude, aisposreport.stationid, aisposreport.cog, aisposreport.heading, aisposreport.navstatus, aisstaticdata.callsign, aisstaticdata.name, aisstaticdata.shiptype, aisstaticdata.classb, aisstaticdata.shipdescription FROM aisstaticdata JOIN hotposition ON aisstaticdata.mmsi = hotposition.mmsi JOIN aisposreport ON aisposreport.id = hotposition.pid ORDER BY aisstaticdata.name";
|
||||||
|
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private int mmsi;
|
||||||
|
private string name;
|
||||||
|
private string callsign;
|
||||||
|
private DateTime? lastposition;
|
||||||
|
private double? lastLatitude;
|
||||||
|
private double? lastLongitude;
|
||||||
|
private int stationid;
|
||||||
|
private int navstatus;
|
||||||
|
private int shiptype;
|
||||||
|
private string shipdescription;
|
||||||
|
private int cog;
|
||||||
|
private int heading;
|
||||||
|
private bool isClassB;
|
||||||
|
private bool isWatchkeeper;
|
||||||
|
private bool isTimedOut = false;
|
||||||
|
private bool isSelected = false;
|
||||||
|
private static DisplayStringType displayStringType = DisplayStringType.NAME;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public int MMSI
|
||||||
|
{
|
||||||
|
get { return this.mmsi; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return this.name; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Callsign
|
||||||
|
{
|
||||||
|
get { return this.callsign; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime? LastPositionReport
|
||||||
|
{
|
||||||
|
get { return this.lastposition; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public double? LastLatitude
|
||||||
|
{
|
||||||
|
get { return this.lastLatitude; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public double? LastLongitude
|
||||||
|
{
|
||||||
|
get { return this.lastLongitude; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsClassB
|
||||||
|
{
|
||||||
|
get { return this.isClassB; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ShipType
|
||||||
|
{
|
||||||
|
get { return this.shiptype; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Description
|
||||||
|
{
|
||||||
|
get { return this.shipdescription; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsWatchkeeperShip
|
||||||
|
{
|
||||||
|
get { return this.isWatchkeeper; }
|
||||||
|
set { this.isWatchkeeper = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int StationId
|
||||||
|
{
|
||||||
|
get { return this.stationid; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Heading
|
||||||
|
{
|
||||||
|
get { return this.heading; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int COG
|
||||||
|
{
|
||||||
|
get { return this.cog; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int NavStatus
|
||||||
|
{
|
||||||
|
get { return this.navstatus; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Selected
|
||||||
|
{
|
||||||
|
get { return this.isSelected; }
|
||||||
|
set { this.isSelected = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DisplayStringType DisplayStringTyp
|
||||||
|
{
|
||||||
|
get { return displayStringType; }
|
||||||
|
set { displayStringType = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsTimedOut
|
||||||
|
{
|
||||||
|
get { return this.isTimedOut; }
|
||||||
|
set { this.isTimedOut = value; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public methods
|
||||||
|
|
||||||
|
public string ToHtmlString()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
sb.Append(string.Format("<em>MMSI</em>: {0} <br />", this.MMSI));
|
||||||
|
sb.Append(string.Format("<em>Name</em>: <span style=\"font-size: bigger\">{0}</span><br />", this.Name));
|
||||||
|
sb.Append(string.Format("Latitude: {0}° <br />", this.LastLatitude.HasValue ? this.LastLatitude.Value.ToString("N3") : "?"));
|
||||||
|
sb.Append(string.Format("Longitude: {0}° <br />", this.LastLongitude.HasValue ? this.LastLongitude.Value.ToString("N3") : "?"));
|
||||||
|
sb.Append(string.Format("Last report: {0} <br />", this.LastPositionReport.HasValue ? this.LastPositionReport.Value.ToString() : "?"));
|
||||||
|
sb.Append(string.Format("Type: {0} [{1}]<br />", this.Description, this.ShipType));
|
||||||
|
sb.Append(string.Format("Navstatus: {0}<br />", this.NavStatus));
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region overrides
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
switch (displayStringType)
|
||||||
|
{
|
||||||
|
case DisplayStringType.NAME:
|
||||||
|
string result = "?";
|
||||||
|
if (this.name != null && this.name.Length > 0)
|
||||||
|
result = this.name;
|
||||||
|
return result;
|
||||||
|
case DisplayStringType.MMSI:
|
||||||
|
return this.mmsi.ToString();
|
||||||
|
case DisplayStringType.CALLSIGN:
|
||||||
|
if (this.Callsign == null || this.Callsign.Length == 0)
|
||||||
|
return "?";
|
||||||
|
return this.Callsign;
|
||||||
|
default:
|
||||||
|
return string.Format("{0} - {1}", this.name, this.mmsi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region static methods
|
||||||
|
|
||||||
|
#region save a position report
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves a (class A or B) position report
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">target to save</param>
|
||||||
|
/// <returns>id of insert operation (to update hotposition table)</returns>
|
||||||
|
public static int? Save(AIS_Target target, DBConnector con, AISStation aisStation)
|
||||||
|
{
|
||||||
|
if(target.LastStaticData == null) return null;
|
||||||
|
|
||||||
|
int mmsi = -1;
|
||||||
|
int id = -1;
|
||||||
|
|
||||||
|
if(target.LastStaticData is AIS_StaticData) {
|
||||||
|
mmsi = ((AIS_StaticData)target.LastStaticData).MMSI;
|
||||||
|
}
|
||||||
|
if(target.LastStaticData is AIS_ClassBStatic) {
|
||||||
|
mmsi = ((AIS_ClassBStatic)target.LastStaticData).MMSI;
|
||||||
|
}
|
||||||
|
|
||||||
|
string query = string.Format("SELECT id FROM aisstaticdata WHERE mmsi={0}", mmsi);
|
||||||
|
object result = con.ExecuteScalar(query);
|
||||||
|
|
||||||
|
if (result != null) // update
|
||||||
|
{
|
||||||
|
id = Convert.ToInt32(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Class A
|
||||||
|
|
||||||
|
if (target.LastStaticData is AIS_StaticData)
|
||||||
|
{
|
||||||
|
AIS_StaticData staticData = target.LastStaticData as AIS_StaticData;
|
||||||
|
|
||||||
|
if (id >= 0)
|
||||||
|
{
|
||||||
|
if (staticData.ETA.HasValue)
|
||||||
|
{
|
||||||
|
query = string.Format("UPDATE aisstaticdata SET imonumber={0}, callsign='{1}', name='{2}', shiptype={3}, typeofdevice='{4}', shipdescription='{5}', eta='{6}', destination='{7}', breadth={8}, length={9}, draught='{10}', stationid={11}, classb=0 WHERE id={12}",
|
||||||
|
staticData.IMONumber,
|
||||||
|
staticData.Callsign.Replace("'","''"),
|
||||||
|
staticData.Name.Replace("'", "''"),
|
||||||
|
staticData.ShipTypeVal,
|
||||||
|
staticData.DeviceName,
|
||||||
|
staticData.ShipType,
|
||||||
|
staticData.DBETA,
|
||||||
|
staticData.Destination.Replace("'", "''"),
|
||||||
|
staticData.Breadth,
|
||||||
|
staticData.Length,
|
||||||
|
staticData.Draught,
|
||||||
|
aisStation.Id,
|
||||||
|
id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
query = string.Format("UPDATE aisstaticdata SET imonumber={0}, callsign='{1}', name='{2}', shiptype={3}, typeofdevice='{4}', shipdescription='{5}', destination='{6}', breadth={7}, length={8}, draught='{9}', stationid={10}, classb=0 WHERE id={11}",
|
||||||
|
staticData.IMONumber,
|
||||||
|
staticData.Callsign.Replace("'", "''"),
|
||||||
|
staticData.Name.Replace("'", "''"),
|
||||||
|
staticData.ShipTypeVal,
|
||||||
|
staticData.DeviceName,
|
||||||
|
staticData.ShipType,
|
||||||
|
staticData.Destination.Replace("'", "''"),
|
||||||
|
staticData.Breadth,
|
||||||
|
staticData.Length,
|
||||||
|
staticData.Draught,
|
||||||
|
aisStation.Id,
|
||||||
|
id);
|
||||||
|
|
||||||
|
}
|
||||||
|
con.ExecuteNonQuery(query);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (staticData.ETA.HasValue)
|
||||||
|
{
|
||||||
|
|
||||||
|
query = string.Format("INSERT INTO aisstaticdata SET imonumber={0}, callsign='{1}', name='{2}', shiptype={3}, typeofdevice='{4}', shipdescription='{5}', eta='{6}', destination='{7}', breadth={8}, length={9}, draught='{10}', stationid={11}, mmsi={12}, classb=0",
|
||||||
|
staticData.IMONumber,
|
||||||
|
staticData.Callsign.Replace("'", "''"),
|
||||||
|
staticData.Name.Replace("'", "''"),
|
||||||
|
staticData.ShipTypeVal,
|
||||||
|
staticData.DeviceName,
|
||||||
|
staticData.ShipType,
|
||||||
|
staticData.DBETA,
|
||||||
|
staticData.Destination.Replace("'", "''"),
|
||||||
|
staticData.Breadth,
|
||||||
|
staticData.Length,
|
||||||
|
staticData.Draught,
|
||||||
|
aisStation.Id,
|
||||||
|
staticData.MMSI);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
query = string.Format("INSERT INTO aisstaticdata SET imonumber={0}, callsign='{1}', name='{2}', shiptype={3}, typeofdevice='{4}', shipdescription='{5}', destination='{6}', breadth={7}, length={8}, draught='{9}', stationid={10}, mmsi={11}, classb=0",
|
||||||
|
staticData.IMONumber,
|
||||||
|
staticData.Callsign.Replace("'", "''"),
|
||||||
|
staticData.Name.Replace("'", "''"),
|
||||||
|
staticData.ShipTypeVal,
|
||||||
|
staticData.DeviceName,
|
||||||
|
staticData.ShipType,
|
||||||
|
staticData.Destination.Replace("'", "''"),
|
||||||
|
staticData.Breadth,
|
||||||
|
staticData.Length,
|
||||||
|
staticData.Draught,
|
||||||
|
aisStation.Id,
|
||||||
|
staticData.MMSI);
|
||||||
|
}
|
||||||
|
|
||||||
|
con.ExecuteNonQuery(query);
|
||||||
|
|
||||||
|
id = Convert.ToInt32(con.ExecuteScalar("SELECT LAST_INSERT_ID()"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Class B
|
||||||
|
|
||||||
|
if (target.LastStaticData is AIS_ClassBStatic)
|
||||||
|
{
|
||||||
|
AIS_ClassBStatic staticData = target.LastStaticData as AIS_ClassBStatic;
|
||||||
|
|
||||||
|
if (id >= 0) // Update
|
||||||
|
{
|
||||||
|
query = string.Format("UPDATE aisstaticdata SET stationid={0}, shiptype={1}, classb=1", aisStation.Id, staticData.ShipTypeVal);
|
||||||
|
if(staticData.Callsign != null) query += string.Format(", callsign='{0}'", staticData.Callsign);
|
||||||
|
if(staticData.Name != null) query += string.Format(", name='{0}'", staticData.Name);
|
||||||
|
if(staticData.VendorId != null) query += string.Format(", typeofdevice='{0}'", staticData.VendorId);
|
||||||
|
if(staticData.ShipType != null) query += string.Format(", shipdescription='{0}'", staticData.ShipType);
|
||||||
|
query += string.Format(" WHERE id={0}", id);
|
||||||
|
|
||||||
|
con.ExecuteNonQuery(query);
|
||||||
|
}
|
||||||
|
else // Insert
|
||||||
|
{
|
||||||
|
query = string.Format("INSERT INTO aisstaticdata SET callsign='{0}', name='{1}', shiptype={2}, typeofdevice='{3}', shipdescription='{4}', stationid={5}, mmsi={6}, classb=1",
|
||||||
|
staticData.Callsign,
|
||||||
|
staticData.Name,
|
||||||
|
staticData.ShipTypeVal,
|
||||||
|
staticData.VendorId,
|
||||||
|
staticData.ShipType,
|
||||||
|
aisStation.Id,
|
||||||
|
staticData.MMSI
|
||||||
|
);
|
||||||
|
|
||||||
|
con.ExecuteNonQuery(query);
|
||||||
|
id = Convert.ToInt32(con.ExecuteScalar("SELECT LAST_INSERT_ID()"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads shipname for display (until static data has been received)
|
||||||
|
/// </summary>
|
||||||
|
public static string LoadName(int mmsi, DBConnector con)
|
||||||
|
{
|
||||||
|
string query = string.Format("SELECT name FROM aisstaticdata where mmsi={0}", mmsi);
|
||||||
|
string result = con.ExecuteScalar(query) as string;
|
||||||
|
if (result == null) result = "";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads callsign for display (until static data has been received)
|
||||||
|
/// </summary>
|
||||||
|
public static string LoadCallsign(int mmsi, DBConnector con)
|
||||||
|
{
|
||||||
|
string query = string.Format("SELECT callsign FROM aisstaticdata where mmsi={0}", mmsi);
|
||||||
|
string result = con.ExecuteScalar(query) as string;
|
||||||
|
if (result == null) result = "";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// preload target with data from database until static data has been received
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">target to load</param>
|
||||||
|
public static void PreloadTarget(AIS_Target target, DBConnector con)
|
||||||
|
{
|
||||||
|
if (target.MMSI == 0) return;
|
||||||
|
string query = string.Format("SELECT name, callsign, shiptype FROM aisstaticdata where mmsi={0}", target.MMSI);
|
||||||
|
IDataReader reader = con.ExecuteQuery(query);
|
||||||
|
if (reader.Read())
|
||||||
|
{
|
||||||
|
if (!reader.IsDBNull(0)) target.LastDBName = reader.GetString(0);
|
||||||
|
if (!reader.IsDBNull(1)) target.Callsign = reader.GetString(1);
|
||||||
|
if (!reader.IsDBNull(2))
|
||||||
|
target.TargetType = AIS_StaticData.GetShipTypeSimple(reader.GetInt32(2));
|
||||||
|
}
|
||||||
|
reader.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Load all ships that have a position and static data from database
|
||||||
|
/// </summary>
|
||||||
|
public static List<AISStaticData> LoadDBShips(DBConnector con)
|
||||||
|
{
|
||||||
|
List<AISStaticData> result = new List<AISStaticData>();
|
||||||
|
IDataReader reader = con.ExecuteQuery(AISStaticData.LoadDBShipsQuery);
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
AISStaticData ship = new AISStaticData();
|
||||||
|
ship.mmsi = reader.GetInt32(0);
|
||||||
|
ship.lastposition = reader.GetDateTime(1);
|
||||||
|
ship.lastLatitude = (double) Math.Round(reader.GetInt32(2) / 600000.0, 4);
|
||||||
|
ship.lastLongitude = (double) Math.Round(reader.GetInt32(3) / 600000.0, 4);
|
||||||
|
ship.stationid = reader.GetInt32(4);
|
||||||
|
ship.cog = reader.GetInt32(5);
|
||||||
|
ship.heading = reader.GetInt32(6);
|
||||||
|
ship.navstatus = reader.GetInt32(7);
|
||||||
|
if(!reader.IsDBNull(8))
|
||||||
|
ship.callsign = reader.GetString(8);
|
||||||
|
if(!reader.IsDBNull(9))
|
||||||
|
ship.name = reader.GetString(9);
|
||||||
|
ship.shiptype = reader.GetInt32(10);
|
||||||
|
if (reader.IsDBNull(11)) ship.isClassB = false;
|
||||||
|
else ship.isClassB = reader.GetBoolean(11);
|
||||||
|
ship.shipdescription = reader.GetString(12);
|
||||||
|
result.Add(ship);
|
||||||
|
}
|
||||||
|
reader.Close();
|
||||||
|
Trace.WriteLine(string.Format("AISStaticData: {0} ships loaded from DB", result.Count));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Comparer Class for grid
|
||||||
|
|
||||||
|
public class AISStaticData_Comparer : IComparer<AISStaticData>
|
||||||
|
{
|
||||||
|
private SortPropertyEnum sortProperty = SortPropertyEnum.NAME;
|
||||||
|
private ListSortDirection sortDirection = ListSortDirection.Ascending;
|
||||||
|
|
||||||
|
public enum SortPropertyEnum
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
MMSI,
|
||||||
|
NAME,
|
||||||
|
CALLSIGN,
|
||||||
|
LASTUPDATE,
|
||||||
|
DESCRIPTION
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public ListSortDirection SortDirection
|
||||||
|
{
|
||||||
|
get { return this.sortDirection; }
|
||||||
|
set { this.sortDirection = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public SortPropertyEnum SortProperty
|
||||||
|
{
|
||||||
|
get { return this.sortProperty; }
|
||||||
|
set { this.sortProperty = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public int Compare(AISStaticData x, AISStaticData y)
|
||||||
|
{
|
||||||
|
switch (this.sortProperty)
|
||||||
|
{
|
||||||
|
case SortPropertyEnum.NONE:
|
||||||
|
return 0;
|
||||||
|
case SortPropertyEnum.NAME:
|
||||||
|
{
|
||||||
|
string xName = x.Name;
|
||||||
|
if (xName == null) xName = "";
|
||||||
|
string yName = y.Name;
|
||||||
|
if (yName == null) yName = "";
|
||||||
|
if (this.sortDirection == ListSortDirection.Ascending)
|
||||||
|
return xName.CompareTo(yName);
|
||||||
|
else
|
||||||
|
return yName.CompareTo(xName);
|
||||||
|
}
|
||||||
|
case SortPropertyEnum.LASTUPDATE:
|
||||||
|
{
|
||||||
|
DateTime xTime = x.LastPositionReport ?? DateTime.MinValue;
|
||||||
|
DateTime yTime = y.LastPositionReport ?? DateTime.MinValue;
|
||||||
|
if (this.sortDirection == ListSortDirection.Ascending)
|
||||||
|
return xTime.CompareTo(yTime);
|
||||||
|
else
|
||||||
|
return yTime.CompareTo(xTime);
|
||||||
|
}
|
||||||
|
case SortPropertyEnum.MMSI:
|
||||||
|
{
|
||||||
|
if (this.sortDirection == ListSortDirection.Ascending)
|
||||||
|
return x.MMSI.CompareTo(y.MMSI);
|
||||||
|
else
|
||||||
|
return y.MMSI.CompareTo(x.MMSI);
|
||||||
|
}
|
||||||
|
case SortPropertyEnum.CALLSIGN:
|
||||||
|
{
|
||||||
|
string xCallsign = x.Callsign;
|
||||||
|
if (xCallsign == null) xCallsign = "";
|
||||||
|
string yCallsign = y.Callsign;
|
||||||
|
if (yCallsign == null) yCallsign = "";
|
||||||
|
if (this.sortDirection == ListSortDirection.Ascending)
|
||||||
|
return xCallsign.CompareTo(yCallsign);
|
||||||
|
else
|
||||||
|
return yCallsign.CompareTo(xCallsign);
|
||||||
|
}
|
||||||
|
case SortPropertyEnum.DESCRIPTION:
|
||||||
|
{
|
||||||
|
string xDescription = x.Description;
|
||||||
|
if (xDescription == null) xDescription = "";
|
||||||
|
string yDescription = y.Description;
|
||||||
|
if (yDescription == null) yDescription = "";
|
||||||
|
if (this.sortDirection == ListSortDirection.Ascending)
|
||||||
|
return xDescription.CompareTo(yDescription);
|
||||||
|
else
|
||||||
|
return yDescription.CompareTo(xDescription);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
258
AIS/bsmd.AISService/DB/AISStation.cs
Normal file
258
AIS/bsmd.AISService/DB/AISStation.cs
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Data;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
using bsmd.AISService.AIS;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.DB
|
||||||
|
{
|
||||||
|
|
||||||
|
public class AISStation
|
||||||
|
{
|
||||||
|
#region private members
|
||||||
|
|
||||||
|
private int station_Id;
|
||||||
|
private string name;
|
||||||
|
private bool active;
|
||||||
|
private string comport;
|
||||||
|
private int baudrate;
|
||||||
|
private int telnetPort;
|
||||||
|
private string telnetHost;
|
||||||
|
private bool onAir = false;
|
||||||
|
private double rangeMax = 0;
|
||||||
|
private double rangeAverage;
|
||||||
|
private double coverage;
|
||||||
|
private double latitude;
|
||||||
|
private double longitude;
|
||||||
|
private string address;
|
||||||
|
private DateTime? lastPosTimestamp;
|
||||||
|
private bool isDirty = false;
|
||||||
|
private Dictionary<int, double> targets = new Dictionary<int, double>();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public string Name { get { return this.name; } set { this.name = value; } }
|
||||||
|
public int Id { get { return this.station_Id; } }
|
||||||
|
public bool Active { get { return this.active; } set { this.active = value; } }
|
||||||
|
public string COMPort { get { return this.comport; } set { this.comport = value; } }
|
||||||
|
public int Baudrate { get { return this.baudrate; } set { this.baudrate = value; } }
|
||||||
|
public string TelnetHost { get { return this.telnetHost; } set { this.telnetHost = value; } }
|
||||||
|
public int TelnetPort { get { return this.telnetPort; } set { this.telnetPort = value; } }
|
||||||
|
public bool OnAir { get { return this.onAir; } set { this.onAir = value; } }
|
||||||
|
public double RangeMax { get { return this.rangeMax; } }
|
||||||
|
public double RangeAverage { get { return this.rangeAverage; } }
|
||||||
|
public double Coverage { get { return this.coverage; } }
|
||||||
|
public string CoverageText { get { return string.Format("{0} qkm", this.coverage.ToString("N2")); } }
|
||||||
|
public double Latitude
|
||||||
|
{
|
||||||
|
get { return this.latitude; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.latitude = value;
|
||||||
|
this.isDirty = true;
|
||||||
|
this.rangeMax = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public double Longitude
|
||||||
|
{
|
||||||
|
get { return this.longitude; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.longitude = value;
|
||||||
|
this.isDirty = true;
|
||||||
|
this.rangeMax = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string Address { get { return this.address; } }
|
||||||
|
public bool IsDirty { get { return this.isDirty; } }
|
||||||
|
|
||||||
|
public DateTime? LastPosTimestamp
|
||||||
|
{
|
||||||
|
get { return this.lastPosTimestamp; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.lastPosTimestamp = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int NumTargets
|
||||||
|
{
|
||||||
|
get { return this.targets.Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<int, double> Targets { get { return this.targets; } }
|
||||||
|
|
||||||
|
public bool MustDelete { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public methods
|
||||||
|
|
||||||
|
public bool Save(DBConnector con)
|
||||||
|
{
|
||||||
|
string query = string.Format("UPDATE aisstation SET lat={0}, lon={1}, telnetHost='{2}', telnetPort={3}, comPort='{4}', name='{5}', baudrate={6} WHERE id={7}",
|
||||||
|
(int) (this.latitude * 600000),
|
||||||
|
(int) (this.longitude * 600000),
|
||||||
|
this.telnetHost,
|
||||||
|
this.telnetPort,
|
||||||
|
this.comport,
|
||||||
|
this.name,
|
||||||
|
this.baudrate,
|
||||||
|
this.station_Id);
|
||||||
|
|
||||||
|
if (con.ExecuteNonQuery(query) == 1)
|
||||||
|
{
|
||||||
|
this.isDirty = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateWithPositionReport(int mmsi, double lat, double lon, DateTime timestamp)
|
||||||
|
{
|
||||||
|
|
||||||
|
double distance = bsmd.AISService.AIS.AIS.GetDistance(this.Latitude, this.Longitude, lat, lon);
|
||||||
|
if (distance > this.rangeMax)
|
||||||
|
{
|
||||||
|
this.rangeMax = distance;
|
||||||
|
this.coverage = Math.PI * this.rangeMax * this.rangeMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (this.Targets)
|
||||||
|
{
|
||||||
|
if (!this.targets.ContainsKey(mmsi))
|
||||||
|
this.targets.Add(mmsi, distance);
|
||||||
|
else this.targets[mmsi] = distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// durchschnittl. Reichweite
|
||||||
|
double sumRange = 0;
|
||||||
|
foreach (int key in this.targets.Keys)
|
||||||
|
sumRange += this.targets[mmsi];
|
||||||
|
this.rangeAverage = sumRange / (double)this.targets.Count;
|
||||||
|
|
||||||
|
if (!this.lastPosTimestamp.HasValue) this.lastPosTimestamp = timestamp;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (this.lastPosTimestamp.Value < timestamp)
|
||||||
|
this.lastPosTimestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// clear targets and reset coverage
|
||||||
|
/// </summary>
|
||||||
|
public void ResetStation()
|
||||||
|
{
|
||||||
|
this.targets.Clear();
|
||||||
|
this.coverage = 0;
|
||||||
|
this.rangeAverage = 0;
|
||||||
|
this.rangeMax = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// deletes this station
|
||||||
|
/// </summary>
|
||||||
|
public void Delete(DBConnector con)
|
||||||
|
{
|
||||||
|
string query = string.Format("DELETE FROM aisstation WHERE id={0}", this.Id);
|
||||||
|
con.ExecuteNonQuery(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region static methods
|
||||||
|
|
||||||
|
public static List<AISStation> LoadStations(DBConnector con)
|
||||||
|
{
|
||||||
|
List<AISStation> result = new List<AISStation>();
|
||||||
|
string query = "SELECT id, name, active, lat, lon, address, telnetHost, telnetPort, comPort, baudrate FROM aisstation";
|
||||||
|
IDataReader reader = con.ExecuteQuery(query);
|
||||||
|
if (reader == null) return result;
|
||||||
|
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
AISStation station = new AISStation();
|
||||||
|
station.station_Id = reader.GetInt32(0);
|
||||||
|
station.name = reader.GetString(1);
|
||||||
|
station.active = reader.GetBoolean(2);
|
||||||
|
station.latitude = (double) reader.GetInt32(3) / 600000;
|
||||||
|
station.longitude = (double) reader.GetInt32(4) / 600000;
|
||||||
|
if(!reader.IsDBNull(5))
|
||||||
|
station.address = reader.GetString(5);
|
||||||
|
if (!reader.IsDBNull(6))
|
||||||
|
station.telnetHost = reader.GetString(6);
|
||||||
|
if (!reader.IsDBNull(7))
|
||||||
|
station.telnetPort = reader.GetInt32(7);
|
||||||
|
if (!reader.IsDBNull(8))
|
||||||
|
station.comport = reader.GetString(8);
|
||||||
|
if (!reader.IsDBNull(9))
|
||||||
|
station.baudrate = reader.GetInt32(9);
|
||||||
|
result.Add(station);
|
||||||
|
}
|
||||||
|
reader.Close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AISStation CreateStation(string name, DBConnector con)
|
||||||
|
{
|
||||||
|
AISStation newStation = new AISStation();
|
||||||
|
newStation.name = name;
|
||||||
|
newStation.active = true;
|
||||||
|
string query = string.Format("INSERT INTO aisstation SET name='{0}',active=1",
|
||||||
|
name);
|
||||||
|
con.ExecuteNonQuery(query);
|
||||||
|
newStation.station_Id = Convert.ToInt32(con.ExecuteScalar("SELECT LAST_INSERT_ID()"));
|
||||||
|
|
||||||
|
return newStation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Serial_IO> CreateSerial_IOs(List<AISStation> stationList)
|
||||||
|
{
|
||||||
|
List<Serial_IO> result = new List<Serial_IO>();
|
||||||
|
foreach (AISStation station in stationList)
|
||||||
|
{
|
||||||
|
if ((station.COMPort != null) && (station.COMPort.Length > 0))
|
||||||
|
{
|
||||||
|
Serial_IO serialIO = new Serial_IO();
|
||||||
|
serialIO.BaudRate = (station.Baudrate == 0) ? 9600 : station.Baudrate;
|
||||||
|
serialIO.ComPort = station.COMPort;
|
||||||
|
serialIO.StationName = station.Name;
|
||||||
|
result.Add(serialIO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<AIS_Telnet> CreateAIS_Telnets(List<AISStation> stationList)
|
||||||
|
{
|
||||||
|
List<AIS_Telnet> result = new List<AIS_Telnet>();
|
||||||
|
foreach (AISStation station in stationList)
|
||||||
|
{
|
||||||
|
if ((station.TelnetHost != null) && (station.TelnetHost.Length > 0))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AIS_Telnet telnet = new AIS_Telnet(station.TelnetHost, station.TelnetPort);
|
||||||
|
telnet.StationName = station.Name;
|
||||||
|
result.Add(telnet);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Trace.WriteLine(string.Format("AIS_Telnet: cannot connect to host {0} port {1}: {2}",
|
||||||
|
station.TelnetHost ?? "", station.TelnetPort, ex.Message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
50
AIS/bsmd.AISService/DB/AISWatchkeeper.cs
Normal file
50
AIS/bsmd.AISService/DB/AISWatchkeeper.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Data;
|
||||||
|
|
||||||
|
using bsmd.AISService.AIS;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.DB
|
||||||
|
{
|
||||||
|
public class AISWatchkeeper
|
||||||
|
{
|
||||||
|
private static string GetAllWatchkeeperShipsQuery = "SELECT mmsi, name, aktiv, watching, tracking FROM wk_ship";
|
||||||
|
private int mmsi;
|
||||||
|
private string name;
|
||||||
|
private bool aktiv;
|
||||||
|
private bool watching;
|
||||||
|
private bool tracking;
|
||||||
|
|
||||||
|
public int MMSI
|
||||||
|
{
|
||||||
|
get { return this.mmsi; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Aktiv
|
||||||
|
{
|
||||||
|
get { return this.aktiv; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<AISWatchkeeper> GetWatchkeeperShips(DBConnector con)
|
||||||
|
{
|
||||||
|
List<AISWatchkeeper> result = new List<AISWatchkeeper>();
|
||||||
|
IDataReader reader = con.ExecuteQuery(AISWatchkeeper.GetAllWatchkeeperShipsQuery);
|
||||||
|
if (reader == null) return result;
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
AISWatchkeeper wkShip = new AISWatchkeeper();
|
||||||
|
wkShip.mmsi = reader.GetInt32(0);
|
||||||
|
wkShip.name = reader.GetString(1);
|
||||||
|
wkShip.aktiv = reader.GetBoolean(2);
|
||||||
|
wkShip.watching = reader.GetBoolean(3);
|
||||||
|
wkShip.tracking = reader.GetBoolean(4);
|
||||||
|
result.Add(wkShip);
|
||||||
|
}
|
||||||
|
reader.Close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
212
AIS/bsmd.AISService/DB/DBConnector.cs
Normal file
212
AIS/bsmd.AISService/DB/DBConnector.cs
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
// Copyright (c) 2008-2018 schick Informatik
|
||||||
|
// Description: Database connector
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.SqlClient;
|
||||||
|
|
||||||
|
using bsmd.AISService.AIS;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.DB
|
||||||
|
{
|
||||||
|
|
||||||
|
public class DBConnector
|
||||||
|
{
|
||||||
|
private string connectionString;
|
||||||
|
private SqlConnection dbCon = null;
|
||||||
|
private List<AISWatchkeeper> watchkeeperShips = null;
|
||||||
|
private List<AISStaticData> dbShips = null;
|
||||||
|
private Dictionary<string, AISStation> updateStations = null;
|
||||||
|
|
||||||
|
public DBConnector() { }
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public string ConnectionString
|
||||||
|
{
|
||||||
|
get { return this.connectionString; }
|
||||||
|
set { this.connectionString = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AISStaticData> DBShips
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.dbShips == null)
|
||||||
|
{
|
||||||
|
lock (this.dbCon)
|
||||||
|
{
|
||||||
|
this.dbShips = AISStaticData.LoadDBShips(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.dbShips;
|
||||||
|
}
|
||||||
|
set { this.dbShips = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AISWatchkeeper> WatchkeeperShips
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.watchkeeperShips == null) this.watchkeeperShips = AISWatchkeeper.GetWatchkeeperShips(this);
|
||||||
|
return this.watchkeeperShips;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region public methods
|
||||||
|
|
||||||
|
public SqlDataReader ExecuteQuery(string query)
|
||||||
|
{
|
||||||
|
if (!this.CheckConnection()) return null;
|
||||||
|
|
||||||
|
SqlCommand cmd = new SqlCommand(query, this.dbCon);
|
||||||
|
return cmd.ExecuteReader();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ExecuteNonQuery(string query)
|
||||||
|
{
|
||||||
|
if (!this.CheckConnection()) return 0;
|
||||||
|
SqlCommand cmd = new SqlCommand(query, this.dbCon);
|
||||||
|
return cmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ExecuteScalar(string query)
|
||||||
|
{
|
||||||
|
if (!this.CheckConnection()) return 0;
|
||||||
|
SqlCommand cmd = new SqlCommand(query, this.dbCon);
|
||||||
|
return cmd.ExecuteScalar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Open()
|
||||||
|
{
|
||||||
|
if (this.dbCon != null && this.dbCon.State == System.Data.ConnectionState.Open) return true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.dbCon = new SqlConnection(this.connectionString);
|
||||||
|
this.dbCon.Open();
|
||||||
|
if (this.dbCon.State == System.Data.ConnectionState.Open)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (SqlException anException)
|
||||||
|
{
|
||||||
|
Trace.WriteLine(string.Format("cannot open SQL DB connection: {0}", anException.Message));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (this.dbCon != null && this.dbCon.State == System.Data.ConnectionState.Open)
|
||||||
|
this.dbCon.Close();
|
||||||
|
}
|
||||||
|
catch (Exception) { } // egal
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(AIS_Target target)
|
||||||
|
{
|
||||||
|
if (this.dbCon.State != System.Data.ConnectionState.Open) // reopen
|
||||||
|
{
|
||||||
|
this.dbCon.Close();
|
||||||
|
this.dbCon.Open();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.updateStations == null)
|
||||||
|
{
|
||||||
|
this.updateStations = new Dictionary<string, AISStation>();
|
||||||
|
Trace.WriteLine("loading stations..");
|
||||||
|
List<AISStation> stations = AISStation.LoadStations(this);
|
||||||
|
Trace.WriteLine(string.Format("{0} stations loaded", stations.Count));
|
||||||
|
foreach (AISStation station in stations)
|
||||||
|
if (!updateStations.ContainsKey(station.Name))
|
||||||
|
updateStations.Add(station.Name, station);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.LastPosReport != null)
|
||||||
|
{
|
||||||
|
Hotposition hotposition = Hotposition.LoadForMMSI(target.MMSI, this);
|
||||||
|
int? pid = AISPosReport.Save(target, this, updateStations.ContainsKey(target.Station) ? updateStations[target.Station] : null);
|
||||||
|
if (pid.HasValue)
|
||||||
|
{
|
||||||
|
hotposition.PosReportId = pid.Value;
|
||||||
|
hotposition.Save(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Trace.WriteLine(string.Format("last pos report is null for target {0}", target.MMSI));
|
||||||
|
}
|
||||||
|
if (target.LastStaticData != null)
|
||||||
|
{
|
||||||
|
AISStaticData.Save(target, this, updateStations.ContainsKey(target.Station) ? updateStations[target.Station] : null);
|
||||||
|
}
|
||||||
|
if ((target.Name == null || target.LastDBName == null) && (target.MMSI > 0))
|
||||||
|
{
|
||||||
|
// preload values from DB
|
||||||
|
AISStaticData.PreloadTarget(target, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
target.UpdateDB = false; // reset update flag
|
||||||
|
// Watchkeeper check
|
||||||
|
|
||||||
|
if (this.watchkeeperShips == null)
|
||||||
|
this.watchkeeperShips = AISWatchkeeper.GetWatchkeeperShips(this);
|
||||||
|
|
||||||
|
|
||||||
|
if (!target.IsWatchkeeperShip.HasValue && this.watchkeeperShips != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < this.watchkeeperShips.Count; i++)
|
||||||
|
{
|
||||||
|
if (this.watchkeeperShips[i].MMSI == target.MMSI) // found it
|
||||||
|
target.IsWatchkeeperShip = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!target.IsWatchkeeperShip.HasValue) // didn't find it
|
||||||
|
target.IsWatchkeeperShip = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetWatchkeeperList()
|
||||||
|
{
|
||||||
|
this.watchkeeperShips = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveStation(AISStation station)
|
||||||
|
{
|
||||||
|
station.Save(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region private methods
|
||||||
|
|
||||||
|
private bool CheckConnection()
|
||||||
|
{
|
||||||
|
// if connection has been closed, re-open the connection
|
||||||
|
if (this.dbCon.State != System.Data.ConnectionState.Open)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.dbCon.Close();
|
||||||
|
this.Open();
|
||||||
|
}
|
||||||
|
catch (SqlException ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Trace.WriteLine(ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.dbCon.State == System.Data.ConnectionState.Open;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
83
AIS/bsmd.AISService/DB/Hotposition.cs
Normal file
83
AIS/bsmd.AISService/DB/Hotposition.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.SqlClient;
|
||||||
|
using bsmd.AISService.AIS;
|
||||||
|
|
||||||
|
namespace bsmd.AISService.DB
|
||||||
|
{
|
||||||
|
internal class Hotposition
|
||||||
|
{
|
||||||
|
private int id;
|
||||||
|
private int mmsi;
|
||||||
|
private int pid;
|
||||||
|
|
||||||
|
public int MMSI
|
||||||
|
{
|
||||||
|
get { return this.mmsi; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int PosReportId
|
||||||
|
{
|
||||||
|
get { return this.pid; }
|
||||||
|
set { this.pid = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save(DBConnector con)
|
||||||
|
{
|
||||||
|
string query = string.Format("UPDATE hotposition SET mmsi={0}, pid={1} WHERE id={2}",
|
||||||
|
this.mmsi, this.pid, this.id);
|
||||||
|
con.ExecuteNonQuery(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Hotposition LoadForMMSI(int mmsi, DBConnector con)
|
||||||
|
{
|
||||||
|
List<Hotposition> results = new List<Hotposition>();
|
||||||
|
string query = string.Format("SELECT id, pid FROM hotposition WHERE mmsi={0}", mmsi);
|
||||||
|
SqlDataReader reader = con.ExecuteQuery(query);
|
||||||
|
if (reader != null)
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
Hotposition hp = new Hotposition();
|
||||||
|
hp.id = reader.GetInt32(0);
|
||||||
|
hp.mmsi = mmsi;
|
||||||
|
if (!reader.IsDBNull(1))
|
||||||
|
hp.pid = reader.GetInt32(1);
|
||||||
|
results.Add(hp);
|
||||||
|
}
|
||||||
|
reader.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (results.Count == 0)
|
||||||
|
{
|
||||||
|
// neuen Eintrag erzeugen
|
||||||
|
Hotposition hp = new Hotposition();
|
||||||
|
string insertQuery = string.Format("INSERT INTO hotposition SET mmsi={0}", mmsi);
|
||||||
|
con.ExecuteNonQuery(insertQuery);
|
||||||
|
|
||||||
|
object ob = con.ExecuteScalar("SELECT LAST_INSERT_ID()");
|
||||||
|
hp.id = Convert.ToInt32(ob);
|
||||||
|
hp.mmsi = mmsi;
|
||||||
|
return hp;
|
||||||
|
}
|
||||||
|
else if (results.Count == 1)
|
||||||
|
{
|
||||||
|
return results[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// überschüssige HP's löschen (jeweils nur eins pro MMSI)
|
||||||
|
for (int i = 1; i < results.Count; i++)
|
||||||
|
{
|
||||||
|
string delQuery = string.Format("DELETE FROM hotposition WHERE id={0}", results[i].id);
|
||||||
|
con.ExecuteNonQuery(delQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
127
AIS/bsmd.AISService/Program.cs
Normal file
127
AIS/bsmd.AISService/Program.cs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
// Copyright (c) 2008-2018 schick Informatik
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Configuration.Install;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.ServiceProcess;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace bsmd.AISService
|
||||||
|
{
|
||||||
|
static class Program
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The main entry point for the application.
|
||||||
|
/// </summary>
|
||||||
|
public static int Main(string[] args)
|
||||||
|
{
|
||||||
|
if (Environment.UserInteractive)
|
||||||
|
{
|
||||||
|
if (args.Length > 0)
|
||||||
|
{
|
||||||
|
string arg = args[0].ToLowerInvariant().Substring(0, 2);
|
||||||
|
switch (arg)
|
||||||
|
{
|
||||||
|
case "/i": // install
|
||||||
|
return InstallService();
|
||||||
|
|
||||||
|
case "/u": // uninstall
|
||||||
|
return UninstallService();
|
||||||
|
|
||||||
|
default: // unknown option
|
||||||
|
Console.WriteLine("Argument not recognized: {0}", args[0]);
|
||||||
|
Console.WriteLine(string.Empty);
|
||||||
|
DisplayUsage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DisplayUsage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ServiceBase[] ServicesToRun;
|
||||||
|
ServicesToRun = new ServiceBase[]
|
||||||
|
{
|
||||||
|
new AISService()
|
||||||
|
};
|
||||||
|
ServiceBase.Run(ServicesToRun);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DisplayUsage()
|
||||||
|
{
|
||||||
|
//..
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int InstallService()
|
||||||
|
{
|
||||||
|
var service = new AISService();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// perform specific install steps for our queue service.
|
||||||
|
//service.InstallService();
|
||||||
|
|
||||||
|
// install the service with the Windows Service Control Manager (SCM)
|
||||||
|
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (ex.InnerException != null && ex.InnerException.GetType() == typeof(Win32Exception))
|
||||||
|
{
|
||||||
|
Win32Exception wex = (Win32Exception)ex.InnerException;
|
||||||
|
Console.WriteLine("Error(0x{0:X}): Service already installed!", wex.ErrorCode);
|
||||||
|
return wex.ErrorCode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.ToString());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int UninstallService()
|
||||||
|
{
|
||||||
|
var service = new AISService();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// perform specific uninstall steps for our queue service
|
||||||
|
//service.UninstallService();
|
||||||
|
|
||||||
|
// uninstall the service from the Windows Service Control Manager (SCM)
|
||||||
|
ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (ex.InnerException.GetType() == typeof(Win32Exception))
|
||||||
|
{
|
||||||
|
Win32Exception wex = (Win32Exception)ex.InnerException;
|
||||||
|
Console.WriteLine("Error(0x{0:X}): Service not installed!", wex.ErrorCode);
|
||||||
|
return wex.ErrorCode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.ToString());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
36
AIS/bsmd.AISService/Properties/AssemblyInfo.cs
Normal file
36
AIS/bsmd.AISService/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("bsmd.AISService")]
|
||||||
|
[assembly: AssemblyDescription("Windows Service zum Einlesen von AIS Daten aus einem TCP/IP Datenstrom")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("schick Informatik")]
|
||||||
|
[assembly: AssemblyProduct("bsmd.AISService")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("a26a6de3-8505-4ec2-9eb5-12e5ebe83b11")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
35
AIS/bsmd.AISService/Properties/Settings.Designer.cs
generated
Normal file
35
AIS/bsmd.AISService/Properties/Settings.Designer.cs
generated
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace bsmd.AISService.Properties {
|
||||||
|
|
||||||
|
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
|
||||||
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
|
|
||||||
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
|
public static Settings Default {
|
||||||
|
get {
|
||||||
|
return defaultInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.ApplicationScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||||
|
public string ConnectionString {
|
||||||
|
get {
|
||||||
|
return ((string)(this["ConnectionString"]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
AIS/bsmd.AISService/Properties/Settings.settings
Normal file
9
AIS/bsmd.AISService/Properties/Settings.settings
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="bsmd.AISService.Properties" GeneratedClassName="Settings">
|
||||||
|
<Profiles />
|
||||||
|
<Settings>
|
||||||
|
<Setting Name="ConnectionString" Type="System.String" Scope="Application">
|
||||||
|
<Value Profile="(Default)" />
|
||||||
|
</Setting>
|
||||||
|
</Settings>
|
||||||
|
</SettingsFile>
|
||||||
126
AIS/bsmd.AISService/bsmd.AISService.csproj
Normal file
126
AIS/bsmd.AISService/bsmd.AISService.csproj
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{A26A6DE3-8505-4EC2-9EB5-12E5EBE83B11}</ProjectGuid>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>bsmd.AISService</RootNamespace>
|
||||||
|
<AssemblyName>bsmd.AISService</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<SignAssembly>true</SignAssembly>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<AssemblyOriginatorKeyFile>bsmdKey.snk</AssemblyOriginatorKeyFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>packages\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Configuration.Install" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Management" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.ServiceProcess" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="AISService.cs">
|
||||||
|
<SubType>Component</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="AISService.Designer.cs">
|
||||||
|
<DependentUpon>AISService.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="AIS\AIS.cs" />
|
||||||
|
<Compile Include="AIS\AIS_ClassB.cs" />
|
||||||
|
<Compile Include="AIS\AIS_ClassBExt.cs" />
|
||||||
|
<Compile Include="AIS\AIS_ClassBStatic.cs" />
|
||||||
|
<Compile Include="AIS\AIS_Configuration.cs" />
|
||||||
|
<Compile Include="AIS\AIS_Decoder.cs" />
|
||||||
|
<Compile Include="AIS\AIS_PosReport.cs" />
|
||||||
|
<Compile Include="AIS\AIS_QueueManager.cs" />
|
||||||
|
<Compile Include="AIS\AIS_StaticData.cs" />
|
||||||
|
<Compile Include="AIS\AIS_Target.cs" />
|
||||||
|
<Compile Include="AIS\AIS_Target_Comparer.cs" />
|
||||||
|
<Compile Include="AIS\AIS_Telnet.cs" />
|
||||||
|
<Compile Include="AIS\NMEA.cs" />
|
||||||
|
<Compile Include="AIS\NMEA_AIS_Sentence.cs" />
|
||||||
|
<Compile Include="AIS\NMEA_PNMLS_Sentence.cs" />
|
||||||
|
<Compile Include="AIS\SerialDataHandler.cs" />
|
||||||
|
<Compile Include="AIS\Serial_IO.cs" />
|
||||||
|
<Compile Include="AIS\TelnetDataHandler.cs" />
|
||||||
|
<Compile Include="DB\AISPosReport.cs" />
|
||||||
|
<Compile Include="DB\AISStaticData.cs" />
|
||||||
|
<Compile Include="DB\AISStation.cs" />
|
||||||
|
<Compile Include="DB\AISWatchkeeper.cs" />
|
||||||
|
<Compile Include="DB\DBConnector.cs" />
|
||||||
|
<Compile Include="DB\Hotposition.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="ProjectInstaller.cs">
|
||||||
|
<SubType>Component</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="ProjectInstaller.Designer.cs">
|
||||||
|
<DependentUpon>ProjectInstaller.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Properties\Settings.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
<None Include="bsmd.AISService.licenseheader" />
|
||||||
|
<None Include="bsmdKey.snk" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
<None Include="Properties\Settings.settings">
|
||||||
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="ProjectInstaller.resx">
|
||||||
|
<DependentUpon>ProjectInstaller.cs</DependentUpon>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
||||||
16
AIS/bsmd.AISService/bsmd.AISService.licenseheader
Normal file
16
AIS/bsmd.AISService/bsmd.AISService.licenseheader
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
extensions: designer.cs generated.cs
|
||||||
|
extensions: .cs .cpp .h
|
||||||
|
// Copyright (c) 2008-2018 schick Informatik
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
|
||||||
|
extensions: .aspx .ascx
|
||||||
|
<%--
|
||||||
|
Copyright (c) 2008-2018 schick Informatik
|
||||||
|
--%>
|
||||||
|
extensions: .vb
|
||||||
|
'Sample license text.
|
||||||
|
extensions: .xml .config .xsd
|
||||||
|
<!--
|
||||||
|
Sample license text.
|
||||||
|
-->
|
||||||
22
AIS/bsmd.AISService/bsmd.AISService.sln
Normal file
22
AIS/bsmd.AISService/bsmd.AISService.sln
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 14
|
||||||
|
VisualStudioVersion = 14.0.25123.0
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bsmd.AISService", "bsmd.AISService.csproj", "{A26A6DE3-8505-4EC2-9EB5-12E5EBE83B11}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{A26A6DE3-8505-4EC2-9EB5-12E5EBE83B11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A26A6DE3-8505-4EC2-9EB5-12E5EBE83B11}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A26A6DE3-8505-4EC2-9EB5-12E5EBE83B11}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A26A6DE3-8505-4EC2-9EB5-12E5EBE83B11}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
BIN
AIS/bsmd.AISService/bsmdKey.snk
Normal file
BIN
AIS/bsmd.AISService/bsmdKey.snk
Normal file
Binary file not shown.
4
AIS/bsmd.AISService/packages.config
Normal file
4
AIS/bsmd.AISService/packages.config
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="log4net" version="2.0.8" targetFramework="net452" />
|
||||||
|
</packages>
|
||||||
@ -26,12 +26,12 @@
|
|||||||
<value>1000</value>
|
<value>1000</value>
|
||||||
</setting>
|
</setting>
|
||||||
<setting name="LockingServerAddress" serializeAs="String">
|
<setting name="LockingServerAddress" serializeAs="String">
|
||||||
<value>http://192.168.2.4/LockingService/LockingService.svc</value>
|
<!--value>http://192.168.2.4/LockingService/LockingService.svc</value-->
|
||||||
<!--value>http://heupferd/bsmd.LockingService/LockingService.svc</value-->
|
<value>http://heupferd/bsmd.LockingService/LockingService.svc</value>
|
||||||
</setting>
|
</setting>
|
||||||
<setting name="ConnectionString" serializeAs="String">
|
<setting name="ConnectionString" serializeAs="String">
|
||||||
<value>Data Source=192.168.2.12;Initial Catalog=nsw;Uid=dfuser;Pwd=dfpasswd;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False</value>
|
<!--value>Data Source=192.168.2.12;Initial Catalog=nsw;Uid=dfuser;Pwd=dfpasswd;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False</value-->
|
||||||
<!--value>Data Source=(localdb)\Projects;Initial Catalog=nsw;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False</value-->
|
<value>Data Source=(localdb)\Projects;Initial Catalog=nsw;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False</value>
|
||||||
</setting>
|
</setting>
|
||||||
</ENI2.Properties.Settings>
|
</ENI2.Properties.Settings>
|
||||||
</applicationSettings>
|
</applicationSettings>
|
||||||
|
|||||||
Binary file not shown.
@ -310,8 +310,8 @@ namespace bsmd.ExcelReadService
|
|||||||
|
|
||||||
if (val.Length == 2)
|
if (val.Length == 2)
|
||||||
{
|
{
|
||||||
this.Conf.ConfirmText(lookup, val, ReadState.OK);
|
|
||||||
val = val.ToUpper();
|
val = val.ToUpper();
|
||||||
|
this.Conf.ConfirmText(lookup, val, ReadState.OK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
|
|||||||
@ -196,7 +196,7 @@ namespace bsmd.database
|
|||||||
|
|
||||||
public override void Validate(List<MessageError> errors, List<MessageViolation> violations)
|
public override void Validate(List<MessageError> errors, List<MessageViolation> violations)
|
||||||
{
|
{
|
||||||
if ((PortArea.Length >= 2) && (PortArea.Length <= 4))
|
if ((PortArea != null) && (PortArea.Length >= 2) && (PortArea.Length <= 4))
|
||||||
{
|
{
|
||||||
if ((RuleEngine.PortAreaChecker != null) && (this.MessageCore != null))
|
if ((RuleEngine.PortAreaChecker != null) && (this.MessageCore != null))
|
||||||
if (!RuleEngine.PortAreaChecker(this.MessageCore.PoC, this.PortArea))
|
if (!RuleEngine.PortAreaChecker(this.MessageCore.PoC, this.PortArea))
|
||||||
@ -204,7 +204,8 @@ namespace bsmd.database
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
errors.Add(RuleEngine.CreateError(ValidationCode.PORTAREA, "PortArea", this.PortArea, "INFO", "", this.Tablename));
|
if(this.MessageCore.PoC != "DEHAM")
|
||||||
|
errors.Add(RuleEngine.CreateError(ValidationCode.PORTAREA, "PortArea", this.PortArea ?? "", "INFO", "", this.Tablename));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user