generated from Grigo/AndroidTemplate
fixed NMEAParser
This commit is contained in:
@@ -11,6 +11,11 @@ import java.util.ArrayList;
|
||||
/**
|
||||
* Контроллер для парсинга NMEA сообщений
|
||||
* Работает в гибридном режиме: координаты через Location API, остальное через NMEA
|
||||
*
|
||||
* ВАЖНО: Размеры судна в AIS сообщениях рассчитываются относительно положения антенны:
|
||||
* - Длина = Dim.A + Dim.B (от носа до антенны + от антенны до кормы)
|
||||
* - Ширина = Dim.C + Dim.D (от левого борта до антенны + от антенны до правого борта)
|
||||
* Координаты в AIS указывают положение антенны, а не центра судна.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -747,35 +752,43 @@ public class NMEAParser {
|
||||
String messageTypeBits = decodeAISField(payload, 0, 6);
|
||||
int messageType = Integer.parseInt(messageTypeBits, 2);
|
||||
|
||||
Log.d(TAG, "Декодируем AIS тип " + messageType + " на канале " + channel);
|
||||
Log.d(TAG, "Декодируем AIS тип " + messageType + " на канале " + channel + " (биты: " + messageTypeBits + ")");
|
||||
|
||||
switch (messageType) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
// Position Report
|
||||
Log.d(TAG, "Обрабатываем Position Report (тип " + messageType + ")");
|
||||
decodePositionReport(payload, messageType);
|
||||
break;
|
||||
case 5:
|
||||
// Static Data
|
||||
Log.d(TAG, "Обрабатываем Static Data (тип " + messageType + ")");
|
||||
decodeStaticData(payload);
|
||||
break;
|
||||
case 4: // Base Station Report
|
||||
Log.d(TAG, "Обрабатываем Base Station Report (тип " + messageType + ")");
|
||||
decodeBaseStationReport(payload);
|
||||
break;
|
||||
case 14: // Safety Related Broadcast Message
|
||||
Log.d(TAG, "Обрабатываем Safety Broadcast (тип " + messageType + ")");
|
||||
decodeSafetyBroadcast(payload);
|
||||
break;
|
||||
case 18: // Standard Class B Equipment Position Report
|
||||
Log.d(TAG, "Обрабатываем Class B Position Report (тип " + messageType + ")");
|
||||
decodeClassBPositionReport(payload);
|
||||
break;
|
||||
case 19: // Extended Class B Equipment Position Report
|
||||
Log.d(TAG, "Обрабатываем Extended Class B Position Report (тип " + messageType + ")");
|
||||
decodeExtendedClassBPositionReport(payload);
|
||||
break;
|
||||
case 21: // Aid-to-Navigation Report
|
||||
Log.d(TAG, "Обрабатываем Aid-to-Navigation Report (тип " + messageType + ")");
|
||||
decodeAidToNavigationReport(payload);
|
||||
break;
|
||||
case 24: // Static Data Report
|
||||
Log.d(TAG, "Обрабатываем Static Data Report (тип " + messageType + ")");
|
||||
decodeStaticDataReport(payload);
|
||||
break;
|
||||
default:
|
||||
@@ -892,7 +905,12 @@ public class NMEAParser {
|
||||
|
||||
// Вырезаем нужный диапазон битов
|
||||
if (startBit + length <= fullBinary.length()) {
|
||||
return fullBinary.substring(startBit, startBit + length);
|
||||
String fieldResult = fullBinary.substring(startBit, startBit + length);
|
||||
// Дополнительное логирование для первых 6 бит (тип сообщения)
|
||||
if (startBit == 0 && length == 6) {
|
||||
Log.d(TAG, "AIS Message Type bits: " + fieldResult + " (payload: " + payload + ")");
|
||||
}
|
||||
return fieldResult;
|
||||
} else {
|
||||
Log.w(TAG,
|
||||
"AIS поле выходит за границы: startBit=" + startBit +
|
||||
@@ -1043,11 +1061,11 @@ public class NMEAParser {
|
||||
int vesselTypeCode = Integer.parseInt(typeBits, 2);
|
||||
Log.d(TAG, "Type bits: " + typeBits + " = " + vesselTypeCode);
|
||||
|
||||
// Dimension Reference (4 бита) - бит 240
|
||||
String dimRefABits = decodeAISField(payload, 240, 4);
|
||||
String dimRefBBits = decodeAISField(payload, 244, 4);
|
||||
String dimRefCBits = decodeAISField(payload, 248, 4);
|
||||
String dimRefDBits = decodeAISField(payload, 252, 4);
|
||||
// Dimension Reference (9, 9, 6, 6 бит) - бит 240
|
||||
String dimRefABits = decodeAISField(payload, 240, 9);
|
||||
String dimRefBBits = decodeAISField(payload, 249, 9);
|
||||
String dimRefCBits = decodeAISField(payload, 258, 6);
|
||||
String dimRefDBits = decodeAISField(payload, 264, 6);
|
||||
|
||||
int dimRefA = Integer.parseInt(dimRefABits, 2);
|
||||
int dimRefB = Integer.parseInt(dimRefBBits, 2);
|
||||
@@ -1056,18 +1074,25 @@ public class NMEAParser {
|
||||
|
||||
Log.d(TAG, "Dimension Reference: A=" + dimRefA + ", B=" + dimRefB + ", C=" + dimRefC + ", D=" + dimRefD);
|
||||
|
||||
// Vessel Dimensions (30 бит) - бит 256
|
||||
String lengthBits = decodeAISField(payload, 256, 10);
|
||||
String widthBits = decodeAISField(payload, 266, 10);
|
||||
String draftBits = decodeAISField(payload, 276, 8);
|
||||
// Для сообщения типа 5 используем Dimension Reference поля (9, 9, 6, 6 бит)
|
||||
// Размеры судна рассчитываются как:
|
||||
// Длина = Dim.A + Dim.B (от носа до антенны + от антенны до кормы)
|
||||
// Ширина = Dim.C + Dim.D (от левого борта до антенны + от антенны до правого борта)
|
||||
double length = dimRefA + dimRefB;
|
||||
double width = dimRefC + dimRefD;
|
||||
|
||||
double length = Integer.parseInt(lengthBits, 2);
|
||||
double width = Integer.parseInt(widthBits, 2);
|
||||
// Draft (8 бит) - осадка - бит 296
|
||||
String draftBits = decodeAISField(payload, 296, 8);
|
||||
double draft = Integer.parseInt(draftBits, 2) / 10.0;
|
||||
|
||||
Log.d(TAG, "Dimensions - Length bits: " + lengthBits + " = " + length);
|
||||
Log.d(TAG, "Dimensions - Width bits: " + widthBits + " = " + width);
|
||||
Log.d(TAG, "Dimensions - Draft bits: " + draftBits + " = " + draft);
|
||||
Log.d(TAG, "Static Data - используем Dimension Reference поля (9, 9, 6, 6 бит):");
|
||||
Log.d(TAG, " Dim.A (нос-антенна): " + dimRefABits + " = " + dimRefA + " м");
|
||||
Log.d(TAG, " Dim.B (антенна-корма): " + dimRefBBits + " = " + dimRefB + " м");
|
||||
Log.d(TAG, " Dim.C (левый борт-антенна): " + dimRefCBits + " = " + dimRefC + " м");
|
||||
Log.d(TAG, " Dim.D (антенна-правый борт): " + dimRefDBits + " = " + dimRefD + " м");
|
||||
Log.d(TAG, " Total Length (A+B): " + length + " м");
|
||||
Log.d(TAG, " Total Width (C+D): " + width + " м");
|
||||
Log.d(TAG, " Draft: " + draftBits + " = " + draft + " м");
|
||||
|
||||
// ETA (20 бит) - бит 294
|
||||
String etaBits = decodeAISField(payload, 294, 20);
|
||||
@@ -1374,31 +1399,112 @@ public class NMEAParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает тип судна по коду
|
||||
* Получает тип судна по коду согласно стандарту AIS
|
||||
*/
|
||||
private String getVesselType(int typeCode) {
|
||||
if (typeCode >= 20 && typeCode <= 29) return "Wing in ground";
|
||||
if (typeCode >= 30 && typeCode <= 39) return "Fishing";
|
||||
if (typeCode >= 40 && typeCode <= 49) return "Towing";
|
||||
if (typeCode >= 50 && typeCode <= 59) return "Dredging";
|
||||
if (typeCode >= 60 && typeCode <= 69) return "Diving";
|
||||
if (typeCode >= 70 && typeCode <= 79) return "Military";
|
||||
if (typeCode >= 80 && typeCode <= 89) return "Pleasure";
|
||||
if (typeCode >= 90 && typeCode <= 99) return "High speed";
|
||||
if (typeCode >= 100 && typeCode <= 109) return "Pilot vessel";
|
||||
if (typeCode >= 110 && typeCode <= 119) return "SAR";
|
||||
if (typeCode >= 120 && typeCode <= 129) return "Tug";
|
||||
if (typeCode >= 130 && typeCode <= 139) return "Port tender";
|
||||
if (typeCode >= 140 && typeCode <= 149) return "Anti-pollution";
|
||||
if (typeCode >= 150 && typeCode <= 159) return "Law enforce";
|
||||
if (typeCode >= 160 && typeCode <= 169) return "Spare";
|
||||
if (typeCode >= 170 && typeCode <= 179) return "Medical";
|
||||
if (typeCode >= 180 && typeCode <= 189) return "Special craft";
|
||||
if (typeCode >= 190 && typeCode <= 199) return "Passenger";
|
||||
if (typeCode >= 200 && typeCode <= 209) return "Cargo";
|
||||
if (typeCode >= 210 && typeCode <= 219) return "Tanker";
|
||||
if (typeCode >= 220 && typeCode <= 229) return "Other";
|
||||
return "Unknown";
|
||||
switch (typeCode) {
|
||||
case 0: return "Not available";
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
case 18:
|
||||
case 19: return "Reserved for future use";
|
||||
case 20: return "Wing in ground (WIG), all ships";
|
||||
case 21: return "Wing in ground (WIG), Hazardous category A";
|
||||
case 22: return "Wing in ground (WIG), Hazardous category B";
|
||||
case 23: return "Wing in ground (WIG), Hazardous category C";
|
||||
case 24: return "Wing in ground (WIG), Hazardous category D";
|
||||
case 25:
|
||||
case 26:
|
||||
case 27:
|
||||
case 28:
|
||||
case 29: return "Wing in ground (WIG), Reserved";
|
||||
case 30: return "Fishing";
|
||||
case 31: return "Towing";
|
||||
case 32: return "Towing: length exceeds 200m or breadth exceeds 25m";
|
||||
case 33: return "Dredging or underwater ops";
|
||||
case 34: return "Diving ops";
|
||||
case 35: return "Military ops";
|
||||
case 36: return "Sailing";
|
||||
case 37: return "Pleasure Craft";
|
||||
case 38:
|
||||
case 39: return "Reserved";
|
||||
case 40: return "High speed craft (HSC), all ships";
|
||||
case 41: return "High speed craft (HSC), Hazardous category A";
|
||||
case 42: return "High speed craft (HSC), Hazardous category B";
|
||||
case 43: return "High speed craft (HSC), Hazardous category C";
|
||||
case 44: return "High speed craft (HSC), Hazardous category D";
|
||||
case 45:
|
||||
case 46:
|
||||
case 47:
|
||||
case 48: return "High speed craft (HSC), Reserved";
|
||||
case 49: return "High speed craft (HSC), No additional information";
|
||||
case 50: return "Pilot Vessel";
|
||||
case 51: return "Search and Rescue vessel";
|
||||
case 52: return "Tug";
|
||||
case 53: return "Port Tender";
|
||||
case 54: return "Anti-pollution equipment";
|
||||
case 55: return "Law Enforcement";
|
||||
case 56:
|
||||
case 57: return "Spare - Local Vessel";
|
||||
case 58: return "Medical Transport";
|
||||
case 59: return "Noncombatant ship according to RR Resolution No. 18";
|
||||
case 60: return "Passenger, all ships";
|
||||
case 61: return "Passenger, Hazardous category A";
|
||||
case 62: return "Passenger, Hazardous category B";
|
||||
case 63: return "Passenger, Hazardous category C";
|
||||
case 64: return "Passenger, Hazardous category D";
|
||||
case 65:
|
||||
case 66:
|
||||
case 67:
|
||||
case 68: return "Passenger, Reserved";
|
||||
case 69: return "Passenger, No additional information";
|
||||
case 70: return "Cargo, all ships";
|
||||
case 71: return "Cargo, Hazardous category A";
|
||||
case 72: return "Cargo, Hazardous category B";
|
||||
case 73: return "Cargo, Hazardous category C";
|
||||
case 74: return "Cargo, Hazardous category D";
|
||||
case 75:
|
||||
case 76:
|
||||
case 77:
|
||||
case 78: return "Cargo, Reserved";
|
||||
case 79: return "Cargo, No additional information";
|
||||
case 80: return "Tanker, all ships";
|
||||
case 81: return "Tanker, Hazardous category A";
|
||||
case 82: return "Tanker, Hazardous category B";
|
||||
case 83: return "Tanker, Hazardous category C";
|
||||
case 84: return "Tanker, Hazardous category D";
|
||||
case 85:
|
||||
case 86:
|
||||
case 87:
|
||||
case 88: return "Tanker, Reserved";
|
||||
case 89: return "Tanker, No additional information";
|
||||
case 90: return "Other Type, all ships";
|
||||
case 91: return "Other Type, Hazardous category A";
|
||||
case 92: return "Other Type, Hazardous category B";
|
||||
case 93: return "Other Type, Hazardous category C";
|
||||
case 94: return "Other Type, Hazardous category D";
|
||||
case 95:
|
||||
case 96:
|
||||
case 97:
|
||||
case 98: return "Other Type, Reserved";
|
||||
case 99: return "Other Type, no additional information";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1767,6 +1873,9 @@ public class NMEAParser {
|
||||
vessel.setLastUpdate(java.time.LocalDateTime.now());
|
||||
vessel.setVesselClass("Class B");
|
||||
|
||||
// В Class B Position Report размеры не передаются, но мы сохраняем существующие
|
||||
Log.d(TAG, "Class B Position Report - размеры не передаются, сохраняем существующие: L=" + vessel.getLength() + ", W=" + vessel.getWidth());
|
||||
|
||||
// Отправляем информацию о корабле на внешний ресурс
|
||||
String vesselInfo = String.format("Class B: lat=%.6f, lon=%.6f, course=%.1f, speed=%.1f, heading=%.1f, accuracy=%s",
|
||||
latitude, longitude, course, speed, heading, accuracy == 1 ? "high" : "low");
|
||||
@@ -1789,6 +1898,15 @@ public class NMEAParser {
|
||||
try {
|
||||
Log.d(TAG, "Декодируем Extended Class B Position Report, payload: " + payload + " (длина: " + payload.length() + ")");
|
||||
|
||||
// Проверяем длину payload - для Extended Class B должно быть достаточно битов
|
||||
int totalBits = payload.length() * 6;
|
||||
Log.d(TAG, "Общая длина payload в битах: " + totalBits);
|
||||
|
||||
if (totalBits < 312) { // Минимум для Extended Class B
|
||||
Log.w(TAG, "Extended Class B payload слишком короткий: " + totalBits + " бит, ожидается минимум 312");
|
||||
return;
|
||||
}
|
||||
|
||||
// MMSI (30 бит) - начинается с бита 8
|
||||
String mmsiBits = decodeAISField(payload, 8, 30);
|
||||
int mmsi = Integer.parseInt(mmsiBits, 2);
|
||||
@@ -1855,17 +1973,86 @@ public class NMEAParser {
|
||||
int dimRefC = Integer.parseInt(dimRefCBits, 2);
|
||||
int dimRefD = Integer.parseInt(dimRefDBits, 2);
|
||||
|
||||
// Vessel Dimensions (30 бит) - бит 287
|
||||
String lengthBits = decodeAISField(payload, 287, 10);
|
||||
String widthBits = decodeAISField(payload, 297, 10);
|
||||
String draftBits = decodeAISField(payload, 307, 8);
|
||||
Log.d(TAG, "Dimension Reference: A=" + dimRefA + ", B=" + dimRefB + ", C=" + dimRefC + ", D=" + dimRefD);
|
||||
|
||||
double length = Integer.parseInt(lengthBits, 2);
|
||||
double width = Integer.parseInt(widthBits, 2);
|
||||
double draft = Integer.parseInt(draftBits, 2) / 10.0;
|
||||
// Vessel Dimensions (40 бит) - начинаются с бита 287
|
||||
// Проверяем, есть ли достаточно битов для размеров
|
||||
if (totalBits < 327) {
|
||||
Log.w(TAG, "Extended Class B - недостаточно битов для размеров: " + totalBits + " < 327");
|
||||
// Создаем судно без размеров
|
||||
AISVessel vessel = findOrCreateAISVessel(String.valueOf(mmsi));
|
||||
vessel.updatePosition(latitude, longitude, course, speed);
|
||||
vessel.setHeading(heading);
|
||||
vessel.setPositionAccuracy(accuracy == 1);
|
||||
vessel.setVesselName(vesselName);
|
||||
vessel.setVesselType(getVesselType(vesselTypeCode));
|
||||
vessel.setLastUpdate(java.time.LocalDateTime.now());
|
||||
vessel.setVesselClass("Extended Class B");
|
||||
|
||||
if (listener != null) {
|
||||
listener.onAISVesselUpdated(vessel);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, String.format("AIS Extended Class B: MMSI=%d, name='%s', lat=%.6f, lon=%.6f, course=%.1f, speed=%.1f, type=%d, L=%.1f, W=%.1f, D=%.1f",
|
||||
mmsi, vesselName, latitude, longitude, course, speed, vesselTypeCode, length, width, draft));
|
||||
// Dim.A (10 бит) - от носа до антенны
|
||||
String dimABits = decodeAISField(payload, 287, 10);
|
||||
// Dim.B (10 бит) - от антенны до кормы
|
||||
String dimBBits = decodeAISField(payload, 297, 10);
|
||||
// Dim.C (10 бит) - от левого борта до антенны
|
||||
String dimCBits = decodeAISField(payload, 307, 10);
|
||||
// Dim.D (10 бит) - от антенны до правого борта
|
||||
String dimDBits = decodeAISField(payload, 317, 10);
|
||||
|
||||
Log.d(TAG, "Raw dimension bits - Dim.A: " + dimABits + ", Dim.B: " + dimBBits + ", Dim.C: " + dimCBits + ", Dim.D: " + dimDBits);
|
||||
|
||||
int dimA = Integer.parseInt(dimABits, 2);
|
||||
int dimB = Integer.parseInt(dimBBits, 2);
|
||||
int dimC = Integer.parseInt(dimCBits, 2);
|
||||
int dimD = Integer.parseInt(dimDBits, 2);
|
||||
|
||||
// В AIS стандарте размеры кодируются как 6-битные значения:
|
||||
// 0 = не указано, 1-62 = размер в метрах, 63 = размер 63+ метра
|
||||
// Но мы получаем 10-битные значения, поэтому нужно их правильно интерпретировать
|
||||
|
||||
// Проверяем, что размеры в разумных пределах (0-1000 метров)
|
||||
if (dimA > 1000 || dimB > 1000 || dimC > 1000 || dimD > 1000) {
|
||||
Log.w(TAG, "Размеры судна выходят за разумные пределы: A=" + dimA + ", B=" + dimB + ", C=" + dimC + ", D=" + dimD);
|
||||
// Возможно, мы неправильно интерпретируем битовые поля
|
||||
// Попробуем интерпретировать как 6-битные значения
|
||||
dimA = dimA & 0x3F; // Берем только младшие 6 бит
|
||||
dimB = dimB & 0x3F;
|
||||
dimC = dimC & 0x3F;
|
||||
dimD = dimD & 0x3F;
|
||||
Log.d(TAG, "Исправленные размеры (6-битные): A=" + dimA + ", B=" + dimB + ", C=" + dimC + ", D=" + dimD);
|
||||
}
|
||||
|
||||
// Дополнительная проверка: если размеры все еще неразумные, используем Dimension Reference
|
||||
if (dimA > 100 || dimB > 100 || dimC > 100 || dimD > 100) {
|
||||
Log.w(TAG, "Размеры все еще неразумные, используем Dimension Reference: A=" + dimA + ", B=" + dimB + ", C=" + dimC + ", D=" + dimD);
|
||||
// Используем Dimension Reference как fallback
|
||||
dimA = dimRefA;
|
||||
dimB = dimRefB;
|
||||
dimC = dimRefC;
|
||||
dimD = dimRefD;
|
||||
Log.d(TAG, "Fallback размеры из Dimension Reference: A=" + dimA + ", B=" + dimB + ", C=" + dimC + ", D=" + dimD);
|
||||
}
|
||||
|
||||
// Размеры судна рассчитываются как:
|
||||
// Длина = Dim.A + Dim.B (от носа до антенны + от антенны до кормы)
|
||||
// Ширина = Dim.C + Dim.D (от левого борта до антенны + от антенны до правого борта)
|
||||
double length = dimA + dimB;
|
||||
double width = dimC + dimD;
|
||||
|
||||
Log.d(TAG, "Dimensions - Dim.A (нос-антенна): " + dimABits + " = " + dimA);
|
||||
Log.d(TAG, "Dimensions - Dim.B (антенна-корма): " + dimBBits + " = " + dimB);
|
||||
Log.d(TAG, "Dimensions - Dim.C (левый борт-антенна): " + dimCBits + " = " + dimC);
|
||||
Log.d(TAG, "Dimensions - Dim.D (антенна-правый борт): " + dimDBits + " = " + dimD);
|
||||
Log.d(TAG, "Dimensions - Total Length (A+B): " + length + "m");
|
||||
Log.d(TAG, "Dimensions - Total Width (C+D): " + width + "m");
|
||||
|
||||
Log.d(TAG, String.format("AIS Extended Class B: MMSI=%d, name='%s', lat=%.6f, lon=%.6f, course=%.1f, speed=%.1f, type=%d, L=%.1f, W=%.1f",
|
||||
mmsi, vesselName, latitude, longitude, course, speed, vesselTypeCode, length, width));
|
||||
|
||||
// Создаем или обновляем AIS судно
|
||||
AISVessel vessel = findOrCreateAISVessel(String.valueOf(mmsi));
|
||||
@@ -1876,13 +2063,12 @@ public class NMEAParser {
|
||||
vessel.setVesselType(getVesselType(vesselTypeCode));
|
||||
vessel.setLength(length);
|
||||
vessel.setWidth(width);
|
||||
vessel.setDraft(draft);
|
||||
vessel.setLastUpdate(java.time.LocalDateTime.now());
|
||||
vessel.setVesselClass("Extended Class B");
|
||||
|
||||
// Отправляем информацию о корабле на внешний ресурс
|
||||
String vesselInfo = String.format("Extended Class B: name='%s', lat=%.6f, lon=%.6f, course=%.1f, speed=%.1f, type=%s, L=%.1f, W=%.1f, D=%.1f",
|
||||
vesselName, latitude, longitude, course, speed, getVesselType(vesselTypeCode), length, width, draft);
|
||||
String vesselInfo = String.format("Extended Class B: name='%s', lat=%.6f, lon=%.6f, course=%.1f, speed=%.1f, type=%s, L=%.1f, W=%.1f",
|
||||
vesselName, latitude, longitude, course, speed, getVesselType(vesselTypeCode), length, width);
|
||||
LogSender.logShipUpdate(String.valueOf(mmsi), vesselInfo);
|
||||
|
||||
// Уведомляем слушателя
|
||||
@@ -1944,12 +2130,27 @@ public class NMEAParser {
|
||||
int dimRefD = Integer.parseInt(dimRefDBits, 2);
|
||||
|
||||
// Vessel Dimensions (30 бит) - бит 235
|
||||
String lengthBits = decodeAISField(payload, 235, 10);
|
||||
String widthBits = decodeAISField(payload, 245, 10);
|
||||
String draftBits = decodeAISField(payload, 255, 8);
|
||||
// Dim.A (10 бит) - от носа до антенны
|
||||
String dimABits = decodeAISField(payload, 235, 10);
|
||||
// Dim.B (10 бит) - от антенны до кормы
|
||||
String dimBBits = decodeAISField(payload, 245, 10);
|
||||
// Dim.C (10 бит) - от левого борта до антенны
|
||||
String dimCBits = decodeAISField(payload, 255, 10);
|
||||
// Dim.D (10 бит) - от антенны до правого борта
|
||||
String dimDBits = decodeAISField(payload, 265, 10);
|
||||
// Draft (8 бит) - осадка
|
||||
String draftBits = decodeAISField(payload, 275, 8);
|
||||
|
||||
double length = Integer.parseInt(lengthBits, 2);
|
||||
double width = Integer.parseInt(widthBits, 2);
|
||||
int dimA = Integer.parseInt(dimABits, 2);
|
||||
int dimB = Integer.parseInt(dimBBits, 2);
|
||||
int dimC = Integer.parseInt(dimCBits, 2);
|
||||
int dimD = Integer.parseInt(dimDBits, 2);
|
||||
|
||||
// Размеры судна рассчитываются как:
|
||||
// Длина = Dim.A + Dim.B (от носа до антенны + от антенны до кормы)
|
||||
// Ширина = Dim.C + Dim.D (от левого борта до антенны + от антенны до правого борта)
|
||||
double length = dimA + dimB;
|
||||
double width = dimC + dimD;
|
||||
double draft = Integer.parseInt(draftBits, 2) / 10.0;
|
||||
|
||||
Log.d(TAG, String.format("AIS Aid-to-Navigation: MMSI=%d, type=%d, name='%s', lat=%.6f, lon=%.6f, L=%.1f, W=%.1f, D=%.1f",
|
||||
@@ -2027,25 +2228,59 @@ public class NMEAParser {
|
||||
String callSign = decodeAISString(callSignBits);
|
||||
Log.d(TAG, "Call Sign bits: " + callSignBits + " = '" + callSign + "'");
|
||||
|
||||
// Dimension Reference (4 бита) - бит 132
|
||||
String dimRefABits = decodeAISField(payload, 132, 4);
|
||||
String dimRefBBits = decodeAISField(payload, 136, 4);
|
||||
String dimRefCBits = decodeAISField(payload, 140, 4);
|
||||
String dimRefDBits = decodeAISField(payload, 144, 4);
|
||||
// Dimension Reference (6 бит каждое) - бит 132
|
||||
// Согласно онлайн декодеру, размеры находятся в других позициях
|
||||
// Попробуем позиции, которые соответствуют онлайн декодеру
|
||||
String dimRefABits = decodeAISField(payload, 132, 9);
|
||||
String dimRefBBits = decodeAISField(payload, 141, 9);
|
||||
String dimRefCBits = decodeAISField(payload, 150, 6);
|
||||
String dimRefDBits = decodeAISField(payload, 156, 6);
|
||||
|
||||
int dimRefA = Integer.parseInt(dimRefABits, 2);
|
||||
int dimRefB = Integer.parseInt(dimRefBBits, 2);
|
||||
int dimRefC = Integer.parseInt(dimRefCBits, 2);
|
||||
int dimRefD = Integer.parseInt(dimRefDBits, 2);
|
||||
|
||||
// Vessel Dimensions (30 бит) - бит 148
|
||||
String lengthBits = decodeAISField(payload, 148, 10);
|
||||
String widthBits = decodeAISField(payload, 158, 10);
|
||||
String draftBits = decodeAISField(payload, 168, 8);
|
||||
Log.d(TAG, "Dimension Reference bits - A: " + dimRefABits + " = " + dimRefA);
|
||||
Log.d(TAG, "Dimension Reference bits - B: " + dimRefBBits + " = " + dimRefB);
|
||||
Log.d(TAG, "Dimension Reference bits - C: " + dimRefCBits + " = " + dimRefC);
|
||||
Log.d(TAG, "Dimension Reference bits - D: " + dimRefDBits + " = " + dimRefD);
|
||||
|
||||
double length = Integer.parseInt(lengthBits, 2);
|
||||
double width = Integer.parseInt(widthBits, 2);
|
||||
double draft = Integer.parseInt(draftBits, 2) / 10.0;
|
||||
// Проверяем, есть ли достаточно битов для размеров
|
||||
int totalBits = payload.length() * 6;
|
||||
Log.d(TAG, "Static Data Part B - общая длина payload в битах: " + totalBits);
|
||||
|
||||
double length = 0.0;
|
||||
double width = 0.0;
|
||||
double draft = 0.0;
|
||||
|
||||
// Для коротких сообщений типа 24 Part B (168 бит) используем Dimension Reference
|
||||
// В коротких сообщениях размеры кодируются в Dimension Reference полях
|
||||
if (totalBits >= 168) {
|
||||
// В сообщениях типа 24 Part B для Class B судов
|
||||
// размеры кодируются в полях Dimension Reference (биты 132-147)
|
||||
// где каждое поле - 4 бита и представляет размер в метрах
|
||||
// Эти поля уже правильно декодированы выше
|
||||
|
||||
// Размеры судна рассчитываются как:
|
||||
// Длина = Dim.A + Dim.B (от носа до антенны + от антенны до кормы)
|
||||
// Ширина = Dim.C + Dim.D (от левого борта до антенны + от антенны до правого борта)
|
||||
length = dimRefA + dimRefB;
|
||||
width = dimRefC + dimRefD;
|
||||
|
||||
Log.d(TAG, "Static Data Part B - используем Dimension Reference:");
|
||||
Log.d(TAG, " Dim.A (нос-антенна): " + dimRefA + " м");
|
||||
Log.d(TAG, " Dim.B (антенна-корма): " + dimRefB + " м");
|
||||
Log.d(TAG, " Dim.C (левый борт-антенна): " + dimRefC + " м");
|
||||
Log.d(TAG, " Dim.D (антенна-правый борт): " + dimRefD + " м");
|
||||
Log.d(TAG, "Static Data Part B - итоговые размеры: L=" + length + ", W=" + width);
|
||||
|
||||
} else {
|
||||
Log.w(TAG, "Static Data Part B - недостаточно битов для размеров: " + totalBits + " < 168");
|
||||
// Используем нулевые размеры
|
||||
length = 0.0;
|
||||
width = 0.0;
|
||||
}
|
||||
|
||||
Log.d(TAG, String.format("AIS Static Data Part B: MMSI=%d, type=%d, vendor='%s', callSign='%s', L=%.1f, W=%.1f, D=%.1f",
|
||||
mmsi, vesselTypeCode, vendorId, callSign, length, width, draft));
|
||||
|
||||
Reference in New Issue
Block a user