summaryrefslogtreecommitdiff
path: root/.agent/worklog.md
diff options
context:
space:
mode:
Diffstat (limited to '.agent/worklog.md')
-rw-r--r--.agent/worklog.md141
1 files changed, 141 insertions, 0 deletions
diff --git a/.agent/worklog.md b/.agent/worklog.md
new file mode 100644
index 0000000..e17781b
--- /dev/null
+++ b/.agent/worklog.md
@@ -0,0 +1,141 @@
+# SESSION_STATE.md
+
+## Current Task Goal
+Section 7.3 AIS display — COMPLETE (2026-03-15): AIS integrated into ViewModel, MapFragment, and MainActivity
+
+## Verified (2026-03-15)
+- All 41 tests GREEN: 22 GPS/NMEA + 16 AIS + 3 ViewModel AIS (via /tmp/ais-vm-test-runner/)
+- NmeaParser extended with MWV (wind), DBT (depth), HDG/HDM (heading) parsers
+- Sensor data classes added: WindData, DepthData, HeadingData
+- NmeaStreamManager added for TCP stream management
+
+## Completed Items
+
+### [APPROVED] GpsPosition data class
+- File: `app/src/main/kotlin/org/terst/nav/gps/GpsPosition.kt`
+- Package: `org.terst.nav.gps`
+- Fields: latitude, longitude, sog (knots), cog (degrees true), timestampMs
+
+### [APPROVED] GpsProvider / GpsListener interfaces
+- File: `app/src/main/kotlin/org/terst/nav/gps/GpsProvider.kt`
+- `GpsProvider`: start/stop, position property, addListener/removeListener
+- `GpsListener`: onPositionUpdate(GpsPosition), onFixLost()
+
+### [APPROVED] DeviceGpsProvider
+- File: `app/src/main/kotlin/org/terst/nav/gps/DeviceGpsProvider.kt`
+- Wraps `LocationManager` with `GPS_PROVIDER`
+- Default interval: 1000ms (1 Hz); configurable via constructor
+- SOG: Location.speed (m/s) × 1.94384 → knots
+- COG: Location.bearing (degrees true, no conversion)
+- Fix-lost timer: fires `onFixLost()` after 10s with no update
+- Thread-safe listener list (synchronized)
+- Android dependency: Context, LocationManager, Handler — device only
+
+### [APPROVED] FakeGpsProvider + GpsProviderTest (9 tests — all GREEN)
+- File: `app/src/test/kotlin/org/terst/nav/gps/GpsProviderTest.kt`
+- No Android dependencies — pure JVM
+- Tests:
+ - `start sets started to true`
+ - `stop sets started to false`
+ - `listener receives position update`
+ - `listener notified of fix lost`
+ - `multiple listeners all receive position update`
+ - `multiple listeners all notified of fix lost`
+ - `removing listener stops notifications`
+ - `position property reflects last simulated position`
+ - `SOG conversion sanity check - 1 mps is approximately 1_94384 knots`
+
+## Build Notes
+- `app/build` and `app/.kotlin/sessions` are root-owned from a prior run.
+ Tests were verified via direct `kotlinc` + `JUnitCore` invocation (all 9 pass).
+ Full Gradle build requires fixing directory permissions: `chown -R www-data:www-data app/build app/.kotlin`
+- Pre-existing XML layout error in `activity_main.xml:300` (unrelated to GPS work)
+
+### [APPROVED] NmeaParser — RMC parser
+- File: `app/src/main/kotlin/org/terst/nav/nmea/NmeaParser.kt`
+- Parses any `*RMC` sentence (GP, GN, etc.)
+- Returns `null` for void status (V), malformed input, wrong sentence type
+- SOG/COG default to 0.0 when fields are empty
+- Latitude: positive = North, negative = South
+- Longitude: positive = East, negative = West
+- Timestamp: HHMMSS + DDMMYY → Unix epoch millis UTC (YY < 70 → 2000+YY)
+- No Android dependencies — pure JVM
+
+### [APPROVED] GpsPositionTest + NmeaParserTest (22 tests — all GREEN)
+- `app/src/test/kotlin/org/terst/nav/gps/GpsPositionTest.kt` (2 tests)
+- `app/src/test/kotlin/org/terst/nav/nmea/NmeaParserTest.kt` (11 tests)
+- `app/src/test/kotlin/org/terst/nav/gps/GpsProviderTest.kt` (9 tests, pre-existing)
+- All verified via direct `kotlinc` (1.9.22) + `JUnitCore` invocation
+
+### [APPROVED] AisVessel data class
+- File: `app/src/main/kotlin/org/terst/nav/ais/AisVessel.kt`
+- Package: `org.terst.nav.ais`
+- Fields: mmsi, name, callsign, lat, lon, sog, cog, heading, vesselType, timestampMs
+- Note: `com/example/androidapp` tree is root-owned; files placed under `org/terst/nav/` (actual project package)
+
+### [APPROVED] CpaCalculator object
+- File: `app/src/main/kotlin/org/terst/nav/ais/CpaCalculator.kt`
+- Flat-earth CPA/TCPA algorithm; returns (cpa_nm, tcpa_min)
+- Zero-relative-velocity guard: returns (currentDist, 0.0)
+
+### [APPROVED] AisVdmParser class
+- File: `app/src/main/kotlin/org/terst/nav/nmea/AisVdmParser.kt`
+- Parses !AIVDM/!AIVDO sentences; multi-part reassembly by seqId
+- Type 1/2/3: MMSI, SOG, lon, lat, COG, heading decoded
+- Type 5: MMSI, callsign (7 chars), name (20 chars), vesselType decoded; trailing '@'/' ' trimmed
+- Not-available sentinel handling: SOG=1023→0.0, COG=3600→0.0, lon=0x6791AC0→0.0, lat=0x3412140→0.0
+
+### [APPROVED] AIS Tests (16 tests — all GREEN)
+- `test-runner/src/test/kotlin/org/terst/nav/ais/AisVesselTest.kt` (4 tests)
+- `test-runner/src/test/kotlin/org/terst/nav/ais/CpaCalculatorTest.kt` (4 tests)
+- `test-runner/src/test/kotlin/org/terst/nav/nmea/AisVdmParserTest.kt` (8 tests)
+- Verification harness: `/tmp/ais-test-runner/` (JUnit5, com.example.androidapp package)
+- Production test files also in `android-app/app/src/test/kotlin/org/terst/nav/ais/`
+
+### [APPROVED] AisRepository class
+- File: `app/src/main/kotlin/org/terst/nav/ais/AisRepository.kt`
+- Upserts position targets by MMSI; merges type-5 static data (name/callsign/vesselType)
+- Pending static map: holds type-5 data until position arrives for same MMSI
+- `evictStale(nowMs)`: removes vessels older than `staleTimeoutMs` (default 10 min)
+- `AisDataSource` interface (with Flow<String>) defined in same file
+
+### [APPROVED] AisHubApiService + AisHubVessel
+- File: `app/src/main/kotlin/org/terst/nav/ais/AisHubApiService.kt`
+- Note: placed in `ais/` directory (writable) with package `org.terst.nav.data.api`
+- `AisHubVessel` data class with Moshi `@Json` and `@JsonClass(generateAdapter=true)` annotations
+- `AisHubApiService` Retrofit interface: GET /0/down with lat/lon bounding box params
+
+### [APPROVED] AisHubSource object
+- File: `app/src/main/kotlin/org/terst/nav/ais/AisHubSource.kt`
+- Converts `AisHubVessel` REST response to `AisVessel` domain objects
+- Returns null for non-numeric MMSI, lat, or lon; defaults sog/cog=0.0, heading=511, vesselType=0
+
+### [APPROVED] AIS Repository Tests (11 tests — all GREEN)
+- `app/src/test/kotlin/org/terst/nav/ais/AisRepositoryTest.kt` (7 tests)
+- `app/src/test/kotlin/org/terst/nav/ais/AisHubSourceTest.kt` (4 tests)
+- Harness: `/tmp/ais-repo-test-runner/` (JUnit5, org.terst.nav package, stub annotations for offline build)
+
+### [APPROVED] Section 7.3 AIS display — ViewModel + MapFragment integration (2026-03-15)
+- `MainViewModel.processAisSentence(sentence)` — delegates to AisRepository, updates `_aisTargets` StateFlow
+- `MainViewModel.refreshAisFromInternet(latMin, latMax, lonMin, lonMax, username, password)` — AISHub polling via inline Retrofit; skips if username empty
+- `MainViewModel.aisTargets: StateFlow<List<AisVessel>>` — exposed to observers
+- `AisRepository.ingestVessel(vessel)` — direct insert for internet-sourced vessels
+- `MapFragment.updateAisLayer(style, vessels)` — GeoJSON FeatureCollection, SymbolLayer "ais-vessels"; heading-based iconRotate; zoom-step text (visible at zoom ≥ 12)
+- `MapFragment.addShipArrowImage(style)` — rasterises ic_ship_arrow.xml into style
+- `ic_ship_arrow.xml` — pink arrow vector drawable for AIS icons
+- `MainActivity.startAisHardwareFeed(host, port)` — TCP stub reads !AIVDM lines, forwards to viewModel
+- `MainViewModelTest` — 3 new tests: valid type-1 adds vessel, same MMSI deduped, non-AIS stays empty
+- JVM test harness: `/tmp/ais-vm-test-runner/` (3 tests — all GREEN)
+
+## Next 3 Specific Steps
+1. **CPA/TCPA alarms** — use CpaCalculator in ViewModel to emit alarm when CPA < threshold; add UI indicator in MapFragment
+2. **AISHub periodic polling** — call refreshAisFromInternet() on a timer (e.g. every 60s) when GPS position is known
+3. **AIS TCP full implementation** — replace stub socket reader with NmeaStreamManager integration
+
+## Scripts Added
+- `test-runner/` — standalone Kotlin/JVM Gradle project; runs all 22 GPS/NMEA tests without Android SDK
+ - Command: `cd /workspace/nav/test-runner && GRADLE_USER_HOME=/tmp/gradle-home ./gradlew test`
+
+## Process Improvements
+- Gradle builds blocked by Android SDK requirement; added `test-runner/` JVM-only subproject as reliable test runner
+- All 22 tests verified GREEN via `test-runner/` JVM project (2026-03-14) \ No newline at end of file