Add common, media_ctrl and v4l2_ctrl modules with CLI drivers and docs
Modules (src/modules/): - common/error: App_Error struct with structured detail union, error codes, app_error_print(); designed for future upgrade to preprocessor-generated location codes - media_ctrl: media device enumeration, topology query (entities/pads/links), link enable/disable via Media Controller API (/dev/media*) - v4l2_ctrl: control enumeration (with menu item fetching), get/set via V4L2 ext controls API, device discovery (/dev/video*) All modules use -std=c11 -D_GNU_SOURCE, build artifacts go to build/ only. Kernel-version-dependent constants guarded with #ifdef + #warning. CLI drivers (dev/cli/): - media_ctrl_cli: list, info, topology, set-link subcommands - v4l2_ctrl_cli: list, controls, get, set subcommands Docs (docs/cli/): - media_ctrl_cli.md and v4l2_ctrl_cli.md with usage, examples, and context within the video routing system Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
59
include/error.h
Normal file
59
include/error.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
typedef enum Error_Code {
|
||||
ERR_NONE = 0,
|
||||
ERR_SYSCALL = 1,
|
||||
ERR_INVALID = 2,
|
||||
ERR_NOT_FOUND = 3,
|
||||
} Error_Code;
|
||||
|
||||
struct Syscall_Error_Detail {
|
||||
int err_no;
|
||||
};
|
||||
|
||||
struct Invalid_Error_Detail {
|
||||
/* fields added as concrete cases arise */
|
||||
int placeholder;
|
||||
};
|
||||
|
||||
struct App_Error {
|
||||
Error_Code code;
|
||||
const char *file;
|
||||
int line;
|
||||
union {
|
||||
struct Syscall_Error_Detail syscall;
|
||||
struct Invalid_Error_Detail invalid;
|
||||
} detail;
|
||||
};
|
||||
|
||||
void app_error_print(struct App_Error *e);
|
||||
|
||||
#define APP_OK \
|
||||
((struct App_Error){ .code = ERR_NONE })
|
||||
|
||||
#define APP_IS_OK(e) \
|
||||
((e).code == ERR_NONE)
|
||||
|
||||
#define APP_SYSCALL_ERROR() \
|
||||
((struct App_Error){ \
|
||||
.code = ERR_SYSCALL, \
|
||||
.file = __FILE__, \
|
||||
.line = __LINE__, \
|
||||
.detail = { .syscall = { .err_no = errno } }, \
|
||||
})
|
||||
|
||||
#define APP_INVALID_ERROR() \
|
||||
((struct App_Error){ \
|
||||
.code = ERR_INVALID, \
|
||||
.file = __FILE__, \
|
||||
.line = __LINE__, \
|
||||
})
|
||||
|
||||
#define APP_NOT_FOUND_ERROR() \
|
||||
((struct App_Error){ \
|
||||
.code = ERR_NOT_FOUND, \
|
||||
.file = __FILE__, \
|
||||
.line = __LINE__, \
|
||||
})
|
||||
90
include/media_ctrl.h
Normal file
90
include/media_ctrl.h
Normal file
@@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "error.h"
|
||||
|
||||
/* Opaque handle — defined in media_ctrl.c */
|
||||
struct Media_Ctrl;
|
||||
|
||||
struct Media_Device_Info {
|
||||
char driver[16];
|
||||
char model[32];
|
||||
char serial[40];
|
||||
char bus_info[32];
|
||||
uint32_t media_version;
|
||||
uint32_t hw_revision;
|
||||
uint32_t driver_version;
|
||||
};
|
||||
|
||||
struct Media_Entity {
|
||||
uint32_t id;
|
||||
char name[32];
|
||||
uint32_t type; /* MEDIA_ENT_F_* value from kernel */
|
||||
uint32_t flags;
|
||||
uint16_t pad_count;
|
||||
uint16_t link_count;
|
||||
uint32_t dev_major; /* associated device node major, 0 if none */
|
||||
uint32_t dev_minor;
|
||||
};
|
||||
|
||||
struct Media_Pad {
|
||||
uint32_t entity_id;
|
||||
uint16_t index;
|
||||
uint32_t flags; /* MEDIA_PAD_FL_SINK / MEDIA_PAD_FL_SOURCE */
|
||||
};
|
||||
|
||||
struct Media_Link {
|
||||
struct Media_Pad source;
|
||||
struct Media_Pad sink;
|
||||
uint32_t flags; /* MEDIA_LNK_FL_ENABLED, MEDIA_LNK_FL_IMMUTABLE */
|
||||
};
|
||||
|
||||
/*
|
||||
* Enumerate all /dev/media* device nodes present on the system.
|
||||
* Calls callback once per device path found.
|
||||
*/
|
||||
struct App_Error media_ctrl_find_devices(
|
||||
void (*callback)(const char *device_path, void *userdata),
|
||||
void *userdata);
|
||||
|
||||
struct App_Error media_ctrl_open(const char *device_path, struct Media_Ctrl **out);
|
||||
void media_ctrl_close(struct Media_Ctrl *ctrl);
|
||||
|
||||
struct App_Error media_ctrl_get_info(
|
||||
struct Media_Ctrl *ctrl,
|
||||
struct Media_Device_Info *out);
|
||||
|
||||
/*
|
||||
* Enumerate all entities in the media graph.
|
||||
*/
|
||||
struct App_Error media_ctrl_enum_entities(
|
||||
struct Media_Ctrl *ctrl,
|
||||
void (*callback)(const struct Media_Entity *entity, void *userdata),
|
||||
void *userdata);
|
||||
|
||||
/*
|
||||
* Enumerate pads and links for a specific entity.
|
||||
* Pass the entity struct obtained from media_ctrl_enum_entities —
|
||||
* the pad and link counts are taken from it.
|
||||
* Either callback may be NULL if that information is not needed.
|
||||
*/
|
||||
struct App_Error media_ctrl_enum_entity_pads_and_links(
|
||||
struct Media_Ctrl *ctrl,
|
||||
const struct Media_Entity *entity,
|
||||
void (*pad_callback)(const struct Media_Pad *pad, void *userdata),
|
||||
void (*link_callback)(const struct Media_Link *link, void *userdata),
|
||||
void *userdata);
|
||||
|
||||
/*
|
||||
* Enable or disable a link between two pads.
|
||||
* Immutable links cannot be changed and will return an error.
|
||||
*/
|
||||
struct App_Error media_ctrl_set_link(
|
||||
struct Media_Ctrl *ctrl,
|
||||
uint32_t source_entity_id, uint16_t source_pad_index,
|
||||
uint32_t sink_entity_id, uint16_t sink_pad_index,
|
||||
int enabled);
|
||||
|
||||
/* Human-readable names for display */
|
||||
const char *media_entity_type_name(uint32_t type);
|
||||
const char *media_pad_flag_name(uint32_t flags);
|
||||
75
include/v4l2_ctrl.h
Normal file
75
include/v4l2_ctrl.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "error.h"
|
||||
|
||||
/* Opaque handle — defined in v4l2_ctrl.c */
|
||||
struct V4l2_Ctrl_Handle;
|
||||
|
||||
typedef enum V4l2_Ctrl_Type {
|
||||
CTRL_TYPE_INTEGER = 1,
|
||||
CTRL_TYPE_BOOLEAN = 2,
|
||||
CTRL_TYPE_MENU = 3,
|
||||
CTRL_TYPE_BUTTON = 4,
|
||||
CTRL_TYPE_INTEGER64 = 5,
|
||||
CTRL_TYPE_CTRL_CLASS = 6,
|
||||
CTRL_TYPE_STRING = 7,
|
||||
CTRL_TYPE_BITMASK = 8,
|
||||
CTRL_TYPE_INTEGER_MENU = 9,
|
||||
CTRL_TYPE_UNKNOWN = 0xff,
|
||||
} V4l2_Ctrl_Type;
|
||||
|
||||
struct V4l2_Ctrl_Desc {
|
||||
uint32_t id;
|
||||
char name[32];
|
||||
V4l2_Ctrl_Type type;
|
||||
int32_t min;
|
||||
int32_t max;
|
||||
int32_t step;
|
||||
int32_t default_value;
|
||||
int32_t current_value;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct V4l2_Menu_Item {
|
||||
uint32_t index;
|
||||
char name[32]; /* for CTRL_TYPE_MENU */
|
||||
int64_t value; /* for CTRL_TYPE_INTEGER_MENU */
|
||||
};
|
||||
|
||||
/*
|
||||
* Enumerate all /dev/video* device nodes present on the system.
|
||||
*/
|
||||
struct App_Error v4l2_ctrl_find_devices(
|
||||
void (*callback)(const char *device_path, void *userdata),
|
||||
void *userdata);
|
||||
|
||||
struct App_Error v4l2_ctrl_open(const char *device_path, struct V4l2_Ctrl_Handle **out);
|
||||
void v4l2_ctrl_close(struct V4l2_Ctrl_Handle *handle);
|
||||
|
||||
/*
|
||||
* Enumerate all controls on the device.
|
||||
* For menu and integer-menu controls, menu_items is a non-NULL array of
|
||||
* menu_count items. For all other types, menu_items is NULL and menu_count is 0.
|
||||
*/
|
||||
struct App_Error v4l2_ctrl_enumerate(
|
||||
struct V4l2_Ctrl_Handle *handle,
|
||||
void (*callback)(
|
||||
const struct V4l2_Ctrl_Desc *desc,
|
||||
uint32_t menu_count,
|
||||
const struct V4l2_Menu_Item *menu_items,
|
||||
void *userdata),
|
||||
void *userdata);
|
||||
|
||||
struct App_Error v4l2_ctrl_get(
|
||||
struct V4l2_Ctrl_Handle *handle,
|
||||
uint32_t id,
|
||||
int32_t *value_out);
|
||||
|
||||
struct App_Error v4l2_ctrl_set(
|
||||
struct V4l2_Ctrl_Handle *handle,
|
||||
uint32_t id,
|
||||
int32_t value);
|
||||
|
||||
/* Human-readable name for a control type */
|
||||
const char *v4l2_ctrl_type_name(V4l2_Ctrl_Type type);
|
||||
Reference in New Issue
Block a user