Ковырял декодер строк

This commit is contained in:
2025-09-12 15:53:55 +03:00
parent bdc0aa3ccf
commit a2f1775f9f
2 changed files with 86 additions and 136 deletions
@@ -1081,8 +1081,8 @@ public class NMEAParser {
double length = dimRefA + dimRefB; double length = dimRefA + dimRefB;
double width = dimRefC + dimRefD; double width = dimRefC + dimRefD;
// Draft (8 бит) - осадка - бит 296 // Draft (8 бит) - осадка - бит 294
String draftBits = decodeAISField(payload, 296, 8); String draftBits = decodeAISField(payload, 294, 8);
double draft = Integer.parseInt(draftBits, 2) / 10.0; double draft = Integer.parseInt(draftBits, 2) / 10.0;
Log.d(TAG, "Static Data - используем Dimension Reference поля (9, 9, 6, 6 бит):"); Log.d(TAG, "Static Data - используем Dimension Reference поля (9, 9, 6, 6 бит):");
@@ -1094,8 +1094,8 @@ public class NMEAParser {
Log.d(TAG, " Total Width (C+D): " + width + " м"); Log.d(TAG, " Total Width (C+D): " + width + " м");
Log.d(TAG, " Draft: " + draftBits + " = " + draft + " м"); Log.d(TAG, " Draft: " + draftBits + " = " + draft + " м");
// ETA (20 бит) - бит 294 // ETA (20 бит) - бит 274
String etaBits = decodeAISField(payload, 294, 20); String etaBits = decodeAISField(payload, 274, 20);
int eta = Integer.parseInt(etaBits, 2); int eta = Integer.parseInt(etaBits, 2);
Log.d(TAG, "ETA bits: " + etaBits + " = " + eta); Log.d(TAG, "ETA bits: " + etaBits + " = " + eta);
@@ -1109,7 +1109,7 @@ public class NMEAParser {
// Вычисляем доступную длину для оставшихся полей // Вычисляем доступную длину для оставшихся полей
int totalBits = payload.length() * 6; int totalBits = payload.length() * 6;
int remainingBits = totalBits - 314; // Остается после ETA int remainingBits = totalBits - 294; // Остается после ETA
Log.d(TAG, "Remaining bits after ETA: " + remainingBits + " (total: " + totalBits + ")"); Log.d(TAG, "Remaining bits after ETA: " + remainingBits + " (total: " + totalBits + ")");
String destination = ""; String destination = "";
@@ -1117,81 +1117,18 @@ public class NMEAParser {
String epfdDescription = "Unknown"; String epfdDescription = "Unknown";
boolean dteReady = false; boolean dteReady = false;
// Для коротких сообщений (426 бит) используем упрощенную структуру // Destination (120 бит) - бит 302
if (totalBits <= 426) { if (totalBits >= 302 + 120) {
// В коротких сообщениях может не быть всех полей String destBits = decodeAISField(payload, 302, 120);
// Пробуем разные позиции для Destination destination = decodeAISString(destBits);
int[] possibleDestStarts = {302, 314, 320, 328}; Log.d(TAG, "Destination bits: " + destBits + " = '" + destination + "'");
for (int destStartBit : possibleDestStarts) { } else if (remainingBits > 0) {
if (destStartBit + 120 <= totalBits) { // Если сообщение короткое, читаем доступные биты
String destBits = decodeAISField(payload, destStartBit, 120); int destStartBit = 302;
String testDest = decodeAISString(destBits); int destLength = Math.min(remainingBits, 120);
Log.d(TAG, "Пробуем Destination с бита " + destStartBit + ": " + testDest); String destBits = decodeAISField(payload, destStartBit, destLength);
if (testDest.contains("DEFAULT") || testDest.contains("FAULT")) { destination = decodeAISString(destBits);
destination = testDest; Log.d(TAG, "Destination bits (short): " + destBits + " = '" + destination + "' (length: " + destLength + ")");
Log.d(TAG, "Найден Destination с бита " + destStartBit + ": '" + destination + "'");
break;
}
}
}
// Если не нашли, используем стандартную позицию
if (destination.isEmpty() && remainingBits > 0) {
int destStartBit = 314;
int destLength = Math.min(remainingBits, 120);
String destBits = decodeAISField(payload, destStartBit, destLength);
destination = decodeAISString(destBits);
Log.d(TAG, "Destination bits (fallback): " + destBits + " = '" + destination + "' (length: " + destLength + ")");
}
} else {
// Для полных сообщений используем стандартную структуру
if (remainingBits >= 8) {
// Maximum present static draught (8 бит) - бит 314
String draughtBits = decodeAISField(payload, 314, 8);
int draughtValue = Integer.parseInt(draughtBits, 2);
maxDraught = (draughtValue == 0) ? 0.0 : (draughtValue == 255) ? 25.5 : draughtValue / 10.0;
Log.d(TAG, "Max Draught bits: " + draughtBits + " = " + maxDraught + "m");
remainingBits -= 8;
}
if (remainingBits >= 4) {
// Type of electronic position fixing device (4 бита)
int epfdStartBit = 314 + 8;
String epfdBits = decodeAISField(payload, epfdStartBit, 4);
int epfdType = Integer.parseInt(epfdBits, 2);
epfdDescription = getEPFDType(epfdType);
Log.d(TAG, "EPFD Type bits: " + epfdBits + " = " + epfdType + " (" + epfdDescription + ")");
remainingBits -= 4;
}
if (remainingBits >= 1) {
// DTE (1 бит)
int dteStartBit = 314 + 8 + 4;
String dteBits = decodeAISField(payload, dteStartBit, 1);
dteReady = Integer.parseInt(dteBits, 2) == 0;
Log.d(TAG, "DTE bits: " + dteBits + " = " + dteReady + " (ready: " + dteReady + ")");
remainingBits -= 1;
}
if (remainingBits >= 1) {
// Spare (1 бит)
int spareStartBit = 314 + 8 + 4 + 1;
String spareBits = decodeAISField(payload, spareStartBit, 1);
int spare = Integer.parseInt(spareBits, 2);
Log.d(TAG, "Spare bits: " + spareBits + " = " + spare);
remainingBits -= 1;
}
if (remainingBits > 0) {
// Destination (оставшиеся биты)
int destStartBit = 314 + 8 + 4 + 1 + 1;
int destLength = Math.min(remainingBits, 120); // Максимум 120 бит
String destBits = decodeAISField(payload, destStartBit, destLength);
destination = decodeAISString(destBits);
Log.d(TAG, "Destination bits (full): " + destBits + " = '" + destination + "' (length: " + destLength + ")");
} else {
Log.w(TAG, "Destination поле недоступно - недостаточно битов");
}
} }
Log.d(TAG, String.format("AIS Static: MMSI=%d, IMO=%d, name='%s', callSign='%s', type=%d, L=%.1f, W=%.1f, D=%.1f, maxD=%.1f, ETA=%s, EPFD=%s, DTE=%s, dest='%s'", Log.d(TAG, String.format("AIS Static: MMSI=%d, IMO=%d, name='%s', callSign='%s', type=%d, L=%.1f, W=%.1f, D=%.1f, maxD=%.1f, ETA=%s, EPFD=%s, DTE=%s, dest='%s'",
@@ -1300,52 +1237,29 @@ public class NMEAParser {
/** /**
* Декодирует AIS строку * Декодирует AIS строку
*/ */
//TODO: Исправить на нормальный декодер строк
private String decodeAISString(String bits) { private String decodeAISString(String bits) {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
Log.d(TAG, "Декодируем AIS строку из битов: " + bits + " (длина: " + bits.length() + ")");
for (int i = 0; i + 6 <= bits.length(); i += 6) {
for (int i = 0; i < bits.length(); i += 6) { String charBits = bits.substring(i, i + 6);
if (i + 6 <= bits.length()) { int value = Integer.parseInt(charBits, 2);
String charBits = bits.substring(i, i + 6);
int value = Integer.parseInt(charBits, 2); char decodedChar;
if (value == 0) {
char decodedChar; decodedChar = ' '; // 0 = пробел
Log.d(TAG, "Обрабатываем значение: " + value + " (биты: " + charBits + ")"); } else if (value >= 1 && value <= 26) {
decodedChar = (char) ('A' + value - 1); // 1..26 = A..Z
// Приоритет специальных случаев (пробелы) } else if (value >= 27 && value <= 36) {
if (value == 32 || value == 63) { decodedChar = (char) ('0' + (value - 27)); // 27..36 = 0..9
decodedChar = ' '; // Пробел } else {
Log.d(TAG, "Найден пробел (" + value + ")"); decodedChar = ' '; // всё остальное = пробел
} else if (value >= 1 && value <= 26) {
// Заглавные буквы A-Z
decodedChar = (char)('A' + value - 1);
Log.d(TAG, "Диапазон A-Z: " + value + " -> " + decodedChar);
} else if (value >= 49 && value <= 58) {
// Цифры 1-9 (кастомное сопоставление на основе AIS1)
decodedChar = (char)('1' + (value - 49));
Log.d(TAG, "Диапазон 1-9: " + value + " -> " + decodedChar);
} else if (value == 59) {
// Цифра 0 (кастомное сопоставление)
decodedChar = '0';
Log.d(TAG, "Декодирован символ (59) -> '0'");
} else if (value == 0) {
// Нулевое значение - конец строки, но не останавливаемся сразу
decodedChar = ' '; // Заменяем на пробел для продолжения
Log.d(TAG, "Найден ноль, заменяем на пробел");
} else {
// Неизвестный или зарезервированный символ
decodedChar = '?';
Log.w(TAG, "Неизвестное или зарезервированное значение AIS символа: " + value + " (биты: " + charBits + ")");
}
result.append(decodedChar);
Log.d(TAG, "Декодирован символ: " + charBits + " (" + value + ") -> '" + decodedChar + "'");
} }
result.append(decodedChar);
} }
String resultStr = result.toString().trim(); return result.toString().trim();
Log.d(TAG, "Результат декодирования строки: '" + resultStr + "'");
return resultStr;
} }
/** /**
@@ -69,11 +69,27 @@ public class CompassView extends BaseDockWidget {
} }
private float getShortestRotation(float start, float end) { private float getShortestRotation(float start, float end) {
// Нормализуем углы к диапазону 0-360
start = normalizeAngle(start);
end = normalizeAngle(end);
float diff = end - start; float diff = end - start;
while (diff > 180) diff -= 360;
while (diff < -180) diff += 360; // Если разность больше 180°, идем в обратную сторону
if (diff > 180) {
diff -= 360;
} else if (diff < -180) {
diff += 360;
}
return diff; return diff;
} }
private float normalizeAngle(float angle) {
while (angle < 0) angle += 360;
while (angle >= 360) angle -= 360;
return angle;
}
@@ -109,9 +125,11 @@ public class CompassView extends BaseDockWidget {
// Плавное обновление азимута // Плавное обновление азимута
float diff = getShortestRotation(currentAzimuth, targetAzimuth); float diff = getShortestRotation(currentAzimuth, targetAzimuth);
if (Math.abs(diff) > 0.1f) { if (Math.abs(diff) > 0.1f) {
currentAzimuth += diff * SMOOTHING_FACTOR; // Ограничиваем максимальное изменение за один кадр
if (currentAzimuth > 360) currentAzimuth -= 360; float maxChange = 3.0f; // максимальное изменение в градусах за кадр
if (currentAzimuth < 0) currentAzimuth += 360; float change = Math.signum(diff) * Math.min(Math.abs(diff * SMOOTHING_FACTOR), maxChange);
currentAzimuth += change;
currentAzimuth = normalizeAngle(currentAzimuth);
postInvalidateOnAnimation(); postInvalidateOnAnimation();
} }
@@ -123,8 +141,7 @@ public class CompassView extends BaseDockWidget {
// Рисуем деления шкалы // Рисуем деления шкалы
for (int degree = 0; degree < 360; degree += 15) { for (int degree = 0; degree < 360; degree += 15) {
// Вычисляем относительное положение деления // Вычисляем относительное положение деления
float relativeDegree = (degree - currentAzimuth + 360) % 360; float relativeDegree = getShortestRotation(currentAzimuth, degree);
if (relativeDegree > 180) relativeDegree -= 360;
// Рисуем только видимые деления // Рисуем только видимые деления
if (Math.abs(relativeDegree) <= visibleDegrees / 2) { if (Math.abs(relativeDegree) <= visibleDegrees / 2) {
@@ -149,8 +166,7 @@ public class CompassView extends BaseDockWidget {
// Рисуем суда // Рисуем суда
for (AISVessel vessel : nearbyVessels) { for (AISVessel vessel : nearbyVessels) {
float relativeBearing = (float) ((vessel.getCourse() - currentAzimuth + 360) % 360); float relativeBearing = getShortestRotation(currentAzimuth, (float) vessel.getCourse());
if (relativeBearing > 180) relativeBearing -= 360;
if (Math.abs(relativeBearing) <= visibleDegrees / 2) { if (Math.abs(relativeBearing) <= visibleDegrees / 2) {
float x = centerX + (relativeBearing / (visibleDegrees / 2)) * (w / 2); float x = centerX + (relativeBearing / (visibleDegrees / 2)) * (w / 2);
double distance = ourVessel != null ? GeoUtils.calculateDistance(ourVessel, vessel) : 0; double distance = ourVessel != null ? GeoUtils.calculateDistance(ourVessel, vessel) : 0;
@@ -218,9 +234,11 @@ public class CompassView extends BaseDockWidget {
// Плавное обновление азимута // Плавное обновление азимута
float diff = getShortestRotation(currentAzimuth, targetAzimuth); float diff = getShortestRotation(currentAzimuth, targetAzimuth);
if (Math.abs(diff) > 0.1f) { if (Math.abs(diff) > 0.1f) {
currentAzimuth += diff * SMOOTHING_FACTOR; // Ограничиваем максимальное изменение за один кадр
if (currentAzimuth > 360) currentAzimuth -= 360; float maxChange = 3.0f; // максимальное изменение в градусах за кадр
if (currentAzimuth < 0) currentAzimuth += 360; float change = Math.signum(diff) * Math.min(Math.abs(diff * SMOOTHING_FACTOR), maxChange);
currentAzimuth += change;
currentAzimuth = normalizeAngle(currentAzimuth);
postInvalidateOnAnimation(); postInvalidateOnAnimation();
} }
@@ -246,7 +264,7 @@ public class CompassView extends BaseDockWidget {
// Рисуем суда по кругу // Рисуем суда по кругу
for (AISVessel vessel : nearbyVessels) { for (AISVessel vessel : nearbyVessels) {
float bearing = (float) ((vessel.getCourse() - currentAzimuth + 360) % 360); float bearing = getShortestRotation(currentAzimuth, (float) vessel.getCourse());
float angle = (float) Math.toRadians(bearing); float angle = (float) Math.toRadians(bearing);
float vesselRadius = radius * 0.6f; float vesselRadius = radius * 0.6f;
float vx = cx + (float) Math.sin(angle) * vesselRadius; float vx = cx + (float) Math.sin(angle) * vesselRadius;
@@ -313,7 +331,25 @@ public class CompassView extends BaseDockWidget {
} }
public void setAzimuth(float azimuth) { public void setAzimuth(float azimuth) {
this.targetAzimuth = azimuth; // Проверяем на валидность азимута
if (Float.isNaN(azimuth) || Float.isInfinite(azimuth)) {
return; // Игнорируем невалидные значения
}
// Нормализуем входящий азимут
this.targetAzimuth = normalizeAngle(azimuth);
// Если текущий азимут еще не инициализирован, устанавливаем его сразу
if (currentAzimuth == 0 && targetAzimuth != 0) {
currentAzimuth = targetAzimuth;
}
// Специальная обработка для 0° - если текущий азимут близок к 360°,
// то 0° должен интерпретироваться как 360°
if (targetAzimuth == 0 && currentAzimuth > 350) {
this.targetAzimuth = 360;
}
invalidate(); invalidate();
} }