Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<PackageVersion Include="AprsNet.Corpus" Version="0.5.0-alpha.1" />
<PackageVersion Include="AprsNet.DeviceId" Version="0.5.0-alpha.1" />
<PackageVersion Include="AprsNet.Filters" Version="0.5.0-alpha.1" />
<PackageVersion Include="AprsNet.Gps" Version="0.5.0-alpha.1" />
<PackageVersion Include="AprsNet.Kiss" Version="0.5.0-alpha.1" />
<PackageVersion Include="AprsNet.Kiss.Serial" Version="0.5.0-alpha.1" />
<PackageVersion Include="AprsNet.Messaging" Version="0.5.0-alpha.1" />
Expand Down
25 changes: 15 additions & 10 deletions docs/features/F1.17-dead-reckoning.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# F1.17 Dead reckoning

Status: draft
Status: built for 0.6.0 ([#198](https://github.com/APRS-NET/AprsMap/issues/198)); decisions proposed, revised
2026-10-21 for the maintainer's review. In the UI: Settings › Map › Show where moving stations probably are now.

## User story

Expand All @@ -11,22 +12,26 @@ estimate, with an indication of how old the real fix is.
## Behavior

1. A station whose last position report carried **course and speed**, with a speed of at least 5 km/h, gets an
**estimated position**: from the last reported position along the course at that speed, for the time since.
**estimated position**: from the last reported position along the course at that speed, for the time since. Only
the latest report's own course and speed count: a later report without them (a parked station) ends the estimate,
and a weather station's course and speed are its wind.
2. Estimates stop after **10 minutes** or when the station goes stale (F1.3), whichever is first; after that the station
is shown only at its last reported position.
3. **On the map**: the station's symbol moves to the estimated position, drawn with a dashed outline, and a thin dashed
line joins it to the last reported position, which keeps a small dot. A **freshness ring** around the symbol shows
the share of the 10 minutes left, shrinking as the fix ages.
4. The station's details (F1.6) show both: "Reported 3 min ago at …" and "Estimated now at …, 4.5 km on".
3. **On the map**: the station's symbol and label move to the estimated position, and a thin dashed line in the track
colour joins it to the last reported position, which keeps a small dot. A **freshness ring** around the symbol shows
the share of the 10 minutes left, an arc shrinking as the fix ages (proposed: the ring marks the estimate, rather
than a dashed outline on the symbol). Clicking the symbol where it's drawn selects the station.
4. The station's details (F1.6) keep the reported position and add a **Now** line: "Probably 2.2 km on along its
course, if it kept going".
5. Distance and bearing (F1.13) and list sorting (F1.7) use the reported position, never the estimate.
6. **Dead reckoning** (Settings › Map, and a layer toggle): On · Off; default Off. Per viewer.
7. Estimates move smoothly: they're recomputed each frame from the time (no engine traffic), within F1.4's frame
budget.
7. Estimates are worked out in the UI from the time (no engine traffic), each frame and at least **once a second**
while there's one (proposed: a second's step is smooth enough at map scales, and costs nothing between).

## Service surface

- `StationState` (the map stream) gains `Course` and `Speed` (km/h) and `PositionTime` (when the reported position was
received), for stations that report them; the UI computes the estimate per frame.
- `StationState` (the map stream) gains `Course` and `SpeedKmh`, from the latest position report only; its
`LastHeard` is when that position came. The UI computes the estimate.
- The estimate needs a destination-point calculation (G08) in the UI, which references only `AprsMap.Contracts`. Until
that is settled (decision 3), it is a small pure function in the UI, marked `// SHIM: G08`.

Expand Down
23 changes: 17 additions & 6 deletions docs/features/F2.2-beacons.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ on top. Two changes from the draft:
- On a TNC, a decay sequence starts at **10 minutes**, not 1: the 10-minute floor (behavior 6) would hold back every
shorter step anyway, so the steps are 10, 20, then the interval. APRS-IS keeps 30 seconds, 1, 2, 4, 8, 16 minutes.

Moving (speed and turns) isn't offered until GPS (F3.6).
Moving (speed and turns) is built with GPS (F3.6) for 0.6.0 ([#335](https://github.com/APRS-NET/AprsMap/issues/335)):
behavior 1.1's third schedule, decisions 3 and 5 revised, proposed 2026-10-21 for the maintainer's review.

## User story

Expand All @@ -36,8 +37,14 @@ checked what it says.
- **Decay after a change** (the default when turned on): a beacon soon after the position, symbol or comment
changes, then at doubling intervals up to the fixed interval (for example 1, 2, 4, 8, 16, then every 30
minutes), so a new position spreads quickly and then settles.
- **Moving (speed and turns)**: SmartBeaconing-style corner pegging (APRS.NET's names and defaults), offered
once the profile has a GPS (F3.6, 0.6.0); until then shown as coming.
- **Moving (speed and turns, with a GPS)**: SmartBeaconing with APRS.NET's `SmartBeaconSchedule`, fed each
fix from the profile's GPS (F3.6). While the fix is fresh: every **fast rate** (90 s) at or above the **fast
speed** (60 mph), every **slow rate** (30 minutes) at or below the **slow speed** (5 mph), in between
inversely to the speed, and at once on a turn sharper than the **turn angle** (30°) plus the **turn slope**
(255 degrees × mph) over the speed, no sooner than the **turn time** (10 s) after the last beacon. The defaults
are APRS.NET's (Dire Wolf's for a car); each can be changed in Settings › Beacons, speeds in the viewer's unit
(km/h, mph or knots after the distance unit). Without a fresh fix it beacons every interval, as Fixed; when a
fix comes back, the first moving beacon goes at once.
2. **Send via**: a checkmark for each of the profile's sources that isn't **RX only** (F2.1), all ticked by default.
RX-only sources aren't listed. Deleting a source takes it out of every beacon's Send via.
3. **Format**: uncompressed (the default) or compressed, which is shorter on air.
Expand Down Expand Up @@ -120,10 +127,14 @@ checked what it says.
settles at the fixed interval, while a change spreads quickly.
2. **30 minutes for positions and 60 for status by default, 10 minutes the shortest** (proposed), the usual fixed-station
etiquette.
3. **A 10-minute floor per RF source** (proposed), whatever the schedule, as a courtesy to the shared channel; APRS-IS has
no floor beyond the interval.
3. **A 10-minute floor per RF source** (proposed), as a courtesy to the shared channel; APRS-IS has no floor beyond the
interval. **Except Moving** (proposed 2026-10-21): a moving station is held to its own fast rate and turn time,
which SmartBeaconing exists for; a 10-minute floor would make it useless on RF.
4. **One schedule per beacon, Send via picks the sources** (proposed), rather than a schedule per source.
5. **The moving schedule waits for GPS** (proposed): it's shown as coming until F3.6, since a fixed location never moves.
5. **The moving schedule comes with GPS** (built for 0.6.0): it's always offered, says it needs a GPS, and beacons as
Fixed without a fresh fix (proposed 2026-10-21), rather than being refused for a profile without one.
6. **Moving's settings are APRS.NET's defaults, all seven adjustable** (proposed 2026-10-21), rather than presets
(car, bike, walking).

## Sources

Expand Down
109 changes: 109 additions & 0 deletions docs/features/F3.6-gps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# F3.6 GPS

Status: built for 0.6.0 ([#205](https://github.com/APRS-NET/AprsMap/issues/205)) except the OS location API, browser
geolocation and a tracked position (decision 6); decisions proposed 2026-10-21 for the maintainer's review. In the UI:
Settings › Sources › GPS; its pill in the status bar.

## User story

As a mobile operator, I plug in a GPS (or point the app at gpsd, or at a GPS shared over the network), and my station
is where the GPS says: my beacons carry my position, course and speed, my APRS-IS range follows me, and the map's
house is where I am. When the GPS loses its fix, the app says so and falls back to my profile's fixed location.

## Background: what already exists

- Sources (F1.25): a master list of sources, picked per profile; each runs, reconnects with backoff and has a pill in
the status bar. F1.25 behavior 12 sketched a GPS source with **Position for**.
- APRS.NET 0.5.0-alpha.1: `NmeaSentence` and `NmeaFixTracker` (G17) turn NMEA lines into a `GpsFix` (position, time,
speed, course, altitude, satellites, HDOP, 2D or 3D fix); `AprsNet.Gps`'s `GpsdConnection` (G30) reads gpsd and gives
the same `GpsFix`, reconnecting by itself. Reading a serial port or a socket stays in the app (G17).
- The Source console (F1.28) shows each source's traffic.

## Behavior

### Adding a GPS

1. **GPS** is a source kind in Settings › Sources, with three ways to reach it (proposed):
1. **NMEA over serial**: a port and its speed, **4800** baud by default (the NMEA 0183 rate; many USB GPSs use
9600, offered beside it);
2. **NMEA over TCP**: a host and port, **10110** by default (the port commonly used for NMEA over a network);
3. **gpsd**: a host and port, **2947** by default, on this machine or another.
2. A profile uses at most **one GPS** (proposed); a second is refused when saving, saying why.
3. A GPS never sends; it's RX only by nature (F2.1), so no Transmit choices show for it.

### Its state

4. Its pill in the status bar says how it's doing: connecting or reconnecting as other sources do, then the fix:
**No fix**, **2D fix** or **3D fix**, with the satellites used where known ("GPS · 3D fix · 9 satellites").
5. A fix is **fresh** for **60 seconds** (proposed). Without a fresh fix the pill says **GPS: no fix, using the
profile's location** when the profile has one.
6. NMEA lines read from serial or TCP go to the Source console (F1.28), each line once, so they can be watched and
saved as text. gpsd's reports aren't shown there (proposed: later, with F3.12).

### Where the station is

7. **Position for my station** (F1.25 behavior 12): while the profile's GPS has a fresh fix, the station is where the
GPS says, in everything that uses the station's location (F1.13):
1. **Beacons and Send position now** (F2.2, F2.1) send the GPS position, with **course and speed**, and the
altitude with a 3D fix;
2. **The APRS-IS filter's range** (F1.2) is around the GPS position, re-sent when the station has moved more than
a quarter of the range since the last one (proposed), at most once per filter interval as now;
3. **The map's house and Home** (F1.13, F1.4) are at the GPS position; distances and bearings from me follow.
8. Without a fresh fix, all of these use the profile's fixed location, as without a GPS. The fixed location isn't
changed by the GPS (proposed): it's the profile's setting, kept for when there's no fix.
9. The position confirmation (F2.2 behavior 12) is unchanged: beacons wait for a position sent by hand once.

### Later

10. **The OS location API** (desktop) and **browser geolocation** sent to the gateway (proposed: a follow-up issue),
and **a tracked position** (F1.25 behavior 12's second option: a GPS somewhere else shown as a named marker,
beaconed as an object). The **Moving** beacon schedule, from the GPS's speed and course, is F2.2's revision
([#335](https://github.com/APRS-NET/AprsMap/issues/335)); the sky view and accuracy are F3.12
([#331](https://github.com/APRS-NET/AprsMap/issues/331)).

## Service surface

- `GpsLink` (`Serial`, `Tcp`, `Gpsd`) and `SourceSettings.GpsLink`; a serial GPS uses `SerialPort` and `Baud`, a TCP
GPS or gpsd `Host` and `Port`. `SourceSettings.GpsFor…` makes each.
- `EngineStatus.Gps` (`GpsStatus`): the GPS source, its fix kind, position, altitude, speed, course, satellites, HDOP,
when the fix was taken, and whether it's fresh.
- Error codes: `settings.source.gps-invalid` (no port or host), `settings.profile.two-gps`.

## APRS.NET dependencies

G17 (NMEA parsing, delivered in 0.4.0-alpha.12) and G30 (gpsd client, `AprsNet.Gps`, delivered in 0.4.0-alpha.12).

## Desktop vs web differences

| | Desktop | Web (gateway) |
| --- | --- | --- |
| Where a serial GPS plugs in | This computer | The gateway's host (a container needs the device passed through) |
| Seeing the fix | The user | Everyone; changing the source is the operator's |

## Acceptance tests

1. NMEA lines (RMC, GGA, GSA) over TCP give a 3D fix with position, speed, course, altitude and satellites in the
status; the pill says "3D fix · 9 satellites"; the lines are in the console.
2. A fix older than 60 s isn't fresh, and the station falls back to the profile's location.
3. With a fresh fix, a beacon goes out at the GPS position with course and speed; without one, at the profile's.
4. Moving the GPS more than a quarter of the range re-sends the filter around the new position; less doesn't.
5. gpsd's fixes do the same.
6. A profile with two GPS sources, or a GPS without its port or host, is refused.
7. Settings › Sources offers GPS with its three links, and shows the right fields for each.

## Decisions for review

All proposed (2026-10-21), built as described so they can be tried:

1. **Three links**: NMEA over serial (4800 baud), NMEA over TCP (port 10110), gpsd (port 2947).
2. **One GPS per profile.**
3. **A fix is fresh for 60 s**, then the profile's location is used.
4. **The GPS doesn't overwrite the profile's location**; it's used while fresh.
5. **The filter follows the GPS** after moving a quarter of the range.
6. **Later**: the OS location API, browser geolocation and a tracked position; gpsd's raw reports in the console.

## Sources

- NMEA 0183 (4800 baud), gpsd's documentation (port 2947, JSON reports), the conventional NMEA-over-TCP port 10110.
- [F1.25](F1.25-sources.md) behavior 12, [F1.13](F1.13-my-location.md), [F1.2](F1.2-automatic-filter.md),
[F2.2](F2.2-beacons.md), [F1.28](F1.28-source-console.md). APRS.NET's `AprsNet.Gps` README. The design is original.
Loading
Loading