mirror of
https://github.com/peterantypas/maiana.git
synced 2025-05-16 23:40:08 -07:00
2441 lines
60 KiB
C++
2441 lines
60 KiB
C++
// -*- c++ -*-
|
|
|
|
// TODO(schwehr): Create an archive of messages that do not decode.
|
|
|
|
#ifndef LIBAIS_AIS_H_
|
|
#define LIBAIS_AIS_H_
|
|
|
|
#include <array>
|
|
#include <bitset>
|
|
#include <cassert>
|
|
#include <cstring>
|
|
#include <string>
|
|
//#include <iostream>
|
|
#include <vector>
|
|
|
|
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<MAX_BITS> {
|
|
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<int, 64> capabilities;
|
|
std::array<int, 64> 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<Ais6_1_14_Window> 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<int, 2> 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<int, 26> 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<Ais6_1_25_Cargo> 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<Ais6_1_32_Window> 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<int> dest_mmsi;
|
|
vector<int> 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<Ais8_1_17_Target> 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<int, 4> 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<float> angles;
|
|
vector<float> 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<float> angles;
|
|
vector<float> 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<Ais8_1_22_SubArea *> 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<std::string, 2> next_ports;
|
|
|
|
// TODO(schwehr): enum list of param types
|
|
std::array<int, 26> 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<Ais8_1_26_SensorReport *> 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<AisPoint> 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<int, 4> gauge_ids;
|
|
std::array<float, 4> 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<int, 3> 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<float> angles;
|
|
vector<float> 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<float> angles;
|
|
vector<float> 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<Ais8_366_22_SubArea *> 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<unsigned char> 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<float> angles;
|
|
vector<float> 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<Ais8_367_22_SubArea *> 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<unsigned char> 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<unsigned char> 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_
|