- 逆向:Ghidra/IDA 全量反编译 CoreSDKLib.dll/ThermalSDK.dll/libthermalSDK.so/ libcoresdk.so(ARM64)/libmagcore.so,导出 analysis/ida/export/ - 解码官方渲染管线:DDT 校准表加载->快门端点选择->Q12 插值->ref(4x type1 帧 均值)->NUC 查表->盲元补偿->窗口->LUT1024 重建->2x 升采样->调色板 - 逐像素验证:NUC+盲元 0/19200、插值 0 误差、2x 0/76800、窗口一致 - demo3 v5:完整复刻官方管线(含 DDT 解析、FFC 状态机、快门温度驱动), 修复 load_ddt 表错位导致的零像素问题 - 鬼影根因分析写入 analysis/reverse_20260813_full.md - 心跳/恢复机制:analysis/session_state.md + tools/resume_rev.ps1 - 新增 tsdk_pair3 增强采集工具;历史工具归档 csdk/tools/legacy/; 根目录抓帧残留删除,历史文档归档 analysis/history/ - csdk/README.md 完整使用文档;.gitignore/.gitattributes 补 LFS 规则
303 lines
23 KiB
Markdown
303 lines
23 KiB
Markdown
# MAG160C Reverse Engineering Progress
|
|
|
|
## 2026-07-12
|
|
|
|
- Started task.
|
|
- Read relevant process skills: using-superpowers, brainstorming, planning-with-files, test-driven-development, systematic-debugging, verification-before-completion.
|
|
- Confirmed current directory is not a git repository.
|
|
- Ran initial file inventory with rg --files; found Windows C# examples, native SDK headers/DLLs, Android demo/AARs, native libraries, and libuvc/libusb source.
|
|
- Created persistent planning files.
|
|
- Extracted SDK PDF text with Python/pdfplumber.
|
|
- Read Windows headers and C# wrappers.
|
|
- Read Android demo source and AAR/class signatures using javap.
|
|
- Extracted thermallib-release.aar to .reverse/thermallib_aar for analysis.
|
|
- Confirmed IR camera VID/PID 0x833C/0x0001 from Hardware Guide.
|
|
- Confirmed Android native libcoresdk.so exports MAG_* APIs and uses libusb.
|
|
- Attempted to install capstone/pyelftools into .tools/python-revlibs; failed because network/proxy is unavailable. No new reverse-engineering software installed.
|
|
- Tried PowerShell Get-PnpDevice for attached hardware; access denied in current environment.
|
|
- Tried MinGW objdump on ARM64 libcoresdk.so; unsupported architecture.
|
|
- Resumed from planning files and continued Android bytecode inspection with javap.
|
|
- Found detailed FTDI/TCM command framing in FTDICommand and confirmed Android TCM bulk communication auto-detects an interface with bulk IN + bulk OUT endpoints.
|
|
- Expanded TCM command table for motor, proximity, light, power, audio, schedule task, and firmware update commands.
|
|
- Extracted MagDevice JNI method surface and core native data structures from coresdk.jar.
|
|
- Inspected Windows ThermalSDK.dll, CameraSDK.dll, and CoreSDKLib.dll exports/imports/strings.
|
|
- Confirmed ThermalSDK.dll wraps CoreSDKLib.dll MAG_* APIs, CoreSDKLib.dll imports libusb0 bulk read/write APIs, and Windows TCM logs match the Android TCM command frame model.
|
|
- Marked reverse-engineering evidence phases 3 and 4 complete; moved into design approval phase.
|
|
- User selected Linux deliverables: C/C++ library plus CLI sample, and Python-callable tooling/bindings.
|
|
- User approved implementation approach 1: C++ core library + stable C ABI + CLI + Python ctypes/cffi-style wrapper.
|
|
- Wrote design spec at docs/superpowers/specs/2026-07-12-mag160c-linux-sdk-design.md and ran a placeholder scan/self-review.
|
|
- Did not commit the design spec because the workspace is not a git repository; progress remains tracked in markdown files.
|
|
- User approved the design/spec and requested the implementation plan.
|
|
- Wrote implementation plan at docs/superpowers/plans/2026-07-12-mag160c-linux-sdk.md.
|
|
- Ran implementation-plan self-review/placeholder scan; no red-flag placeholders were found.
|
|
- Implemented Task 1 scaffold: CMake, public C ABI lifecycle, error names, and lifecycle tests.
|
|
- Task 1 verification note: cmake is unavailable in PATH, so substituted direct MinGW g++ compile/run verification with MAG160C_STATIC and MAG160C_HAS_LIBUSB=0; test executable passed with exit code 0.
|
|
- Implemented Task 2 TCM frame codec with byte-exact encode/decode tests and C ABI utility functions.
|
|
- Task 2 verification note: cmake remains unavailable in PATH, so substituted direct MinGW g++ compile/run verification for test_c_api and test_tcm_frame; both passed with exit code 0.
|
|
- Implemented Task 3 TCM command builder, dry-run C ABI helpers, and command payload tests.
|
|
- Task 3 verification note: cmake remains unavailable in PATH, so substituted direct MinGW g++ compile/run verification for test_c_api, test_tcm_frame, and test_tcm_device; all passed with exit code 0.
|
|
- Implemented Task 4 USB device model, endpoint-pair selection, and C ABI device listing/freeing.
|
|
- Task 4 verification note: cmake remains unavailable in PATH, so substituted direct MinGW g++ compile/run verification for test_c_api and test_device_model; both passed with exit code 0.
|
|
|
|
## 2026-07-14 Handoff
|
|
|
|
- User asked to stop and then requested a compact context handoff for a new conversation.
|
|
- Updated `task_plan.md`, `findings.md`, and `progress.md` with a short resume-ready summary.
|
|
- Current implementation state to remember:
|
|
- design and plan are already approved
|
|
- Tasks 1-4 are implemented and verified in the no-libusb fallback path
|
|
- remaining work is the live Linux runtime path, CLI sample, and Python wrapper integration
|
|
- Important stop condition:
|
|
- do not continue execution unless the user explicitly asks to resume work
|
|
|
|
## 2026-07-14 Resume
|
|
|
|
- User explicitly resumed the task and added a Linux SDK under `IR_Camera_SDK-1.0.1/linux`.
|
|
- Restored context from `task_plan.md`, `findings.md`, and `progress.md`.
|
|
- Attempted planning-with-files session catchup via `.claude` skill path; it failed because `C:\Users\ZXC\.claude\skills\planning-with-files\scripts\session-catchup.py` does not exist in this Codex install.
|
|
- Verified the workspace is still not a git repository, so implementation continues in-place with markdown progress tracking.
|
|
- Began Linux SDK inventory. Found versioned Linux packages for 1.0.0, 1.0.1, 1.2.1, and 1.2.2; 1.2.2 is extracted with Qt demo sources, headers, Linux shared libraries, and firmware.
|
|
- Read Linux 1.2.2 `CHANGELOG`, `Coding Tips`, `ThermalSDK.h`, `CameraSDK.h`, `Def.h`, and Qt project file.
|
|
- Inspected Linux `libthermalSDK.so` and `libmagcore.so.2.1.1` ELF symbols/strings. Confirmed `libmagcore` exports `MAG_*` plus bundled `libusb_*`; confirmed Linux TCM implementation uses `SerialPort`/`TCMDevice::open(std::string)` classes around the same FTDI command concept.
|
|
- Extracted text from Linux `SDK Guide.pdf` and `Quick Start.pdf` after two PowerShell quoting failures; root cause was Bash-style heredoc/Python newline quoting in PowerShell, not PDF tooling.
|
|
- Read Linux Qt demo `basewidget.cpp`, `testwidget.cpp`, `expertwidget.cpp`, and `smartwidget.cpp`; recorded startup/callback/calibration usage in findings.
|
|
- Disassembled small Linux x86-64 slices of `MAG_LinkCamera`, `MAG_LinkCameraEx`, `MAG_StartProcessImage`, `MAG_TriggerFFC`, `MAG_EnumCameras`, `MAG_GetCamInfo`, `MAG_SetFFCMode`, `EloMotorDevice::rotate`, and `TCMVirtualDevice::sendData` to extract interoperability facts only.
|
|
- New low-level Linux evidence recorded: IR endpoints `0x03` OUT, `0x81/0x82/0x84` IN; raw stream markers `0x1bb1b11b/0x1bb1b11c`; `MAG_LinkCamera` default VID `0x833c`; Linux rotate clamp `[-250,250]` while Android evidence had `[-128,128]`.
|
|
- Implemented Task 5 IR API skeleton with public `mag160c_ir_info_t`, `mag160c_ir_open_first`, `mag160c_ir_close`, `mag160c_ir_get_info`, `mag160c_ir_trigger_ffc`, and `mag160c_ir_read_raw_once`.
|
|
- Task 5 RED verification: direct MinGW compile of `tests/cpp/test_ir_skeleton.cpp` failed as expected because `mag160c_ir_*` and `mag160c_ir_info_t` were not declared.
|
|
- Task 5 GREEN verification: direct MinGW compile and run of `build_task5_ir_skeleton_test.exe` passed with exit code 0.
|
|
- CMake is still unavailable in PATH (`cmake --version` failed), so full Task 5 verification used direct MinGW no-libusb builds.
|
|
- Full no-libusb direct verification after Task 5 passed: `test_c_api`, `test_tcm_frame`, `test_tcm_device`, `test_device_model`, and `test_ir_skeleton` all compiled and ran; output ended with `ALL_DIRECT_TESTS_PASSED`.
|
|
- Implemented Task 6 `mag160c-cli` with `probe`, `tcm-rotate --dry-run`, `tcm-light --dry-run`, and `ir-info`.
|
|
- Task 6 RED verification: direct MinGW compile of `tools/mag160c_cli.cpp` failed as expected because the CLI source file did not exist.
|
|
- Task 6 CLI verification: `build_task6_mag160c_cli.exe` no-args printed usage and exited 1; `tcm-rotate --dry-run 5` printed `7e 00 07 85 02 77 00 01 00 05 7f`; `tcm-light --dry-run green blink` printed `7e 00 09 87 02 32 00 01 01 00 ff 00 35`; `ir-info` printed MAG160C skeleton info and known Linux endpoint evidence.
|
|
- Full no-libusb direct verification after Task 6 passed again for `test_c_api`, `test_tcm_frame`, `test_tcm_device`, `test_device_model`, and `test_ir_skeleton`; output ended with `ALL_DIRECT_TESTS_PASSED`.
|
|
|
|
## 2026-08-10 Deep Disassembly: Full Protocol Recovery
|
|
|
|
- Network became available; pip-installed capstone 5.0.7 + pyelftools 0.33 into `.tools/python-revlibs` (verified: r2pipe/angr/keystone/unicorn also installed). Built reusable `analysis/revtools.py` (ELF loader, ARM64 PLT/GOT resolver, lite C++ demangler, xref scan) and used MinGW objdump/readelf on the x86-64 Linux `libmagcore.so.2.1.1` and Windows `CoreSDKLib.dll`.
|
|
- Recovered the complete vendor USB protocol from libmagcore (was the #1 open question):
|
|
- Link: VID 0x833C, set_configuration(2), claim_interface(0), auto-detach on, optional pid/bus/addr filters.
|
|
- Command channel: EP OUT 0x03 + EP IN 0x82 (0x1000, 2000ms); 8-byte packets `{u32 magic, u32 param}`; 0x3c-byte packets for DDT.
|
|
- Command magic table: 0x6bb6b66b/66c prepare, 66d/66e DDT read/write (0x38-byte payload), 66f camera info, 670 version, 671 (Windows-only), 672 FFC, 673 start (after 50ms + thread setup), 674 stop, 676/677 set params (Linux-only).
|
|
- Response magic table: 0x5bb5b55b/55c/55d/55f = 0x38-byte info blocks (55b: pid@0, width@0x10, height@0x14), 55e = 16-byte qword pair, 57b = saved-file header.
|
|
- Frame stream EP 0x81: marker 0x1bb1b11b@0, frame counter@4, data length@8, type@0xc (0/1), shutter@0x10, pixel data@0x1c (uint16 LE), trailing 0x1bb1b11c@0x1c+len, total 0x38+len, width 160 or 384. Reader thread 0x170a4 + dispatcher 0x16fb5.
|
|
- Windows CoreSDKLib.dll cross-validates: same magic codes (66b/66c/66f/670/671/672/673/674), same frame markers with 0x1c offset, same 50ms-then-start flow, same 0xe4ae error domain, same response dispatch shape (0x5bb5b55b..0x5bb5b560).
|
|
- Recovered temperature conversion math from ARM64 libcoresdk.so exported CFunctions:
|
|
- Calibration (0x6a41c): per-pixel PWL - diff=(raw-baseline)>>1, band search on per-pixel threshold table (stride bands-1), v=off[i][p]+(diff*coeff[i][p]>>12), clamp [0,0xffff].
|
|
- ConvertResponse2Temperature (0x73124): base=(50000-gain)>>shift + diff*coeff, auto-gain decrement when >0x101 pixels saturate.
|
|
- CAccumulator::PushFrame (0x62548): baseline copy/avg accumulation with restart state machine.
|
|
- GetTemperature (0x7252c): window average (radius 1..3) -> ReviseTemperature (0x6cdb8, T2E PWL 0x112 entries + emissivity float mixing + inverse-map binary search) -> CorrectTemperature (0x6d6b0, offset segmentation k=(v-15000)/100 clamped 0..6, float gains +0xc4/+0xcc/+0xd0).
|
|
- T2E table symbol exported (`T2E` @ 0x402010), monotonic 1000..737212, dumped to analysis/t2e_table.json; float constants 1000.0/0.01/0.99; units consistent with millidegree-C scale.
|
|
- DDT saved file: 0x5bb5b57b header + aligned payload + 0x5bb5b55b/55c/55d/55e/55f typed blocks.
|
|
- Wrote complete spec to `analysis/protocol_spec.md`; updated `findings.md` with the 2026-08-10 session summary.
|
|
- Implementation updates (all passing direct MinGW builds, same method as before):
|
|
- include/mag160c/mag160c.h: frame header struct, all magic constants, temp-conversion constants.
|
|
- src/core/ir_frame.{hpp,cpp}: recovered frame parser (parse_ir_frame) + Calibration piecewise-linear converter (calibrate_frame).
|
|
- tests/cpp/test_ir_frame.cpp: 7 tests (frame parse valid/bad marker/bad type/bad trailer/truncated, calibration band select/interpolation+clamp/negative diff).
|
|
- ir_device.cpp + CLI ir-info now report the recovered protocol; skeleton errors changed from PROTOCOL_UNKNOWN to UNSUPPORTED; CMakeLists updated.
|
|
- Full suite green: test_c_api, test_tcm_frame, test_tcm_device, test_device_model, test_ir_skeleton, test_ir_frame all EXIT=0; mag160c-cli ir-info shows the recovered protocol line.
|
|
|
|
## 2026-08-10 Windows Test Prep + USB Capture Tooling
|
|
|
|
- Organized workspace: disassembly outputs moved to `analysis/disasm/`, legacy
|
|
C++ exe artifacts moved to `analysis/legacy-cpp/build/`, temp files removed.
|
|
- Hardware check: no VID 0x833C device currently attached (present USB
|
|
devices: FFFF/FFFF, 0CF2/7750, 258A/010C, Logitech receiver). User will plug
|
|
the camera in for Windows testing.
|
|
- Installed USB capture tooling via winget:
|
|
- USBPcap 1.5.4.0 (`desowin.USBPcap`) - driver + USBPcapCMD.exe
|
|
- Wireshark 4.6.7 (`WiresharkFoundation.Wireshark`)
|
|
- Reboot needed for the USBPcap driver to load.
|
|
- Windows libusb-1.0 build support:
|
|
- Found a 64-bit `libusb-1.0.dll` in TI CCS
|
|
(`C:\ti\ccs2050\ccs\ccs_base\common\bin\`); openocd's copy is 32-bit
|
|
(pei-i386), which crashed with 0xC000007B on a 64-bit exe.
|
|
- Generated MinGW import library with `gendef` + `dlltool -k` (kill-at so
|
|
symbols match the undecorated x64 calls) into
|
|
`csdk/third_party/libusb/win64/` (libusb.h + libusb-1.0.dll +
|
|
libusb-1.0.x64.a + original .def).
|
|
- CMakeLists now falls back to this bundled libusb on Windows when
|
|
pkg-config finds nothing, and copies the DLL next to the CLI.
|
|
- Verified full libusb+threads build on Windows:
|
|
- `csdk_cli_libusb.exe` runs; tcm/frame/temp tests pass; `ir-info` reports
|
|
"no device with VID 0x833c" (libusb enumeration works); `ffc` returns
|
|
NOT_OPEN cleanly.
|
|
- Wrote `csdk/WINDOWS_TESTING.md`: build commands, hardware test flow, USBPcap
|
|
capture procedure, and the pcap verification checklist against the recovered
|
|
protocol (magic bytes per command/response/frame).
|
|
|
|
## 2026-08-10 Pure-C SDK Rewrite (csdk/)
|
|
|
|
- User requested a C SDK faithful to the reverse-engineered protocol; the
|
|
previous C++ implementation (fake `ir_open`, dynamic endpoint discovery,
|
|
missing temperature math) was replaced. Old tree archived to
|
|
`analysis/legacy-cpp/`.
|
|
- New pure-C tree in `csdk/`:
|
|
- `include/mag160c/mag160c.h` - C ABI: vendor error domain, all magic
|
|
command/response codes, frame format constants, temperature pipeline API,
|
|
TCM framing API.
|
|
- `src/mag160c_error.c` - TLS last-error.
|
|
- `src/mag160c_frame.c` - 0x1bb1b11b frame parse + streaming assembler
|
|
(marker align, length check, trailing marker, 0x38+len consumption).
|
|
- `src/mag160c_temp.c` - Calibration (per-pixel PWL w/ baseline),
|
|
ConvertResponse2Temperature (auto-gain + saturation counting),
|
|
T2E Q13 interpolation using the dumped tables.
|
|
- `src/mag160c_tcm.c` - FTDICommand 0x7e framing; NOTE: checksum is
|
|
additive mod-256 (0x7e+0x07=0x85), byte-exact vs. the old C++ tests.
|
|
- `src/mag160c_ir.c` - libusb session: VID 0x833C, config 2, iface 0,
|
|
EP 0x03/0x82 command channel, EP 0x81 frame reader thread, 50 ms then
|
|
START, STOP, FFC; compiles in libusb/threads/no-libusb modes.
|
|
- `src/mag160c_tables.h` - T2E + E2TAccQ10 tables generated from the
|
|
ARM64 binary dump.
|
|
- `tools/mag160c_cli.c` - ir-info / ffc / start / stop / tcm-rotate /
|
|
tcm-light / frame-test / temp-test.
|
|
- `tests/` - test_frame, test_temp, test_tcm, test_api.
|
|
- Verification (mingw gcc, no-libusb mode): all 4 tests pass
|
|
(ALL_CSDK_TESTS_PASSED); threads mode passes; libusb+threads mode compiles
|
|
clean (no libusb .lib on this machine to link).
|
|
- CLI output verified: `tcm-rotate 5` ->
|
|
`7e 00 07 85 02 77 00 01 00 05 7f` (byte-exact), `tcm-light green blink` ->
|
|
`7e 00 09 87 02 32 00 01 01 00 ff 00 35`, frame-test/temp-test pass,
|
|
ir-info prints the recovered protocol.
|
|
|
|
## 2026-07-14 Workspace Organization
|
|
|
|
- Organized generated and analysis files without deleting source or vendor SDK material.
|
|
- Moved root `build_*.exe` binaries into `build-artifacts/`.
|
|
- Moved `.reverse/` to `analysis/reverse-cache/`.
|
|
- Moved `reverse_tools/` to `analysis/reverse_tools/`.
|
|
- Moved root `【模块文档】MAG160CORE.pdf` to `vendor-docs/【模块文档】MAG160CORE.pdf`.
|
|
- Left vendor SDK/app directories and active source directories in place: `IR_Camera_SDK-1.0.1/`, `app/`, `src/`, `include/`, `tests/`, `tools/`, and `docs/`.
|
|
|
|
## 2026-08-10 Live Hardware Protocol Verification (WinUSB/libusb-win32)
|
|
|
|
User connected the actual device (Magnity Thermal Camera, VID 0x833C PID 0x0001,
|
|
serial 160043865). Full protocol verified live against the official Windows demo
|
|
(EloThermal.exe, which shows a real thermal image).
|
|
|
|
### Driver / libusb matrix (important)
|
|
- Device ships without a driver; SDK's ThermoCube_stream.inf fails signature
|
|
validation on Win10/11 (2012 cat). Zadig installed WinUSB, then
|
|
libusb-win32 for the official demo (demo links libusb0.dll directly).
|
|
- Working combo: **TI libusb-1.0.dll + libusb-win32 driver** (all commands/stream
|
|
work; harmless "monotonic clock" warnings). Official libusb-1.0.27 MinGW build
|
|
crashes on bulk transfer with the libusb-win32 driver; official DLL + WinUSB
|
|
crashes in libusb_control_transfer; TI DLL + WinUSB fails FFC writes.
|
|
|
|
### Protocol verified on hardware (differs from Linux-SDK assumptions)
|
|
- Commands are 4-byte packets (magic only); only FFC (0x6bb6b672) uses the
|
|
8-byte {magic, param} form.
|
|
- Init: 66b(4B) -> 66c(4B) -> 66f(4B). Response 0x5bb5b55b from 66b carries the
|
|
camera info (width@+0x10=160, height@+0x14=120, fps@+0x18=15). The 0x5bb5b55c
|
|
block (from 66c) is a DIFFERENT layout and must not be parsed as info.
|
|
- START: FFC(0) x2, sleep 300ms, then 73(4B). This switches the unit into live
|
|
imaging mode (frames with type field 0/1). FFC(param=1) toggles type 1->0,
|
|
FFC(param=0) toggles 0->1; the official demo alternates FFC every ~10 frames.
|
|
- STOP: clear_halt(0x03/0x82) then 74(4B) works.
|
|
- Frame stream: 28-byte header (marker 0x1bb1b11b, counter, len=0x9600,
|
|
type, shutter) + 38400-byte payload + 28-byte tail (0x1bb1b11c trailer), at
|
|
15 fps. Verified: 4 s capture = 60 frames.
|
|
- Thermal response: hand vs background delta ~1322 counts (whole-FOV hand)
|
|
=> roughly 147 counts/C with a plausible 34C vs 25C assumption.
|
|
|
|
### csdk fixes made from live testing
|
|
- send_cmd4 for 66b/66c/66f/73/74; FFC stays 8-byte with param.
|
|
- ir_open sequence 66b,66c,66f (was sending 670 in third slot).
|
|
- FFC(0) x2 before START in ir_start.
|
|
- Keep libusb_context alive for handle lifetime (was libusb_exit'ing it).
|
|
- Only 0x5bb5b55b parsed as info (0x5bb5b55c corrupted width/height).
|
|
- GUI live thermal viewer (thermal_viewer.c) shows real-time pseudo-color
|
|
imagery; single-threaded read/render loop required (TI libusb DLL is
|
|
unreliable with a reader thread + GUI thread).
|
|
|
|
### Artifacts
|
|
- official demo traffic capture: analysis/captures/libusb0_trace.txt
|
|
(26k lines: init, periodic FFC, 10k+ frames) via a libusb0.dll API shim.
|
|
- ETW capture experiments (USB-UCX has no payload data; etl2pcapng is
|
|
network-only) - kept as notes in csdk/WINDOWS_TESTING.md.
|
|
|
|
## 2026-08-10 Post-reboot USBPcap Verification
|
|
|
|
- System rebooted; USBPcap driver now bound to the root hubs. Device is on
|
|
\\\\.\\USBPcap4 (AMD USB 3.x hub on this machine).
|
|
- Captured the csdk's own live traffic with USBPcap (no shim needed anymore):
|
|
analysis/captures/csdk_verified.pcap.
|
|
- Sequence verified identical to the official demo: 66b -> 66c -> 66f ->
|
|
FFC(0) x2 -> START -> 61 frames @ 15 fps -> STOP.
|
|
- csdk frame callback test: 60 frames in 4 s (type=1). All tests green.
|
|
|
|
## 2026-08-10 (evening)
|
|
|
|
- Task 1: researched open-source thermal display pipelines (OpenThermal/libseek-thermal
|
|
SeekCam.cpp, MLX90640 API, FLIR Lepton AGC/LUT). Key learnings: bad pixel = histogram
|
|
peak-deviation threshold (thr = peak - (max - peak)) + temporal min/max, topological
|
|
4-neighbour fill; AGC = percentile stretch + ironbow LUT; diff AGC = adaptive mean-based span.
|
|
- Task 2: rewrote tools/mag160c_demo2.c v3: Seek-style bad pixel detection + topological
|
|
fill order applied to live frame and reference; adaptive diff AGC (span=2*mean|d|, deadband);
|
|
ironbow LUT; two-point calibration buttons (Cal Cold 0C / Cal Hot 90C / Reset).
|
|
- Task 3: decoded official FFC cadence from libusb0_trace.txt (26092 lines):
|
|
FFC(1) after ~frame 10, then FFC(0) -> 9 frames -> FFC(1) -> variable gap (34..2680).
|
|
Built mag160c_ffc_test.c with period 400 + gap 9: PASS 1400 type=0 frames / 95s /
|
|
15.1 fps / 0 stalls (twice). 44-frame period failed (fps drop + 17.7% type=1).
|
|
- Task 4: added two-point linear calibration (mag160c_temp_calibrate_linear) to csdk +
|
|
demo2 GUI buttons; physical measurement (ice water / boiling water) still TODO by user.
|
|
- Task 5: new csdk module src/mag160c_display.c + include/mag160c/mag160c_display.h
|
|
(badmap, AGC range/diff span, ironbow, FFC scheduler, linear cal); mag160c_ir.c now
|
|
supports mag160c_ir_set_ffc_scheduler() ticking in the reader thread. test_display.c
|
|
added (20/20 pass); all old tests still pass; CLI gained display-test/ffc-test/calibrate.
|
|
- Hardware validation: csdk_stream_test.exe (threaded reader + scheduler) PASS 1030
|
|
type=0 frames / 14.7 fps; csdk_cli_libusb.exe ffc-test 1000 PASS. demo2 GUI verified
|
|
rendering type=0 with bad-pixel red/blue down to ~0.02% and no saturated defects.
|
|
- Evidence: analysis/demo2_v3_verified_20260810.png (GUI screenshot).
|
|
|
|
## 2026-08-10 (late night, third fix round)
|
|
|
|
- User reported: FFC flash fixed but (1) startup noise image (red/yellow dots)
|
|
persists and overlays the normal view, (2) ghosting still present.
|
|
- Root cause: MOG permanent-freeze defect - reference collected before the
|
|
first auto-FFC cycle baked startup noise in; frozen pixels (|d|>=60) could
|
|
never heal, so noise + wrong reference persisted forever.
|
|
- Fixes in mag160c_demo2.c:
|
|
* first reference collection moved to right after startup FFC(1) settling
|
|
(nread>=40, not >=150)
|
|
* reference re-collected after EVERY FFC(1) (quiet-frame median, keeps bad
|
|
map) instead of one-shot median rebase - any stale reference self-heals
|
|
within one FFC cycle (~27s)
|
|
* MOG self-healing: isolated foreground pixels (8-neighbor fg < 2) stuck
|
|
for >=30 frames are reference errors (startup noise/bad pixel), reset to
|
|
live value; contiguous objects never healed/absorbed
|
|
- csdk: new mag160c_display_ref_track_heal() (w,h variant with fg counters);
|
|
demo2 uses it directly. test_display now 30/30.
|
|
- Verified on hardware: startup noise 0.12% -> 0.10% over 2157 frames
|
|
(5+ FFC cycles), no growth, no overlay; red content all real scene blobs;
|
|
no FFC flash (red stable, blue 0.01%); stream never stalls.
|
|
- Evidence: analysis/demo2_v4_selfheal_verified_20260810.png
|
|
|
|
## 2026-08-10 (late night, fourth fix round - root cause found)
|
|
|
|
- User reported startup noise image and ghosting STILL present after the
|
|
MOG self-heal fix. Started a data-driven investigation instead of more
|
|
reference-model tweaks.
|
|
- Captured 60 real type=0 frames (tools/mag160c_frame_dump.c) and analyzed:
|
|
* temporal noise std ~248 counts per pixel (99.9% of pixels) -> diff mode
|
|
with adaptive span ~400 amplifies this into visible red/blue speckle =
|
|
the "startup noise image"
|
|
* fixed sensor mura: row profile span 15594 (row1 constant +5000), col
|
|
span 8714, FFT shows ~10% energy on row/col axes
|
|
* mura drifts ~350 counts per session and jumps after FFC -> reference
|
|
diff shows old pattern = ghosting
|
|
* flat-field correction live-(ref-mean(ref)) reduces mura std 3557->379
|
|
- Decided to abandon the scene-diff approach (which caused both problems)
|
|
and adopt the official pipeline: raw -> NUC flat-field correction ->
|
|
absolute temperature display (median-centered window + ironbow) + 3x3
|
|
median smoothing (cuts temporal noise ~3x).
|
|
- csdk: new mag160c_display_nuc(); reference capture now rejects frames
|
|
where >5% pixels deviate from the running average (persistent objects
|
|
never enter the flat field) - the anti-ghost guarantee. diff mode kept
|
|
as optional.
|
|
- Verified on hardware: speckle residual 2.2-2.7 (smooth), pure blue 0%,
|
|
red content all real scene blobs (1-1.4%), 5+ FFC cycles with no flash
|
|
and no pattern growth, stream 2268+ frames. csdk tests 32/32.
|
|
- Evidence: analysis/demo2_v5_nuc_verified_20260810.png
|