Skip to content

Latest commit

 

History

262 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ThingDAQ

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.

Supported acquisition

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.

Start without hardware

For application integration, install thingdone-daq from PyPI and import thingdone_daq:

python -m pip install thingdone-daq

For 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 D13

Run 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/experiments

The 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-demo

The 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.py

See the quickstart for the complete example roster, physical discovery by hardware serial, and lifecycle guidance.

Minimal API

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.

Hardware use

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-loss

Use 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.

Validation scope

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 map

Repository layout and checks

  • firmware/: Teensy 4.0 sketch, portable C++ components, build tooling, and host-compiled firmware tests.
  • daq_api/: installable thingdone_daq package, 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.py

Distribution and trademark boundary

The 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.

License

This project is available under the MIT License. Copyright (c) 2026 THING DONE LLC.

About

ThingDAQ (Thing Done DAQ): synchronized, loss-visible data acquisition for Teensy 4.0 hardware.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages