Skip to content

Adding Fullhan FH885xV100 support - #63

Merged
wberube merged 3 commits into
masterfrom
fhan-v100
Oct 25, 2026
Merged

wberube merged 3 commits into
masterfrom
fhan-v100

Conversation

@wberube

@wberube wberube commented Oct 25, 2026

Copy link
Copy Markdown
Member

Supersedes #43.

Integrated Fullhan FH885xV100 support extracted from #43, plus the shared Fullhan compatibility shim and the platform-identification refactor. The contributor's branch is left untouched.

  • Adding Fullhan FH885xV100 support (authored by Kasperi)
  • Sharing the Fullhan libc compatibility shim
  • Refactoring platform identification

All 14 canonical build.sh targets pass, including fhan-v1, fhan-v2, mips-musl, and ak39xx.

wberube and others added 3 commits October 25, 2026 03:31
The SIOCGIFCONF workaround is the same on the V100 and V200 generations,
and the V100 branch carries a duplicate of it. Move the existing shim to
fh_compat.c so both generations share one implementation before the V100
HAL is extracted.
Audio initialization failure stays fatal, as it is on every other
platform. The watchdog has been disarmed on normal exits since 3f80a4a,
so a bad microphone configuration no longer turns into a reboot loop and
nothing here needs a platform-specific exception.

A HAL for the Fullhan V100 generation (FH8852/FH8856, ARM1176/ARMv6),
driving the vendor SDK's libdsp/libisp/libvmm and libacw_mpi through
dlopen. Sensor drivers come from the userspace lib<name>.so modules that
OpenIPC provides, the same mechanism as the V200 HAL.

Identification follows ipctool: the PMU registers at 0xf0000000 report
CHIP_ID 0x17092901 with IP_VER low nibble 0xc/0xd for FH8852V100 and
FH8856V100, while 0x19112201 is the V200/V210 family. Keeping them apart
matters because building a V100 board as V200 hangs the SoC in
fh_pinctrl_init_devices() and corrupts the console baud. The platform
lives in src/hal/fhan/ with an f1_ prefix so it mirrors the f2_ V200 HAL.

The SDK has no public headers, so the interfaces were recovered from the
vendor application and verified on hardware. Frames are copied once out
of the uncached DMA buffer; the HEVC encoder bundles VPS, SPS and PPS
into the IDR entry, so entries are split on start codes; H.264 is
Main-only because the encoder rejects High and closes the channel; and
there is no FH_VENC_DestroyChn, so channels are created once with both
codecs reserved. The exported GPIO sysfs directory is GPIO<n> on these
kernels, and the ISP reports an image gain that drives day/night
switching without a light sensor.

Extracted from #43, authored by Kasperi.
Move each platform's detection into its HAL (v4_system_identify,
i6_system_readtemp, ...) and share the common probes from per-directory
common.h headers. Move the register and chip-id constants out of
hal_identify() and the HAL sources into the matching *_sys.h files, keep
/sys/class/thermal as the generic temperature fallback, retry strict
/dev/mem mappings a page at a time, and fall back to CLOCK_MONOTONIC when
the toolchain has no CLOCK_MONOTONIC_COARSE.
@wberube
wberube merged commit 7cace4c into master Oct 25, 2026
1 check passed
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add Fullhan FH885xV100 support and modularize platform detection

✨ Enhancement 🐞 Bug fix 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add an FH8852/FH8856 V100 HAL for sensor, video, audio, overlays, snapshots, and night mode.
• Distinguish Fullhan generations before SDK initialization to avoid selecting the incompatible V200
 HAL.
• Move platform identification into HALs and share Fullhan lamp and libc compatibility code.
Diagram

graph TD
  A["Platform dispatcher"] --> B{"Chip generation"} --> C["V100 HAL"] --> D["Vendor SDK"]
  C --> E["Sensor modules"]
  C --> F["Media consumers"]
  C --> G["Night controls"]
  H["Shared Fullhan support"] --> C
  H --> I["V200 HAL"]
  B --> I
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Extend the V200 HAL with generation-specific SDK adapters
  • ➕ Could consolidate common media lifecycle and streaming behavior.
  • ➖ Recovered V100 and V200 SDK interfaces and hardware constraints differ substantially.
  • ➖ A shared implementation would increase regression risk for working V200 devices.

Recommendation: Keep separate f1 and f2 HALs while sharing generation-independent identification, lamp control, and libc compatibility. This preserves a clear SDK boundary; broader media-code unification is better considered after both generations have hardware validation.

Files changed (68) +2936 / -450

Enhancement (19) +2176 / -4
app_config.cParse and save night lamp modes +33/-1

Parse and save night lamp modes

• Defaults to IR, accepts combinations of IR and white or 'none', and persists the selected mode. Allows '999' as the IR sensor pin.

src/app_config.c

app_config.hStore the configured night lamp +1/-0

Store the configured night lamp

• Adds a 'hal_light' field to application configuration.

src/app_config.h

common.hShare Fullhan chip detection and lamp constants +91/-0

Share Fullhan chip detection and lamp constants

• Identifies V100 and V200 variants using PMU registers, with procfs name fallback. Defines shared PWM and lamp constants.

src/hal/fhan/common.h

f1_aud.hDeclare and load V100 audio interfaces +77/-0

Declare and load V100 audio interfaces

• Defines audio configuration and frame layouts and resolves capture functions from 'libacw_mpi.so'.

