2.2.13 V4L2 Controls

2.2.13.1 Introduction
V4L2控制API似乎足够简单,但在驱动程序中正确实现时很快变得非常困难。但是,处理控制所需的许多代码实际上并非驱动程序特定,可以移动到V4L核心框架中。
毕竟,驱动程序开发人员感兴趣的仅是:
1)如何添加控件?
2)如何设置控件的值?(即s_ctrl)
偶尔会有:
3)如何获取控件的值?(即g_volatile_ctrl)
4)如何验证用户提出的控件值?(即try_ctrl)
所有其余内容都可以在中央完成。
控件框架是为了在一个中央位置实现V4L2规范关于控件的所有规则而创建的。并尽可能地简化驱动程序开发人员的生活。
请注意,控制框架依赖于V4L2驱动程序中struct v4l2_device和子设备驱动程序中的struct v4l2_subdev的存在。
2.2.13.2 Objects in the framework
有两个主要的对象:
v4l2_ctrl对象描述控制属性并跟踪控制的值(当前值和建议的新值)。
v4l2_ctrl_handler是跟踪控件的对象。它维护了一个v4l2_ctrl对象列表和另一个引用控件的列表,可能引用其他处理程序拥有的控件。
2.2.13.3 Basic usage for V4L2 and sub-device drivers
1) Prepare the driver:

#include <media/v4l2-ctrls.h>

1.1) Add the handler to your driver’s top-level struct:
For V4L2 drivers:

struct foo_dev {
...
struct v4l2_device v4l2_dev;
...
struct v4l2_ctrl_handler ctrl_handler;
...
};

For sub-device drivers:

struct foo_dev {
...
struct v4l2_subdev sd;
...
struct v4l2_ctrl_handler ctrl_handler;
...
};

1.2) Initialize the handler:

v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls);

第二个参数是一个提示,告诉函数此处理程序预计要处理多少个控件。它将根据此信息分配哈希表。这只是一个提示。
1.3) Hook the control handler into the driver:
For V4L2 drivers:

foo->v4l2_dev.ctrl_handler = &foo->ctrl_handler;

For sub-device drivers:

foo->sd.ctrl_handler = &foo->ctrl_handler;

1.4) Clean up the handler at the end:

v4l2_ctrl_handler_free(&foo->ctrl_handler);

2) Add controls:
You add non-menu controls by calling v4l2_ctrl_new_std():

struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_ops *ops,
u32 id, s32 min, s32 max, u32 step, s32 def);

Menu and integer menu controls are added by calling v4l2_ctrl_new_std_menu():

struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_ops *ops,
u32 id, s32 max, s32 skip_mask, s32 def);

Menu controls with a driver specifific menu are added by calling v4l2_ctrl_new_std_menu_items():

struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(
struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_ops *ops, u32 id, s32 max,
s32 skip_mask, s32 def, const char * const *qmenu);

Standard compound controls can be added by calling v4l2_ctrl_new_std_compound():

struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_ops *ops, u32 id,
const union v4l2_ctrl_ptr p_def);

Integer menu controls with a driver specifific menu can be added by calling v4l2_ctrl_new_int_menu():

struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_ops *ops,
u32 id, s32 max, s32 def, const s64 *qmenu_int);

These functions are typically called right after the v4l2_ctrl_handler_init():

static const s64 exp_bias_qmenu[] = {
-2, -1, 0, 1, 2
};
static const char * const test_pattern[] = {
"Disabled",
"Vertical Bars",
"Solid Black",
"Solid White",
};
v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls);
v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops,
V4L2_CID_CONTRAST, 0, 255, 1, 128);
v4l2_ctrl_new_std_menu(&foo->ctrl_handler, &foo_ctrl_ops,
V4L2_CID_POWER_LINE_FREQUENCY,
V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
V4L2_CID_POWER_LINE_FREQUENCY_DISABLED);
v4l2_ctrl_new_int_menu(&foo->ctrl_handler, &foo_ctrl_ops,
V4L2_CID_EXPOSURE_BIAS,
ARRAY_SIZE(exp_bias_qmenu) - 1,
ARRAY_SIZE(exp_bias_qmenu) / 2 - 1,
exp_bias_qmenu);
v4l2_ctrl_new_std_menu_items(&foo->ctrl_handler, &foo_ctrl_ops,
V4L2_CID_TEST_PATTERN, ARRAY_SIZE(test_pattern) - 1, 0,
0, test_pattern);
...
if (foo->ctrl_handler.error) {
int err = foo->ctrl_handler.error;
v4l2_ctrl_handler_free(&foo->ctrl_handler);
return err;
}

