diff --git a/libraries/AP_AIS/AP_AIS.cpp b/libraries/AP_AIS/AP_AIS.cpp index 02d1ec4e91..29bde18a8b 100644 --- a/libraries/AP_AIS/AP_AIS.cpp +++ b/libraries/AP_AIS/AP_AIS.cpp @@ -343,6 +343,8 @@ bool AP_AIS::payload_decode(const char *payload) case 2: // Position Report Class A (Assigned schedule) case 3: // Position Report Class A (Response to interrogation) return decode_position_report(payload, type); + case 4: // Base Station Report + return decode_base_station_report(payload); case 5: // Static and Voyage Related Data return decode_static_and_voyage_data(payload); @@ -440,6 +442,63 @@ bool AP_AIS::decode_position_report(const char *payload, uint8_t type) return true; } +bool AP_AIS::decode_base_station_report(const char *payload) +{ + if (strlen(payload) != 28) { + return false; + } + + uint8_t repeat = get_bits(payload, 6, 7); + uint32_t mmsi = get_bits(payload, 8, 37); + uint16_t year = get_bits(payload, 38, 51); + uint8_t month = get_bits(payload, 52, 55); + uint8_t day = get_bits(payload, 56, 60); + uint8_t hour = get_bits(payload, 61, 65); + uint8_t minute = get_bits(payload, 66, 71); + uint8_t second = get_bits(payload, 72, 77); + bool fix = get_bits(payload, 78, 78); + int32_t lon = get_bits_signed(payload, 79, 106) * ((1.0f / 600000.0f)*1e7); + int32_t lat = get_bits_signed(payload, 107, 133) * ((1.0f / 600000.0f)*1e7); + uint8_t epfd = get_bits(payload, 134, 137); + // 138 - 147: spare + bool raim = get_bits(payload, 148, 148); + uint32_t radio = get_bits(payload, 149, 167); + + // log the raw infomation + if ((_log_options & AIS_OPTIONS_LOG_DECODED) != 0) { + struct log_AIS_msg4 pkt { + LOG_PACKET_HEADER_INIT(LOG_AIS_MSG4), + time_us : AP_HAL::micros64(), + repeat : repeat, + mmsi : mmsi, + year : year, + month : month, + day : day, + hour : hour, + minute : minute, + second : second, + fix : fix, + lon : lon, + lat : lat, + epfd : epfd, + raim : raim, + radio : radio + }; + AP::logger().WriteBlock(&pkt, sizeof(pkt)); + } + + uint16_t index; + if (!get_vessel_index(mmsi, index)) { + return true; + } + + _list[index].info.lat = lat; // int32_t [degE7] Latitude + _list[index].info.lon = lon; // int32_t [degE7] Longitude + _list[index].last_update_ms = AP_HAL::millis(); + + return true; +} + bool AP_AIS::decode_static_and_voyage_data(const char *payload) { if (strlen(payload) != 71) { diff --git a/libraries/AP_AIS/AP_AIS.h b/libraries/AP_AIS/AP_AIS.h index 2f52a13850..a31a187988 100644 --- a/libraries/AP_AIS/AP_AIS.h +++ b/libraries/AP_AIS/AP_AIS.h @@ -104,6 +104,7 @@ private: // decode specific message types bool decode_position_report(const char *payload, uint8_t type) WARN_IF_UNUSED; + bool decode_base_station_report(const char *payload) WARN_IF_UNUSED; bool decode_static_and_voyage_data(const char *payload) WARN_IF_UNUSED; // read the specified bits from the char array each char giving 6 bits diff --git a/libraries/AP_AIS/LogStructure.h b/libraries/AP_AIS/LogStructure.h index 46a687acec..563a29e9c6 100644 --- a/libraries/AP_AIS/LogStructure.h +++ b/libraries/AP_AIS/LogStructure.h @@ -5,6 +5,7 @@ #define LOG_IDS_FROM_AIS \ LOG_AIS_RAW_MSG,\ LOG_AIS_MSG1, \ + LOG_AIS_MSG4, \ LOG_AIS_MSG5 struct PACKED log_AIS_raw { @@ -36,6 +37,25 @@ struct PACKED log_AIS_msg1 { uint32_t radio; }; +struct PACKED log_AIS_msg4 { + LOG_PACKET_HEADER; + uint64_t time_us; + uint8_t repeat; + uint32_t mmsi; + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t fix; + int32_t lon; + int32_t lat; + uint8_t epfd; + uint8_t raim; + uint32_t radio; +}; + struct PACKED log_AIS_msg5 { LOG_PACKET_HEADER; uint64_t time_us; @@ -83,6 +103,24 @@ struct PACKED log_AIS_msg5 { // @Field: raim: RAIM flag // @Field: rad: Radio status +// @LoggerMessage: AIS4 +// @Description: Contents of 'Base Station Report' AIS message, see: https://gpsd.gitlab.io/gpsd/AIVDM.html#_type_4_base_station_report +// @Field: US: Time since system startup +// @Field: rep: Repeat Indicator +// @Field: mmsi: MMSI +// @Field: year: Year (UTC) +// @Field: mth: Month (UTC) +// @Field: day: Day (UTC) +// @Field: h: Hour (UTC) +// @Field: m: Minute (UTC) +// @Field: s: Second (UTC) +// @Field: fix: Fix quality +// @Field: lon: Longitude +// @Field: lat: Latitude +// @Field: epfd: Type of EPFD +// @Field: raim: RAIM flag +// @Field: rad: Radio status + // @LoggerMessage: AIS5 // @Description: Contents of 'static and voyage related data' AIS message, see: https://gpsd.gitlab.io/gpsd/AIVDM.html#_type_5_static_and_voyage_related_data // @Field: US: Time since system startup @@ -107,5 +145,7 @@ struct PACKED log_AIS_msg5 { "AISR", "QBBBZ", "TimeUS,num,total,ID,payload", "s----", "F0000" }, \ { LOG_AIS_MSG1, sizeof(log_AIS_msg1), \ "AIS1", "QBBIBbHbLLHHBBbI", "US,typ,rep,mmsi,nav,rot,sog,pos,lon,lat,cog,hed,sec,man,raim,rad", "s---------------", "F000000000000000" }, \ + { LOG_AIS_MSG4, sizeof(log_AIS_msg4), \ + "AIS4", "QBIHBBBBBBLLBBI", "US,rep,mmsi,year,mth,day,h,m,s,fix,lon,lat,epfd,raim,rad", "s--------------", "F00000000000000" }, \ { LOG_AIS_MSG5, sizeof(log_AIS_msg5), \ "AIS5", "QBIBINZBHHBBBBZB", "US,rep,mmsi,ver,imo,cal,nam,typ,bow,stn,prt,str,fix,dght,dst,dte", "s-------mmmm-m--", "F------------A--" }