Skip to main content

Crate ados_gpio

Crate ados_gpio 

Source
Expand description

§ados-gpio

crates.io docs.rs license MSRV

Drive a buzzer or LED on a Linux GPIO character-device line and compute bounded software-PWM beep schedules, as used by the ADOS Drone Agent.

A status buzzer or LED on a single-board computer needs two things: a way to drive a GPIO line, and a beep pattern that can never leave the line stuck high. This crate keeps the timing maths pure and testable on any host, and puts the hardware write behind a small Linux-only type. Reach for it when a service must signal state through a buzzer or LED and must stay safe under malformed commands.

use ados_gpio::{beep_schedule, BeepPattern, Level, MAX_TOTAL_MS};

// Three short beeps with a 2 kHz carrier at 50 % duty.
let pattern = BeepPattern { freq_hz: 2_000, duty_pct: 50, on_ms: 100, off_ms: 150, cycles: 3 };
let schedule = beep_schedule(pattern);

assert_eq!(schedule[0].level, Level::High);
assert_eq!(schedule[0].hold_ms, 100);
// The schedule always ends with the line low.
assert_eq!(schedule.last().unwrap().level, Level::Low);

// A hostile pattern is clamped and truncated to the total budget.
let huge = BeepPattern { freq_hz: 0, duty_pct: 100, on_ms: u32::MAX, off_ms: u32::MAX, cycles: u32::MAX };
let total: u64 = beep_schedule(huge).iter().map(|p| u64::from(p.hold_ms)).sum();
assert!(total <= MAX_TOTAL_MS);

§Highlights

  • Safe by default: every pattern is clamped (BeepPattern::clamp) and every schedule is capped at MAX_TOTAL_MS and ends low.
  • Timing and command parsing are pure functions with no hardware or clock, unit-tested on any host.
  • The hardware half uses the pure-Rust gpio-cdev backend, so there is no libgpiod C dependency.
  • Linux-only items are gated with cfg(target_os = "linux"); the rest builds on any platform.

§How it works

The crate has two halves.

  • Hardware output. GpioOutput opens a /dev/gpiochip* line in output mode and drives it high or low. It exists only on Linux.
  • Portable maths. BeepPattern, beep_schedule and carrier_timing turn a pattern into a list of BeepPhase toggle instants plus the carrier half-periods. A software-PWM beep is that list applied to a GpioOutput.

Commands arrive as one newline-delimited JSON request per connection. parse_command validates a request into a Command or a stable error code, without touching hardware. A fresh service drives no line until it receives an explicit command.

Bounds: carrier up to MAX_CARRIER_HZ (5 kHz), each phase up to MAX_PHASE_MS (5 s), up to MAX_BEEP_CYCLES (64) cycles, and a whole schedule of at most MAX_TOTAL_MS (30 s).

§Part of ADOS

Used in production by the ADOS Drone Agent, the onboard software of the ADOS software-defined drone platform. All ADOS crates · Docs · Discord

§Other ADOS crates

Platform (versioned with the ADOS Drone Agent)

CrateWhat it doesDocs
ados-protocolWire contracts of the ADOS Drone Agent: IPC framing, plugin RPC envelope, capability tokens and the vision frame bus.docs.rs
ados-sdkWrite Rust plugins for the ADOS Drone Agent: IPC client, plugin context, driver traits and lifecycle runner.docs.rs
ados-visionSingle-object visual tracker: Kalman motion model, appearance re-identification and YOLOv8 head decoding.docs.rs
ados-hal-probeFind out what a board’s hardware can really do by probing it, plus bundled board profiles.docs.rs

Standalone

CrateWhat it doesDocs
ados-sensorhubSensor hub wire protocol: COBS framing, CRC-16 and fixed-layout IMU, baro, mag and GNSS packets. no_std.docs.rs
ados-offloadChoose where perception runs (onboard, offloaded or hybrid) and hold the vehicle when results go stale.docs.rs
ados-macpinStable MAC addresses for Linux network adapters that randomize theirs every boot.docs.rs
ados-loraLoRa transmit governor with cited regional band plans, duty cycle, dwell time and airtime accounting.docs.rs
ados-crsf-codecno_std CRSF / ExpressLRS codec for RC channels, telemetry and parameter frames.docs.rs
ados-positioningSplit mixed UBX, NMEA and RTCM3 GNSS streams, configure u-blox receivers and run an RTK base survey-in.docs.rs
ados-rtcmRTCM3 framing, CRC-24Q and MAVLink GPS_RTCM_DATA fragmentation for RTK corrections.docs.rs
ados-clockMap remote clocks onto the host clock: least-squares and envelope fits, TIMESYNC and a chrony sink.docs.rs
ados-swarmSwarm control laws: separation, flocking, formations, CBBA task allocation and a point-mass simulator.docs.rs
ados-mavlink-tunnelSend large messages over MAVLink TUNNEL frames with chunking and bounded reassembly.docs.rs
ados-display-driverSmall-display output on Linux: SSD1306/SH1106 OLED over I2C, pixel packers and a framebuffer writer.docs.rs
ados-hmiFront-panel input: touchscreen calibration and gestures, button presses and rotary encoders.docs.rs

