#include #include #include #include "error.h" #include "v4l2_ctrl.h" static void usage(const char *prog) { fprintf(stderr, "Usage: %s [args]\n" "\n" "Commands:\n" " list List all /dev/video* devices\n" " controls List all controls with current values\n" " get Get a control value by ID (decimal or 0x hex)\n" " set =\n" " Set a control value\n" "\n" "Examples:\n" " %s list\n" " %s controls /dev/video0\n" " %s get /dev/video0 0x00980900\n" " %s set /dev/video0 0x00980900=128\n", prog, prog, prog, prog, prog); } /* --- list --- */ static void on_device_found(const char *path, void *userdata) { (void)userdata; printf(" %s\n", path); } static int cmd_list(void) { printf("Video devices:\n"); struct App_Error err = v4l2_ctrl_find_devices(on_device_found, NULL); if (!APP_IS_OK(err)) { app_error_print(&err); return 1; } return 0; } /* --- controls --- */ static void on_control( const struct V4l2_Ctrl_Desc *desc, uint32_t menu_count, const struct V4l2_Menu_Item *menu_items, void *userdata) { (void)userdata; printf(" 0x%08x %-32s %-9s current=%-6d default=%-6d min=%-6d max=%-6d", desc->id, desc->name, v4l2_ctrl_type_name(desc->type), desc->current_value, desc->default_value, desc->min, desc->max); if (desc->type == CTRL_TYPE_INTEGER || desc->type == CTRL_TYPE_INTEGER64) { printf(" step=%d", desc->step); } printf("\n"); for (uint32_t i = 0; i < menu_count; i++) { if (desc->type == CTRL_TYPE_INTEGER_MENU) { printf(" [%u] %lld\n", menu_items[i].index, (long long)menu_items[i].value); } else { printf(" [%u] %s\n", menu_items[i].index, menu_items[i].name); } } } static int cmd_controls(const char *device) { struct V4l2_Ctrl_Handle *handle = NULL; struct App_Error err = v4l2_ctrl_open(device, &handle); if (!APP_IS_OK(err)) { app_error_print(&err); return 1; } printf("Controls on %s:\n", device); err = v4l2_ctrl_enumerate(handle, on_control, NULL); if (!APP_IS_OK(err)) { app_error_print(&err); v4l2_ctrl_close(handle); return 1; } v4l2_ctrl_close(handle); return 0; } /* --- get --- */ static int cmd_get(const char *device, const char *id_arg) { uint32_t id = (uint32_t)strtoul(id_arg, NULL, 0); struct V4l2_Ctrl_Handle *handle = NULL; struct App_Error err = v4l2_ctrl_open(device, &handle); if (!APP_IS_OK(err)) { app_error_print(&err); return 1; } int32_t value; err = v4l2_ctrl_get(handle, id, &value); if (!APP_IS_OK(err)) { app_error_print(&err); v4l2_ctrl_close(handle); return 1; } printf("0x%08x = %d\n", id, value); v4l2_ctrl_close(handle); return 0; } /* --- set --- */ static int cmd_set(const char *device, const char *assignment) { char id_str[64]; const char *eq = strchr(assignment, '='); if (!eq) { fprintf(stderr, "Expected =, got: %s\n", assignment); return 1; } size_t id_len = (size_t)(eq - assignment); if (id_len >= sizeof(id_str)) { fprintf(stderr, "ID string too long\n"); return 1; } memcpy(id_str, assignment, id_len); id_str[id_len] = '\0'; uint32_t id = (uint32_t)strtoul(id_str, NULL, 0); int32_t value = (int32_t)strtol(eq + 1, NULL, 0); struct V4l2_Ctrl_Handle *handle = NULL; struct App_Error err = v4l2_ctrl_open(device, &handle); if (!APP_IS_OK(err)) { app_error_print(&err); return 1; } err = v4l2_ctrl_set(handle, id, value); if (!APP_IS_OK(err)) { app_error_print(&err); v4l2_ctrl_close(handle); return 1; } printf("0x%08x set to %d\n", id, value); v4l2_ctrl_close(handle); return 0; } /* --- main --- */ int main(int argc, char **argv) { if (argc < 2) { usage(argv[0]); return 1; } const char *cmd = argv[1]; if (strcmp(cmd, "list") == 0) { return cmd_list(); } if (strcmp(cmd, "controls") == 0) { if (argc < 3) { fprintf(stderr, "controls requires a device argument\n"); return 1; } return cmd_controls(argv[2]); } if (strcmp(cmd, "get") == 0) { if (argc < 4) { fprintf(stderr, "get requires: \n"); return 1; } return cmd_get(argv[2], argv[3]); } if (strcmp(cmd, "set") == 0) { if (argc < 4) { fprintf(stderr, "set requires: =\n"); return 1; } return cmd_set(argv[2], argv[3]); } fprintf(stderr, "Unknown command: %s\n\n", cmd); usage(argv[0]); return 1; }