No description
  • Kotlin 98.2%
  • Shell 1.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-15 17:04:17 -04:00
.agents/skills/dual-variant-deployment chore(pricing): bump thermal camera pro price to .99 2026-10-15 11:37:08 -04:00
app feat(strings): extract Pro upgrade and pricing strings into Android XML resources with multi-flavor titles 2026-10-15 17:04:17 -04:00
docs/playstore chore(playstore): add Amazon Appstore assets and icon 2026-10-15 17:00:03 -04:00
gradle Initial commit: Pure Kotlin REVASRI / ThermPal thermal camera driver and Compose app 2026-09-28 16:54:59 -04:00
.gitignore feat(skills): add dual-variant deployment skill and pre-flight verification script 2026-10-11 13:00:52 -04:00
build.gradle.kts Initial commit: Pure Kotlin REVASRI / ThermPal thermal camera driver and Compose app 2026-09-28 16:54:59 -04:00
GEMINI.md docs(rules): add module-scoped app/GEMINI.md for calibration state machine and hardware timing 2026-10-01 12:30:27 -04:00
gradle.properties Initial commit: Pure Kotlin REVASRI / ThermPal thermal camera driver and Compose app 2026-09-28 16:54:59 -04:00
gradlew Initial commit: Pure Kotlin REVASRI / ThermPal thermal camera driver and Compose app 2026-09-28 16:54:59 -04:00
gradlew.bat Initial commit: Pure Kotlin REVASRI / ThermPal thermal camera driver and Compose app 2026-09-28 16:54:59 -04:00
LICENSE Initial commit: Pure Kotlin REVASRI / ThermPal thermal camera driver and Compose app 2026-09-28 16:54:59 -04:00
README.md docs: add README.md and GEMINI.md, set 90 deg default rotation, add +22F default camera offset 2026-09-28 20:45:29 -04:00
settings.gradle.kts Initial commit: Pure Kotlin REVASRI / ThermPal thermal camera driver and Compose app 2026-09-28 16:54:59 -04:00

Revasri Thermal Vision (Android)

Platform Android 15/16/17 Ready License Zero NDK

An open-source Android application and USB driver for the REVASRI R-T160, NOHAWK N-T160, and ThermPal USB-C thermal imaging cameras (0x04b4:0x000a).


Why This Project Exists

Budget USB-C thermal cameras like the REVASRI R-T160 (and OEM variants from Nohawk and Inreii) offer outstanding sensor performance for their price, but their official companion app (Camera+ / com.inreii.neutralapp):

  1. Is not readily available on Google Play.
  2. Bundles legacy 32-bit (armeabi-v7a) native .so libraries that fail to run on modern 64-bit-only phones (Pixel 7/8/9/10, Galaxy S23/S24/S25).
  3. Lacks 16 KB ELF segment alignment, triggering immediate OS memory-fault aborts on Android 15, 16, and 17 beta.
  4. Standard UVC (USB Video Class) camera viewers cannot stream from this device because it communicates over a vendor-specific bulk endpoint protocol.

This project provides a 100% pure Kotlin implementation using Android's native android.hardware.usb API:

  • Zero NDK or C/C++ libraries (.so): Immune to 32/64-bit ABI conflicts and 16 KB page-size enforcement.
  • Runs natively on Android 15, 16, and 17 beta.
  • Modern, responsive Jetpack Compose interface with hardware-accelerated rendering.

Hardware & Protocol Specifications

Through protocol reverse-engineering of USB descriptors and bus packets:

Attribute Specification
USB Identifiers Vendor ID: 0x04b4 (Cypress), Product ID: 0x000a
USB Class Class 255 (Vendor Specific), Subclass 240, Protocol 1 (com.white.ThermPalProtocol)
Interface & AltSetting Interface 0, Alternate Setting 1 (AltSetting 0 contains 0 endpoints)
Bulk IN Endpoint 0x82 (Packet size 512 bytes)
Bulk OUT Endpoint 0x06 (Packet size 512 bytes)
Stream Frame Rate ~24.0 – 25.6 FPS (~41.6 ms period)
Readout Matrix 256 columns × 196 rows (192 sensor rows + 4 telemetry rows)
Active Sensor Area 160 × 120 pixels (Centered at Rows 36..155, Columns 48..207)

Control Commands (Bulk OUT to 0x06)

  • Init Handshake: 0x80 0x81 (Sent once upon connection to start bulk streaming)
  • Mechanical Shutter Trigger: 0x80 0x00 (Actuates internal solenoid for NUC dark-frame calibration)
  • High Gain Mode (-20°C to 150°C): 0x80 0x21
  • Low Gain Mode (Up to 450°C): 0x80 0x20

