Brent Perteet a788cebea3 test(S1-b): add IF-LOC codec boundary/edge-case vectors
QA-owned boundary coverage for the frozen IF-LOC v1.0 codec, complementing
app-owner's nominal round-trip suite. Pins min/max/resolution limits per wire
field via the pure Encode/Decode seam, staying clear of the no-value sentinels,
and characterises the two sentinel-collision edges (depth -327.68 m, current
0xFFFF) so the contract's documented ranges are enforceable.

40/40 green; full QA gate green (app 43 + server 2). Trace: SRS §3.1, Risk R-3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-20 13:13:49 -05:00
2026-07-10 20:29:01 -05:00
2026-07-10 20:29:01 -05:00
2026-07-10 20:29:01 -05:00

Field Logger

Cross-platform .NET MAUI app (Windows, macOS, iOS, Android) for logging utility locate points from an Underground Magnetics locating receiver paired with RTK GPS positions from a Maglink (H11) RTK receiver, both over BLE.

Solution layout

FieldLogger/
  Models/            Device protocol models (UmLogPacket, GnssFix) and DB entities (Job, LoggedPoint)
  Services/
    Ble/             BleSerialClient (line-oriented GATT serial) and BleScanner (Plugin.BLE)
    UmReceiverService.cs      $UMPBDL protocol, PBDL schema-1 packet parsing
    MaglinkService.cs         $GNPOS/$GNDEV NMEA parsing + AT commands
    DeviceConnectionManager.cs  Auto-connect on launch, reconnect with backoff
    PointLogger.cs            Joins locator packets with the latest GNSS fix, saves to SQLite
    Data/AppDatabase.cs       sqlite-net-pcl store (jobs + points)
    Sync/IMqttSyncService.cs  Stub for the future MQTT job/point synchronization
  ViewModels/ + Views/        Shell tabs: Home, Jobs, Map, Settings (+ DeviceScan, JobDetail)
  Resources/Raw/map.html      Google Maps JS page used by the Windows map view
doc/                 Device protocol documentation

How it works

  • First launch: the Home page redirects to the device scan page. Pick your locating receiver (names starting with UMRX or DT100) and, from Settings or Home, the Maglink RTK receiver. Selections are persisted.
  • Subsequent launches: DeviceConnectionManager auto-connects to both saved devices and keeps retrying/reconnecting with backoff. Devices can be changed or forgotten in Settings.
  • Logging: create a job (Home or Jobs tab) — it becomes the active job. When the operator presses the log button on the UM receiver, the app receives the PBDL packet, attaches the most recent RTK fix (if fresher than 5 s), and stores the combined record with all metadata in SQLite (fieldlogger.db3 in app data).
  • Map: plots the active (or selected) job's points. Native map control on iOS/Android/macOS (Google Maps on Android, Apple Maps on iOS/macOS); Google Maps JavaScript in a WebView on Windows.

Setup required before running

  1. Google Maps key (Android): the manifest key is injected at build time, never committed (SEC-1). Provide it one of three ways: pass -p:MapsApiKey=<key> to dotnet build (how CI supplies it from a secret), set the MAPS_API_KEY environment variable, or copy maps.key.props.example to maps.key.props (gitignored) at the repo root and put your key there. Use a key restricted to the app package + release SHA-1 (Google Cloud Console → Maps SDK for Android). Without a key, maps render blank but the app builds.
  2. Google Maps key (Windows): create a Maps JavaScript API key and paste it into the Settings page of the app.
  3. Maglink GATT UUIDs: the Maglink docs describe the serial protocol but not its GATT table. MaglinkService currently assumes the Nordic UART Service (6e400001-b5a3-f393-e0a9-e50e24dcca9e). Verify against the actual hardware (any BLE scanner app will show the service UUIDs) and update the constants at the top of FieldLogger/Services/MaglinkService.cs if they differ.

Building and running

All commands are run from the repository root. (dotnet run does not support MAUI projects — use dotnet build -t:Run to deploy and launch instead.)

Windows

# Build
dotnet build FieldLogger/FieldLogger.csproj -f net9.0-windows10.0.19041.0

# Run (unpackaged; WindowsPackageType=None)
dotnet build FieldLogger/FieldLogger.csproj -f net9.0-windows10.0.19041.0 -t:Run
# ...or launch the built exe directly:
.\FieldLogger\bin\Debug\net9.0-windows10.0.19041.0\win10-x64\FieldLogger.exe

Android

# Build (APK is produced under bin/Debug/net9.0-android)
dotnet build FieldLogger/FieldLogger.csproj -f net9.0-android

# Deploy + launch on the connected device or running emulator
dotnet build FieldLogger/FieldLogger.csproj -f net9.0-android -t:Run

# If several devices/emulators are attached, pick one by adb serial (see `adb devices`)
dotnet build FieldLogger/FieldLogger.csproj -f net9.0-android -t:Run -p:AdbTarget="-s emulator-5554"

Note: BLE does not work in the Android emulator — use a physical device (enable USB debugging, then adb devices to confirm it is attached).

iOS (requires a Mac; run these on the Mac, or from Windows via Visual Studio's paired Mac)

# Build
dotnet build FieldLogger/FieldLogger.csproj -f net9.0-ios

# Run in the default iOS Simulator (note: the simulator has no Bluetooth)
dotnet build FieldLogger/FieldLogger.csproj -f net9.0-ios -t:Run

# Run on a specific simulator by UDID (list with: xcrun simctl list devices)
dotnet build FieldLogger/FieldLogger.csproj -f net9.0-ios -t:Run -p:_DeviceName=:v2:udid=<SIMULATOR_UDID>

# Run on a physical iPhone (requires provisioning profile / signing set up in Xcode first)
dotnet build FieldLogger/FieldLogger.csproj -f net9.0-ios -t:Run -p:RuntimeIdentifier=ios-arm64 -p:_DeviceName=<DEVICE_UDID>

macOS (Mac Catalyst — requires a Mac)

# Build
dotnet build FieldLogger/FieldLogger.csproj -f net9.0-maccatalyst

# Build + launch
dotnet build FieldLogger/FieldLogger.csproj -f net9.0-maccatalyst -t:Run

Visual Studio

Open FieldLogger.sln, pick the target framework/device in the debug-target dropdown, and press F5. This is the most convenient route for iOS from Windows (via a paired Mac) and for Android device debugging.

Roadmap

  • MQTT sync (Services/Sync/IMqttSyncService.cs is the seam): receive configured jobs from the server and publish logged points. Job.RemoteId / Synced and LoggedPoint.Synced columns are already in the schema. Suggested client: MQTTnet.
  • The Maglink can also upload positions directly via MQTT (AT+UPLOADDATA_* commands, see doc/AT_UPLOADDATA_MQTT_Configuration_EN.md) if server-side ingestion is preferred.
Description
No description provided
Readme 1.4 MiB
Languages
C# 94.4%
Shell 4.6%
HTML 0.9%