// IMO 1371-5 Ack Ais6_1_5::Ais6_1_5(const char *nmea_payload, const size_t pad) : Ais6(nmea_payload, pad), ack_dac(0), ack_fi(0), seq_num(0), ai_available(false), ai_response(0), spare(0) { assert(dac == 1); assert(fi == 5); if (num_bits != 168) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } bs.SeekTo(88); ack_dac = bs.ToUnsignedInt(88, 10); ack_fi = bs.ToUnsignedInt(98, 6); seq_num = bs.ToUnsignedInt(104, 11); ai_available = static_cast<bool>(bs[115]); ai_response = bs.ToUnsignedInt(116, 3); spare = bs.ToUnsignedInt(119, 49); assert(bs.GetRemaining() == 0); status = AIS_OK; }
Ais6_1_0::Ais6_1_0(const char *nmea_payload, const size_t pad) : Ais6(nmea_payload, pad), ack_required(false), msg_seq(0), spare2(0) { assert(dac == 1); assert(fi == 0); if (num_bits < 88 || num_bits > 936) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; // TODO(schwehr): what is the real max size? const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } bs.SeekTo(88); ack_required = bs[88]; msg_seq = bs.ToUnsignedInt(89, 11); const size_t text_size = 6 * ((num_bits - 100) / 6); const size_t spare2_size = num_bits - 100 - text_size; text = bs.ToString(100, text_size); if (!spare2_size) spare2 = 0; else spare2 = bs.ToUnsignedInt(100 + text_size, spare2_size); assert(bs.GetRemaining() == 0); status = AIS_OK; }
Ais6_1_1::Ais6_1_1(const char *nmea_payload, const size_t pad) : Ais6(nmea_payload, pad), ack_dac(0), msg_seq(0), spare2(0) { assert(dac == 1); assert(fi == 1); if (num_bits != 112) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } bs.SeekTo(88); ack_dac = bs.ToUnsignedInt(88, 10); msg_seq = bs.ToUnsignedInt(98, 11); spare2 = bs.ToUnsignedInt(109, 3); assert(bs.GetRemaining() == 0); status = AIS_OK; }
Ais6::Ais6(const char *nmea_payload, const size_t pad) : AisMsg(nmea_payload, pad), seq(0), mmsi_dest(0), retransmit(false), spare(0), dac(0), fi(0) { assert(message_id == 6); // TODO(olafsinram): 46 or rather 56? const int payload_len = num_bits - 46; // in bits w/o DAC/FI if (num_bits < 88 || payload_len < 0 || payload_len > 952) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } bs.SeekTo(38); seq = bs.ToUnsignedInt(38, 2); mmsi_dest = bs.ToUnsignedInt(40, 30); retransmit = !bs[70]; spare = bs[71]; dac = bs.ToUnsignedInt(72, 10); fi = bs.ToUnsignedInt(82, 6); }
Ais8_1_26_Location::Ais8_1_26_Location(const AisBitset &bits, const size_t offset) { position = bits.ToAisPoint(offset, 55); z = bits.ToUnsignedInt(offset + 55, 11) / 10.; owner = bits.ToUnsignedInt(offset + 66, 4); timeout = bits.ToUnsignedInt(offset + 70, 3); spare = bits.ToUnsignedInt(offset + 73, 12); }
Ais8_366_22_Rect::Ais8_366_22_Rect(const AisBitset &bs, const size_t offset) { const int scale_factor = bs.ToUnsignedInt(offset + 3, 2); position = bs.ToAisPoint(offset + 5, 55); e_dim_m = bs.ToUnsignedInt(offset + 60, 8) * scale_multipliers[scale_factor]; n_dim_m = bs.ToUnsignedInt(offset + 68, 8) * scale_multipliers[scale_factor]; orient_deg = bs.ToUnsignedInt(offset + 76, 9); spare = bs.ToUnsignedInt(offset + 85, 5); }
Ais8_366_22_Sector::Ais8_366_22_Sector(const AisBitset &bits, const size_t offset) { const int scale_factor = bits.ToUnsignedInt(offset + 3, 2); position = bits.ToAisPoint(offset + 5, 55); radius_m = bits.ToUnsignedInt(offset + 60, 12) * scale_multipliers[scale_factor]; left_bound_deg = bits.ToUnsignedInt(offset + 72, 9); right_bound_deg = bits.ToUnsignedInt(offset + 81, 9); }
Ais8_366_22_Circle::Ais8_366_22_Circle(const AisBitset &bits, const size_t offset) { const int scale_factor = bits.ToUnsignedInt(offset + 3, 2); position = bits.ToAisPoint(offset + 5, 55); // TODO(schwehr): precision? And bit counts for radius and spare? // TODO(schwehr): collapse these numbers radius_m = bits.ToUnsignedInt(offset + 60, 12) * scale_multipliers[scale_factor]; spare = bits.ToUnsignedInt(offset + 72, 16); }
Ais8_1_26_Curr2D::Ais8_1_26_Curr2D(const AisBitset &bits, const size_t offset) { for (size_t idx = 0; idx < 3; idx++) { size_t start = offset + idx * 26; currents[idx].speed = bits.ToUnsignedInt(start, 8) / 10.; currents[idx].dir = bits.ToUnsignedInt(start + 8, 9); currents[idx].depth = bits.ToUnsignedInt(start + 17, 9); } type = bits.ToUnsignedInt(offset + 78, 3); spare = bits.ToUnsignedInt(offset + 81, 4); }
Ais8_1_26_HorzFlow::Ais8_1_26_HorzFlow(const AisBitset &bits, const size_t offset) { for (size_t idx = 0; idx < 2; idx++) { size_t start = offset + idx * 42; currents[idx].bearing = bits.ToUnsignedInt(start, 9); currents[idx].dist = bits.ToUnsignedInt(start + 9, 7); currents[idx].speed = bits.ToUnsignedInt(start + 16, 8) / 10.; currents[idx].dir = bits.ToUnsignedInt(start + 24, 9); currents[idx].level = bits.ToUnsignedInt(start + 33, 9); } spare = bits[offset + 84]; }
// TODO(schwehr): Merge with Polyline. Ais8_366_22_Polygon::Ais8_366_22_Polygon(const AisBitset &bits, const size_t offset) { const int scale_factor = bits.ToUnsignedInt(offset + 3, 2); for (size_t i = 0; i < 4; i++) { const int angle = bits.ToUnsignedInt(offset + 5 + (i*21), 10); const int dist = bits.ToUnsignedInt(offset + 15 + (i*21), 11) * scale_multipliers[scale_factor]; if (dist == 0) { break; } angles.push_back(angle); dists_m.push_back(dist); } spare = bits[offset + 89]; }
Ais8_1_26_SeaState::Ais8_1_26_SeaState(const AisBitset &bits, const size_t offset) { swell_height = bits.ToUnsignedInt(offset, 8) / 10.; swell_period = bits.ToUnsignedInt(offset + 8, 6); swell_dir = bits.ToUnsignedInt(offset + 14, 9); sea_state = bits.ToUnsignedInt(offset + 23, 4); swell_sensor_type = bits.ToUnsignedInt(offset + 27, 3); water_temp = bits.ToInt(offset + 30, 10) / 10.; water_temp_depth = bits.ToUnsignedInt(offset + 40, 7) / 10.; water_sensor_type = bits.ToUnsignedInt(offset + 47, 3); wave_height = bits.ToUnsignedInt(offset + 50, 8) / 10.; wave_period = bits.ToUnsignedInt(offset + 58, 6); wave_dir = bits.ToUnsignedInt(offset + 64, 9); wave_sensor_type = bits.ToUnsignedInt(offset + 73, 3); salinity = bits.ToUnsignedInt(offset + 76, 9) / 10.; }
// IFM 4: Capability reply - OLD ITU 1371-4 // TODO(schwehr): WTF? 10 + 128 + 6 == 80 Is this 168 or 232 bits? Ais6_1_4::Ais6_1_4(const char *nmea_payload, const size_t pad) : Ais6(nmea_payload, pad), ack_dac(0), capabilities(), cap_reserved(), spare2(0) { assert(dac == 1); assert(fi == 4); // TODO(schwehr): num_bits for 6_1_4. 226 bits? if (num_bits != 232) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } bs.SeekTo(88); ack_dac = bs.ToUnsignedInt(88, 10); for (size_t cap_num = 0; cap_num < 128/2; cap_num++) { size_t start = 98 + cap_num * 2; capabilities[cap_num] = bs[start]; cap_reserved[cap_num] = bs[start + 1]; } // spare2 = bs.ToUnsignedInt(226, 6); // OR NOT // TODO(schwehr): add in the offset of the dest mmsi assert(bs.GetRemaining() == 0); status = AIS_OK; }
Ais8_1_26_Wx::Ais8_1_26_Wx(const AisBitset &bits, const size_t offset) { air_temp = bits.ToInt(offset, 11) / 10.; air_temp_sensor_type = bits.ToUnsignedInt(offset + 11, 3); precip = bits.ToUnsignedInt(offset + 14, 2); horz_vis = bits.ToUnsignedInt(offset + 16, 8) / 10.; dew_point = bits.ToInt(offset + 24, 10) / 10.; dew_point_type = bits.ToUnsignedInt(offset + 34, 3); air_pressure = (bits.ToUnsignedInt(offset + 37, 9) + 800) / 100.0; // Pa. air_pressure_trend = bits.ToUnsignedInt(offset + 46, 2); air_pressor_type = bits.ToUnsignedInt(offset + 48, 3); salinity = bits.ToUnsignedInt(offset + 51, 9) / 10.; spare = bits.ToUnsignedInt(offset + 60, 25); }
Ais8_1_26_Salinity::Ais8_1_26_Salinity(const AisBitset &bits, const size_t offset) { water_temp = bits.ToUnsignedInt(offset, 10) / 10. - 10; conductivity = bits.ToUnsignedInt(offset + 10, 10) / 100.; pressure = bits.ToUnsignedInt(offset + 20, 16) / 10.; salinity = bits.ToUnsignedInt(offset + 36, 9) / 10.; salinity_type = bits.ToUnsignedInt(offset + 45, 2); sensor_type = bits.ToUnsignedInt(offset + 47, 3); spare[0] = bits.ToUnsignedInt(offset + 50, 32); spare[1] = bits.ToUnsignedInt(offset + 82, 3); }
Ais8_1_26_AirDraught::Ais8_1_26_AirDraught(const AisBitset &bits, const size_t offset) { draught = bits.ToUnsignedInt(offset, 13) / 100.; gap = bits.ToUnsignedInt(offset + 13, 13) / 10.; trend = bits.ToUnsignedInt(offset + 26, 2); forecast_gap = bits.ToUnsignedInt(offset + 28, 13) / 10.; utc_day_forecast = bits.ToUnsignedInt(offset + 41, 5); utc_hour_forecast = bits.ToUnsignedInt(offset + 46, 5); utc_min_forecast = bits.ToUnsignedInt(offset + 51, 6); spare = bits.ToUnsignedInt(offset + 57, 28); }
// IMO Circ 289 - Clearance time to enter port Ais6_1_18::Ais6_1_18(const char *nmea_payload, const size_t pad) : Ais6(nmea_payload, pad), link_id(0), utc_month(0), utc_day(0), utc_hour(0), utc_min(0), spare2() { assert(dac == 1); assert(fi == 18); if (num_bits != 360) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } link_id = bs.ToUnsignedInt(88, 10); utc_month = bs.ToUnsignedInt(98, 4); utc_day = bs.ToUnsignedInt(102, 5); utc_hour = bs.ToUnsignedInt(107, 5); utc_min = bs.ToUnsignedInt(112, 6); port_berth = bs.ToString(118, 120); dest = bs.ToString(238, 30); position = bs.ToAisPoint(268, 49); spare2[0] = bs.ToUnsignedInt(317, 32); spare2[1] = bs.ToUnsignedInt(349, 11); assert(bs.GetRemaining() == 0); status = AIS_OK; }
// http://www.e-navigation.nl/content/monitoring-aids-navigation Ais6_0_0::Ais6_0_0(const char *nmea_payload, const size_t pad) : Ais6(nmea_payload, pad), sub_id(1), voltage(0.0), current(0.0), dc_power_supply(true), light_on(true), battery_low(false), off_position(false), spare2(0) { assert(dac == 0); assert(fi == 0); if (num_bits != 136) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } bs.SeekTo(88); sub_id = bs.ToUnsignedInt(88, 16); voltage = bs.ToUnsignedInt(104, 12) / 10.0; current = bs.ToUnsignedInt(116, 10) / 10.0; dc_power_supply = bs[126]; light_on = bs[127]; battery_low = bs[128]; off_position = bs[129]; spare2 = bs.ToUnsignedInt(130, 6); assert(bs.GetRemaining() == 0); status = AIS_OK; }
Ais8_1_26_WaterLevel::Ais8_1_26_WaterLevel(const AisBitset &bits, const size_t offset) { type = bits[offset]; level = bits.ToInt(offset + 1, 16) / 100.; trend = bits.ToUnsignedInt(offset + 17, 2); vdatum = bits.ToUnsignedInt(offset + 19, 5); sensor_type = bits.ToUnsignedInt(offset + 24, 3); forecast_type = bits[offset + 27]; level_forecast = bits.ToInt(offset + 28, 16) / 100.; utc_day_forecast = bits.ToUnsignedInt(offset + 44, 5); utc_hour_forecast = bits.ToUnsignedInt(offset + 49, 5); utc_min_forecast = bits.ToUnsignedInt(offset + 54, 6); duration = bits.ToUnsignedInt(offset + 60, 8); spare = bits.ToUnsignedInt(offset + 68, 17); }
Ais6_1_2::Ais6_1_2(const char *nmea_payload, const size_t pad) : Ais6(nmea_payload, pad), req_dac(0), req_fi(0) { assert(dac == 1); assert(fi == 2); if (num_bits != 104) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } bs.SeekTo(88); req_dac = bs.ToUnsignedInt(88, 10); req_fi = bs.ToUnsignedInt(98, 6); assert(bs.GetRemaining() == 0); status = AIS_OK; }
// IFM 40: people on board - OLD ITU 1371-4 Ais6_1_40::Ais6_1_40(const char *nmea_payload, const size_t pad) : Ais6(nmea_payload, pad), persons(0), spare2(0) { assert(dac == 1); assert(fi == 40); if (num_bits != 104) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } bs.SeekTo(88); persons = bs.ToUnsignedInt(88, 13); spare2 = bs.ToUnsignedInt(101, 3); assert(bs.GetRemaining() == 0); status = AIS_OK; }
// IMO Circ 289 - Berthing data Ais6_1_20::Ais6_1_20(const char *nmea_payload, const size_t pad) : Ais6(nmea_payload, pad), link_id(0), length(0), depth(0.0), mooring_position(0), utc_month(0), utc_day(0), utc_hour(0), utc_min(0), services_known(false), services() { assert(dac == 1); assert(fi == 20); if (num_bits != 360) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } bs.SeekTo(88); link_id = bs.ToUnsignedInt(88, 10); length = bs.ToUnsignedInt(98, 9); depth = bs.ToUnsignedInt(107, 8); mooring_position = bs.ToUnsignedInt(115, 3); utc_month = bs.ToUnsignedInt(118, 4); utc_day = bs.ToUnsignedInt(122, 5); utc_hour = bs.ToUnsignedInt(127, 5); utc_min = bs.ToUnsignedInt(132, 6); services_known = bs[138]; for (size_t serv_num = 0; serv_num < 26; serv_num++) { // TODO(schwehr): const int val = bs.ToUnsignedInt(139 + 2*serv_num, 2); services[serv_num] = static_cast<int>(bs.ToUnsignedInt(139 + 2*serv_num, 2)); } name = bs.ToString(191, 120); position = bs.ToAisPoint(311, 49); assert(bs.GetRemaining() == 0); status = AIS_OK; }
Ais8_1_26_Curr3D::Ais8_1_26_Curr3D(const AisBitset &bits, const size_t offset) { for (size_t idx = 0; idx < 2; idx++) { size_t start = offset + idx * 33; currents[idx].north = bits.ToUnsignedInt(start, 8) / 10.; currents[idx].east = bits.ToUnsignedInt(start + 8, 8) / 10.; currents[idx].up = bits.ToUnsignedInt(start + 16, 8) / 10.; currents[idx].depth = bits.ToUnsignedInt(start + 24, 9); } type = bits.ToUnsignedInt(offset + 66, 3); spare = bits.ToUnsignedInt(offset + 69, 16); }
// IMO Circ 289 - Tidal Window // See also Circ 236 Ais6_1_14::Ais6_1_14(const char *nmea_payload, const size_t pad) : Ais6(nmea_payload, pad), utc_month(0), utc_day(0) { // TODO(schwehr): untested - no sample of the correct length yet assert(dac == 1); assert(fi == 14); if (num_bits != 376) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } bs.SeekTo(88); utc_month = bs.ToUnsignedInt(88, 4); utc_day = bs.ToUnsignedInt(92, 5); for (size_t window_num = 0; window_num < 3; window_num++) { Ais6_1_14_Window w; const size_t start = 97 + window_num * 93; // Reversed order for lng/lat. float y = bs.ToInt(start, 27) / 600000.; float x = bs.ToInt(start + 27, 28) / 600000.; w.position = AisPoint(x, y); w.utc_hour_from = bs.ToUnsignedInt(start + 55, 5); w.utc_min_from = bs.ToUnsignedInt(start + 60, 6); w.utc_hour_to = bs.ToUnsignedInt(start + 66, 5); w.utc_min_to = bs.ToUnsignedInt(start + 71, 6); w.cur_dir = bs.ToUnsignedInt(start + 77, 9); w.cur_speed = bs.ToUnsignedInt(start + 86, 7) / 10.; windows.push_back(w); } assert(bs.GetRemaining() == 0); status = AIS_OK; }
// IMO Circ 289 - Tidal window // See also Circ 236 Ais6_1_32::Ais6_1_32(const char *nmea_payload, const size_t pad) : Ais6(nmea_payload, pad), utc_month(0), utc_day(0) { assert(dac == 1); assert(fi == 32); // TODO(schwehr): might get messages with not all windows if (num_bits != 350) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } bs.SeekTo(88); utc_month = bs.ToUnsignedInt(88, 4); utc_day = bs.ToUnsignedInt(92, 5); for (size_t window_num = 0; window_num < 3; window_num++) { Ais6_1_32_Window w; const size_t start = 97 + 88*window_num; w.position = bs.ToAisPoint(start, 49); w.from_utc_hour = bs.ToUnsignedInt(start + 49, 5); w.from_utc_min = bs.ToUnsignedInt(start + 54, 6); w.to_utc_hour = bs.ToUnsignedInt(start + 60, 5); w.to_utc_min = bs.ToUnsignedInt(start + 65, 6); w.cur_dir = bs.ToUnsignedInt(start + 71, 9); w.cur_speed = bs.ToUnsignedInt(start + 80, 8) / 10.; windows.push_back(w); } assert(bs.GetRemaining() == 0); status = AIS_OK; }
Ais8_366_22::Ais8_366_22(const char *nmea_payload, const size_t pad) : Ais8(nmea_payload, pad), link_id(0), notice_type(0), month(0), day(0), utc_hour(0), utc_minute(0), duration_minutes(0) { assert(dac == 366); assert(fi == 22); if (num_bits <= 208 || num_bits >= 1020) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } link_id = bs.ToUnsignedInt(56, 10); notice_type = bs.ToUnsignedInt(66, 7); month = bs.ToUnsignedInt(73, 4); day = bs.ToUnsignedInt(77, 5); utc_hour = bs.ToUnsignedInt(82, 5); utc_minute = bs.ToUnsignedInt(87, 6); duration_minutes = bs.ToUnsignedInt(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; return; } } assert(bs.GetRemaining() == 0); status = AIS_OK; }
Ais23::Ais23(const char *nmea_payload, const size_t pad) : AisMsg(nmea_payload, pad), spare(0), station_type(0), type_and_cargo(0), spare2(3), txrx_mode(0), interval_raw(0), quiet(0), spare3(0) { assert(message_id == 23); if (pad != 2 || num_chars != 27) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } bs.SeekTo(38); spare = bs.ToUnsignedInt(38, 2); position1 = bs.ToAisPoint(40, 35); position2 = bs.ToAisPoint(75, 35); station_type = bs.ToUnsignedInt(110, 4); type_and_cargo = bs.ToUnsignedInt(114, 8); spare2 = bs.ToUnsignedInt(122, 22); txrx_mode = bs.ToUnsignedInt(144, 2); interval_raw = bs.ToUnsignedInt(146, 4); quiet = bs.ToUnsignedInt(150, 4); spare3 = bs.ToUnsignedInt(154, 6); assert(bs.GetRemaining() == 0); status = AIS_OK; }
// IMO Circ 289 - Dangerous cargo // See also Circ 236 Ais6_1_12::Ais6_1_12(const char *nmea_payload, const size_t pad) : Ais6(nmea_payload, pad), un(0), value(0), value_unit(0), spare2(0) { assert(dac == 1); assert(fi == 12); if (num_bits != 360) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } // TODO(schwehr): add in the offset of the dest mmsi #if 0 bs.SeekTo(56); last_port = bs.ToString(56, 30); utc_month_dep = bs.ToUnsignedInt(86, 4); utc_day_dep = bs.ToUnsignedInt(90, 5); utc_hour_dep = bs.ToUnsignedInt(95, 5); utc_min_dep = bs.ToUnsignedInt(100, 6); next_port = bs.ToString(106, 30); utc_month_next = bs.ToUnsignedInt(136, 4); // estimated arrival utc_day_next = bs.ToUnsignedInt(140, 5); utc_hour_next = bs.ToUnsignedInt(145, 5); utc_min_next = bs.ToUnsignedInt(150, 6); main_danger = bs.ToString(156, 120); imo_cat = bs.ToString(276, 24); un = bs.ToUnsignedInt(300, 13); value = bs.ToUnsignedInt(313, 10); // TODO(schwehr): units value_unit = bs.ToUnsignedInt(323, 2); spare = bs.ToUnsignedInt(325, 3); // 360 #endif // TODO(schwehr): Add assert(bs.GetRemaining() == 0); status = AIS_OK; }
Ais8_366_22_Text::Ais8_366_22_Text(const AisBitset &bits, const size_t offset) { text = string(bits.ToString(offset + 3, 84)); spare = bits.ToUnsignedInt(offset + 87, 3); }
// IMO Circ 289 - Dangerous cargo indication 2 // See also Circ 236 Ais6_1_25::Ais6_1_25(const char *nmea_payload, const size_t pad) : Ais6(nmea_payload, pad), amount_unit(0), amount(0) { assert(dac == 1); assert(fi == 25); // TODO(schwehr): verify multiple of the size of cargos + header // or padded to a slot boundary // Allowing a message with no payloads // TODO(schwehr): (num_bits - 100) % 17 != 0) is okay if (num_bits < 100 || num_bits > 576) { status = AIS_ERR_BAD_BIT_COUNT; return; } if ((num_bits - 100) % 17 != 0) { status = AIS_ERR_BAD_BIT_COUNT; return; } AisBitset bs; const AIS_STATUS r = bs.ParseNmeaPayload(nmea_payload, pad); if (r != AIS_OK) { status = r; return; } bs.SeekTo(88); amount_unit = bs.ToUnsignedInt(88, 2); amount = bs.ToUnsignedInt(90, 10); const size_t total_cargos = static_cast<int>(floor((num_bits - 100) / 17.)); for (size_t cargo_num = 0; cargo_num < total_cargos; cargo_num++) { Ais6_1_25_Cargo cargo; const size_t start = 100 + 17*cargo_num; cargo.code_type = bs.ToUnsignedInt(start, 4); // TODO(schwehr): Is this the correct behavior? switch (cargo.code_type) { // No 0 case 1: // IMDG Code in packed form cargo.imdg = bs.ToUnsignedInt(start + 4, 7); cargo.imdg_valid = true; cargo.spare = bs.ToUnsignedInt(start + 11, 6); cargo.spare_valid = true; break; case 2: // IGC Code cargo.un = bs.ToUnsignedInt(start + 4, 13); cargo.un_valid = true; break; case 3: // BC Code cargo.bc = bs.ToUnsignedInt(start + 4, 3); cargo.bc_valid = true; cargo.imdg = bs.ToUnsignedInt(start + 7, 7); cargo.imdg_valid = true; cargo.spare = bs.ToUnsignedInt(start + 14, 3); cargo.spare_valid = true; break; case 4: // MARPOL Annex I cargo.marpol_oil = bs.ToUnsignedInt(start + 4, 4); cargo.marpol_oil_valid = true; cargo.spare = bs.ToUnsignedInt(start + 8, 9); cargo.spare_valid = true; break; case 5: // MARPOL Annex II IBC cargo.marpol_cat = bs.ToUnsignedInt(start + 4, 3); cargo.marpol_cat_valid = true; cargo.spare = bs.ToUnsignedInt(start + 7, 10); cargo.spare_valid = true; break; // 6: Regional use // 7: 7-15 reserved for future default: break; // Just push in an all blank record? } cargos.push_back(cargo); } assert(bs.GetRemaining() == 0); status = AIS_OK; }