Skip to content

Re-arch: typed devices + hardware CI + ADRV9371/AD9081/FMCDAQ3 coverage#56

Merged
tfcollins merged 20 commits intomainfrom
tfcollins/re-arch
Apr 20, 2026
Merged

Re-arch: typed devices + hardware CI + ADRV9371/AD9081/FMCDAQ3 coverage#56
tfcollins merged 20 commits intomainfrom
tfcollins/re-arch

Conversation

@tfcollins
Copy link
Copy Markdown
Collaborator

@tfcollins tfcollins commented Apr 18, 2026

Summary

Coalesces the tfcollins/re-arch branch's 55 iterative commits into a 12-commit deliverable. Three threads:

  1. Typed device model + hw test infrastructure. Replace the legacy board/parts/template layers with the typed adidt.devices model and add a board pytest fixture that drives labgrid in either coordinator or direct mode from a single env-var set (LG_COORDINATOR / LG_ENV).

  2. New hardware coverage. End-to-end hw tests for ADRV9371+ZC706 (System API + XSA pipeline), AD9081+ZCU102 (XSA pipeline), and FMCDAQ3+VCU118 (coordinator BootFabric / JTAG). File-based kernel-image cache keyed on the sha256 of the pyadi-build YAML config.

  3. Hardware CI workflow. New Hardware Tests GitHub Actions workflow fanning out over a declarative .github/hw-nodes.json manifest. Preflight on the coordinator host, hw-direct and hw-coord matrix legs on per-node self-hosted runners, uv-managed venvs, private-dep PAT plumbing, artifact uploads (DTS / DTB / dmesg / UART logs), pre-emptive cold-cycle + one-shot retry in BootFPGASoC to eliminate the silent-first-power-on flake, and board power-off on test teardown. Fork-PR protection via GitHub's built-in workflow approval gate (no custom environment:).

Test plan

  • Full unit suite passes locally (36 passed, 2 skipped on the device-model tests; 597 passed in the full test tree — one pre-existing, unrelated SVG dark-mode failure).
  • 25 parametrized local DTS-parity checks (test/devices/test_system_ad9081_dts_parity.py) pin the System API's emission against the committed XSA-reference DTS fixture.
  • 14 consecutive green Hardware Tests workflow runs on the final SHAs:
    • preflight (ubuntu-latest via hw-coordinator self-hosted) 3–4 s
    • hw-direct (bq) 70–73 s (full ADRV9371+ZC706 XSA pipeline + boot + IIO)
    • hw-coord (bq) 75–80 s
    • hw-coord (mini2) 238–250 s (AD9081+ZCU102 XSA + System API, both green)
    • hw-coord (nuc) 272–281 s (FMCDAQ3+VCU118 BootFabric)
    • hw-direct (mini2), hw-direct (nuc) skip cleanly (no LG_DIRECT_ENV on those runners yet)

Commit layout

Twelve commits, each a self-contained, reviewable unit:

  1. feat: coordinator + direct-mode hardware test infrastructure
  2. feat: ADRV9371 + ZC706 support via System API and XSA pipeline
  3. feat: cache built kernel images across test runs
  4. test: AD9081 + ZCU102 XSA pipeline hardware test + DT corrections
  5. test: FMCDAQ3 + VCU118 coordinator hw test (BootFabric / JTAG)
  6. doc: add Authoring a new device class developer guide
  7. ci: add Hardware Tests workflow + manifest + runner registration helper
  8. ci: preflight + adidt venv plumbing for self-hosted hw runners
  9. ci: hw-coord on per-node runners, labgrid acquire/release, Vivado source
  10. fix(system): AD9081 DT emission — dev_clk + pll2 + per-side JESD modes
  11. fix(ad9081): mode-table + HMC7044 dividers + CI artifact + local-DTS parity
  12. test(hw): power boards off on teardown; doc the CI behaviour

Dependencies

  • adi-labgrid-plugins fork (tfcollins/labgrid-plugins) ships the BootFPGASoC cold-cycle + retry additions used here. Upstream-compatible; the strategy attrs are all opt-in defaults.
  • pyadi-build is private — CI pulls it through a repo-scoped PYADI_BUILD_TOKEN secret configured in the workflow's install step.

Out of scope

  • Authoring the node-local direct-mode YAMLs for mini2 / nuc (lab owner; hw-direct legs skip cleanly until they land).
  • Adding boards that don't yet have a coordinator place (FMCOMMS8, VCU118+AD9084, etc. — each is a one-entry manifest edit when its exporter + runner come online).
  • Moving the labgrid-plugins fork's fixes upstream to mainline labgrid-plugins (separate PR, separate repo).

See doc/source/developer/hardware_ci.rst for the full operator manual (runner registration, LG_DIRECT_ENV convention, PAT setup, troubleshooting, artifact recipes, local DT-parity-test flow).

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 18, 2026

ADI Binding Audit Report

  • Source: /tmp/linux
  • Generated: 2026-04-20T17:37:28+00:00
Metric Value
Total bindings 197
Total compatibles 1167
Known bindings 0
Partially known bindings 0
Undocumented bindings 197
Undocumented compatible entries 1167
Generated templates 0
Skipped existing templates 0
Not generated templates 0

Undocumented bindings

