Files
MAG160C/docs/superpowers/specs/2026-07-12-mag160c-linux-sdk-design.md

7.9 KiB

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
    • 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
    • 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.