Repository navigation
pdn_aprs 0.3.0
API changes:
- New builder calls, so nothing existing changes:
pdn_aprs_build_telemetry_channels()(a presence flag per analog channel, so a channel can be empty;pdn_aprs_build_telemetry()calls it with all present),pdn_aprs_build_status_options()withpdn_aprs_status_options(locator with symbol, and beam heading and power;pdn_aprs_build_status()calls it), andpdn_aprs_build_message_reply_ack()(reply-ack,""for support with nothing to ack). Because the public structs change as below, this still needs a minor version bump. pdn_aprs_third_party.packetnow holds2 * PDN_APRS_MAX_INFObytes, as text does, so the encoder takes an inner packet longer than the decoder reads off the air; onlypdn_aprs_third_partychanges layout (pdn_aprs_dataandpdn_aprs_packetkeep their sizes and offsets), but rebuild anything that includespdn_aprs.h.pdn_aprs_decode_third_party()decodes such a long inner packet, which keeps no copy of its information field, and returnsPDN_APRS_ERR_ARGUMENTfor alenlarger thanpacket.- The
pdn_aprs_build_mic_e()locator is now sent in upper case, as the status builder's is. - The diff dump tool refuses (no longer reports
unsupported) a third-party packet whose inner data is unrecognized but not empty. - Deliberate design limits, now written in the README: text longer than 1,024 bytes and text holding a NUL are not buildable through the builder (no allocation, C strings); the diff dump tool reports them as
unsupportedand nothing else. - New
pdn_aprs_decode_written(): decodes an information field aspdn_aprs_decode_info()does, but keeps no copy of it, so it takes one longer thanPDN_APRS_MAX_INFO. It returnsPDN_APRS_ERR_TOO_LONGonly when a part of the field is longer than the packet's data holds. pdn_aprs_querygainslatitude_textandlongitude_text, a general query's footprint numbers as sent, so struct layouts change: rebuild everything that includespdn_aprs.h.course_degreesinpdn_aprs_report,pdn_aprs_positionandpdn_aprs_mic_e, andradius_milesinpdn_aprs_query, are nowdouble, so a program can give a course or a radius between whole numbers and the encoder rounds it to the step of the field it goes in (a compressed course to 4 degrees, once). Decoded values are still whole numbers. Code that prints them with%uneeds a cast or%.0f.pdn_aprs_mic_egainshas_altitude_mandaltitude_m, an altitude in metres for the Mic-E altitude bytes, rounded to the metre.altitude_feetis now always written as a/A=(vectors ruling B2); before, the encoder put it in the Mic-E bytes whenever it was a whole number of metres. Give one or the other.pdn_aprs_build_message()refuses an empty message ID (""), which it took as none; pass NULL for none (ruling B8).
Encoding:
- No size limit (vectors ruling E11: the rules set none). The encoder refused an information field over 512 bytes, which text received as Latin-1 and written back as UTF-8 can be; it now writes any length that fits the buffer, straight into it, and checks what it wrote with
pdn_aprs_decode_written().PDN_APRS_ERR_BUFFERmeans the buffer is too small to write and check the field. - Exact bytes (vectors rulings E1-E12): the vectors'
canonical_infois now binding, so where the spec allows several forms the encoder writes the one the Encoding rule names.- A general query's footprint numbers are written as sent, with or without a leading space (
?APRS? 34.0,-117.15,0200,-.1715); it wrote them normalised (E1). - After the data extension a position, object or item report's comment is written in the order the voice frequency with its fields, the braces, the
/A=altitude, the free text after a space, base-91 telemetry, the!DAO!(j006/058/146.520MHz/A=000889 Dayton Bound): the frequency comes first, in the bytes radios read (APRS12c ch. 18); it came after the altitude (E3). - A Mic-E speed of 190-199 knots is written with
/, the printable one of its two forms; it wrote DEL (E5). - Mic-E status text starting with 0x1D after Rev 0 telemetry is written straight on; the
/is only for status text that would start with 0x1D (E6). - No delimiter where none is needed: none before
.../...text after a compressed position, which has no data extension to mistake it for, and none before text after a Mic-E type code that only looks like a locator (wO91SX/G: a locator's first two letters are A-R). The space after a frequency is written before a comment that starts with a NUL, which was taken for a tone letter (E7). - Snowfall under 1 inch is
.and two digits (0.5 as.50); it wrote0.5(E8). - A compressed wind direction that rounds to 360 degrees is written as north (c = 0); a 358-degree wind was refused (E9). A compressed course that rounds to north (1 degree, say) is no longer refused either.
- A
!DAO!on a compressed position carries the digits of the position the compressed bytes report; they were taken from the position given, which can differ by a fraction of a compressed step (E2).
- A general query's footprint numbers are written as sent, with or without a leading space (
- A value is range-checked once rounded to the step its field holds: a humidity of 99.7% is written
h00(100%), a speed of 999.4 knots999, a luminosity of 999.7 W/m2l000. They were refused. - NMEA data whose position, fix, course, speed, altitude, time or waypoint disagrees with its sentence is refused, since the sentence is written as it is and would read back with its own; the fields were not checked. Fields left unset are not checked, so data holding only a sentence is still written.
- Exact bytes, batch 2 (vectors rulings F1-F17, B1-B8, G1-G3 and the run 2 rulings; vectors e27a79f):
- Values between steps are rounded once to the nearest step, halves away from zero, a value within 1e-6 of a half (measured in steps) being the half, and checked after rounding (F2): a course or speed,
/A=feet, Mic-E speed and course, latitude and longitude minutes, DAO digits, weather values, RNG miles, a footprint radius, a voice frequency, and what the cs bytes carry. Negative halves went toward +infinity (-0.5 wast000and/A=000000; nowt-01and/A=-00001), and halves were decided without the tolerance (58.584999999999996 minutes from 0.9764166666666666 degrees is now58.59). A course of -0.3 is 0 and a course of 360.4 is 360. A value the cs bytes carry rounds to the nearest step of their formula for any whole s, and is refused when that s is outside the byte (G3): a compressed speed of -0.03 knots is written as 0, -0.3 is refused, a range of 1.95 miles is written as 2. With a!DAO!the position is taken in DAO steps, rounded once, and split into the main digits and the DAO digit. - A course of 0 is written only where it reads back as 0:
000uncompressed, refused in Mic-E and compressed reports, after rounding (F1). A compressed course needs a speed and a speed a course (F5). - Snowfall that rounds to a whole number is three digits (0.995 is
001, 9.96 is010), and one that rounds past 999 is refused (F3). - A frequency after a DF bearing or storm data follows a
/(F9). - Numbers given without their text (F11): a telemetry value that is a whole number 0-999 is three digits (
005,000,091); a general query's footprint latitude and longitude that are not negative take a leading space, 0 included (F15), and the radius is rounded to whole miles. - A compressed weather report's GGA altitude goes in the cs bytes alone, rounded to their step, as it has no comment for a
/A=(F14); it was refused. - Comment text holding a PHG, RNG or DFS after an area is refused, since it now reads back as the data extension (F7a). A Mic-E locator followed straight by base-91 telemetry or a
!DAO!is written (F16). - Text after an area symbol that only looks like an area (
81019310, whose1form would give colour 19) is written straight on, as a decoder does not read it as one; it was written after a/(E7). - A luminosity that rounds to 1000 W/m2 (999.5) is
l000; it was refused. - A Mic-E comment starting with
/that a/delimiter would still join into an altitude (/{}after a/A=) is written after a space; it was refused. - The ambiguity cut takes the 1e-6 tolerance in the box's units, so 80.49 degrees (29.40 minutes) is the box 29.4x (G2).
- With ambiguity, the Mic-E longitude digits a decoder ignores hold the centre it reports (README Mic-E rule); they held the position's own digits.
- Where neither the canonical form nor a
/reads back, a space is written before the comment: a Mic-E comment such as{5}after a/A=would join its digits into a Mic-E altitude, and/is a base-91 byte itself (README Encoding rule, E12). - The builder passes a compressed course on as given, so it is rounded once: 301.7 degrees is
l, where whole degrees first gavem. A Mic-E builder course that rounds to 0 is the spec's unknown (B1).
- Values between steps are rounded once to the nearest step, halves away from zero, a value within 1e-6 of a half (measured in steps) being the half, and checked after rounding (F2): a course or speed,
Decoding:
- A PHG, RNG or DFS later in an area object's comment is found as the data extension, as after a course/speed (ruling F7a: an area, like a DF bearing or storm data, describes the object, not the station's radio).
- A later Mic-E altitude is looked for before base-91 telemetry and a
!DAO!are lifted from the status text (only the locator is read as if they were out), so bytes either side of a!DAO!never join into an altitude, and a!DAO!that shares a byte with the altitude found is not one ("13.7V!w*@!7e}: the altitude is!7e}). Withmic-e-altitude-not-firstswitched off, a report with a later altitude is rejected when the text left, once telemetry and the!DAO!are lifted, holds an altitude formed across a place one was taken from (an altitude the bytes already held is kept); with no later altitude, a strict decoder reads the status text as a lenient one does. - A PHG or RNG straight after a Mic-E locator and its space is lifted before a later Mic-E altitude is looked for, so its digits are never one (G1; this already held, and is now tested).
- Base-91 telemetry and a
!DAO!come out of Mic-E status text before the locator is read, so a locator followed straight by either has nomissing-space-after-locator(F16).
Tests and tools:
pdn_aprs_diffdumpgains--encode(neutral data in, the bytes written and what they decode to out) and--build(builder recipes in, the line built out), and its decode records gain the API view, as the vectors' README describes. It reads stdin and writes stdout.pdn_aprs_diffdump --buildreports text longer than the C data holds (1024 bytes) asunsupported, not refused; refuses a telemetry sequence over 999 (B6); and gives a Mic-E altitude in metres to the builder as metres (B2).- The vectors move to the exact-bytes branch. The runner compares the bytes written with
canonical_infobyte for byte forequivalentand the newrounded(whose data read back is not compared); it only checked that they decoded to the same data.