Skip to main content

OpenHTF plug for driving an EmbeddedCI BenchPod directly over TCP or serial (no cloud)

Project description

embeddedci-openhtf

⚠️ Experimental. This package is new and its API may change between releases. Pin a version and expect breaking changes before 1.0.

Drive an EmbeddedCI BenchPod from OpenHTF — Google's open-source hardware test framework — connecting directly to the pod over a TCP socket or serial port. No EmbeddedCI cloud account, OIDC, or web UI is required: this package is for teams who want OpenHTF's test sequencing, limits, records, and station GUI while talking straight to a pod on their own bench.

It's a thin wrapper over the embeddedci BenchPod SDK: a single plug plus a few phase helpers. The dependency direction is strictly embeddedci-openhtfembeddedci.

pip install embeddedci-openhtf      # pulls in embeddedci + openhtf

The plug

BenchPodPlug opens a BenchPod when a test starts and closes it at teardown. Bind the connection inline with benchpod_plug(...), or leave it unbound and supply it through OpenHTF config / the BENCHPOD_CONNECTION env var.

import openhtf as htf
from embeddedci_openhtf import benchpod_plug

bench = benchpod_plug("192.168.1.50:8080")   # TCP — or benchpod_plug("/dev/ttyACM0")

@htf.plug(bench=bench)
def power_up(test, bench):
    bench.power_on()                 # methods proxy to the BenchPod SDK client
    bench.pod.capture_uart(...)      # or reach the full client via .pod

Connection forms (all direct, never cloud):

Form Example
TCP host[:port] benchpod_plug("192.168.1.50:8080")
Serial device path benchpod_plug("/dev/ttyACM0") / benchpod_plug("COM5")
BENCHPOD_CONNECTION env benchpod_plug() (unbound)
OpenHTF config htf.conf.load(benchpod_connection="...") then @htf.plug(bench=BenchPodPlug)

Phase helpers

Ready-made, fully-decorated phases for the common steps:

from embeddedci_openhtf import benchpod_plug, flash_phase, boot_banner_phase

bench = benchpod_plug("192.168.1.50:8080")

test = htf.Test(
    flash_phase(bench, file="fw.elf", target="target/stm32f4x.cfg",
                swclk=11, swdio=12, nreset=3),      # records flash_ok, attaches openocd.log
    boot_banner_phase(bench, rx=1, tx=2, expect="APP_OK"),   # records boot_ok, attaches uart.txt
)
test.execute(test_start=lambda: "SN-0001")

LA channels are 1-12 (the pod has 12 generic logic-analyzer channels and no fixed-role pins — wire any DUT signal to any channel and name it here).

For anything custom, write a normal phase and use the recorders in embeddedci_openhtf.measurements (record_flash, record_uart, record_samples) to map SDK results onto measurements and attachments.

flash_phase needs openocd on PATH (the pod is the CMSIS-DAP probe; OpenOCD runs the flash algorithm from the target= config, so every OpenOCD-supported MCU works unchanged).

Analog steps

The pod's DAC output and ADC input are exposed as analog phases (and low-level helpers). These are TCP-only — they need the JSON/sample channel that the serial console doesn't provide.

from embeddedci_openhtf import (
    benchpod_plug, signal_generate_phase, adc_capture_phase, loopback_measure_phase,
)
bench = benchpod_plug("192.168.1.50:8080")

test = htf.Test(
    # drive the DAC and capture the ADC together (loopback), assert the round trip
    loopback_measure_phase(bench, waveform="sine", freq=10_000, amplitude=120,
                           pp_range=(180, 255), mean_range=(110, 150)),
    # or: free-run a waveform, then snapshot the ADC separately
    signal_generate_phase(bench, waveform="square", freq=1_000, amplitude=100),
    adc_capture_phase(bench, samples=4096, pp_range=(150, 255)),
)

Each capture/measure phase records <prefix>_min / _max / _mean / _pp (peak-to-peak) measurements — pass any as (low, high) to make it a limit — and attaches the raw samples as adc.json. The low-level helpers signal_generate, signal_stop, and measure are available for custom phases.

Station mode (persistent connection)

By default the plug opens a connection per Test.execute() and closes it at teardown. On a station cycling many DUTs back-to-back, pass persistent=True to keep one connection open across executions (re-checked with a ping each run, reconnected if it dropped). Reuse the same plug class for every execution, and close it once at the end:

from embeddedci_openhtf import benchpod_plug, close_persistent_benchpods
from openhtf.plugs import user_input

bench = benchpod_plug("192.168.1.50:8080", persistent=True)
test = htf.Test(power_phase(bench, on=True), boot_banner_phase(bench, rx=1, tx=2, expect="APP_OK"))
try:
    while test.execute(test_start=user_input.prompt_for_test_start()):
        pass            # next DUT — same pod connection
finally:
    close_persistent_benchpods()   # also runs automatically at process exit

Examples

Development

# from the repo root
pip install -e "packages/embeddedci[dev]"
pip install -e "packages/embeddedci-openhtf[dev]"
pytest packages/embeddedci-openhtf

The test suite runs the real OpenHTF executor against an in-memory fake transport (tests/_fake.py), so it needs no pod and no OpenOCD.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

embeddedci_openhtf-0.1.0.tar.gz (17.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

embeddedci_openhtf-0.1.0-py3-none-any.whl (14.6 kB view details)

Uploaded Python 3

File details

Details for the file embeddedci_openhtf-0.1.0.tar.gz.

File metadata

  • Download URL: embeddedci_openhtf-0.1.0.tar.gz
  • Upload date:
  • Size: 17.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for embeddedci_openhtf-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1ac31d34740c22f1353be4b87a4ea27469a4cd8892b5838608fbd108f21511f4
MD5 dc3a680743f481d7ff02f7c8ddc7868f
BLAKE2b-256 337ce18c942e044da7356041271da42f29dcec22a0e9a1432356885403edb26f

See more details on using hashes here.

Provenance

The following attestation bundles were made for embeddedci_openhtf-0.1.0.tar.gz:

Publisher: publish.yml on embeddedci-com/embeddedci-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file embeddedci_openhtf-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for embeddedci_openhtf-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 244b73e7deaceb3a90973a61e86b5e87f820fb0e5d3f0ae486498c9c62f5cde8
MD5 40a894ed0cde6fbbabed211a7ec66ae5
BLAKE2b-256 070efec888d0bf525e6d286c9e3093d1e54464a1dae47d8eb5fb0d492114078e

See more details on using hashes here.

Provenance

The following attestation bundles were made for embeddedci_openhtf-0.1.0-py3-none-any.whl:

Publisher: publish.yml on embeddedci-com/embeddedci-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page