Adopting a Stray: Porting a New Camera

Part 4 of The Thingino Developer’s Journey / <- Part 3

Eventually it happens: you find a camera nobody has ported yet. Maybe it was $12 on clearance. Maybe a friend handed you a box of them. Either way, this is the moment you go from user of ports to author of ports — and it’s less mystical than it looks, because most Ingenic cameras are variations on a small number of reference designs.

Step 0: Find out what’s inside

Before touching software, identify the holy trinity that names every Thingino camera:

<brand>_<model>_<soc>_<sensor>_<wifi_chip>
  • SoC: printed on the biggest chip — T21, T23, T31 (N/L/X/AL…), T40, T41.
  • Sensor: under the lens module — GC2053, SC2336, JXH63, IMX307…
  • Wifi: the third chip — ATBM, Realtek, SSV, Bcm…

Open the case (usually four screws and one betrayed warranty sticker), or check the FCC ID database photos if you’d rather not. Cross-reference docs/supported_hardware.md — a camera with the same SoC + sensor + wifi combination under a different brand often means your “port” is a rename plus GPIO tweaks.

Step 1: Dump the original firmware

Always back up the factory firmware before flashing anything. It’s your only way back to stock, and it’s a goldmine of porting information (partition layout, sensor drivers, GPIO hints in init scripts).

docs/firmware.md covers the options in detail:

  • UART + SD card — solder three wires to the serial pads, interrupt U-Boot, dump flash to SD. The most common path.
  • Programmer clip — a CH341A with a SOIC8 clip reads the flash chip in-circuit. Dump twice, compare hashes.
  • Desolder — the last resort, for boards that fight back.

While you’re wired into UART, capture the full factory boot log. It names the sensor, the wifi driver, GPIO numbers, and the flash chip — half your defconfig, printed for free at 115200 baud.

Step 2: Start from the closest existing camera

Never start from scratch. Find a camera in configs/cameras/ with the same SoC and sensor, copy its directory, and rename per the scheme:

configs/cameras/<your_camera>/
|-- <your_camera>_defconfig    # the main config
|-- thingino.json              # runtime defaults (optional)
`-- uenv.txt                   # U-Boot environment tweaks (optional)

The defconfig is refreshingly small, because the heavy lifting lives in shared fragments. The anatomy:

# NAME: ATOM Cam 2 (T31X, GC2053, ATBM6031)     <- human-readable name (line 1)
# FRAG: soc-xburst1 core ssl                    <- fragments to include (line 2)
BR2_INGENIC_SOC_MODEL="t31x"                    <- the SoC - drives everything
BR2_SENSOR_1_NAME="gc2053"                      <- sensor driver
BR2_SENSOR_1_PARAMS="sensor_max_fps=30 data_interface=1"
BR2_PACKAGE_WIFI_ATBM6031=y                     <- wifi driver
BR2_THINGINO_AUDIO_GPIO=63                      <- board-specific GPIOs
FLASH_SIZE_MB=16                                <- flash chip size

At build time, the final .config is assembled from a toolchain fragment, the # FRAG: fragments, your defconfig, and a U-Boot fragment. The SoC model alone pulls in the right kernel branch, ISP memory reservation, and CPU settings via the SoC database (scripts/soc_database.txt) — you declare what the hardware is, not how to build for it.

Step 3: The GPIO scavenger hunt

This is the real work of a port. IR-cut filter, IR LEDs, day/night sensor, status LEDs, button, speaker enable — each is a GPIO number that differs per board. Your sources of truth, in rough order of pleasantness:

  1. The factory dump — grep extracted init scripts and config files for gpio.
  2. The factory boot log — drivers frequently announce their pins.
  3. Brute force — from a running Thingino shell, toggle candidates with the gpio tool until the right LED blinks. (docs/gpio.md has the map of which ranges are safe to poke.)

Expect a few build–flash–squint iterations. This is normal. This is the hobby.

Step 4: Boot it, gently

First boot of a fresh port is best done in a way you can walk back:

  • Keep the UART attached. All truth is in the serial console.
  • Ingenic SoCs have a mask-ROM USB recovery mode (Cloner) — you can nearly always recover, see docs/camera-recovery.md.
  • Verify in order: U-Boot comes up -> kernel boots -> sensor is detected -> stream works (rtsp://cam-ip/ch0) -> then chase LEDs, IR-cut, and audio.

The web UI’s diagnostics page and logcat will tell you what the ISP thinks of your sensor parameters.

Step 5: Send it home

When the camera works, submit the port upstream: your new configs/cameras/<camera>/ directory, formatted like its neighbors, in a PR. First line of your defconfig (# NAME:) is what users will see in the build menu — make it accurate. Hardware photos and a boot log in the PR description earn you reviewer goodwill.

Congratulations: strangers on the internet now own their cameras a little more because of you.

What you learned

  • Identify SoC + sensor + wifi; the name is the datasheet.
  • Dump factory firmware first — it’s a rollback and a treasure map.
  • Copy the closest existing camera; the defconfig is small because fragments and the SoC database do the heavy lifting.
  • GPIOs are the actual work; UART is the actual debugger.

Next up: Part 5 — Building Your Own: packages, patches, and source overrides — how to put your software on the camera, and iterate on it without fighting Buildroot.