Binding Undocumented compatibles
adi,axi-clkgen.yaml adi,axi-clkgen-2.00.a, adi,axi-clkgen.yaml, adi,zynqmp-axi-clkgen-2.00.a
altr,c5-fpll.yaml adi,extended-name, adi,fractional-carry-bit
clk-ad9545.yaml adi,ad9545, adi,aux-dpll-bw-mhz, adi,compensation-source, adi,current-source-microamp, adi,freq-lock-threshold-ps, adi,output-mode, adi,phase-lock-threshold-ps, adi,pin-nr, adi,pll-loop-bandwidth-uhz, adi,pll-source, adi,profile-priority, adi,r-divider-ratio, adi,ref-crystal, adi,ref-dtol-pbb, adi,ref-frequency-hz, adi,ref-monitor-hysteresis-pbb, adi,ref-validation-timer-ms
adi,adv7511.yaml adi,adv7511, adi,adv7511.yaml, adi,adv7511w, adi,adv7513, adi,input-clock, adi,input-colorspace, adi,input-depth, adi,input-justification, adi,input-style
adi,adv7533.yaml adi,adv7533, adi,adv7533.yaml, adi,adv7535, adi,dsi-lanes
simple-bridge.yaml adi,adv7123
adi,axi-dmac.txt adi,axi-dmac.txt
adi,ds4520-gpio.yaml adi,ds4520-gpio, adi,ds4520-gpio.yaml
adi,ad741x.yaml adi,ad7416, adi,ad7417, adi,ad7418, adi,ad741x.yaml
adi,adm1177.yaml adi,adm1177, adi,adm1177.yaml, adi,shutdown-threshold-microamp, adi,vrange-high-enable
adi,adm1266.yaml adi,adm1266, adi,adm1266.yaml
adi,adm1275.yaml adi,adm1075, adi,adm1272, adi,adm1273, adi,adm1275, adi,adm1275.yaml, adi,adm1276, adi,adm1278, adi,adm1281, adi,adm1293, adi,adm1294, adi,power-sample-average, adi,volt-curr-sample-average
adi,axi-fan-control.yaml adi,axi-fan-control-1.00.a, adi,axi-fan-control.yaml
adi,ltc2945.yaml adi,ltc2945, adi,ltc2945.yaml
adi,ltc2947.yaml adi,accumulator-ctl-pol, adi,gpio-out-pol., adi,ltc2947, adi,ltc2947.yaml
adi,ltc2991.yaml adi,ltc2991, adi,ltc2991.yaml, adi,temperature-enable
adi,ltc2992.yaml adi,ltc2992, adi,ltc2992.yaml
adi,ltc4282.yaml adi,gpio1-mode, adi,gpio2-mode, adi,gpio3-monitor-enable, adi,ltc4282, adi,ltc4282.yaml, adi,rsense-nano-ohms
adi,max31760.yaml adi,max31760, adi,max31760.yaml
adi,max31827.yaml adi,alarm-pol, adi,comp-int, adi,fault-q, adi,max31827, adi,max31827.yaml, adi,max31828, adi,max31829, adi,timeout-enable
adt7475.yaml adi,adt7473, adi,adt7475, adi,adt7475., adi,adt7476, adi,adt7490, adi,adt7490., adi,bypass-attenuator-in0, adi,bypass-attenuator-in1, adi,pin10-function, adi,pin14-function
jedec,jc42.yaml adi,adt7408
lltc,ltc4286.yaml adi,vrange-low-enable
lm75.yaml adi,adt75
national,lm90.yaml adi,adm1032, adi,adt7461, adi,adt7461a, adi,adt7481
adi,adp1050.yaml adi,adp1050, adi,adp1050.yaml, adi,adp1051, adi,adp1055, adi,ltp8800
adi,lt3074.yaml adi,lt3074, adi,lt3074.yaml
adi,max17616.yaml adi,max17616, adi,max17616.yaml
i2c-demux-pinctrl.yaml adi,adv7180, adi,adv7511w, adi,input-clock, adi,input-colorspace, adi,input-depth
adi,adis16201.yaml adi,adis16201, adi,adis16201.yaml, adi,adis16209
adi,adis16240.yaml adi,adis16240, adi,adis16240.yaml
adi,adxl313.yaml adi,adxl312, adi,adxl313, adi,adxl313.yaml, adi,adxl314
adi,adxl345.yaml adi,adxl345, adi,adxl345.yaml, adi,adxl346, adi,adxl375
adi,adxl355.yaml adi,adxl355, adi,adxl355.yaml, adi,adxl359
adi,adxl367.yaml adi,adxl367, adi,adxl367.yaml
adi,adxl372.yaml adi,adxl372, adi,adxl372.yaml
adi,adxl380.yaml adi,adxl380, adi,adxl380.yaml, adi,adxl382
ad7091r5.txt adi,ad7091r5
adi,ad4000.yaml adi,ad4000, adi,ad4000.yaml, adi,ad4001, adi,ad4002, adi,ad4003, adi,ad4004, adi,ad4005, adi,ad4006, adi,ad4007, adi,ad4008, adi,ad4010, adi,ad4011, adi,ad4020, adi,ad4021, adi,ad4022, adi,ad7685, adi,ad7686, adi,ad7687, adi,ad7688, adi,ad7690, adi,ad7691, adi,ad7693, adi,ad7942, adi,ad7946, adi,ad7980, adi,ad7982, adi,ad7983, adi,ad7984, adi,ad7988-1, adi,ad7988-5, adi,adaq4001, adi,adaq4003, adi,gain-milli, adi,high-z-input, adi,sdi-pin
adi,ad4030.yaml adi,ad4030-24, adi,ad4030.yaml, adi,ad4032-24, adi,ad4630-16, adi,ad4630-24, adi,ad4632-16, adi,ad4632-24
adi,ad4062.yaml adi,ad4060, adi,ad4062, adi,ad4062.yaml
adi,ad4130.yaml adi,ad4130, adi,ad4130.yaml, adi,excitation-pin-0, adi,excitation-pin-1, adi,reference-select
adi,ad4134-spi-engine.yaml adi,ad4134-spi-engine, adi,ad4134-spi-engine.yaml
adi,ad4134.yaml adi,ad4134, adi,ad4134.yaml, adi,spi-engine
adi,ad4170-4.yaml adi,ad4170-4, adi,ad4170-4.yaml, adi,ad4190-4, adi,ad4195-4, adi,excitation-ac, adi,excitation-current-0-microamp, adi,excitation-current-1-microamp, adi,excitation-current-2-microamp, adi,excitation-current-3-microamp, adi,excitation-pin-0, adi,excitation-pin-1, adi,excitation-pin-2, adi,excitation-pin-3, adi,negative-reference-buffer, adi,positive-reference-buffer, adi,reference-select, adi,sensor-type, adi,vbias-pins
adi,ad4630.yaml adi,ad4030-24, adi,ad4032-24, adi,ad4630-16, adi,ad4630-20, adi,ad4630-24, adi,ad4630.yaml, adi,ad4632-16, adi,ad4632-20, adi,ad4632-24, adi,ad463x, adi,adaq4216, adi,adaq4220, adi,adaq4224, adi,clock-mode, adi,dual-data-rate, adi,lane-mode, adi,out-data-mode, adi,pga-gpios, adi,spi-trigger
adi,ad4695.yaml adi,ad4695, adi,ad4695.h, adi,ad4695.h., adi,ad4695.yaml, adi,ad4696, adi,ad4697, adi,ad4698
adi,ad7091r5.yaml adi,ad7091r2, adi,ad7091r4, adi,ad7091r5, adi,ad7091r5.yaml, adi,ad7091r8
adi,ad7124.yaml adi,ad7124-4, adi,ad7124-8, adi,ad7124.yaml, adi,buffered-negative, adi,buffered-positive, adi,reference-select
adi,ad7173.yaml adi,ad4111, adi,ad4112, adi,ad4114, adi,ad4115, adi,ad4116, adi,ad7172-2, adi,ad7172-4, adi,ad7173-8, adi,ad7173.yaml, adi,ad7175-2, adi,ad7175-8, adi,ad7176-2, adi,ad7177-2, adi,current-channel, adi,reference-select
adi,ad7191.yaml adi,ad7191, adi,ad7191.yaml, adi,odr-value, adi,pga-value
adi,ad7192.yaml adi,ad7190, adi,ad7192, adi,ad7192.yaml, adi,ad7193, adi,ad7194, adi,ad7195, adi,buffer-enable, adi,burnout-currents-enable, adi,refin2-pins-enable, adi,rejection-60-hz-enable
adi,ad7280a.yaml adi,acquisition-time-ns, adi,ad7280a, adi,ad7280a.yaml, adi,thermistor-termination, adi,voltage-alert-last-chan
adi,ad7291.yaml adi,ad7291, adi,ad7291.yaml
adi,ad7292.yaml adi,ad7292, adi,ad7292.yaml
adi,ad7298.yaml adi,ad7298, adi,ad7298.yaml
adi,ad7380.yaml adi,ad7380, adi,ad7380-4, adi,ad7380.yaml, adi,ad7381, adi,ad7381-4, adi,ad7383, adi,ad7383-4, adi,ad7384, adi,ad7384-4, adi,ad7386, adi,ad7386-4, adi,ad7387, adi,ad7387-4, adi,ad7388, adi,ad7388-4, adi,ad7389-4, adi,adaq4370-4, adi,adaq4380-4, adi,adaq4381-4, adi,gain-milli
adi,ad7476.yaml adi,ad7091, adi,ad7091r, adi,ad7273, adi,ad7274, adi,ad7276, adi,ad7277, adi,ad7278, adi,ad7466, adi,ad7467, adi,ad7468, adi,ad7475, adi,ad7476, adi,ad7476.yaml, adi,ad7476a, adi,ad7477, adi,ad7477a, adi,ad7478, adi,ad7478a, adi,ad7495, adi,ad7910, adi,ad7920, adi,ad7940
adi,ad7606.yaml adi,ad7605-4, adi,ad7606-4, adi,ad7606-6, adi,ad7606-8, adi,ad7606.yaml, adi,ad7606b, adi,ad7616, adi,conversion-start-gpios, adi,first-data-gpios, adi,oversampling-ratio-gpios
adi,ad7625.yaml adi,ad7625, adi,ad7625.yaml, adi,ad7626, adi,ad7960, adi,ad7961
adi,ad7768-1.yaml adi,ad7768-1, adi,ad7768-1.yaml, adi,sync-in-gpios
adi,ad7768.yaml adi,ad7768, adi,ad7768-4, adi,ad7768.yaml, adi,data-lines
adi,ad7780.yaml adi,ad7170, adi,ad7171, adi,ad7780, adi,ad7780.yaml, adi,ad7781, adi,filter-gpios, adi,gain-gpios
adi,ad7923.yaml adi,ad7904, adi,ad7908, adi,ad7914, adi,ad7918, adi,ad7923, adi,ad7923.yaml, adi,ad7924, adi,ad7927, adi,ad7928
adi,ad7944.yaml adi,ad7944, adi,ad7944.yaml, adi,ad7985, adi,ad7986, adi,always-turbo, adi,spi-mode
adi,ad7949.yaml adi,ad7682, adi,ad7689, adi,ad7949, adi,ad7949.yaml, adi,internal-ref-microvolt
adi,ad799x.yaml adi,ad7991, adi,ad7992, adi,ad7993, adi,ad7994, adi,ad7995, adi,ad7997, adi,ad7998, adi,ad7999, adi,ad799x.yaml
adi,ad9081.yaml adi,ad9081, adi,ad9081.h, adi,ad9081.yaml, adi,ad9082, adi,ad9177, adi,ad9207, adi,ad9209, adi,ad9986, adi,ad9988, adi,adc-frequency-hz, adi,channelizer-paths, adi,channelizer-paths., adi,crossbar-select, adi,dac-frequency-hz, adi,decimation, adi,full-scale-current-ua, adi,gain, adi,interpolation, adi,jesd-links, adi,main-data-paths, adi,nco-frequency-shift-hz, adi,nco-mixer-mode, adi,nyquist-zone, adi,pa-protection-gpio-as-pa-enable, adi,pa-protection-long-avg-enable, adi,pa-protection-long-avg-threshold, adi,pa-protection-long-avg-time, adi,pa-protection-rotation-mode, adi,pa-protection-soft-off-enable, adi,pa-protection-soft-off-ramp-rate, adi,pa-protection-soft-off-triggers, adi,rx-adcs, adi,tx-dacs
adi,ad9083.yaml adi,ad9083, adi,ad9083.h, adi,ad9083.yaml, adi,backoff, adi,bits-per-sample, adi,cic_decimation, adi,control-bits-per-sample, adi,converter-resolution, adi,converters-per-device, adi,fc-hz, adi,finmax-hz, adi,frames-per-multiframe, adi,g_decimation, adi,h_decimation, adi,hp-en, adi,j_decimation, adi,lanes-per-device, adi,nco0_datapath_mode, adi,nco0_freq-hz, adi,nco1_freq-hz, adi,nco2_freq-hz, adi,octets-per-frame, adi,rterm-ohms, adi,subclass, adi,vmax-microvolt
adi,ad9208.txt adi,ad9208.txt
adi,ad9361.txt adi,ad9361.txt
adi,ad9467.yaml adi,ad9265, adi,ad9434, adi,ad9467, adi,ad9467.yaml, adi,ad9643, adi,ad9649, adi,ad9652
adi,adaq8092.yaml adi,adaq8092, adi,adaq8092.yaml
adi,adar1000.yaml adi,adar1000, adi,adar1000.yaml, adi,phasetable-name
adi,adrv903x.yaml adi,adrv9032, adi,adrv9032r, adi,adrv903x.yaml, adi,arm-firmware-name, adi,device-config-name, adi,rx-gaintable-channel-masks, adi,rx-gaintable-channel-masks., adi,rx-gaintable-names, adi,rx-gaintable-names., adi,stream-firmware-name
adi,axi-adc.yaml adi,axi-adc-10.0.a, adi,axi-adc.yaml
adi,axi-pulse-capture.yaml adi,axi-pulse-capture-1.00.a, adi,axi-pulse-capture.yaml
adi,ltc2308.yaml adi,ltc2308, adi,ltc2308.yaml
adi,ltc2358.yaml adi,ltc2353-16, adi,ltc2353-18, adi,ltc2357-16, adi,ltc2357-18, adi,ltc2358-16, adi,ltc2358-18, adi,ltc2358.yaml, adi,softspan-code
adi,ltc2471.yaml adi,ltc2461, adi,ltc2463, adi,ltc2471, adi,ltc2471.yaml, adi,ltc2473
adi,max11410.yaml adi,input-mode, adi,max11410, adi,max11410.yaml, adi,reference
adi,pulsar.yaml adi,pulsar, adi,pulsar,ad4003, adi,pulsar,ad4007, adi,pulsar,ad4011, adi,pulsar,ad4020, adi,pulsar,ad4021, adi,pulsar,ad4022, adi,pulsar,ad7682, adi,pulsar,ad7683, adi,pulsar,ad7684, adi,pulsar,ad7685, adi,pulsar,ad7686, adi,pulsar,ad7687, adi,pulsar,ad7688, adi,pulsar,ad7689, adi,pulsar,ad7690, adi,pulsar,ad7691, adi,pulsar,ad7693, adi,pulsar,ad7694, adi,pulsar,ad7699, adi,pulsar,ad7942, adi,pulsar,ad7946, adi,pulsar,ad7949, adi,pulsar,ad7980, adi,pulsar,ad7982, adi,pulsar,ad7983, adi,pulsar,ad7984, adi,pulsar,ad7988-1, adi,pulsar,ad7988-5, adi,pulsar,adaq4003, adi,pulsar.yaml, adi,single-channel, adi,temp-sensor
lltc,ltc2387.yaml adi,use-two-lanes
renesas,rcar-gyroadc.yaml adi,ad7476
adi,ad74115.yaml adi,ad74115.yaml, adi,ad74115h, adi,ch-func, adi,conv2-mux, adi,conv2-range-microvolt, adi,dac-bipolar, adi,digital-input-sink-range-high, adi,gpio0-mode, adi,gpio1-mode, adi,gpio2-mode, adi,gpio3-mode
adi,ad74413r.yaml adi,ad74412r, adi,ad74413r, adi,ad74413r.h, adi,ad74413r.yaml, adi,ch-func, adi,gpo-comparator
adi,one-bit-adc-dac.yaml adi,one-bit-adc-dac, adi,one-bit-adc-dac.yaml
ad916x-amp.yaml adi,ad9166-amp
adi,ad8366.yaml adi,ad8366, adi,ad8366.yaml, adi,ada4961, adi,adl5240, adi,adrf5702, adi,adrf5703, adi,adrf5720, adi,adrf5730, adi,adrf5731, adi,hmc1018a, adi,hmc1019a, adi,hmc1119, adi,hmc271a, adi,hmc792a
adi,ada4250.yaml adi,ada4250, adi,ada4250.yaml
adi,adl5580.yaml adi,adl5580, adi,adl5580.yaml, adi,ms-itrm, adi,ms-otrm, adi,prg-cpeak, adi,prg-itrm, adi,prg-otrm
adi,hmc425a.yaml adi,adrf5740, adi,hmc425a, adi,hmc425a.yaml, adi,hmc540s, adi,ltc6373
adi,adar300x.yaml adi,adar3000, adi,adar3001, adi,adar3002, adi,adar3003, adi,adar300x.yaml
adi,ad7150.yaml adi,ad7150, adi,ad7150.yaml, adi,ad7151, adi,ad7156
adi,ad7746.yaml adi,ad7745, adi,ad7746, adi,ad7746.yaml, adi,ad7747, adi,exca-output-en, adi,exca-output-invert, adi,excb-output-en, adi,excb-output-invert, adi,excitation-vdd-permille
adi,ad3530r.yaml adi,ad3530, adi,ad3530r, adi,ad3530r.yaml, adi,ad3531, adi,ad3531r
adi,ad3552r.yaml adi,ad3541r, adi,ad3542r, adi,ad3551r, adi,ad3552r, adi,ad3552r.yaml, adi,gain-offset, adi,gain-scaling-n, adi,gain-scaling-p, adi,output-range-microvolt, adi,rfb-ohms
adi,ad5064.yaml adi,ad5024, adi,ad5025, adi,ad5044, adi,ad5045, adi,ad5064, adi,ad5064-1, adi,ad5064.yaml, adi,ad5065, adi,ad5625, adi,ad5625r-1v25, adi,ad5625r-2v5, adi,ad5627, adi,ad5627r-1v25, adi,ad5627r-2v5, adi,ad5628-1, adi,ad5628-2, adi,ad5629-1, adi,ad5629-2, adi,ad5629-3, adi,ad5645r-1v25, adi,ad5645r-2v5, adi,ad5647r-1v25, adi,ad5647r-2v5, adi,ad5648-1, adi,ad5648-2, adi,ad5665, adi,ad5665r-1v25, adi,ad5665r-2v5, adi,ad5666-1, adi,ad5666-2, adi,ad5667, adi,ad5667r-1v25, adi,ad5667r-2v5, adi,ad5668-1, adi,ad5668-2, adi,ad5668-3, adi,ad5669-1, adi,ad5669-2, adi,ad5669-3
adi,ad5360.yaml adi,ad5360, adi,ad5360.yaml, adi,ad5361, adi,ad5363, adi,ad5370, adi,ad5371, adi,ad5372, adi,ad5373
adi,ad5380.yaml adi,ad5380-3, adi,ad5380-5, adi,ad5380.yaml, adi,ad5381-3, adi,ad5381-5, adi,ad5382-3, adi,ad5382-5, adi,ad5383-3, adi,ad5383-5, adi,ad5384-3, adi,ad5384-5, adi,ad5390-3, adi,ad5390-5, adi,ad5391-3, adi,ad5391-5, adi,ad5392-3, adi,ad5392-5
adi,ad5421.yaml adi,ad5421, adi,ad5421.yaml
adi,ad5449.yaml adi,ad5415, adi,ad5426, adi,ad5429, adi,ad5432, adi,ad5439, adi,ad5443, adi,ad5449, adi,ad5449.yaml
adi,ad5504.yaml adi,ad5501, adi,ad5504, adi,ad5504.yaml
adi,ad5592r.yaml adi,ad5592r, adi,ad5592r.h, adi,ad5592r.yaml, adi,ad5593r, adi,mode, adi,off-state
adi,ad5624r.yaml adi,ad5624r.yaml, adi,ad5624r3, adi,ad5624r5, adi,ad5644r3, adi,ad5644r5, adi,ad5664r3, adi,ad5664r5
adi,ad5686.yaml adi,ad5310r, adi,ad5672r, adi,ad5674r, adi,ad5676, adi,ad5676r, adi,ad5679r, adi,ad5681r, adi,ad5682r, adi,ad5683, adi,ad5683r, adi,ad5684, adi,ad5684r, adi,ad5685r, adi,ad5686, adi,ad5686.yaml, adi,ad5686r
adi,ad5696.yaml adi,ad5311r, adi,ad5337r, adi,ad5338r, adi,ad5671r, adi,ad5675r, adi,ad5691r, adi,ad5692r, adi,ad5693, adi,ad5693r, adi,ad5694, adi,ad5694r, adi,ad5695r, adi,ad5696, adi,ad5696.yaml, adi,ad5696r
adi,ad5755.yaml adi,ad5735, adi,ad5737, adi,ad5755, adi,ad5755-1, adi,ad5755.yaml, adi,ad5757, adi,dc-dc-freq-hz, adi,dc-dc-max-microvolt, adi,dc-dc-phase, adi,ext-current-sense-resistor, adi,mode, adi,slew
adi,ad5758.yaml adi,ad5758, adi,ad5758.yaml, adi,dc-dc-ilim-microamp, adi,dc-dc-mode, adi,range-microamp, adi,range-microvolt, adi,slew-time-us
adi,ad5761.yaml adi,ad5721, adi,ad5721r, adi,ad5761, adi,ad5761.yaml, adi,ad5761r
adi,ad5764.yaml adi,ad5744, adi,ad5744r, adi,ad5764, adi,ad5764.yaml, adi,ad5764r
adi,ad5766.yaml adi,ad5766, adi,ad5766.yaml, adi,ad5767
adi,ad5770r.yaml adi,ad5770r, adi,ad5770r.yaml, adi,external-resistor, adi,range-microamp
adi,ad5791.yaml adi,ad5760, adi,ad5780, adi,ad5781, adi,ad5790, adi,ad5791, adi,ad5791.yaml
adi,ad7293.yaml adi,ad7293, adi,ad7293.yaml
adi,ad7303.yaml adi,ad7303, adi,ad7303.yaml
adi,ad8460.yaml adi,ad8460, adi,ad8460.yaml, adi,external-resistor-ohms, adi,max-millicelsius, adi,range-microamp, adi,range-microvolt
adi,ad8801.yaml adi,ad8801, adi,ad8801.yaml, adi,ad8803
adi,ad9739a.yaml adi,ad9739a, adi,ad9739a.yaml
adi,axi-dac.yaml adi,ad3552r, adi,axi-ad3552r, adi,axi-dac-9.1.b, adi,axi-dac.yaml, adi,output-range-microvolt
adi,ltc2664.yaml adi,ltc2664, adi,ltc2664.yaml, adi,toggle-mode
adi,ltc2672.yaml adi,ltc2672, adi,ltc2672.yaml, adi,toggle-mode
adi,ltc2688.yaml adi,ltc2688, adi,ltc2688.yaml, adi,output-range-microvolt, adi,overrange, adi,toggle-dither-input, adi,toggle-mode
adi,max22007.yaml adi,ad74413r.h, adi,ch-func, adi,max22007, adi,max22007.yaml
adi,admv8818.yaml adi,admv8818, adi,admv8818.yaml
ad916x.yaml adi,ad9161, adi,ad9162, adi,ad9163, adi,ad9164, adi,ad9166, adi,bits-per-sample, adi,control-bits-per-sample, adi,converter-resolution, adi,converters-per-device, adi,frames-per-multiframe, adi,full-scale-current-mircoamp, adi,interpolation, adi,lanes-per-device, adi,octets-per-frame, adi,samples-per-converter-per-frame, adi,subclass, adi,version
adf4371.yaml adi,adf4371, adi,adf4372, adi,output-enable, adi,power-up-frequency
adi,ad9172.txt adi,ad9172.txt
adi,ad9783.yaml adi,ad9780, adi,ad9781, adi,ad9783, adi,ad9783.yaml
adi,adf4030.yaml adi,adf4030, adi,adf4030.yaml, adi,bsync-autoalign-iteration-count, adi,bsync-autoalign-reference-channel, adi,bsync-frequency-hz, adi,extended-name, adi,input-output-reconfig-en, adi,output-en, adi,rcm, adi,vco-frequency-hz
adi,adf4350.yaml adi,12bit-clkdiv-mode, adi,adf4350, adi,adf4350.yaml, adi,adf4351, adi,channel-spacing, adi,charge-pump-current, adi,mute-till-lock-enable, adi,output-power, adi,phase-detector-polarity-positive-enable, adi,power-up-frequency
adi,adf4360.yaml adi,adf4360-0, adi,adf4360-1, adi,adf4360-2, adi,adf4360-3, adi,adf4360-4, adi,adf4360-5, adi,adf4360-6, adi,adf4360-7, adi,adf4360-8, adi,adf4360-9, adi,adf4360.yaml, adi,loop-filter-charge-pump-current, adi,loop-filter-pfd-frequency-hz, adi,vco-maximum-frequency-hz, adi,vco-minimum-frequency-hz, adi,vco-minimum-frequency-hz.
adi,adf4377.yaml adi,adf4377, adi,adf4377.yaml, adi,adf4378
adi,adf4382.yaml adi,adf4382, adi,adf4382.yaml, adi,adf4382a, adi,charge-pump-microamp, adi,ref-divider
adi,adl5960.yaml adi,adl5960, adi,adl5960.yaml
adi,admfm2000.yaml adi,admfm2000, adi,admfm2000.yaml, adi,mixer-mode
adi,admv1013.yaml adi,admv1013, adi,admv1013.yaml, adi,detector-enable, adi,quad-se-mode
adi,admv1014.yaml adi,admv1014, adi,admv1014.yaml, adi,detector-enable, adi,p1db-compensation-enable, adi,quad-se-mode
adi,admv4420.yaml adi,admv4420, adi,admv4420.yaml, adi,lo-freq-khz, adi,ref-ext-single-ended-en
adi,adrf6780.yaml adi,adrf6780, adi,adrf6780.yaml, adi,lo-en
adi,ltc6952.yaml adi,analog-delay, adi,digital-delay, adi,divider, adi,extended-name, adi,ltc6952, adi,ltc6952.yaml, adi,ltc6953, adi,pulse-generator-mode, adi,ref-frequency-hz, adi,vco-frequency-hz
adi,adxrs290.yaml adi,adxrs290, adi,adxrs290.yaml
adi,ad5933.yaml adi,ad5933, adi,ad5933.yaml, adi,ad5934
adi,adis16460.yaml adi,adis16460, adi,adis16460.yaml
adi,adis16475.yaml adi,adis16465-1, adi,adis16465-2, adi,adis16465-3, adi,adis16467-1, adi,adis16467-2, adi,adis16467-3, adi,adis16470, adi,adis16475-1, adi,adis16475-2, adi,adis16475-3, adi,adis16475.yaml, adi,adis16477-1, adi,adis16477-2, adi,adis16477-3, adi,adis16500, adi,adis16501, adi,adis16505-1, adi,adis16505-2, adi,adis16505-3, adi,adis16507-1, adi,adis16507-2, adi,adis16507-3, adi,adis16575-2, adi,adis16575-3, adi,adis16576-2, adi,adis16576-3, adi,adis16577-2, adi,adis16577-3
adi,adis16480.yaml adi,adis16375, adi,adis16480, adi,adis16480.yaml, adi,adis16485, adi,adis16488, adi,adis16490, adi,adis16495-1, adi,adis16495-2, adi,adis16495-3, adi,adis16497-1, adi,adis16497-2, adi,adis16497-3, adi,adis16545-1, adi,adis16545-2, adi,adis16545-3, adi,adis16547-1, adi,adis16547-2, adi,adis16547-3, adi,ext-clk-pin
adi,adis16550.yaml adi,adis16550, adi,adis16550.yaml
adi,iio-fakedev.yaml adi,attribute-names, adi,faked-dev, adi,iio-fake-i2c-device, adi,iio-fake-platform-device, adi,iio-fake-spi-device, adi,iio-fakedev.yaml
adi,jesd204-rx.txt adi,jesd204-rx.txt
adi,jesd204-tx.txt adi,jesd204-tx.txt
adux1020.yaml adi,adux1020
iio-gen-mux.yaml adi,gen_mux
adi,ad5272.yaml adi,ad5272-020, adi,ad5272-050, adi,ad5272-100, adi,ad5272.yaml, adi,ad5274-020, adi,ad5274-100
adi,ad2s1210.yaml adi,ad2s1210, adi,ad2s1210.yaml, adi,fixed-mode
adi,ad2s90.yaml adi,ad2s90, adi,ad2s90.yaml
adi,ltc2983.yaml adi,cold-junction-handle, adi,custom-rtd, adi,custom-steinhart, adi,custom-temp, adi,custom-thermistor, adi,custom-thermocouple, adi,excitation-current-microamp, adi,ltc2983, adi,ltc2983.yaml, adi,ltc2984, adi,ltc2986, adi,ltm2985, adi,number-of-wires, adi,rsense-handle, adi,rsense-share, adi,rsense-val-milli-ohms, adi,sensor-oc-current-microamp, adi,sensor-type, adi,single-ended
adi,ad9088.yaml adi,ad9084, adi,ad9088, adi,ad9088.h, adi,ad9088.yaml, adi,axi-hsci-connected, adi,device-profile-fw-name, adi,gpio-hop-block, adi,gpio-hop-profile, adi,gpio-sniffer-a-export, adi,gpio-sniffer-b-export, adi,hsci-auto-linkup-mode-en, adi,hsci-disable-after-boot-en
adi,adp5588.yaml adi,adp5587, adi,adp5588, adi,adp5588.yaml
adi,ad7879.yaml adi,acquisition-time, adi,ad7879, adi,ad7879-1, adi,ad7879.yaml, adi,averaging, adi,conversion-interval, adi,first-conversion-delay, adi,median-filter-size, adi,resistance-plate-x
adi,adi-axi-fb.yaml adi,adi-axi-fb.yaml, adi,axi-framebuffer-1.00.a, adi,flock-distance, adi,flock-dwidth, adi,flock-frm-buf-nr, adi,flock-mode, adi,flock-resolution
adi,addi9036.yaml adi,addi9036, adi,addi9036.yaml
adv7180.yaml adi,adv7180, adi,adv7180cp, adi,adv7180st, adi,adv7182, adi,adv7280, adi,adv7280-m, adi,adv7281, adi,adv7281-m, adi,adv7281-ma, adi,adv7282, adi,adv7282-m
adv748x.yaml adi,adv7481, adi,adv7482
adv7604.yaml adi,adv7610, adi,adv7611, adi,adv7612
adi,adp5585.yaml adi,adp5585, adi,adp5585-00, adi,adp5585-01, adi,adp5585-02, adi,adp5585-03, adi,adp5585-04, adi,adp5585.yaml
adi,max77541.yaml adi,max77540, adi,max77541, adi,max77541-regulator.yaml, adi,max77541.yaml
adi,axi-data-offload.yaml adi,axi-data-offload-1.0.a, adi,axi-data-offload.yaml, adi,bringup, adi,bypass, adi,oneshot, adi,sync-config, adi,transfer-length
adi,axi-tdd.yaml adi,axi-tdd, adi,axi-tdd.yaml
adi,adg792a.txt adi,adg792a.txt
adi,adgs1408.txt adi,adgs1408.txt
mux-controller.yaml adi,adg792a
adi,adin.yaml adi,adin.yaml, adi,fifo-depth-bits, adi,rx-internal-delay-ps, adi,tx-internal-delay-ps
adi,adin1110.yaml adi,adin1110, adi,adin1110.yaml, adi,adin2111, adi,spi-crc
adi,axi-pwmgen.yaml adi,axi-pwmgen-2.00.a, adi,axi-pwmgen.yaml
adi,adp5055-regulator.yaml adi,adp5055, adi,adp5055-regulator.yaml, adi,delay-power-good, adi,dvs-limit-lower-microvolt, adi,dvs-limit-upper-microvolt, adi,fast-transient, adi,mask-power-good, adi,ocp-blanking, adi,tset-us
adi,max77503-regulator.yaml adi,max77503, adi,max77503-regulator.yaml
adi,max77541-regulator.yaml adi,max77541-regulator.yaml, adi,max77541.yaml
adi,max77857.yaml adi,max77831, adi,max77857, adi,max77857.yaml, adi,max77859, adi,max77859a, adi,rbot-ohms, adi,rtop-ohms
adi,max31335.yaml adi,max31331, adi,max31335, adi,max31335.yaml, adi,tc-diode
adi,adau1372.yaml adi,adau1372, adi,adau1372.yaml
adi,adau1701.txt adi,adau1701.txt
adi,adau17x1.yaml adi,adau1361, adi,adau1381, adi,adau1461, adi,adau1761, adi,adau1781, adi,adau17x1.yaml, adi,adau1961
adi,adau1977.yaml adi,adau1977, adi,adau1977.yaml, adi,adau1978, adi,adau1979, adi,micbias
adi,adau7002.yaml adi,adau7002, adi,adau7002.yaml
adi,adau7118.yaml adi,adau7118, adi,adau7118.yaml, adi,decimation-ratio, adi,pdm-clk-map
adi,axi-i2s.txt adi,axi-i2s.txt
adi,axi-spdif-tx.txt adi,axi-spdif-tx.txt
adi,max98363.yaml adi,max98363.yaml
adi,max98388.yaml adi,imon-slot-no, adi,interleave-mode, adi,max98388, adi,max98388.yaml, adi,vmon-slot-no
adi,max98396.yaml adi,imon-slot-no, adi,max98396, adi,max98396.yaml, adi,max98397, adi,vmon-slot-no
adi,ssm2305.txt adi,ssm2305.txt
adi,ssm2518.yaml adi,ssm2518, adi,ssm2518.yaml
adi,ssm2602.txt adi,ssm2602.txt
adi,ssm3515.yaml adi,ssm3515, adi,ssm3515.yaml
adi,axi-spi-engine.yaml adi,axi-spi-engine-1.00.a, adi,axi-spi-engine.yaml
adi-ex,axi-spi-engine.yaml adi,axi-spi-engine-1.00.a
trivial-devices.yaml adi,ad5110, adi,ad7414, adi,adp5589, adi,lt7182s

