Skip to content

fix(v4l2): fix str, rect and bitmask logging - #367

Merged
mryel00 merged 10 commits into
mainsail-crew:developfrom
mryel00:fix/v4l2_rect_bitmask
Oct 4, 2026
Merged

mryel00 merged 10 commits into
mainsail-crew:developfrom
mryel00:fix/v4l2_rect_bitmask

Conversation

@mryel00

@mryel00 mryel00 commented Sep 14, 2026

Copy link
Copy Markdown
Member

This fixes the logging of the str, rect and bitmask types in the v4l2 module.
The wrong logging can be seen here: #366 (comment)
The logging is expected to look like this now:

region_of_interest_rectangle 0x00981ae1 (rect)   : value=(0,0)/3844x2164 flags=has-payload, has-min-max
region_of_interest_auto_ctrls 0x00981ae2 (bitmask): max=0x00000001 default=0x00000001 value=0x00000001 flags=has-min-max

A side effect of this PR is a fix for the logging of min and max for the menu type, similar to #366, as they are needed for str and bitmask too.

Signed-off-by: Patrick Gehrsitz <github@mryel.de>
@mryel00
mryel00 requested review from meteyou and a lite review from Copilot September 14, 2026 15:04
@mryel00

mryel00 commented Sep 14, 2026 •

Copy link
Copy Markdown
Member Author

@8023 could you please test this PR and share the controls output of the log?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Critical Python compatibility and ctypes pointer issues remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Fixes V4L2 logging for string, rectangle, bitmask, and menu controls.

Changes:

  • Adds rectangle and extended-control payload support.
  • Formats compound and hexadecimal control values.
  • Generalizes UVC control metadata logging.
File summaries
File Summary
crowsnest/v4l2/utils.py Adds rectangle mapping and hex formatting.
crowsnest/v4l2/raw.py Adds rectangle and extended-control definitions.
crowsnest/v4l2/ctl.py Parses metadata and retrieves compound control values.
crowsnest/v4l2/constants.py Defines the rectangle control type.
crowsnest/camera/types/uvc.py Updates control logging and value typing.
Review details

Suppressed comments (3)

crowsnest/v4l2/ctl.py:269

  • Formatting every non-payload value as a string changes the established numeric return type. _brokenfocus() compares this result with int(focus_absolute_conf) (components/streamer/ustreamer.py:142), so a configured focus_absolute is now treated as different on every startup and the corrective branch always runs. Preserve integers for scalar controls and use a mixed return annotation for payload controls.
            return f"{ctrl.value}"

crowsnest/v4l2/ctl.py:246

  • ioctl_safe() catches OSError and returns -1; it never raises into this try. Since this return value is ignored, a failed VIDIOC_G_EXT_CTRLS leaves the zero-initialized payload buffer and the code logs an empty or zero rectangle/string as if it were the current value. Check the ioctl result and return None on -1 before decoding.
            utils.ioctl_safe(fd, raw.VIDIOC_G_EXT_CTRLS, ctrls)

crowsnest/v4l2/ctl.py:50

  • A string control's default_value is not a printable/default setting; the V4L2 control logger prints min, max, and step for strings and omits default. With this addition every string is logged as default=0 while step is missing, which makes the new string logging inaccurate. Add STRING to the step condition instead and keep it out of this default whitelist.
        constants.V4L2_CTRL_TYPE_STRING,
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread crowsnest/v4l2/ctl.py Resolved
Comment thread crowsnest/v4l2/raw.py Resolved
Signed-off-by: Patrick Gehrsitz <github@mryel.de>
Signed-off-by: Patrick Gehrsitz <github@mryel.de>
Signed-off-by: Patrick Gehrsitz <github@mryel.de>
@8023

8023 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Thanks for following up on this properly, instead of leaving the guard from #366 as the fix. Heads up: I used AI to help me write this comment.

Tested on the same machine as #366 . The full log in attached. The rect and bitmask controls now match v4l2-ctl.

A small difference: v4l2-ctl on this machine prints the bitmask value as decimal, only max and default are hex:

region_of_interest_auto_ctrls 0x00981ae2 (bitmask): max=0x00000001 default=0x00000001 value=1 flags=has-min-max

Regression: brokenfocus now triggers on every start

With v4l2ctl: focus_absolute=200,... in the config I get this on every start:

focus_absolute (int)               : min=0 max=800 step=1 default=150 value=200 flags=has-min-max
WARN: [cam 1]: Detected 'brokenfocus' device.
INFO: [cam 1]: Try to set to configured Value.