src/hal/fhan/f1_aud.h

f1_common.hDefine V100 SDK constants and dimensions +50/-0

Define V100 SDK constants and dimensions

• Records channel limits, sensor frame formats, codec identifiers, and rate-control modes for the recovered V100 interface.

src/hal/fhan/f1_common.h

f1_hal.cImplement the FH885xV100 HAL +1198/-0

Implement the FH885xV100 HAL

• Adds sensor selection, SDK and pipeline lifecycle, audio capture, video encoding, snapshots, overlays, and gain-based night detection. Handles V100 scaler and encoder pool constraints and translates SDK streams for existing consumers.

src/hal/fhan/f1_hal.c

f1_hal.hExpose V100 HAL operations +63/-0

Expose V100 HAL operations

• Declares the V100 lifecycle, media, overlay, night-status, and identification entry points.

src/hal/fhan/f1_hal.h

f1_isp.hDefine V100 ISP and sensor ABI +220/-0

Define V100 ISP and sensor ABI

• Declares recovered sensor and ISP structures and dynamically loads ISP, core, MIPI, and advanced-image functions.

src/hal/fhan/f1_isp.h

f1_osd.hDefine V100 overlay region state +11/-0

Define V100 overlay region state

• Adds the region limit and bookkeeping structure for the V100 graphics plane.

src/hal/fhan/f1_osd.h

f1_snr.hLoad userspace V100 sensor drivers +54/-0

Load userspace V100 sensor drivers

• Loads 'lib<sensor>.so' modules from sensor directories and accepts both observed sensor-table and destroy-symbol spellings.

src/hal/fhan/f1_snr.h

f1_sys.hBind V100 system and allocator functions +71/-0

Bind V100 system and allocator functions

• Defines system version and buffer structures and loads 'libvmm' before the dependent 'libdsp' functions.

src/hal/fhan/f1_sys.h

f1_venc.hDefine V100 encoder ABI +125/-0

Define V100 encoder ABI

• Declares encoder configurations, rate control, stream layouts, and dynamically resolved channel and stream operations.

src/hal/fhan/f1_venc.h

f1_vpss.hDefine V100 scaler and graphics ABI +107/-0

Define V100 scaler and graphics ABI

• Declares scaler, frame-control, and graphics-plane structures and loads the corresponding 'libdsp' functions.

src/hal/fhan/f1_vpss.h

types.hAdd the V100 platform identifier +4/-3

Add the V100 platform identifier

• Adds 'HAL_PLATFORM_F1' and expresses illuminator values as combinable bit flags.

src/hal/types.h

jpeg.cRoute JPEG operations to V100 +3/-0

Route JPEG operations to V100

• Adds V100 dispatch for snapshot encoder creation, destruction, and capture.

src/jpeg.c

media.cWire V100 into media lifecycle +21/-0

Wire V100 into media lifecycle

• Adds V100 dispatch across SDK startup and shutdown, audio, channels, video streams, MJPEG, MP4, and encoder controls.

src/media.c

night.cAdd V100 gain-driven night mode and lamp policies +34/-0

Add V100 gain-driven night mode and lamp policies

• Uses ISP image gain for automatic V100 switching when available. Applies configured IR or white illumination with corresponding grayscale and IR-cut behavior.

src/night.c

night.hInclude Fullhan lamp controls for night mode +4/-0

Include Fullhan lamp controls for night mode

• Makes the shared lamp API available to ARMv6 night-mode handling.

src/night.h

region.cRoute overlays to the V100 HAL +9/-0

Route overlays to the V100 HAL

• Adds V100 overlay creation, bitmap updates, and destruction to region rendering.

src/region.c

Bug fix (3) +39 / -10
gpio.cSupport Fullhan GPIO sysfs naming +25/-10

Support Fullhan GPIO sysfs naming

• Probes for uppercase 'GPIO<n>' directories and retains lowercase naming elsewhere. Corrects checks for failed 'open()' calls.

src/gpio.c

tools.cRetry restricted physical-register mappings +10/-0

Retry restricted physical-register mappings

• Retries a failed 64 KiB '/dev/mem' mapping with a page-sized mapping when strict devmem returns 'EPERM'.

src/hal/tools.c

tools.hProvide a monotonic clock fallback +4/-0

Provide a monotonic clock fallback

• Aliases 'CLOCK_MONOTONIC_COARSE' to 'CLOCK_MONOTONIC' where the former is unavailable.

src/hal/tools.h

Refactor (43) +680 / -399
f2_aud.hAlign V200 audio declaration formatting +3/-3

Align V200 audio declaration formatting

• Adjusts comments and spacing in the existing audio configuration structure without changing its fields.

src/hal/fhan/f2_aud.h

f2_common.hUse shared Fullhan definitions in V200 +4/-10

Use shared Fullhan definitions in V200

• Includes shared Fullhan constants and removes duplicate lamp definitions.

src/hal/fhan/f2_common.h

f2_hal.cUse shared lamps and identify V200 explicitly +16/-10

Use shared lamps and identify V200 explicitly

• Replaces local lamp control with the shared implementation and adds a V200 identification entry point.

src/hal/fhan/f2_hal.c

f2_hal.hExpose V200 identification and shared lamp API +3/-2

Expose V200 identification and shared lamp API

• Includes the shared lamp header and replaces the local lamp declaration with a V200 identification declaration.

src/hal/fhan/f2_hal.h

