hal: add Fullhan FH8852/FH8856 (V100) support - #43
Conversation
A HAL for the Fullhan V100 generation (ARM1176, ARMv6), driving the vendor SDK's libdsp/libisp/libvmm through dlopen, with a GC4653 sensor driver. Identification is by chip_name in /proc/driver/chip, which is where the vendor kernel reports FH8852/FH8856; the platform is gated on __ARM_ARCH == 6 so no other ARM build changes. Notable points, all found on hardware and commented at the point of use: - Video frames are copied once out of the SDK's uncached DMA buffer. Every pass over it reads at bus speed, and a 300 KB keyframe cost about 400 ms of CPU. - The HEVC encoder bundles VPS, SPS and PPS into the IDR entry, so entries are split on start codes for the consumers that trust per-NALU boundaries. - H.264 High profile is rejected by the encoder (0x19d) and would leave the channel closed, so every profile maps to Main. - There is no FH_VENC_DestroyChn; a channel's pool lives until FH_SYS_Exit, so channels are created once with both codecs reserved and switched afterwards. - gpio: the exported line's sysfs directory is GPIO<n> on these kernels rather than gpio<n>; probed and cached. The same commit corrects three open() error checks that tested !fd rather than fd < 0. - quirks: the Fullhan ISP library exports its own isp_malloc(), which the trampoline would shadow under -rdynamic, so it is left out of ARMv6 builds. - An audio init failure is a warning rather than fatal on this platform: the SoC is watchdog-guarded and aborting the SDK start means a reboot loop.
PR Summary by QodoAdd Fullhan FH8852/FH8856 V100 HAL support
AI Description
Diagram
High-Level Assessment
Files changed (23)
|
Code Review by Qodo
1.
|
| if (_fh_mjpeg_len > jpeg->length) { | ||
| jpeg->data = realloc(jpeg->data, _fh_mjpeg_len); | ||
| jpeg->length = _fh_mjpeg_len; | ||
| } | ||
| memcpy(jpeg->data, _fh_mjpeg_cache, _fh_mjpeg_len); |
There was a problem hiding this comment.
3. Unchecked snapshot reallocations 🐞 Bug ☼ Reliability
The snapshot paths replace jpeg->data directly with realloc() and update its capacity without checking for failure. Under memory pressure this loses the existing buffer and passes NULL to memcpy(), crashing snapshot handling.
Agent Prompt
## Issue description
All snapshot buffer expansions must preserve the old pointer until `realloc()` succeeds and return a failure without copying when allocation fails. Update capacity only after successful allocation.
## Issue Context
The MJPEG fallback, JPEG output, and NALU aggregation branches all directly assign `realloc()` results to `jpeg->data`.
## Fix Focus Areas
- src/hal/fh/fh_hal.c[842-853]
- src/hal/fh/fh_hal.c[884-900]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
fh_osd_clear() derived its clipped width from rect.x before checking rect.x was inside the plane. hal_rect.x is an unsigned short and OSD positions are only range-checked against SHRT_MAX, so a region placed past the frame wrapped _fh_snr_dim.width - rect.x and memset most of memory. The rectangle is now rejected up front and the width computed once. fh_region_setbitmap() scaled a region's position from main-stream to sensor coordinates but copied its bitmap at the original size, so whenever the main stream was smaller than the sensor the overlay was placed for one resolution and drawn at another. The bitmap is now sampled nearest neighbour through the same ratio, and the stored clear bounds match what was drawn. fh_region_create() took an opacity and ignored it while the plane alpha stayed at 255. The hardware has one alpha for the whole graphics plane and ARGB1555 carries only an opaque/transparent bit per pixel, so a per-region value cannot be honoured individually; the highest opacity among active regions is applied to the plane, which is exact for the usual single region and never leaves one more transparent than configured. The three snapshot buffer growths assigned realloc() straight to jpeg->data, losing the old buffer and memcpy()ing to NULL under memory pressure. They now keep the old pointer until the allocation succeeds and fail the snapshot otherwise. night_mode.lamp was read by the unbounded parse_param_value() into an eight-byte field, so a longer configured value overwrote neighbouring AppConfig members at startup. It is parsed into a temporary and accepted only as ir, white or none.
Adds src/hal/fh: a HAL for the Fullhan FH8852/FH8856 V100 generation (ARM1176 softfloat, kernel 3.0.8, SDK V1.2.0 "OSDRV" libraries libdsp/ libisp/libispcore/libvmm/libmipi/libadvapi/libacw_mpi). The SDK ships as binary-only shared objects without headers; the interface was recovered from the libraries and a vendor application that statically links the same SDK, and verified on an Asecam/Vatilon PB1 (FH8856 + GC4653). - fh_sys/fh_vpss/fh_venc/fh_isp/fh_aud: dlopen wrappers for the MPI subset - fh_snr_gc4653: userspace GC4653 driver (the ISP calls back into a sensor op table; registers go over /dev/i2c-0) - H.264 and H.265 over RTSP, MJPEG, JPEG snapshots, audio capture, OSD via the VPU graphic plane (ARGB1555 at sensor resolution) - anti-flicker via the AE flicker command; SmartIR image-gain day/night detection wired into night mode (no external light sensor needed) - the VPU exposes two scaler channels (main + one sub); the JPEG snapshot is taken from the MJPEG sub-stream when MJPEG is enabled, mirroring the vendor - fh_compat: getifaddrs() over SIOCGIFCONF; gpio.c resolves GPIO<n> vs gpio<n> sysfs node naming (fh kernels use uppercase) - server: do not crash on an OSD POST without a Content-Type header - platform detection via /proc/driver/chip; built only for ARMv6 targets Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Epx86cKNLr14TY4B41nq89 Includes the fixes from the upstream review of the three PRs this branch is split into (OpenIPC/divinus OpenIPC#41, OpenIPC#42, OpenIPC#43): stage-aware rollback on media init failure, the RTCP bounds check before indexing, validated audio API ranges, interleaved flush for audio-only sessions, a latched RTSP audio codec, exact 8 kHz G.711 resampling, bounded config parsing for rtsp.audio_codec and night_mode.lamp, JSON escaping in the new endpoints, OSD clipping and bitmap scaling, per-region OSD opacity, and checked snapshot reallocations.
Adds src/hal/fh: a HAL for the Fullhan FH8852/FH8856 V100 generation (ARM1176 softfloat, kernel 3.0.8, SDK V1.2.0 "OSDRV" libraries libdsp/ libisp/libispcore/libvmm/libmipi/libadvapi/libacw_mpi). The SDK ships as binary-only shared objects without headers; the interface was recovered from the libraries and a vendor application that statically links the same SDK, and verified on an Asecam/Vatilon PB1 (FH8856 + GC4653). - fh_sys/fh_vpss/fh_venc/fh_isp/fh_aud: dlopen wrappers for the MPI subset - fh_snr_gc4653: userspace GC4653 driver (the ISP calls back into a sensor op table; registers go over /dev/i2c-0) - H.264 and H.265 over RTSP, MJPEG, JPEG snapshots, audio capture, OSD via the VPU graphic plane (ARGB1555 at sensor resolution) - anti-flicker via the AE flicker command; SmartIR image-gain day/night detection wired into night mode (no external light sensor needed) - the VPU exposes two scaler channels (main + one sub); the JPEG snapshot is taken from the MJPEG sub-stream when MJPEG is enabled, mirroring the vendor - fh_compat: getifaddrs() over SIOCGIFCONF; gpio.c resolves GPIO<n> vs gpio<n> sysfs node naming (fh kernels use uppercase) - server: do not crash on an OSD POST without a Content-Type header - platform detection via /proc/driver/chip; built only for ARMv6 targets Claude-Session: https://claude.ai/code/session_01Epx86cKNLr14TY4B41nq89 Includes the fixes from the upstream review of the three PRs this branch is split into (OpenIPC/divinus OpenIPC#41, OpenIPC#42, OpenIPC#43): stage-aware rollback on media init failure, the RTCP bounds check before indexing, validated audio API ranges, interleaved flush for audio-only sessions, a latched RTSP audio codec, exact 8 kHz G.711 resampling, bounded config parsing for rtsp.audio_codec and night_mode.lamp, JSON escaping in the new endpoints, OSD clipping and bitmap scaling, per-region OSD opacity, and checked snapshot reallocations.
a77c369 to
1e92d52
Compare
A HAL for the Fullhan V100 generation (FH8852/FH8856, ARM1176, ARMv6), driving the vendor SDK's
libdsp/libisp/libvmmthroughdlopen, with a GalaxyCore GC4653 sensor driver. There is no public SDK header set for these parts; the interfaces here were derived from the vendor application's behaviour and verified on hardware.Identification is by
chip_namein/proc/driver/chip, where the vendor kernel reportsFH8852/FH8856. The whole platform is gated on__ARM_ARCH == 6, so no other ARM build changes.Note on the SoC generation.
FH8856onplat_id 0x17092901is the V100 part (pkg_id & 0xF == 0xD);FH8856V200is a different platform id entirely. Building this board as V200 hangs the SoC infh_pinctrl_init_devices(), misreads PLL2 and corrupts the console baud — worth stating because the naming invites the mistake.Points worth a reviewer's attention, each commented at the point of use:
FH_VENC_SetChnAttrwith0x19dand leaves the channel closed, so every profile maps to Main (77), as the vendor application does.FH_VENC_DestroyChn; a channel's memory pool lives untilFH_SYS_Exitand a secondCreateChnfails with-0x3f3. Channels are therefore created once with both codecs reserved and reconfigured afterwards.gpio: the exported line's sysfs directory isGPIO<n>on these kernels rather thangpio<n>; probed once and cached. The same change corrects threeopen()error checks that tested!fdinstead offd < 0.quirks: the Fullhan ISP library exports its ownisp_malloc(), which the HiSilicon trampoline would shadow under-rdynamic, so it is left out of ARMv6 builds.Testing
Built for
fh8856v100_liteand running from flash on three Fullhan FH8856 cameras (Vatilon PB1 / Asecam, GC4653): RTSP, ONVIF, the web UI, full-resolution snapshots, IR-cut switching and day/night. This branch is build-tested on its own; the hardware runs the combined branch it was split from, which is these three PRs together.Depends on the two companion PRs only for merge order, not for compilation.