Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/pr-build-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,11 @@ jobs:
export PATH=/opt/$PLATFORM/bin:$PATH
cmake -H. -Bbuild -DCMAKE_C_COMPILER=${TOOLCHAIN}-gcc -DCMAKE_BUILD_TYPE=Release
cmake --build build

test-extraction-pipeline:
name: Test sensor extraction pipeline
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run end-to-end pipeline smoke test
run: tools/test_pipeline.sh
13 changes: 13 additions & 0 deletions docs/sensor-driver-extraction.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,19 @@ sensor: `<sensor>_linear_init` and `<sensor>_post_init_exposure_prime`,
plus a comment block summarising the most-frequently-written runtime
registers (the AE/AGC hot list).

The output is **standalone-buildable** — it includes a small "SDK stubs"
block (typedef for `VI_PIPE`, a no-op `sensor_write_register`) so that
`gcc -fsyntax-only` and `gcc -c` succeed without the vendor headers.
Delete that block and replace it with `#include "hi_comm_video.h"` /
`#include "hi_sns_ctrl.h"` plus the vendor's bus-aware
`sensor_write_register` to integrate into a HiSilicon SDK build.

`tools/test_pipeline.sh` runs the full segment → generate → compile flow
end-to-end on a synthetic trace and is wired into CI
(`pr-build-check.yml::test-extraction-pipeline`), so a regression in
any of the three Python scripts that breaks the generator output is
caught at PR time.

```bash
python3 tools/trace_to_driver.py tools/dumps/cap.log.segments.json \
--sensor sc2315e \
Expand Down
70 changes: 70 additions & 0 deletions tools/test_pipeline.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env bash
# End-to-end smoke test for the post-processing pipeline.
#
# Synthesises a minimal trace, runs:
# trace_segment.py -> trace_to_driver.py -> gcc -fsyntax-only
# and verifies each step succeeds. Designed for CI: no hardware needed,
# no external deps beyond python3 and gcc.

set -euo pipefail

cd "$(dirname "$0")/.."

tmp=$(mktemp -d)
trap "rm -rf $tmp" EXIT

# Minimal synthetic trace: probe + init (reset + a few writes + stream-on)
# + runtime (one register written enough times to trigger the runtime
# heuristic at threshold >= 3).
cat > "$tmp/sample.log" <<'TRACE'
[100] child 101 created
sensor_i2c_change_addr(0x60);
sensor_write_register(0x100, 0x0);
usleep(10000)
sensor_write_register(0x3034, 0x81);
sensor_write_register(0x3039, 0xa6);
sensor_write_register(0x320e, 0x4);
sensor_write_register(0x100, 0x1);
sensor_write_register(0x3e02, 0x80);
sensor_write_register(0x5781, 0x60);
sensor_write_register(0x5781, 0x60);
sensor_write_register(0x5781, 0x60);
sensor_write_register(0x5781, 0x60);
TRACE

echo "== trace_segment.py =="
python3 tools/trace_segment.py "$tmp/sample.log" --out "$tmp/segments.json"
test -s "$tmp/segments.json" || { echo "segments.json empty"; exit 1; }
python3 - "$tmp/segments.json" <<'PY'
import json, sys
d = json.load(open(sys.argv[1]))
phases = d["phases"]
assert phases.get("init"), "init phase missing"
assert phases.get("runtime"), "runtime phase missing"
assert d["summary"]["init"] >= 3, f"init too short: {d['summary']}"
assert d["summary"]["runtime"] >= 3, f"runtime too short: {d['summary']}"
print(f" phases: {d['summary']}")
PY

echo "== trace_to_driver.py =="
python3 tools/trace_to_driver.py "$tmp/segments.json" \
--sensor testsensor --out "$tmp/driver.c"
test -s "$tmp/driver.c" || { echo "driver.c empty"; exit 1; }
grep -q '^void testsensor_linear_init' "$tmp/driver.c" \
|| { echo "linear_init function not emitted"; exit 1; }

echo "== gcc -fsyntax-only =="
gcc -Wall -Wextra -fsyntax-only "$tmp/driver.c"

echo "== gcc -c (full compile) =="
gcc -Wall -Wextra -c "$tmp/driver.c" -o "$tmp/driver.o"
test -s "$tmp/driver.o" || { echo "object empty"; exit 1; }

echo "== trace_diff.py self-diff (must be 100%) =="
python3 tools/trace_diff.py "$tmp/driver.c" "$tmp/driver.c" \
--gen-scope testsensor_linear_init \
--ref-scope testsensor_linear_init | tee "$tmp/diff.out"
grep -q '100.0%)' "$tmp/diff.out" \
|| { echo "self-diff not 100%"; exit 1; }

echo "OK: pipeline test passed"
23 changes: 19 additions & 4 deletions tools/trace_to_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,30 @@
* Runtime AE/AGC writes are emitted as a comment block, not C code -
* the surrounding logic (gain math, exposure scaling) is not derivable
* from a register trace alone.
*
* To integrate into a HiSilicon SDK build:
* - Replace the SDK-stubs block with #include "hi_comm_video.h" and
* #include "hi_sns_ctrl.h"
* - Replace the sensor_write_register stub with the vendor's bus-aware
* implementation, typically declared in <sensor>_sensor_ctl.c
*
* As shipped, this file passes `gcc -fsyntax-only` standalone.
*/
#include "hi_comm_video.h"
#include "hi_sns_ctrl.h"

extern void {sensor}_write_register(VI_PIPE ViPipe, HI_U32 addr, HI_U32 data);
#include <unistd.h>

/* --- SDK stubs (delete when integrating into a vendor SDK) --- */
typedef int VI_PIPE;
static inline void sensor_write_register(unsigned int addr, unsigned int val)
{{
(void)addr;
(void)val;
}}
/* --- end SDK stubs --- */
"""

FN_TEMPLATE = """
void {sensor}_{suffix}(VI_PIPE ViPipe) {{
(void)ViPipe; /* implicit pipe ID in the vendor SDK; void-cast for the standalone scaffold */
{body}}}
"""

Expand Down
Loading