fh_compat.cGeneralize the Fullhan libc shim +6/-6

Generalize the Fullhan libc shim

• Clarifies that the ioctl-based 'getifaddrs()' replacement serves both Fullhan generations and removes V200-specific naming.

src/hal/fhan/fh_compat.c

fh_lamp.cShare Fullhan PWM and GPIO lamp control +24/-0

Share Fullhan PWM and GPIO lamp control

• Implements IR and white illuminator control for both Fullhan generations.

src/hal/fhan/fh_lamp.c

fh_lamp.hDeclare shared Fullhan lamp control +12/-0

Declare shared Fullhan lamp control

• Exposes the common lamp function and its GPIO, type, and PWM dependencies.

src/hal/fhan/fh_lamp.h

common.hExtract shared HiSilicon identification +105/-0

Extract shared HiSilicon identification

• Moves UART, system-ID, and legacy chip-subtype detection into a common helper used by HiSilicon generations.

src/hal/hisi/common.h

v1_hal.cIdentify first-generation HiSilicon in its HAL +15/-0

Identify first-generation HiSilicon in its HAL

• Adds local detection and registers the V1 channel state and media threads.

src/hal/hisi/v1_hal.c

v1_hal.hDeclare V1 platform identification +4/-0

Declare V1 platform identification

• Includes common detection dependencies and exposes the V1 identifier.

src/hal/hisi/v1_hal.h

v2_hal.cIdentify HiSilicon V2 and name temperature registers +19/-4

Identify HiSilicon V2 and name temperature registers

• Adds V2-specific identification and substitutes named constants in temperature readings.

src/hal/hisi/v2_hal.c

v2_hal.hDeclare V2 platform identification +4/-0

Declare V2 platform identification

• Includes shared detection dependencies and exposes the V2 identifier.

src/hal/hisi/v2_hal.h

v2_sys.hName V2 temperature registers +4/-0

Name V2 temperature registers

• Defines configuration, measurement, and preparation constants.

src/hal/hisi/v2_sys.h

v3_hal.cIdentify HiSilicon V3 and name temperature registers +19/-4

Identify HiSilicon V3 and name temperature registers

• Adds V3-specific identification and replaces temperature-register literals with constants.

src/hal/hisi/v3_hal.c

v3_hal.hDeclare V3 platform identification +4/-0

Declare V3 platform identification

• Includes shared detection dependencies and exposes the V3 identifier.

src/hal/hisi/v3_hal.h

v3_sys.hName V3 temperature registers +6/-0

Name V3 temperature registers

• Defines V3 and V3A temperature configuration and measurement addresses.

src/hal/hisi/v3_sys.h

v4_hal.cIdentify HiSilicon V4 and name temperature registers +19/-4

Identify HiSilicon V4 and name temperature registers

• Adds V4-specific identification and replaces temperature-register literals with constants.

src/hal/hisi/v4_hal.c

v4_hal.hDeclare V4 platform identification +4/-0

Declare V4 platform identification

• Includes shared detection dependencies and exposes the V4 identifier.

src/hal/hisi/v4_hal.h

v4_sys.hName V4 temperature registers +7/-0

Name V4 temperature registers

• Defines V4 and V4A temperature configuration, measurement, and preparation constants.

src/hal/hisi/v4_sys.h

t31_hal.cMove Ingenic T31 detection into its HAL +32/-0

Move Ingenic T31 detection into its HAL

• Identifies the T31 generation and chip subtype, then registers its media callbacks and channel state.

src/hal/inge/t31_hal.c

t31_hal.hDeclare T31 platform identification +3/-0

Declare T31 platform identification

• Includes register-access dependencies and exposes the T31 identifier.

src/hal/inge/t31_hal.h

t31_sys.hName T31 detection registers and subtypes +13/-0

Name T31 detection registers and subtypes

• Defines the register addresses, generation value, and chip-type constants.

src/hal/inge/t31_sys.h

ak_hal.cMove Anyka identification into its HAL +28/-2

Move Anyka identification into its HAL

• Reads the chip revision, registers Anyka channel and video handling, and retains the required pthread library load. Names the watchdog-disable values.

src/hal/plus/ak_hal.c

ak_hal.hDeclare Anyka platform identification +5/-0

Declare Anyka platform identification

• Adds detection dependencies and the identification declaration.

src/hal/plus/ak_hal.h

ak_sys.hName Anyka chip and boot constants +9/-0

Name Anyka chip and boot constants

• Defines chip revision values and the watchdog-related boot register and magic value.

src/hal/plus/ak_sys.h

cvi_hal.cMove CV181x detection into its HAL +15/-0

Move CV181x detection into its HAL

• Detects the CVI procfs marker and registers channel state and media threads.

src/hal/plus/cvi_hal.c

cvi_hal.hDeclare CVI platform identification +2/-0

Declare CVI platform identification

• Exposes the CVI identification entry point.

src/hal/plus/cvi_hal.h

gm_hal.cMove Grain Media detection into its HAL +22/-0

Move Grain Media detection into its HAL

• Detects the VPD device, reads the chip version when available, and registers channel state and media threads.

src/hal/plus/gm_hal.c

gm_hal.hDeclare Grain Media platform identification +4/-0

Declare Grain Media platform identification

• Adds the filesystem-access dependency and identification declaration.

src/hal/plus/gm_hal.h

rk_hal.cMove Rockchip detection into its HAL +15/-0

Move Rockchip detection into its HAL

