266 lines
7.9 KiB
Markdown
266 lines
7.9 KiB
Markdown
# MAG160C Linux SDK Design
|
|
|
|
Date: 2026-07-12
|
|
|
|
## Status
|
|
|
|
Draft for user review. Approved approach: C++ core library + stable C ABI + CLI + Python-callable layer.
|
|
|
|
## Goal
|
|
|
|
Build an original Linux-usable SDK for the MAG160C USB thermal camera kit, based on interoperability evidence from the bundled Windows and Android SDKs.
|
|
|
|
The deliverable should support:
|
|
|
|
- a reusable C/C++ library;
|
|
- a command-line sample/tool;
|
|
- Python-callable access to the same library;
|
|
- clear boundaries between confirmed behavior and unknown IR camera private protocol details.
|
|
|
|
## Key evidence driving the design
|
|
|
|
- IR camera USB identity: VID 0x833C, PID 0x0001.
|
|
- Android MagDevice passes an Android USB file descriptor into native LinkCamera(fd), then calls MAG-style native APIs.
|
|
- Android libcoresdk.so exports MAG_* APIs and uses libusb_bulk_transfer.
|
|
- Windows ThermalSDK.dll wraps CoreSDKLib.dll MAG_* APIs.
|
|
- Windows CoreSDKLib.dll imports libusb0 bulk read/write APIs.
|
|
- TCM control framing is recoverable from Java bytecode:
|
|
- packet starts with 0x7e;
|
|
- big-endian body length;
|
|
- additive byte checksums for header and body;
|
|
- main/sub/frame fields;
|
|
- payload starts after frame id.
|
|
- TCM commands for motor, proximity, light, audio, power, schedule task, and firmware update are known enough to implement.
|
|
|
|
## Architecture
|
|
|
|
The project should be split into four layers.
|
|
|
|
### 1. Core C++ library
|
|
|
|
Internal name: libmag160c_core.
|
|
|
|
Responsibilities:
|
|
|
|
- Own libusb context/device handles.
|
|
- Enumerate USB devices.
|
|
- Match known MAG IR camera VID/PID.
|
|
- Discover bulk endpoints for IR/TCM-like devices.
|
|
- Encode and decode TCM frames.
|
|
- Provide IR camera lifecycle abstractions matching the SDK shape:
|
|
- open/close;
|
|
- start/stop;
|
|
- trigger FFC;
|
|
- camera info;
|
|
- raw capture/probe hooks;
|
|
- callback plumbing.
|
|
- Return explicit unsupported/protocol-unknown errors where low-level IR packet details are not yet known.
|
|
|
|
The C++ layer may use RAII and internal classes, but those classes are not the public ABI.
|
|
|
|
### 2. Stable C ABI
|
|
|
|
Public header: include/mag160c/mag160c.h.
|
|
|
|
Responsibilities:
|
|
|
|
- Expose opaque handles.
|
|
- Provide simple structs and error codes.
|
|
- Avoid C++ types in public signatures.
|
|
- Support CLI and Python bindings through the same ABI.
|
|
|
|
Proposed API families:
|
|
|
|
- Context:
|
|
- mag160c_init
|
|
- mag160c_shutdown
|
|
- mag160c_last_error
|
|
- Device discovery:
|
|
- mag160c_list_devices
|
|
- mag160c_free_device_list
|
|
- IR camera:
|
|
- mag160c_ir_open
|
|
- mag160c_ir_close
|
|
- mag160c_ir_get_info
|
|
- mag160c_ir_start
|
|
- mag160c_ir_stop
|
|
- mag160c_ir_trigger_ffc
|
|
- mag160c_ir_read_raw_once
|
|
- TCM:
|
|
- mag160c_tcm_open
|
|
- mag160c_tcm_close
|
|
- mag160c_tcm_rotate
|
|
- mag160c_tcm_read_distance
|
|
- mag160c_tcm_set_light
|
|
- mag160c_tcm_set_audio
|
|
- mag160c_tcm_get_version
|
|
- Utilities:
|
|
- mag160c_tcm_encode_frame
|
|
- mag160c_tcm_decode_frame
|
|
|
|
### 3. CLI tool
|
|
|
|
Binary name: mag160c-cli.
|
|
|
|
Initial commands:
|
|
|
|
- probe
|
|
- list matching USB devices and endpoints;
|
|
- print VID/PID, bus/address, interfaces, endpoints.
|
|
- tcm-rotate <angle>
|
|
- send known motor rotate command.
|
|
- tcm-light <off|red|green|blue|yellow> [steady|blink|breath]
|
|
- send known light command.
|
|
- tcm-distance
|
|
- read/parse proximity distance if the TCM device is available.
|
|
- ir-info
|
|
- open IR device if possible and show descriptors/endpoints.
|
|
- ir-capture-raw --out <file>
|
|
- attempt one raw read using discovered endpoints.
|
|
- if protocol command is unknown, fail with a clear MAG160C_ERR_PROTOCOL_UNKNOWN.
|
|
|
|
The CLI is both a sample and a hardware diagnostic tool.
|
|
|
|
### 4. Python-callable layer
|
|
|
|
Package name: mag160c.
|
|
|
|
Recommended first implementation: ctypes wrapper over the C ABI.
|
|
|
|
Why ctypes first:
|
|
|
|
- no compiled Python extension needed;
|
|
- easier to use in experiments;
|
|
- shares the exact tested C ABI used by the CLI.
|
|
|
|
Python modules:
|
|
|
|
- mag160c.core
|
|
- shared-library loading, error handling, ctypes structs.
|
|
- mag160c.tcm
|
|
- rotate, light, distance helpers.
|
|
- mag160c.ir
|
|
- probe, open, info, raw capture helper.
|
|
- mag160c.cli
|
|
- optional Python CLI wrapper for quick scripts.
|
|
|
|
## Data flow
|
|
|
|
### TCM command flow
|
|
|
|
Caller -> C ABI -> C++ TCM codec -> libusb bulk OUT -> device -> libusb bulk IN -> C++ TCM parser -> caller.
|
|
|
|
TCM frames are framed, checksummed, and correlated by frame id. The implementation should keep a 15-bit-ish monotonically increasing frame id compatible with the Android behavior: start at 1, increment, wrap before 0x8000.
|
|
|
|
### IR camera flow
|
|
|
|
Caller -> C ABI -> C++ IR device -> libusb endpoint discovery -> protocol-specific start/read/stop path.
|
|
|
|
Known today:
|
|
|
|
- device is vendor-specific bulk USB;
|
|
- proprietary SDK converts raw/response words into temperature data;
|
|
- exact start/read packet protocol remains unknown.
|
|
|
|
Therefore initial IR behavior should focus on descriptor probing, safe endpoint discovery, raw read experiments, and clearly marked unsupported operations until protocol evidence is recovered.
|
|
|
|
## Error handling
|
|
|
|
Use explicit error codes:
|
|
|
|
- MAG160C_OK
|
|
- MAG160C_ERR_INVALID_ARGUMENT
|
|
- MAG160C_ERR_NO_DEVICE
|
|
- MAG160C_ERR_PERMISSION
|
|
- MAG160C_ERR_USB
|
|
- MAG160C_ERR_TIMEOUT
|
|
- MAG160C_ERR_CHECKSUM
|
|
- MAG160C_ERR_PROTOCOL_UNKNOWN
|
|
- MAG160C_ERR_UNSUPPORTED
|
|
- MAG160C_ERR_INTERNAL
|
|
|
|
Every public function returns an error code or a documented sentinel. Detailed messages are available through mag160c_last_error.
|
|
|
|
The CLI must print actionable messages, especially for Linux USB permission problems and unknown IR protocol paths.
|
|
|
|
## Build system
|
|
|
|
Use CMake.
|
|
|
|
Targets:
|
|
|
|
- mag160c_core shared library
|
|
- mag160c_cli executable
|
|
- mag160c_tests test executable
|
|
- optional install target
|
|
|
|
Dependencies:
|
|
|
|
- libusb-1.0
|
|
- standard C/C++ runtime
|
|
- Python only for wrapper/tests, not for core build
|
|
|
|
No vendored proprietary SDK binaries should be linked into the implementation.
|
|
|
|
## Testing strategy without hardware
|
|
|
|
Unit tests:
|
|
|
|
- TCM frame encode/decode round trips.
|
|
- checksum validation.
|
|
- command payload construction.
|
|
- frame id wrapping.
|
|
- error-code behavior for null/invalid arguments.
|
|
|
|
Mock tests:
|
|
|
|
- fake USB transport interface for TCM read/write.
|
|
- fake device descriptor/endpoints for probe logic.
|
|
|
|
CLI dry-run tests:
|
|
|
|
- commands that support --dry-run print the bytes they would send.
|
|
- probe gracefully reports no device when hardware is absent.
|
|
|
|
Hardware tests to document:
|
|
|
|
- verify udev permissions;
|
|
- run mag160c-cli probe;
|
|
- run tcm-light/tcm-rotate with small safe values;
|
|
- run ir-info;
|
|
- run ir-capture-raw and preserve captured bytes for protocol analysis.
|
|
|
|
## Scope boundaries
|
|
|
|
In scope for first implementation:
|
|
|
|
- project scaffolding;
|
|
- C ABI and Python wrapper;
|
|
- TCM frame codec and known commands;
|
|
- USB enumeration and endpoint discovery;
|
|
- CLI diagnostics;
|
|
- IR API skeleton with honest protocol-unknown errors.
|
|
|
|
Not in scope until more evidence exists:
|
|
|
|
- exact proprietary IR start/stream command sequence;
|
|
- full raw-to-temperature parity;
|
|
- face/RGB camera logic beyond noting that RGB is ordinary UVC/V4L2 territory;
|
|
- firmware update execution by default. Firmware update commands may be encoded but should be guarded and not exposed as an easy accidental CLI action.
|
|
|
|
## Open decisions
|
|
|
|
- Whether to expose firmware update commands at all in the first public CLI. Recommendation: keep them internal or behind an explicit experimental flag.
|
|
- Whether to use C++17 or C++20. Recommendation: C++17 for broader Linux compatibility.
|
|
- Whether Python packaging should initially be source-tree-only or installable via pyproject.toml. Recommendation: include pyproject.toml once the shared library layout is settled.
|
|
|
|
## Acceptance criteria for first implementation
|
|
|
|
- CMake configures without proprietary SDK dependencies.
|
|
- Unit tests pass without hardware.
|
|
- CLI probe works and reports no-device cleanly when absent.
|
|
- TCM codec tests include byte-exact known examples generated from the recovered frame rules.
|
|
- Python can import mag160c and call at least probe/dry-run TCM helpers.
|
|
- IR unsupported/protocol-unknown operations are explicit, not silent stubs.
|
|
|