@tfcollins tfcollins changed the title Hardware CI: self-hosted runners + direct/coordinator workflow Re-arch: typed devices + hardware CI + ADRV9371/AD9081/FMCDAQ3 coverage Apr 19, 2026
Refactor the legacy board/parts/template layers into a typed device
model and add the plumbing for running hw tests through a labgrid
coordinator as well as the existing direct-mode (exporter-on-DUT)
path.

- ``adidt.devices.*`` typed device model replacing the old
  ``boards`` / ``parts`` / ``templates`` stack.
- ``test/hw/conftest.py`` that drives either connection mode from a
  single ``board`` fixture — labgrid picks the mode from
  ``LG_COORDINATOR`` (coordinator) or ``LG_ENV`` only (direct).
- ``pytest-dotenv`` so the mode vars can live in ``.env``; a
  ``.env.example`` template documents every knob.
- AD9081 and ADRV9009 hw test skip guards accept either
  ``LG_COORDINATOR`` or ``LG_ENV`` to enable the test.
- Design spec at ``doc/source/developer/`` capturing the
  coordinator-vs-direct architecture.
End-to-end ADRV9371-FMC on ZC706 coverage:

- ``adidt.fpga.zc706`` and ``adidt.eval.adrv937x_fmc`` device models.
- ``adidt.xsa.builders.adrv9009.ADRV937xBuilder`` for the XSA
  pipeline.  Unit tests + topology fixture exercise the builder.
