// -*- c++ -*- // TODO(schwehr): Create an archive of messages that do not decode. #ifndef LIBAIS_AIS_H_ #define LIBAIS_AIS_H_ #include #include #include #include #include //#include #include using std::bitset; using std::ostream; using std::string; using std::vector; #define LIBAIS_VERSION_MAJOR 0 #define LIBAIS_VERSION_MINOR 15 extern "C" { // For configuration scripts to detect libais and the version numbers. int LibAisVersionMajor(); int LibAisVersionMinor(); } namespace libais { // Returns the text in the nth field starting with the first field being 0. // Empty delim_str is not allowed. string GetNthField(const string &str, const size_t n, const string &delim_str); // Returns the number of pad bits in an AIS AIVDM NMEA string. // Returns -1 if there is an error. int GetPad(const string &nmea_str); // Returns the armored payload of an AIS AIVDM NMEA string. // Returns an empty string if there was an error. string GetBody(const string &nmea_str); // Note: Needs to be kept in sync with AIS_STATUS_STRINGS list in ais.cpp. enum AIS_STATUS { AIS_UNINITIALIZED, // Message is not yet completely decoded. AIS_OK, AIS_ERR_BAD_BIT_COUNT, AIS_ERR_BAD_NMEA_CHR, AIS_ERR_BAD_PTR, AIS_ERR_UNKNOWN_MSG_TYPE, AIS_ERR_MSG_NOT_IMPLEMENTED, AIS_ERR_MSG_SUB_NOT_IMPLEMENTED, AIS_ERR_EXPECTED_STRING, AIS_ERR_BAD_MSG_CONTENT, AIS_ERR_MSG_TOO_LONG, AIS_ERR_BAD_SUB_MSG, AIS_ERR_BAD_SUB_SUB_MSG, AIS_STATUS_NUM_CODES }; extern const char *const AIS_STATUS_STRINGS[AIS_STATUS_NUM_CODES]; // Designated Area Codes (DAC) / Maritime Identification Digits define // which country controls a subset of the submessage spaces within // AIS "binary" messages 6, 8, 25, and 26. See: // http://www.itu.int/online/mms/glad/cga_mids.sh?lng=E // http://en.wikipedia.org/w/index.php?title=Maritime_identification_digits // River Information System (RIS): // ECE-TRANS-SC3-2006-10r-RIS.pdf enum Dac { AIS_DAC_0_TEST = 0, AIS_DAC_1_INTERNATIONAL, AIS_DAC_200_RIS = 200, AIS_DAC_201_ALBANIA = 201, AIS_DAC_202_ANDORRA = 202, AIS_DAC_203_AUSTRIA = 203, AIS_DAC_204_AZORES = 204, AIS_DAC_205_BELGIUM = 205, AIS_DAC_206_BELARUS = 206, AIS_DAC_207_BULGARIA = 207, AIS_DAC_208_VATICAN_CITY_STATE = 208, AIS_DAC_209_CYPRUS = 209, AIS_DAC_210_CYPRUS = 210, AIS_DAC_211_GERMANY = 211, AIS_DAC_212_CYPRUS = 212, AIS_DAC_213_GEORGIA = 213, AIS_DAC_214_MOLDOVA = 214, AIS_DAC_215_MALTA = 215, AIS_DAC_216_ARMENIA = 216, AIS_DAC_218_GERMANY = 218, AIS_DAC_219_DENMARK = 219, AIS_DAC_220_DENMARK = 220, AIS_DAC_224_SPAIN = 224, AIS_DAC_225_SPAIN = 225, AIS_DAC_226_FRANCE = 226, AIS_DAC_227_FRANCE = 227, AIS_DAC_228_FRANCE = 228, AIS_DAC_229_MALTA = 229, AIS_DAC_230_FINLAND = 230, AIS_DAC_231_FAROE_ISLANDS = 231, AIS_DAC_232_UNITED_KINGDOM_OF_GREAT_BRITAIN_AND_NORTHERN_IRELAND = 232, AIS_DAC_233_UNITED_KINGDOM_OF_GREAT_BRITAIN_AND_NORTHERN_IRELAND = 233, AIS_DAC_234_UNITED_KINGDOM_OF_GREAT_BRITAIN_AND_NORTHERN_IRELAND = 234, AIS_DAC_235_UNITED_KINGDOM_OF_GREAT_BRITAIN_AND_NORTHERN_IRELAND = 235, AIS_DAC_236_GIBRALTAR = 236, AIS_DAC_237_GREECE = 237, AIS_DAC_238_CROATIA = 238, AIS_DAC_239_GREECE = 239, AIS_DAC_240_GREECE = 240, AIS_DAC_241_GREECE = 241, AIS_DAC_242_MOROCCO = 242, AIS_DAC_243_HUNGARY = 243, AIS_DAC_244_NETHERLANDS = 244, AIS_DAC_245_NETHERLANDS = 245, AIS_DAC_246_NETHERLANDS = 246, AIS_DAC_247_ITALY = 247, AIS_DAC_248_MALTA = 248, AIS_DAC_249_MALTA = 249, AIS_DAC_250_IRELAND = 250, AIS_DAC_251_ICELAND = 251, AIS_DAC_252_LIECHTENSTEIN = 252, AIS_DAC_253_LUXEMBOURG = 253, AIS_DAC_254_MONACO = 254, AIS_DAC_255_MADEIRA = 255, AIS_DAC_256_MALTA = 256, AIS_DAC_257_NORWAY = 257, AIS_DAC_258_NORWAY = 258, AIS_DAC_259_NORWAY = 259, AIS_DAC_261_POLAND = 261, AIS_DAC_262_MONTENEGRO = 262, AIS_DAC_263_PORTUGAL = 263, AIS_DAC_264_ROMANIA = 264, AIS_DAC_265_SWEDEN = 265, AIS_DAC_266_SWEDEN = 266, AIS_DAC_267_SLOVAKIA = 267, AIS_DAC_268_SAN_MARINO = 268, AIS_DAC_269_SWITZERLAND = 269, AIS_DAC_270_CZECH_REPUBLIC = 270, AIS_DAC_271_TURKEY = 271, AIS_DAC_272_UKRAINE = 272, AIS_DAC_273_RUSSIAN_FEDERATION = 273, AIS_DAC_274_MACEDONIA = 274, AIS_DAC_275_LATVIA = 275, AIS_DAC_276_ESTONIA = 276, AIS_DAC_277_LITHUANIA = 277, AIS_DAC_278_SLOVENIA = 278, AIS_DAC_279_SERBIA = 279, AIS_DAC_301_ANGUILLA = 301, AIS_DAC_303_ALASKA = 303, AIS_DAC_304_ANTIGUA_AND_BARBUDA = 304, AIS_DAC_305_ANTIGUA_AND_BARBUDA = 305, AIS_DAC_306_NETHERLANDS_ANTILLES = 306, AIS_DAC_307_ARUBA = 307, AIS_DAC_308_BAHAMAS = 308, AIS_DAC_309_BAHAMAS = 309, AIS_DAC_310_BERMUDA = 310, AIS_DAC_311_BAHAMAS = 311, AIS_DAC_312_BELIZE = 312, AIS_DAC_314_BARBADOS = 314, AIS_DAC_316_CANADA = 316, AIS_DAC_319_CAYMAN_ISLANDS = 319, AIS_DAC_321_COSTA_RICA = 321, AIS_DAC_323_CUBA = 323, AIS_DAC_325_DOMINICA = 325, AIS_DAC_327_DOMINICAN_REPUBLIC = 327, AIS_DAC_329_GUADELOUPE = 329, AIS_DAC_330_GRENADA = 330, AIS_DAC_331_GREENLAND = 331, AIS_DAC_332_GUATEMALA = 332, AIS_DAC_334_HONDURAS = 334, AIS_DAC_336_HAITI = 336, AIS_DAC_338_UNITED_STATES_OF_AMERICA = 338, AIS_DAC_339_JAMAICA = 339, AIS_DAC_341_SAINT_KITTS_AND_NEVIS = 341, AIS_DAC_343_SAINT_LUCIA = 343, AIS_DAC_345_MEXICO = 345, AIS_DAC_347_MARTINIQUE = 347, AIS_DAC_348_MONTSERRAT = 348, AIS_DAC_350_NICARAGUA = 350, AIS_DAC_351_PANAMA = 351, AIS_DAC_352_PANAMA = 352, AIS_DAC_353_PANAMA = 353, AIS_DAC_354_PANAMA = 354, AIS_DAC_355_PANAMA = 355, AIS_DAC_356_PANAMA = 356, AIS_DAC_357_PANAMA = 357, AIS_DAC_358_PUERTO_RICO = 358, AIS_DAC_359_EL_SALVADOR = 359, AIS_DAC_361_SAINT_PIERRE_AND_MIQUELON = 361, AIS_DAC_362_TRINIDAD_AND_TOBAGO = 362, AIS_DAC_364_TURKS_AND_CAICOS_ISLANDS = 364, AIS_DAC_366_UNITED_STATES_OF_AMERICA = 366, AIS_DAC_367_UNITED_STATES_OF_AMERICA = 367, AIS_DAC_368_UNITED_STATES_OF_AMERICA = 368, AIS_DAC_369_UNITED_STATES_OF_AMERICA = 369, AIS_DAC_370_PANAMA = 370, AIS_DAC_371_PANAMA = 371, AIS_DAC_372_PANAMA = 372, AIS_DAC_373_PANAMA = 373, AIS_DAC_375_SAINT_VINCENT_AND_THE_GRENADINES = 375, AIS_DAC_376_SAINT_VINCENT_AND_THE_GRENADINES = 376, AIS_DAC_377_SAINT_VINCENT_AND_THE_GRENADINES = 377, AIS_DAC_378_BRITISH_VIRGIN_ISLANDS = 378, AIS_DAC_379_UNITED_STATES_VIRGIN_ISLANDS = 379, AIS_DAC_401_AFGHANISTAN = 401, AIS_DAC_403_SAUDI_ARABIA = 403, AIS_DAC_405_BANGLADESH = 405, AIS_DAC_408_BAHRAIN = 408, AIS_DAC_410_BHUTAN = 410, AIS_DAC_412_CHINA = 412, AIS_DAC_413_CHINA = 413, AIS_DAC_414_CHINA = 414, AIS_DAC_416_TAIWAN = 416, AIS_DAC_417_SRI_LANKA = 417, AIS_DAC_419_INDIA = 419, AIS_DAC_422_IRAN = 422, AIS_DAC_423_AZERBAIJAN = 423, AIS_DAC_425_IRAQ = 425, AIS_DAC_428_ISRAEL = 428, AIS_DAC_431_JAPAN = 431, AIS_DAC_432_JAPAN = 432, AIS_DAC_434_TURKMENISTAN = 434, AIS_DAC_436_KAZAKHSTAN = 436, AIS_DAC_437_UZBEKISTAN = 437, AIS_DAC_438_JORDAN = 438, AIS_DAC_440_KOREA = 440, AIS_DAC_441_KOREA = 441, AIS_DAC_443_STATE_OF_PALESTINE = 443, AIS_DAC_445_DEMOCRATIC_PEOPLES_REPUBLIC_OF_KOREA = 445, AIS_DAC_447_KUWAIT = 447, AIS_DAC_450_LEBANON = 450, AIS_DAC_451_KYRGYZ_REPUBLIC = 451, AIS_DAC_453_MACAO = 453, AIS_DAC_455_MALDIVES = 455, AIS_DAC_457_MONGOLIA = 457, AIS_DAC_459_NEPAL = 459, AIS_DAC_461_OMAN = 461, AIS_DAC_463_PAKISTAN = 463, AIS_DAC_466_QATAR = 466, AIS_DAC_468_SYRIAN_ARAB_REPUBLIC = 468, AIS_DAC_470_UNITED_ARAB_EMIRATES = 470, AIS_DAC_472_TAJIKISTAN = 472, AIS_DAC_473_YEMEN = 473, AIS_DAC_475_YEMEN = 475, AIS_DAC_477_HONG_KONG = 477, AIS_DAC_478_BOSNIA_AND_HERZEGOVINA = 478, AIS_DAC_501_ADELIE_LAND = 501, AIS_DAC_503_AUSTRALIA = 503, AIS_DAC_506_MYANMAR = 506, AIS_DAC_508_BRUNEI_DARUSSALAM = 508, AIS_DAC_510_MICRONESIA = 510, AIS_DAC_511_PALAU = 511, AIS_DAC_512_NEW_ZEALAND = 512, AIS_DAC_514_CAMBODIA = 514, AIS_DAC_515_CAMBODIA = 515, AIS_DAC_516_CHRISTMAS_ISLAND = 516, AIS_DAC_518_COOK_ISLANDS = 518, AIS_DAC_520_FIJI = 520, AIS_DAC_523_COCOS = 523, AIS_DAC_525_INDONESIA = 525, AIS_DAC_529_KIRIBATI = 529, AIS_DAC_531_LAO_PEOPLES_DEMOCRATIC_REPUBLIC = 531, AIS_DAC_533_MALAYSIA = 533, AIS_DAC_536_NORTHERN_MARIANA_ISLANDS = 536, AIS_DAC_538_MARSHALL_ISLANDS = 538, AIS_DAC_540_NEW_CALEDONIA = 540, AIS_DAC_542_NIUE = 542, AIS_DAC_544_NAURU = 544, AIS_DAC_546_FRENCH_POLYNESIA = 546, AIS_DAC_548_PHILIPPINES = 548, AIS_DAC_553_PAPUA_NEW_GUINEA = 553, AIS_DAC_555_PITCAIRN_ISLAND = 555, AIS_DAC_557_SOLOMON_ISLANDS = 557, AIS_DAC_559_AMERICAN_SAMOA = 559, AIS_DAC_561_SAMOA = 561, AIS_DAC_563_SINGAPORE = 563, AIS_DAC_564_SINGAPORE = 564, AIS_DAC_565_SINGAPORE = 565, AIS_DAC_566_SINGAPORE = 566, AIS_DAC_567_THAILAND = 567, AIS_DAC_570_TONGA = 570, AIS_DAC_572_TUVALU = 572, AIS_DAC_574_VIETNAM = 574, AIS_DAC_576_VANUATU = 576, AIS_DAC_577_VANUATU = 577, AIS_DAC_578_WALLIS_AND_FUTUNA_ISLANDS = 578, AIS_DAC_601_SOUTH_AFRICA = 601, AIS_DAC_603_ANGOLA = 603, AIS_DAC_605_ALGERIA = 605, AIS_DAC_607_SAINT_PAUL_AND_AMSTERDAM_ISLANDS = 607, AIS_DAC_608_ASCENSION_ISLAND = 608, AIS_DAC_609_BURUNDI = 609, AIS_DAC_610_BENIN = 610, AIS_DAC_611_BOTSWANA = 611, AIS_DAC_612_CENTRAL_AFRICAN_REPUBLIC = 612, AIS_DAC_613_CAMEROON = 613, AIS_DAC_615_CONGO = 615, AIS_DAC_616_COMOROS = 616, AIS_DAC_617_CABO_VERDE = 617, AIS_DAC_618_CROZET_ARCHIPELAGO = 618, AIS_DAC_619_COTE_DIVOIRE = 619, AIS_DAC_620_COMOROS = 620, AIS_DAC_621_DJIBOUTI = 621, AIS_DAC_622_EGYPT = 622, AIS_DAC_624_ETHIOPIA = 624, AIS_DAC_625_ERITREA = 625, AIS_DAC_626_GABONESE_REPUBLIC = 626, AIS_DAC_627_GHANA = 627, AIS_DAC_629_GAMBIA = 629, AIS_DAC_630_GUINEABISSAU = 630, AIS_DAC_631_EQUATORIAL_GUINEA = 631, AIS_DAC_632_GUINEA = 632, AIS_DAC_633_BURKINA_FASO = 633, AIS_DAC_634_KENYA = 634, AIS_DAC_635_KERGUELEN_ISLANDS = 635, AIS_DAC_636_LIBERIA = 636, AIS_DAC_637_LIBERIA = 637, AIS_DAC_638_SOUTH_SUDAN = 638, AIS_DAC_642_LIBYA = 642, AIS_DAC_644_LESOTHO = 644, AIS_DAC_645_MAURITIUS = 645, AIS_DAC_647_MADAGASCAR = 647, AIS_DAC_649_MALI = 649, AIS_DAC_650_MOZAMBIQUE = 650, AIS_DAC_654_MAURITANIA = 654, AIS_DAC_655_MALAWI = 655, AIS_DAC_656_NIGER = 656, AIS_DAC_657_NIGERIA = 657, AIS_DAC_659_NAMIBIA = 659, AIS_DAC_660_REUNION = 660, AIS_DAC_661_RWANDA = 661, AIS_DAC_662_SUDAN = 662, AIS_DAC_663_SENEGAL = 663, AIS_DAC_664_SEYCHELLES = 664, AIS_DAC_665_SAINT_HELENA = 665, AIS_DAC_666_SOMALIA = 666, AIS_DAC_667_SIERRA_LEONE = 667, AIS_DAC_668_SAO_TOME_AND_PRINCIPE = 668, AIS_DAC_669_SWAZILAND = 669, AIS_DAC_670_CHAD = 670, AIS_DAC_671_TOGOLESE_REPUBLIC = 671, AIS_DAC_672_TUNISIA = 672, AIS_DAC_674_TANZANIA = 674, AIS_DAC_675_UGANDA = 675, AIS_DAC_676_DEMOCRATIC_REPUBLIC_OF_THE_CONGO = 676, AIS_DAC_677_TANZANIA = 677, AIS_DAC_678_ZAMBIA = 678, AIS_DAC_679_ZIMBABWE = 679, AIS_DAC_701_ARGENTINE_REPUBLIC = 701, AIS_DAC_710_BRAZIL = 710, AIS_DAC_720_BOLIVIA = 720, AIS_DAC_725_CHILE = 725, AIS_DAC_730_COLOMBIA = 730, AIS_DAC_735_ECUADOR = 735, AIS_DAC_740_FALKLAND_ISLANDS = 740, AIS_DAC_745_GUIANA = 745, AIS_DAC_750_GUYANA = 750, AIS_DAC_755_PARAGUAY = 755, AIS_DAC_760_PERU = 760, AIS_DAC_765_SURINAME = 765, AIS_DAC_770_URUGUAY = 770, AIS_DAC_775_VENEZUELA = 775 }; class AisPoint { public: double lng_deg; double lat_deg; AisPoint(); AisPoint(double lng_deg_, double lat_deg_); }; ostream& operator<< (ostream &o, const AisPoint &position); ////////////////////////////////////////////////////////////////////// // Support class for decoding ////////////////////////////////////////////////////////////////////// static const int MAX_BITS = 1192; class AisBitset : protected bitset { public: AisBitset(); AIS_STATUS ParseNmeaPayload(const char *nmea_payload, int pad); int GetNumBits() const { return num_bits; } int GetNumChars() const { return num_chars; } int GetPosition() const { return current_position; } int GetRemaining() const { return num_bits - current_position; } const AisBitset& SeekRelative(int d) const; const AisBitset& SeekTo(size_t pos) const; bool operator[](size_t pos) const; unsigned int ToUnsignedInt(const size_t start, const size_t len) const; int ToInt(const size_t start, const size_t len) const; string ToString(const size_t start, const size_t len) const; const AisPoint ToAisPoint(const size_t start, const size_t point_size) const; // Visible for testing. static bitset<6> Reverse(const bitset<6> &bits); protected: int num_bits; int num_chars; static bool nmea_ord_initialized_; static bitset<6> nmea_ord_[128]; static const char bits_to_char_tbl_[]; static void InitNmeaOrd(); private: // This will help uncover dicontinuities when querying sequential bits, i.e. // when we query a bit sequence that is not in direct succession of the // previous one. In the future, we may use this to automatically determine // the next read location. // This field is also used to determine the number of remaining bits after the // last read position. // That being said, the 'start' argument in all the 'To...' methods above is // redundant and the only purpose is to discover typos in the bit positions in // each message's parse method, i.e. debugging. mutable int current_position; }; class AisMsg { public: int message_id; int repeat_indicator; int mmsi; // TODO(schwehr): make status private and have accessors. bool had_error() const { return status != AIS_OK; } AIS_STATUS get_error() const { return status; } virtual ~AisMsg() {} size_t numBits() { return num_bits; } protected: AIS_STATUS status; // AIS_OK or error code int num_chars; // Number of characters in the nmea_payload. size_t num_bits; // Number of bits in the nmea_payload. AisBitset bits; // The bitset that was constructed out of the nmea_payload. AisMsg() : status(AIS_UNINITIALIZED), num_chars(0), num_bits(0), bits() {} AisMsg(const char *nmea_payload, const size_t pad); // Returns true if the msg is in a good state "so far", i.e. either AIS_OK or // AIS_UNINITIALIZED. bool CheckStatus() const; }; // TODO(schwehr): factor out commstate from all messages? class Ais1_2_3 : public AisMsg { public: int nav_status; bool rot_over_range; int rot_raw; float rot; float sog; // Knots. int position_accuracy; AisPoint position; float cog; // Degrees. int true_heading; // TODO(schwehr): What about a leap second when timestamp 60 may be valid? int timestamp; int special_manoeuvre; int spare; bool raim; // COMM state SOTDMA msgs 1 and 2 int sync_state; // SOTDMA and ITDMA bool slot_timeout_valid; int slot_timeout; // Based on slot_timeout which ones are valid bool received_stations_valid; int received_stations; bool slot_number_valid; int slot_number; bool utc_valid; int utc_hour; int utc_min; int utc_spare; bool slot_offset_valid; int slot_offset; // ITDMA - msg type 3 bool slot_increment_valid; int slot_increment; bool slots_to_allocate_valid; int slots_to_allocate; bool keep_flag_valid; bool keep_flag; // 3.3.7.3.2 Annex 2 ITDMA. Table 20 Ais1_2_3(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais1_2_3 &msg); // 4 bsreport and 11 utc date response class Ais4_11 : public AisMsg { public: int year; int month; int day; int hour; int minute; int second; int position_accuracy; AisPoint position; int fix_type; int transmission_ctl; int spare; bool raim; // COMM state SOTDMA msgs 1 and 2 int sync_state; int slot_timeout; // Based on slot_timeout which ones are valid bool received_stations_valid; int received_stations; bool slot_number_valid; int slot_number; bool utc_valid; int utc_hour; int utc_min; int utc_spare; bool slot_offset_valid; int slot_offset; // **NO** ITDMA Ais4_11(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais4_11 &msg); class Ais5 : public AisMsg { public: int ais_version; int imo_num; string callsign; string name; int type_and_cargo; int dim_a; int dim_b; int dim_c; int dim_d; int fix_type; int eta_month; int eta_day; int eta_hour; int eta_minute; float draught; // present static draft. m string destination; int dte; int spare; Ais5(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais5 &msg); // AIS Binary Broadcast message ... parent to many class Ais6 : public AisMsg { public: int seq; // sequence number int mmsi_dest; bool retransmit; int spare; int dac; // dac+fi = app id int fi; // TODO(schwehr): how to make Ais6 protected? Ais6(const char *nmea_payload, const size_t pad); protected: Ais6() {} }; ostream& operator<< (ostream &o, const Ais6 &msg); // http://www.e-navigation.nl/content/monitoring-aids-navigation // Zeni Lite Buoy Co., Ltd buoy status. class Ais6_0_0 : public Ais6 { public: int sub_id; float voltage; float current; bool dc_power_supply; // False is AC. bool light_on; bool battery_low; bool off_position; int spare2; Ais6_0_0(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais6_0_0 &msg); // Text message. ITU 1371-1 class Ais6_1_0 : public Ais6 { public: bool ack_required; int msg_seq; string text; int spare2; Ais6_1_0(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais6_1_0 &msg); // Application ack. ITU 1371-1 class Ais6_1_1 : public Ais6 { public: int ack_dac; int msg_seq; int spare2; Ais6_1_1(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais6_1_1 &msg); // Interrogation for a DAC/FI. ITU 1371-1 class Ais6_1_2 : public Ais6 { public: int req_dac; int req_fi; // TODO(schwehr): spare2? Ais6_1_2(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais6_1_2 &msg); // Capability interogation. ITU 1371-1 class Ais6_1_3 : public Ais6 { public: unsigned int req_dac; unsigned int spare2; unsigned int spare3; unsigned int spare4; Ais6_1_3(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais6_1_3 &msg); // Capability interogation reply. ITU 1371-1 // 5.4 International function message 4: Capability reply class Ais6_1_4 : public Ais6 { public: int ack_dac; std::array capabilities; std::array cap_reserved; // 126 bits of spare. So dumb. int spare2; int spare3; int spare4; int spare5; Ais6_1_4(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais6_1_4 &msg); // International function message 5: Application ack to addr binary message. class Ais6_1_5 : public Ais6 { public: // TODO(schwehr): How to handle the sequence number and retransmit flag? int ack_dac; int ack_fi; int seq_num; bool ai_available; // TODO(schwehr): AI? Is this the dac/fi being acked? int ai_response; int spare; int spare2; Ais6_1_5(const char *nmea_payload, const size_t pad); }; // IMO Circ 236 Dangerous cargo indication // Not to be transmitted after 2012-Jan-01 class Ais6_1_12 : public Ais6 { public: string last_port; int utc_month_dep; // actual time of departure int utc_day_dep; int utc_hour_dep; int utc_min_dep; string next_port; int utc_month_next; // estimated arrival int utc_day_next; int utc_hour_next; int utc_min_next; string main_danger; string imo_cat; int un; int value; // TODO(schwehr): units? int value_unit; int spare2; Ais6_1_12(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais6_1_12 &msg); class Ais6_1_14_Window { public: AisPoint position; int utc_hour_from; int utc_min_from; int utc_hour_to; int utc_min_to; int cur_dir; float cur_speed; }; // IMO Circ 236 Tidal window // Not to be transmitted after 2012-Jan-01 class Ais6_1_14 : public Ais6 { public: int utc_month; int utc_day; vector windows; Ais6_1_14(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais6_1_14 &msg); // IMO Circ 289 Clearance time to enter port class Ais6_1_18 : public Ais6 { public: int link_id; int utc_month; int utc_day; int utc_hour; int utc_min; string port_berth; string dest; AisPoint position; std::array spare2; // 32 bits per spare Ais6_1_18(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais6_1_18 &msg); // IMO Circ 289 Berthing data class Ais6_1_20 : public Ais6 { public: int link_id; int length; float depth; int mooring_position; int utc_month; int utc_day; int utc_hour; int utc_min; bool services_known; // TODO(schwehr): enum of service types std::array services; string name; AisPoint position; Ais6_1_20(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais6_1_20 &msg); class Ais6_1_25_Cargo { public: int code_type; bool imdg_valid; // also set with BC int imdg; bool spare_valid; int spare; // imdg or dc or marpols bool un_valid; int un; bool bc_valid; int bc; bool marpol_oil_valid; int marpol_oil; bool marpol_cat_valid; int marpol_cat; Ais6_1_25_Cargo(); // TODO(schwehr): Add a constructor from an AisBitset. }; // IMO Circ 289 Dangerous cargo indication 2 // Replaces 8_1_12? class Ais6_1_25 : public Ais6 { public: int amount_unit; int amount; vector cargos; // 0 to 17 cargo entries Ais6_1_25(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais6_1_25 &msg); // TODO(schwehr): Addressed sensor report 6_1_26. // TODO(schwehr): IMO Circ 289 Route information 6_1_28. // TODO(schwehr): IMO Circ 289 Text description 6_1_30. // IMO Circ 289 // Warning: The bit encoding for 6_1_14_Window and 6_1_32 on // the wire has x and y in a different order. // TODO(schwehr): Reuse Ais6_1_14_Window class Ais6_1_32_Window { public: AisPoint position; int from_utc_hour; int from_utc_min; int to_utc_hour; int to_utc_min; int cur_dir; float cur_speed; // knots Ais6_1_32_Window(); }; // IMO Circ 289 Tidal window class Ais6_1_32 : public Ais6 { public: int utc_month; int utc_day; vector windows; Ais6_1_32(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais6_1_32 &msg); // Number of persons on board. ITU 1371-1 class Ais6_1_40 : public Ais6 { public: int persons; int spare2; Ais6_1_40(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais6_1_40 &msg); ////////////////////////////////////////////////////////////////////// // 7 and 13 are ACKs for msg 6 and 12 class Ais7_13 : public AisMsg { public: int spare; vector dest_mmsi; vector seq_num; Ais7_13(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais7_13 &msg); // AIS Binary Broadcast message ... parent to many class Ais8 : public AisMsg { public: int spare; // TODO(schwehr): seq? // ITU M.R. 1371-3 Anex 2 5.3.1 int dac; // dac+fi = app id int fi; // TODO(schwehr): make Ais8 protected Ais8(const char *nmea_payload, const size_t pad); protected: Ais8() {} }; ostream& operator<< (ostream &o, const Ais8 &msg); // Text telegram ITU 1371-1 class Ais8_1_0 : public Ais8 { public: bool ack_required; int msg_seq; string text; int spare2; Ais8_1_0(const char *nmea_payload, size_t pad); }; ostream& operator<< (ostream &o, const Ais8_1_0 &msg); // 8_1_1 No message // 8_1_2 No message // 8_1_3 No message // 8_1_4 No message // IMO Circ 289 met hydro - Not to be transmitted after 2013-Jan-01 // See also IMO Circ 236 class Ais8_1_11 : public Ais8 { public: AisPoint position; int day; int hour; int minute; int wind_ave; // kts int wind_gust; // kts int wind_dir; int wind_gust_dir; float air_temp; // C int rel_humid; float dew_point; float air_pres; int air_pres_trend; float horz_vis; // NM float water_level; // m int water_level_trend; float surf_cur_speed; int surf_cur_dir; float cur_speed_2; // kts int cur_dir_2; int cur_depth_2; // m float cur_speed_3; // kts int cur_dir_3; int cur_depth_3; // m float wave_height; // m int wave_period; int wave_dir; float swell_height; int swell_period; int swell_dir; int sea_state; // beaufort scale float water_temp; int precip_type; float salinity; // Part per mil (1/1000). int ice; // yes/no/undef/unknown int spare2; int extended_water_level; // OHMEX uses this for extra water level precision Ais8_1_11(const char *nmea_payload, size_t pad); }; ostream& operator<< (ostream &o, const Ais8_1_11 &msg); // IMO Circ 236 Fairway closed - Not to be transmitted after 2012-Jan-01 class Ais8_1_13 : public Ais8 { public: string reason; string location_from; string location_to; int radius; int units; // TODO(schwehr): utc? warning: day/month out of order int day_from; int month_from; int hour_from; int minute_from; int day_to; int month_to; int hour_to; int minute_to; int spare2; Ais8_1_13(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais8_1_13 &msg); // IMO Circ 236 Extended ship static and voyage data // Not to be transmitted after 2012-Jan-01 class Ais8_1_15 : public Ais8 { public: float air_draught; int spare2; Ais8_1_15(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais8_1_15 &msg); // IMO Circ 236 Number of persons on board class Ais8_1_16 : public Ais8 { public: int persons; int spare2; Ais8_1_16(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais8_1_16 &msg); class Ais8_1_17_Target { public: int type; string id; int spare; AisPoint position; int cog; int timestamp; int sog; Ais8_1_17_Target(); }; // IMO Circ 236 VTS Generated/synthetic targets class Ais8_1_17 : public Ais8 { public: vector targets; Ais8_1_17(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais8_1_17 &msg); // No 8_1_18 // IMO Circ 289 Marine traffic signal class Ais8_1_19 : public Ais8 { public: int link_id; string name; AisPoint position; // funny bit count int status; int signal; int utc_hour_next; int utc_min_next; int next_signal; std::array spare2; Ais8_1_19(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais8_1_19 &msg); // No message 8_1_20 // IMO Circ 289 Weather observation report from ship class Ais8_1_21 : public Ais8 { public: int type_wx_report; // TYPE 0 string location; AisPoint position; // 25, 24 bits int utc_day; int utc_hour; int utc_min; // wx - use wx[0] float horz_viz; // nautical miles int humidity; // % int wind_speed; // ave knots int wind_dir; float pressure; // hPa - float needed for type 1 int pressure_tendency; float air_temp; // C float water_temp; // C int wave_period; // s float wave_height; int wave_dir; float swell_height; // m int swell_dir; int swell_period; // s int spare2; // TYPE 1 - !@#$!!!!! // x, y int utc_month; // utc_day, hour, min int cog; float sog; int heading; // Assume this is true degrees???? // pressure defined in type 0 float rel_pressure; // 3 hour hPa // pressure_tendenc defined in type 0 // wind_dir defined in type 0 float wind_speed_ms; // m/s int wind_dir_rel; float wind_speed_rel; // m/s float wind_gust_speed; // m/s int wind_gust_dir; int air_temp_raw; // TODO(schwehr): Convert this to C. Kelvin makes no sense // humidity defined in type 0 // sea_temp_k int water_temp_raw; // TODO(schwehr): fix this // hor_viz int wx[3]; // current, past 1, past 2 int cloud_total; int cloud_low; int cloud_low_type; int cloud_middle_type; int cloud_high_type; float alt_lowest_cloud_base; // wave_period // wave_height // swell_dir // swell_period // swell_height int swell_dir_2; int swell_period_2; float swell_height_2; float ice_thickness; // Network is cm, storing m. int ice_accretion; int ice_accretion_cause; int sea_ice_concentration; int amt_type_ice; int ice_situation; int ice_devel; int bearing_ice_edge; Ais8_1_21(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais8_1_21 &msg); const size_t AIS8_1_22_NUM_NAMES = 128; const size_t AIS8_1_22_SUBAREA_SIZE = 87; extern const char *ais8_1_22_notice_names[AIS8_1_22_NUM_NAMES]; enum Ais8_1_22_AreaShapeEnum { AIS8_1_22_SHAPE_ERROR = -1, AIS8_1_22_SHAPE_CIRCLE = 0, // OR Point. AIS8_1_22_SHAPE_RECT = 1, AIS8_1_22_SHAPE_SECTOR = 2, AIS8_1_22_SHAPE_POLYLINE = 3, AIS8_1_22_SHAPE_POLYGON = 4, AIS8_1_22_SHAPE_TEXT = 5, AIS8_1_22_SHAPE_RESERVED_6 = 6, AIS8_1_22_SHAPE_RESERVED_7 = 7 }; extern const char *ais8_1_22_shape_names[8]; // Sub-Areas for the Area Notice class class Ais8_1_22_SubArea { public: virtual Ais8_1_22_AreaShapeEnum getType() const = 0; virtual ~Ais8_1_22_SubArea() {} }; Ais8_1_22_SubArea* ais8_1_22_subarea_factory(const AisBitset &bs, const size_t offset); // or Point if radius is 0 class Ais8_1_22_Circle : public Ais8_1_22_SubArea { public: AisPoint position; // Longitude and latitude. // Going to assume that the precision is not useful. int precision; // How many decimal places for x and y. int radius_m; unsigned int spare; // 18 bits. Ais8_1_22_Circle(const AisBitset &bs, const size_t offset); ~Ais8_1_22_Circle() {} Ais8_1_22_AreaShapeEnum getType() const {return AIS8_1_22_SHAPE_CIRCLE;} }; class Ais8_1_22_Rect : public Ais8_1_22_SubArea { public: AisPoint position; // Longitude and latitude. int precision; // How many decimal places for x and y. Useless. int e_dim_m; // East dimension in meters. int n_dim_m; int orient_deg; // Orientation in degrees from true north. unsigned int spare; // 5 bits. Ais8_1_22_Rect(const AisBitset &bs, const size_t offset); ~Ais8_1_22_Rect() {} Ais8_1_22_AreaShapeEnum getType() const {return AIS8_1_22_SHAPE_RECT;} }; class Ais8_1_22_Sector : public Ais8_1_22_SubArea { public: AisPoint position; // Longitude and latitude. // TODO(schwehr): precision in IMO, but not RTCM. Double check. int precision; // How many decimal places for x and y? int radius_m; int left_bound_deg; int right_bound_deg; Ais8_1_22_Sector(const AisBitset &bs, const size_t offset); ~Ais8_1_22_Sector() {} Ais8_1_22_AreaShapeEnum getType() const {return AIS8_1_22_SHAPE_SECTOR;} }; // Or Waypoint // Must have a point before on the VDL // TODO(schwehr): do I bring in the prior point x, y, precision? class Ais8_1_22_Polyline : public Ais8_1_22_SubArea { public: // TODO(schwehr): int precision; // How many decimal places for x and y. // Up to 4 points vector angles; vector dists_m; unsigned int spare; // 2 bit. Ais8_1_22_Polyline(const AisBitset &bs, const size_t offset); ~Ais8_1_22_Polyline() {} Ais8_1_22_AreaShapeEnum getType() const {return AIS8_1_22_SHAPE_POLYLINE;} }; // TODO(schwehr): Bring in the prior point? And do we fold the sub area data // into one polygon if there are more than one? class Ais8_1_22_Polygon : public Ais8_1_22_SubArea { public: // TODO(schwehr): int precision; // How many decimal places for x and y. // Up to 4 points in a first message, but aggregated if multiple sub areas vector angles; vector dists_m; unsigned int spare; // 2 bit Ais8_1_22_Polygon(const AisBitset &bs, const size_t offset); ~Ais8_1_22_Polygon() {} Ais8_1_22_AreaShapeEnum getType() const {return AIS8_1_22_SHAPE_POLYGON;} }; class Ais8_1_22_Text : public Ais8_1_22_SubArea { public: string text; // TODO(schwehr): spare? Ais8_1_22_Text(const AisBitset &bs, const size_t offset); ~Ais8_1_22_Text() {} Ais8_1_22_AreaShapeEnum getType() const {return AIS8_1_22_SHAPE_TEXT;} }; // Area Notice class class Ais8_1_22 : public Ais8 { public: int link_id; // 10 bit id to match up text blocks. int notice_type; // Area type / Notice Description. int month; // These are in UTC. int day; int hour; int minute; int duration_minutes; // Time from the start until the notice expires. // 1 or more sub messages vector sub_areas; Ais8_1_22(const char *nmea_payload, const size_t pad); ~Ais8_1_22(); }; ostream& operator<< (ostream& o, Ais8_1_22 const& msg); // No message 8_1_23 // IMO Circ 289 Extended ship static and voyage-related class Ais8_1_24 : public Ais8 { public: int link_id; float air_draught; // m string last_port; std::array next_ports; // TODO(schwehr): enum list of param types std::array solas_status; // 0 NA, 1 operational, 2 SNAFU, 3 no data int ice_class; int shaft_power; // horses int vhf; string lloyds_ship_type; int gross_tonnage; int laden_ballast; int heavy_oil; int light_oil; int diesel; int bunker_oil; // tonnes int persons; int spare2; Ais8_1_24(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais8_1_24 &msg); // No message 8_1_25 const size_t AIS8_1_26_REPORT_SIZE = 112; enum Ais8_1_26_SensorEnum { AIS8_1_26_SENSOR_ERROR = -1, AIS8_1_26_SENSOR_LOCATION = 0, AIS8_1_26_SENSOR_STATION = 1, AIS8_1_26_SENSOR_WIND = 2, AIS8_1_26_SENSOR_WATER_LEVEL = 3, AIS8_1_26_SENSOR_CURR_2D = 4, AIS8_1_26_SENSOR_CURR_3D = 5, AIS8_1_26_SENSOR_HORZ_FLOW = 6, AIS8_1_26_SENSOR_SEA_STATE = 7, AIS8_1_26_SENSOR_SALINITY = 8, AIS8_1_26_SENSOR_WX = 9, AIS8_1_26_SENSOR_AIR_DRAUGHT = 10, AIS8_1_26_SENSOR_RESERVED_11 = 11, AIS8_1_26_SENSOR_RESERVED_12 = 12, AIS8_1_26_SENSOR_RESERVED_13 = 13, AIS8_1_26_SENSOR_RESERVED_14 = 14, AIS8_1_26_SENSOR_RESERVED_15 = 15, }; class Ais8_1_26_SensorReport { public: int report_type; int utc_day; int utc_hr; int utc_min; int site_id; // aka link_id virtual Ais8_1_26_SensorEnum getType() const = 0; virtual ~Ais8_1_26_SensorReport() {} }; Ais8_1_26_SensorReport* ais8_1_26_sensor_report_factory(const AisBitset &bs, const size_t offset); class Ais8_1_26_Location : public Ais8_1_26_SensorReport { public: AisPoint position; float z; // alt in m from MSL int owner; int timeout; int spare; Ais8_1_26_Location(const AisBitset &bs, const size_t offset); Ais8_1_26_Location() {} Ais8_1_26_SensorEnum getType() const { return AIS8_1_26_SENSOR_LOCATION; } }; class Ais8_1_26_Station : public Ais8_1_26_SensorReport { public: string name; int spare; Ais8_1_26_Station(const AisBitset &bs, const size_t offset); Ais8_1_26_Station() {} Ais8_1_26_SensorEnum getType() const {return AIS8_1_26_SENSOR_STATION;} }; class Ais8_1_26_Wind : public Ais8_1_26_SensorReport { public: int wind_speed; // knots int wind_gust; // knots int wind_dir; int wind_gust_dir; int sensor_type; int wind_forecast; // knots int wind_gust_forecast; // knots int wind_dir_forecast; int utc_day_forecast; int utc_hour_forecast; int utc_min_forecast; int duration; int spare; Ais8_1_26_Wind(const AisBitset &bs, const size_t offset); Ais8_1_26_Wind() {} Ais8_1_26_SensorEnum getType() const {return AIS8_1_26_SENSOR_WIND;} }; class Ais8_1_26_WaterLevel : public Ais8_1_26_SensorReport { public: int type; float level; // m. assuming it is being stored at 0.01 m inc. int trend; int vdatum; int sensor_type; int forecast_type; float level_forecast; int utc_day_forecast; int utc_hour_forecast; int utc_min_forecast; int duration; // minutes int spare; Ais8_1_26_WaterLevel(const AisBitset &bs, const size_t offset); Ais8_1_26_WaterLevel() {} Ais8_1_26_SensorEnum getType() const {return AIS8_1_26_SENSOR_WATER_LEVEL;} }; class Ais8_1_26_Curr2D_Current { public: float speed; // knots int dir; int depth; // m }; class Ais8_1_26_Curr2D : public Ais8_1_26_SensorReport { public: Ais8_1_26_Curr2D_Current currents[3]; int type; int spare; Ais8_1_26_Curr2D(const AisBitset &bs, const size_t offset); Ais8_1_26_Curr2D() {} Ais8_1_26_SensorEnum getType() const {return AIS8_1_26_SENSOR_CURR_2D;} }; class Ais8_1_26_Curr3D_Current { public: float north; float east; float up; int depth; // m }; class Ais8_1_26_Curr3D : public Ais8_1_26_SensorReport { public: Ais8_1_26_Curr3D_Current currents[2]; int type; int spare; Ais8_1_26_Curr3D(const AisBitset &bs, const size_t offset); Ais8_1_26_Curr3D() {} Ais8_1_26_SensorEnum getType() const {return AIS8_1_26_SENSOR_CURR_3D;} }; class Ais8_1_26_HorzFlow_Current { public: int bearing; // deg int dist; // m float speed; // knots int dir; // deg int level; // m }; class Ais8_1_26_HorzFlow : public Ais8_1_26_SensorReport { public: Ais8_1_26_HorzFlow_Current currents[2]; int spare; Ais8_1_26_HorzFlow(const AisBitset &bs, const size_t offset); Ais8_1_26_HorzFlow() {} Ais8_1_26_SensorEnum getType() const {return AIS8_1_26_SENSOR_HORZ_FLOW;} }; class Ais8_1_26_SeaState : public Ais8_1_26_SensorReport { public: float swell_height; int swell_period; // seconds int swell_dir; // deg int sea_state; int swell_sensor_type; float water_temp; // C float water_temp_depth; // m int water_sensor_type; float wave_height; int wave_period; // seconds int wave_dir; // deg int wave_sensor_type; float salinity; Ais8_1_26_SeaState(const AisBitset &bs, const size_t offset); Ais8_1_26_SeaState() {} Ais8_1_26_SensorEnum getType() const {return AIS8_1_26_SENSOR_SEA_STATE;} }; class Ais8_1_26_Salinity : public Ais8_1_26_SensorReport { public: float water_temp; // C float conductivity; // siemens/m float pressure; // decibars float salinity; // 0/00 ppt int salinity_type; int sensor_type; int spare[2]; Ais8_1_26_Salinity(const AisBitset &bs, const size_t offset); Ais8_1_26_Salinity() {} Ais8_1_26_SensorEnum getType() const {return AIS8_1_26_SENSOR_SALINITY;} }; class Ais8_1_26_Wx : public Ais8_1_26_SensorReport { public: float air_temp; // C int air_temp_sensor_type; int precip; float horz_vis; // nm float dew_point; // C int dew_point_type; float air_pressure; // Pascals (Pa). int air_pressure_trend; int air_pressor_type; float salinity; // 0/00 ppt int spare; Ais8_1_26_Wx(const AisBitset &bs, const size_t offset); Ais8_1_26_Wx() {} Ais8_1_26_SensorEnum getType() const {return AIS8_1_26_SENSOR_WX;} }; class Ais8_1_26_AirDraught : public Ais8_1_26_SensorReport { public: float draught; float gap; float forecast_gap; int trend; int utc_day_forecast; int utc_hour_forecast; int utc_min_forecast; int spare; Ais8_1_26_AirDraught(const AisBitset &bs, const size_t offset); Ais8_1_26_AirDraught() {} Ais8_1_26_SensorEnum getType() const {return AIS8_1_26_SENSOR_AIR_DRAUGHT;} }; // IMO Circ 289 Environmental class Ais8_1_26 : public Ais8 { public: vector reports; Ais8_1_26(const char *nmea_payload, const size_t pad); ~Ais8_1_26(); }; ostream& operator<< (ostream &o, const Ais8_1_26 &msg); // IMO Circ 289 Route information class Ais8_1_27 : public Ais8 { public: int link_id; int sender_type; int route_type; int utc_month; int utc_day; int utc_hour; int utc_min; int duration; vector waypoints; Ais8_1_27(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais8_1_27 &msg); // No message 8_1_28 // IMO Circ 289 Text description class Ais8_1_29 : public Ais8 { public: int link_id; string text; int spare2; Ais8_1_29(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais8_1_29 &msg); // No message 8_1_30 // IMO Circ 289 Meteorological and Hydrographic data // Section 1, Table 1.1 // TODO(schwehr): is this exactly the same as 8_1_11 or has anything changed? // x,y swapped. class Ais8_1_31 : public Ais8 { public: AisPoint position; // Opposite the bit order of 8_1_11 int position_accuracy; // New field int utc_day; int utc_hour; int utc_min; int wind_ave; // kts int wind_gust; // kts int wind_dir; int wind_gust_dir; float air_temp; // C int rel_humid; float dew_point; float air_pres; // Pascals (Pa). int air_pres_trend; float horz_vis; // NM float water_level; // m int water_level_trend; float surf_cur_speed; int surf_cur_dir; float cur_speed_2; // kts int cur_dir_2; int cur_depth_2; // m float cur_speed_3; // kts int cur_dir_3; int cur_depth_3; // m float wave_height; // m int wave_period; int wave_dir; float swell_height; // m int swell_period; int swell_dir; int sea_state; // beaufort scale - Table 1.2 float water_temp; int precip_type; float salinity; int ice; // yes/no/undef/unknown int spare2; Ais8_1_31(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais8_1_31 &msg); // TODO(schwehr): Persons on board ITU 1371-1 8_1_40. // ECE-TRANS-SC3-2006-10e-RIS.pdf - River Information System // Inland ship static and voyage related data class Ais8_200_10 : public Ais8 { public: string eu_id; // European Vessel ID - 8 characters float length; // m float beam; // m int ship_type; int haz_cargo; float draught; int loaded; // Sensor quality. int speed_qual; int course_qual; int heading_qual; int spare2; Ais8_200_10(const char *nmea_payload, const size_t pad); }; // http://www.ris.eu/docs/File/536/vessel_traking_and_tracing_standard_ed1-2_ccnr_23-apr_2013_en.pdf // ETA at lock/bridge/terminal class Ais8_200_21 : public Ais8 { public: string country; // UN country code 0 = not available = default string location; // UN location code 0 = not available = default string section; // Fairway section number 0 = not available = default string terminal; // Terminal code 0 = not available = default string hectometre; // Fairway hectometre 0 = not available = default // Examples for previous fields. See: // http://www.ris.eu/docs/File/427/implementation_location_code_austria.pdf // ETA at lock/bridge/terminal - Estimated Time of Arrival; MMDDHHMM UTC int eta_month; // 1 - 12; 0 = not available = default int eta_day; // 1 - 31; 0 = not available = default int eta_hour; // 0 - 23; 24 = not available = default int eta_minute; // 0 - 59; 60 = not available = default int tugboats; // 0 - 6, 7 = unknown = default // Maximum present static air draught 0 float air_draught; // 4000 (rest not used), in 1/100m, 0 = not used int spare2; // 5 bits Not used, should be set to zero. Ais8_200_21(const char *nmea_payload, const size_t pad); }; // vessel_traking_and_tracing_standard_ed1-2_ccnr_23-apr_2013_en.pdf // RTA at lock/bridge/terminal class Ais8_200_22 : public Ais8 { public: string country; // UN country code 0 = not available string location; // UN location code 0 = not available string section; // Fairway section number 0 = not available string terminal; // Terminal code 0 = not available string hectometre; // Fairway hectometre 0 = not available // Examples for previous fields. See: // http://www.ris.eu/docs/File/427/implementation_location_code_austria.pdf // RTA at lock/bridge/terminal - Recommended Time of Arrival; MMDDHHMM UTC int rta_month; // 0 = not available int rta_day; // 0 = not available int rta_hour; // 24 = not available int rta_minute; // 60 = not available int lock_status; // Lock/bridge/terminal status // 0 = operational // 1 = limited operation // 2 = out of order // 3 = not available int spare2; // Spare Ais8_200_22(const char *nmea_payload, const size_t pad); }; // ECE-TRANS-SC3-2006-10e-RIS.pdf - River Information System // EMMA warning class Ais8_200_23 : public Ais8 { public: int utc_year_start; int utc_month_start; int utc_day_start; int utc_year_end; int utc_month_end; int utc_day_end; int utc_hour_start; int utc_min_start; int utc_hour_end; int utc_min_end; AisPoint position1; AisPoint position2; int type; int min; int max; int classification; int wind_dir; // EMMA CODE int spare2; Ais8_200_23(const char *nmea_payload, const size_t pad); }; // ECE-TRANS-SC3-2006-10e-RIS.pdf - River Information System // Water Level class Ais8_200_24 : public Ais8 { public: // UN 2 letter code. See Comtrade Country Code and Name. // https://unstats.un.org/unsd/tradekb/Knowledgebase/50377/Comtrade-Country-Code-and-Name string country; std::array gauge_ids; std::array levels; // m Ais8_200_24(const char *nmea_payload, const size_t pad); }; // ECE-TRANS-SC3-2006-10e-RIS.pdf - River Information System // Signal status class Ais8_200_40 : public Ais8 { public: AisPoint position; int form; int dir; // degrees int stream_dir; int status_raw; // TODO(schwehr): int status[9]; // WTF is the encoding for this? int spare2; Ais8_200_40(const char *nmea_payload, const size_t pad); }; // ECE-TRANS-SC3-2006-10e-RIS.pdf - River Information System // Number of persons on board class Ais8_200_55 : public Ais8 { public: int crew; int passengers; int yet_more_personnel; std::array spare2; // 51 spare bits. Ais8_200_55(const char *nmea_payload, const size_t pad); }; enum Ais8_366_22_AreaShapeEnum { AIS8_366_22_SHAPE_ERROR = -1, AIS8_366_22_SHAPE_CIRCLE = 0, AIS8_366_22_SHAPE_RECT = 1, AIS8_366_22_SHAPE_SECTOR = 2, AIS8_366_22_SHAPE_POLYLINE = 3, AIS8_366_22_SHAPE_POLYGON = 4, AIS8_366_22_SHAPE_TEXT = 5, AIS8_366_22_SHAPE_RESERVED_6 = 6, AIS8_366_22_SHAPE_RESERVED_7 = 7 }; extern const char *shape_names[8]; class Ais8_366_22_SubArea { public: virtual Ais8_366_22_AreaShapeEnum getType() = 0; virtual ~Ais8_366_22_SubArea() { } }; Ais8_366_22_SubArea* ais8_366_22_subarea_factory(const AisBitset &bs, const size_t offset); // or Point if radius is 0 class Ais8_366_22_Circle : public Ais8_366_22_SubArea { public: AisPoint position; // TODO(schwehr): int precision int radius_m; unsigned int spare; Ais8_366_22_Circle(const AisBitset &bs, const size_t offset); ~Ais8_366_22_Circle() {} Ais8_366_22_AreaShapeEnum getType() {return AIS8_366_22_SHAPE_CIRCLE;} }; class Ais8_366_22_Rect : public Ais8_366_22_SubArea { public: AisPoint position; // longitude and latitude // TODO(schwehr): int precision int e_dim_m; // East dimension in meters int n_dim_m; int orient_deg; // Orientation in degrees from true north unsigned int spare; // 5 bits Ais8_366_22_Rect(const AisBitset &bs, const size_t offset); ~Ais8_366_22_Rect() {} Ais8_366_22_AreaShapeEnum getType() {return AIS8_366_22_SHAPE_RECT;} }; class Ais8_366_22_Sector : public Ais8_366_22_SubArea { public: AisPoint position; // TODO(schwehr): int precision int radius_m; int left_bound_deg; int right_bound_deg; // TODO(schwehr): spare? Ais8_366_22_Sector(const AisBitset &bs, const size_t offset); ~Ais8_366_22_Sector() {} Ais8_366_22_AreaShapeEnum getType() {return AIS8_366_22_SHAPE_SECTOR;} }; // Or Waypoint // Must have a point before on the VDL, but pulled together here. class Ais8_366_22_Polyline : public Ais8_366_22_SubArea { public: AisPoint position; // longitude and latitude // TODO(schwehr): precision // Up to 4 points vector angles; vector dists_m; unsigned int spare; Ais8_366_22_Polyline(const AisBitset &bs, const size_t offset); ~Ais8_366_22_Polyline() {} Ais8_366_22_AreaShapeEnum getType() {return AIS8_366_22_SHAPE_POLYLINE;} }; class Ais8_366_22_Polygon : public Ais8_366_22_SubArea { public: AisPoint position; // longitude and latitude // TODO(schwehr): precision? // Up to 4 points in a first message, but aggregated if multiple sub areas vector angles; vector dists_m; unsigned int spare; Ais8_366_22_Polygon(const AisBitset &bs, const size_t offset); ~Ais8_366_22_Polygon() {} Ais8_366_22_AreaShapeEnum getType() {return AIS8_366_22_SHAPE_POLYGON;} }; class Ais8_366_22_Text : public Ais8_366_22_SubArea { public: string text; unsigned int spare; // 3 bits Ais8_366_22_Text(const AisBitset &bs, const size_t offset); ~Ais8_366_22_Text() {} Ais8_366_22_AreaShapeEnum getType() {return AIS8_366_22_SHAPE_TEXT;} }; class Ais8_366_22 : public Ais8 { public: // Common block at the front int link_id; // 10 bit id to match up text blocks int notice_type; // area_type / Notice Description int month; // These really are in utc int day; int utc_hour; int utc_minute; int duration_minutes; // Time from the start until the notice expires // 1 or more sub messages vector sub_areas; Ais8_366_22(const char *nmea_payload, const size_t pad); ~Ais8_366_22(); }; ostream& operator<< (ostream& o, Ais8_366_22 const& msg); const size_t AIS8_366_22_NUM_NAMES = 128; extern const char *ais8_366_22_notice_names[AIS8_366_22_NUM_NAMES]; // 366 34 - Kurt older whale message 2008-2010 // TODO(schwehr): Ais8_366_34 // USCG Blue Force encrypted message. class Ais8_366_56 : public Ais8 { public: vector encrypted; Ais8_366_56(const char *nmea_payload, const size_t pad); }; class Ais8_367_22_SubArea { public: virtual Ais8_366_22_AreaShapeEnum getType() const = 0; virtual ~Ais8_367_22_SubArea() { } }; Ais8_367_22_SubArea* ais8_367_22_subarea_factory(const AisBitset &bs, const size_t offset); class Ais8_367_22_Circle : public Ais8_367_22_SubArea { public: AisPoint position; int precision; int radius_m; unsigned int spare; Ais8_367_22_Circle(const AisBitset &bs, const size_t offset); ~Ais8_367_22_Circle() {} Ais8_366_22_AreaShapeEnum getType() const {return AIS8_366_22_SHAPE_CIRCLE;} }; class Ais8_367_22_Rect : public Ais8_367_22_SubArea { public: AisPoint position; int precision; int e_dim_m; int n_dim_m; int orient_deg; unsigned int spare; Ais8_367_22_Rect(const AisBitset &bs, const size_t offset); ~Ais8_367_22_Rect() {} Ais8_366_22_AreaShapeEnum getType() const {return AIS8_366_22_SHAPE_RECT;} }; class Ais8_367_22_Sector : public Ais8_367_22_SubArea { public: AisPoint position; int precision; int radius_m; int left_bound_deg; int right_bound_deg; int spare; Ais8_367_22_Sector(const AisBitset &bs, const size_t offset); ~Ais8_367_22_Sector() {} Ais8_366_22_AreaShapeEnum getType() const {return AIS8_366_22_SHAPE_SECTOR;} }; // Polyline or Polygon class Ais8_367_22_Poly : public Ais8_367_22_SubArea { public: Ais8_366_22_AreaShapeEnum shape; AisPoint position; int precision; // Up to 4 points vector angles; vector dists_m; unsigned int spare; Ais8_367_22_Poly(const AisBitset &bs, const size_t offset, Ais8_366_22_AreaShapeEnum area_shape); ~Ais8_367_22_Poly() {} Ais8_366_22_AreaShapeEnum getType() const {return shape;} }; class Ais8_367_22_Text : public Ais8_367_22_SubArea { public: string text; unsigned int spare; // 3 bits Ais8_367_22_Text(const AisBitset &bs, const size_t offset); ~Ais8_367_22_Text() {} Ais8_366_22_AreaShapeEnum getType() const {return AIS8_366_22_SHAPE_TEXT;} }; class Ais8_367_22 : public Ais8 { public: int version; int link_id; int notice_type; int month; int day; int hour; int minute; int duration_minutes; int spare2; vector sub_areas; Ais8_367_22(const char *nmea_payload, const size_t pad); ~Ais8_367_22(); }; ostream& operator<< (ostream& o, Ais8_367_22 const& msg); class Ais9 : public AisMsg { public: int alt; // m above sea level int sog; int position_accuracy; AisPoint position; float cog; int timestamp; int alt_sensor; int spare; int dte; int spare2; int assigned_mode; bool raim; int commstate_flag; int sync_state; // In both SOTDMA and ITDMA // SOTDMA bool slot_timeout_valid; int slot_timeout; // Based on slot_timeout which ones are valid bool received_stations_valid; int received_stations; bool slot_number_valid; int slot_number; bool utc_valid; int utc_hour; int utc_min; int utc_spare; bool slot_offset_valid; int slot_offset; // ITDMA bool slot_increment_valid; int slot_increment; bool slots_to_allocate_valid; int slots_to_allocate; bool keep_flag_valid; bool keep_flag; Ais9(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais9 &msg); // 10 ":" - UTC and date inquiry class Ais10 : public AisMsg { public: int spare; int dest_mmsi; int spare2; Ais10(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais10 &msg); // 11 ';' - See 4_11 // 12 - '<' - Addressed safety related text. class Ais12 : public AisMsg { public: int seq_num; int dest_mmsi; bool retransmitted; int spare; string text; int spare2; Ais12(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais12 &msg); // 13 '=' - See 7 // 14 - '>' - Safety broadcast text. class Ais14 : public AisMsg { public: int spare; string text; int spare2; Ais14(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais14 &msg); // 15 - '?' - Interrogation class Ais15 : public AisMsg { public: int spare; int mmsi_1; int msg_1_1; int slot_offset_1_1; int spare2; int dest_msg_1_2; int slot_offset_1_2; int spare3; int mmsi_2; int msg_2; int slot_offset_2; int spare4; Ais15(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais15 &msg); // 16 - '@' - Assigned mode command class Ais16 : public AisMsg { public: int spare; int dest_mmsi_a; int offset_a; int inc_a; int dest_mmsi_b; int offset_b; int inc_b; int spare2; Ais16(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais16 &msg); // ITU-R M.823 http://www.itu.int/rec/R-REC-M.823/en // 17 - 'A' - GNSS broacast - TODO(schwehr): only partially coded class Ais17 : public AisMsg { public: int spare; AisPoint position; int spare2; int gnss_type; int z_cnt; int station; int seq; // N - do not need to store this int health; // TODO(schwehr): Handle payload Ais17(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais17 &msg); // 18 - 'B' - Class B position report class Ais18 : public AisMsg { public: int spare; float sog; int position_accuracy; AisPoint position; // Long and lat float cog; int true_heading; int timestamp; int spare2; int unit_flag; // 0 is SOTDMA, 1 is Carrier Sense (CS). int display_flag; int dsc_flag; int band_flag; int m22_flag; int mode_flag; bool raim; int commstate_flag; // SOTDMA int sync_state; bool slot_timeout_valid; int slot_timeout; // Based on slot_timeout which ones are valid bool received_stations_valid; int received_stations; bool slot_number_valid; int slot_number; bool utc_valid; int utc_hour; int utc_min; int utc_spare; bool slot_offset_valid; int slot_offset; // ITDMA bool slot_increment_valid; int slot_increment; bool slots_to_allocate_valid; int slots_to_allocate; bool keep_flag_valid; bool keep_flag; // If commstate set to 1 for Carrier Sense (CS) devices, there is no // state and the commstate region is supposed to be filled with this value: // 1100000000000000110 bool commstate_cs_fill_valid; int commstate_cs_fill; Ais18(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais18 &msg); // 19 - 'C' - Class B extended ship and position class Ais19 : public AisMsg { public: int spare; float sog; int position_accuracy; AisPoint position; // Long and lat float cog; int true_heading; int timestamp; int spare2; string name; int type_and_cargo; int dim_a; int dim_b; int dim_c; int dim_d; int fix_type; bool raim; int dte; int assigned_mode; int spare3; Ais19(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais19 &msg); // 20 - 'D' - Data link management // TODO(schwehr): consider a vector class Ais20 : public AisMsg { public: int spare; int offset_1; int num_slots_1; int timeout_1; int incr_1; bool group_valid_2; int offset_2; int num_slots_2; int timeout_2; int incr_2; bool group_valid_3; int offset_3; int num_slots_3; int timeout_3; int incr_3; bool group_valid_4; int offset_4; int num_slots_4; int timeout_4; int incr_4; int spare2; Ais20(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais20 &msg); // 21 - 'E' - Aids to navigation report class Ais21 : public AisMsg { public: int aton_type; string name; int position_accuracy; AisPoint position; int dim_a; int dim_b; int dim_c; int dim_d; int fix_type; int timestamp; bool off_pos; int aton_status; bool raim; bool virtual_aton; bool assigned_mode; int spare; // Extended name goes on the end of name int spare2; Ais21(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais21 &msg); // 22 - 'F' - Channel Management class Ais22 : public AisMsg { public: int spare; int chan_a; int chan_b; int txrx_mode; bool power_low; // if addressed false, then geographic position bool pos_valid; AisPoint position1; AisPoint position2; // if addressed is true bool dest_valid; int dest_mmsi_1; int dest_mmsi_2; int chan_a_bandwidth; int chan_b_bandwidth; int zone_size; int spare2; // Lame that they make a huge spare here. Bad bad bad Ais22(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais22 &msg); // 23 - 'G' - Group Assignment Command class Ais23 : public AisMsg { public: int spare; AisPoint position1; AisPoint position2; int station_type; int type_and_cargo; int spare2; // 22 bits of spare here? what were people thinking? int txrx_mode; int interval_raw; // raw value, not sec int quiet; int spare3; Ais23(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais23 &msg); // 24 - 'H' - Class B Static Data report class Ais24 : public AisMsg { public: int part_num; // Part A string name; // Part B int type_and_cargo; string vendor_id; string callsign; int dim_a; int dim_b; int dim_c; int dim_d; int spare; // Part C - Not defined by ITU 1371-5 // Part D - Not defined by ITU 1371-5 Ais24(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais24 &msg); // 25 - 'I' - Single slot binary message - addressed or broadcast // TODO(schwehr): handle payload class Ais25 : public AisMsg { public: bool use_app_id; // if false, payload is unstructured binary. bool dest_mmsi_valid; int dest_mmsi; // only valid if addressed // If unstructured: // TODO(schwehr): vector payload; int dac; // valid if use_app_id is true int fi; Ais25(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais25 &msg); // 26 - 'J' - Multi slot binary message with comm state // TODO(schwehr): handle payload class Ais26 : public AisMsg { public: bool use_app_id; // if false, payload is unstructured binary bool dest_mmsi_valid; int dest_mmsi; // only valid if addressed int dac; // valid it use_app_id int fi; // TODO(schwehr): vector payload; // If unstructured. Yuck. int commstate_flag; // 0 - SOTDMA, 1 - TDMA // SOTDMA int sync_state; bool slot_timeout_valid; int slot_timeout; // Based on slot_timeout which ones are valid bool received_stations_valid; int received_stations; bool slot_number_valid; int slot_number; bool utc_valid; int utc_hour; int utc_min; int utc_spare; bool slot_offset_valid; int slot_offset; // ITDMA bool slot_increment_valid; int slot_increment; bool slots_to_allocate_valid; int slots_to_allocate; bool keep_flag_valid; bool keep_flag; Ais26(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais26 &msg); // 27 - 'K' - Long-range position report - e.g. for satellite receivers class Ais27 : public AisMsg { public: int position_accuracy; bool raim; int nav_status; AisPoint position; int sog; // Knots. int cog; // Degrees. bool gnss; // warning: bits in AIS are flipped sense int spare; Ais27(const char *nmea_payload, const size_t pad); }; ostream& operator<< (ostream &o, const Ais27 &msg); } // namespace libais #endif // LIBAIS_AIS_H_