using System; using System.Collections; using System.Diagnostics; using System.Text; using log4net; namespace bsmd.AIS2Service { internal class AIS_StaticData : AISClass { #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; private static readonly ILog _log = LogManager.GetLogger(typeof(AIS_StaticData)); #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 int DBShipType { get { return this.shiptype; } } public int DBDimension { get { return this.dimension; } } public int DBTypeOfDevice { get { return this.typeofdevice; } } public int DTE { get { return this.dte; } } public int Spare { get { return this.spare; } } public string DBETA { get { if (this.eta.HasValue) { return this.eta.Value.ToString("yyyy-MM-ddTHH:mm:ss.000Z"); } else { return ""; } } } #endregion #region abstract method implementation protected override Status Decode() { BitArray bits = DecodeBinary(_data); Status result = Status.OK; if (bits.Count < 424) { _log.WarnFormat("AISStaticData truncated: {0}/424", bits.Count); result = Status.PARSE_ERROR; } else { try { int type = GetInt(bits, 0, 5); if (type != 5) { result = Status.ILLEGAL_ARGUMENT; } else { _mmsi = GetInt(bits, 6, 37); this.ais_version = GetInt(bits, 38, 39); this.imoNumber = GetInt(bits, 40, 69); StringBuilder sb_callsign = new StringBuilder(7); for (int i = 0; i < 7; i++) { int cval = GetInt(bits, 70 + (6 * i), 75 + (6 * i)); char ch = 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 = GetInt(bits, 112 + (6 * i), 117 + (6 * i)); char ch = GetAISChar(cval); if (ch == '@') ch = ' '; sb_name.Append(ch); } this.name = sb_name.ToString().Trim(); this.shiptype = GetInt(bits, 232, 239); this.dimension = GetInt(bits, 240, 269); this.a = GetInt(bits, 240, 248); this.b = GetInt(bits, 249, 257); this.c = GetInt(bits, 258, 263); this.d = GetInt(bits, 264, 269); this.typeofdevice = GetInt(bits, 270, 273); this.etamonth = GetInt(bits, 274, 277); this.etaday = GetInt(bits, 278, 282); this.etahour = GetInt(bits, 283, 287); this.etaminute = 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 e) { _log.WarnFormat("ETA timestamp creation failed: {0}", e.Message); } this.maxpresetstaticdraught = GetInt(bits, 294, 301); StringBuilder sb_destination = new StringBuilder(20); for (int i = 0; i < 20; i++) { int cval = GetInt(bits, 302 + (6 * i), 307 + (6 * i)); char ch = GetAISChar(cval); if (ch == '@') break; //ch = ' '; // alles nach einem @ nicht mehr beachten sb_destination.Append(ch); } this.destination = sb_destination.ToString().Trim(); this.dte = GetInt(bits, 422, 422); this.spare = GetInt(bits, 423, 423); } } catch (Exception e) { _log.WarnFormat("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 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 } }