using log4net; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace bsmd.AIS2Service { internal abstract class AISClass { #region constant defs protected const double ERAD = 6378.135; protected const double DE2RA = 0.01745329252; protected const double AVG_ERAD = 6371.0; #endregion #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 fields private AISType _type = AISType.AIS_NONE; protected int _mmsi; protected string _data; private static readonly ILog _log = LogManager.GetLogger(typeof(AISClass)); #endregion #region Properties public AISType MessageType { get { return this._type; } } public int MMSI { get { return _mmsi; } } #endregion #region abstract method signatures protected abstract Status Decode(); #endregion #region static methods internal static AISClass Decode(string data, ref Status status) { if (data == null || data.Length == 0) { status = Status.ILLEGAL_ARGUMENT; return null; } BitArray bits = AISClass.DecodeChar(data[0]); int type = AISClass.GetInt(bits, 0, 5); AISClass result = AISClass.CreateMessage(type); if (result != null) { result._data = data; status = result.Decode(); } else { status = Status.UNSUPPORTED; } return result; } /// /// Factory method to create messages based on the message type /// protected static AISClass CreateMessage(int type) { AISClass 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 4: result = new AIS_BaseStationReport(); result._type = AISType.BASE_STATION_REPORT; 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: // _log.InfoFormat("No decoder for AIS class {0}", (AISType)type); 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 uint GetUInt(BitArray bits, int lo, int hi) { uint result = 0; uint 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 /// /// mehr dazu hier: /// http://www.codeguru.com/cpp/cpp/algorithms/general/article.php/c5115/ /// public static double GetDistance(double lat1, double lon1, double lat2, double lon2) { lat1 *= DE2RA; lon1 *= DE2RA; lat2 *= DE2RA; lon2 *= DE2RA; double d = Math.Sin(lat1) * Math.Sin(lat2) + Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(lon1 - lon2); return (AVG_ERAD * Math.Acos(d)); } #endregion #endregion #region overrides public override string ToString() { return Enum.GetName(typeof(AISClass.AISType), this.MessageType); } #endregion } }