umsh_ulcp/
ids.rs

1//! Property, stream, and capability identifiers, plus protocol
2//! constants. The complete allocation is in
3//! `docs/protocol/src/ulcp-index.md`.
4
5/// Protocol version advertised in `PROP_PROTOCOL_VERSION`.
6pub const PROTOCOL_MAJOR_VERSION: u8 = 6;
7/// Protocol version advertised in `PROP_PROTOCOL_VERSION`.
8pub const PROTOCOL_MINOR_VERSION: u8 = 0;
9
10/// Value of `PROP_INTERFACE_TYPE` for this protocol.
11pub const INTERFACE_TYPE: u32 = 8;
12
13/// Property identifiers.
14pub mod prop {
15    /// Status of the last operation (`PROP_LAST_STATUS`).
16    pub const LAST_STATUS: u32 = 0;
17    /// Protocol major/minor version (`PROP_PROTOCOL_VERSION`).
18    pub const PROTOCOL_VERSION: u32 = 1;
19    /// device firmware version string (`PROP_DEV_VERSION`).
20    pub const DEV_VERSION: u32 = 2;
21    /// Interface type discriminator (`PROP_INTERFACE_TYPE`).
22    pub const INTERFACE_TYPE: u32 = 3;
23    /// Hardware model name (`PROP_DEV_MODEL`) — what the board *is*, where
24    /// `DEV_VERSION` is what it *runs*. Optional and ungated: a device
25    /// that cannot name its own hardware refuses the get.
26    pub const DEV_MODEL: u32 = 4;
27    /// Supported capability list (`PROP_CAPS`).
28    pub const CAPS: u32 = 5;
29    /// Seconds since the device booted (`PROP_UPTIME`). Optional and
30    /// ungated, like `DEV_MODEL`: a device with no monotonic clock to
31    /// answer from refuses the get. Reads next to `LAST_STATUS`, which
32    /// says why the device last reset — this says how long ago.
33    pub const UPTIME: u32 = 6;
34    /// PHY enabled flag (`PROP_PHY_ENABLED`).
35    pub const PHY_ENABLED: u32 = 32;
36    /// Frequency in kHz (`PROP_PHY_FREQ`).
37    pub const PHY_FREQ: u32 = 35;
38    /// TX power in dBm (`PROP_PHY_TX_POWER`).
39    pub const PHY_TX_POWER: u32 = 37;
40    /// Current RSSI in dBm (`PROP_PHY_RSSI`).
41    pub const PHY_RSSI: u32 = 38;
42    /// LoRa bandwidth in Hz (`PROP_PHY_LORA_BW`).
43    pub const PHY_LORA_BW: u32 = 39;
44    /// LoRa spreading factor (`PROP_PHY_LORA_SF`).
45    pub const PHY_LORA_SF: u32 = 40;
46    /// LoRa coding rate (`PROP_PHY_LORA_CR`).
47    pub const PHY_LORA_CR: u32 = 41;
48    /// Maximum `STR_PHY_RAW` data size in octets (`PROP_PHY_MTU`).
49    pub const PHY_MTU: u32 = 42;
50    /// LoRa sync word, SX126x-style 16-bit (`PROP_PHY_LORA_SW`).
51    pub const PHY_LORA_SW: u32 = 43;
52    /// Deliver all received frames, bypassing host receive filtering
53    /// (`PROP_MAC_PROMISCUOUS`). Session-scoped.
54    pub const MAC_PROMISCUOUS: u32 = 48;
55    /// Whether a saved snapshot exists (`PROP_SAVED`).
56    pub const SAVED: u32 = 49;
57    /// Carry the host on a point-to-point link to the device's own node
58    /// instead of the shared medium (`PROP_MAC_BACKHAUL`). Session-scoped.
59    pub const MAC_BACKHAUL: u32 = 50;
60    /// Device identity public key (`PROP_DEV_KEY`).
61    pub const DEV_KEY: u32 = 64;
62    /// Device identity private key, write-only (`PROP_DEV_PRIVATE_KEY`).
63    pub const DEV_PRIVATE_KEY: u32 = 65;
64    /// Device identity channel keys (`PROP_DEV_CHANNEL_KEYS`).
65    pub const DEV_CHANNEL_KEYS: u32 = 66;
66    /// Device identity peer list (`PROP_DEV_PEERS`).
67    pub const DEV_PEERS: u32 = 67;
68    /// Human-readable device name (`PROP_DEV_NAME`).
69    pub const DEV_NAME: u32 = 68;
70    /// Battery status snapshot (`PROP_BATTERY`).
71    pub const BATTERY: u32 = 69;
72    /// Autonomous MAC-layer repeater/forwarding enable (`PROP_MAC_REPEATER_ENABLED`).
73    ///
74    /// First of the device-behavior settings range (70–95), which is
75    /// subdivided as 70–79 repeater and identity, 80–87 advertisement
76    /// policy (80–84 allocated, 85–87 spare), 88–93 positioning, 94–95
77    /// environmental sensing (94 illuminance, 95 spare — the board's
78    /// thermistor is the expected claimant). A
79    /// single-octet identifier is the scarce resource, so the positioning
80    /// range holds the enable toggle and the fix telemetry a host reads
81    /// and the device announces continually; the rarely-touched
82    /// positioning *configuration* lives in the extended device range
83    /// alongside `PROP_TIME`. A persisted, device-domain boolean: when
84    /// set, the device identity's on-board MAC forwards overheard routable
85    /// frames and advertises the `REP` capability bit. The advertised
86    /// *role* is a separate matter — see `IDENT_ROLE`.
87    pub const MAC_REPEATER_ENABLED: u32 = 70;
88    /// The device identity's complete signed node-identity blob
89    /// (`PROP_IDENT`), served through a deferred signing effect.
90    pub const IDENT: u32 = 71;
91    /// Advertised `ROLE` byte of the device identity (`PROP_IDENT_ROLE`).
92    /// Empty means "derive it from what the device is actually doing".
93    pub const IDENT_ROLE: u32 = 72;
94    /// Whether the device identity advertises the `MOB` capability bit
95    /// (`PROP_IDENT_MOBILE`) — mobile versus fixed, which is orthogonal
96    /// to tethered versus standalone.
97    pub const IDENT_MOBILE: u32 = 73;
98    /// Regions the device identity flood-forwards for
99    /// (`PROP_MAC_REPEATER_REGIONS`) — multiple-value, each item 1 to 24
100    /// octets of UTF-8 naming a region in its string form, empty for
101    /// "forward regardless of region code". The device derives the
102    /// 2-octet forwarding codes itself; the strings are what it
103    /// advertises, since a hash-derived code names nothing.
104    pub const MAC_REPEATER_REGIONS: u32 = 74;
105    /// Region code inserted into untagged flood packets
106    /// (`PROP_MAC_REPEATER_DEFAULT_REGION`) — one 2-octet code, or empty
107    /// to never tag.
108    pub const MAC_REPEATER_DEFAULT_REGION: u32 = 75;
109    /// Minimum received RSSI in dBm for flood forwarding
110    /// (`PROP_MAC_REPEATER_MIN_RSSI`) — INT16, or empty for no threshold.
111    pub const MAC_REPEATER_MIN_RSSI: u32 = 76;
112    /// Minimum received SNR in whole dB for flood forwarding
113    /// (`PROP_MAC_REPEATER_MIN_SNR`) — INT8, or empty for no threshold.
114    pub const MAC_REPEATER_MIN_SNR: u32 = 77;
115    /// Whether the device identity answers Identity Requests
116    /// (`PROP_DEV_DISCOVERABLE`) — BOOL, default 1. Requires
117    /// `CAP_DEV_IDENTITY`.
118    pub const DEV_DISCOVERABLE: u32 = 78;
119    /// Locate-alert state (`PROP_ALERT`) — what the device is currently
120    /// doing to draw attention to where it physically is. Volatile: never
121    /// saved, unaffected by `CMD_RST`, `ALERT_NONE` after every reset.
122    /// Requires `CAP_ALERT`.
123    pub const ALERT: u32 = 79;
124    /// Seconds between unsolicited advertisements (`PROP_ADVERT_INTERVAL`)
125    /// — UINT32, 0 to send none. An advertisement carries the signed node
126    /// identity and goes out with no flood hops and no source route, so it
127    /// reaches the neighbours that can hear the device directly and stops
128    /// there. The accepted range is [`MIN_AUTO_ANNOUNCE_INTERVAL_S`] to
129    /// [`MAX_AUTO_ANNOUNCE_INTERVAL_S`], and the value is a floor rather
130    /// than a period: the device scatters each send later by up to a
131    /// quarter of it. Requires `CAP_ADVERT`.
132    pub const ADVERT_INTERVAL: u32 = 80;
133    /// Seconds between unsolicited beacons (`PROP_BEACON_INTERVAL`) —
134    /// UINT32, 0 to send none. A beacon carries no payload and goes out
135    /// with a flood budget and the trace-route and trace-signal options,
136    /// so what it announces is the path back to the device rather than who
137    /// the device is. Same range and same scatter as
138    /// [`ADVERT_INTERVAL`]. Requires `CAP_ADVERT`.
139    pub const BEACON_INTERVAL: u32 = 81;
140    /// Whether the device emits one beacon once it comes up
141    /// (`PROP_STARTUP_BEACON`) — BOOL, default 1. Requires `CAP_ADVERT`.
142    pub const STARTUP_BEACON: u32 = 82;
143    /// Location the device identity advertises (`PROP_IDENT_LOCATION`) —
144    /// 0–7 octets in the variable-precision interleaved format, empty to
145    /// advertise none. The value carries its own precision, so a location
146    /// entered by hand needs no separate precision setting.
147    ///
148    /// This and [`IDENT_ALTITUDE`] are where the advertised identity gets
149    /// its position, whether a fix wrote them or an administrator did.
150    /// [`GNSS_IDENT_UPDATE`] set, the device writes them itself from each
151    /// fix and refuses a write with `STATUS_INVALID_STATE`; cleared, they
152    /// are writable and hold whatever they last held. Requires
153    /// `CAP_IDENT`, not `CAP_GNSS` — a fixed repeater with no receiver
154    /// still has somewhere to be.
155    pub const IDENT_LOCATION: u32 = 83;
156    /// Altitude the device identity advertises (`PROP_IDENT_ALTITUDE`) —
157    /// a minimal-length signed integer (see [`crate::sint`]) of meters
158    /// above the WGS-84 ellipsoid, or empty. Advertised only alongside a
159    /// location. Same writability rule as [`IDENT_LOCATION`]; requires
160    /// `CAP_IDENT`.
161    pub const IDENT_ALTITUDE: u32 = 84;
162    /// Whether the GNSS receiver is powered (`PROP_GNSS_ENABLED`) — BOOL,
163    /// default 0. Off means the lowest power state the receiver reaches;
164    /// a board whose receiver RTC is the board's only clock keeps that
165    /// domain alive regardless. Requires `CAP_GNSS`.
166    pub const GNSS_ENABLED: u32 = 88;
167    /// Last position fix (`PROP_GNSS_LOCATION`) — 0–7 octets in the
168    /// variable-precision interleaved format. Empty means no fix has been
169    /// obtained this power cycle. Requires `CAP_GNSS`.
170    pub const GNSS_LOCATION: u32 = 89;
171    /// Altitude of the last fix (`PROP_GNSS_ALTITUDE`) — `INT32_LE`
172    /// meters above the WGS-84 ellipsoid, matching the units of node
173    /// identity option 2. Empty when there is no fix. Requires `CAP_GNSS`.
174    pub const GNSS_ALTITUDE: u32 = 90;
175    /// Fix quality (`PROP_GNSS_FIX`) — `UINT8`, 0 none, 1 two-dimensional,
176    /// 2 three-dimensional. Reads 0 while the receiver is disabled.
177    /// Requires `CAP_GNSS`.
178    pub const GNSS_FIX: u32 = 91;
179    /// Estimated horizontal accuracy of the last fix
180    /// (`PROP_GNSS_PRECISION`) — `UINT16_LE` decimeters. An estimate
181    /// derived from the receiver's dilution of precision, not a measured
182    /// error bound. Empty when there is no fix. Requires `CAP_GNSS`.
183    pub const GNSS_PRECISION: u32 = 92;
184    /// Satellite counts (`PROP_GNSS_SATELLITES`) — `UINT8` satellites used
185    /// in the solution, optionally followed by `UINT8` satellites in view.
186    /// Reads 0 while the receiver is disabled. Requires `CAP_GNSS`.
187    pub const GNSS_SATELLITES: u32 = 93;
188    /// Ambient illuminance (`PROP_ILLUMINANCE`) — `UINT32_LE` millilux.
189    /// Millilux rather than lux because the interesting region for an
190    /// indicator that should not be intrusive at night is below one lux.
191    /// Sampled when read; empty when the sensor could not be read. A
192    /// board reports its clamped maximum above the sensor's saturation
193    /// point rather than extrapolating past it. Requires
194    /// `CAP_ILLUMINANCE`.
195    pub const ILLUMINANCE: u32 = 94;
196    /// Tethered host identity public key (`PROP_HOST_KEY`).
197    pub const HOST_KEY: u32 = 96;
198    /// Host channel keys (`PROP_HOST_CHANNEL_KEYS`).
199    pub const HOST_CHANNEL_KEYS: u32 = 97;
200    /// Host pairwise peer keys (`PROP_HOST_PEER_KEYS`).
201    pub const HOST_PEER_KEYS: u32 = 98;
202    /// Host receive filter table (`PROP_HOST_RX_FILTERS`).
203    pub const HOST_RX_FILTERS: u32 = 99;
204    /// Acknowledgement-delegation enable (`PROP_HOST_AUTO_ACK`).
205    pub const HOST_AUTO_ACK: u32 = 100;
206    /// Frames currently queued (`PROP_HOST_RX_QUEUE_COUNT`).
207    pub const HOST_RX_QUEUE_COUNT: u32 = 101;
208    /// Inbound queue capacity in frames (`PROP_HOST_RX_QUEUE_CAPACITY`).
209    pub const HOST_RX_QUEUE_CAPACITY: u32 = 102;
210    /// Cumulative frames dropped from the queue (`PROP_HOST_RX_QUEUE_DROPPED`).
211    pub const HOST_RX_QUEUE_DROPPED: u32 = 103;
212    /// Transmit duty usage over the past hour (`PROP_PHY_DUTY_NOW`).
213    pub const PHY_DUTY_NOW: u32 = 4820;
214    /// Duty-cycle limit (`PROP_PHY_DUTY_LIMIT`).
215    pub const PHY_DUTY_LIMIT: u32 = 4822;
216    /// Frames that reached the air (`PROP_STAT_TX_PACKETS`) — `UINT32_LE`,
217    /// counted for every client of the radio, the attached host included.
218    /// Requires `CAP_STATS`. See [`crate::stats`] for what the counters
219    /// share: they wrap, they are not saved, `CMD_RST` does not touch
220    /// them, and the only value a write may carry is zero.
221    pub const STAT_TX_PACKETS: u32 = 4832;
222    /// Transmits the channel-activity check held back
223    /// (`PROP_STAT_TX_CHANNEL_BUSY`) — `UINT32_LE`. Counted per attempt,
224    /// so one frame that retries several times before it airs is counted
225    /// several times here and once in
226    /// [`STAT_TX_PACKETS`]. Requires `CAP_STATS`.
227    pub const STAT_TX_CHANNEL_BUSY: u32 = 4833;
228    /// Receptions off the air that are UMSH packets
229    /// (`PROP_STAT_RX_PACKETS`) — `UINT32_LE`, counted whoever they were
230    /// addressed to. Requires `CAP_STATS`.
231    pub const STAT_RX_PACKETS: u32 = 4834;
232    /// Receptions the radio rejected on CRC (`PROP_STAT_RX_BAD_CRC`) —
233    /// `UINT32_LE`. These never reach the MAC: the bytes are unusable and
234    /// the frame is dropped where it was demodulated. A count that climbs
235    /// with a quiet packet count is interference or a marginal link.
236    /// Requires `CAP_STATS`.
237    pub const STAT_RX_BAD_CRC: u32 = 4835;
238    /// Receptions that passed CRC but are not UMSH packets
239    /// (`PROP_STAT_RX_NON_UMSH`) — `UINT32_LE`. The test is the first
240    /// octet's protocol version and reserved bits, so a truncated UMSH
241    /// frame still counts as UMSH; this is somebody else's traffic on the
242    /// same sync word. Requires `CAP_STATS`.
243    pub const STAT_RX_NON_UMSH: u32 = 4836;
244    /// Receptions the device's own node acted on
245    /// (`PROP_STAT_RX_ACCEPTED`) — `UINT32_LE`. Frames addressed to an
246    /// attached host's identity are that host's business and are not
247    /// counted here. Requires `CAP_STATS` and `CAP_REPEATER`.
248    pub const STAT_RX_ACCEPTED: u32 = 4837;
249    /// Receptions this node chose to repeat (`PROP_STAT_FORWARDED`) —
250    /// `UINT32_LE`, counted at the decision rather than at the transmit,
251    /// so a repeat the channel never let out is counted here and not in
252    /// [`STAT_TX_PACKETS`]. Requires `CAP_STATS`
253    /// and `CAP_REPEATER`.
254    pub const STAT_FORWARDED: u32 = 4838;
255    /// Receptions this node would have repeated and declined under the
256    /// operator's forwarding policy (`PROP_STAT_FORWARD_DROPPED`) —
257    /// `UINT32_LE`: an exhausted flood budget, a signal below the
258    /// configured minimum RSSI or SNR, or a region the repeater does not
259    /// serve. Duplicates and traffic addressed to this device are not
260    /// policy decisions and are not counted. Requires `CAP_STATS` and
261    /// `CAP_REPEATER`.
262    pub const STAT_FORWARD_DROPPED: u32 = 4839;
263    /// Queued repeats dropped after the destination's acknowledgement was
264    /// overheard (`PROP_STAT_FORWARD_CANCELLED`) — `UINT32_LE`. Airtime
265    /// this node did not have to spend. Requires `CAP_STATS` and
266    /// `CAP_REPEATER`.
267    pub const STAT_FORWARD_CANCELLED: u32 = 4840;
268    /// Persisted, write-only BLE pairing passkey (`PROP_BLE_PAIRING_PIN`).
269    pub const BLE_PAIRING_PIN: u32 = 4864;
270    /// Nodes authorized to manage this device over the mesh
271    /// (`PROP_DEV_ADMINS`) — a multiple-value property whose items are
272    /// 32-octet Ed25519 public keys, reported verbatim. An empty list
273    /// disables node management. Requires `CAP_ADMIN`.
274    pub const DEV_ADMINS: u32 = 4865;
275    /// Wall-clock time (`PROP_TIME`) — `UINT32_LE` seconds since the Unix
276    /// epoch, or **empty** when the device does not know what time it is.
277    /// Unsigned, so the encoding is wrap-free into 2106. Requires
278    /// `CAP_TIME`.
279    pub const TIME: u32 = 4866;
280    /// Local time-zone offset from UTC (`PROP_TZ_OFFSET`) — `INT16_LE`
281    /// minutes, default 0. Unlike `PROP_TIME` this always has a value:
282    /// where the device is configured to be is known even when what time
283    /// it is is not. Requires `CAP_TIME`.
284    pub const TZ_OFFSET: u32 = 4867;
285    /// Whether position fixes update the advertised node identity
286    /// (`PROP_GNSS_IDENT_UPDATE`) — BOOL, default 0. Requires `CAP_GNSS`.
287    pub const GNSS_IDENT_UPDATE: u32 = 4868;
288    /// Precision the advertised location is clamped to
289    /// (`PROP_GNSS_IDENT_PRECISION`) — `UINT8` 1–7, default 5. Requires
290    /// `CAP_GNSS`.
291    pub const GNSS_IDENT_PRECISION: u32 = 4869;
292    /// Whether receiver-derived time may set the wall clock
293    /// (`PROP_GNSS_TIME_TRUST`) — BOOL, default 1. Cleared, neither a fix
294    /// nor a receiver-RTC read touches `PROP_TIME`, which leaves a
295    /// manually-set clock proof against a jammed or spoofed sky. Position
296    /// reporting is unaffected. Requires `CAP_GNSS`.
297    pub const GNSS_TIME_TRUST: u32 = 4870;
298    /// Whether the device is reachable over Bluetooth
299    /// (`PROP_BLE_ENABLED`) — BOOL, default 1. Requires `CAP_BLE`.
300    ///
301    /// Cleared, the device stops advertising and drops any attached
302    /// host; bonds survive, and the host reconnects when it is set
303    /// again. It does not claim the radio is powered down: tearing a
304    /// vendor stack down at runtime is not something every platform can
305    /// do, and a property that says "off" while a stack is still up
306    /// would be lying about the thing a user turns it off for.
307    pub const BLE_ENABLED: u32 = 4871;
308    /// How many Bluetooth bonds the device is holding
309    /// (`PROP_BLE_BOND_COUNT`) — `UINT8`, read-only. Requires `CAP_BLE`;
310    /// a device whose bonds it cannot manage answers
311    /// `STATUS_PROP_NOT_FOUND`.
312    ///
313    /// The count is live state rather than configuration, so it is not
314    /// part of the saved snapshot. It says how many hosts are enrolled,
315    /// never which: a bond identifies a host, and a device that named its
316    /// bonded hosts to whoever asked would leak the association its
317    /// pairing ceremony exists to protect.
318    pub const BLE_BOND_COUNT: u32 = 4872;
319    /// How far the Bluetooth transport has got with whoever is on the
320    /// other end of it (`PROP_BLE_LINK`) — `UINT8`, read-only, one of
321    /// [`crate::ble::BleLinkState`]. Requires `CAP_BLE`.
322    ///
323    /// Live transport state, so it is not part of the saved snapshot and
324    /// a protocol reset does not touch it. Read over Bluetooth it always
325    /// answers `BLE_LINK_ATTACHED`, because the session asking is the
326    /// session it is reporting; it earns its keep over the mesh and over
327    /// a cable, where it is the only way to ask whether a phone is on the
328    /// device right now.
329    pub const BLE_LINK: u32 = 4873;
330    /// Whether a pairing window is open (`PROP_BLE_PAIRING`) — BOOL,
331    /// read-write. Requires `CAP_BLE`; a device that does not manage its
332    /// own bonds answers `STATUS_PROP_NOT_FOUND`.
333    ///
334    /// A property rather than a command because a window is a state, not
335    /// an act: it can be opened, closed early, observed, and — the case
336    /// no command can express — it closes on its own, on a new bond or a
337    /// timeout, and the device publishes that transition. Writing 1
338    /// opens (or renews) the window; a device that cannot open one right
339    /// now — locked out after repeated pairing failures, or with its
340    /// Bluetooth disabled — answers `STATUS_INVALID_STATE`. Writing 0
341    /// closes it.
342    ///
343    /// Live transport state like the link and the bond count: not part
344    /// of the saved snapshot, and untouched by `CMD_RST`.
345    pub const BLE_PAIRING: u32 = 4874;
346}
347
348/// `PROP_SAVED` values.
349///
350/// A snapshot that exists but cannot be read is distinguishable from no
351/// snapshot at all, and running on an older generation than the one last
352/// written is distinguishable from running on the newest.
353pub mod saved {
354    /// Nothing is saved.
355    pub const NONE: u8 = 0;
356    /// The newest saved generation is in effect.
357    pub const CURRENT: u8 = 1;
358    /// A newer generation was rejected; an older one is in effect.
359    pub const FALLBACK: u8 = 2;
360    /// A snapshot exists but no generation could be read.
361    pub const UNREADABLE: u8 = 3;
362}
363
364/// Stream identifiers.
365pub mod stream {
366    /// Raw radio frame stream (`STR_PHY_RAW`).
367    pub const PHY_RAW: u32 = 113;
368}
369
370/// Capability codes advertised via `PROP_CAPS`.
371pub mod cap {
372    /// `CAP_WRITABLE_RAW_STREAM`
373    pub const WRITABLE_RAW_STREAM: u32 = 8;
374    /// `CAP_PHY_DUTY_LIMIT`
375    pub const PHY_DUTY_LIMIT: u32 = 16;
376    /// `CAP_PHY_LORA`
377    pub const PHY_LORA: u32 = 515;
378    /// `CAP_HOST_FILTER`
379    pub const HOST_FILTER: u32 = 32;
380    /// `CAP_HOST_RX_QUEUE` (requires `CAP_HOST_FILTER`)
381    pub const HOST_RX_QUEUE: u32 = 33;
382    /// `CAP_HOST_KEYS` (requires `CAP_HOST_FILTER`)
383    pub const HOST_KEYS: u32 = 34;
384    /// `CAP_HOST_AUTO_ACK` (requires `CAP_HOST_KEYS` and `CAP_HOST_RX_QUEUE`)
385    pub const HOST_AUTO_ACK: u32 = 35;
386    /// `CAP_SAVE`
387    pub const SAVE: u32 = 36;
388    /// `CAP_DEV_IDENTITY`
389    pub const DEV_IDENTITY: u32 = 37;
390    /// `CAP_DEV_NAME`
391    pub const DEV_NAME: u32 = 38;
392    /// `CAP_BATTERY`
393    pub const BATTERY: u32 = 39;
394    /// `CAP_REPEATER` — the device can act as an autonomous mesh repeater
395    /// (`PROP_MAC_REPEATER_ENABLED`). Requires `CAP_DEV_IDENTITY`.
396    pub const REPEATER: u32 = 40;
397    /// `CAP_IDENT` — the device serves and configures its own advertised
398    /// node identity (`PROP_IDENT`, `PROP_IDENT_ROLE`,
399    /// `PROP_IDENT_MOBILE`). Requires `CAP_DEV_IDENTITY`.
400    pub const IDENT: u32 = 41;
401    /// `CAP_ALERT` — the device has some means of making itself
402    /// physically conspicuous on demand (`PROP_ALERT`). It says nothing
403    /// about *which* means, so a host must not assume audibility.
404    pub const ALERT: u32 = 42;
405    /// `CAP_ADMIN` — the device can be managed over the mesh by the nodes
406    /// listed in `PROP_DEV_ADMINS`. Requires `CAP_DEV_IDENTITY`, since an
407    /// administrator addresses the device identity, and `CAP_CMD_MULTI`,
408    /// so an administrator may rely on the multi-property commands.
409    pub const ADMIN: u32 = 43;
410    /// `CAP_TIME` — the device keeps a wall clock (`PROP_TIME`,
411    /// `PROP_TZ_OFFSET`). It says nothing about where the time comes from
412    /// or whether it survives a power cycle.
413    pub const TIME: u32 = 44;
414    /// `CAP_GNSS` — a GNSS receiver is fitted, so the positioning
415    /// properties exist and the wall clock has a source that can set
416    /// itself. Requires `CAP_TIME`.
417    pub const GNSS: u32 = 45;
418    /// `CAP_ADVERT` — the device announces itself on a schedule of its own
419    /// (`PROP_ADVERT_INTERVAL`, `PROP_BEACON_INTERVAL`,
420    /// `PROP_STARTUP_BEACON`). Requires `CAP_DEV_IDENTITY`, since what an
421    /// advertisement carries is the device identity.
422    pub const ADVERT: u32 = 46;
423    /// `CAP_ILLUMINANCE` — an ambient light sensor is fitted, so
424    /// `PROP_ILLUMINANCE` reads a measurement rather than nothing.
425    pub const ILLUMINANCE: u32 = 47;
426    /// `CAP_MAC_BACKHAUL` — the device can carry the host on a
427    /// point-to-point link to its own node (`PROP_MAC_BACKHAUL`).
428    /// Requires `CAP_REPEATER`: without a repeater there is nothing on
429    /// the far side of that link to carry the host's traffic onward.
430    pub const MAC_BACKHAUL: u32 = 48;
431    /// `CAP_CMD_MULTI` — the device accepts `CMD_PROP_MULTI_GET` and
432    /// `CMD_PROP_MULTI_SET` and answers them with `CMD_PROP_ARE`.
433    pub const CMD_MULTI: u32 = 49;
434    /// `CAP_BLE` — the device has a Bluetooth transport whose
435    /// reachability it can turn on and off (`PROP_BLE_ENABLED`,
436    /// `PROP_BLE_LINK`). It says nothing about the stack underneath, and
437    /// in particular does not promise that clearing `PROP_BLE_ENABLED`
438    /// powers a radio down.
439    ///
440    /// The only Bluetooth capability there is. What else a given
441    /// transport will do — manage its own bonds, hold a pairing PIN — a
442    /// host learns by asking for the property or sending the command and
443    /// reading the refusal, which is a question it has to be able to
444    /// answer anyway.
445    pub const BLE: u32 = 50;
446    /// `CAP_REBOOT` — the device can restart its hardware on command
447    /// (`CMD_REBOOT`). A device that cannot — one whose ULCP session is
448    /// a process rather than a board — leaves this out and answers the
449    /// command `STATUS_UNIMPLEMENTED`.
450    pub const REBOOT: u32 = 51;
451    /// `CAP_STATS` — the device keeps traffic counters and will report
452    /// them (`PROP_STAT_*`). The forwarding counters additionally require
453    /// [`REPEATER`]: a session with no node of its own
454    /// behind it never repeats anything, and reporting zero forwards
455    /// would read as a repeater that has done nothing rather than as no
456    /// repeater at all.
457    pub const STATS: u32 = 52;
458}
459
460/// Whether a property is reachable from a mesh administrator.
461///
462/// The out-of-reach set is small and named explicitly by the spec rather
463/// than derived, because "device domain" is not a property of the key: a
464/// host-domain table and a device-domain one differ only by which half of
465/// the device they configure. A device answers all three with
466/// `STATUS_PROP_NOT_FOUND` — an administrator learns that the property does
467/// not exist for it, not that it exists and was refused — and an
468/// administrator that reads this first spends no airtime asking.
469pub fn admin_reachable(key: u32) -> bool {
470    !matches!(
471        key,
472        // The host domain in full: the assistance the device owes to
473        // whatever host it serves is that host's business.
474        prop::HOST_KEY
475            | prop::HOST_CHANNEL_KEYS
476            | prop::HOST_PEER_KEYS
477            | prop::HOST_RX_FILTERS
478            | prop::HOST_AUTO_ACK
479            | prop::HOST_RX_QUEUE_COUNT
480            | prop::HOST_RX_QUEUE_CAPACITY
481            | prop::HOST_RX_QUEUE_DROPPED
482            // Session state: an exchange is not an attach, so there is no
483            // session for it to describe.
484            | prop::MAC_PROMISCUOUS
485            | prop::MAC_BACKHAUL
486            // A device identity cannot be installed over the mesh.
487            | prop::DEV_PRIVATE_KEY
488    )
489}
490
491/// Value used in `PROP_PHY_DUTY_LIMIT` to disable duty-cycle limiting.
492pub const DUTY_LIMIT_DISABLED: u16 = 0xFFFF;
493
494/// Shortest accepted `PROP_ADVERT_INTERVAL` / `PROP_BEACON_INTERVAL`, in
495/// seconds.
496///
497/// An absolute floor, and one a device may only ever round *up* from:
498/// scheduling jitter delays an announcement and never brings it forward,
499/// so no configuration can put an unsolicited broadcast on the air more
500/// often than this. The duty ledger remains the airtime control; this is
501/// what keeps a mistyped interval from spending the whole budget on
502/// announcements before anything else can speak.
503pub const MIN_AUTO_ANNOUNCE_INTERVAL_S: u32 = 20 * 60;
504
505/// Longest accepted `PROP_ADVERT_INTERVAL` / `PROP_BEACON_INTERVAL`, in
506/// seconds.
507///
508/// A ceiling on how stale the mesh's picture of a node may get while that
509/// node still considers itself to be announcing. Past a day the schedule
510/// has stopped being one, and 0 says so more honestly.
511pub const MAX_AUTO_ANNOUNCE_INTERVAL_S: u32 = 24 * 60 * 60;
512
513/// Default `PROP_ADVERT_INTERVAL`, in seconds.
514pub const DEFAULT_ADVERT_INTERVAL_S: u32 = 4 * 60 * 60;
515
516/// Default `PROP_BEACON_INTERVAL`, in seconds.
517pub const DEFAULT_BEACON_INTERVAL_S: u32 = 60 * 60;