-
Notifications
You must be signed in to change notification settings - Fork 6.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
drivers: video: introduce "GET" sub-operations #78603
base: main
Are you sure you want to change the base?
Conversation
There are various ways that the controls can be implemented in the drivers, such as the image sensors: Split functions for every controls. static int sensor_get_ctrl_exposure(const struct device *dev, uint32_t cid, uint32_t *value)
{
const struct sensor_config *cfg = dev->config;
uint16_t u16;
int ret;
switch (cid & VIDEO_CTRL_GET_MASK) {
case VIDEO_CTRL_GET_CUR:
ret = sensor_read_reg(&cfg->i2c, SENSOR_EXPOSURE_REG, &u16, 2);
*value = u16;
return ret;
case VIDEO_CTRL_GET_MIN:
*(uint32_t *)value = 0;
return 0;
case VIDEO_CTRL_GET_MAX:
*(uint32_t *)value = 320;
return 0;
case VIDEO_CTRL_GET_DEF:
*(uint32_t *)value = 9;
return 0;
default:
return -EINVAL;
}
}
static int sensor_get_ctrl(const struct device *dev, unsigned int cid, void *value)
{
switch (cid & ~VIDEO_GET_MASK) {
case VIDEO_CID_CAMERA_EXPOSURE:
return sensor_get_ctrl_exposure(dev, cid, value);
default:
return -ENOTSUP;
}
} Everything inline. static int sensor_get_ctrl(const struct device *dev, unsigned int cid, void *value)
{
const struct sensor_config *cfg = dev->config;
uint16_t u16;
int ret;
switch (cid) {
case VIDEO_CTRL_GET_CUR | VIDEO_CID_CAMERA_EXPOSURE:
ret = sensor_read_reg(&cfg->i2c, SENSOR_EXPOSURE_REG, &u16, 2);
*(uint32_t)value = u16;
return ret;
case VIDEO_CTRL_GET_MIN | VIDEO_CID_CAMERA_EXPOSURE:
*(uint32_t *)value = 0;
return 0;
case VIDEO_CTRL_GET_MAX | VIDEO_CID_CAMERA_EXPOSURE:
*(uint32_t *)value = 320;
return 0;
case VIDEO_CTRL_GET_DEF | VIDEO_CID_CAMERA_EXPOSURE:
*(uint32_t *)value = 9;
return 0;
default:
return -ENOTSUP;
}
} Helper function specifying the min/max/def. static int video_ctrl_range_u32(unsigned int cid, void *value, uint32_t min, uint32_t max, uint32_t def)
{
switch (cid & VIDEO_CTRL_GET_MASK) {
case VIDEO_CTRL_GET_MIN:
*(uint32_t *)value = min;
return 0;
case VIDEO_CTRL_GET_MAX:
*(uint32_t *)value = max;
return 0;
case VIDEO_CTRL_GET_DEF:
*(uint32_t *)value = def;
return 0;
case VIDEO_CTRL_GET_CUR:
return 1;
default:
return -ENOTSUP;
}
}
static int sensor_get_ctrl(const struct device *dev, unsigned int cid, void *value)
{
uint16_t u16;
int ret;
switch (cid & ~VIDEO_CTRL_GET_MASK) {
case VIDEO_CID_CAMERA_EXPOSURE:
ret = video_get_ctrl_range(cid, value, 0, 320, 9);
if (ret == 1) {
ret = sensor_read_reg(&cfg->i2c, SENSOR_EXPOSURE_REG, &u16, 2);
*(uint32_t)value = u16;
}
return ret;
default:
return -ENOTSUP;
}
} |
26f0023
to
fd5e76b
Compare
It is possible to know the default value by probing the systems at startup and storing the default value. |
The way Linux does this is to initialize new controls, which likely means memory allocation: The last code block above with Maybe adding a set of "CID wrappers" like this could help simplifying the min/max handling while not introducing any memory allocation or involve a complete subsystem? /* Standard helpers for simple situations fitting most controls */
int video_ctrl_range_u32(const struct device *dev, unsigned int cid, void *value,
uint32_t min, uint32_t max, uint32_t def);
int video_ctrl_range_i32(const struct device *dev, unsigned int cid, void *value,
int32_t min, int32_t max, int32_t def);
int video_ctrl_range_enum(const struct device *dev, unsigned int cid, void *value,
int min, int max, int def);
/* Customized helpers for customized structures */
int video_ctrl_range_roi(const struct device *dev, unsigned int cid, void *value,
struct video_ctrl_roi *min, video_ctrl_roi *max, video_ctrl_roi *def); |
fd5e76b
to
84b2763
Compare
84b2763
to
96a0c3e
Compare
Last block seems fair. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this approach is reasonable
96a0c3e
to
b6a2b3c
Compare
b6a2b3c
to
71de5b5
Compare
Force-push:
|
I think @ngphibang might have been planning something around the video API CID types, which might obsolete this PR. |
71de5b5
to
ec5aeb9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@josuah Thanks for mentioning this ! Yes, I am working on improving the control aspect as well. This PR seems targeting part of this scope. But just go ahead merging this if we see that it's ok.
return ret; | ||
} | ||
|
||
if (value < min || value > max) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should also check min > max
drivers/video/video_common.c
Outdated
@@ -83,3 +84,45 @@ void video_buffer_release(struct video_buffer *vbuf) | |||
VIDEO_COMMON_FREE(block->data); | |||
} | |||
} | |||
|
|||
int video_get_range_u32(unsigned int cid, uint32_t *value, uint32_t min, uint32_t max, uint32_t def) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we only check uint32_t ? What if the control values are of other types, e,g, int (control values can be negative), uint64_t (pixel_rate, link frequencies), menu (test pattern), etc. ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, this should be void *
like video_get_ctrl()
.
If some concept of type is to be introduced, this should be a separate PR.
Thank you for the help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it cannot be uint64_t
(as it does not fit in a pointer in some architectures supported by Zephyr) but it can be uint64_t *
.
Maybe a first compromise is to support int32_t
and uint32_t
(or to be more correct, uintptr_t
and intptr_t
) is good enough for a first cycle? I am updating this branch to illustrate this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am waiting before introducing bool
, menu
, bitmap
and extra types as I tried to focus on the mechanism that enable fetching a range that would fit the current API.
Let me know if I should include them on this PR, I'd be glad to give it a try!
What if user specifies : |
This becomes #define VIDEO_CTRL_GET_CUR 0x00000000 /**< Get the current value */
#define VIDEO_CTRL_GET_MIN 0x00001000 /**< Get the minimum value */
#define VIDEO_CTRL_GET_MAX 0x00002000 /**< Get the maximum value */
#define VIDEO_CTRL_GET_DEF 0x00003000 /**< Get the default value */
#define VIDEO_CTRL_GET_MASK 0x0000f000 /**< Mask for get operations */ In the current implementation, this is not a bitmask of flags, but a field added inside of the CID that contains an integer value from 0 to 3. Is this too confusing? |
I think it's ok. At least this is a solution, and we can adjust it later if necessary. |
Maybe a better solution can be visible after starting to use it a bit. |
ec5aeb9
to
af11160
Compare
5b701f2
to
c7b61f5
Compare
The video_get_ctrl() API permits to retrieve a value from a device using standard CIDs from <zephyr/drivers/video-controls.h>. The CIDs do not come with a range information, and to know which value to apply to a video driver, knowing the minimum and maximum value before-hand is required. This prevents building generic layers that handle any video devices, such as protocols such as USB UVC, GigE Vision, or anything making use of "zephyr,camera" chosen node. This commit introduces extra flags added to the CIDs that indicates to the target device that instead of returning the current value, they should return the minimum, maximum, or default value instead, with the same type as the current value. The GET_CUR operation having a flag of 0x00, this makes all drivers implicitly support this new API, with an opt-in migration to also support the extra controls, correctly rejecting the unsupported extra operations by default. Signed-off-by: Josuah Demangeon <me@josuah.net>
e40296b
to
2665a9a
Compare
Force-push: CI fixes. Developing:
Before submitting:
|
This allows implementing the VIDEO_CTRL_GET_MIN/MAX/DEF controls on drivers with minimum modification of the drivers. A typical usage in a video_get_ctrl() implementation would be: ret = video_get_ctrl_range(cid, value, 0, 320, 9); if (ret <= 0) { return ret; } return sensor_read_u32(&cfg->i2c, EXPOSURE_REG, value, 2); A typical usage in a video_set_ctrl() implementation would be: ret = video_check_range_u32(dev, cid, (uint32_t)value); if (ret < 0) { return ret; } return sensor_read_reg(&cfg->i2c, EXPOSURE_REG, value, 2); Signed-off-by: Josuah Demangeon <me@josuah.net>
2665a9a
to
1a4dcb1
Compare
force-push: switch from |
An issue faced while working on UVC: how to know the min/max value of a video control ID (CID)?
The UVC protocol supports
GET_CUR
,GET_DEF
,GET_MIN
,GET_MAX
,GET_RES
operation to requst a value whose storage length is given byGET_LEN
.The
video_get_ctrl()
API permits to retrieve a value from a device using standard CIDs from<zephyr/drivers/video-controls.h>
. The CIDs do not define standard min/max values. This means knowing what value to apply needs knowing the particular sensor before-hand.This commit introduces extra flags added to the CIDs asking for the current, minimum, maximum, or default value, with the same type.
The
GET_CUR
operation having a flag of0x00
, this makes all drivers implicitly support this new API, with an opt-in migration to also support the extra controls, correctly rejecting the unsupported extra operations by default.Is this a reasonable way to solve this?