Release 1.1.0 uses protocol v2, a 450 MHz core and fixed 1 MHz
rates on both ADCs and GPIO. Select 8 or 16 GPIO inputs; other acquisition
rates are rejected. See the current wire contract.
Build identity, validation and limits are in the
v1.1.0 release report.
The optional equal-frame TimestampAligner is not supported for this new
profile; acquisition blocks provide exact per-sample timestamps.
The Python SDK's combined ADC + 16-GPIO path is not qualified as lossless on the remote test server's 0.5-core CPU quota: runs reported USB queue loss and, in one case, parser rejections. The independent wire validator sustains that firmware mode; the SDK errors and faster-host throughput need further qualification. Strict loss detection remains enabled—no missing data is silently accepted.
ThingDAQ (Thing Done DAQ) is firmware and a typed Python API for synchronized, loss-visible acquisition on the Teensy 4.0 platform. It captures two phase-shifted ADC channels and either eight or sixteen packed digital inputs. The same public API runs against a deterministic in-memory simulator, so discovery, configuration, parsing, timestamps, calibration, alignment, loss handling, and cleanup can be developed without hardware.
Warning
Read the hardware-safety guide before connecting a signal. A0/A1, D6-D13 and D16-D23 are 3.3 V inputs and are not 5 V tolerant. Host calibration does not add electrical protection.
| Input | Physical schedule | Python representation |
|---|---|---|
| ADC0 on A0/D14 | 1 MS/s, nominal ticks 0, 8, 16, ... |
unchanged 12-bit raw codes |
| ADC1 on A1/D15 | 1 MS/s, nominally 500 ns after ADC0 | unchanged 12-bit raw codes |
| GPIO D6-D13, optionally D16-D23 | 1 MS/s packed snapshots | 8-bit or little-endian 16-bit samples |
The timestamp domain is an unsigned, START-relative 8 MHz clock. Explicit ADC
interleaving yields the nominal order ADC0[0], ADC1[0], ADC0[1], ADC1[1], ....
That 2 MS/s view does not increase the analog bandwidth of the converters,
pins, source, or front end.
For application integration, install thingdone-daq from PyPI and import
thingdone_daq:
python -m pip install thingdone-daqFor development from this checkout:
python3 -m venv .venv
.venv/bin/python -m pip install --editable './daq_api[dev,numpy]'Run the complete deterministic demo or a bounded CLI capture:
.venv/bin/thingdone-daq-demo --frames 2
.venv/bin/thingdone-daq capture --simulate --duration 1 --strict-loss \
--gpio-channel D6 --gpio-channel D13Run the autonomous experiment baseline from a clean checkout. This exercises the historical simulator profile and invokes the firmware builder without uploading it, and writes validated JSON and structured Markdown:
.venv/bin/python firmware/tools/baseline_prototype.py \
--output-dir doc/results/experimentsThe baseline's simulator command-latency fields use a deterministic logical clock so normalized reports are reproducible. They are simulator bookkeeping, not host, live-USB, or target timing evidence.
Run the isolated auxiliary-input workload matrix entirely offline:
.venv/bin/python daq_api/examples/aux_input_matrix.py
.venv/bin/python daq_api/examples/aux_input_matrix.py \
--output .maestro/aux-input-demoThe optional output prefix writes temporary shared-schema JSON and structured Markdown. The printed 12 MB/s full-combined payload and protocol-framed byte rates are analytic load hypotheses, not physical USB acceptance. The validated two-run simulator/host result is retained in the auxiliary-input prototype evidence. The subsequent target campaign and its reproducible pre-START DMA failure are recorded in the final auxiliary-input report.
All examples default to the simulator. A script touches hardware only when
--real is present:
.venv/bin/python daq_api/examples/raw_adc_channels.py
.venv/bin/python daq_api/examples/combined_alignment.py
.venv/bin/python daq_api/examples/status_and_loss.pySee the quickstart for the complete example roster, physical discovery by hardware serial, and lifecycle guidance.
from thingdone_daq import ADCBlock, GPIOBlock, Source, ThingDAQ
with ThingDAQ.simulated(strict=True) as daq:
applied = daq.configure(
adc=True,
gpio=True,
source=Source.SYNTHETIC,
adc_pair_rate_hz=1_000_000,
gpio_sample_rate_hz=4_000_000,
adc_resolution_bits=12,
)
run_id = daq.start()
for item in daq.blocks(2):
if isinstance(item, ADCBlock):
print(run_id, item.adc0[0], item.adc1[0])
elif isinstance(item, GPIOBlock):
print(item.sample(0), item.channel(6)[0])
daq.validate_stream_health()
daq.stop()configure() checks the exact stream/source profile, checksum, and optional
rate/resolution requirements against synchronized INFO capabilities before it
sends CONFIGURE. The returned DAQConfiguration is the device's exact applied
echo; a changed CONFIGURE or START echo is rejected.
Metadata-only enumeration never opens candidate ports:
.venv/bin/thingdone-daq list
.venv/bin/thingdone-daq info --hardware-serial 20512460
.venv/bin/thingdone-daq monitor --hardware-serial 20512460 \
--streams both --source hardware --duration 10 --strict-lossUse the stable fuse-derived INFO serial instead of assuming a COM or /dev
path remains attached to the same unit. The client re-probes identity when it
opens the selected endpoint, and context-manager exit attempts bounded STOP
before deterministic reader/transport shutdown.
The recorded pre-rename Teensy 4.0 campaigns include a 60-second combined physical run at the nominal ADC/GPIO rates with zero complete-frame or payload loss, deliberate host-stall loss/recovery checks, malformed-control recovery, repeated lifecycle cycles, and CDC close/reopen recovery. Exact historical evidence is in Phase 08 and Phase 09. The reproducible package matrix and final byte-matched real-device workflow are recorded in the Phase 10 local gate and Phase 10 physical workflow.
The historical autonomous release-candidate gate added two 10-minute synthetic runs, three 10-minute physical-combined runs, and one 10-minute alternating control-stress run on one immutable pre-rename artifact. The six-job decision, complete exclusion lineage, conservation equations, fixture limits, and post-campaign reproducibility gate are in the Phase 11 soak evidence and the cross-phase evidence index. The prepared Phase 12 Windows handoff for that artifact is now historical and superseded.
The historical ThingDAQ firmware 1.0.0 candidate had a byte-identical two-build freeze,
generated validators, and passing local software/build gates. Because the USB
identity, firmware build ID, host namespace, and packaging identity changed,
the earlier physical results are engineering history rather than release
acceptance for the renamed binary. Physical acceptance was pending at that
historical freeze; use the v1.1.0 release report for current qualification.
The identity-pinned standalone and installed thingdone-daq-soak entry paths are
documented in the soak harness guide. Both embed
the deterministic firmware/soak/validation-manifest.json contract; a
different INFO identity is rejected unless the explicit diagnostic override is
used, and override reports are always non-release.
The superseded artifacts, exact hashes, local packaging results, diagnostic
fixture smoke, and report interpretation for the earlier candidate remain in
the Phase 12 Windows handoff. Use
the current soak harness guide—not those historical hashes—for a new run.
Those runs used unstimulated A0/A1 and no declared external digital stimulus. They do not establish analog accuracy, analog bandwidth, true aperture timing, external GPIO transition timing, or compatibility with a particular customer front end. The distinction between tested and untested claims is maintained in the hardware-safety guide.
- Documentation index
- Evidence index
- Phase 11 autonomous soak evidence
- Phase 12 Windows validation handoff
- Quickstart
- Autonomous soak harness
- Python API architecture
- Python API reference
- Hardware safety
- Calibration
- Optional NumPy integration
- Current protocol v2
- Historical protocol v1
- System overview
- Phase 10 package workflow evidence
firmware/: Teensy 4.0 sketch, portable C++ components, build tooling, and host-compiled firmware tests.daq_api/: installablethingdone_daqpackage, CLI, simulator, examples, and Python tests.protocol/: canonical machine-readable contract and cross-language golden frames.doc/: structured architecture, guide, reference, decision, and evidence artifacts.
Common local gates:
.venv/bin/python tools/generate_protocol.py --check
.venv/bin/python -m ruff format --check daq_api firmware tools
.venv/bin/python -m ruff check daq_api firmware tools
.venv/bin/python -m mypy daq_api/src/thingdone_daq
.venv/bin/python -m pytest
python3 firmware/tools/build_firmware.pyThe Python distribution is thingdone-daq; the import package is
thingdone_daq. See the Python package README and
Python changelog. Firmware, protocol, and Python SDK
versions are independent. Other language SDKs can share protocol/ and its
golden fixtures; the SDK documentation plan
describes language-specific documentation boundaries.
ThingDAQ is an independent project and is not affiliated with or endorsed by PJRC.COM, LLC or SparkFun Electronics. Teensy® is a registered trademark of PJRC.COM, LLC. References to Teensy identify the supported hardware platform; they are not part of the ThingDAQ product name.
This project is available under the MIT License. Copyright (c) 2026 THING DONE LLC.