- ``test/hw/test_adrv9371_zc706_hw.py`` drives real hardware via the
  declarative System API and the XSA pipeline (dual coverage).
- Fixes to the emitted DT overlays and the ZC706 GPIO label so the
  generated DTB actually boots the board.
- Developer-guide pages documenting the new builder + FPGA board,
  and the coordinator-mode hw flow.
Add a file-based kernel cache keyed by sha256 of the pyadi-build config
YAML so consecutive hw test runs skip the ``prepare_source`` + ``build``
cycle (typically ~8 minutes).  Wrap Zynq-7000 ``zImage`` output with
``mkimage`` so the cached filename matches what ``BootFPGASoCTFTP``'s
``tftpboot uImage`` expects.  Session-scope the ``built_kernel_image_*``
fixtures so the cached path is shared across all hw tests in one pytest
run.  Cache controls via env vars:

- ``ADIDT_KERNEL_CACHE=0`` forces a rebuild.
- ``ADIDT_KERNEL_CACHE_DIR`` relocates the cache (default
  ``~/.cache/adidt/kernel``).

Measured: ADRV9371+ZC706 hw test dropped from ~600s to ~70s on a cache
hit — the kernel build dominates the uncached runtime.
Real-hardware coverage for the XSA-pipeline path on ZCU102 + AD9081
and the DT-emission corrections the hardware exposed:

- ``test/hw/test_ad9081_zcu102_xsa_hw.py`` — XSA → sdtgen → merged
  DTS → DTB → boot → IIO + JESD204 link verification.
- HMC7044 PLL / SD-card / SPI wiring corrections for the
  AD9081-FMCA-EBZ + ZCU102 combination.
- AD9081 DT fixes: lane-mapping direction, DAC/ADC property
  completeness (crossbar-select, nco-frequency-shift-hz, gain), and
  alignment with the upstream analogdevicesinc/linux reference DT
  (rx_link_mode=10, tx_link_mode=9, CLKIN1=30.72 MHz,
  tpl-phase-adjust=3).
Prebuilt-image smoke test that drives FMCDAQ3 on VCU118 via the
coordinator path and ``BootFabric`` (MicroBlaze JTAG boot).  Documents
the new test alongside the AD9081 XSA hw test and the kernel caching
feature in the developer guide.
Land a new standalone developer walkthrough at
``doc/source/developer/authoring_devices.rst`` aimed at contributors
extending the declarative device layer.  The existing coverage
(`api/devices` "Writing a new device" bullets, `xsa_developer.rst`
black-box reference to the device layer) was too thin for a
first-time contributor to add a clock, converter, or eval-board
class without reverse-engineering from source.

The new guide (11 sections) covers:

