diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 0000000..9f8f9bc
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,57 @@
+name: docs
+
+# Build the CAN-FIX specification (Sphinx) and publish the HTML to GitHub Pages.
+# Docs-only: this reads src/CAN-FIX.ods + the .rst sources to build the site and
+# never modifies the schema. Mirrors src/buildall.sh (minus the PDF).
+
+on:
+ push:
+ branches: [master]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+# One Pages deployment at a time.
+concurrency:
+ group: pages
+ cancel-in-progress: true
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
+ with:
+ python-version: "3.12"
+ - name: Install Sphinx + spreadsheet readers
+ run: pip install sphinx pyexcel pyexcel-ods
+ - name: Generate parameter data from CAN-FIX.ods
+ working-directory: src
+ run: |
+ python canfix_json.py
+ python canfix_xml.py
+ python parameters.py
+ - name: Build HTML
+ working-directory: src
+ run: sphinx-build -b html . _build/html
+ - name: Field-list cleanup + root redirect to the TOC
+ run: |
+ find src/_build/html -name '*.html' -exec sed -i 's/::/:/g' {} +
+ printf '\n' > src/_build/html/index.html
+ - uses: actions/upload-pages-artifact@v3
+ with:
+ path: src/_build/html
+
+ deploy:
+ needs: build
+ runs-on: ubuntu-latest
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..92524fe
--- /dev/null
+++ b/README.md
@@ -0,0 +1,87 @@
+# CAN-FIX Protocol Specification
+
+**Status:** Open Source Specification — Creative Commons Licensed
+**Format:** Sphinx documentation source (builds to PDF and HTML)
+**Scope:** Experimental Amateur-Built (E-AB) Aircraft Avionics
+
+---
+
+## What This Is
+
+This repository contains the **authoritative specification** for the CAN-FIX communication protocol — the CAN bus implementation of the Flight Information eXchange (FIX) protocol family. CAN-FIX defines how avionics nodes on an aircraft CAN network identify themselves, publish flight data parameters, and consume data from other nodes.
+
+The specification is licensed under Creative Commons, meaning anyone can read, implement, modify, and distribute compliant devices without licensing fees or vendor lock-in.
+
+## Read the Specification Online
+
+- **Full specification (web):** — the complete document, rebuilt automatically from this repository on every push.
+- **Wiki (quick reference):** — a friendly companion with a [parameter quick-reference](https://github.com/billmallard/canfix-spec/wiki/Parameter-Reference) table, a [frame-format](https://github.com/billmallard/canfix-spec/wiki/Frame-Format) cheat-sheet, and an [implementer's quick-start](https://github.com/billmallard/canfix-spec/wiki/Implementing-a-Node).
+- **PDF:** build it locally with `make latexpdf` (see [Building the Documentation](#building-the-documentation)).
+
+## What CAN-FIX Defines
+
+- **Parameter namespace:** Every flight data value (airspeed, altitude, heading, GPS position, engine temperatures, control surface positions, etc.) has a named identifier. Parameters are organized by type and support multiple simultaneous sources (e.g., two independent EGT sensors for two engines).
+- **Frame structure:** How 11-bit CAN identifiers are allocated across parameter types, node IDs, and index bytes for multi-instance data.
+- **Node types and device IDs:** Standard device type identifiers so nodes can announce their role on the network.
+- **Multi-source design:** The protocol explicitly accommodates redundant nodes publishing the same parameter type using separate identifier ranges, avoiding CAN arbitration conflicts.
+- **Data types:** float, int, bool, string with defined units and ranges per parameter.
+
+## Parameter Coverage
+
+The specification covers the full avionics parameter set for a modern aircraft:
+
+| Domain | Example Parameters |
+|---|---|
+| Navigation | LAT, LONG, ALT, IAS, TAS, GS, heading, track |
+| AHRS | Pitch, roll, yaw rate, accelerations |
+| Engine (×2) | RPM, MAP, EGT (×N cylinders), CHT, oil temp/pressure, fuel flow |
+| Control surfaces | Pitch, roll, yaw, flap, trim positions |
+| Electrical | Bus voltage, current, alternator status |
+| Fuel | Quantity (×N tanks), flow, pressure |
+| COM/NAV radios | Active/standby frequencies |
+| Systems | Gear position, door status, general annunciators |
+
+## Repository Contents
+
+| Path | Description |
+|---|---|
+| `src/CAN-FIX.ods` | **Master parameter spreadsheet** — the source of truth for all parameter definitions |
+| `src/canfix.json` | Machine-readable parameter definitions (*generated* from `CAN-FIX.ods`) |
+| `src/canfix.xml` | XML form of parameter definitions (*generated* from `CAN-FIX.ods`) |
+| `src/parameters.rst` | Human-readable parameter list (*generated* from `CAN-FIX.ods`) |
+| `src/framedef.rst` | CAN frame format specification |
+| `src/datatypes.rst` | Data type definitions |
+| `src/physical.rst` | Physical layer requirements (wiring, termination, bit rate) |
+| `src/requirements.rst` | Protocol requirements |
+| `src/practices.rst` | Recommended implementation practices |
+| `tools/gen_param_reference.py` | Generates the wiki parameter quick-reference from `canfix.json` |
+| `tools/sync_wiki.sh` | Mirrors `wiki/` to the GitHub wiki clone for publishing |
+
+> **Editing parameters:** change `src/CAN-FIX.ods` (the master), then regenerate
+> the derived files with the commands below. Do not hand-edit `canfix.json`,
+> `canfix.xml`, or `parameters.rst` — they are overwritten on every build.
+
+## Building the Documentation
+
+Requires Python with Sphinx and supporting packages:
+
+```bash
+sudo pip install pyexcel pyexcel-ods sphinx
+sudo apt install texlive-latex-base texlive-fonts-recommended texlive-fonts-extra texlive-latex-extra texlive-xetex latexmk
+cd src
+python canfix_json.py # regenerate canfix.json from CAN-FIX.ods
+python canfix_xml.py # regenerate canfix.xml from CAN-FIX.ods
+python parameters.py # regenerate parameter_list from CAN-FIX.ods
+make latexpdf # builds PDF -> src/_build/latex
+make html # builds HTML -> src/_build/html
+```
+
+The web specification at is built
+and published automatically by GitHub Actions (`.github/workflows/docs.yml`) on
+every push to `master`, so the online copy always matches the repository.
+
+## Important Disclaimer
+
+> This specification is developed for Experimental Amateur-Built aircraft use only.
+> It is not FAA-approved avionics software or a certified communication standard.
+> All implementations are the builder's responsibility.
diff --git a/tests/test_canfix_spec.py b/tests/test_canfix_spec.py
new file mode 100644
index 0000000..41c165f
--- /dev/null
+++ b/tests/test_canfix_spec.py
@@ -0,0 +1,252 @@
+"""
+Structural validation tests for canfix.json.
+
+Run from the repo root:
+ python -m pytest tests/ -v
+"""
+import json
+import os
+import pytest
+
+SPEC_PATH = os.path.join(os.path.dirname(__file__), "..", "src", "canfix.json")
+
+# Base types per the CAN-FIX spec; compound types (e.g. INT[2],BYTE) are split on ','
+# and array suffixes (e.g. CHAR[2]) are stripped before lookup.
+VALID_BASE_TYPES = {"BYTE", "WORD", "SHORT", "USHORT", "FLOAT", "DOUBLE", "CHAR", "BOOL",
+ "INT", "UINT", "LONG", "ULONG", "DINT", ""}
+
+
+@pytest.fixture(scope="module")
+def spec():
+ with open(SPEC_PATH, encoding="utf-8") as f:
+ return json.load(f)
+
+
+@pytest.fixture(scope="module")
+def parameters(spec):
+ return spec["parameters"]
+
+
+@pytest.fixture(scope="module")
+def groups(spec):
+ return spec["groups"]
+
+
+@pytest.fixture(scope="module")
+def status(spec):
+ return spec["status"]
+
+
+# ── Top-level structure ────────────────────────────────────────────────────────
+
+class TestTopLevelStructure:
+ def test_has_parameters_key(self, spec):
+ assert "parameters" in spec
+
+ def test_has_groups_key(self, spec):
+ assert "groups" in spec
+
+ def test_has_status_key(self, spec):
+ assert "status" in spec
+
+ def test_parameter_count(self, parameters):
+ assert len(parameters) == 230, (
+ f"Expected 230 parameters, got {len(parameters)}"
+ )
+
+ def test_group_count(self, groups):
+ assert len(groups) == 17
+
+ def test_status_count(self, status):
+ assert len(status) == 10
+
+
+# ── Parameter required fields ─────────────────────────────────────────────────
+
+class TestParameterRequiredFields:
+ def test_all_have_id(self, parameters):
+ missing = [p.get("name", "?") for p in parameters if "id" not in p]
+ assert not missing, f"Parameters missing 'id': {missing}"
+
+ def test_all_have_name(self, parameters):
+ missing = [p.get("id", "?") for p in parameters if "name" not in p or not p["name"]]
+ assert not missing, f"Parameters missing 'name': {missing}"
+
+ def test_all_have_count(self, parameters):
+ missing = [p.get("id", "?") for p in parameters if "count" not in p]
+ assert not missing, f"Parameters missing 'count': {missing}"
+
+ def test_all_have_type(self, parameters):
+ missing = [p.get("id", "?") for p in parameters if "type" not in p]
+ assert not missing, f"Parameters missing 'type': {missing}"
+
+ def test_all_have_index_key(self, parameters):
+ missing = [p.get("id", "?") for p in parameters if "index" not in p]
+ assert not missing, f"Parameters missing 'index' key (may be null): {missing}"
+
+ def test_all_have_metadata_key(self, parameters):
+ missing = [p.get("id", "?") for p in parameters if "metadata" not in p]
+ assert not missing, f"Parameters missing 'metadata' key: {missing}"
+
+
+# ── Parameter ID constraints ──────────────────────────────────────────────────
+
+class TestParameterIds:
+ def test_ids_are_integers(self, parameters):
+ non_int = [p["name"] for p in parameters if not isinstance(p["id"], int)]
+ assert not non_int, f"Non-integer IDs: {non_int}"
+
+ def test_ids_are_unique(self, parameters):
+ ids = [p["id"] for p in parameters]
+ seen = set()
+ dupes = []
+ for i in ids:
+ if i in seen:
+ dupes.append(i)
+ seen.add(i)
+ assert not dupes, f"Duplicate parameter IDs: {dupes}"
+
+ def test_ids_in_parameter_range(self, parameters):
+ # Parameters live in IDs 256–1759 per the CAN-FIX spec
+ out_of_range = [p["id"] for p in parameters if not (256 <= p["id"] <= 1759)]
+ assert not out_of_range, f"Parameter IDs outside 256–1759: {out_of_range}"
+
+ def test_ids_sorted_ascending(self, parameters):
+ ids = [p["id"] for p in parameters]
+ assert ids == sorted(ids), "Parameter list is not sorted by ID"
+
+
+# ── Parameter type constraints ────────────────────────────────────────────────
+
+class TestParameterTypes:
+ def test_types_are_strings(self, parameters):
+ non_str = [p["id"] for p in parameters if not isinstance(p["type"], str)]
+ assert not non_str, f"Non-string types: {non_str}"
+
+ def test_types_are_valid(self, parameters):
+ import re
+ def base_types(type_str):
+ # Split compound types on ',' then strip array notation e.g. CHAR[2] → CHAR
+ parts = [t.strip() for t in type_str.split(",")]
+ return [re.sub(r"\[\d+\]$", "", p) for p in parts]
+
+ invalid = []
+ for p in parameters:
+ for bt in base_types(p["type"]):
+ if bt not in VALID_BASE_TYPES:
+ invalid.append((p["id"], p["type"], bt))
+ assert not invalid, f"Unrecognized base types: {invalid}"
+
+ def test_count_is_positive_integer(self, parameters):
+ bad = [p["id"] for p in parameters
+ if not isinstance(p["count"], int) or p["count"] < 1]
+ assert not bad, f"Parameters with invalid count: {bad}"
+
+
+# ── Min/max constraints ───────────────────────────────────────────────────────
+
+class TestMinMax:
+ @staticmethod
+ def _parse_number(s):
+ # Some values use comma-formatted numbers e.g. "60,000" → 60000
+ return float(str(s).replace(",", ""))
+
+ def test_min_max_parseable_as_float(self, parameters):
+ bad = []
+ for p in parameters:
+ for key in ("min", "max"):
+ if key in p and p[key] is not None:
+ try:
+ self._parse_number(p[key])
+ except (TypeError, ValueError):
+ bad.append((p["id"], key, p[key]))
+ assert not bad, f"Non-numeric min/max values: {bad}"
+
+ def test_min_less_than_max_where_present(self, parameters):
+ violations = []
+ for p in parameters:
+ if "min" in p and "max" in p and p["min"] is not None and p["max"] is not None:
+ try:
+ mn = self._parse_number(p["min"])
+ mx = self._parse_number(p["max"])
+ if mn >= mx:
+ violations.append((p["id"], p["name"], mn, mx))
+ except (TypeError, ValueError):
+ violations.append((p["id"], p["name"], p["min"], p["max"]))
+ assert not violations, f"min >= max: {violations}"
+
+ def test_multiplier_parseable_as_float(self, parameters):
+ bad = []
+ for p in parameters:
+ if "multiplier" in p and p["multiplier"] is not None:
+ try:
+ float(p["multiplier"])
+ except (TypeError, ValueError):
+ bad.append((p["id"], p["multiplier"]))
+ assert not bad, f"Non-numeric multipliers: {bad}"
+
+
+# ── Group constraints ─────────────────────────────────────────────────────────
+
+class TestGroups:
+ def test_groups_have_required_fields(self, groups):
+ for g in groups:
+ assert "name" in g, f"Group missing 'name': {g}"
+ assert "startid" in g, f"Group missing 'startid': {g}"
+ assert "endid" in g, f"Group missing 'endid': {g}"
+
+ def test_group_startid_lte_endid(self, groups):
+ violations = [
+ (g["name"], g["startid"], g["endid"])
+ for g in groups
+ if g["startid"] > g["endid"]
+ ]
+ assert not violations, f"Groups with startid > endid: {violations}"
+
+ def test_group_ids_cover_0_to_2047(self, groups):
+ covered = set()
+ for g in groups:
+ for i in range(g["startid"], g["endid"] + 1):
+ covered.add(i)
+ assert 0 in covered
+ assert 2047 in covered
+
+ def test_every_parameter_id_falls_in_a_group(self, parameters, groups):
+ def in_any_group(pid):
+ return any(g["startid"] <= pid <= g["endid"] for g in groups)
+
+ orphans = [p["id"] for p in parameters if not in_any_group(p["id"])]
+ assert not orphans, f"Parameter IDs not covered by any group: {orphans}"
+
+
+# ── Status entries ────────────────────────────────────────────────────────────
+
+class TestStatus:
+ def test_status_have_required_fields(self, status):
+ for s in status:
+ assert "type" in s, f"Status entry missing 'type': {s}"
+ assert "description" in s, f"Status entry missing 'description': {s}"
+ assert "datatype" in s, f"Status entry missing 'datatype': {s}"
+
+ def test_status_descriptions_are_nonempty(self, status):
+ empty = [s.get("type") for s in status if not s.get("description")]
+ assert not empty, f"Status entries with empty description: {empty}"
+
+
+# ── Spot-check well-known parameters ─────────────────────────────────────────
+
+class TestKnownParameters:
+ def _get(self, parameters, pid):
+ return next((p for p in parameters if p["id"] == pid), None)
+
+ def test_flap_control_switches_id_256(self, parameters):
+ p = self._get(parameters, 256)
+ assert p is not None
+ assert p["name"] == "Flap Control Switches"
+ assert p["type"] == "BYTE"
+
+ def test_trim_switches_id_258(self, parameters):
+ p = self._get(parameters, 258)
+ assert p is not None
+ assert p["name"] == "Trim Switches"
+ assert p["type"] == "WORD"
diff --git a/tools/gen_param_reference.py b/tools/gen_param_reference.py
new file mode 100644
index 0000000..bcba362
--- /dev/null
+++ b/tools/gen_param_reference.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python3
+"""Generate the Parameter Quick-Reference wiki page from src/canfix.json.
+
+canfix.json is itself generated from the master spreadsheet (src/CAN-FIX.ods)
+by src/canfix_json.py, so this script never touches the schema -- it only
+reformats the already-generated parameter table into a Markdown quick reference
+for the GitHub wiki. Paths are resolved relative to the repo root, so it can be
+run from anywhere:
+
+ python tools/gen_param_reference.py
+"""
+import json
+import os
+
+REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+SRC = os.path.join(REPO, "src", "canfix.json")
+OUT = os.path.join(REPO, "wiki", "Parameter-Reference.md")
+PAGES = "https://billmallard.github.io/canfix-spec"
+JSON_URL = "https://github.com/billmallard/canfix-spec/blob/master/src/canfix.json"
+
+
+def esc(text):
+ """Escape a value for use inside a Markdown table cell."""
+ return str(text).replace("|", "\\|").replace("\n", " ").strip()
+
+
+def id_label(p):
+ """A single ID, or a 'start-end' range when the parameter spans several."""
+ count = p.get("count", 1) or 1
+ start = p["id"]
+ if count > 1:
+ return f"{start}-{start + count - 1}"
+ return str(start)
+
+
+def range_label(p):
+ lo = p.get("min")
+ hi = p.get("max")
+ has_lo = lo not in (None, "")
+ has_hi = hi not in (None, "")
+ if not has_lo and not has_hi:
+ return ""
+ return f"{lo if has_lo else ''} to {hi if has_hi else ''}"
+
+
+def notes(p):
+ bits = []
+ idx = p.get("index")
+ if idx:
+ bits.append(f"Indexed by {idx}")
+ fmt = p.get("format")
+ if fmt:
+ bits.append(fmt)
+ for remark in (p.get("remarks") or []):
+ bits.append(remark)
+ return "; ".join(esc(b) for b in bits)
+
+
+def main():
+ with open(SRC, encoding="utf-8") as f:
+ spec = json.load(f)
+
+ groups = spec["groups"]
+ params = spec["parameters"]
+ version = spec.get("version", "")
+
+ out = []
+ out.append("# Parameter Quick-Reference")
+ out.append("")
+ out.append(
+ f"Every CAN-FiX parameter (protocol version **{version}**), grouped by "
+ f"CAN identifier range. This page is generated from "
+ f"[`src/canfix.json`]({JSON_URL}), which is built from the master "
+ f"spreadsheet `src/CAN-FIX.ods` -- so it always matches the specification."
+ )
+ out.append("")
+ out.append(
+ f"For the full normative definitions (data encodings, frame formats, "
+ f"meta data and bit fields) see the [complete specification]({PAGES}/), "
+ f"in particular the [Parameters chapter]({PAGES}/parameters.html)."
+ )
+ out.append("")
+ out.append("**Reading this table**")
+ out.append("")
+ out.append(
+ "- **ID** -- the 11-bit CAN frame identifier. A range (e.g. `256-257`) "
+ "means the parameter occupies several consecutive IDs for multiple "
+ "instances."
+ )
+ out.append(
+ f"- **Type** -- the [data type]({PAGES}/datatypes.html) of the value "
+ "(see also [Data Types](Data-Types))."
+ )
+ out.append("- **Units / Range / Mult** -- engineering units, min/max, and the "
+ "multiplier (the value each least-significant bit represents).")
+ out.append(
+ "- **Notes** -- the index dimension (for indexed parameters), the data "
+ "format, and any per-parameter remarks."
+ )
+ out.append("")
+
+ total_groups = 0
+ for g in groups:
+ gparams = sorted(
+ (p for p in params if g["startid"] <= p["id"] <= g["endid"]),
+ key=lambda x: x["id"],
+ )
+ if not gparams:
+ continue
+ total_groups += 1
+ out.append(f"## {esc(g['name'])} ({g['startid']}-{g['endid']})")
+ out.append("")
+ out.append("| ID | Parameter | Type | Units | Range | Mult | Notes |")
+ out.append("|---|---|---|---|---|---|---|")
+ for p in gparams:
+ row = [
+ id_label(p),
+ esc(p.get("name", "")),
+ esc(p.get("type", "")),
+ esc(p.get("units", "") or ""),
+ esc(range_label(p)),
+ esc(p.get("multiplier", "") or ""),
+ notes(p),
+ ]
+ out.append("| " + " | ".join(row) + " |")
+ out.append("")
+
+ out.append("---")
+ out.append("")
+ out.append(
+ f"_{len(params)} parameters across {total_groups} groups. Generated by "
+ f"`tools/gen_param_reference.py` from `src/canfix.json` (version "
+ f"{version}). Do not edit by hand -- edit the master spreadsheet and "
+ f"regenerate._"
+ )
+ out.append("")
+
+ os.makedirs(os.path.dirname(OUT), exist_ok=True)
+ with open(OUT, "w", encoding="utf-8", newline="\n") as f:
+ f.write("\n".join(out))
+ print(f"wrote {OUT}")
+ print(f" {len(params)} parameters, {total_groups} groups")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/sync_wiki.sh b/tools/sync_wiki.sh
new file mode 100644
index 0000000..66c9974
--- /dev/null
+++ b/tools/sync_wiki.sh
@@ -0,0 +1,57 @@
+#!/usr/bin/env bash
+#
+# Mirror the canonical wiki source (wiki/) to a local clone of the GitHub wiki.
+#
+# This regenerates the parameter quick-reference from src/canfix.json, then
+# copies the wiki pages into a sibling ../canfix-spec.wiki working copy. It does
+# NOT push -- review the result and push it yourself (publishing is outward-facing).
+#
+# Usage:
+# tools/sync_wiki.sh [wiki-remote-url] [wiki-clone-dir]
+#
+# Defaults:
+# wiki-remote-url = https://github.com/billmallard/canfix-spec.wiki.git
+# wiki-clone-dir = ../canfix-spec.wiki (relative to repo root)
+#
+set -euo pipefail
+
+REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
+SRC="$REPO_ROOT/wiki"
+WIKI_URL="${1:-https://github.com/billmallard/canfix-spec.wiki.git}"
+WIKI_DIR="${2:-$REPO_ROOT/../canfix-spec.wiki}"
+
+# 1. Regenerate the parameter quick-reference from the spec data.
+echo "Regenerating Parameter-Reference.md from src/canfix.json"
+python "$REPO_ROOT/tools/gen_param_reference.py"
+
+if [ ! -d "$SRC" ]; then
+ echo "error: $SRC not found" >&2
+ exit 1
+fi
+
+# 2. Clone or update the wiki working copy.
+if [ -d "$WIKI_DIR/.git" ]; then
+ echo "Updating existing wiki clone at $WIKI_DIR"
+ git -C "$WIKI_DIR" pull --ff-only
+else
+ echo "Cloning wiki from $WIKI_URL into $WIKI_DIR"
+ echo " (the wiki must exist: open the repo's Wiki tab and create one page first,"
+ echo " or push an initial commit to $WIKI_URL)"
+ git clone "$WIKI_URL" "$WIKI_DIR"
+fi
+
+# 3. Copy each page. Inter-page links already use the extension-less GitHub wiki
+# form ([text](Page-Name)); the sed is a harmless safety net for any that use
+# a .md suffix.
+shopt -s nullglob
+for f in "$SRC"/*.md; do
+ base="$(basename "$f")"
+ sed -e 's#\](\([A-Za-z0-9_-]*\)\.md\([)#]\)#](\1\2#g' \
+ "$f" > "$WIKI_DIR/$base"
+ echo " page: $base"
+done
+
+echo
+echo "Mirror staged in $WIKI_DIR (NOT pushed)."
+echo "Review and publish:"
+echo " cd \"$WIKI_DIR\" && git add -A && git commit -m 'Sync wiki from wiki/' && git push"
diff --git a/wiki/Background-CANaerospace.md b/wiki/Background-CANaerospace.md
new file mode 100644
index 0000000..6da6180
--- /dev/null
+++ b/wiki/Background-CANaerospace.md
@@ -0,0 +1,111 @@
+# Background: CANaerospace and why CAN-FiX exists
+
+CAN-FiX was born from Phil Birkelbach's frustrations with
+**CANaerospace**, the 1998 aviation CAN protocol it most resembles.
+This page gives the history: what CANaerospace is, where it went, and
+what CAN-FiX deliberately did differently. (Researched 2026-07-05;
+sources at the bottom.)
+
+## What CANaerospace is
+
+CANaerospace is an application-layer protocol over CAN, created in
+**1998 by Michael Stock** of Stock Flight Systems — an aerospace
+engineering firm in Farchach (Berg, Bavaria) specialized in flight-test
+instrumentation. Design highlights:
+
+- Big-endian, **self-identifying messages**: 8-byte payload = 4-byte
+ header (Node-ID, data type, service code, message code) + 4 bytes of
+ data — half of every frame is metadata.
+- Priority-ordered logical channels (emergency events, node services,
+ normal operation data, user-defined, debug) over a standard
+ identifier distribution (IDs 300–1799).
+- The same parameter may be sent with **different data types**, and
+ **alternative identifier distributions may coexist** on one bus.
+- Free to download and use — genuinely open for its era.
+
+The flexibility was deliberate: in a flight-test lab you want to put
+arbitrary new parameters on the bus quickly.
+
+## Its pedigree
+
+- **NASA AGATE (2001):** published by NASA as the databus standard of
+ the Advanced General Aviation Transport Experiments consortium, which
+ carried it into research aircraft, simulators and UAVs worldwide.
+- **Rotax iS engines (2012–present):** the Rotax 912iS/915iS ECUs speak
+ CANaerospace — it ships in essentially every new injected-Rotax
+ installation today.
+- **ARINC 825 (2007–present):** an AEEC working group (Airbus, Boeing,
+ GE, Rockwell Collins, Vector, and Stock Flight Systems itself) used
+ CANaerospace as the basis for ARINC 825, the certified-aviation CAN
+ standard — still actively revised, with CAN FD in later revisions.
+
+## Current status: frozen, not failed
+
+The open spec's last revision is **V1.7 (2006)** — two decades
+untouched, with no active steward. stockflightsystems.com survives as a
+legacy brochure site; the commercial products (Rotax iS EMU, MT
+propeller control, CANaerospace loggers) are sold today by RS Flight
+Systems GmbH of Berg — likely a Reiser/Stock venture carrying the
+product line forward (probable, not confirmed). The certified world
+absorbed CANaerospace into ARINC 825; the protocol itself keeps flying
+inside Rotax ECUs.
+
+## Why CAN-FiX — Birkelbach, August 2013
+
+The primary source is the MakerPlane forum thread
+[*"What's wrong with CANaerospace?"*](http://makerplane.org/forum/viewtopic.php?t=216):
+
+> "With it you can send the same parameter over the bus with different
+> data types. This is a great feature if what you are after is
+> flexibility. **The problem with flexibility in a communication
+> protocol is that it forces complexity at the end points.**"
+
+> "CA also allows for multiple identifier distributions to exist on the
+> bus at the same time. It would be up to the end points to determine
+> if the data that they are receiving is what they think it is."
+
+> "CAN-FIX is a much more rigid protocol… **There is only one way to
+> send airspeed on CAN-FIX.**"
+
+Concretely, CAN-FiX:
+
+- replaced the data-type byte with an **index byte** — up to 256
+ instances of a parameter (all your EGTs) instead of type negotiation
+ (see [Frame Format](Frame-Format));
+- pinned **one canonical encoding per parameter** (see
+ [Data Types](Data-Types)), so a $2 microcontroller needs no
+ type-handling layer;
+- put **metadata on the bus** (V-speeds, ranges, alarm setpoints);
+- targeted the Experimental/Amateur-Built ecosystem under a Creative
+ Commons license.
+
+A fair framing: CANaerospace optimizes for the flight-test lab
+(flexibility first); CAN-FiX optimizes for a fixed avionics ecosystem
+of heterogeneous cheap nodes (rigidity first). Both are rational in
+their own domains.
+
+## Family tree
+
+```
+Bosch CAN (1986, automotive)
+ ├─ CANopen / DeviceNet (industrial)
+ ├─ NMEA 2000 (marine)
+ └─ CANaerospace (1998, GA / research / flight test)
+ ├─ ARINC 825 (2007, certified transport; CAN FD later)
+ ├─ UAVCAN (2014) ─┬─ DroneCAN (2022)
+ │ └─ Cyphal (2022)
+ └─ CAN-FiX (~2012, MakerPlane — experimental aviation)
+```
+
+## Sources
+
+- [Wikipedia — CANaerospace](https://en.wikipedia.org/wiki/CANaerospace)
+- [MakerPlane forum — "What's wrong with CANaerospace?" (Aug 2013)](http://makerplane.org/forum/viewtopic.php?t=216)
+- [CAN-FiX Overview (makerplane.org)](https://makerplane.org/can-fix-overview/)
+- [CANaerospace V1.7 specification (PDF)](https://www.stockflightsystems.com/tl_files/downloads/canaerospace/canas_17.pdf)
+- [Stock Flight Systems — ARINC 825 presentation (PDF)](https://files.stockflightsystems.com/_5_Arinc_825/ARINC825_Presentation.pdf)
+- [arinc-825.com — The ARINC825 Standard](https://www.arinc-825.com/the-arinc825-standard/)
+- [Vector application note — CAN-based protocols in Avionics (PDF)](https://cdn.vector.com/cms/content/know-how/_application-notes/canopen/AN-ION-1-0104_CAN-based_protocols_in_Avionics.pdf)
+- [RS Flight Systems](https://www.rs-flightsystems.com/)
+- [Wikipedia — Cyphal](https://en.wikipedia.org/wiki/Cyphal)
+- [Zubax — Cyphal vs DroneCAN](https://zubax.com/blog/on-the-key-differences-between-cyphal-and-dronecan-formerly-uavcan/2038)
diff --git a/wiki/Data-Types.md b/wiki/Data-Types.md
new file mode 100644
index 0000000..7f309fa
--- /dev/null
+++ b/wiki/Data-Types.md
@@ -0,0 +1,47 @@
+# Data Types
+
+How the 1-5 data bytes of a [Normal Data frame](Frame-Format#normal-data-frame)
+are encoded. The full text is in the
+[Data Types chapter](https://billmallard.github.io/canfix-spec/datatypes.html).
+
+Each parameter has a **fixed** data type -- there is no type indicator in the
+message itself (this is deliberate, to keep small 8-bit nodes simple). Fixed-point
+integers with an assumed multiplier are strongly preferred over floating point.
+
+| Type | Description |
+|---|---|
+| `CHAR` | 8-bit ASCII character |
+| `BYTE` | 8 bits (discrete states, switch positions, commands) |
+| `WORD` | 16 bits (discrete states, 16 bit wide) |
+| `SHORT` | 8-bit signed integer |
+| `USHORT` | 8-bit unsigned integer |
+| `INT` | 16-bit signed integer |
+| `UINT` | 16-bit unsigned integer |
+| `DINT` | 32-bit signed integer |
+| `UDINT` | 32-bit unsigned integer |
+| `FLOAT` | 32-bit IEEE 754 floating point |
+
+## Key rules
+
+- **Little-endian.** Multi-byte values are sent least-significant byte first
+ (Byte 3 of the frame is the LSB).
+- **Assumed decimal places.** Most quantities are integers scaled by a
+ **multiplier**. The engineering value is `raw x multiplier`. Example: a
+ parameter with units `%`, multiplier `0.01` and a raw `INT` of `5000` means
+ `50.00 %`. The multiplier for each parameter is in the
+ [Parameter Quick-Reference](Parameter-Reference).
+- **Arrays and mixed types.** A parameter may pack several values into the five
+ data bytes. Time, for example, is three `USHORT`s (hours, minutes, seconds);
+ a date could be `UINT, USHORT[2]` (year, then month and day). The packing is
+ given in each parameter's definition -- the array/mixed forms show up in the
+ **Type** column of the quick-reference (e.g. `INT[2],BYTE`).
+- **64-bit floats** are not a type; when extra precision is needed a parameter is
+ sent across two messages, defined per parameter (rarely needed).
+- **Discrete bits.** `BYTE`/`WORD` parameters often carry independent bit flags
+ (switch up/down, mode engaged). The bit meanings are in the parameter's
+ **Notes** in the [Parameter Quick-Reference](Parameter-Reference) and in the
+ [Parameters chapter](https://billmallard.github.io/canfix-spec/parameters.html).
+
+---
+
+See also: **[Frame Format](Frame-Format)** · **[Parameter Quick-Reference](Parameter-Reference)**
diff --git a/wiki/Frame-Format.md b/wiki/Frame-Format.md
new file mode 100644
index 0000000..10a1a0f
--- /dev/null
+++ b/wiki/Frame-Format.md
@@ -0,0 +1,137 @@
+# Frame Format
+
+A quick reference for the CAN-FiX frame layouts. The full, authoritative text is
+in the [Frame Definitions chapter](https://billmallard.github.io/canfix-spec/framedef.html)
+of the specification.
+
+CAN-FiX uses the **CAN 2.0B base frame** -- an **11-bit identifier** and up to
+**8 data bytes**. The identifier both names the message *and* sets its priority:
+**lower ID = higher priority** (it wins bus arbitration). All multi-byte values
+in the data field are **little-endian** (least-significant byte first).
+
+## How the 11-bit ID space is divided
+
+The identifier tells you which of the four frame formats you are looking at:
+
+| ID range | Frame type | Format |
+|---|---|---|
+| 1 - 255 | **Node Alarms** (highest priority) | [Node Alarm](#node-alarm-frame) |
+| 256 - 1759 | **Parameter data** (the bulk of traffic) | [Normal Data](#normal-data-frame) |
+| 1760 - 2015 | **Node-Specific messages** (config, ID, firmware...) | [Node-Specific](#node-specific-frame) |
+| 2016 - 2047 | **Two-way connection channels** | (point-to-point payloads) |
+
+Within the parameter-data range, IDs are grouped by category and priority. These
+are the groups used by the [Parameter Quick-Reference](Parameter-Reference):
+
+| ID range | Group |
+|---|---|
+| 256 - 319 | High Priority Pilot Control Inputs |
+| 320 - 383 | High Priority Measured Positions |
+| 384 - 447 | High Priority Flight Data |
+| 448 - 511 | High Priority Navigation Data |
+| 512 - 639 | High Priority Engine / Aircraft System Data |
+| 640 - 767 | High Priority Auxiliary Data |
+| 768 - 895 | Normal Priority Pilot Control Inputs |
+| 896 - 1023 | Normal Priority Measured Positions |
+| 1024 - 1151 | Normal Priority Flight Data |
+| 1152 - 1279 | Normal Priority Navigation Data |
+| 1280 - 1407 | Normal Priority Engine / Aircraft System Data |
+| 1408 - 1535 | Normal Priority Auxiliary Data |
+
+## Normal Data frame
+
+The heart of the protocol -- a parameter value update. Frame ID = the parameter
+ID (see [Parameter Quick-Reference](Parameter-Reference)).
+
+| Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7 |
+|---|---|---|---|---|---|---|---|
+| Node | Index | Function Code | Data LSB | Data | Data | Data | Data MSB |
+
+- **Node** -- the Node ID of the sender (1-255, unique on the network).
+- **Index** -- selects an instance of an indexed parameter (e.g. EGT per
+ cylinder: 0, 1, 2...). Zero when the parameter is not indexed.
+- **Function Code** -- meta data selector + quality flags (see below).
+- **Data** -- 1 to 5 bytes, little-endian, encoded per the parameter's
+ [data type](Data-Types).
+
+### Function / Status Code byte
+
+A value of **0** means "ordinary value update, good quality" -- the common case.
+
+| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
+|---|---|---|---|---|---|---|---|
+| Meta Data 3 | Meta Data 2 | Meta Data 1 | Meta Data 0 | Future | Failure | Quality | Annunciate |
+
+- **Annunciate (bit 0)** -- the value is out of range and should be annunciated
+ (e.g. an alarm set point was exceeded).
+- **Quality (bit 1)** -- the sender suspects the data; show it flagged (like an
+ attitude-indicator flag).
+- **Failure (bit 2)** -- the sender knows the data is bad; do not show it,
+ indicate the failure.
+- **Meta Data (bits 4-7)** -- when non-zero, the data field carries one of 15
+ meta-data values for this parameter (alarm set points, V-speeds, scaling)
+ instead of the parameter value itself. Meta data shares the parameter's units,
+ range and data type. Value 0 = the parameter itself.
+
+> If Quality or Failure is set, use an alternate source for the value if one is
+> available.
+
+## Node Alarm frame
+
+Identifiers **1-255**: a real-time alarm from the node whose ID equals the frame
+identifier. These are the highest-priority messages on the bus -- use them for
+millisecond-critical notifications (e.g. coordinating a fly-by-wire failover),
+**not** for annunciating a low oil pressure to the pilot.
+
+| Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7 |
+|---|---|---|---|---|---|---|---|
+| Alarm Code LSB | Alarm Code MSB | Data LSB | Data | Data | Data | Data | Data MSB |
+
+The 16-bit alarm code and the six data bytes are **not** defined by the
+specification -- their meaning is left to the implementer.
+
+## Node-Specific frame
+
+Identifiers **1760-2015**: configuration and management messages. The sender's
+Node ID is implied by the identifier:
+
+```
+Node ID = Frame ID - 1760
+```
+
+| Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7 |
+|---|---|---|---|---|---|---|---|
+| Control Code | Data LSB | Data | Data | Data | Data | Data | Data MSB |
+
+For most of these, **Byte 1 is the destination node** (0 = broadcast to all).
+
+### Control codes
+
+| Code | Message | Mandatory | Responds to broadcast |
+|---|---|---|---|
+| 0 | Node Identification | Yes | Yes |
+| 1 | Bit Rate Set | Yes | Yes |
+| 2 | Node ID Set | Yes | No |
+| 3 | Disable Parameter | Yes | Yes |
+| 4 | Enable Parameter | Yes | No |
+| 5 | Node Report | Yes | Yes |
+| 6 | Node Status Information | No | N/A |
+| 7 | Update Firmware | No | No |
+| 8 | Two-Way Connection Request | No | No |
+| 9 | Node Configuration Set | No | No |
+| 10 | Node Configuration Query | No | No |
+| 11 | Node Description | No | No |
+| 12 - 19 | Parameter Set (8 codes cover index ranges 0-255) | No | N/A |
+| 20 - 127 | Reserved for future use | | |
+| 128 - 255 | User defined | No | |
+
+**Bit rates** (Bit Rate Set, byte 2): `1` = 125 kbps, `2` = 250 kbps,
+`3` = 500 kbps, `4` = 1 Mbps.
+
+See the [Frame Definitions chapter](https://billmallard.github.io/canfix-spec/framedef.html)
+for the per-message payloads (Node Identification response, Parameter Set bit
+layout, firmware/channel handshakes, etc.).
+
+---
+
+See also: **[Data Types](Data-Types)** · **[Parameter Quick-Reference](Parameter-Reference)** · **[Implementing a Node](Implementing-a-Node)**
diff --git a/wiki/Home.md b/wiki/Home.md
new file mode 100644
index 0000000..05d542e
--- /dev/null
+++ b/wiki/Home.md
@@ -0,0 +1,85 @@
+# CAN-FiX
+
+**CAN-FiX** is the CAN bus implementation of **FIX** (*Flight Information
+eXchange*), an open, vendor-neutral protocol family for exchanging data between
+aircraft avionics and flight systems. It is aimed at the Experimental Amateur
+Built (E-AB) community: the specification and protocols are released under a
+Creative Commons license, so anyone can build a device or write software that
+talks to other CAN-FiX equipment without paying for a license.
+
+This wiki is a **friendly companion** to the formal specification. It gives you
+quick-reference tables and a get-started guide. The **full, normative
+specification** -- the document that actually defines the protocol -- is
+published here:
+
+- **Specification (web):**
+- **Specification (PDF):** built by `make latexpdf` (see [Building the docs](#building-the-spec-yourself))
+- **Source repository:**
+
+> If the wiki and the specification ever disagree, **the specification wins.**
+> The wiki is generated/curated from the same source and is meant for speed of
+> lookup, not as the authority.
+
+## Start here
+
+| If you want to... | Go to |
+|---|---|
+| Understand what CAN-FiX is and why | [Introduction chapter](https://billmallard.github.io/canfix-spec/intro.html) |
+| Look up a parameter (ID, units, range) | **[Parameter Quick-Reference](Parameter-Reference)** |
+| Decode or build a CAN frame | **[Frame Format](Frame-Format)** |
+| Know how a value is encoded on the wire | **[Data Types](Data-Types)** |
+| Build your own CAN-FiX node | **[Implementing a Node](Implementing-a-Node)** |
+| Read the complete, normative text | [Full specification](https://billmallard.github.io/canfix-spec/) |
+
+## What CAN-FiX is in one minute
+
+A CAN-FiX network is made of **nodes**, each with a unique **Node ID** (1-255;
+0 is the broadcast address). The normal pattern is *producer / consumer*: a node
+that measures something (airspeed, altitude, engine data, GPS position) puts that
+value on the bus, and any other node that cares (a display, a recorder, an
+autopilot) reads it. No node addresses another to receive data -- data is simply
+produced for all to consume.
+
+CAN-FiX is built on CAN 2.0B but uses only the **base frame format** (an 11-bit
+identifier), giving 2048 message types. The identifier *is* the priority: lower
+ID wins arbitration, so the most critical data (node alarms, pilot control
+inputs) sits at the low end of the ID space and is delivered first. The
+[Frame Format](Frame-Format) page shows how that ID space is divided up.
+
+Beyond live data, the protocol also defines node configuration, identification,
+firmware update, and point-to-point parameter setting -- see
+[Implementing a Node](Implementing-a-Node).
+
+## About this fork
+
+This is **[billmallard/canfix-spec](https://github.com/billmallard/canfix-spec)**,
+a fork of the MakerPlane CAN-FiX specification, maintained and published under
+the project's open-source license. The web specification and this wiki are built
+and kept current from this fork. The master copy of the parameter data is the
+spreadsheet `src/CAN-FIX.ods`; everything else (the JSON/XML exports, the
+parameter list, this wiki's quick-reference) is **generated** from it.
+
+## Building the spec yourself
+
+The HTML and PDF are produced with [Sphinx](https://www.sphinx-doc.org/). From
+the repository:
+
+```bash
+cd src
+pip install sphinx pyexcel pyexcel-ods # one-time
+python canfix_json.py # regenerate canfix.json from the .ods
+python canfix_xml.py # regenerate canfix.xml
+python parameters.py # regenerate parameter_list.rst
+make html # -> src/_build/html
+make latexpdf # -> src/_build/latex (needs LaTeX)
+```
+
+The web spec at the link above is rebuilt automatically by GitHub Actions on
+every push to `master`. The [Parameter Quick-Reference](Parameter-Reference) in
+this wiki is regenerated by `tools/gen_param_reference.py`.
+
+---
+
+*CAN is a registered trademark of Robert Bosch GmbH. CAN-FiX and the FIX
+protocols are licensed under Creative Commons -- see the
+[License chapter](https://billmallard.github.io/canfix-spec/license.html).*
diff --git a/wiki/Implementing-a-Node.md b/wiki/Implementing-a-Node.md
new file mode 100644
index 0000000..354b50e
--- /dev/null
+++ b/wiki/Implementing-a-Node.md
@@ -0,0 +1,82 @@
+# Implementing a Node
+
+A practical get-started checklist for building a CAN-FiX node. It summarizes the
+specification; the binding rules are in the
+[Requirements](https://billmallard.github.io/canfix-spec/requirements.html) and
+[Best Practices](https://billmallard.github.io/canfix-spec/practices.html)
+chapters, with frame details in
+[Frame Definitions](https://billmallard.github.io/canfix-spec/framedef.html).
+
+## 1. Pick a Node ID and bit rate
+
+- Choose a **Node ID** in **1-255**, unique on the network (0 is the broadcast
+ address, never a real node).
+- Use the **CAN 2.0B base frame** (11-bit identifier) only.
+- Default to a network **bit rate** the installation agrees on -- the protocol
+ defines `125k / 250k / 500k / 1M` and a [Bit Rate Set](Frame-Format#control-codes)
+ message to change it.
+- Read the bus as you transmit (standard CAN arbitration); a lower identifier
+ always wins, so your most critical parameters belong at lower IDs.
+
+## 2. Produce your parameters
+
+For each thing your node measures:
+
+1. Find (or choose) its parameter ID in the
+ [Parameter Quick-Reference](Parameter-Reference). The **frame ID is the
+ parameter ID**.
+2. Build the [Normal Data frame](Frame-Format#normal-data-frame):
+ - Byte 0 = your Node ID
+ - Byte 1 = Index (0 if the parameter is not indexed)
+ - Byte 2 = Function Code (0 for a good-quality value)
+ - Bytes 3-7 = the value, **little-endian**, in the parameter's
+ [data type](Data-Types) (`raw = engineering / multiplier`)
+3. Transmit it periodically. Send only what your node is responsible for.
+
+**Quality matters.** When a reading is suspect or failed, set the **Quality** or
+**Failure** bit in the Function Code rather than sending a silently-wrong value.
+Set **Annunciate** when a value crosses an alarm threshold. See
+[the Function/Status code](Frame-Format#function--status-code-byte).
+
+**Send your meta data.** If a parameter has alarm set points or ranges (e.g. oil
+pressure limits, V-speeds), the *measuring* node should transmit them as meta data
+(Function Code meta-data bits 1-15) so every display stays consistent without
+separate configuration. This is a core design principle of CAN-FiX.
+
+## 3. Handle the mandatory node-specific messages
+
+Every node **must** respond to these [control codes](Frame-Format#control-codes)
+(Node-Specific frames, ID = `1760 + your Node ID`):
+
+| Code | Message | What your node must do |
+|---|---|---|
+| 0 | Node Identification | Reply with the spec revision you implement (`0x01` for this spec); optionally follow with a [Node Description](https://billmallard.github.io/canfix-spec/framedef.html#node-description) string |
+| 1 | Bit Rate Set | Change CAN bit rate immediately and permanently |
+| 2 | Node ID Set | Change your Node ID, then announce success on the new ID |
+| 3 | Disable Parameter | Stop broadcasting the named parameter |
+| 4 | Enable Parameter | Resume broadcasting the named parameter |
+| 5 | Node Report | Immediately send every parameter you own, plus its meta data |
+
+Optional messages (firmware update, two-way channels, node configuration,
+node status, point-to-point Parameter Set) are described in the
+[Frame Definitions chapter](https://billmallard.github.io/canfix-spec/framedef.html).
+
+## 4. Consume what you need
+
+To use data from the bus, just listen for the relevant parameter IDs and decode
+per [Data Types](Data-Types). Respect the **Quality / Failure** flags -- fall
+back to an alternate source when set. Remember that **one parameter should have
+one producer**: if two nodes broadcast the same parameter they will conflict, so
+use Disable/Enable Parameter (or a Node Report at startup) to resolve duplicates.
+
+## Reference implementations
+
+- **C / Arduino:** the [can-fix-arduinolib](https://github.com/makerplane/can-fix-arduinolib)
+ library implements the node-specific protocol and parameter framing.
+- **Python:** the [python-canfix](https://github.com/birkelbach/python-canfix)
+ package (and MakerPlane's FIX-Gateway, which bridges CAN-FiX to other
+ transports) are useful references for decode/encode.
+
+---
+
+See also: **[Frame Format](Frame-Format)** · **[Data Types](Data-Types)** · **[Parameter Quick-Reference](Parameter-Reference)**
diff --git a/wiki/Parameter-Reference.md b/wiki/Parameter-Reference.md
new file mode 100644
index 0000000..009f782
--- /dev/null
+++ b/wiki/Parameter-Reference.md
@@ -0,0 +1,306 @@
+# Parameter Quick-Reference
+
+Every CAN-FiX parameter (protocol version **0.7**), grouped by CAN identifier range. This page is generated from [`src/canfix.json`](https://github.com/billmallard/canfix-spec/blob/master/src/canfix.json), which is built from the master spreadsheet `src/CAN-FIX.ods` -- so it always matches the specification.
+
+For the full normative definitions (data encodings, frame formats, meta data and bit fields) see the [complete specification](https://billmallard.github.io/canfix-spec/), in particular the [Parameters chapter](https://billmallard.github.io/canfix-spec/parameters.html).
+
+**Reading this table**
+
+- **ID** -- the 11-bit CAN frame identifier. A range (e.g. `256-257`) means the parameter occupies several consecutive IDs for multiple instances.
+- **Type** -- the [data type](https://billmallard.github.io/canfix-spec/datatypes.html) of the value (see also [Data Types](Data-Types)).
+- **Units / Range / Mult** -- engineering units, min/max, and the multiplier (the value each least-significant bit represents).
+- **Notes** -- the index dimension (for indexed parameters), the data format, and any per-parameter remarks.
+
+## High Priority Pilot Control Inputs (256-319)
+
+| ID | Parameter | Type | Units | Range | Mult | Notes |
+|---|---|---|---|---|---|---|
+| 256-257 | Flap Control Switches | BYTE | | | | Discrete Bits; b0 = Up; b1 = Down; b2 - b7 Can be used for predefined notches |
+| 258-259 | Trim Switches | WORD | | | | Discrete Bits; b0 = Pitch Up; b1 = Pitch Down; b2 = Pitch Center; b3 = Roll Left; b4 = Roll Right; b5 = Roll Center; b6 = Yaw Left; b7 = Yaw Right; b8 = Yaw Center; b9 = Collective Up; b10 = Collective Dn; b11 = AT Pedals Left; b12 = AT Pedals Right; b13 = AT Pedals Center |
+| 260-261 | Electrical Bus Control Switches | BYTE | | | | Discrete Bits |
+| 262-263 | Lighting Control Switches | BYTE | | | | Discrete Bits |
+| 264-265 | Fuel Pump System Switches | BYTE | | | | Discrete Bits |
+| 266-267 | Fuel Valve System Switches | BYTE | | | | Discrete Bits |
+| 268-269 | Auto Pilot Commands | WORD | | | | Discrete Bits; b0 = Engage; b1 = Disconnect; b2 = VS Mode; b3 = Alt Hold Mode; b4 = Alt Select Mode; b5 = Heading Increment; b6 = Heading Decrement |
+| 270-271 | VHF Control Commands | BYTE | | | | Indexed by Radio; Discrete Bits; b0 = PTT; b1 = Flip; b2 = Next Saved Freq; b3 = Prev Saved Freq |
+| 272-273 | VOR/LOC Control Commands | BYTE | | | | Indexed by Radio; Discrete Bits; b1 = Flip; b2 = Next Saved Freq; b3 = Prev Saved Freq |
+| 274-275 | Transponder Commands | BYTE | | | | Discrete Bits; b0 = IDENT; b1 = ALT; b2 = STBY; b3 = VFR; b4 = OFF; b5 = Squat |
+| 276-277 | Starter / Magneto Commands | BYTE | | | | Discrete Bits |
+| 278-279 | Landing Gear Control Position | BYTE | | | | Discrete Bits; 0=Down; 1=Up; b0=Nose; b1=Left; b2=Right |
+| 280-281 | Keypad Input | CHAR[2] | | | | Key, Function Key |
+| 282-283 | Encoder Input (High Priority) | INT[2],BYTE | | | | Indexed by Unit; Steps Moved; X,Y and Switch Positions; Less than 0 = CCW, Greater than 0 = CW |
+| 284-291 | Generic Switches (High Priority) | BYTE[5] | | | | Indexed by Unit; Discrete Bits; User Defined For Multiplexing Switches |
+| 292 | Pitch Control Position | INT | % | -100 to 100 | 0.01 | Greater Than 0 = Nose Up |
+| 293 | Roll Control Position | INT | % | -100 to 100 | 0.01 | Greater Than 0 = Right |
+| 294 | Yaw Control Position | INT | % | -100 to 100 | 0.01 | Greater Than 0 = Right |
+| 295 | Collective Control Position | INT | % | -100 to 100 | 0.01 | Greater Than 0 = Up |
+| 296 | Anti-Torque Pedals Position | INT | % | -100 to 100 | 0.01 | Greater Than 0 = Right |
+| 297 | Flap Control Position | INT | % | -100 to 100 | 0.01 | Greater Than 0 = Down |
+| 298 | Left Brake Control Position | UINT | % | 0 to 100 | 0.01 | |
+| 299 | Right Brake Control Position | UINT | % | 0 to 100 | 0.01 | |
+| 300-301 | Engine Throttle Control Position | UINT | % | 0 to 100 | 0.01 | |
+| 302-303 | Engine Prop Control Position | UINT | % | 0 to 100 | 0.01 | |
+| 304-305 | Engine Mixture Control Position | UINT | % | 0 to 100 | 0.01 | |
+| 306-307 | Generic Analog Control (High Priority) | UINT | % | 0 to 100 | 0.01 | Indexed by Unit; User Defined |
+
+## High Priority Measured Positions (320-383)
+
+| ID | Parameter | Type | Units | Range | Mult | Notes |
+|---|---|---|---|---|---|---|
+| 320 | Elevator Position | INT | ° | -90 to 90 | 0.01 | Greater Than 0 = Nose Up |
+| 321 | Aileron Position | INT | ° | -90 to 90 | 0.01 | Greater Than 0 = Right |
+| 322 | Rudder Position | INT | ° | -90 to 90 | 0.01 | Greater Than 0 = Right |
+| 323 | Collective Position | INT | ° | -90 to 90 | 0.01 | Greater Than 0 = Up |
+| 324 | Tail Rotor Angle | INT | ° | -90 to 90 | 0.01 | Greater Than 0 = Right |
+| 325 | Flap Position | INT | ° | -90 to 90 | 0.01 | Greater Than 0 = Down |
+| 326-328 | Landing Gear Position Switches | BYTE | | | | Discrete Bits; b0=Nose Up; b1=Nose Down; b2=Left Up; b3=Left Down; b4=Right Up; b5=Right Down |
+
+## High Priority Flight Data (384-447)
+
+| ID | Parameter | Type | Units | Range | Mult | Notes |
+|---|---|---|---|---|---|---|
+| 384 | Pitch Angle | INT | ° | -90 to 90 | 0.01 | Greater Than 0 = Nose Up |
+| 385 | Roll Angle | INT | ° | -180 to 180 | 0.01 | Greater Than 0 = Right |
+| 386 | Angle of Attack | INT | ° | -90 to 90 | 0.01 | |
+| 387 | Indicated Airspeed | UINT | knots | 0 to 999.9 | 0.1 | |
+| 388 | Indicated Altitude | DINT | ft | -1000 to 60,000 | | |
+| 389 | Heading | UINT | ° | 0 to 359.9 | 0.1 | Magnetic Heading |
+| 390 | Vertical Speed | INT | ft/min | -30,000 to 30,000 | | |
+| 391 | TE Variometer Vertical Speed | INT | knots | -300 to 300 | 0.01 | |
+| 392 | Radar Altitude | UINT | ft | 0 to 60,000 | | |
+| 393 | Yaw Angle | INT | ° | -180 to 180 | 0.01 | |
+| 394 | Normal Acceleration | INT | g | -30 to 30 | 0.001 | |
+| 395 | Lateral Acceleration | INT | g | -30 to 30 | 0.001 | |
+| 396 | Longitudinal Acceleration | INT | g | -30 to 30 | 0.001 | |
+| 397 | True Airspeed | UINT | knots | 0 to 999.9 | 0.1 | |
+| 398 | Calibrated Airspeed | UINT | knots | 0 to 999.9 | 0.1 | |
+| 399 | Mach Number | UINT | Mach | 0 to 100 | 0.01 | |
+| 400 | Altimeter Setting | UINT | inHg | 0 to 35 | 0.001 | |
+| 401 | Pressure Altitude | DINT | ft | -1,000 to 60,000 | | |
+
+## High Priority Navigation Data (448-511)
+
+| ID | Parameter | Type | Units | Range | Mult | Notes |
+|---|---|---|---|---|---|---|
+| 448 | VOR/LOC Deviation | UINT | ° | 0 to 359.9 | 0.1 | |
+| 449 | Glideslope Deviation | INT | ° | -45 to 45 | 0.01 | |
+| 450 | OBI Flags | WORD | | | | b0 = To/From (To = 1); b1:b2 = Input (00=NAV1, 01=NAV2, 10=GPS1, 11=GPS2); b3 = GS; b4 = LOC/NAV |
+| 451 | Aircraft Position Latitude | FLOAT | ° | -90 to 90 | | |
+| 452 | Aircraft Position Longitude | FLOAT | ° | -180 to 180 | | |
+| 453 | Groundspeed | UINT | knots | 0 to 2000 | 0.1 | |
+| 454 | True Ground Track | UINT | ° | 0 to 359.9 | 0.1 | |
+| 455 | Magnetic Ground Track | UINT | ° | 0 to 359.9 | 0.1 | |
+| 456 | Cross Track Error | INT | nm | | 0.01 | |
+| 457 | Selected Course | UINT | ° | 0 to 359.9 | 0.1 | |
+| 458 | Selected Glidepath Angle | UINT | ° | 0 to 90 | 0.1 | |
+| 459 | Selected Vertical Speed | INT | ft/min | -30,000 to 30,000 | | |
+| 460 | Selected Airspeed | UINT | knots | 0 to 999.9 | 0.1 | |
+| 461 | Selected Altitude | DINT | ft | -1000 to 60,000 | | |
+| 462 | RAIM Status | USHORT | | | | 0 if Good; Otherwise the ID of the most likely failed satellite |
+| 463 | RAIM Horizontal Error | UINT | ft | | | |
+| 464 | RAIM Vertical Error | UINT | ft | | | |
+| 465 | ADS-B ES Airborne Position Latitude | FLOAT | ° | -90 to 90 | | Indexed by Aircraft |
+| 466 | ADS-B ES Airborne Position Longitude | FLOAT | ° | -180 to 180 | | Indexed by Aircraft |
+| 467 | ADS-B ES Airborne Position Altitude | DINT | ft | -1000 to 60,000 | | Indexed by Aircraft |
+| 468 | ADS-B ES Surface Position Latitude | FLOAT | ° | -90 to 90 | | Indexed by Aircraft |
+| 469 | ADS-B ES Surface Position Longitude | FLOAT | ° | -180 to 180 | | Indexed by Aircraft |
+| 470 | ADS-B ES Surface Position Altitude | DINT | ft | -1000 to 60,000 | | Indexed by Aircraft |
+| 471 | ADS-B ES Status | | | | | Indexed by Aircraft |
+| 472 | ADS-B ES Identification | | | | | Indexed by Aircraft |
+| 473 | ADS-B ES Type | | | | | Indexed by Aircraft |
+| 474 | ADS-B ES Airborne Velocity | UINT | knots | 0 to 2000 | 0.1 | Indexed by Aircraft |
+| 475 | ADS-B ES Airborne Bearing | UINT | ° | 0 to 359.9 | 0.1 | Indexed by Aircraft |
+| 476 | ADS-B ES Airborne Rate of Climb | INT | ft/min | -30,000 to 30,000 | | Indexed by Aircraft |
+| 477 | ADS-B ES Emergency Priority Status | | | | | Indexed by Aircraft; Event Driven Information |
+| 478 | ADS-B ES Current Trajectory Change Point | | | | | Indexed by Aircraft; Event Driven Information |
+| 479 | ADS-B ES Next Trajectory Change Point | | | | | Indexed by Aircraft; Event Driven Information |
+| 480 | ADS-B ES Operation Coord. Message | | | | | Indexed by Aircraft; Event Driven Information |
+| 481 | ADS-B ES Operational Status | | | | | Indexed by Aircraft; Event Driven Information |
+
+## High Priority Engine / Aircraft System Data (512-639)
+
+| ID | Parameter | Type | Units | Range | Mult | Notes |
+|---|---|---|---|---|---|---|
+| 512-513 | N1 or Engine RPM | UINT | RPM | | | N1 for Turbines |
+| 514-515 | N2, Prop RPM or Rotor RPM | UINT | RPM | | | N2 for Turbines |
+| 516-517 | Torque | INT | | | | |
+| 518-519 | Turbine Inlet Temperature | UINT | °C | | 0.1 | |
+| 520-521 | Inter-turbine Temperature | UINT | °C | | 0.1 | |
+| 522-523 | Turbine Outlet Temperature | UINT | °C | | 0.1 | |
+| 524-525 | Fuel Pressure Switch | SHORT | | | | 0 = Normal; -1 = Low; 1 = High |
+| 526-527 | Oil Pressure Switch | SHORT | | | | 0 = Normal; -1 = Low; 1 = High |
+| 528-529 | Oil Temperature Switch | SHORT | | | | 0 = Normal; -1 = Low; 1 = High |
+| 530-531 | Coolant Temperature Switch | SHORT | | | | 0 = Normal; -1 = Low; 1 = High |
+| 532-533 | Fuel Quantity Switch | SHORT | | | | 0 = Normal; -1 = Low; 1 = High |
+| 534-535 | Oil Quantity Switch | SHORT | | | | 0 = Normal; -1 = Low; 1 = High |
+| 536-537 | Coolant Quantity Switch | SHORT | | | | 0 = Normal; -1 = Low; 1 = High |
+| 538-539 | Fuel Flow | UINT | gal/hr | | 0.01 | |
+| 540-541 | Fuel Pressure | UINT | psi | | 0.01 | |
+| 542-543 | Manifold Pressure | UINT | inHg | | 0.01 | |
+| 544-545 | Oil Pressure | UINT | psi | | 0.01 | |
+| 546-547 | Oil Temperature | UINT | °C | | 0.1 | |
+| 548-549 | Coolant Temperature | UINT | °C | | 0.1 | |
+| 550-553 | Fuel Quantity | UINT | gal | | 0.01 | Indexed by Aux Tank |
+| 554-555 | Fuel Pump Pressure | UINT | psi | | 0.01 | |
+| 556-557 | Oil Quantity | UINT | gal | | 0.01 | |
+| 558-559 | Coolant Quantity | UINT | gal | | 0.01 | |
+| 560-561 | Electric Propulsion Motor Current | UINT | A | | | |
+| 562-563 | Main Propulsion Bus Voltage | UINT | V | | 0.1 | |
+| 564-565 | Main Battery Current | INT | A | | | |
+| 566-567 | Main Battery Temperature | UINT | °C | | 0.1 | |
+| 568-569 | Main Battery Charge | UINT | % | 0 to 100 | 0.1 | |
+| 570-571 | Hybrid System Status | WORD | | | | |
+| 572-573 | Upper Deck Pressure | UINT | inHg | | 0.01 | |
+
+## High Priority Auxiliary Data (640-767)
+
+| ID | Parameter | Type | Units | Range | Mult | Notes |
+|---|---|---|---|---|---|---|
+| 640 | Cabin Pressure | UINT | inHg | 0 to 35 | 0.001 | |
+| 641 | Cabin Altitude | INT | ft | -1,000 to 30,000 | | |
+
+## Normal Priority Pilot Control Inputs (768-895)
+
+| ID | Parameter | Type | Units | Range | Mult | Notes |
+|---|---|---|---|---|---|---|
+| 768-775 | Encoder Input | INT[2],BYTE | | | | Indexed by Unit; Steps Moved; X,Y and Switch Positions; Less than 0 = CCW, Greater than 0 = CW |
+| 776-783 | Generic Switches | BYTE[5] | | | | Indexed by Unit; Discrete Bits; User Defined For Multiplexing Switches |
+| 784 | Speedbrake Control Position | UINT | % | 0 to 100 | 0.01 | |
+| 785 | Cowl Flaps Control Position | UINT | % | 0 to 100 | 0.01 | |
+| 786 | Pitch Trim Control Position | INT | % | -100 to 100 | 0.01 | |
+| 787 | Roll Trim Control Position | INT | % | -100 to 100 | 0.01 | |
+| 788 | Yaw Trim Control Position | INT | % | -100 to 100 | 0.01 | |
+| 789 | Collective Trim Control Position | INT | % | -100 to 100 | 0.01 | |
+| 790 | Anti-Torque Pedals Trim Position | INT | % | -100 to 100 | 0.01 | |
+| 791-798 | Generic Analog Control | UINT | % | 0 to 100 | 0.01 | Indexed by Unit; User Defined |
+
+## Normal Priority Measured Positions (896-1023)
+
+| ID | Parameter | Type | Units | Range | Mult | Notes |
+|---|---|---|---|---|---|---|
+| 896 | Speedbrake Position | INT | ° | -90 to 90 | 0.01 | Less than 0 = Down; Greater than 0 = Up |
+| 897 | Cowl Flaps Position | UINT | % | 0 to 100 | 0.01 | 100% = Open |
+| 898 | Pitch Trim Position | INT | ° | -90 to 90 | 0.01 | Less than 0 = Down; Greater than 0 = Up |
+| 899 | Roll Trim Position | INT | ° | -90 to 90 | 0.01 | Less than 0 = Left; Greater than 0 = Right |
+| 900 | Yaw Trim Position | INT | ° | -90 to 90 | 0.01 | Less than 0 = Left; Greater than 0 = Right |
+| 901 | Pitch Trim Motor Speed | INT | % | -100 to 100 | 0.01 | Less than 0 = Down; Greater than 0 = Up |
+| 902 | Roll Trim Motor Speed | INT | % | -100 to 100 | 0.01 | Less than 0 = Left; Greater than 0 = Right |
+| 903 | Yaw Trim Motor Speed | INT | % | -100 to 100 | 0.01 | Less than 0 = Left; Greater than 0 = Right |
+| 904 | Collective Trim Motor Speed | INT | % | -100 to 100 | 0.01 | Less than 0 = Down; Greater than 0 = Up |
+| 905 | Anti-Torque Pedals Trim Motor Speed | INT | % | -100 to 100 | 0.01 | Less than 0 = Left; Greater than 0 = Right |
+| 906 | Light Status | BYTE | | | | Discrete Bits |
+| 907-910 | Fuel Pump Status | BYTE | | | | Discrete Bits |
+| 911 | Fuel Valve Status | BYTE | | | | Discrete Bits |
+| 912-919 | Generic Analog Measurement | UINT | % | 0 to 100 | 0.01 | Indexed by Unit; User Defined |
+
+## Normal Priority Flight Data (1024-1151)
+
+| ID | Parameter | Type | Units | Range | Mult | Notes |
+|---|---|---|---|---|---|---|
+| 1024 | Pitch Rate | INT | °/sec | -3000 to 3000 | 0.1 | Less than 0 = Down; Greater than 0 = Up |
+| 1025 | Roll Rate | INT | °/sec | -3000 to 3000 | 0.1 | Less than 0 = Left; Greater than 0 = Right |
+| 1026 | Yaw Rate | INT | °/sec | -3000 to 3000 | 0.1 | Less than 0 = Left; Greater than 0 = Right |
+| 1027 | Turn Rate | INT | °/sec | -3000 to 3000 | 0.1 | Less than 0 = Left; Greater than 0 = Right |
+| 1028 | Static Pressure | UINT | inHg | | 0.001 | |
+| 1029 | Pitot Pressure | UINT | inHg | | 0.001 | |
+| 1030 | Total Air Temperature | INT | °C | -300 to 300 | 0.01 | |
+| 1031 | Static Air Temperature | INT | °C | -300 to 300 | 0.01 | |
+| 1032 | Density Altitude | DINT | ft | -1,000 to 60,000 | | |
+| 1033 | True Altitude | DINT | ft | -1,000 to 60,000 | | |
+| 1034 | GPS Altitude | DINT | ft | -1,000 to 60,000 | | |
+| 1035 | Wind Speed | UINT | knots | 0 to 2000 | 0.1 | |
+| 1036 | Wind Direction | UINT | ° | 0 to 360 | 0.01 | Magnetic |
+
+## Normal Priority Navigation Data (1152-1279)
+
+| ID | Parameter | Type | Units | Range | Mult | Notes |
+|---|---|---|---|---|---|---|
+| 1152 | Next Waypoint Identifier | CHAR[5] | | | | |
+| 1153 | Next Waypoint Latitude | FLOAT | ° | -90 to 90 | | |
+| 1154 | Next Waypoint Longitude | FLOAT | ° | -180 to 180 | | |
+| 1155 | Next Waypoint Altitude | DINT | ft | -1000 to 60,000 | | |
+| 1156 | Next Waypoint ETA | USHORT[3] | UTC | | | Hour, Min, Sec |
+| 1157 | Next Waypoint ETE | USHORT[3] | | | | Hour, Min, Sec |
+| 1158 | Waypoint Identifier | CHAR[5] | | | | Indexed by Waypoint |
+| 1159 | Waypoint Latitude | FLOAT | ° | -90 to 90 | | Indexed by Waypoint |
+| 1160 | Waypoint Longitude | FLOAT | ° | -180 to 180 | | Indexed by Waypoint |
+| 1161 | Waypoint Altitude | DINT | ft | -1000 to 60,000 | | Indexed by Waypoint |
+| 1162 | Waypoint ETA | USHORT[3] | UTC | | | Indexed by Waypoint; Hour, Min, Sec |
+| 1163 | Waypoint ETE | USHORT[3] | | | | Indexed by Waypoint; Hour, Min, Sec |
+| 1164 | Waypoint, Distance To | UINT | nm | | | Indexed by Waypoint |
+| 1165 | Waypoint Minimum Altitude | DINT | ft | -1000 to 60,000 | | Indexed by Waypoint |
+| 1166 | Waypoint Minimum Flight Level | UINT | | | | Indexed by Waypoint |
+| 1167 | Waypoint Minimum Radar Level | UINT | | | | Indexed by Waypoint |
+| 1168 | Waypoint Maximum Altitude | DINT | ft | -1000 to 60,000 | | Indexed by Waypoint |
+| 1169 | Waypoint Maximum Flight Level | UINT | | | | Indexed by Waypoint |
+| 1170 | Waypoint Maximum Radar Level | UINT | | | | Indexed by Waypoint |
+| 1171 | Waypoint Planned Altitude | DINT | ft | -1000 to 60,000 | | Indexed by Waypoint |
+| 1172 | Waypoint Reserved | | | | | Indexed by Waypoint |
+| 1173 | Destination Identifier | CHAR[5] | | | | |
+| 1174 | Destination Latitude | FLOAT | ° | -90 to 90 | | |
+| 1175 | Destination Longitude | FLOAT | ° | -180 to 180 | | |
+| 1176 | Destination Altitude | DINT | ft | -1000 to 60,000 | | |
+| 1177 | Destination ETA | USHORT[3] | UTC | | | Hour, Min, Sec |
+| 1178 | Destination ETE | USHORT[3] | | | | Hour, Min, Sec |
+| 1179 | Track Error Angle | | ° | | | |
+| 1180-1215 | Reserved | | | | | |
+| 1216-1219 | VHF Com Frequency | UINT | MHz | | 0.01 | Indexed by 0=Current, 1=Standby, >1 = Memory Locations |
+| 1220-1223 | VOR/ILS Frequency | UINT | ° | 0 to 359 | | Indexed by 0=Current, 1=Standby, >1 = Memory Locations |
+| 1224-1227 | VOR/ILS Identifier | CHAR[5] | | | | |
+| 1228-1231 | Actual VOR Radial | UINT | ° | 0 to 359.9 | 0.1 | |
+| 1232-1235 | Selected VOR Radial | UINT | ° | 0 to 359.9 | 0.1 | |
+| 1236 | Transponder Code | USHORT[4] | | | | |
+| 1240 | Auto Pilot / FD Mode | WORD | | | | Indexed by 0=AP Mode, 1=Horizontal Mode, 2=Vertical Mode, 255=Status |
+
+## Normal Priority Engine / Aircraft System Data (1280-1407)
+
+| ID | Parameter | Type | Units | Range | Mult | Notes |
+|---|---|---|---|---|---|---|
+| 1280-1281 | Cylinder Head Temperature | UINT | °C | | 0.1 | Indexed by Cylinder |
+| 1282-1283 | Exhaust Gas Temperature | UINT | °C | | 0.1 | Indexed by Cylinder |
+| 1284-1285 | Cylinder Head Temp. Rate of Change | UINT | °C/Min | | 0.1 | Indexed by Cylinder |
+| 1286-1287 | Cylinder Head Temp. Deviation | UINT | °C | | 0.1 | |
+| 1288-1289 | Exhaust Gas Temp. Rate of Change | UINT | °C/Min | | 0.1 | Indexed by Cylinder |
+| 1290-1291 | Exhaust Gas Temp. Deviation | UINT | °C | | 0.1 | |
+| 1292-1293 | Carburetor Temperature | UINT | °C | | 0.1 | |
+| 1294-1297 | Electrical Bus Voltage | UINT | V | | 0.1 | |
+| 1298-1301 | Electrical Bus Current | UINT | A | | 0.1 | |
+| 1302-1305 | Generator / Alternator Voltage | UINT | V | | 0.1 | |
+| 1306-1309 | Generator / Alternator Current | UINT | A | | 0.1 | |
+| 1310-1311 | Engine Power | UINT | % | | 0.1 | |
+| 1312-1313 | Total Engine Time | UINT | Hours | | 0.1 | Indexed by Flight; Index 0 = Total, 1 = last flight, reverse chronological order from there |
+| 1314-1315 | Total Engine Time (Tach) | UINT | Hours | | 0.1 | Indexed by Flight; Index 0 = Total, 1 = last flight, reverse chronological order from there |
+| 1316-1317 | Gearbox Speed | UINT | RPM | | | |
+| 1318-1319 | Gearbox Oil Pressure Switch | BYTE | | | | 0 = Normal; -1 = Low; 1 = High |
+| 1320-1321 | Gearbox Oil Temperature Switch | BYTE | | | | 0 = Normal; -1 = Low; 1 = High |
+| 1322-1323 | Gearbox Oil Quantity Switch | BYTE | | | | 0 = Normal; -1 = Low; 1 = High |
+| 1324-1325 | Hydraulic Pressure Switch | BYTE | | | | 0 = Normal; -1 = Low; 1 = High |
+| 1326-1327 | Hydraulic Temperature Switch | BYTE | | | | 0 = Normal; -1 = Low; 1 = High |
+| 1328-1329 | Hydraulic Fluid Quantity Switch | BYTE | | | | 0 = Normal; -1 = Low; 1 = High |
+| 1330-1331 | Gearbox Oil Pressure | UINT | psi | | 0.01 | |
+| 1332-1333 | Gearbox Oil Temperature | UINT | °C | | 0.1 | |
+| 1334-1335 | Gearbox Oil Quantity | UINT | % | 0 to 100 | 0.01 | |
+| 1336-1337 | Hydraulic Pressure | UINT | psi | | 0.01 | |
+| 1338-1339 | Hydraulic Temperature | UINT | °C | | 0.1 | |
+| 1340-1341 | Hydraulic Fluid Quantity | UINT | % | 0 to 100 | 0.01 | |
+| 1342-1345 | Tire Pressure | UINT | psi | | 0.01 | |
+| 1346-1349 | Strut Pressure | UINT | psi | | 0.01 | |
+| 1350 | Flight Time | UINT | Hours | | 0.1 | Indexed by Flight; Index 0 = last flight, reverse chronological order from there |
+
+## Normal Priority Auxiliary Data (1408-1535)
+
+| ID | Parameter | Type | Units | Range | Mult | Notes |
+|---|---|---|---|---|---|---|
+| 1408 | Time | USHORT[3],UINT | UTC | | | Hour, Min, Sec, mSec |
+| 1409 | Date | UINT,USHORT[2] | | | | Year, Month, Day |
+| 1410 | Time Zone | SHORT | Hours | -12 to 12 | 0.1 | |
+| 1411 | Cabin Temperature | UINT | °C | | 0.1 | |
+| 1412 | Panel Dimmer Level | USHORT | % | 0 to 100 | | |
+| 1413 | Longitudinal Center of Gravity | UINT | %MAC | 0 to 100 | 0.1 | |
+| 1414 | Lateral Center of Gravity | INT | % | -100 to 100 | 0.1 | |
+| 1415 | Aircraft Identifier | CHAR[5] | | | | |
+| 1416 | Aircraft Type | CHAR[5] | | | | |
+
+---
+
+_230 parameters across 12 groups. Generated by `tools/gen_param_reference.py` from `src/canfix.json` (version 0.7). Do not edit by hand -- edit the master spreadsheet and regenerate._
diff --git a/wiki/_Footer.md b/wiki/_Footer.md
new file mode 100644
index 0000000..a44acbc
--- /dev/null
+++ b/wiki/_Footer.md
@@ -0,0 +1,4 @@
+[CAN-FiX specification](https://billmallard.github.io/canfix-spec/) ·
+[Repository](https://github.com/billmallard/canfix-spec) ·
+Wiki quick-references are generated/curated from `src/CAN-FIX.ods` -- the
+specification is authoritative.
diff --git a/wiki/_Sidebar.md b/wiki/_Sidebar.md
new file mode 100644
index 0000000..11458c0
--- /dev/null
+++ b/wiki/_Sidebar.md
@@ -0,0 +1,20 @@
+### CAN-FiX Wiki
+
+- [Home](Home)
+- [Parameter Quick-Reference](Parameter-Reference)
+- [Frame Format](Frame-Format)
+- [Data Types](Data-Types)
+- [Implementing a Node](Implementing-a-Node)
+- [Background: CANaerospace](Background-CANaerospace)
+
+### Full specification
+
+- [Specification (web)](https://billmallard.github.io/canfix-spec/)
+- [Introduction](https://billmallard.github.io/canfix-spec/intro.html)
+- [Frame Definitions](https://billmallard.github.io/canfix-spec/framedef.html)
+- [Parameters](https://billmallard.github.io/canfix-spec/parameters.html)
+- [License](https://billmallard.github.io/canfix-spec/license.html)
+
+### Project
+
+- [Repository](https://github.com/billmallard/canfix-spec)