The value is already 200. I had several earlier starts with the same config and no warning. The cause is that get_control_cur_value_with_qc() now returns f"{ctrl.value}", while _brokenfocus() still compares the result against int(focus_absolute_conf). "200" != 200 is always true.

Suggestion: keep returning int for scalar controls and do the string formatting in get_controls_string(). The same goes for the hex strings stored in parse_qc. That way callers always get raw values back.

Two more things from reading the code. My camera has no controls of these types, so I couldn't test either:

  • ioctl_safe() swallows the OSError, and its return value is ignored here. The except OSError only covers os.open. If VIDIOC_G_EXT_CTRLS fails, we log a zeroed buffer like (0,0)/0x0 as if it were the real value. The same happens for write-only controls such as UVC pan_reset/tilt_reset: G_CTRL returns EACCES, and they get logged as value=0.
  • For str controls, v4l2-ctl prints min max step and no default. This PR adds default (always 0) and leaves out step.

3dprinter-60cm_crowsnest.txt

@mryel00

mryel00 commented Sep 15, 2026

Copy link
Copy Markdown
Member Author

Thanks for the small review and the output. Seems like I have to fix the intendation (currently just a magic number 😂)

v4l2-ctl on this machine prints the bitmask value as decimal, only max and default are hex

I saw this in your output too. But if you look at the v4l2-ctl code, it should print it as hex too, at least in the latest version:
https://git.linuxtv.org/v4l-utils.git/tree/utils/v4l2-ctl/v4l2-ctl-common.cpp#n644
Therefore I just copied the latest behavior for this.

Regression: brokenfocus now triggers on every start

Thanks for pointing out the regression. I already thought that I introduced a bug, but I couldn't find it 😅

For str controls, v4l2-ctl prints min max step and no default. This PR adds default (always 0) and leaves out step.

Good catch ^^

ioctl_safe() swallows the OSError

This is true but this is nothing new introduced by this PR. This would need a separate fix.
But this is only a best effort implementation for v4l2. I do not intend to fully mimic v4l2-ctl. Just the basic things that most cameras got and maybe some exotic stuff that people report as a problem with their owned camera.

Signed-off-by: Patrick Gehrsitz <github@mryel.de>
Signed-off-by: Patrick Gehrsitz <github@mryel.de>
@mryel00

mryel00 commented Sep 15, 2026

Copy link
Copy Markdown
Member Author

The string and brokenfocus should be fixed now. Please test them again.
I decided against an integer for bitmask as it would result in more complex logging code without any real use case that I can think of for the integer value (at least within the scope of Crowsnest)

Signed-off-by: Patrick Gehrsitz <github@mryel.de>
Signed-off-by: Patrick Gehrsitz <github@mryel.de>
Signed-off-by: Patrick Gehrsitz <github@mryel.de>
@8023

8023 commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Retested with c44d142. The config and v4l2-ctl output are the same as last time, so I'm not pasting them again. The startup log is attached: 3dprinter-60cm_crowsnest.txt

  • brokenfocus: fixed. No warning on startup, and focus_absolute stays at 200.
  • Alignment: fixed. All colons now line up, including region_of_interest_auto_ctrls (bitmask).
  • str controls: not tested. My camera doesn't have any.

One small thing in get_controls_string(): max() has no default=0. If a UVC device reports no controls at all, control_values stays empty and max() raises ValueError: max() arg is an empty sequence. That's rare, but libcamera.py:72 already handles the empty case, so it would be nice to cover it here too:

max_len = max(
    (len(f"{c} ({d['type']})") for controls in self.control_values.values() for c, d in controls.items()),
    default=0,
)

Thanks for the quick fixes!

Signed-off-by: Patrick Gehrsitz <github@mryel.de>
@mryel00

mryel00 commented Sep 15, 2026

Copy link
Copy Markdown
Member Author

hope you don't mind me sharing

Please keep off-topic stuff out of the issues. You can share timelapses and similar things in our Discord in the i-made-a-timelapse channel.

If a UVC device reports no controls at all

I'm not sure if there are any UVC devices without any controls at all, but it's a good point to add some fallback, even if it just occurs due to some weird communication error.

Thanks for the quick fixes!

Thanks for the quick review and testing!

@mryel00
mryel00 merged commit a5e8802 into mainsail-crew:develop Oct 4, 2026
4 checks passed
@mryel00
mryel00 deleted the fix/v4l2_rect_bitmask branch October 4, 2026 14:09
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.

4 participants