完成官方管线全量逆向与 demo3 v5 复刻,清理仓库
- 逆向: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 规则
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
# MAG160C Reverse Engineering Findings
|
||||
|
||||
## Initial Inventory
|
||||
|
||||
- Workspace root: C:/Project/MAG160C
|
||||
- Top-level materials:
|
||||
- app/ contains Windows and Android application packages.
|
||||
- IR_Camera_SDK-1.0.1/ contains Windows and Android SDK files.
|
||||
- 【模块文档】MAG160CORE.pdf is likely module hardware documentation.
|
||||
- Windows SDK includes C# WPF example source, C headers/libs/DLLs, OpenCV DLLs, and libusb-win32 driver tools.
|
||||
- Android SDK includes demo source, AARs, native libcoresdk.so, OpenCV, and a libuvc/libusb source tree.
|
||||
|
||||
## Confirmed Hardware / API Facts
|
||||
|
||||
- IR thermal camera USB identity from Hardware Guide: Vendor ID 0x833C, Product ID 0x0001.
|
||||
- Android ThermalController checks Mag IR devices by vendor ID 33596 decimal, which equals 0x833C.
|
||||
- Android ThermalController checks TCM/control-board devices by vendor ID 1027 decimal, which equals FTDI 0x0403.
|
||||
- SDK Guide states the kit contains:
|
||||
- IR camera.
|
||||
- RGB camera.
|
||||
- TCM control board for motor rotation and proximity sensor.
|
||||
- SDK Guide states RGB camera APIs are demo-level third-party integrations; ISVs are encouraged to use their own RGB camera and face tracking APIs.
|
||||
- Therefore Linux core support should prioritize IR camera + TCM, with RGB/UVC as optional.
|
||||
|
||||
## Windows SDK Evidence
|
||||
|
||||
- CameraSDK.h exposes only:
|
||||
- OpenCamera(num, width, height)
|
||||
- CloseCamera()
|
||||
- SetNewUVCFrame(callback)
|
||||
- ThermalSDK.h exposes:
|
||||
- lifecycle: GetSDKVersion, Start, Stop, IsWorking
|
||||
- IR callback: SetNewIRFrameDelegate
|
||||
- temperature reads: ReadTemperatureAtPoint, ReadTemperatureInRect
|
||||
- configuration: SetTempBoundary, SetTempOffset, SetUnitMode, SetEmissivity
|
||||
- hardware controls/status: Rotate, Trigger, GetInnerIRCameraTemp, GetTCMVersion, firmware update APIs
|
||||
- Windows demo opens RGB/UVC as 640x480 and handles thermal IR frames as width x height x 3 RGB data.
|
||||
- Windows binary linkage:
|
||||
- ThermalSDK.dll is a higher-level wrapper that imports CoreSDKLib.dll MAG_* functions such as MAG_Initialize, MAG_EnumCameras, MAG_NewChannel, MAG_LinkCamera, MAG_StartProcessImage, MAG_GetTemperatureProbe, MAG_GetRectTemperatureInfo, MAG_TriggerFFC, and MAG_DisLinkCamera.
|
||||
- CoreSDKLib.dll exports the MAG_* C ABI directly and imports libusb0.dll functions including usb_init, usb_find_busses, usb_find_devices, usb_get_busses, usb_open, usb_set_configuration, usb_claim_interface, usb_bulk_write, usb_bulk_read, usb_clear_halt, usb_release_interface, and usb_close.
|
||||
- CoreSDKLib.dll strings include the diagnostic format "usb error: usb_bulk_read=%d, %s", confirming the Windows IR camera path is also bulk-transfer based, via libusb-win32/libusb0.
|
||||
- ThermalSDK.dll contains TCM firmware update strings such as beginUpdate/completeUpdate timeout and logs "Main:%.2X Sub:%.2X Frame:%d", matching the Android TCM framed command model.
|
||||
|
||||
## Android SDK Evidence
|
||||
|
||||
- Public ThermalController API mirrors Windows ThermalSDK.
|
||||
- ThermalConst values:
|
||||
- units: metric=0, US=1
|
||||
- invalid temp=-1.0e8
|
||||
- default fever=37.0, low=32.0, high=40.0
|
||||
- judgements: illegal=-2, beyond=-1, normal=0, fever=1
|
||||
- ThermalController internal constants and allocations show IR_WIDTH=160, IR_HEIGHT=120, allTempData length=19200.
|
||||
- Android MagDevice exposes a native API around:
|
||||
- link/unlink camera
|
||||
- start/stop process image
|
||||
- get output image/RGBA/YUV/raw data
|
||||
- get temperature data/probe/rect/line/ellipse/region info
|
||||
- get/set correction parameters
|
||||
- trigger FFC
|
||||
- save/load DDT/MDT
|
||||
- libcoresdk.so exports many MAG_* C symbols and uses libusb_* APIs, including libusb_bulk_transfer, so the IR camera is vendor-protocol USB rather than plain UVC.
|
||||
- Android libcoresdk.so additionally exports/contains MAG_GetTemperatureData_Raw, MAG_GetOutputRawData, MAG_GetFilteredRaw, MAG_TransferPulseImage, MAG_StartProcessPulseImage, and low-level CFunctions conversion symbols such as Raw2Temperature, ConvertResponse2Temperature, ReviseTemperature, ConvertInnerTemp2mC, and ConvertmC2InnerTemp. This suggests the device returns raw/response words that the proprietary SDK converts to millidegree-C-like integer units.
|
||||
- TCM Java bytecode shows:
|
||||
- motor rotate command main=2 sub=119, payload [direction, magnitude], direction 0=positive and 1=negative, magnitude capped to 128.
|
||||
- proximity command main=2 sub=120 for distance, sub=121 for gesture.
|
||||
- firmware update commands main=2, get-version=4, begin=5, stop=6, transmit=7.
|
||||
- FTDI/TCM command framing from `com.elotouch.ftdi.FTDICommand`:
|
||||
- header protocol byte is `0x7e`.
|
||||
- header length is 4 bytes: `[0]=0x7e`, `[1..2]=big-endian command-body length`, `[3]=checksum over bytes 0..2`.
|
||||
- command body length is `payload_length + 5`.
|
||||
- body indexes relative to whole packet: main command at 4, sub command at 5, frame/index at 6..7 big-endian, payload starts at 8, final byte is checksum over body bytes from index 4 through the byte before final checksum.
|
||||
- The receive parser validates the header byte/checksum, then validates the body checksum, then dispatches by main/sub and frame id.
|
||||
- Android TCM bulk communication class searches USB interfaces for any interface containing both a bulk OUT endpoint and a bulk IN endpoint, claims it, then starts read/write threads. This supports implementing TCM over generic Linux libusb bulk endpoints in addition to/without Android D2XX.
|
||||
- Additional TCM command table recovered from Java bytecode:
|
||||
- All observed TCM main commands use main 0x02.
|
||||
- motor rotate: sub 0x77, payload [direction, magnitude], with signed input clamped to [-128, 128].
|
||||
- proximity: sub 0x78 reports distance; sub 0x79 reports gesture/event byte.
|
||||
- light: sub 0x31 steady, 0x32 blink, 0x33 breath; payload is 4 bytes [on, red, green, blue] where 0xff means channel enabled at full intensity in the demo.
|
||||
- power manager: sub 0x41, payload [value2, value1] as passed to updateDevicePower(byte, byte).
|
||||
- audio: sub 0x50 beep volume, sub 0x51 USB audio volume; payload is one byte clamped to 0..16.
|
||||
- schedule task: sub 0x21 set time, 0x22 get time, 0x23 add action, 0x24 remove action, 0x25 get all actions, 0x26 remove all actions.
|
||||
- firmware update: sub 0x04 get version, 0x05 begin, 0x06 complete/stop, 0x07 transmit; flash status notifications include sub 0x0a, 0x0b, 0x0c.
|
||||
- TCM command frame id is stored as a hex string preference named index under Android shared preferences HEMATESTAPP; default is 0x0001, increments after each response, and wraps to 1 when it reaches 0x8000.
|
||||
- Android MagDevice JNI public shape:
|
||||
- MagUsb opens Android USB by device id and passes UsbDeviceConnection.getFileDescriptor() into native LinkCamera(fd).
|
||||
- Almost all native methods take the native channel handle as their first parameter.
|
||||
- CameraInfo exposes fpaWidth, fpaHeight, name, type, maxFps, curFps, bmpWidth, bmpHeight.
|
||||
- Correction/temperature APIs use integer temperature units in the native layer; Java wrappers return int temperature values for probes/regions and arrays.
|
||||
|
||||
## Tooling Attempts
|
||||
|
||||
- Existing usable tools:
|
||||
- C:/mingw64/bin/strings.exe
|
||||
- C:/mingw64/bin/readelf.exe
|
||||
- C:/mingw64/bin/objdump.exe for PE/exports, but not ARM64 ELF disassembly
|
||||
- C:/Program Files/Zulu/zulu-21/bin/javap.exe
|
||||
- Python 3.10 with pdfplumber
|
||||
- Attempted installation:
|
||||
- Tried to install capstone and pyelftools into C:/Project/MAG160C/.tools/python-revlibs.
|
||||
- Both sandboxed and escalated pip attempts failed because the network/proxy was unavailable.
|
||||
- No new reverse-engineering software was successfully installed.
|
||||
- Generated analysis cache:
|
||||
- C:/Project/MAG160C/analysis/reverse-cache/thermallib_aar contains extracted thermallib-release.aar contents for inspection.
|
||||
|
||||
## Linux SDK Evidence
|
||||
|
||||
- A Linux SDK has been added under `IR_Camera_SDK-1.0.1/linux` with versioned packages for 1.0.0, 1.0.1, 1.2.1, and 1.2.2.
|
||||
- Version 1.2.2 is already extracted and contains a Qt demo, Linux headers, firmware blob, and Linux shared libraries:
|
||||
- `libthermalSDK.so`
|
||||
- `libcameraSDK.so`
|
||||
- `libmagcore.so.2.1.1`
|
||||
- `libfaceTrackingSDK.so`
|
||||
- Early inventory confirms Linux headers and demo sources exist in `IR_Camera_SDK-1.0.1/linux/1.2.2/1.2.2/EloThermal/qtDemo`.
|
||||
- Need to inspect Linux docs, headers, demo calls, and ELF symbols before deciding whether the private IR command/streaming gap can be narrowed from this SDK.
|
||||
- Linux SDK 1.2.2 `ThermalSDK.h` largely mirrors the Windows high-level API and adds/keeps `IsTCMOpen`, `IsIROpen`, distance/error callbacks, limit events, `LimitReset`, `SoftResetTCM`, preset calibration storage, and `GetDefaultCalibration`.
|
||||
- Linux SDK `CameraSDK.h` exposes RGB/UVC `OpenCamera`, `CloseCamera`, `SetNewUVCFrame`, and `SetCameraLightParameter`; RGB remains separate from the IR vendor-bulk path.
|
||||
- Linux `Def.h` confirms the same IR dimensions and constants: `IR_WIDTH=160`, `IR_HEIGHT=120`, metric/US units, invalid temp `-1e8`, and fever/boundary defaults.
|
||||
- Linux Qt `.pro` links `libthermalSDK`, `libmagcore`, `libcameraSDK`, `libfaceTrackingSDK`, OpenMP, and OpenCV; `libmagcore` is therefore the IR MAG/libusb layer.
|
||||
- Linux `libmagcore.so.2.1.1` is x86-64 ELF and exports the same useful `MAG_*` API surface seen on Windows/Android, plus bundled `libusb_*` symbols including `libusb_bulk_transfer`, `libusb_control_transfer`, and descriptor/open/claim functions.
|
||||
- Linux `libthermalSDK.so` exported/demangled symbols show TCM-side classes such as `TCMVirtualDevice`, `ThermalTCMDevice`, `EloMotorDevice`, `EloProximityDevice`, `EloEEROMDevice`, `EloTCMUpdaterDevice`, `EloTCMHeartBeatDevice`, `SerialPort`, and `FTDICommand`.
|
||||
- Linux TCM transport appears to use a serial-port abstraction (`SerialPort`, `serial::list_ports`, `TCMDevice::open(std::string)`), which differs from Android's USB bulk communication but should carry the same `FTDICommand` frame model.
|
||||
- New TCM high-level features visible in Linux symbols: EEPROM preset read/write, limit reset/event, heartbeat/failure notification, firmware update, soft reset, proximity, motor rotate.
|
||||
- Linux Quick Start says to grant both generic USB device permissions and `ttyUSB*` permissions, matching the split IR-via-libusb plus TCM-via-serial model.
|
||||
- Linux SDK Guide documents only high-level API behavior; it does not publish low-level IR bulk commands or raw frame packet layout.
|
||||
- Linux demo startup sequence: `OpenCamera(cameraIndex, 640, 480)` + `SetNewUVCFrame`, then `Start()` + `SetNewIRFrameDelegate`, `SetNewDistanceDelegate`, `SetDistanceError`, `SetLimitEventListener`, and `SetUpdateCallback`.
|
||||
- Linux demo discovers RGB camera index by picking the first `/dev/video*` entry from `ls -al /dev/video*`; this should not be copied as-is, but confirms RGB is treated as ordinary V4L/OpenCV camera input.
|
||||
- Linux IR frame callback receives RGB888 rendered IR frames (`channel == 3`), then high-level calls like `ReadTemperatureAtPoint(80,40, ...)` or `ReadTemperatureInRect(...)` fetch calculated temperatures from SDK state.
|
||||
- Linux demo uses `GetDefaultCalibration` or stored TCM preset offsets, then applies them in RGB/IR overlay conversion; calibration is for aligning RGB face boxes to 160x120 IR coordinates.
|
||||
- Linux demo exposes safe user actions for TCM: rotate, trigger FFC, limit reset, firmware update, preset write, and soft reset.
|
||||
- Linux `MAG_LinkCamera` disassembly confirms the default MAG camera link path hard-codes VID `0x833c` before calling `MAG_LinkCameraEx`; no new public PID constant was exposed there, so hardware identity remains `0x833c/0x0001` from the hardware guide until a live descriptor says otherwise.
|
||||
- Linux `libmagcore` bulk-transfer call sites reveal default IR endpoints used internally: OUT endpoint `0x03`, IN endpoint `0x82` for command/response-style reads up to `0x1000` bytes, IN endpoint `0x84` for large reads up to `0x80000` bytes with `0xea60` ms timeout, and IN endpoint `0x81` for another small/status stream with `0x1f4` ms timeout.
|
||||
- Linux frame-stream parsing searches for 32-bit markers `0x1bb1b11b` and `0x1bb1b11c` in data read from endpoint `0x81`; this is a useful raw stream framing clue but not yet enough to implement decoded temperature/image parity.
|
||||
- Linux `EloMotorDevice::rotate(int)` confirms TCM rotate command main `0x02`, sub `0x77`, payload `[direction, magnitude]`. Linux clamps public rotate input to `[-250,250]`; Android bytecode previously showed `[-128,128]`, so our first-release dry-run helper should either document the conservative Android clamp or be adjusted deliberately after tests.
|
||||
- Linux TCM send path constructs an `FTDICommand`, calls `FTDICommand::getCommand()`, then writes the resulting bytes through an abstract data communication object; this independently validates our TCM frame-builder architecture.
|
||||
|
||||
## Working Hypotheses
|
||||
|
||||
- The RGB camera likely exposes USB Video Class and can be handled by Linux V4L2/libuvc.
|
||||
- The IR camera uses a vendor-specific libusb protocol on VID 0x833C/PID 0x0001.
|
||||
- A useful first Linux deliverable can be structured as a libusb-based skeleton with descriptor probing, endpoint discovery, TCM command framing, public SDK-compatible API, and raw-frame capture hooks.
|
||||
- Full temperature parity with the proprietary SDK requires either ARM64 disassembly of libcoresdk.so or live USB traffic capture, because the vendor bulk command protocol and raw frame packet format are not fully exposed in headers/docs.
|
||||
|
||||
## Remaining Unknowns
|
||||
|
||||
- Exact libusb bulk endpoints and command packets for MAG_LinkCamera / StartProcessImage / TriggerFFC / temperature frame transfer.
|
||||
- Exact raw IR frame packet format before libcoresdk converts it to 160x120 temperatures and rendered RGB bitmap.
|
||||
- Whether a camera is physically connected and accessible for descriptor/traffic capture.
|
||||
|
||||
## 2026-08-10 Deep-Disassembly Session (capstone/pyelftools)
|
||||
|
||||
All previously "unknown" protocol facts were recovered by disassembling the x86-64
|
||||
`libmagcore.so.2.1.1` and the ARM64 `libcoresdk.so` (which exports the internal
|
||||
`CFunctions`/`CAccumulator`/`CMagDevice` classes). Full spec in
|
||||
`analysis/protocol_spec.md`; key facts:
|
||||
|
||||
- Link: VID 0x833C, set_configuration(2), claim_interface(0), auto_detach on.
|
||||
- Command channel: EP OUT 0x03 + EP IN 0x82 (0x1000, 2000 ms); 8-byte packets
|
||||
`{u32 magic, u32 param}`; 0x3c-byte packets for DDT.
|
||||
- Command magic table: 66b/66c prepare, 66d/66e DDT rw, 66f camera info,
|
||||
670 version, 672 FFC, 673 start, 674 stop, 676/677 set params.
|
||||
- Response magic table: 5bb5b55b (info, 0x38 B → pid/width@0x10/height@0x14),
|
||||
55c/55d/55f (0x38 B blocks), 55e (16 B two qwords), 57b (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 0xa0 (160) or 0x180 (384).
|
||||
- Temperature pipeline (ARM64 symbols): PushFrame → CAccumulator::PushFrame
|
||||
(baseline avg) → Raw2Temperature / ConvertResponse2Temperature →
|
||||
BlindCompensation. Calibration = per-pixel PWL: diff=(raw-baseline)>>1,
|
||||
band search on per-pixel threshold table, v = off[i][p] + (diff*coeff[i][p]>>12),
|
||||
clamp [0,0xffff]. ConvertResponse2Temperature: base=(50000-gain)>>shift +
|
||||
diff*coeff with auto-gain reduction on >0x101 overflow pixels.
|
||||
- Probe reads: GetTemperature = window average (radius 1..3) → ReviseTemperature
|
||||
(T2E PWL table, 0x112 entries, sensor-temp/emissivity float mixing, binary
|
||||
search inverse map) → CorrectTemperature (offset segmentation k=(v-15000)/100
|
||||
clamped 0..6, float gains at +0xc4/+0xcc/+0xd0). T2E table dumped to
|
||||
analysis/t2e_table.json (monotonic 1000..737212).
|
||||
- DDT saved file format: 0x5bb5b57b header + aligned payload + 5bb5b55b/55c/55d/
|
||||
55e/55f typed blocks.
|
||||
- Error domain: custom errno 0xE4AE0001..0xE4AE0206.
|
||||
- Tools used this session: pip-installed capstone 5.0.7, pyelftools 0.33 into
|
||||
.tools/python-revlibs (network was available this time); analysis helper
|
||||
analysis/revtools.py (ELF loader, ARM64 PLT resolver, C++-lite demangler,
|
||||
xref scan); objdump/readelf/nm/strings from C:/mingw64/bin.
|
||||
|
||||
## Handoff Summary
|
||||
|
||||
- The key protocol facts to carry into a new conversation are:
|
||||
- IR camera VID/PID: `0x833C/0x0001`.
|
||||
- TCM frame format: `0x7e` header + big-endian body length + header checksum + main/sub/frame + payload + body checksum.
|
||||
- Observed TCM main command: `0x02`.
|
||||
- TCM subcommands already mapped for rotate, proximity, light, audio, power, schedule, and firmware update.
|
||||
- Windows and Android evidence agree that the IR camera path is vendor-specific USB over libusb-style bulk transfers, not plain UVC.
|
||||
- Linux implementation should keep IR protocol support as a skeleton/probe path until live USB traffic or better disassembly is available.
|
||||
- The user already chose the deliverable shape:
|
||||
- C/C++ library
|
||||
- CLI sample
|
||||
- Python-callable wrapper/tooling
|
||||
- The workspace now has enough evidence to continue implementation without redoing the reverse-engineering discovery work.
|
||||
|
||||
## 2026-08-10 Live Hardware Verification - Protocol Corrections
|
||||
|
||||
### Verified command format (this unit, WinUSB/libusb-win32)
|
||||
- 4-byte commands: 0x6bb6b66b/66c/66f (init), 0x6bb6b673 (START),
|
||||
0x6bb6b674 (STOP). FFC = 0x6bb6b672 + 4-byte param (8-byte packet).
|
||||
- Init order: 66b -> 66c -> 66f, then FFC(0) x2, sleep 300ms, START.
|
||||
- Camera info comes from the 0x6bb6b66b response (0x5bb5b55b, 0x38-byte
|
||||
payload): pid@+0x00, width=160@+0x10, height=120@+0x14, fps=15@+0x18.
|
||||
The 0x5bb5b55c block (from 66c) has a different layout (width@+0x10=5,
|
||||
height@+0x14=4 on this unit) - do not parse it as camera info.
|
||||
- FFC param toggles frame type: FFC(1) -> type 0, FFC(0) -> type 1.
|
||||
The official demo alternates FFC(0)/FFC(1) every ~10 frames during
|
||||
streaming; FFC must be sent after a complete frame (header+payload),
|
||||
not between header and payload.
|
||||
- STOP: clear_halt(0x03), clear_halt(0x82), then 0x6bb6b674.
|
||||
- Temperature signal: hand vs background ~1322 counts over most of the FOV
|
||||
(~147 counts/C under a 34C-vs-25C assumption). Frame-difference display
|
||||
(current - reference) makes the hand clearly visible.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,302 @@
|
||||
# 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
|
||||
@@ -0,0 +1,58 @@
|
||||
# MAG160C Linux SDK Reverse Engineering Plan
|
||||
|
||||
## Goal
|
||||
|
||||
Create an original, Linux-usable source implementation for the USB thermal camera in this workspace, using the bundled Windows/Android apps and SDK as interoperability references.
|
||||
|
||||
## Constraints
|
||||
|
||||
- Prefer clean-room-style interoperability notes: derive public behavior, protocol, data formats, and API shapes; do not copy proprietary binary code.
|
||||
- Do not install tools unless they are needed. If tools are installed, record what was installed and where.
|
||||
- Current workspace is not a git repository, so progress is tracked in these markdown files instead of commits.
|
||||
- Ask for approval before writing implementation code because the brainstorming skill requires an approved design first.
|
||||
|
||||
## Phases
|
||||
|
||||
1. [complete] Set up persistent planning files.
|
||||
2. [complete] Inventory SDK documents, headers, examples, APK/AAR/native libraries, and USB identifiers.
|
||||
3. [complete] Extract public API and data-flow evidence from Windows C# and Android Java/JNI/libuvc code.
|
||||
4. [complete] Inspect binaries only as needed for symbols/strings/imports, using installed or portable open-source tools where available.
|
||||
5. [complete] Present Linux implementation design with 2-3 approaches and get user approval.
|
||||
6. [pending] Implement Linux source after approval, preferably as a small libusb/libuvc-based C/C++ project plus CLI sample.
|
||||
7. [pending] Verify build/tests as far as possible without physical hardware, and document hardware test steps.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Whether the physical camera is currently attached to this Windows machine/WSL environment for live USB descriptor capture.
|
||||
- Whether the desired Linux API should be C, C++, Python bindings, or a CLI-first tool. Answered: C++ core library with stable C ABI, CLI sample, and Python-callable wrapper/tooling.
|
||||
|
||||
## Errors Encountered
|
||||
|
||||
| Error | Attempt | Resolution |
|
||||
|---|---|---|
|
||||
| Not a git repository | Ran git status | Track with markdown files instead of commits. |
|
||||
| Old using-superpowers path missing | Tried .system path | Read correct skill path under C:/Users/ZXC/.codex/skills/using-superpowers. |
|
||||
| Get-PnpDevice access denied | Tried to enumerate attached USB devices from PowerShell | Need elevated device enumeration or user-provided lsusb/USB descriptor if live hardware testing is required. |
|
||||
| ARM64 disassembly unsupported by MinGW objdump | Tried objdump on Android libcoresdk.so | Need LLVM objdump/capstone/ghidra/r2 or USB trace to recover low-level vendor protocol. |
|
||||
| pip install capstone/pyelftools failed | Tried sandbox and escalated pip install into .tools/python-revlibs | Network/proxy unavailable; no new reverse-engineering package installed. |
|
||||
| planning catchup script missing | Tried planning-with-files `.claude` catchup path from Codex session | Logged error; continued because task planning files were read directly. |
|
||||
| PowerShell heredoc/Python quoting failed | Tried Bash heredoc and then malformed `python -c` for PDF extraction | Switched to PowerShell here-string piped into `python -`; PDF extraction succeeded. |
|
||||
|
||||
## Handoff Summary
|
||||
|
||||
- Reverse-engineering evidence is complete enough for a Linux-first source implementation skeleton.
|
||||
- User chose approach 1: C++ core library + stable C ABI + CLI sample + Python-callable wrapper.
|
||||
- Implemented so far:
|
||||
- public C ABI scaffolding
|
||||
- TCM frame encode/decode
|
||||
- TCM command builders
|
||||
- USB device model and endpoint discovery
|
||||
- IR API skeleton with explicit protocol-unknown errors and Linux endpoint/marker evidence in diagnostics
|
||||
- CLI diagnostics and dry-run commands
|
||||
- Verification status:
|
||||
- CMake is not available in PATH in this environment.
|
||||
- Direct MinGW g++ compile/run checks were used instead and passed for the completed tasks.
|
||||
- Current stop point:
|
||||
- Task 6 was implemented and locally verified in no-libusb mode after the user resumed work.
|
||||
- Next implementation task is Task 7: Python ctypes wrapper.
|
||||
- If a new chat resumes work, start from the existing implementation plan and continue with the remaining Linux runtime pieces, keeping the same file-based notes.
|
||||
Reference in New Issue
Block a user