- Class hierarchy at a glance — Device / ClockDevice /
  ConverterDevice / FpgaBoard plus the Port / ClockOutput / GtLane /
  SpiMaster plumbing.
- End-to-end call flow from ``System.generate_dts()`` through
  ``to_board_model`` → per-device ``render_dt`` → ``render_node``
  field walk → ``BoardModelRenderer`` aggregation.
- Anatomy of a Device: ``part`` / ``role`` / ``label``, the
  ClassVars consumed by ``render_node`` (``compatible``,
  ``dt_header``, ``dt_flags``), pydantic ``Field(alias="adi,...")``,
  the ``DtSkip`` / ``DtSubnodes`` / ``DtBits64`` markers, and the
  ``extra_dt_lines`` / ``trailing_blocks`` hooks with guidance on
  which to override when.
- Port & clock-output plumbing — when ``SpiPort`` / ``SpiMaster`` /
  ``ClockOutput`` / ``GtLane`` are instantiated, how
  ``System._spi_location`` resolves a device's bus / CS, and the
  named-alias pattern EvalBoards use.
- Converter shapes — MxFE with ``.adc`` / ``.dac`` sides
  (``ConverterSide`` + ``Jesd204Settings`` + ``MODE_TABLE``) vs.
  single-transducer (ADRV9009 / AD9371) vs. single-side parts
  (AD9172 / AD9680) — with pointers to the representative source
  files and guidance on which template to start from.
- Three cookbook recipes — adding a clock, adding a converter /
  transceiver, and adding an eval board or FPGA board — each citing
  real files (``adidt/devices/clocks/hmc7044.py``,
  ``adidt/devices/converters/ad9081.py``,
  ``adidt/eval/ad9081_fmc.py``, ``adidt/fpga/zcu102.py``, …) with
  minimal inline excerpts so the doc stays in sync with the code.
- Bridging to the XSA pipeline — how a new device class is picked
  up by an ``XsaBuilder`` and feeds the same renderer, with a
  pointer back to ``xsa_developer.rst`` for pipeline authoring.
- Testing layers — device unit test, System-API smoke test, and
  XSA builder / golden-file regression tests, each with a concrete
  ``test/…`` file to copy.

Also:

- ``doc/source/developer/index.rst`` — tiny nested toctree page
  that gives the developer/ subdirectory a home in the main
  "Developer Guide" navigation section.