• Detects the Rockchip procfs marker and registers channel state and media threads.

src/hal/plus/rk_hal.c

rk_hal.hDeclare Rockchip platform identification +2/-0

Declare Rockchip platform identification

• Exposes the Rockchip identification entry point.

src/hal/plus/rk_hal.h

common.hExtract shared SigmaStar detection and temperature access +68/-0

Extract shared SigmaStar detection and temperature access

• Reads the series, memory, and package indicators for SigmaStar HALs and centralizes their temperature read.

src/hal/star/common.h

i3_hal.cMove Infinity3 detection into its HAL +20/-0

Move Infinity3 detection into its HAL

• Identifies supported MSC313/316/318 variants and registers the Infinity3 channel state.

src/hal/star/i3_hal.c

i3_hal.hDeclare Infinity3 platform identification +3/-0

Declare Infinity3 platform identification

• Adds register-access dependencies and exposes the Infinity3 identifier.

src/hal/star/i3_hal.h

i3_sys.hName Infinity3 chip ID values +6/-0

Name Infinity3 chip ID values

• Defines the chip-ID register, mask, and known model values.

src/hal/star/i3_sys.h

i6_hal.cIdentify Infinity6 variants locally +61/-0

Identify Infinity6 variants locally

• Moves Infinity6, Infinity6e, and Infinity6b0 model selection into the I6 HAL and delegates temperature readings to shared code.

src/hal/star/i6_hal.c

i6_hal.hDeclare Infinity6 identification and temperature APIs +4/-0

Declare Infinity6 identification and temperature APIs

• Includes SigmaStar common helpers and exposes I6 detection and temperature functions.

src/hal/star/i6_hal.h

i6c_hal.cIdentify Infinity6c locally +31/-0

Identify Infinity6c locally

• Selects Infinity6c chip naming from shared series, memory, and package data and delegates temperature readings.

src/hal/star/i6c_hal.c

i6c_hal.hDeclare Infinity6c identification and temperature APIs +4/-0

Declare Infinity6c identification and temperature APIs

• Includes SigmaStar common helpers and exposes I6C detection and temperature functions.

src/hal/star/i6c_hal.h

m6_hal.cIdentify Mercury6 locally +24/-0

Identify Mercury6 locally

• Detects the Mercury6 series, registers its media handlers, and delegates temperature readings to shared code.

src/hal/star/m6_hal.c

m6_hal.hDeclare Mercury6 identification and temperature APIs +4/-0

Declare Mercury6 identification and temperature APIs

• Includes SigmaStar common helpers and exposes M6 detection and temperature functions.

src/hal/star/m6_hal.h

support.cDelegate detection to platform HALs +21/-350

Delegate detection to platform HALs

• Replaces monolithic chip detection with architecture-ordered HAL identification calls. Delegates SigmaStar temperature readings to platform functions.

src/hal/support.c

support.hExpose V100 and identification dependencies +6/-4

Expose V100 and identification dependencies

• Includes the V100 HAL on ARMv6 and arranges shared support headers for delegated detection.

src/hal/support.h

Documentation (2) +40 / -37
README.mdList FH885xV100 platform capabilities +38/-36

List FH885xV100 platform capabilities

• Adds FH8852/FH8856 V100 to the support matrix and renumbers subsequent footnotes.

README.md

config.mdDocument lamp selection and absent sensors +2/-1

Document lamp selection and absent sensors

• Describes Fullhan lamp modes and the '999' sentinel for no IR sensor.

doc/config.md

Other (1) +1 / -0
divinus.yamlSet the default night lamp +1/-0

Set the default night lamp

• Adds 'lamp: ir' to the example night-mode configuration.

divinus.yaml

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (10) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Night-mode changes can hang the service 🐞 Bug ☼ Reliability
Description
night_thread falls through to the no-sensor loop when F1 gain detection is unavailable, but that
loop checks keepRunning rather than nightOn. With the documented default sensor pin of 999, an
API reconfiguration calls night_disable(), sets nightOn to zero, and waits indefinitely for that
loop to exit.
Code

src/night.c[83]

+    } else
Evidence
The new F1 branch falls through when gain detection is unavailable; the default pin selects a loop
that ignores the flag cleared before the join.

src/night.c[73-110]
src/night.c[148-153]
src/app_config.c[283-292]
src/server.c[1335-1336]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
On F1 devices without gain detection, the newly selected fallback reaches the no-sensor loop, which cannot be stopped by `night_disable()`.
## Fix Focus Areas
- src/night.c[73-110]
## Recommended Fix
Make the no-sensor loop observe `nightOn` as well as `keepRunning`, so disabling or reconfiguring night mode releases the join.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Newer Fullhan V210/V201 boards boot as V100 🐞 Bug ≡ Correctness
Description
When the PMU register read fails or reports a package code missing from the table, the
/proc/cpuinfo fallback in fh_identify returns F2 only if the name contains "V200". Otherwise it
returns F1 for any name starting with FH8852/FH8856, so FH8852V210, FH8856V210 and FH8856V201
are treated as V100, and FH8858V210/FH8858V201 come back as an unknown platform. Before this PR,
every "FH8" name mapped to F2, and the commit message says that running the wrong generation's HAL
hangs the SoC.
Code

src/hal/fhan/common.h[R82-86]

