reticulum-js
    Preparing search index...

    Class RNodeSerialInterface

    RNode interface over a POSIX serial device.

    Subclasses the transport-agnostic RNodeInterface and supplies the byte transport via RNodeSerialInterface#_openTransport using a non-blocking fd + inherited-fd stty + polled readSync/writeSync.

    Registered in the Node interface registry as "rnode-serial".

    Hierarchy

    • RNodeInterface
      • RNodeSerialInterface
    Index
    _closed _command _commandBuffer _dataBuffer _displayUpdateTimer _fd _idTimer _inEscape _inFrame _loopPromise _packetQueue _packetWriter _pollTimer _readableBytes _readAbort _readController _reader _reconnectAbort _reconnectAttempts _reconnecting _transportClose _transportWrite _writable airtimeLimitLong airtimeLimitShort announceBurstCount arFreqDecay autoReconnect bandwidth baudRate bitrate connectTimeout cr created DEFAULT_IFAC_SIZE detached detected detectTimeout display firmwareOk firstTx flowControl frequency fwVersionReceived gravity heldAnnounceDrops heldAnnounceReleases heldAnnounces hwErrors iaFreqDeque icBurstActivated icBurstActive icBurstFreq icBurstFreqNew icBurstHold icBurstPenalty icHeldRelease icHeldReleaseInterval icMaxHeldAnnounces icNewTime icPrBurstActivated icPrBurstActive icPrBurstCooldown icPrBurstFreq icPrBurstFreqNew idCallsign idInterval ifacIdentity ifacKey ifacNetkey ifacNetname ifacSignature ifacSize ifacViolations ingressControl initiator interfaceReady ipFreqDeque majVersion maxReconnectTries mcu minVersion name oaFreqDeque online opFreqDeque packetFilterHits platform port postOpenDelayMs prBurstCount prBurstDrops prFreqDecay protocolViolations rAirtimeLong rAirtimeShort rBandwidth rBatteryPercent rBatteryState rChannelLoadLong rChannelLoadShort rCr rCsmaCwBand rCsmaCwMax rCsmaCwMin rCsmaDifsMs rCsmaSlotTimeMs rCurrentRssi rDisp rDispLatency rDispReadTime reconnectWait rFrameBuffer rFrameBufferLatency rFrameBufferReadTime rFrequency rInterference rLock rLtAlock rNoiseFloor rPreambleSymbols rPreambleTimeMs rRandom rSf rStAlock rState rStatQ rStatRssi rStatRx rStatSnr rStatTx rSymbolRate rSymbolTimeMs rTemperature rTxPower rxb sf shouldId socket supportsDiscovery txb txPower validateTimeout ANNOUNCE_FREQ_DECAY CALLSIGN_MAX_LEN DEFAULT_IFAC_SIZE DISPLAY_READ_INTERVAL DISPLAY_READ_SIZE FB_BITS_PER_PIXEL FB_BYTES_PER_LINE FB_PIXEL_WIDTH FB_PIXELS_PER_BYTE FB_SIZE_BYTES FREQ_MAX FREQ_MIN FREQ_SAMPLES HW_MTU IC_BURST_FREQ IC_BURST_FREQ_NEW IC_BURST_HOLD IC_BURST_PENALTY IC_DEQUE_MIN_SAMPLE IC_HELD_RELEASE_INTERVAL IC_NEW_TIME IC_PR_BURST_COOLDOWN IC_PR_BURST_FREQ IC_PR_BURST_FREQ_NEW MAX_HELD_ANNOUNCES PR_FREQ_DECAY REQUIRED_FW_VER_MAJ REQUIRED_FW_VER_MIN RSSI_OFFSET
    _closed: boolean = false

    Whether a terminal closed event has already been dispatched for the current connection episode (dedupe guard).

    _command: number
    _commandBuffer: number[]
    _dataBuffer: number[]
    _displayUpdateTimer: Timeout | null
    _fd: number | null
    _idTimer: Timeout | null
    _inEscape: boolean
    _inFrame: boolean
    _loopPromise: Promise<void> | null
    _packetQueue: { isBeacon: boolean; raw: Uint8Array }[]

    Outbound queue. Each entry is the already-serialized raw RNS payload plus a flag distinguishing ordinary packets from the raw id-callsign beacon (which, like Python, is framed as a CMD_DATA payload without being a real Packet).

    _packetWriter: WritableStreamDefaultWriter<any> | null = null
    _pollTimer: Timeout | null
    _readableBytes: ReadableStream<Uint8Array<ArrayBufferLike>> | null
    _readAbort: AbortController | null
    _readController:
        | ReadableStreamDefaultController<Uint8Array<ArrayBufferLike>>
        | null
    _reader: ReadableStreamDefaultReader<Uint8Array<ArrayBufferLike>> | null
    _reconnectAbort: AbortController | null = null

    AbortController for the current reconnect wait, so disconnect() can cancel an in-flight backoff immediately.

    _reconnectAttempts: number = 0

    Reconnect attempt counter for the current drop episode. Reset to 0 at the start of each Interface._runReconnectLoop run.

    _reconnecting: boolean = false

    Single-flight guard: only one reconnect loop runs at a time.

    _transportClose: (() => void | Promise<void>) | null
    _transportWrite: ((bytes: Uint8Array) => void | Promise<void>) | null
    _writable: WritableStream<Packet>
    airtimeLimitLong: number | null
    airtimeLimitShort: number | null
    announceBurstCount: number = 0

    Times an announce burst has latched on this interface.

    arFreqDecay: number = Interface.ANNOUNCE_FREQ_DECAY
    autoReconnect: boolean = RECONNECT_DEFAULTS.autoReconnect

    Whether automatic reconnection is enabled for this initiator interface.

    bandwidth: number
    baudRate: number
    bitrate: number = 62500

    Nominal physical bitrate of this interface in bits per second (self.bitrate on RNS.Interfaces.Interface in the Python reference, default 62500). Each interface overrides this with its medium's rate.

    Used by TransportCore.prioritizeInterfaces() to order the interface set highest-bitrate-first (mirrors the Python reference's Transport.prioritize_interfaces); the per-bitrate link-timeout and announce-rate-limit behaviours that also build on it are tracked as Phase 2 of work doc #20. Configured bitrates below Reticulum.MINIMUM_BITRATE are ignored (matching Python).

    connectTimeout: number = RECONNECT_DEFAULTS.connectTimeout

    Per-dial connect timeout in seconds.

    cr: number
    created: number = ...

    Epoch milliseconds when the interface was constructed (self.created in the Python reference, which uses time.time()).

    DEFAULT_IFAC_SIZE: number = 16

    Per-interface default IFAC size (bytes) when IFAC is enabled but no explicit ifacSize was given. Mirrors DEFAULT_IFAC_SIZE on each Python interface (16 for Auto/Backbone, 8 for AX.25). Subclasses override; the base default of 16 matches the common case.

    detached: boolean = false

    Permanent stop signal read by the reconnect loop. Set by disconnect().

    detected: boolean
    detectTimeout: number
    display: boolean

    True once a display-capable device (ESP32/NRF52) has been detected.

    firmwareOk: boolean
    firstTx: number | null
    flowControl: boolean
    frequency: number
    fwVersionReceived: boolean
    gravity: number | null = null

    Per-interface path preference weight (Interface.gravity in the Python reference, DEFAULT_GRAVITY = 0). When the same announce reaches this node over multiple interfaces, the path table prefers the entry learned via the higher-gravity interface (e.g. a wired backbone over a slow radio link). null means "no preference" — import("../core/reticulum.js").Reticulum substitutes its defaultGravity at addInterface time.

    heldAnnounceDrops: number = 0

    Announces dropped (not held) because the held table was at its cap.

    heldAnnounceReleases: number = 0

    Held announces released back into the inbound pipeline.

    heldAnnounces: Map<string, Packet> = ...

    Announces held while an ingress burst is latched, keyed by destination hash hex (Python held_announces). Drained by processHeldAnnounces on the transport sweep.

    hwErrors: { description: string; error: number }[]
    iaFreqDeque: number[] = []

    Incoming-announce timestamp ring (seconds).

    icBurstActivated: number = 0
    icBurstActive: boolean = false
    icBurstFreq: number = Interface.IC_BURST_FREQ
    icBurstFreqNew: number = Interface.IC_BURST_FREQ_NEW
    icBurstHold: number = Interface.IC_BURST_HOLD
    icBurstPenalty: number = Interface.IC_BURST_PENALTY
    icHeldRelease: number = 0

    Earliest held-announce release time (seconds); set on burst activation.

    icHeldReleaseInterval: number = Interface.IC_HELD_RELEASE_INTERVAL
    icMaxHeldAnnounces: number = Interface.MAX_HELD_ANNOUNCES
    icNewTime: number = Interface.IC_NEW_TIME
    icPrBurstActivated: number = 0
    icPrBurstActive: boolean = false
    icPrBurstCooldown: number = 0

    Remaining quiet evaluations before a latched PR burst unlatches.

    icPrBurstFreq: number = Interface.IC_PR_BURST_FREQ
    icPrBurstFreqNew: number = Interface.IC_PR_BURST_FREQ_NEW
    idCallsign: Uint8Array<ArrayBufferLike> | null
    idInterval: number | null
    ifacIdentity: Identity | null = null

    Derived IFAC Ed25519 identity (only its signing ability is used). Populated lazily by _ensureIfacMaterial; null while IFAC is disabled or before first use.

    ifacKey: Uint8Array<ArrayBufferLike> | null = null

    Derived 64-byte IFAC key (HKDF over import("../core/ifac.js").IFAC_SALT).

    ifacNetkey: string | null = null

    Shared passphrase enabling IFAC (ifac_netkey). See ifacNetname.

    ifacNetname: string | null = null

    Shared network name enabling IFAC (ifac_netname). When set together with ifacNetkey (or alone), packets on this interface are authenticated and obfuscated. Both endpoints must share the same value.

    ifacSignature: Uint8Array<ArrayBufferLike> | null = null

    IFAC signature of fullHash(ifacKey), published in the discovery announce.

    ifacSize: number
    ifacViolations: number = 0

    IFAC-specific violations: missing/invalid/short IFAC fields.

    ingressControl: boolean = true

    Whether ingress burst control is enabled on this interface (Python ingress_control). Disabling makes shouldIngressLimit and shouldIngressLimitPr always return false.

    initiator: boolean

    The initiator flag is always true for an RNode (it dials the radio).

    interfaceReady: boolean
    ipFreqDeque: number[] = []

    Incoming path-request timestamp ring (seconds).

    majVersion: number
    maxReconnectTries: number = RECONNECT_DEFAULTS.maxReconnectTries

    Maximum reconnection attempts per drop. Infinity retries forever.

    mcu: number | null
    minVersion: number
    name: string
    oaFreqDeque: number[] = []

    Outgoing-announce timestamp ring (seconds).

    online: boolean
    opFreqDeque: number[] = []

    Outgoing path-request timestamp ring (seconds).

    packetFilterHits: number = 0

    Inbound packet-filter (dedup) hits.

    platform: number | null
    port: string
    postOpenDelayMs: number
    prBurstCount: number = 0

    Times a path? burst has latched on this interface.

    prBurstDrops: number = 0

    Unique-tag path requests dropped while a PR burst was latched.

    prFreqDecay: number = Interface.PR_FREQ_DECAY
    protocolViolations: number = 0

    Generic protocol violations: malformed packets, bad signatures, etc.

    rAirtimeLong: number
    rAirtimeShort: number
    rBandwidth: number | null
    rBatteryPercent: number
    rBatteryState: number
    rChannelLoadLong: number
    rChannelLoadShort: number
    rCr: number | null
    rCsmaCwBand: number | null
    rCsmaCwMax: number | null
    rCsmaCwMin: number | null
    rCsmaDifsMs: number | null
    rCsmaSlotTimeMs: number | null
    rCurrentRssi: number | null
    rDisp: Uint8Array<ArrayBufferLike> | null
    rDispLatency: number | null
    rDispReadTime: number | null
    reconnectWait: number = RECONNECT_DEFAULTS.reconnectWait

    Seconds to wait between reconnection attempts.

    rFrameBuffer: Uint8Array<ArrayBufferLike> | null
    rFrameBufferLatency: number | null
    rFrameBufferReadTime: number | null
    rFrequency: number | null
    rInterference: number | null
    rLock: number | null
    rLtAlock: number | null
    rNoiseFloor: number | null
    rPreambleSymbols: number | null
    rPreambleTimeMs: number | null
    rRandom: number | null
    rSf: number | null
    rStAlock: number | null
    rState: number | null
    rStatQ: number | null
    rStatRssi: number | null
    rStatRx: number | null
    rStatSnr: number | null
    rStatTx: number | null
    rSymbolRate: number | null
    rSymbolTimeMs: number | null
    rTemperature: number | null
    rTxPower: number | null
    rxb: number
    sf: number
    shouldId: boolean
    socket: Socket | null = null

    The underlying socket, when this interface is backed by a Node.js stream.

    supportsDiscovery: boolean
    txb: number
    txPower: number
    validateTimeout: number
    ANNOUNCE_FREQ_DECAY: number = 10

    Seconds after which an unanswered announce sample decays out of the deque (AR_FREQ_DECAY = 1/AR_MINFREQ_HZ = 10 s).

    CALLSIGN_MAX_LEN: number = CALLSIGN_MAX_LEN

    Maximum encoded ID callsign beacon length in bytes (Python parity).

    DEFAULT_IFAC_SIZE: number = 8

    Default IFAC size, matching the Python DEFAULT_IFAC_SIZE = 8.

    DISPLAY_READ_INTERVAL: number = DISPLAY_READ_INTERVAL

    Default display-read poll interval in seconds (Python parity).

    DISPLAY_READ_SIZE: number = DISPLAY_READ_SIZE

    Display snapshot size in bytes (CMD_DISP_READ, Python parity).

    FB_BITS_PER_PIXEL: number = FB_BITS_PER_PIXEL

    Framebuffer bits per pixel (Python FB_BITS_PER_PIXEL).

    FB_BYTES_PER_LINE: number = FB_BYTES_PER_LINE

    Bytes per framebuffer line (Python FB_BYTES_PER_LINE).

    FB_PIXEL_WIDTH: number = FB_PIXEL_WIDTH

    Framebuffer width in pixels (Python FB_PIXEL_WIDTH).

    FB_PIXELS_PER_BYTE: number = FB_PIXELS_PER_BYTE

    Pixels packed per framebuffer byte (Python FB_PIXELS_PER_BYTE).

    FB_SIZE_BYTES: number = FB_SIZE_BYTES

    Full framebuffer size in bytes.

    FREQ_MAX: number = 3000000000

    Maximum supported frequency in Hz.

    FREQ_MIN: number = 137000000

    Minimum supported frequency in Hz.

    FREQ_SAMPLES: number = 48

    Rolling-sample cap for the announce/PR frequency deques (IA_FREQ_SAMPLES / IP_FREQ_SAMPLES / OP_FREQ_SAMPLES in the Python reference — all 48; Python reuses IA_FREQ_SAMPLES for the PR deque).

    HW_MTU: number = 508

    Hardware MTU for the LoRa path, matching the Python HW_MTU = 508.

    IC_BURST_FREQ: number = 10

    Announce burst threshold for established interfaces, Hz (IC_BURST_FREQ).

    IC_BURST_FREQ_NEW: number = 3

    Announce burst threshold for new interfaces, Hz (IC_BURST_FREQ_NEW).

    IC_BURST_HOLD: number = 15

    Seconds a burst stays latched after activation (IC_BURST_HOLD).

    IC_BURST_PENALTY: number = 15

    Seconds before held announces may release after a burst (IC_BURST_PENALTY).

    IC_DEQUE_MIN_SAMPLE: number = 2

    Minimum deque samples before a frequency is reported (IC_DEQUE_MIN_SAMPLE = 2 — i.e. > 2 samples).

    IC_HELD_RELEASE_INTERVAL: number = 5

    Seconds between held-announce releases once draining (IC_HELD_RELEASE_INTERVAL).

    IC_NEW_TIME: number = ...

    Interface age in seconds below which the stricter "new interface" burst thresholds apply (IC_NEW_TIME = 2 h).

    IC_PR_BURST_COOLDOWN: number = 3

    Quiet evaluations required to unlatch a PR burst after the hold (ic_pr_burst_cooldown = 3; any above-threshold evaluation resets it). Anti-flapping hysteresis added upstream in "Improved PR ingress limiter" — the announce limiter has no cooldown.

    IC_PR_BURST_FREQ: number = 8

    Path-request burst threshold for established interfaces, Hz (IC_PR_BURST_FREQ).

    IC_PR_BURST_FREQ_NEW: number = 3

    Path-request burst threshold for new interfaces, Hz (IC_PR_BURST_FREQ_NEW).

    MAX_HELD_ANNOUNCES: number = 256

    Maximum held announces buffered per interface while an announce burst is latched (MAX_HELD_ANNOUNCES). A held table at this size silently drops further announces for destinations not already held.

    PR_FREQ_DECAY: number = 10

    Seconds after which a PR sample decays (PR_FREQ_DECAY = 10 s).

    REQUIRED_FW_VER_MAJ: number = 1

    Minimum required firmware major version.

    REQUIRED_FW_VER_MIN: number = 52

    Minimum required firmware minor version.

    RSSI_OFFSET: number = 157

    RSSI offset applied to raw radio RSSI readings, matching the Python ref.

    • get ifacEnabled(): boolean

      Whether IFAC is enabled on this interface (a shared secret is configured).

      Returns boolean

    • get readable(): null

      Not used: RNode inbound is event-driven (the internal read loop dispatches packet events directly). Returns null.

      Returns null

    • get writable(): WritableStream<Packet> | null

      The outbound Packet stream. Transport acquires a writer in addInterface; each written packet is KISS-framed as a data frame and sent once the radio is online and ready (see RNodeInterface#send).

      Returns WritableStream<Packet> | null

    • Protected

      Signals the reconnect loop to stop and cancels any in-flight backoff. Client subclasses call this at the top of their disconnect().

      Returns void

    • Protected

      Dispatches a terminal closed event exactly once per connection episode.

      Returns void

    • Protected

      Counts an inbound packet against rxb and dispatches the "packet" event, the single inbound chokepoint each interface's read loop funnels through. Mirrors the self.rxb += len(data) + self.owner.inbound(...) pairing in each Python interface's process_incoming.

      Uses the deserialized packet's cached raw bytes when available (set by Packet.deserialize), avoiding a re-serialize. RNodeInterface dispatches its own packets (it counts the IFAC-inclusive payload) and does not call this.

      Parameters

      Returns void

    • Protected

      Derives and caches the IFAC key/identity/signature from the configured ifacNetname / ifacNetkey, mirroring the per-interface setup in RNS/Reticulum.py (~l.975). No-op (resolves false) when IFAC is disabled. Memoised so the HKDF + Ed25519 key load runs at most once.

      Returns Promise<boolean>

      true if IFAC material is available.

    • Protected

      Opens the transport and configures the radio. Used both for the initial connection and for each reconnect attempt.

      Returns Promise<void>

      Resolves once the radio is online.

    • Protected

      Called when the underlying connection drops (the inbound stream ends or errors). For an initiator with auto-reconnect enabled and not deliberately detached, dispatches disconnected and kicks off the reconnect loop; otherwise dispatches a terminal closed event.

      Matches the Python reference read_loop, which reconnects the initiator on any termination and tears down (non-reconnecting) everyone else.

      Returns void

    • Protected

      Initializes shared reconnect state from constructor options. Called by client interface subclasses (TCP, WebSocket) that support reconnection.

      Subclasses must also set Interface.initiator: true for an outbound dialer, false for an adopted/server-spawned socket.

      Parameters

      • options: ReconnectOptions

      Returns void

    • Protected

      Verifies and unseals inbound raw wire bytes (RNS.Transport.inbound).

      Enforces the flag-presence rules: an IFAC-enabled interface drops a flag-clear packet, and a plain interface drops a flag-set packet — both return null (silent drop). For an IFAC interface it then unmasks, strips the IFAC and verifies it by re-signing; a mismatch also yields null. Subclasses/interfaces call this at the chokepoint where a frame has been unframed to bytes, just before Packet.deserialize.

      Parameters

      • raw: Uint8Array<ArrayBufferLike>

        Sealed or plain wire bytes straight off the medium.

      Returns Promise<Uint8Array<ArrayBufferLike> | null>

      The unsealed bytes, or null to drop.

    • Protected

      Opens the serial device (non-blocking), configures the line discipline via inherited-fd stty, and returns the transport handles for the base class.

      Returns RNodeTransport

    • Protected

      Records an outbound packet against txb. Subclasses (or the interface's outbound stream write callback) call this at the point a packet is handed to the medium — the single chokepoint where every transmitted packet passes, whether sent via send, the transport router, or a broadcast. Mirrors the self.txb += len(data) line in each Python interface's process_outgoing.

      RNodeInterface overrides its own counting (it measures the IFAC-inclusive wire payload) and does not call this.

      Parameters

      Returns void

    • Protected

      Runs the single-flight reconnect loop. Repeatedly waits reconnectWait seconds then attempts to re-establish the connection via the subclass _establishConnection() hook, until it succeeds, the interface is detached, or maxReconnectTries is exceeded (terminal closed).

      Each attempt fires a reconnecting event with the upcoming attempt number, the wait, and the cap, for observability. A successful reconnect fires connected (via _establishConnection).

      Returns Promise<void>

    • Protected

      Seals raw (un-IFACed) wire bytes for transmit (RNS.Transport.transmit). No-op passthrough when IFAC is disabled; otherwise derives the IFAC material on first use, then signs, sets the ifac_flag, inserts the IFAC field and XOR-masks the packet. Subclasses/interfaces call this at the chokepoint where a packet is serialised to bytes, just before framing.

      Parameters

      • raw: Uint8Array<ArrayBufferLike>

        Serialised, unsealed wire bytes.

      Returns Promise<Uint8Array<ArrayBufferLike>>

      The bytes to put on the medium.

    • Protected

      Resolves after ms, or immediately if signal aborts. Used so disconnect() can cancel an in-flight reconnect backoff at once.

      Parameters

      • ms: number
      • signal: AbortSignal

      Returns Promise<void>

    • The addEventListener() method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target.

      MDN Reference

      Parameters

      • type: string
      • callback: EventListenerOrEventListenerObject | null
      • Optionaloptions: boolean | AddEventListenerOptions

      Returns void

    • Applies node-global ingress-control overrides to this interface (mirrors Python, where every interface reads the [reticulum]-section ic_* defaults via RNS.Reticulum.get_instance()._default_ic_*() — there is no per-interface config for these). Only keys present in overrides are assigned; absent keys keep the class constants. Called by import("../core/reticulum.js").Reticulum#addInterface when the node was constructed with an ingressControl config block. These are deliberately not constructor options / interface schema properties: they scope to the whole node, like the Python reference.

      Parameters

      • overrides: Partial<IngressControlConfig>

      Returns void

    • Optional hook invoked by import("../transport/transport.js").TransportCore#addInterface with the transport that owns this interface, right after the interface is attached.

      The base implementation is a no-op. Interfaces that spawn sub-interfaces dynamically — notably AutoInterface, which discovers peers and spawns one per peer — override it to remember the transport so the spawned peers can be auto-registered without a separate Reticulum global (the Python reference uses the global RNS.Transport.add_interface for this).

      Overriders should also register any peers spawned before the transport was attached, so the addInterface/connect call order doesn't matter.

      Parameters

      • _transport: TransportCore

      Returns void

    • Opens the transport, runs the detect → configure → validate handshake, and brings the radio online.

      On a first-attempt failure with auto-reconnect enabled, the promise rejects (so the caller knows) but the reconnect loop keeps retrying in the background — matching the Python reference, which spawns a reconnect thread on the first failure.

      Returns Promise<void>

    • Sends the detect + firmware/platform/MCU query sequence, matching the Python detect() byte-for-byte (four frames sharing FEND boundaries).

      Returns void

    • Returns control of the display to the device firmware. Mirrors Python disable_external_framebuffer. No-op on headless devices.

      Returns void

    • Powers the radio down, sends the host-leave command, closes the transport, and cancels any pending reconnect. Dispatches disconnected then a terminal closed.

      Returns Promise<void>

    • The dispatchEvent() method of the EventTarget sends an Event to the object, (synchronously) invoking the affected event listeners in the appropriate order. The normal event processing rules (including the capturing and optional bubbling phase) also apply to events dispatched manually with dispatchEvent().

      MDN Reference

      Parameters

      • event: Event

      Returns boolean

    • Writes a full image to the framebuffer, one RNodeInterface.FB_BYTES_PER_LINE-byte line at a time. Trailing bytes that do not fill a complete line are ignored. Mirrors Python display_image.

      Parameters

      • imageData: Uint8Array<ArrayBufferLike> | number[]

      Returns number

      The number of complete lines written.

    • Enables host control of the on-device display (external framebuffer mode) so that RNodeInterface#displayImage output is shown. Mirrors Python enable_external_framebuffer. No-op on headless devices.

      Returns void

    • Returns a stats snapshot for this RNode, extending the base traffic counters with the LoRa radio telemetry the firmware reports over KISS: on-air bitrate, active radio parameters, signal quality (RSSI/SNR/Q), channel airtime & load, and battery/temperature. Fields are null until the radio has reported them.

      Returns RNodeStats

    • Forces a hardware reset of the RNode. Sends CMD_RESET with the 0xF8 reset code, then waits for the device to reboot (Python hard_reset, which sleeps 2.25s). A rebooting ESP32 reports CMD_RESET 0xF8 once it is back, which the read loop treats as a connection loss (→ reconnect). No-op before connect.

      Returns Promise<void>

    • Buffers an announce for delayed processing while an ingress burst is latched (Python hold_announce). Announces at or beyond PATHFINDER_M - 1 (127) hops are dropped rather than held; a destination already in the table always replaces its entry (newest emission wins); beyond icMaxHeldAnnounces distinct destinations, new ones are silently dropped.

      Parameters

      • packet: Packet

        Validated announce.

      Returns void

    • Records an IFAC (interface authentication code) violation on this interface (Python ifac_violation): missing IFAC flag, insufficient packet size for the IFAC field, or an IFAC that fails re-verification. Increments ifacViolations, logs at DEBUG, returns null.

      Parameters

      • Optionaldescription: string | null = null

      Returns null

    • Outgoing announce rate in Hz (Python outgoing_announce_frequency). Needs more than one sample.

      Returns number

    • Outgoing path? request rate in Hz (Python outgoing_pr_frequency). Needs more than one sample.

      Returns number

    • Records a packet-filter (dedup) hit on this interface (Python packet_filter_hit): an inbound non-announce packet whose hash is already in the dedup ring. Increments packetFilterHits, returns null.

      Returns null

    • Releases one held announce if conditions allow (the selection half of Python process_held_announces): at most one announce per icHeldReleaseInterval, never before icHeldRelease, and only while the incoming announce frequency is back below the burst threshold. Selection prefers the lowest hop count (nearest destinations converge first). The caller re-injects the returned packet into the normal inbound pipeline (Python spawns a thread calling Transport.inbound(raw, receiving_interface)).

      Returns Packet | null

      The announce to re-inject, or null when nothing is releasable.

    • Records a generic protocol violation on this interface (Python protocol_violation): malformed packets, invalid announce signatures, tagless / oversized path requests, undecodable MTU signalling, inbound processing exceptions. Increments protocolViolations, logs at DEBUG, and returns null so it chains as the return value at every drop site.

      Parameters

      • Optionaldescription: string | null = null

        Optional human-readable detail.

      Returns null

    • Requests the current 1024-byte on-device display snapshot and resolves once the device echoes it back (or after timeoutMs). The image is kept on RNodeInterface#rDisp; the round-trip latency is on RNodeInterface#rDispLatency. Mirrors Python read_display. This is distinct from RNodeInterface#readFramebuffer (the host-writable 512-byte framebuffer). No-op on headless devices.

      Parameters

      • OptionaltimeoutMs: number = 2000

      Returns Promise<Uint8Array<ArrayBufferLike> | null>

      The display image, or null on timeout or on a headless device.

    • Requests the current 512-byte framebuffer contents and resolves once the device has echoed them back (or after timeoutMs). The image is also kept on RNodeInterface#rFrameBuffer; the measured round-trip latency is on RNodeInterface#rFrameBufferLatency. Mirrors Python read_framebuffer.

      Parameters

      • OptionaltimeoutMs: number = 2000

      Returns Promise<Uint8Array<ArrayBufferLike> | null>

      The framebuffer, or null on timeout or on a headless device.

    • Records an inbound announce into iaFreqDeque (Python received_announce). Spawned interfaces propagate the sample to their parent so bursts are detected at the medium level.

      Parameters

      • OptionalfromSpawned: boolean = false

        Internal: true when called on a parent.

      Returns void

    • Records an inbound path? request into ipFreqDeque (Python received_path_request). Spawned interfaces propagate to their parent.

      Parameters

      • OptionalfromSpawned: boolean = false

        Internal: true when called on a parent.

      Returns void

    • The removeEventListener() method of the EventTarget interface removes an event listener previously registered with EventTarget.addEventListener() from the target. The event listener to be removed is identified using a combination of the event type, the event listener function itself, and various optional options that may affect the matching process; see Matching event listeners for removal.

      MDN Reference

      Parameters

      • type: string
      • callback: EventListenerOrEventListenerObject | null
      • Optionaloptions: boolean | EventListenerOptions

      Returns void

    • Sends a packet, honouring flow control. If the radio is online and ready the packet is transmitted immediately (and, with flow control, the next one is gated on CMD_READY); otherwise it is queued for later. Mirrors the Python reference process_outgoing. Sending a packet also arms the ID beacon timer (see RNodeInterface#_armIdBeacon).

      Parameters

      Returns Promise<void>

    • Records an outbound announce into oaFreqDeque (Python sent_announce); counted by TransportCore.broadcast at the transmit chokepoint, and surfaced as outgoingAnnounceFrequency for the future announce-rate-table work (#31 step 6).

      Parameters

      • OptionalfromSpawned: boolean = false

        Internal: true when called on a parent.

      Returns void

    • Records an outbound path? request into opFreqDeque (Python sent_path_request); consumed by egress PR limiting (work doc #31 step 4).

      Parameters

      • OptionalfromSpawned: boolean = false

        Internal: true when called on a parent.

      Returns void

    • Whether announce ingress should be limited right now (Python should_ingress_limit). Latches a burst when the incoming announce frequency exceeds the threshold for the interface's age — stricter (icBurstFreqNew) during the first icNewTime seconds. Once latched, stays limiting for at least icBurstHold seconds and until the frequency drops back below the threshold; the call that unlatches still reports true (mirroring the Python reference, the next packet after it flows normally).

      Consumers: held-announce buffering for unknown destinations (work doc #31 step 3). The announce frequency side effects (latching plus arming icHeldRelease with the icBurstPenalty) match Python so the state is already correct when that lands.

      Returns boolean

    • Whether path? request ingress should be limited right now (Python should_ingress_limit_pr, incl. the upstream cooldown hysteresis). Latches when the incoming PR frequency exceeds the age-dependent threshold (icPrBurstFreqNew during the first icNewTime seconds, icPrBurstFreq after). Once latched, stays limiting for at least icBurstHold seconds; after the hold, unlatching takes Interface.IC_PR_BURST_COOLDOWN+1 consecutive below-threshold evaluations — any above-threshold evaluation resets the cooldown (anti-flapping at the boundary). Consumers: TransportCore drops unique-tag path requests while a burst is latched (work doc #31 step 2 — our inline processing equivalent of the Python reference's TC_INGRESS_LIMITED traffic-class demotion).

      Returns boolean

    • Stops the periodic display-update poll started by startDisplayUpdates.

      Returns void

    • Writes one RNodeInterface.FB_BYTES_PER_LINE-byte line to the framebuffer at the given line index (0-based). The payload [line, ...lineData] is KISS-escaped, matching Python write_framebuffer.

      Parameters

      • line: number
      • lineData: Uint8Array<ArrayBufferLike> | number[]

      Returns void

    • Returns the JSON Schema for the serial RNode backend (the base radio options plus the serial port/baudRate).

      Returns Record<string, any>

      A JSON Schema object.