1 #ifndef __AIS__MESSAGE__HPP__
2 #define __AIS__MESSAGE__HPP__
5 #include <marnav/utils/bitset.hpp>
12 /// All known AIS message IDs.
13 enum class message_id
: uint8_t {
15 position_report_class_a
= 1,
16 position_report_class_a_assigned_schedule
= 2,
17 position_report_class_a_response_to_interrogation
= 3,
18 base_station_report
= 4,
19 static_and_voyage_related_data
= 5,
20 binary_addressed_message
= 6,
21 binary_acknowledge
= 7,
22 binary_broadcast_message
= 8,
23 standard_sar_aircraft_position_report
= 9,
24 utc_and_date_inquiry
= 10,
25 utc_and_date_response
= 11,
26 addressed_safety_related_message
= 12,
27 safety_related_acknowledgement_
= 13,
28 safety_related_broadcast_message
= 14,
30 assignment_mode_command
= 16,
31 dgnss_binary_broadcast_message
= 17,
32 standard_class_b_cs_position_report
= 18,
33 extended_class_b_equipment_position_report
= 19,
34 data_link_management
= 20,
35 aid_to_navigation_report
= 21,
36 channel_management
= 22,
37 group_assignment_command
= 23,
38 static_data_report
= 24,
39 single_slot_binary_message
= 25,
40 multiple_slot_binary_message_with_communications_state
= 26,
41 position_report_for_long_range_applications
= 27,
44 enum class navigation_status
: uint8_t {
45 under_way_using_engine
= 0,
47 not_under_command
= 2,
48 restricted_maneuverability
= 3,
49 constrained_by_her_draught
= 4,
52 engaged_in_Fishing
= 7,
53 under_way_sailing
= 8,
59 ais_sart_is_active
= 14,
60 not_defined
= 15, // default
63 enum class ship_type
: uint8_t {
65 // 1..19 reserved for future use
67 wing_in_ground_hazardous_cat_a
= 21,
68 wing_in_ground_hazardous_cat_b
= 22,
69 wing_in_ground_hazardous_cat_c
= 23,
70 wing_in_ground_hazardous_cat_d
= 24,
71 // 25..29 WIG reserved for future use
74 towing_large
= 32, // exceeds 200m length or 25m breadth
75 dredging_or_underwater_ops
= 33,
81 high_speed_craft
= 40,
82 high_speed_craft_hazardous_cat_a
= 41,
83 high_speed_craft_hazardous_cat_b
= 42,
84 high_speed_craft_hazardous_cat_c
= 43,
85 high_speed_craft_hazardous_cat_d
= 44,
86 // 45..48 HSC reserved for future use
87 high_speed_craft_no_info
= 49,
89 search_and_rescue_vessel
= 51,
92 anti_pollution_equipment
= 54,
94 // 56..57 spare, local vessel
95 medical_transport
= 58,
98 passenger_hazardous_cat_a
= 61,
99 passenger_hazardous_cat_b
= 62,
100 passenger_hazardous_cat_c
= 63,
101 passenger_hazardous_cat_d
= 64,
102 // 65..68 Passenger reserved for future use
103 passenger_no_info
= 69,
105 cargo_hazardous_cat_a
= 71,
106 cargo_hazardous_cat_b
= 72,
107 cargo_hazardous_cat_c
= 73,
108 cargo_hazardous_cat_d
= 74,
109 // 75..78 Cargo reserved for future use
112 tanker_hazardous_cat_a
= 81,
113 tanker_hazardous_cat_b
= 82,
114 tanker_hazardous_cat_c
= 83,
115 tanker_hazardous_cat_d
= 84,
116 // 85..88 Tanker reserved for future use
119 other_hazardous_cat_a
= 91,
120 other_hazardous_cat_b
= 92,
121 other_hazardous_cat_c
= 93,
122 other_hazardous_cat_d
= 94,
123 // 95..98 Other type reserved for future use
127 /// Electronic Position Fixing Device
128 enum class epfd_fix_type
: uint8_t {
132 combined_gps_glonass
= 3,
135 integrated_navigation_system
= 6,
140 enum class virtual_aid
: uint32_t { real_aid
= 0, virtual_aid
= 1 };
142 enum class off_position_indicator
: uint32_t { on_position
= 0, off_position
= 1 };
144 /// Enumeration of all aid types
145 enum class aid_type_id
: uint32_t {
146 /// 0 : Default, Type of Aid to Navigation not specified
149 /// 1 : Reference point
152 /// 2 : RACON (radar transponder marking a navigation hazard)
155 /// 3 : Fixed structure off shore, such as oil platforms, wind farms, rigs. (Note: This
156 /// code should identify an obstruction that is fitted with an Aid-to-Navigation AIS
160 /// 4 : Spare, Reserved for future use.
163 /// 5 : Light, without sectors
164 light_no_sectors
= 5,
166 /// 6 : Light, with sectors
169 /// 7 : Leading Light Front
170 leading_light_fromt
= 7,
172 /// 8 : Leading Light Rear
173 leading_light_rear
= 8,
175 /// 9 : Beacon, Cardinal N
176 beacon_cardinal_n
= 9,
178 /// 10: Beacon, Cardinal E
179 beacon_cardinal_e
= 10,
181 /// 11: Beacon, Cardinal S
182 beacon_cardinal_s
= 11,
184 /// 12: Beacon, Cardinal W
185 beacon_cardinal_w
= 12,
187 /// 13: Beacon, Port hand
188 beacon_port_hand
= 13,
190 /// 14: Beacon, Starboard hand
191 beacon_starboard_hand
= 14,
193 /// 15: Beacon, Preferred Channel port hand
194 beacon_preferred_channel_port_hand
= 15,
196 ///< 16: Beacon, Preferred Channel starboard hand
197 beacon_preferred_channel_starboard_hand
= 16,
199 /// 17: Beacon, Isolated danger
200 beacon_isolated_danger
= 17,
202 /// 18: Beacon, Safe water
203 beacon_safe_water
= 18,
205 /// 19: Beacon, Special mark
206 beacon_sepcial_mark
= 19,
208 /// 20: Cardinal Mark N
211 /// 21: Cardinal Mark E
214 /// 22: Cardinal Mark S
217 /// 23: Cardinal Mark W
220 /// 24: Port hand Mark
223 /// 25: Starboard hand Mark
224 mark_starboard_hand
= 25,
226 /// 26: Preferred Channel Port hand
227 preferred_channel_port_hand
= 26,
229 /// 27: Preferred Channel Starboard hand
230 preferred_channel_starboard_hand
= 27,
232 /// 28: Isolated danger
233 isolated_danger
= 28,
241 /// 31: Light Vessel / LANBY / Rigs
246 enum class maneuver_indicator_id
: uint32_t { not_available
= 0, normal
= 1, special
= 2 };
248 // AIS data is coded in a binary form. This implies a need for special
249 // value that mark the invalidity of a certain value.
252 /// Value for a longitude that is not specified.
253 constexpr static const uint32_t longitude_not_available
= 0x6791AC0;
255 /// Value for a latitude that is not specified.
256 constexpr static const uint32_t latitude_not_available
= 0x3412140;
258 /// Value for a longitude that is not specified, short version.
259 constexpr static const uint32_t longitude_not_available_short
= 0x1a838;
261 /// Value for a latitude that is not specified, short version.
262 constexpr static const uint32_t latitude_not_available_short
= 0xd548;
264 /// Value for a speed over ground that is not specified.
265 constexpr static const uint32_t sog_not_available
= 1023;
267 /// Value for a course over ground that is not specified.
268 constexpr static const uint32_t cog_not_available
= 3600;
270 /// Value for a heading that is not specified.
271 constexpr static const uint32_t hdg_not_available
= 511;
273 /// Value for a rate of turn that is not specified.
274 constexpr static const int32_t rot_not_available
= 128;
276 /// Value to indicate the absense of a timestamp.
277 constexpr static const uint8_t timestamp_not_available
= 60;
279 /// Value for a year that is not specified.
280 constexpr static const uint32_t year_not_available
= 0;
282 /// Value for a month that is not specified.
283 constexpr static const uint32_t month_not_available
= 0;
285 /// Value for a day that is not specified.
286 constexpr static const uint32_t day_not_available
= 0;
288 /// Value for a hour that is not specified.
289 constexpr static const uint32_t hour_not_available
= 24;
291 /// Value for a minute that is not specified.
292 constexpr static const uint32_t minute_not_available
= 60;
294 /// Value for a second that is not specified.
295 constexpr static const uint32_t second_not_available
= 60;
299 /// Type for raw AIS data.
300 using raw
= utils::bitset
<uint8_t>;
304 char decode_sixbit_ascii(uint8_t value
);
305 uint8_t encode_sixbit_ascii(char c
);
309 std::string
trim_ais_string(const std::string
& s
);
311 /// @brief Base class for all AIS messages.
314 friend std::vector
<std::pair
<std::string
, uint32_t>> encode_message(const message
& msg
);
317 virtual ~message() = default;
319 message(const message
&) = default;
320 message
& operator=(const message
&) = default;
321 message(message
&&) = default;
322 message
& operator=(message
&&) = default;
324 message_id
type() const { return message_type
; }
327 /// Represents data to be read from / written to a bitset.
328 /// The offset and number of bits (or sixbits) is encoded in the
329 /// template signature.
331 /// This template is used to specify the mapping (offset, count) of
332 /// a specific datum within the bitset, without the need of repeating
333 /// the mapping for read and write operations.
334 template <std::size_t Offset
, std::size_t Count
, typename T
> struct bitset_value final
{
335 static constexpr std::size_t offset
= Offset
;
336 static constexpr std::size_t count
= Count
;
337 using value_type
= T
;
344 bitset_value(const bitset_value
&) = default;
345 bitset_value
& operator=(const bitset_value
&) = default;
347 bitset_value(bitset_value
&&) = default;
348 bitset_value
& operator=(bitset_value
&&) = default;
350 operator T() const { return value
; }
352 bitset_value
& operator=(T t
)
361 explicit message(message_id type
)
366 virtual raw
get_data() const = 0;
370 static std::string
read_string(
371 const raw
& bits
, raw::size_type ofs
, raw::size_type count_sixbits
);
373 static void write_string(
374 raw
& bits
, raw::size_type ofs
, raw::size_type count_sixbits
, const std::string
& s
);
380 /// Reads data from the AIS message (bitset).
381 /// This is the `enum` variant.
383 /// @tparam T `bitset_value` type.
384 /// @param[in] bits The AIS message to read from.
385 /// @param[out] t The data read from the message.
387 template <typename T
,
388 typename
std::enable_if
<std::is_enum
<typename
T::value_type
>::value
, int>::type
= 0>
389 static void get(const raw
& bits
, T
& t
)
391 typename
std::underlying_type
<typename
T::value_type
>::type tmp
;
392 bits
.get(tmp
, T::offset
, T::count
);
393 t
.value
= static_cast<typename
T::value_type
>(tmp
);
396 /// The non `enum` and non `string` variant of `get`.
398 template <typename T
, typename
std::enable_if
<!std::is_enum
<typename
T::value_type
>::value
399 && !std::is_same
<typename
T::value_type
, std::string
>::value
,
402 static void get(const raw
& bits
, T
& t
)
404 bits
.get(t
.value
, T::offset
, T::count
);
407 /// The `string` variant of `get`.
409 template <typename T
, typename
std::enable_if
<!std::is_enum
<typename
T::value_type
>::value
410 && std::is_same
<typename
T::value_type
, std::string
>::value
,
413 static void get(const raw
& bits
, T
& t
)
415 t
.value
= read_string(bits
, T::offset
, T::count
);
422 /// Writes data to the AIS message (bitset).
423 /// This is the `enum` variant.
425 /// @tparam T `bitset_value` type.
426 /// @param[in] bits The AIS message to write to.
427 /// @param[out] t The data to write into the message.
429 template <typename T
,
430 typename
std::enable_if
<std::is_enum
<typename
T::value_type
>::value
, int>::type
= 0>
431 static void set(raw
& bits
, const T
& t
)
434 static_cast<typename
std::underlying_type
<typename
T::value_type
>::type
>(t
.value
),
435 T::offset
, T::count
);
438 /// The non `enum` and non `string` variant of `set`.
440 template <typename T
, typename
std::enable_if
<!std::is_enum
<typename
T::value_type
>::value
441 && !std::is_same
<typename
T::value_type
, std::string
>::value
,
444 static void set(raw
& bits
, const T
& t
)
446 bits
.set(t
.value
, T::offset
, T::count
);
449 /// The `string` variant of `set`.
451 template <typename T
, typename
std::enable_if
<!std::is_enum
<typename
T::value_type
>::value
452 && std::is_same
<typename
T::value_type
, std::string
>::value
,
455 static void set(raw
& bits
, const T
& t
)
457 write_string(bits
, T::offset
, T::count
, t
.value
);
463 message_id message_type
;
466 /// Helper function to parse a specific sentence.
467 template <class T
> std::unique_ptr
<message
> message_parse(const raw
& bits
)
469 return std::unique_ptr
<T
>(new T
{bits
});
475 /// Checks if the specified cast is valid, throws `bad_cast` if not.
476 /// If the pointer is `nullptr`, false returns.
477 template <class T
> bool check_cast(const message
* s
)
481 if (s
->type() != T::ID
)
482 throw std::bad_cast
{};
490 /// Casts the specified message to the message given by the template parameter.
491 /// The object converted only if it is valid and of the correct type. It is not
492 /// possible to cast a message into a completley different one.
494 /// @param[in] s The message object to convert.
495 /// @retval nullptr The specified message is invalid.
496 /// @return The converted message.
497 /// @exception std::bad_cast The specified message has the wrong ID.
498 template <class T
> T
* message_cast(message
* s
)
500 return detail::check_cast
<T
>(s
) ? static_cast<T
*>(s
) : nullptr;
505 /// @see message_cast(message * s)
506 template <class T
> const T
* message_cast(const message
* s
)
508 return detail::check_cast
<T
>(s
) ? static_cast<const T
*>(s
) : nullptr;
511 /// std::unique_ptr variant.
513 /// @see message_cast(message * s)
514 template <class T
> T
* message_cast(std::unique_ptr
<message
> & s
)
516 return message_cast
<T
>(s
.get());
519 /// const std::unique_ptr variant.
521 /// @see message_cast(message * s)
522 template <class T
> const T
* message_cast(const std::unique_ptr
<message
> & s
)
524 return message_cast
<const T
>(s
.get());
531 #define MARNAV_AIS_MESSAGE_FRIENDS(s) \
532 friend std::unique_ptr<message> detail::parse_##s(const raw & bits); \
533 template <class T> friend std::unique_ptr<message> message_parse(const raw & bits);
535 #define MARNAV_AIS_DECLARE_MESSAGE_PARSE_FUNC(s) \
538 std::unique_ptr<message> parse_##s(const raw & bits); \
541 #define MARNAV_AIS_DEFINE_MESSAGE_PARSE_FUNC(s) \
544 std::unique_ptr<message> parse_##s(const raw & bits) \
546 return std::unique_ptr<s>(new s{bits}); \