+            if (strstr(name, "V200"))
+                return HAL_PLATFORM_F2;
+            if (strstr(name, "V100") || !strncmp(name, "FH8852", 6) ||
+                !strncmp(name, "FH8856", 6))
+                return HAL_PLATFORM_F1;
Evidence
The fallback only checks for the "V200" substring before matching on the FH8852/FH8856 prefix. The
PMU table (lines 20-27) lists V210 and V201 packages as V200-family parts, and the old support.c
code mapped every FH8 name to HAL_PLATFORM_F2.

src/hal/fhan/common.h[14-27]
src/hal/fhan/common.h[80-90]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The string fallback in fh_identify classifies FH8852V210/FH8856V210/FH8856V201 as V100 (F1) and FH8858V2x0 as unknown, because it only checks for the "V200" substring.

## Fix Focus Areas
- src/hal/fhan/common.h[80-87]

## Recommended Fix
Return HAL_PLATFORM_F1 only when the name contains "V100". Treat any other name containing V2 (V200/V201/V210), or any other FH8 name, as HAL_PLATFORM_F2, which matches the behaviour before this PR.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. A register read can crash after the page fallback 🐞 Bug ☼ Reliability
Description
When the 64 KiB mmap fails with EPERM, hal_registry maps a single page and stores that
page-aligned address in loaded_offset, but later calls still compare their 64 KiB-aligned offset
against it. If the fallback page sits at a 64 KiB boundary, a later access elsewhere in the same 64
KiB window reuses the 4 KiB mapping and reads or writes past its end (SIGSEGV). If the page is not
64 KiB-aligned, every call instead unmaps and remaps.
Code

src/hal/tools.c[R303-305]

+            offset = addr & ~((unsigned int)page - 1);
+            size = (unsigned int)page;
+            mapped_area = mmap64(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, offset);
Evidence
offset = addr & 0xffff0000 is compared with loaded_offset to decide whether the mapping can be
reused. After the fallback, loaded_offset is page-aligned and loaded_size is one page, yet the
access mapped_area + (addr - offset) is never checked against loaded_size.

src/hal/tools.c[276-323]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
After the single-page EPERM fallback, hal_registry can reuse a 4 KiB mapping for addresses outside it, because the reuse test compares only the 64 KiB-aligned offset.

## Fix Focus Areas
- src/hal/tools.c[276-323]

## Recommended Fix
Reuse the cached mapping only when `addr >= loaded_offset && addr + 4 <= loaded_offset + loaded_size`. Otherwise munmap and remap, trying the 64 KiB window first and the page fallback second. Use the same condition for the munmap check at the top of the function.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. Configured light sensors are ignored 🐞 Bug ≡ Correctness
Description
night_thread selects F1 image-gain detection before checking app_config.adc_device. On a V100
device where gain detection is available, a configured ADC and its threshold never participate in
day/night switching.
Code

src/night.c[74]

