Ais21::Ais21(const char *nmea_payload, const size_t pad) : AisMsg(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(message_id == 21); const size_t num_bits = strlen(nmea_payload) * 6 - pad; // TODO(schwehr): make this more careful than 272-360 if (num_bits < 272 || num_bits > 360) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<360> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } aton_type = ubits(bs, 38, 5); name = ais_str(bs, 43, 120); position_accuracy = bs[163]; x = sbits(bs, 164, 28) / 600000.; y = sbits(bs, 192, 27) / 600000.; dim_a = ubits(bs, 219, 9); dim_b = ubits(bs, 228, 9); dim_c = ubits(bs, 237, 6); dim_d = ubits(bs, 243, 6); fix_type = ubits(bs, 249, 4); timestamp = ubits(bs, 253, 6); off_pos = bs[259]; aton_status = ubits(bs, 260, 8); raim = bs[268]; virtual_aton = bs[269]; assigned_mode = bs[270]; spare = bs[271]; const size_t extra_total_bits = num_bits - 272; const size_t extra_chars = extra_total_bits / 6; const size_t extra_char_bits = extra_chars * 6; const size_t extra_bits = extra_total_bits % 6; if (extra_chars > 0) { name += ais_str(bs, 272, extra_char_bits); } if (extra_bits > 0) { spare2 = ubits(bs, 272 + extra_char_bits, extra_bits); } else { spare2 = 0; } status = AIS_OK; }
Ais24::Ais24(const char *nmea_payload, const size_t pad) : AisMsg(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(message_id == 24); const int num_bits = std::strlen(nmea_payload) * 6 - pad; if (num_bits != 160 && num_bits != 168) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<168> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } part_num = ubits(bs, 38, 2); switch (part_num) { case 0: // Part A if (num_bits != 160) { status = AIS_ERR_BAD_BIT_COUNT; return; } name = ais_str(bs, 40, 120); type_and_cargo = -1; dim_a = dim_b = dim_c = dim_d = spare = -1; break; case 1: // Part B if (num_bits != 168) { status = AIS_ERR_BAD_BIT_COUNT; return; } type_and_cargo = ubits(bs, 40, 8); vendor_id = ais_str(bs, 48, 42); callsign = ais_str(bs, 90, 42); dim_a = ubits(bs, 132, 9); dim_b = ubits(bs, 141, 9); dim_c = ubits(bs, 150, 6); dim_d = ubits(bs, 156, 6); spare = ubits(bs, 162, 6); break; case 2: // FALLTHROUGH - not yet defined by ITU case 3: // FALLTHROUGH - not yet defined by ITU default: status = AIS_ERR_BAD_MSG_CONTENT; return; } status = AIS_OK; }
Ais21::Ais21(const char *nmea_payload, const int pad) { assert(nmea_payload); init(); const size_t num_bits = strlen(nmea_payload) * 6 - pad; // 272-360 - FIX: make this more careful if (272 > num_bits || num_bits > 360) { status = AIS_ERR_BAD_BIT_COUNT; return; } std::bitset<360> bs; // 360 % 6 == 0 -> 60 NMEA characters exactly status = aivdm_to_bits(bs, nmea_payload); if (had_error()) return; message_id = ubits(bs, 0, 6); if (message_id != 21) {status = AIS_ERR_WRONG_MSG_TYPE; return;} repeat_indicator = ubits(bs,6,2); mmsi = ubits(bs,8,30); aton_type = ubits(bs,38,5); name = ais_str(bs, 43, 120); position_accuracy = bs[163]; x = sbits(bs, 164, 28) / 600000.; y = sbits(bs, 192, 27) / 600000.; dim_a = ubits(bs, 219, 9); dim_b = ubits(bs, 228, 9); dim_c = ubits(bs, 237, 6); dim_d = ubits(bs, 243, 6); fix_type = ubits(bs, 249, 4); timestamp = ubits(bs, 253, 6); off_pos = bool(bs[259]); aton_status = ubits(bs, 260, 8); raim = bool(bs[268]); virtual_aton = bool(bs[269]); assigned_mode = bool(bs[270]); spare = bs[271]; const size_t extra_total_bits = num_bits - 272; const size_t extra_chars = extra_total_bits / 6; const size_t extra_char_bits = extra_chars * 6; const size_t extra_bits = extra_total_bits % 6; if (extra_chars > 0) { name += ais_str(bs,272,extra_char_bits); } if (extra_bits > 0) { spare2 = ubits(bs,272+extra_char_bits, extra_bits); } else { spare2 = 0; } }
// River Information Systems ECE-TRANS-SC3-2006-10r-RIS.pdf // Inland ship static and voyage related data Ais8_200_10::Ais8_200_10(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 200); assert(fi == 10); const size_t num_bits = strlen(nmea_payload) * 6 - pad; if (num_bits != 168) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<168> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } eu_id = ais_str(bs, 56, 48); length = (float)(ubits(bs, 104, 13) / 10.0); // m //Crouse:Added typecasting beam = (float)(ubits(bs, 117, 10) / 10.0); // m //Crouse:Added typecasting ship_type = ubits(bs, 127, 14); haz_cargo = ubits(bs, 141, 3); draught = (float)(ubits(bs, 144, 11) / 10.0); // m //Crouse:Added typecasting loaded = ubits(bs, 155, 2); speed_qual = bs[157]; course_qual = bs[158]; heading_qual = bs[159]; spare2 = ubits(bs, 160, 8); status = AIS_OK; }
// River Information Systems ECE-TRANS-SC3-2006-10r-RIS.pdf Ais8_200_24::Ais8_200_24(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 200); assert(fi == 24); const size_t num_bits = strlen(nmea_payload) * 6 - pad; if (num_bits != 168) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<168> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } ais_str(bs, 56, 12); for (size_t i = 0; i < 4; i++) { size_t start = 68 + 25*i; gauge_ids[i] = ubits(bs, start, 11); const int sign = bs[start + 11] ? 1 : -1; // 0 negative, 1 pos // ERROR: the spec has a bit listing mistake levels[i] = (float)(sign * ubits(bs, start + 12, 13)); } status = AIS_OK; }
Ais12::Ais12(const char *nmea_payload, const size_t pad) : AisMsg(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(message_id == 12); // WARNING: The ITU 1371 specifications says the maximum number of bits is // 1008, but it appears that the maximum should be 1192. const size_t num_bits = strlen(nmea_payload) * 6 - pad; if (num_bits < 72 || num_bits > 1192) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<MAX_BITS> bs; // Spec says 1008 const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } seq_num = ubits(bs, 38, 2); dest_mmsi = ubits(bs, 40, 30); retransmitted = bs[70]; spare = bs[71]; const int num_txt = (num_bits - 72) / 6; const int num_txt_bits = num_txt * 6; text = ais_str(bs, 72, num_txt_bits); // TODO(schwehr): watch for trailing spares status = AIS_OK; }
// IMO Circ 289 - Text description // See also Circ 236 Ais8_1_29::Ais8_1_29(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 1); assert(fi == 29); const size_t num_bits = strlen(nmea_payload) * 6 - pad; if (72 > num_bits || num_bits > 1032) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<1032> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } link_id = ubits(bs, 56, 10); size_t text_bits = ((num_bits - 66) / 6) * 6; text = ais_str(bs, 66, text_bits); const size_t spare2_bits = num_bits - 66 - text_bits; if (spare2_bits) { const size_t start = 66 + text_bits; spare2 = ubits(bs, start, spare2_bits); } else { spare2 = 0; } status = AIS_OK; }
// IMO Circ 289 - Extended ship static and voyage-related // See also Circ 236 Ais8_1_24::Ais8_1_24(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 1); assert(fi == 24); const size_t num_bits = strlen(nmea_payload) * 6 - pad; if (num_bits != 360) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<360> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } link_id = ubits(bs, 56, 10); air_draught = (float)(ubits(bs, 66, 13) / 10.0); // m //Crouse: Added typecasting last_port = ais_str(bs, 79, 30); next_ports[0] = ais_str(bs, 109, 30); next_ports[1] = ais_str(bs, 139, 30); // TODO(schwehr): enum list of param types // 0 NA, 1 operational, 2 SNAFU, 3 no data for (size_t equip_num = 0; equip_num < 26; equip_num++) { solas_status[equip_num] = ubits(bs, 169 + 2 * equip_num, 2); } ice_class = ubits(bs, 221, 4); shaft_power = ubits(bs, 225, 18); // horses vhf = ubits(bs, 243, 12); lloyds_ship_type = ais_str(bs, 255, 42); gross_tonnage = ubits(bs, 297, 18); laden_ballast = ubits(bs, 315, 2); heavy_oil = ubits(bs, 317, 2); light_oil = ubits(bs, 319, 2); diesel = ubits(bs, 321, 2); bunker_oil = ubits(bs, 323, 14); // tonnes persons = ubits(bs, 337, 13); spare2 = ubits(bs, 350, 10); status = AIS_OK; }
Ais5::Ais5(const char *nmea_payload, const size_t pad) : AisMsg(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(message_id == 5); if (pad != 2 || strlen(nmea_payload) != 71) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<426> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } ais_version = ubits(bs, 38, 2); imo_num = ubits(bs, 40, 30); callsign = ais_str(bs, 70, 42); name = ais_str(bs, 112, 120); type_and_cargo = ubits(bs, 232, 8); dim_a = ubits(bs, 240, 9); dim_b = ubits(bs, 249, 9); dim_c = ubits(bs, 258, 6); dim_d = ubits(bs, 264, 6); fix_type = ubits(bs, 270, 4); eta_month = ubits(bs, 274, 4); eta_day = ubits(bs, 278, 5); eta_hour = ubits(bs, 283, 5); eta_minute = ubits(bs, 288, 6); draught = (float)(ubits(bs, 294, 8) / 10.0);//Crouse: Added typecasting destination = ais_str(bs, 302, 120); dte = bs[422]; spare = bs[423]; status = AIS_OK; }
// IMO Circ 289 - Fairway Closed // See also Circ 236 Ais8_1_13::Ais8_1_13(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 1); assert(fi == 13); const size_t num_bits = strlen(nmea_payload) * 6 - pad; if (num_bits != 472) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<472> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } reason = ais_str(bs, 56, 120); location_from = ais_str(bs, 176, 120); location_to = ais_str(bs, 296, 120); radius = ubits(bs, 416, 10); units = ubits(bs, 426, 2); day_from = ubits(bs, 428, 5); month_from = ubits(bs, 433, 4); hour_from = ubits(bs, 437, 5); minute_from = ubits(bs, 442, 6); day_to = ubits(bs, 448, 5); month_to = ubits(bs, 453, 4); hour_to = ubits(bs, 457, 5); minute_to = ubits(bs, 462, 6); spare2 = ubits(bs, 468, 4); status = AIS_OK; }
// TODO: pad Ais19::Ais19(const char *nmea_payload) { assert(nmea_payload); init(); if (strlen(nmea_payload) != 52) { status = AIS_ERR_BAD_BIT_COUNT; return; } std::bitset<312> bs; status = aivdm_to_bits(bs, nmea_payload); if (had_error()) return; message_id = ubits(bs, 0, 6); if (19 != message_id) { status = AIS_ERR_WRONG_MSG_TYPE; return; } repeat_indicator = ubits(bs,6,2); mmsi = ubits(bs,8,30); spare = ubits(bs,38,8); sog = ubits(bs,46,10) / 10.; position_accuracy = bs[56]; x = sbits(bs, 57, 28) / 600000.; y = sbits(bs, 85, 27) / 600000.; cog = ubits(bs, 112, 12) / 10.; true_heading = ubits(bs, 124, 9); timestamp = ubits(bs, 133, 6); spare2 = ubits(bs, 139, 4); name = ais_str(bs, 143, 120); type_and_cargo = ubits(bs, 263, 8); dim_a = ubits(bs, 271, 9); dim_b = ubits(bs, 280, 9); dim_c = ubits(bs, 289, 6); dim_d = ubits(bs, 295, 6); fix_type = ubits(bs, 301, 4); raim = bs[305]; dte = bs[306]; assigned_mode = bs[307]; spare3 = ubits(bs,308,4); }
// IMO Circ 289 - Marine traffic signal Ais8_1_19::Ais8_1_19(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 1); assert(fi == 19); const size_t num_bits = strlen(nmea_payload) * 6 - pad; // Some people transmit without the idiodic spare padding if (num_bits != 258 && num_bits != 360) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<360> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } link_id = ubits(bs, 56, 10); name = ais_str(bs, 66, 120); x = (float)(sbits(bs, 186, 25) / 60000.0);//Crouse: Added typecasting y = (float)(sbits(bs, 211, 24) / 60000.0);//Crouse: Added typecasting status = ubits(bs, 235, 2); signal = ubits(bs, 237, 5); utc_hour_next = ubits(bs, 242, 5); utc_min_next = ubits(bs, 247, 6); next_signal = ubits(bs, 253, 5); if (num_bits != 360) return; spare2[0] = ubits(bs, 258, 32); spare2[1] = ubits(bs, 290, 32); spare2[2] = ubits(bs, 322, 32); spare2[3] = ubits(bs, 354, 6); status = AIS_OK; }
// IMO Circ 289 - VTS Generated/Synthetic Targets // See also Circ 236 Ais8_1_17::Ais8_1_17(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 1); assert(fi == 17); const size_t num_bits = strlen(nmea_payload) * 6 - pad; const size_t num_targets = (num_bits - 56) / 120; const size_t extra_bits = (num_bits - 56) % 120; if (extra_bits || num_targets > 4) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<536> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } for (size_t target_num = 0; target_num < num_targets; target_num++) { Ais8_1_17_Target target; const size_t start = 56 + (120 * target_num); target.type = ubits(bs, start, 2); target.id = ais_str(bs, start + 2, 42); target.spare = ubits(bs, start + 44, 4); target.y = (float)(sbits(bs, start + 48, 24) / 60000.0); // booo - lat, lon //Crouse: Added typecasting target.x = (float)(sbits(bs, start + 72, 25) / 60000.0);//Crouse: Added typecasting target.cog = ubits(bs, start + 97, 9); target.timestamp = ubits(bs, start + 106, 6); target.sog = ubits(bs, start + 112, 8); } status = AIS_OK; }
Ais8_1_0::Ais8_1_0(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 1); assert(fi == 0); const size_t num_bits = strlen(nmea_payload) * 6 - pad; if (56 > num_bits || num_bits > 1024) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<MAX_BITS> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } ack_required = bs[56]; msg_seq = ubits(bs, 57, 11); const size_t text_size = 6 * ((num_bits - 68)/6); // wrong? needs to land on 8-bit boundary const size_t spare2_size = num_bits - 68 - text_size; text = ais_str(bs, 68, text_size); // TODO(schwehr): Is this correct? if (!spare2_size) spare2 = 0; else spare2 = ubits(bs, 68, spare2_size); status = AIS_OK; }
Ais8_366_22_Text::Ais8_366_22_Text(const bitset<AIS8_MAX_BITS> &bs, const size_t offset) { text = string(ais_str(bs, offset + 3, 84)); spare = ubits(bs, offset + 87, 3); }
Ais8_1_26_Station::Ais8_1_26_Station(const bitset<AIS8_MAX_BITS> &bs, const size_t offset) { name = ais_str(bs, offset, 84); spare = ubits(bs, offset + 84, 1); }
// IMO Circ 289 - Weather observation report from ship // See also Circ 236 Ais8_1_21::Ais8_1_21(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 1); assert(fi == 21); const size_t num_bits = strlen(nmea_payload) * 6 - pad; if (num_bits != 360) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<360> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } type_wx_report = bs[56]; if (!type_wx_report) { // WX obs from ship location = ais_str(bs, 57, 120); x = (float)(sbits(bs, 177, 25) / 60000.0);//Crouse: Added typecasting y = (float)(sbits(bs, 202, 24) / 60000.0);//Crouse: Added typecasting utc_day = ubits(bs, 226, 5); utc_hour = ubits(bs, 231, 5); utc_min = ubits(bs, 236, 6); wx[0] = ubits(bs, 242, 4); // TODO(schwehr): set wx[1] and wx[2]? horz_viz = (float)(ubits(bs, 246, 8) / 10.0); // nautical miles //Crouse: Added typecasting humidity = ubits(bs, 254, 7); // % wind_speed = ubits(bs, 261, 7); // ave knots wind_dir = ubits(bs, 268, 9); pressure = (float)ubits(bs, 277, 9); // hPa pressure_tendency = ubits(bs, 286, 4); // TODO(schwehr): is air_temp correct? air_temp = (float)(sbits(bs, 290, 11) / 10.0); // C //Crouse: Added typecasting water_temp = (float)(ubits(bs, 301, 10) / 10.0 - 10); // C //Crouse: Added typecasting wave_period = ubits(bs, 311, 6); // s wave_height = (float)(ubits(bs, 317, 8) / 10.0);//Crouse: Added typecasting wave_dir = ubits(bs, 325, 9); swell_height = (float)(ubits(bs, 334, 8) / 10.0); // m //Crouse: Added typecasting swell_dir = ubits(bs, 342, 9); swell_period = ubits(bs, 351, 6); // s spare2 = ubits(bs, 357, 3); } else { // type == 1 // PAIN IN THE ASS WMO OBS from ship // TODO(schwehr): double check the insanity x = (float)((ubits(bs, 57, 16) / 100.0) - 180);//Crouse: Added typecasting y = (float)((ubits(bs, 73, 15) / 100.0) - 180);//Crouse: Added typecasting utc_month = ubits(bs, 88, 4); utc_day = ubits(bs, 92, 6); utc_hour = ubits(bs, 98, 5); utc_min = ubits(bs, 102, 3) * 10; cog = ubits(bs, 106, 7) * 5; sog = (float)(ubits(bs, 113, 5) * 0.5);//Crouse: Added typecasting heading = ubits(bs, 118, 7) *5; // Assume this is true degrees???? pressure = (float)(ubits(bs, 125, 11) / 10.0 + 900);//Crouse: Added typecasting rel_pressure = (float)(ubits(bs, 136, 10) / 10.0 -50);//Crouse: Added typecasting pressure_tendency = ubits(bs, 146, 4); wind_dir = ubits(bs, 150, 7) * 5; wind_speed_ms = (float)(ubits(bs, 157, 8) * 0.5); // m/s //Crouse: Added typecasting wind_dir_rel = ubits(bs, 165, 7) * 5; wind_speed_rel= (float)(ubits(bs, 172, 8) * 0.5); // m/s //Crouse: Added typecasting wind_gust_speed = (float)(ubits(bs, 180, 8) * 0.5); // m/s //Crouse: Added typecasting wind_gust_dir = ubits(bs, 188, 7) * 5; // 0C = 273.15 Kelvin // TODO(schwehr): change this to celcius air_temp_raw = ubits(bs, 195, 10); humidity =ubits(bs, 205, 7); water_temp_raw = ubits(bs, 212, 9); // TODO(schwehr): change this to C horz_viz = (float)(pow((double)ubits(bs, 221, 6), 2) * 13.073); // m //Crouse: added typecasting to get rid of an error compiling under Windows wx[0] = ubits(bs, 227, 9); // current wx[1] = ubits(bs, 236, 5); // past 1 wx[2] = ubits(bs, 241, 5); // past 2 cloud_total = ubits(bs, 246, 4) * 10; cloud_low = ubits(bs, 250, 4); cloud_low_type = ubits(bs, 254, 6); cloud_middle_type = ubits(bs, 260, 6); cloud_high_type = ubits(bs, 266, 6); alt_lowest_cloud_base = (float)(pow((double)ubits(bs, 272, 7), 2) * 0.16); //Crouse: Added typecasting to get rid of an error compiling under Windows wave_period = ubits(bs, 279, 5); // s wave_height = (float)(ubits(bs, 284, 6) * 0.5); // m //Crouse: Added typecasting swell_dir = ubits(bs, 290, 6) * 10; swell_period = ubits(bs, 296, 5); // s swell_height = (float)(ubits(bs, 301, 6) * 0.5); // m //Crouse: Added typecasting swell_dir_2 = ubits(bs, 307, 6) * 10; swell_period_2 = ubits(bs, 313, 5); // s swell_height_2 = (float)(ubits(bs, 318, 6) * 0.5); // m //Crouse: Added typecasting ice_thickness = (float)(ubits(bs, 324, 7) / 100.0); // network is cm, storing m //Crouse: Added typecasting ice_accretion = ubits(bs, 331, 3); ice_accretion_cause = ubits(bs, 334, 3); sea_ice_concentration = ubits(bs, 337, 5); amt_type_ice = ubits(bs, 342, 4); ice_situation = ubits(bs, 346, 5); ice_devel = ubits(bs, 351, 5); bearing_ice_edge = ubits(bs, 356, 4) * 45; } status = AIS_OK; }