27#include <wx/tokenzr.h>
29#include <wx/datetime.h>
31#include "model/comm_ais.h"
34static const long long lNaN = 0xfff8000000000000;
35#define NAN (*(double *)&lNaN)
43 if (str.Len() > 128)
return AIS_NMEAVDX_TOO_LONG;
45 if (!NMEA_AISCheckSumOK(str))
return AIS_NMEAVDX_CHECKSUM_BAD;
47 if (!pos)
return AIS_GENERIC_ERROR;
52 if (!str.Mid(1, 5).IsSameAs(_T(
"AIVDO")))
return AIS_GENERIC_ERROR;
55 wxStringTokenizer tkz(str, _T(
","));
58 token = tkz.GetNextToken();
60 token = tkz.GetNextToken();
61 int nsentences = atoi(token.mb_str());
63 token = tkz.GetNextToken();
64 int isentence = atoi(token.mb_str());
66 token = tkz.GetNextToken();
67 token = tkz.GetNextToken();
69 wxString string_to_parse;
70 string_to_parse.Clear();
83 if ((1 == nsentences) && (1 == isentence)) {
84 string_to_parse = tkz.GetNextToken();
86 wxASSERT_MSG(
false, wxT(
"Multipart AIVDO detected"));
87 return AIS_INCOMPLETE_MULTIPART;
93 auto TargetData = std::make_unique<AisTargetData>(
94 *AisTargetDataMaker::GetInstance().GetTargetData());
96 bool bdecode_result = Parse_VDXBitstring(&strbit, TargetData.get());
99 switch (TargetData->MID) {
104 if (!TargetData->b_positionDoubtful) {
105 pos->kLat = TargetData->Lat;
106 pos->kLon = TargetData->Lon;
112 if (TargetData->COG == 360.0)
115 pos->kCog = TargetData->COG;
117 if (TargetData->SOG > 102.2)
120 pos->kSog = TargetData->SOG;
122 if ((
int)TargetData->HDG == 511)
125 pos->kHdt = TargetData->HDG;
133 return AIS_GENERIC_ERROR;
138 return AIS_GENERIC_ERROR;
145 bool parse_result =
false;
146 bool b_posn_report =
false;
148 wxDateTime now = wxDateTime::Now();
150 int message_ID = bstr->
GetInt(1, 6);
151 ptd->MID = message_ID;
154 ptd->MMSI = bstr->
GetInt(9, 30);
156 switch (message_ID) {
160 ptd->NavStatus = bstr->
GetInt(39, 4);
161 ptd->SOG = 0.1 * (bstr->
GetInt(51, 10));
163 int lon = bstr->
GetInt(62, 28);
164 if (lon & 0x08000000)
166 double lon_tentative = lon / 600000.;
168 int lat = bstr->
GetInt(90, 27);
169 if (lat & 0x04000000)
171 double lat_tentative = lat / 600000.;
173 if ((lon_tentative <= 180.) && (lat_tentative <= 90.))
176 ptd->Lon = lon_tentative;
177 ptd->Lat = lat_tentative;
178 ptd->b_positionDoubtful =
false;
179 ptd->b_positionOnceValid =
true;
180 ptd->PositionReportTicks = now.GetTicks();
182 ptd->b_positionDoubtful =
true;
185 ptd->COG = 0.1 * (bstr->
GetInt(117, 12));
186 ptd->HDG = 1.0 * (bstr->
GetInt(129, 9));
188 ptd->ROTAIS = bstr->
GetInt(43, 8);
189 double rot_dir = 1.0;
191 if (ptd->ROTAIS == 128)
193 else if ((ptd->ROTAIS & 0x80) == 0x80) {
194 ptd->ROTAIS = ptd->ROTAIS - 256;
199 ptd->ROTIND = round(rot_dir * pow((((
double)ptd->ROTAIS) / 4.733), 2));
201 ptd->m_utc_sec = bstr->
GetInt(138, 6);
203 if ((1 == message_ID) || (2 == message_ID))
206 ptd->SyncState = bstr->
GetInt(151, 2);
207 ptd->SlotTO = bstr->
GetInt(153, 2);
208 if ((ptd->SlotTO == 1) && (ptd->SyncState == 0))
210 ptd->m_utc_hour = bstr->
GetInt(155, 5);
212 ptd->m_utc_min = bstr->
GetInt(160, 7);
214 if ((ptd->m_utc_hour < 24) && (ptd->m_utc_min < 60) &&
215 (ptd->m_utc_sec < 60)) {
216 wxDateTime rx_time(ptd->m_utc_hour, ptd->m_utc_min, ptd->m_utc_sec);
218 rx_ticks = rx_time.GetTicks();
220 first_rx_ticks = rx_ticks;
229 ptd->blue_paddle = bstr->
GetInt(144, 2);
230 ptd->b_blue_paddle = (ptd->blue_paddle == 2);
232 if (!ptd->b_isDSCtarget) ptd->Class = AIS_CLASS_A;
235 int mmsi_start = ptd->MMSI / 10000000;
237 if (mmsi_start == 97) {
238 ptd->Class = AIS_SART;
239 ptd->StaticReportTicks =
254 b_posn_report =
true;
261 ptd->NavStatus = UNDEFINED;
263 ptd->SOG = 0.1 * (bstr->
GetInt(47, 10));
265 int lon = bstr->
GetInt(58, 28);
266 if (lon & 0x08000000)
268 double lon_tentative = lon / 600000.;
270 int lat = bstr->
GetInt(86, 27);
271 if (lat & 0x04000000)
273 double lat_tentative = lat / 600000.;
275 if ((lon_tentative <= 180.) && (lat_tentative <= 90.))
278 ptd->Lon = lon_tentative;
279 ptd->Lat = lat_tentative;
280 ptd->b_positionDoubtful =
false;
281 ptd->b_positionOnceValid =
true;
282 ptd->PositionReportTicks = now.GetTicks();
284 ptd->b_positionDoubtful =
true;
286 ptd->COG = 0.1 * (bstr->
GetInt(113, 12));
287 ptd->HDG = 1.0 * (bstr->
GetInt(125, 9));
289 ptd->m_utc_sec = bstr->
GetInt(134, 6);
291 if (!ptd->b_isDSCtarget) ptd->Class = AIS_CLASS_B;
294 b_posn_report =
true;
304 if (b_posn_report) ptd->b_lost =
false;
306 if (
true == parse_result) {
308 if (!ptd->b_active && !ptd->b_positionDoubtful && b_posn_report)
309 ptd->b_active =
true;
315bool NMEA_AISCheckSumOK(
const wxString &str_in) {
316 unsigned char checksum_value = 0;
317 int sentence_hex_sum;
319 wxCharBuffer buf = str_in.ToUTF8();
320 if (!buf.data())
return false;
322 char str_ascii[AIS_MAX_MESSAGE_LEN + 1];
323 strncpy(str_ascii, buf.data(), AIS_MAX_MESSAGE_LEN);
324 str_ascii[AIS_MAX_MESSAGE_LEN] =
'\0';
326 int string_length = strlen(str_ascii);
328 int payload_length = 0;
329 while ((payload_length < string_length) &&
330 (str_ascii[payload_length] !=
'*'))
333 if (payload_length == string_length)
338 while (index < payload_length) {
339 checksum_value ^= str_ascii[index];
343 if (string_length > 4) {
345 scanstr[0] = str_ascii[payload_length + 1];
346 scanstr[1] = str_ascii[payload_length + 2];
348 sscanf(scanstr,
"%2x", &sentence_hex_sum);
350 if (sentence_hex_sum == checksum_value)
return true;
int GetInt(int sp, int len, bool signed_flag=false)
sp is starting bit, 1-based