+    if (plat == HAL_PLATFORM_F1 && f1_night_available()) {
Evidence
The gain branch precedes the ADC branch, although the ADC device and threshold are parsed from
configuration.

src/night.c[73-105]
src/app_config.c[376-401]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The F1 gain-detection branch overrides an explicitly configured ADC night sensor.
## Fix Focus Areas
- src/night.c[73-86]
## Recommended Fix
Use gain detection only when no explicit ADC or GPIO sensor is configured; preserve the existing configured-sensor paths.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Night lighting toggles an extra pin 🐞 Bug ≡ Correctness
Description
night_mode calls night_irled() as well as fh_lamp_enable() on F1, so its IR setting drives
both the generic configured GPIO and the Fullhan PWM lamp. When no generic LED pin is configured,
the default value 999 is still passed to gpio_write(); when a pin is configured, it is toggled in
addition to the selected Fullhan lamp.
Code

src/night.c[R55-57]

+            night_ircut(false);
+            night_irled((lamp & HAL_LIGHT_IR) != 0);
+            fh_lamp_enable(lamp);
Evidence
The new F1 branch invokes both controls, while the generic helper always writes its configured pin
and the Fullhan helper controls the lamps independently.

src/night.c[30-34]
src/night.c[40-59]
src/app_config.c[283-292]
src/hal/fhan/fh_lamp.c[15-21]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
F1 night-mode lamp control also writes the generic IR LED GPIO, including its unconfigured default.
## Fix Focus Areas
- src/night.c[40-59]
- src/hal/fhan/fh_lamp.c[15-21]
## Recommended Fix
Let the Fullhan lamp path control its hardware without calling `night_irled()` for an unconfigured or unrelated GPIO; retain coherent reported lamp state.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. V100 ignores custom sensor tuning 🐞 Bug ≡ Correctness
Description
sdk_start adds the F1 pipeline path but omits F1 from its later sensor_config loading dispatch.
When an operator supplies a custom tuning file, f1_pipeline_create() can load its built-in search
paths, but the configured file is never passed to the available f1_config_load() function.
Code

src/media.c[965]

+        case HAL_PLATFORM_F1:  ret = f1_pipeline_create(width, height, app_config.mirror, app_config.flip, framerate, app_config.antiflicker); break;
Evidence
F1 has a tuning-file loader and startup support, but the existing configured-file dispatch names
only F2 among Fullhan platforms.

src/hal/fhan/f1_hal.c[291-324]
src/hal/fhan/f1_hal.c[432-438]
src/media.c[1029-1044]
doc/config.md[5-8]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new F1 startup path never applies a configured `sensor_config` file despite providing an F1 tuning loader.
## Fix Focus Areas
- src/media.c[1029-1044]
- src/hal/fhan/f1_hal.c[291-324]
## Recommended Fix
Add F1 to the guarded post-start configuration dispatch and pass `app_config.sensor_config` to `f1_config_load()` when the configured file exists.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View review recommended (3)
7. V100 snapshots ignore request options 🐞 Bug ≡ Correctness
Description
jpeg_get dispatches F1 snapshots using only the channel index and output buffer, leaving the
request's dimensions and quality unused. Requests with different width, height, or qfactor values
therefore capture from the same JPEG encoder configured once from application defaults.
Code

src/jpeg.c[139]

+        case HAL_PLATFORM_F1:  ret = f1_video_snapshot_grab(jpeg_index, jpeg); break;
Evidence
The server parses and forwards these request parameters, but F1 receives none of them and its JPEG
channel was configured from fixed application settings.

src/server.c[827-866]
src/server.c[428-428]
src/jpeg.c[24-51]
src/jpeg.c[117-141]
src/hal/fhan/f1_hal.c[735-742]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
F1 snapshot requests cannot affect the dimensions or quality supplied by the endpoint.
## Fix Focus Areas
- src/jpeg.c[117-141]
- src/hal/fhan/f1_hal.c[683-802]
- src/hal/fhan/f1_hal.c[834-947]
## Recommended Fix
Pass supported per-request settings into the F1 snapshot path and apply them before capture; explicitly reject settings the encoder cannot support rather than silently ignoring them.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Missing audio symbol crashes audio startup 🐞 Bug ☼ Reliability
Description
f1_aud_load returns failure after dlopen has set handle but before every function pointer is
resolved, and f1_hal_init only logs a warning without unloading. f1_audio_init checks only
f1_aud.handle, so a libacw_mpi missing, say, FH_AC_AI_MICIN_SetVol gets past that check and
calls a NULL function pointer instead of returning an error.
Code

src/hal/fhan/f1_hal.c[R76-77]

+    if (f1_aud_load(&f1_aud))
+        HAL_WARNING("f1_hal", "Audio library unavailable, audio disabled\n");
Evidence
The handle is assigned at f1_aud.h line 35, before any symbol loads. Each later failure returns
EXIT_FAILURE and leaves handle set, while f1_audio_init calls fnInit, fnSetConfig, fnEnable,
fnSetMicVolume and fnSetVolume directly.

src/hal/fhan/f1_aud.h[34-71]
src/hal/fhan/f1_hal.c[76-121]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A partial audio library load leaves f1_aud.handle set while some function pointers are NULL, and f1_audio_init then calls through them.

## Fix Focus Areas
- src/hal/fhan/f1_hal.c[76-77]

## Recommended Fix
When f1_aud_load fails, call f1_aud_unload(&f1_aud) before logging the warning, so that the handle check in f1_audio_init rejects audio cleanly.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. Lamp setting is ignored on V200 Fullhan 🐞 Bug ≡ Correctness
Description
The new night_mode branch that honours app_config.night_lamp through fh_lamp_enable only runs
when plat == HAL_PLATFORM_F1. FH885xV200 cameras still take the generic path, which never drives
the PWM illuminators. The docs present lamp as a Fullhan setting, so V200 users who set white or
ir,white get no change.
Code

src/night.c[R40-42]

+#if defined(__arm__) && !defined(__ARM_PCS_VFP) && __ARM_ARCH == 6
+    if (plat == HAL_PLATFORM_F1) {
+        hal_light lamp = app_config.night_lamp;
Evidence
doc/config.md describes lamp as "Illuminator mode on Fullhan". fh_lamp is shared by both
generations, but on F2 it is only called once, to switch the lamps off in f2_pipeline_create, and
night.c handles only F1.

src/night.c[38-66]
doc/config.md[31-31]
src/hal/fhan/f2_hal.c[410-416]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `lamp` night-mode setting is only applied on HAL_PLATFORM_F1, even though it is documented as a Fullhan setting and fh_lamp_enable is shared with F2.

## Fix Focus Areas
- src/night.c[40-61]
- doc/config.md[31-31]

## Recommended Fix
Change the condition to `plat == HAL_PLATFORM_F1 || plat == HAL_PLATFORM_F2` so V200 also gets the lamp handling. If that is not intended, update the documentation to say the setting is V100-only.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

10. Sensor pins above 127 read the wrong GPIO 🐞 Bug ≡ Correctness
Description
The ir_sensor_pin limit went from PIN_MAX (95) to 999 so that 999 can mean "no sensor", but
every value from 96 to 998 is now accepted too. gpio_read takes a char pin, so a configured
value above 127 is truncated and the night thread polls an unrelated or invalid line.
Code

src/app_config.c[R360-361]

+            &ini, "night_mode", "ir_sensor_pin", 0, 999, /* 999 = no sensor */
            &app_config.ir_sensor_pin);
Evidence
night.c treats only 999 as the sentinel and otherwise calls gpio_read(app_config.ir_sensor_pin,
...), and gpio.c declares the pin parameter as char.

src/app_config.c[357-362]
src/gpio.c[123-130]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Widening the range to 999 makes pins 96-998 valid, and they get truncated to char later.

## Fix Focus Areas
- src/app_config.c[357-362]

## Recommended Fix
Parse into a temporary value. Accept it only if it is within 0..PIN_MAX or exactly 999, and otherwise keep the default of 999.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
Review mode: Auto: 🧠 Deep: Large cross-platform HAL addition spans many independent logic paths.

Grey Divider

Tip of the day
💡 Did you know, you can enable the Remediation agent and Qodo fixes findings in a dedicated fix PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/night.c
else if (state != applied) { night_mode(state); applied = state; }
usleep(40000);
}
} else

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Night-mode changes can hang the service 🐞 Bug ☼ Reliability