Framing Protocol

Each video frame is transmitted across 7 sequential bulk packets of 14,348 bytes each:

  • 12-byte header: Contains magic (0x0c8c/0x0c8d), timestamp, and line offset (1, 29, 57, 85, 113, 141, 169).
  • 14,336-byte payload: 28 lines × 256 pixels of 16-bit little-endian raw bolometer ADU readings.
  • Telemetry (Rows 192..195): Serial number, model identifier (R-T160), firmware version, and real-time die/shutter temperature sensors (Row 193).

Calibration & Radiometry Engine

Verified Two-Phase Shutter Calibration

Unlike standard consumer apps that merely click the shutter mechanically without synchronizing software, Revasri Thermal Vision executes a closed-loop calibration pipeline:

  1. Solenoid Transit Handling: When Calibrate is tapped, the hardware shutter command is dispatched, and transient transit frames (~80 ms) are automatically bypassed.
  2. Phase 1: Stabilization & Temperature Calibration:
    • Observes consecutive frame mean delta (\le 12 ADU).
    • Verifies stability across 3 consecutive readings with the shutter paddle fully seated.
    • Anchors the radiometric baseline reference to the internal unit die temperature (T_{\text{unit}} = \text{fpaTemperatureC}).
  3. Phase 2: Video Calibration:
    • Accumulates closed-shutter frames to compute a 2D spatial Fixed-Pattern Noise (FPN) matrix.
    • Eliminates microbolometer vertical stripes, column offsets, and static grain.
  4. Verification & Persistence:
    • Verifies consistency between video mean and temperature baseline (|\Delta| < 150 ADU), verifies bolometer noise spread, and validates temperature sanity before committing.
    • Saves verified baseline to thermal_fpn_baseline.bin across app launches.

Radiometric Temperature Calculation

Pixel temperature is calculated via linear microbolometer radiometry:

T_i = baselineTempC + (pixelAdu_i - baselineMeanAdu) / (Sensitivity * Emissivity) + userOffsetC
  • Default Offset Constant: Includes a defined constant DEFAULT_CAMERA_TEMP_OFFSET_FAHRENHEIT = +22.0°F (+12.22°C) to align baseline radiometry with ambient environmental readings.
  • Material Emissivity: Configurable from 0.10 to 1.00 (defaults to 0.95 for skin, wood, drywall, and matte surfaces).

App Features

  • Fluid Live Thermal Stream: 24+ FPS real-time rendering via Jetpack Compose.
  • Spot Tracking HUD:
    • Red crosshair on hottest point with peak temperature readout badge.
    • Cyan crosshair on coldest point with minimum temperature readout badge.
    • Green crosshair on center point with live temperature badge.
  • Orientation: Defaults to 90° orientation; one-tap rotation cycling (0°, 90°, 180°, 270°).
  • Temperature Units: Automatic locale detection (Celsius / Fahrenheit) with one-tap toggle.
  • Color Palettes:
    • Inferno
    • Ironbow
    • Rainbow
    • White Hot (Grayscale)
    • Black Hot (Inverted Grayscale)
  • 1-Tap Calibrate & Options:
    • Tapping Calibrate immediately fires the verified shutter calibration.
    • Dropdown arrow provides quick access to Fine-Tune Temperature, Guide, and Calibration Reset.
  • Interactive Guide: Built-in explainer dialog (?) covering calibration, emissivity, and thermal tips.
  • Screen Wake-Lock: Automatically holds screen awake (FLAG_KEEP_SCREEN_ON) while the camera is active.
  • Persistent Preferences: Automatically saves palette, rotation, gain mode, temperature units, emissivity, and calibration to SharedPreferences.
  • Snapshot Capture: Exports uncompressed PNG captures directly to device gallery (Pictures/RevasriThermal).

Building & Installing

Prerequisites

  • JDK 17+
  • Android SDK 35 (Android 15)

Build Debug APK

./gradlew assembleDebug

Output APK: app/build/outputs/apk/debug/app-debug.apk

Install via ADB

adb install -r app/build/outputs/apk/debug/app-debug.apk

Launch App

adb shell am start -n com.adamoutler.revasri/.MainActivity

License

Developed by Adam Outler (adamoutler@gmail.com).

Licensed under the Apache License, Version 2.0. See LICENSE for details.