- ``doc/source/index.rst`` — swap the former bullet to
  ``:doc:\`developer/authoring_devices\``` and add
  ``developer/index`` to the Developer Guide toctree.
- ``doc/source/api/devices.rst`` — collapse the old six-bullet
  "Writing a new device" section to a paragraph pointing at the
  new guide.
- ``doc/source/xsa_developer.rst`` — the Declarative-devices
  lead-in and the Step-5-wire-into-builder section both gain a
  cross-reference to the new authoring guide.

Sphinx build is clean; all 20 source-file citations and all 7
test-file citations resolve to files that exist on disk.
Full hardware CI plumbing:

- ``.github/workflows/hardware-test.yml`` — preflight job that probes
  the labgrid coordinator, then a direct-mode matrix and a
  coordinator-mode matrix fanned out over the available nodes
  listed in ``.github/hw-nodes.json``.  The workflow has no
  hardcoded board names; adding a node means one manifest entry +
  one runner.
- ``.github/hw-nodes.json`` declarative manifest mapping place →
  runner label → env yaml → test list.
- ``.github/scripts/register-hw-runners.sh`` — bulk-register the
  self-hosted runners (one per lab host plus the coordinator host),
  ship a fresh token via ``gh api``, and poll ``/actions/runners``
  until every registered runner is online.
- ``env_remote_{bq,mini2,nuc,all}.yaml`` — RemotePlace-only
  coordinator-mode env YAMLs; safe-to-commit (no SSH creds, no
  local paths).
Make the Hardware Tests workflow self-contained on the self-hosted
runners:

- Run ``preflight`` on the ``hw-coordinator`` self-hosted runner so
  the labgrid-client probe has a route to the private-lab
  coordinator (GitHub-hosted runners can't reach
  10.0.0.41:20408).
- Robust ``labgrid-client`` discovery: probe several common install
  paths, surface which binary is being used, and log full
  ``labgrid-client places`` output for diagnostics.
- Use ``astral-sh/uv`` to manage venvs on every hw-node runner,
  sidestepping PEP 668 on Debian/Ubuntu.  Two helper scripts
  (``.github/scripts/bootstrap-uv.sh``,
  ``install-adidt-venv.sh``) keep the workflow YAML compact.
- Pull pytsk3 through ``adi-labgrid-plugins[kuiper]``, document the
  ``python3-venv`` prerequisite, and plumb a
  ``PYADI_BUILD_TOKEN`` PAT through a process-local
  ``GIT_CONFIG_COUNT`` triple so ``uv pip install`` can clone the
  private ``tfcollins/pyadi-build`` dependency without leaving the
  secret in ``~/.gitconfig``.
Run each hw-coord matrix leg on the same per-node self-hosted runner
as hw-direct so XSA-pipeline tests have access to the local Vivado
toolchain (sdtgen, xsct, xsdb) — the coordinator host lacks Vivado
and silently skipped every XSA-dependent test there.  Source
``/tools/Xilinx/2025.1/Vivado/settings64.sh`` before pytest (with
``set -u`` toggled so the script's unset PYTHONPATH reference
doesn't abort).

Wrap each hw-coord pytest invocation in explicit labgrid-client
``acquire`` / ``release`` calls so the RemotePlace flow doesn't
fail at ``UserError: place <X> is not acquired``.

Skip hw-direct with a green job when ``LG_DIRECT_ENV`` isn't set on
a runner — direct-mode requires a node-local yaml authored by the
lab owner; until that exists the job is a no-op (the same tests
still run via hw-coord).

Drop the custom ``hardware-tests`` GitHub environment and rely on
GitHub Actions' built-in *Approval for outside collaborators* gate
for fork-PR protection.  Same-repo PRs, pushes to main, and
workflow_dispatch bypass the gate so trusted authors don't
rubber-stamp their own runs.

Ship the ADRV9371+ZC706 XSA as a committed test fixture
(``test/hw/xsa/system_top_adrv9371_zc706.xsa``) now that the
2023_R2_P1 Kuiper CDN URL it used to fetch from returns 404.
Three correctness gaps in the declarative System-API path that made
the AD9081+ZCU102 driver fail to probe on real hardware:

- ``System._find_sink_reference_clock`` only matched links whose
  endpoint was the parent ``ConverterDevice``.  MxFE parts target
  their ``adc`` / ``dac`` sides instead, so the lookup returned
  ``None`` and the AD9081 DT node lost its ``clocks = <&hmc7044 N>``
  + ``clock-names = "dev_clk"`` pair, producing ``ENOENT`` at kernel
  probe.  Now matches against the converter or either side.

- Eval board HMC7044 ``pll2_output_hz`` set to ``vcxo * 25`` (3072
  MHz), giving DEV_REFCLK = 768 MHz.  The AD9081 internal PLL can't
  hit 12 GHz DAC clock from 768 MHz (non-integer multiplier).  Pin
  at 3000 MHz matching the XSA builder.

- ``test_ad9081_zcu102_system_hw`` called
  ``converter.set_jesd204_mode(rx_mode, rx_class)`` which applied
  the SAME mode to both sides; DAC's MODE_TABLE lookup missed,
  framing params stayed at defaults (L=0).  Apply ``rx_mode`` to
  ADC and ``tx_mode`` to DAC separately.
Two DT-emission correctness gaps the AD9081+ZCU102 System-API hw
test surfaced on real hardware:

- ``_AD9081_{RX,TX}_MODE_TABLE`` had ``M=4`` / ``F=2`` where the
  reference DTS + AD9081 API mode table use ``M=8`` / ``F=4`` for
  jesd204b mode-10 (JTX) and mode-9 (JRX).  The kernel driver
  programmed the TPL + ADXCVR for fewer converters than the part's
  jtx actually frames; JESD PLL never locked ("ad9081 ...: JESD PLL
  is not locked.  Failed to initialize: -24").  Correct to
  ``M=8, L=4, F=4``.

- ``ad9081_fmc`` eval-board HMC7044 channel dividers diverged from
  the XSA builder's values.  With PLL2 at 3000 MHz they produced
  375 MHz on CORE_CLK_*, 750 MHz on DEV_REFCLK — the kernel
  reported a 250 MHz JESD link clock and the link stayed disabled
  ("Link is disabled / Measured Link Clock: 375.029 MHz").  Sync
  dividers to ``(12, 12, 1536, 12, 6, 12, 6, 1536)`` matching the
  XSA builder and the stock Kuiper
  ``zynqmp-zcu102-rev10-ad9081-m8-l4`` reference DTS.
Fast offline debug loop for System-API vs XSA-pipeline DT-emission
divergences — every bug chased in this branch is now a <1 s unit
test failure instead of a 5 min hw-coord CI round-trip.

- ``adidt.tools.dts_inspect`` — grep-based DT parser keyed by
  "grouping ancestor" (``ad9081:``, ``tx-dacs:``, ``rx-adcs:``,
  ``channel@N:``) with a ``compare_properties`` diff helper.
- ``adidt.tools.dts_compare_cli`` — ``python3 -m`` CLI that diffs
  two DTSs on the curated ``KERNEL_CRITICAL_KEYS`` set.
- ``test/devices/fixtures/ad9081_zcu102_xsa_reference.dts`` —
  committed reference DTS from a passing XSA-pipeline run.
- ``test/devices/test_system_ad9081_dts_parity.py`` — parametrizes
  the XSA reference over ``KERNEL_CRITICAL_KEYS`` so any
  per-property divergence is its own focused pytest failure.
- ``.github/workflows/hardware-test.yml`` — upload
  ``test/hw/output/*.{dts,pp.dts,dtb,dtbo,log}`` and workspace-root
  ``uart_log_*.txt`` as per-leg artifacts (retention 14 d), so
  flaky boots and DT regressions can be post-mortem'd from the
  Actions run page.
Wrap the ``board`` fixture's ``yield`` in try/finally so every
hw test module exits with the board transitioned to
``powered_off``.  Fallback path calls ``power.off()`` directly on
the bound ``PowerProtocol`` if the strategy is in a broken state
from a prior failure.  Lab hardware is never left energised
between runs.

Document the complete Hardware CI design in
``doc/source/developer/hardware_ci.rst`` — preflight + matrix
topology, the ``hardware-tests`` fork-PR gate, ``LG_DIRECT_ENV``
convention, private-dep PAT plumbing, Vivado ``settings64.sh``
sourcing, boot-reliability (pre-emptive cold-cycle + one-shot
retry, tunable via strategy attrs), artifact bundles + local DTS
parity test recipe, teardown semantics, and troubleshooting
entries for the common failure modes.
…lper

Ship redacted direct-mode labgrid YAML templates under
``doc/source/developer/samples/`` so the ``hw-direct (<place>)``
matrix legs can exercise the direct-mode test path without the
lab owner hand-authoring the YAML from scratch:

- ``lg_direct_mini2.yaml.example`` — AD9081 + ZCU102 on mini2
  (CP2108 serial, USB SD-mux, MassStorageDevice partuuid, VeSync).
- ``lg_direct_nuc.yaml.example`` — FMCDAQ3 + VCU118 on nuc
  (CP2105 serial, XilinxDeviceJTAG target IDs, XilinxVivadoTool,
  VeSync).

Every host-specific path and credential is marked ``<FILL>``.  The
developer-guide walkthrough (``Direct-mode YAML templates`` sub-
section of ``hardware_ci.rst``) covers the per-node bring-up:
scp → fill placeholders from the existing exporter YAML on the
host → ``LG_DIRECT_ENV`` + ``svc.sh`` restart → workflow_dispatch
to verify the ``hw-direct (<place>)`` leg now runs instead of
skipping.

Narrow the root ``.gitignore``'s ``lg_*`` pattern with a
``!doc/source/developer/samples/lg_*.yaml.example`` un-ignore so
the templates can be tracked while real ``lg_*`` YAMLs anywhere
else still stay out of git.  Also ignore a local operator helper
``/setup-direct-mode.sh`` (never tracked — pushes templates to the
hosts, opens an editor, sets ``LG_DIRECT_ENV``, restarts the
runner service).
@tfcollins tfcollins force-pushed the tfcollins/re-arch branch 2 times, most recently from 74108b0 to 2a26fbc Compare April 19, 2026 23:50
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 20, 2026

Unit Test Results

    3 files      3 suites   8s ⏱️
  617 tests   591 ✅ 26 💤 0 ❌
1 851 runs  1 773 ✅ 78 💤 0 ❌

Results for commit 1d15664.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 20, 2026

Kuiper64 Test Results

625 tests   601 ✅  2s ⏱️
  1 suites   24 💤
  1 files      0 ❌

Results for commit 1d15664.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 20, 2026

Hardware Test Results

6 files  6 suites   18m 2s ⏱️
4 tests 4 ✅ 0 💤 0 ❌
8 runs  8 ✅ 0 💤 0 ❌

Results for commit 1d15664.

♻️ This comment has been updated with latest results.

Narrow real nullable dereferences and silence ty 0.0.31 rules that
the current pydantic plugin can't infer through ``ConfigDict``.

Real narrowing fixes:
- ``adrv9009.py`` — assert ``trx2_cs`` is not None in the
  ``is_fmcomms8`` branch the caller already requires.
- ``fmcdaq2.py`` — AD9523 channel specs become typed 3-tuples
  ``(id: int, name: str, divider: int)`` so ``_m1 // divider`` is
  ``int // int`` again.
- ``adxcvr.py`` — widen the ``use_div40`` guard to narrow all three
  of ``jesd_l/m/s`` before dereference.
- ``system.py`` — swap ``hasattr(x, 'foo')`` + ``x.foo`` for
  ``getattr(x, 'foo', None)`` + explicit-None checks so the optional-
  attribute fact is visible via the returned type.

Workflow + rule config:
- ``type-check.yml`` — drop the stale ``adidt/boards/`` path and add
  ``adidt/devices/``, ``adidt/system.py``, ``adidt/tools/``.
- ``pyproject.toml`` — silence ``unknown-argument`` and
  ``invalid-argument-type`` on the typed surface with revisit notes
  (pydantic-plugin false positives on populate_by_name + flow-
  sensitive narrowing of pydantic ``int | None`` fields).

``ty check`` now completes with "All checks passed!" on the
typed path list.
Extend the offline DT-emission parity framework to the second hw
board in CI.  Commits the XSA-pipeline output DTS from a passing
``hw-direct (bq)`` artifact as
``test/devices/fixtures/adrv9371_zc706_xsa_reference.dts``, and
adds a new parametrized test
``test/devices/test_system_adrv9371_zc706_dts_parity.py`` that
pins 31 kernel-relevant properties where the System-API and XSA
paths already agree (AD9371 top-level + AD9528 clock-chip PLL/SYSREF
configuration).

Four properties the System-API path is known to miss vs XSA —
``ad9371:clocks``, ``ad9371:clock-names``,
``ad9371:jesd204-inputs``, ``ad9371:jesd204-link-ids`` — are
recorded as ``@pytest.mark.xfail`` with reasons referencing the
gap noted in ``test/hw/test_adrv9371_zc706_hw.py`` (System API
doesn't yet emit the XCVR/TPL-core/clkgen overlay for ZC706).
Each xfail becomes a regression guard the moment the System-API
starts emitting the property.

Along the way, extend ``adidt.tools.dts_inspect`` so the parser
covers this board's DTS too:

- ``_GROUPING_ANCESTORS`` gains ``ad9371-phy``, ``adrv9009-phy``,
  ``ad9528-1``, ``ad9523-1``, ``axi-adxcvr``, ``axi-clkgen``, and
  the JESD204 TPL core nodes.  ``_ANCESTOR_ALIAS`` strips the
  ``-phy`` / ``-1`` suffix so keys stay canonical
  (``ad9371:compatible`` regardless of whether the node is
  ``ad9371`` or ``ad9371-phy@1``).
- ``extract_props`` now normalises the ``};		foo: bar@0 {``
  multi-node-on-one-line pattern that appears in merged DTS output
  by splitting on ``};`` before the line-oriented matchers run.
  Without the split the parser leaves the previous node open and
  misattributes the next node's properties to it — the AD9371's
  clocks/gpios were landing under ``ad9528:`` before this change.

FMCDAQ3+VCU118 doesn't ship a DT generation path (boots a prebuilt
simpleImage via JTAG), so no parity fixture is possible for that
board.

31 parity keys * ADRV9371 + 14 parity keys * AD9081 now run in
<0.5 s locally — keeps the "catch DT-emission regressions before
hw" story covered for the two boards with a generated DT path.
Bandit's ``B610:django_extra_used`` rule pattern-matches any
``x.extra(...)`` call as a potential Django ORM ``.extra()`` SQL
injection vector.  Here ``extra`` is just a local variable holding
a callable (the device model's optional ``extra_dt_lines`` hook),
not a Django queryset — inline ``# nosec B610`` silences the
check with a comment explaining the context.  Fixes the only new
security-scanning error on the PR branch; the other failing
"Analyze (c-cpp)" is a CodeQL default-setup artifact ("No source
files found" on a Python-only repo) and is configured at the
repo-settings level, outside this PR.
Emit JUnit XML from every pytest invocation in CI and surface the
results two ways on each PR:

1. ``dorny/test-reporter@v1`` per job — creates a GitHub Check Run
   per Python version / hw-node / kuiper flavour with the full
   markdown table of failures, so the failing test is one click
   from the PR checks tab.

2. ``EnricoMi/publish-unit-test-result-action@v2`` — aggregates the
   XMLs across all legs and posts a single conversation comment
   per workflow ("Unit Test Results", "Hardware Test Results",
   "Kuiper64 Test Results"), visible inline on the PR without
   drilling into check details.

Workflow changes:
- ``test.yml`` — ``--junitxml=junit-py<ver>.xml``, upload standalone
  artifact, dorny report "Tests (Python X.YZ)", PR-comment summary
  job gated on ``pull_request``.
- ``hardware-test.yml`` — ``--junitxml=junit-hw-{direct,coord}-
  <place>.xml`` per matrix leg, standalone artifact + dorny report
  per leg, aggregated PR-comment job needing both matrix groups.
- ``test-kuiper.yml`` — ``--junitxml`` inside ``docker exec``, dorny
  with ``working-directory: ${{env.APP_NAME}}`` to match the
  checkout sub-path (dorny shells ``git ls-files`` from CWD), then
  the EnricoMi PR comment.

Permissions bumped to ``checks: write`` + ``pull-requests: write``
on every workflow that writes a report.
Four coordinator-mode labgrid env YAMLs lived at the repo root with
a redundant ``env_remote_`` prefix.  Group them with the hw tests
they configure and drop the prefix:

  env_remote_bq.yaml    → test/hw/env/bq.yaml
  env_remote_mini2.yaml → test/hw/env/mini2.yaml
  env_remote_nuc.yaml   → test/hw/env/nuc.yaml
  env_remote_all.yaml   → test/hw/env/all.yaml

Update every reference:
- ``.github/hw-nodes.json`` — ``env_remote`` field now holds the
  full repo-relative path (workflow reads it verbatim).
- ``.github/scripts/register-hw-runners.sh`` — comment updated.
- ``doc/source/api/devices.rst`` + ``doc/source/developer/hardware_ci.rst``
  — docs now document the ``test/hw/env/`` location and the
  ``env_remote`` field as a repo-relative path.
- ``test/hw/test_fmcdaq3_vcu118_hw.py`` — usage docstring updated.
- YAML file docstrings updated for the new ``LG_ENV`` paths.

The hardware-test workflow needs no change — it already reads the
manifest's ``env_remote`` field verbatim via
``${{ github.workspace }}/${{ matrix.node.env_remote }}``.
…cker

The declarative ``adidt.System`` pattern has fully replaced the old
``BoardModel`` + ``XsaPipeline`` rendering paths.  The 17-file
``test/hw/deprecated/`` tree has carried a ``RUN_DEPRECATED_HW``
opt-in gate for months with no user and no plan to promote any of
it — remove it outright.

Also remove the now-orphaned petalinux docker runner — it only ever
wrapped ``test/hw/deprecated/xsa/test_petalinux_build_hw.py`` and
has no other consumer:
- ``docker/Dockerfile.petalinux``
- ``docker/entrypoint.sh``
- ``docker/run-petalinux-tests.sh``

noxfile.py cleanup:
- Drop ``tests_remote`` — required ``--ip`` from the old BoardModel
  flow; no current hw test accepts it.
- Drop ``petalinux_build`` — pointed at the removed deprecated test.
- Fix ``ty`` path list to match ``.github/workflows/type-check.yml``
  (``adidt/boards/`` was removed during the re-arch).
- Drop the stale commented ``PYTHON_VERSIONS`` line.
- Drop the empty try/except wrappers around the ruff sessions.
- Drop commented ``_install_local_pyd2lang`` calls in ``docs`` /
  ``docs_serve`` (the sessions now install ``pyd2lang-native`` from
  PyPI like CI does).
@tfcollins tfcollins merged commit 38dd739 into main Apr 20, 2026
47 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant