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
40 changes: 40 additions & 0 deletions docs/sensor-driver-extraction.md
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,46 @@ function carries the default. This is **expected**, not a bug; scope
the diff to the `linear_init` function on both sides and the mismatches
disappear.

### Triangulating against multiple references

When a sensor has more than one published source — e.g. an OpenIPC port
**and** an older reverse-engineering effort — diffing against both lets
you triangulate registers that appear in only one as either:

- **In trace + only in ref-A**: ref-B is incomplete (the RE missed
this register, or the port pruned it).
- **In trace + only in ref-B**: ref-A drifted from the binary
(vendor patched the closed driver, port didn't follow).
- **In both refs but not in trace**: probably dead code in both refs,
or behind a build flag the trace didn't exercise.
- **In trace and both refs**: high confidence, ship it.

For SC2315E specifically, the four artifacts available — the trace
from Majestic, the trace from Sofia, `widgetii/smart_sc2315e`
(OpenIPC port from SC2231 SDK template), and `widgetii/sc_sc2315e`
(older RE port from SC2235 SDK template) — agree byte-for-byte on
init: 172 writes, 169 unique addresses, identical values, identical
order, every pair-wise comparison at 100/100/100%.

```bash
# OpenIPC port
python3 tools/trace_diff.py generated.c \
/tmp/smart_sc2315e/sc2315e_sensor_ctl.c \
--gen-scope sc2315e_linear_init \
--ref-scope sc2315e_linear_1080P30_init

# Reverse-engineered port (note: int return, sensor_write_register_0)
python3 tools/trace_diff.py generated.c \
/tmp/sc_sc2315e/sc2235_sensor_ctl.c \
--gen-scope sc2315e_linear_init \
--ref-scope sc2235_init
```

`trace_diff.py` accepts both `void <name>(...)` and `int <name>(...)`
function definitions, and its register-write regex matches both
`sensor_write_register(...)` and `sensor_write_register_0(...)`
(the bus-numbered suffix used by the older RE port).

Other expected sources of mismatch on a real capture:

- **Registers in the reference source but not in the trace**: these are
Expand Down
27 changes: 27 additions & 0 deletions tools/test_pipeline.sh
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,31 @@ python3 tools/trace_diff.py "$tmp/driver.c" "$tmp/driver.c" \
grep -q '100.0%)' "$tmp/diff.out" \
|| { echo "self-diff not 100%"; exit 1; }

# Diff against a reference that uses the older RE-port shape:
# `int <fn>(VI_PIPE)` returning int (not void), with
# `sensor_write_register_0(...)` (bus-numbered suffix). Validates that
# extract_function_body and RE_ANY_WRITE handle both styles.
echo "== trace_diff.py cross-style ref =="
cat > "$tmp/ref_old_style.c" <<'REF'
#include <unistd.h>
typedef int VI_PIPE;
static void sensor_write_register_0(unsigned int a, unsigned int v)
{ (void)a; (void)v; }

int oldstyle_init(VI_PIPE pipe) {
(void)pipe;
sensor_write_register_0(0x100, 0x0);
sensor_write_register_0(0x3034, 0x81);
sensor_write_register_0(0x3039, 0xa6);
sensor_write_register_0(0x320e, 0x4);
sensor_write_register_0(0x100, 0x1);
return 0;
}
REF
python3 tools/trace_diff.py "$tmp/driver.c" "$tmp/ref_old_style.c" \
--gen-scope testsensor_linear_init \
--ref-scope oldstyle_init | tee "$tmp/cross.out"
grep -q 'address match: 4 / 4' "$tmp/cross.out" \
|| { echo "cross-style ref didn't match (relaxed regex broken?)"; exit 1; }

echo "OK: pipeline test passed"
18 changes: 13 additions & 5 deletions tools/trace_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
r"((?:0[xX])?[0-9a-fA-F]+)\s*,\s*"
r"((?:0[xX])?[0-9a-fA-F]+)\s*\)"
)
# Wider net for things like sc2315e_write_register(...).
# Wider net for things like sc2315e_write_register(...) or
# sensor_write_register_0(...) (the older RE port at widgetii/sc_sc2315e
# uses the bus-numbered suffix).
RE_ANY_WRITE = re.compile(
r"\b\w*write_register\s*\(\s*"
r"\b\w*write_register\w*\s*\(\s*"
r"(?:[^,]+,\s*)?"
r"((?:0[xX])?[0-9a-fA-F]+)\s*,\s*"
r"((?:0[xX])?[0-9a-fA-F]+)\s*\)"
Expand All @@ -44,12 +46,18 @@ def parse_int(s):


def extract_function_body(src, fn_name):
"""Return text inside `void <fn_name>(...) { ... }`, brace-balanced.
"""Return text inside `<rettype> <fn_name>(...) { ... }`, brace-balanced.

Strings/comments are not handled — fine for these driver files which
rettype is any whitespace-delimited token (int, void, HI_S32, HI_VOID,
static, etc.) - some references use C int returns instead of void.
Strings/comments are not handled - fine for these driver files which
keep everything on one line per write.
"""
pat = re.compile(r"\bvoid\s+" + re.escape(fn_name) + r"\s*\([^)]*\)\s*\{")
# Match a function definition: identifier(s) before the name, then (args) {
# The qualifier+rettype block can include `static`, `inline`, multiple words.
pat = re.compile(
r"(?:\b\w+\s+)+" + re.escape(fn_name) + r"\s*\([^)]*\)\s*\{"
)
m = pat.search(src)
if not m:
return None
Expand Down
Loading