§ADOS repositories

RepoRuns onWhat it doesLink
ADOS Mission ControlBrowser, desktop (Electron)Ground control station: FC setup, mission planning, flight, 3D simulation, fleetADOSMissionControl
ADOS Drone AgentCompanion computer on the drone, or a ground nodeOnboard agent: MAVLink routing, HD video, long-range radio link, plugins, remote controlADOSDroneAgent
ADOS Android GCSAndroid phones and tabletsNative ground control app for agents on the LAN, direct flight controllers and the cloudADOSAndroidGCS
ADOS ExtensionsDrone Agent and Mission ControlFirst-party signed plugins, each with an agent half and a GCS halfADOSExtensions
ADOS MCPYour machineModel Context Protocol server that lets AI clients operate ADOS drones under scopes and a safety gateADOS-MCP
Documentationdocs.altnautica.comPublic docs for every ADOS productDocumentation

§License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Modules§

daemon
ados-gpio daemon.
sidecar
The /run/ados/gpio-output.json state sidecar: the current driven line states, written atomically through ados_protocol::sidecar::write_atomic (unique temp sibling + fsync + rename) so a reader never sees a half-written file.

Structs§

BeepPattern
A bounded software-PWM beep description.
BeepPhase
One phase of a beep schedule: hold the line at level for hold_ms, then move to the next phase. The final phase always returns the line low.
GpioOutput
Owns the set of output lines the service is driving, opening each chip lazily on first use and caching the line handle so repeated writes reuse it.

Enums§

Command
A validated GPIO-output command, parsed from one request line. Parsing is pure (no hardware), so every malformed request is rejected before the service touches a line. A set drives one line to a level; a beep runs a bounded software-PWM envelope on one line; status reports the current line states.
Level
The logical level a pin is driven to.
Parsed
The outcome of parsing a request line: a routed Command, or a terminal machine-readable error string for a malformed/unknown request (answered without ever touching hardware).

Constants§

GPIO_CMD_SOCK
Operator command socket the service serves and the plugin host forwards to (/run/ados/gpio-cmd.sock). Mirrors the radio’s radio-cmd.sock and the net manager’s wifi-cmd.sock pattern: one newline-JSON request, one newline-JSON response per connection.
MAX_BEEP_CYCLES
Largest number of on/off cycles a single beep pattern may schedule. A request for more is clamped down to this.
MAX_CARRIER_HZ
Highest carrier frequency the service toggles, in Hz. The carrier is driven from userspace, so a request above this is clamped down rather than producing a toggle loop the scheduler cannot keep up with.
MAX_PHASE_MS
Longest a single on or off phase may last, in milliseconds. Caps the worst case where one cycle of a clamped pattern still holds the line for a long time.
MAX_TOTAL_MS
Hard ceiling on the total scheduled duration of one pattern, in milliseconds (30 s). Even a pattern within the per-phase and per-cycle bounds is truncated so the whole beep can never run away; the service stops driving and returns the line low once the schedule completes.

Functions§

beep_schedule
Compute the toggle schedule for a beep pattern. Pure: no hardware, no clock, fully unit-testable. The pattern is clamped first, then expanded into a list of BeepPhases (a High for on_ms then a Low for off_ms, repeated cycles times), and the whole sequence is truncated so its summed duration never exceeds MAX_TOTAL_MS. The returned schedule always ends with the line low, so the service never leaves a buzzer/LED stuck on.
carrier_timing
The carrier half-periods for a clamped pattern: how long the line is high and low within one carrier period during an on phase. None means the on phase is a steady high: no carrier requested (freq_hz 0), or a duty of 0 or 100 that a toggle cannot express.
parse_command
Parse + validate one request line. Pure: no hardware, no I/O, fully unit-testable. Bad JSON, an unknown op, or a missing required field resolve to Parsed::Error with a stable E_* code; a beep pattern is clamped into the safe bounds here so an out-of-range request is corrected, never rejected outright (the operator still gets a bounded beep). An empty line is a clean E_BAD_REQUEST, never a panic.