night_thread falls through to the no-sensor loop when F1 gain detection is unavailable, but that
loop checks keepRunning rather than nightOn. With the documented default sensor pin of 999, an
API reconfiguration calls night_disable(), sets nightOn to zero, and waits indefinitely for that
loop to exit.
Agent Prompt
## Issue description
On F1 devices without gain detection, the newly selected fallback reaches the no-sensor loop, which cannot be stopped by `night_disable()`.
## Fix Focus Areas
- src/night.c[73-110]
## Recommended Fix
Make the no-sensor loop observe `nightOn` as well as `keepRunning`, so disabling or reconfiguring night mode releases the join.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/night.c
night_mode(night_mode_on());

#if defined(__arm__) && !defined(__ARM_PCS_VFP) && __ARM_ARCH == 6
if (plat == HAL_PLATFORM_F1 && f1_night_available()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

4. Configured light sensors are ignored 🐞 Bug ≡ Correctness

night_thread selects F1 image-gain detection before checking app_config.adc_device. On a V100
device where gain detection is available, a configured ADC and its threshold never participate in
day/night switching.
Agent Prompt
## Issue description
The F1 gain-detection branch overrides an explicitly configured ADC night sensor.
## Fix Focus Areas
- src/night.c[73-86]
## Recommended Fix
Use gain detection only when no explicit ADC or GPIO sensor is configured; preserve the existing configured-sensor paths.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/night.c
Comment on lines +55 to +57
night_ircut(false);
night_irled((lamp & HAL_LIGHT_IR) != 0);
fh_lamp_enable(lamp);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

5. Night lighting toggles an extra pin 🐞 Bug ≡ Correctness

night_mode calls night_irled() as well as fh_lamp_enable() on F1, so its IR setting drives
both the generic configured GPIO and the Fullhan PWM lamp. When no generic LED pin is configured,
the default value 999 is still passed to gpio_write(); when a pin is configured, it is toggled in
addition to the selected Fullhan lamp.
Agent Prompt
## Issue description
F1 night-mode lamp control also writes the generic IR LED GPIO, including its unconfigured default.
## Fix Focus Areas
- src/night.c[40-59]
- src/hal/fhan/fh_lamp.c[15-21]
## Recommended Fix
Let the Fullhan lamp path control its hardware without calling `night_irled()` for an unconfigured or unrelated GPIO; retain coherent reported lamp state.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/media.c
case HAL_PLATFORM_V3: ret = v3_pipeline_create(); break;
case HAL_PLATFORM_V4: ret = v4_pipeline_create(); break;
#if __ARM_ARCH == 6
case HAL_PLATFORM_F1: ret = f1_pipeline_create(width, height, app_config.mirror, app_config.flip, framerate, app_config.antiflicker); break;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

6. V100 ignores custom sensor tuning 🐞 Bug ≡ Correctness

sdk_start adds the F1 pipeline path but omits F1 from its later sensor_config loading dispatch.
When an operator supplies a custom tuning file, f1_pipeline_create() can load its built-in search
paths, but the configured file is never passed to the available f1_config_load() function.
Agent Prompt
## Issue description
The new F1 startup path never applies a configured `sensor_config` file despite providing an F1 tuning loader.
## Fix Focus Areas
- src/media.c[1029-1044]
- src/hal/fhan/f1_hal.c[291-324]
## Recommended Fix
Add F1 to the guarded post-start configuration dispatch and pass `app_config.sensor_config` to `f1_config_load()` when the configured file exists.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/jpeg.c
case HAL_PLATFORM_V3: ret = v3_video_snapshot_grab(jpeg_index, jpeg); break;
case HAL_PLATFORM_V4: ret = v4_video_snapshot_grab(jpeg_index, jpeg); break;
#if __ARM_ARCH == 6
case HAL_PLATFORM_F1: ret = f1_video_snapshot_grab(jpeg_index, jpeg); break;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

7. V100 snapshots ignore request options 🐞 Bug ≡ Correctness

jpeg_get dispatches F1 snapshots using only the channel index and output buffer, leaving the
request's dimensions and quality unused. Requests with different width, height, or qfactor values
therefore capture from the same JPEG encoder configured once from application defaults.
Agent Prompt
## Issue description
F1 snapshot requests cannot affect the dimensions or quality supplied by the endpoint.
## Fix Focus Areas
- src/jpeg.c[117-141]
- src/hal/fhan/f1_hal.c[683-802]
- src/hal/fhan/f1_hal.c[834-947]
## Recommended Fix
Pass supported per-request settings into the F1 snapshot path and apply them before capture; explicitly reject settings the encoder cannot support rather than silently ignoring them.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/hal/fhan/common.h
Comment on lines +82 to +86
if (strstr(name, "V200"))
return HAL_PLATFORM_F2;
if (strstr(name, "V100") || !strncmp(name, "FH8852", 6) ||
!strncmp(name, "FH8856", 6))
return HAL_PLATFORM_F1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Newer fullhan v210/v201 boards boot as v100 🐞 Bug ≡ Correctness

When the PMU register read fails or reports a package code missing from the table, the
/proc/cpuinfo fallback in fh_identify returns F2 only if the name contains "V200". Otherwise it
returns F1 for any name starting with FH8852/FH8856, so FH8852V210, FH8856V210 and FH8856V201
are treated as V100, and FH8858V210/FH8858V201 come back as an unknown platform. Before this PR,
every "FH8" name mapped to F2, and the commit message says that running the wrong generation's HAL
hangs the SoC.
Agent Prompt
## Issue description
The string fallback in fh_identify classifies FH8852V210/FH8856V210/FH8856V201 as V100 (F1) and FH8858V2x0 as unknown, because it only checks for the "V200" substring.

## Fix Focus Areas
- src/hal/fhan/common.h[80-87]

## Recommended Fix
Return HAL_PLATFORM_F1 only when the name contains "V100". Treat any other name containing V2 (V200/V201/V210), or any other FH8 name, as HAL_PLATFORM_F2, which matches the behaviour before this PR.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/hal/tools.c
Comment on lines +303 to +305
offset = addr & ~((unsigned int)page - 1);
size = (unsigned int)page;
mapped_area = mmap64(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, offset);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. A register read can crash after the page fallback 🐞 Bug ☼ Reliability

When the 64 KiB mmap fails with EPERM, hal_registry maps a single page and stores that
page-aligned address in loaded_offset, but later calls still compare their 64 KiB-aligned offset
against it. If the fallback page sits at a 64 KiB boundary, a later access elsewhere in the same 64
KiB window reuses the 4 KiB mapping and reads or writes past its end (SIGSEGV). If the page is not
64 KiB-aligned, every call instead unmaps and remaps.
Agent Prompt
## Issue description
After the single-page EPERM fallback, hal_registry can reuse a 4 KiB mapping for addresses outside it, because the reuse test compares only the 64 KiB-aligned offset.

## Fix Focus Areas
- src/hal/tools.c[276-323]

## Recommended Fix
Reuse the cached mapping only when `addr >= loaded_offset && addr + 4 <= loaded_offset + loaded_size`. Otherwise munmap and remap, trying the 64 KiB window first and the page fallback second. Use the same condition for the munmap check at the top of the function.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/hal/fhan/f1_hal.c
Comment on lines +76 to +77
if (f1_aud_load(&f1_aud))
HAL_WARNING("f1_hal", "Audio library unavailable, audio disabled\n");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

8. Missing audio symbol crashes audio startup 🐞 Bug ☼ Reliability

f1_aud_load returns failure after dlopen has set handle but before every function pointer is
resolved, and f1_hal_init only logs a warning without unloading. f1_audio_init checks only
f1_aud.handle, so a libacw_mpi missing, say, FH_AC_AI_MICIN_SetVol gets past that check and
calls a NULL function pointer instead of returning an error.
Agent Prompt
## Issue description
A partial audio library load leaves f1_aud.handle set while some function pointers are NULL, and f1_audio_init then calls through them.

## Fix Focus Areas
- src/hal/fhan/f1_hal.c[76-77]

## Recommended Fix
When f1_aud_load fails, call f1_aud_unload(&f1_aud) before logging the warning, so that the handle check in f1_audio_init rejects audio cleanly.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/night.c
Comment on lines +40 to +42
#if defined(__arm__) && !defined(__ARM_PCS_VFP) && __ARM_ARCH == 6
if (plat == HAL_PLATFORM_F1) {
hal_light lamp = app_config.night_lamp;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

9. Lamp setting is ignored on v200 fullhan 🐞 Bug ≡ Correctness

The new night_mode branch that honours app_config.night_lamp through fh_lamp_enable only runs
when plat == HAL_PLATFORM_F1. FH885xV200 cameras still take the generic path, which never drives
the PWM illuminators. The docs present lamp as a Fullhan setting, so V200 users who set white or
ir,white get no change.
Agent Prompt
## Issue description
The `lamp` night-mode setting is only applied on HAL_PLATFORM_F1, even though it is documented as a Fullhan setting and fh_lamp_enable is shared with F2.

## Fix Focus Areas
- src/night.c[40-61]
- doc/config.md[31-31]

## Recommended Fix
Change the condition to `plat == HAL_PLATFORM_F1 || plat == HAL_PLATFORM_F2` so V200 also gets the lamp handling. If that is not intended, update the documentation to say the setting is V100-only.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/app_config.c
Comment on lines +360 to 361
&ini, "night_mode", "ir_sensor_pin", 0, 999, /* 999 = no sensor */
&app_config.ir_sensor_pin);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Informational

10. Sensor pins above 127 read the wrong gpio 🐞 Bug ≡ Correctness

The ir_sensor_pin limit went from PIN_MAX (95) to 999 so that 999 can mean "no sensor", but
every value from 96 to 998 is now accepted too. gpio_read takes a char pin, so a configured
value above 127 is truncated and the night thread polls an unrelated or invalid line.
Agent Prompt
## Issue description
Widening the range to 999 makes pins 96-998 valid, and they get truncated to char later.

## Fix Focus Areas
- src/app_config.c[357-362]

## Recommended Fix
Parse into a temporary value. Accept it only if it is within 0..PIN_MAX or exactly 999, and otherwise keep the default of 999.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@wberube
wberube deleted the fhan-v100 branch October 25, 2026 04:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants