Ais8::Ais8(const char *nmea_payload, const size_t pad) : AisMsg(nmea_payload, pad) { // Ais8 is used in some apps as a standalone, so be extra // careful to make sure we have the lookup table built assert(nmea_ord_initialized); if (status != AIS_UNINITIALIZED) return; assert(message_id == 8); // in bits w/o DAC/FI const ptrdiff_t payload_len = strlen(nmea_payload) * 6 - 46 - pad;//Crouse: Changed from int to ptrdiff_t if (payload_len < 0 || payload_len > 952) { 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; } spare = ubits(bs, 38, 2); dac = ubits(bs, 40, 10); fi = ubits(bs, 50, 6); }
// 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; }
// TODO: pad Ais8_366_22::Ais8_366_22(const char *nmea_payload) { assert(nmea_payload); assert(strlen(nmea_payload) >= 28); init(); const int num_bits = (strlen(nmea_payload) * 6); if (208 <= num_bits && num_bits >= 1020) { status = AIS_ERR_BAD_BIT_COUNT; return; } std::bitset<MAX_BITS> bs; status = aivdm_to_bits(bs, nmea_payload); if (had_error()) return; if (!decode_header8(bs)) return; link_id = ubits(bs,56,10); notice_type = ubits(bs,66,7); month = ubits(bs,73,4); day = ubits(bs,77,5); utc_hour = ubits(bs,82,5); utc_minute = ubits(bs,87,6); duration_minutes = ubits(bs,93,18); const int num_sub_areas = int( floor( (num_bits - 111)/90.) ); for (int sub_area_idx=0; sub_area_idx < num_sub_areas; sub_area_idx++) { Ais8_366_22_SubArea *sub_area = ais8_366_22_subarea_factory(bs, 111+90*sub_area_idx); if (sub_area) { sub_areas.push_back(sub_area); } else { std::cout << "ERROR: bad sub area " << sub_area_idx << std::endl; } } }
// River Information Systems ECE-TRANS-SC3-2006-10r-RIS.pdf Ais8_200_40::Ais8_200_40(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 200); assert(fi == 40); 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; } x = (float)(sbits(bs, 56, 28) / 600000.0);//Crouse:Added typecasting y = (float)(sbits(bs, 84, 27) / 600000.0);//Crouse:Added typecasting form = ubits(bs, 111, 4); dir = ubits(bs, 115, 9); // degrees stream_dir = ubits(bs, 124, 3); status_raw = ubits(bs, 127, 30); // TODO(schwehr): status[ ] = bite me; spare2 = ubits(bs, 157, 11); 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; }
// IMO Circ 289 - Extended Shipdata - Air gap // See also Circ 236 Ais8_1_15::Ais8_1_15(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 1); assert(fi == 15); const size_t num_bits = strlen(nmea_payload) * 6 - pad; if (num_bits != 72) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<72> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } air_draught = (float)(ubits(bs, 56, 11) / 10.0);//Crouse: Added typecasting spare2 = ubits(bs, 67, 5); status = AIS_OK; }
// IMO Circ 289 - Number of persons on board // See also Circ 236 // TODO(schwehr): there might also be an addressed version? Ais8_1_16::Ais8_1_16(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 1); assert(fi == 16); const size_t num_bits = strlen(nmea_payload) * 6 - pad; if (num_bits != 72) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<72> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } persons = ubits(bs, 56, 13); spare2 = ubits(bs, 69, 3); 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; }
// 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; }
Ais27::Ais27(const char *nmea_payload, const size_t pad) { assert(nmea_payload); assert(0==pad); init(); const size_t num_bits = strlen(nmea_payload) * 6 - pad; assert(96==num_bits); if (96 != num_bits) { status = AIS_ERR_BAD_BIT_COUNT; return; } std::bitset<96> bs; status = aivdm_to_bits(bs, nmea_payload); if (had_error()) return; message_id = ubits(bs, 0, 6); if (27 != message_id) {status = AIS_ERR_WRONG_MSG_TYPE; return;} repeat_indicator = ubits(bs,6,2); mmsi = ubits(bs,8,30); position_accuracy = bs[38]; raim = bs[39]; nav_status = ubits(bs, 40, 4); x = sbits(bs, 44, 18) / 600.; y = sbits(bs, 62, 17) / 600.; sog = ubits(bs,79,6); cog = ubits(bs,85,9); gnss = !bs[94]; spare = bs[95]; }
Ais10::Ais10(const char *nmea_payload, const size_t pad) : AisMsg(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(message_id == 10); if (pad != 0 || strlen(nmea_payload) != 12) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<72> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } spare = ubits(bs, 38, 2); dest_mmsi = ubits(bs, 40, 30); spare2 = ubits(bs, 70, 2); status = AIS_OK; }
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; } }
// TODO: pad Ais22::Ais22(const char *nmea_payload) { assert(nmea_payload); init(); const int num_char = std::strlen(nmea_payload); if (28 != num_char) { status = AIS_ERR_BAD_BIT_COUNT; return; } std::bitset<168> bs; status = aivdm_to_bits(bs, nmea_payload); if (had_error()) return; message_id = ubits(bs, 0, 6); if (message_id != 22) { status = AIS_ERR_WRONG_MSG_TYPE; return; } repeat_indicator = ubits(bs,6,2); mmsi = ubits(bs,8,30); spare = ubits(bs,38,2); chan_a = ubits(bs,40,12); chan_b = ubits(bs,52,12); txrx_mode = ubits(bs, 64, 4); power_low = bs[68]; // WARNING: OUT OF ORDER DECODE bool addressed = bs[139]; if (not(addressed)) { // geographic position pos_valid = true; dest_valid = false; x1 = sbits(bs, 69, 28) / 600000.; y1 = sbits(bs, 87, 27) / 600000.; x2 = sbits(bs, 104, 28) / 600000.; y2 = sbits(bs, 122, 27) / 600000.; } else { pos_valid = false; dest_valid = true; dest_mmsi_1 = ubits(bs, 69, 30); // TODO: save the 5 spare bits dest_mmsi_2 = ubits(bs, 104, 30); // TODO: save the 5 spare bits } // OUT OF ORDER: addressed is before chan_a_bandwidth = bs[140]; chan_b_bandwidth = bs[141]; zone_size = ubits(bs, 142, 3); spare2 = ubits(bs, 145, 23); }
// River Information Systems ECE-TRANS-SC3-2006-10r-RIS.pdf Ais8_200_23::Ais8_200_23(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 200); assert(fi == 23); const size_t num_bits = strlen(nmea_payload) * 6 - pad; if (num_bits != 256) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<256> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } utc_year_start = ubits(bs, 56, 9); utc_month_start = ubits(bs, 65, 4); utc_day_start = ubits(bs, 69, 4); // ERROR: not enough bits to cover 1-31 utc_year_end = ubits(bs, 73, 9); utc_month_end = ubits(bs, 82, 4); utc_day_end = ubits(bs, 86, 4); // ERROR: not enough bits to cover 1-31 utc_hour_start = ubits(bs, 90, 5); utc_min_start = ubits(bs, 95, 6); utc_hour_end = ubits(bs, 101, 5); utc_min_end = ubits(bs, 106, 6); x1 = (float)(sbits(bs, 112, 28) / 600000.0);//Crouse:Added typecasting y1 = (float)(sbits(bs, 140, 27) / 600000.0);//Crouse:Added typecasting x2 = (float)(sbits(bs, 167, 28) / 600000.0);//Crouse:Added typecasting y2 = (float)(sbits(bs, 195, 27) / 600000.0);//Crouse:Added typecasting type = ubits(bs, 222, 4); min = ubits(bs, 226, 9); max = ubits(bs, 235, 9); classification = ubits(bs, 244, 2); wind_dir = ubits(bs, 246, 4); spare2 = ubits(bs, 250, 6); 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; }
// TODO: pad Ais15::Ais15(const char *nmea_payload) { assert(nmea_payload); init(); const int num_char = std::strlen(nmea_payload); if (num_char != 15 && num_char!=18 and num_char!=27) { // 88-160 bits status = AIS_ERR_BAD_BIT_COUNT; return; } std::bitset<162> bs; // 160 / 6 = 26.66 status = aivdm_to_bits(bs, nmea_payload); if (had_error()) return; message_id = ubits(bs, 0, 6); if (15 != message_id) { status = AIS_ERR_WRONG_MSG_TYPE; return; } repeat_indicator = ubits(bs,6,2); mmsi = ubits(bs,8,30); spare = ubits(bs,38,2); mmsi_1 = ubits(bs,40,30); // Destination ID 1 msg_1_1 = ubits(bs,70,6); slot_offset_1_1 = ubits(bs,76,12); // TODO: set remaining fields to -1 if (num_char <= 15) return; spare2 = ubits(bs,88,2); dest_msg_1_2 = ubits(bs,90,6); slot_offset_1_2 = ubits(bs,96,12); // TODO: set remaining fields to -1 if (num_char <= 18) return; spare3 = ubits(bs,108,2); mmsi_2 = ubits(bs,110,30); msg_2 = ubits(bs,140,6); slot_offset_2 = ubits(bs,146,12); spare4 = ubits(bs,158,2); }
// IMO Circ 289 - Route information // See also Circ 236 Ais8_1_27::Ais8_1_27(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 1); assert(fi == 27); const size_t num_bits = strlen(nmea_payload) * 6 - pad; const size_t num_waypoints = (num_bits - 117) / 55; const size_t extra_bits = (num_bits - 117) % 55; if (extra_bits || num_waypoints > 16) { status = AIS_ERR_BAD_BIT_COUNT; return; } bitset<997> bs; const AIS_STATUS r = aivdm_to_bits(bs, nmea_payload); if (r != AIS_OK) { status = r; return; } link_id = ubits(bs, 56, 10); sender_type = ubits(bs, 66, 3); route_type = ubits(bs, 69, 5); utc_month = ubits(bs, 74, 4); utc_day = ubits(bs, 78, 5); utc_hour = ubits(bs, 83, 5); utc_min = ubits(bs, 88, 6); duration = ubits(bs, 94, 18); // TODO(schwehr): manage the case where num_waypoints does not match // const size_t num_waypoints_stated = ubits(bs, 112, 5); for (size_t waypoint_num = 0; waypoint_num < num_waypoints; waypoint_num++) { AisPoint pt; const size_t start = 117 + 55*waypoint_num; pt.x = (float)(sbits(bs, start, 28) / 600000.0);//Crouse: Added typecasting pt.y = (float)(sbits(bs, start + 28, 27) / 600000.0);//Crouse: Added typecasting waypoints.push_back(pt); } status = AIS_OK; }
// River Information Systems ECE-TRANS-SC3-2006-10r-RIS.pdf Ais8_200_55::Ais8_200_55(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 200); assert(fi == 55); const size_t num_bits = strlen(nmea_payload) * 6 - pad; // People might get smart and leave out the 51 spare bits // TODO(schwehr): do we have any cases of that? if (num_bits != 88 && num_bits != 136 && 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; } crew = ubits(bs, 56, 8); passengers = ubits(bs, 64, 13); yet_more_personnel = ubits(bs, 77, 8); if (88 == num_bits) { spare2[0] = ubits(bs, 85, 3); spare2[1] = 0; spare2[2] = 0; } else if (136 == num_bits) { // as in the spec - maybe? spare2[0] = ubits(bs, 85, 32); spare2[1] = ubits(bs, 117, 32); spare2[2] = ubits(bs, 149, 19); } else { spare2[0] = ubits(bs, 85, 32); spare2[1] = ubits(bs, 117, 19); spare2[2] = 0; } 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; }
// 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); }
Ais8_366_22::Ais8_366_22(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 366); assert(fi == 22); const int num_bits = (strlen(nmea_payload) * 6) - pad; if (num_bits <= 208 || num_bits >= 1020) { 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; } link_id = ubits(bs, 56, 10); notice_type = ubits(bs, 66, 7); month = ubits(bs, 73, 4); day = ubits(bs, 77, 5); utc_hour = ubits(bs, 82, 5); utc_minute = ubits(bs, 87, 6); duration_minutes = ubits(bs, 93, 18); const int num_sub_areas = static_cast<int>(floor((num_bits - 111)/90.)); for (int area_idx = 0; area_idx < num_sub_areas; area_idx++) { Ais8_366_22_SubArea *area = ais8_366_22_subarea_factory(bs, 111 + 90*area_idx); if (area) sub_areas.push_back(area); else status = AIS_ERR_BAD_SUB_SUB_MSG; } }
// 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; }
Ais8_1_26::Ais8_1_26(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(dac == 1); assert(fi == 26); const ptrdiff_t num_bits = strlen(nmea_payload) * 6 - pad;//Crouse: Changed int to ptrdiff_t if (168 > num_bits || num_bits > 1098) { 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; } const size_t num_sensor_reports = (num_bits - 56) / AIS8_1_26_REPORT_SIZE; // TODO(schwehr): what to do about extra data in sensor report msg 8_1_26? // if ((num_bits - 56) % AIS8_1_26_REPORT_SIZE) for (size_t report_idx = 0; report_idx < num_sensor_reports; report_idx++) { const size_t start = 56 + report_idx * AIS8_1_26_REPORT_SIZE; Ais8_1_26_SensorReport *sensor = ais8_1_26_sensor_report_factory(bs, start); if (sensor) { reports.push_back(sensor); } else { status = AIS_ERR_BAD_SUB_SUB_MSG; } } if (AIS_UNINITIALIZED == status) 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; }
// 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; }
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; }
Ais18::Ais18(const char *nmea_payload) { assert(nmea_payload); init(); if (strlen(nmea_payload) != 168/6) { status = AIS_ERR_BAD_BIT_COUNT; return; } std::bitset<168> bs; // 1 slot status = aivdm_to_bits(bs, nmea_payload); if (had_error()) return; message_id = ubits(bs, 0, 6); if (18 != 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 = ubits(bs,56,1); 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, 2); unit_flag = bs[141]; display_flag = bs[142]; dsc_flag = bs[143]; band_flag = bs[144]; m22_flag = bs[145]; mode_flag = bs[146]; raim = bool(bs[147]); commstate_flag = bs[148]; // 0 SOTDMA, 1 ITDMA // FIX: set all to -1 and set valids to NOT! if (1 == unit_flag) { // CS - carrier sense - fixed commstate payload of 1100000000000000110 int commstate = ubits(bs,149, 19); //std::cout << "\tcs commstate: " << commstate << std::endl; if (393222 != commstate) { // FIX: is this the right value? // FIX: return an error? } } else { sync_state = ubits(bs, 149, 2); if (0 == commstate_flag) { // SOTDMA slot_timeout = ubits(bs,151,3); switch (slot_timeout) { case 0: slot_offset = ubits(bs, 154, 14); slot_offset_valid = true; break; case 1: utc_hour = ubits(bs, 154, 5); utc_min = ubits(bs, 159, 7); utc_spare = ubits(bs, 166, 2); utc_valid = true; break; case 2: // FALLTHROUGH case 4: // FALLTHROUGH case 6: slot_number = ubits(bs, 154, 14); slot_number_valid = true; break; case 3: // FALLTHROUGH case 5: // FALLTHROUGH case 7: received_stations = ubits(bs, 154, 14); received_stations_valid = true; break; default: assert (false); } } else { // ITDMA slot_increment = ubits(bs, 151, 13); slot_increment_valid = true; slots_to_allocate = ubits(bs, 164, 3); slots_to_allocate_valid = true; keep_flag = bool(bs[167]); keep_flag_valid = true; } } }
Ais9::Ais9(const char *nmea_payload, const size_t pad) : AisMsg(nmea_payload, pad) { if (status != AIS_UNINITIALIZED) return; assert(message_id == 9); if (pad != 0 || strlen(nmea_payload) != 28) { 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; } alt = ubits(bs, 38, 12); sog = (float)(ubits(bs, 50, 10) / 10.0);//Crouse:Added typecasting position_accuracy = bs[60]; x = (float)(sbits(bs, 61, 28) / 600000.0);//Crouse:Added typecasting y = (float)(sbits(bs, 89, 27) / 600000.0);//Crouse:Added typecasting cog = (float)(ubits(bs, 116, 12) / 10.0);//Crouse:Added typecasting timestamp = ubits(bs, 128, 6); alt_sensor = bs[134]; spare = ubits(bs, 135, 7); dte = bs[142]; spare2 = ubits(bs, 143, 3); assigned_mode = bs[146]; raim = bs[147]; commstate_flag = bs[148]; // 0 SOTDMA, 1 ITDMA sync_state = ubits(bs, 149, 2); #ifndef NDEBUG slot_timeout = -1; received_stations = slot_number = utc_hour = utc_min = utc_spare -1; slot_offset = slot_increment = slots_to_allocate = -1; keep_flag = false; #endif slot_timeout_valid = false; received_stations_valid = false; slot_number_valid = false; utc_valid = false; slot_offset_valid = false; slot_increment_valid = false; slots_to_allocate_valid = false; keep_flag_valid = false; if (0 == commstate_flag) { // SOTDMA slot_timeout = ubits(bs, 151, 3); slot_timeout_valid = true; switch (slot_timeout) { case 0: slot_offset = ubits(bs, 154, 14); slot_offset_valid = true; break; case 1: utc_hour = ubits(bs, 154, 5); utc_min = ubits(bs, 159, 7); utc_spare = ubits(bs, 166, 2); utc_valid = true; break; case 2: // FALLTHROUGH case 4: // FALLTHROUGH case 6: slot_number = ubits(bs, 154, 14); slot_number_valid = true; break; case 3: // FALLTHROUGH case 5: // FALLTHROUGH case 7: received_stations = ubits(bs, 154, 14); received_stations_valid = true; break; default: assert(false); } } else { // ITDMA slot_increment = ubits(bs, 151, 13); slot_increment_valid = true; slots_to_allocate = ubits(bs, 164, 3); slots_to_allocate_valid = true; keep_flag = bs[167]; keep_flag_valid = true; } status = AIS_OK; }