v4l2_ctrl_new_std()函数返回指向新控件的v4l2_ctrl指针,但如果您不需要在控件操作之外访问指针,则没有必要存储它。
v4l2_ctrl_new_std()函数将根据控件ID填充大多数字段,除了最小值、最大值、步长和默认值。这些值是驱动程序特定的,而控制属性(如类型、名称、标志)都是全局的。控件的当前值将设置为默认值。
v4l2_ctrl_new_std_menu()函数非常相似,但用于菜单控件。由于菜单控件的最小值始终为0,因此不存在min参数。而且它没有步骤,而是有一个skip_mask参数:如果位X为1,则跳过菜单项X。
v4l2_ctrl_new_int_menu()函数创建一个带有驱动程序特定菜单项的新标准整数菜单控件。它与v4l2_ctrl_new_std_menu不同之处在于它没有掩码参数,而是将最后一个参数作为64位有符号整数数组,形成精确的菜单项列表。
v4l2_ctrl_new_std_menu_items()函数与v4l2_ctrl_new_std_menu非常相似,但还取一个额外的参数qmenu,它是用于定义驱动程序特定菜单项的标准菜单控件。这个控件的一个很好的例子是捕获/显示/传感器设备的测试模式控件,这些设备具有生成测试模式的功能。这些测试模式是硬件特定的,因此菜单的内容将因设备而异。
请注意,如果某些操作失败,函数将返回NULL或错误,并设置ctrl_handler->error为错误代码。如果ctrl_handler->error已经设置,则它将返回并且不执行任何操作。如果v4l2_ctrl_handler_init无法分配内部数据结构,情况也是如此。
这使得初始化处理程序变得容易,只需要添加所有控件,最后检查错误代码即可。节省了大量重复的错误检查。
建议按升序控件ID顺序添加控件:这样会更快一些。
3) Optionally force initial control setup:

v4l2_ctrl_handler_setup(&foo->ctrl_handler);

这将无条件地为所有控件调用s_ctrl。实际上,这会将硬件初始化为默认控件值。建议您这样做,因为这可以确保内部数据结构和硬件同步。
4) Finally: implement the v4l2_ctrl_ops

static const struct v4l2_ctrl_ops foo_ctrl_ops = {
.s_ctrl = foo_s_ctrl,
};

Usually all you need is s_ctrl:

static int foo_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct foo *state = container_of(ctrl->handler, struct foo, ctrl_handler);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
write_reg(0x123, ctrl->val);
break;
case V4L2_CID_CONTRAST:
write_reg(0x456, ctrl->val);
break;
}
return 0;
}

控制操作使用v4l2_ctrl指针作为参数进行调用。新的控件值已经过验证,因此您需要做的就是实际更新硬件寄存器。您完成了!对于我们拥有的大多数驱动程序来说,这已足够。无需对控件值进行任何验证,也不需要实现QUERYCTRL、QUERY_EXT_CTRL和QUERYMENU。而且G/S_CTRL以及G/TRY/S_EXT_CTRLS也会自动支持。
注意:其余部分处理更高级的控件主题和场景。在实践中,上述描述的基本用法对于大多数驱动程序来说已经足够。

Spring Boot 2.2.13 中整合 PostgreSQL 数据库,主要包括以下几个步骤: 1. **添加依赖**: 在项目的 `pom.xml` 或者 Gradle build 文件中,添加 Spring Data JPA 和 PostgreSQL JDBC 驱动的依赖: ```xml <!-- Maven --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> </dependency> <!-- Gradle (Kotlin) --> implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.postgresql:postgresql") ``` 2. **配置数据库**: 在 `application.properties` 或 `application.yml` 中配置数据库连接信息,如 URL、用户名、密码等: ```properties spring.datasource.url=jdbc:postgresql://localhost:5432/mydb spring.datasource.username=myuser spring.datasource.password=mypassword spring.jpa.hibernate.ddl-auto=update ``` `- jpa.hibernate.ddl-auto` 设置为 `update` 表示每次应用启动时都会自动更新数据库结构。 3. **创建实体类**: 创建一个或多个 `@Entity` 注解的 Java 类来表示数据库表结构。比如: ```java @Entity public class MyEntity { @Id private Long id; private String name; // getters and setters... } ``` 4. **配置数据源和JPA**: 如果使用 `application.yml`,可以在 `spring` 区域下配置: ```yaml data: jpa: properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect ``` 5. **启用扫描**: 如果实体类不在默认的扫描包中,记得在 `Application` 类里启用扫描: ```java @EnableJpaRepositories(basePackages = "com.example.myapp.repository") @ComponentScan(basePackages = "com.example.myapp") public class Application { ... } ``` 6. **编写Repository接口**: 为每个实体类创建对应的 Repository 接口,Spring Data JPA 将会生成 CRUD 方法。例如: ```java public interface MyEntityRepository extends JpaRepository<MyEntity, Long> {} ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值