diff --git a/tools/ratbag-command.c b/tools/ratbag-command.c index f79a70ed..71a42101 100644 --- a/tools/ratbag-command.c +++ b/tools/ratbag-command.c @@ -58,6 +58,7 @@ enum cmd_flags { FLAG_NEED_PROFILE = 1 << 11, FLAG_NEED_RESOLUTION = 1 << 12, FLAG_NEED_BUTTON = 1 << 13, + FLAG_NEED_LED = 1 << 14, }; struct ratbag_cmd_options { @@ -66,6 +67,7 @@ struct ratbag_cmd_options { struct ratbag_profile *profile; struct ratbag_resolution *resolution; struct ratbag_button *button; + struct ratbag_led *led; }; struct ratbag_cmd { @@ -145,12 +147,27 @@ usage(void) "\n" " switch-etekcity Switch the Etekcity mouse active profile\n" "\n" + "LED Commands:\n" + " LED commands work on the given profile, or on the\n" + " active profile if none is given.\n" + "\n" + " led N {COMMAND}\n" + " get print the LED properties\n" + " set {COMMAND} sets LED properties\n" + " mode [on|off|cycle|breath] sets LED mode\n" + " color COLOR sets LED's color in hex format\n" + " rate N sets LED's effect rate in Hz\n" + " brightness N sets LED's effect brightness\n" + "\n" "Examples:\n" " %s profile active get\n" " %s profile 0 resolution active set 4\n" " %s profile 0 resolution 1 dpi get\n" " %s resolution 4 rate get\n" " %s dpi set 800\n" + " %s profile 0 led 0 set mode on\n" + " %s profile 0 led 0 set color ff00ff\n" + " %s profile 0 led 0 set rate 20\n" "\n" "Exit codes:\n" " 0 Success\n" @@ -163,6 +180,9 @@ usage(void) program_invocation_short_name, program_invocation_short_name, program_invocation_short_name, + program_invocation_short_name, + program_invocation_short_name, + program_invocation_short_name, program_invocation_short_name); } @@ -318,9 +338,11 @@ ratbag_cmd_info(const struct ratbag_cmd *cmd, struct ratbag_device *device; struct ratbag_profile *profile; struct ratbag_button *button; + struct ratbag_led *led; char *action; - int num_profiles, num_buttons; - int i, j, b; + int num_profiles, num_buttons, num_leds; + int i, j, b, l; + struct ratbag_color color; device = options->device; @@ -339,11 +361,17 @@ ratbag_cmd_info(const struct ratbag_cmd *cmd, if (ratbag_device_has_capability(device, RATBAG_DEVICE_CAP_BUTTON_MACROS)) printf(" btn-macros"); + if (ratbag_device_has_capability(device, + RATBAG_DEVICE_CAP_LED)) + printf(" led"); printf("\n"); num_buttons = ratbag_device_get_num_buttons(device); printf("Number of buttons: %d\n", num_buttons); + num_leds = ratbag_device_get_num_leds(device); + printf("Number of leds: %d\n", num_leds); + num_profiles = ratbag_device_get_num_profiles(device); printf("Profiles supported: %d\n", num_profiles); @@ -393,6 +421,21 @@ ratbag_cmd_info(const struct ratbag_cmd *cmd, button = ratbag_button_unref(button); } + for (l = 0; l < num_leds; l++) { + led = ratbag_profile_get_led(profile, l); + color = ratbag_led_get_color(led); + + printf(" LED: %d type %s mode %s color %02x%02x%02x rate %d brightness: %d\n", + l, + led_type_to_str(ratbag_led_get_type(led)), + led_mode_to_str(ratbag_led_get_mode(led)), + color.red, color.green, color.blue, + ratbag_led_get_effect_rate(led), + ratbag_led_get_brightness(led)); + + led = ratbag_led_unref(led); + } + profile = ratbag_profile_unref(profile); } @@ -1434,6 +1477,291 @@ static const struct ratbag_cmd cmd_button = { }, }; +static int +ratbag_cmd_led_set_brightness(const struct ratbag_cmd *cmd, + struct ratbag *ratbag, + struct ratbag_cmd_options *options, + int argc, char **argv) +{ + struct ratbag_device *device; + struct ratbag_led *led; + char *str, *endptr; + int brightness, b; + int rc; + + if (argc < 1) + return ERR_USAGE; + + led = options->led; + brightness = atoi(argv[0]); + + device = options->device; + + rc = ratbag_led_set_brightness(led, brightness); + if (rc != 0) + return ERR_DEVICE; + + return SUCCESS; +} + +static const struct ratbag_cmd cmd_led_set_brightness = { + .name = "brightness", + .cmd = ratbag_cmd_led_set_brightness, + .flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE | FLAG_NEED_LED, + .subcommands = { + NULL, + }, +}; + +static int +ratbag_cmd_led_set_effect_rate(const struct ratbag_cmd *cmd, + struct ratbag *ratbag, + struct ratbag_cmd_options *options, + int argc, char **argv) +{ + + struct ratbag_device *device; + struct ratbag_led *led; + char *str, *endptr; + int hz, b; + int rc; + + if (argc < 1) + return ERR_USAGE; + + led = options->led; + str = argv[0]; + hz = strtoul(str, &endptr, 10); + if (*endptr != '\0') + return ERR_USAGE; + + rc = ratbag_led_set_effect_rate(led, hz); + if (rc != 0) + return ERR_DEVICE; + + return SUCCESS; +} + +static const struct ratbag_cmd cmd_led_set_effect_rate = { + .name = "rate", + .cmd = ratbag_cmd_led_set_effect_rate, + .flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE | FLAG_NEED_LED, + .subcommands = { + NULL, + }, +}; + +static int +ratbag_cmd_led_set_color(const struct ratbag_cmd *cmd, + struct ratbag *ratbag, + struct ratbag_cmd_options *options, + int argc, char **argv) +{ + struct ratbag_device *device; + struct ratbag_led *led; + struct ratbag_color color; + char *str, *endptr; + int rc; + char red[2], green[2], blue[2]; + char *p; + + if (argc < 1) + return ERR_USAGE; + + led = options->led; + + sscanf(argv[0], "%2s%2s%2s", &red, &green, &blue); + + color.red = strtoul(red, &p, 16); + color.green = strtoul(green, &p, 16); + color.blue = strtoul(blue, &p, 16); + + rc = ratbag_led_set_color(led, color); + if (rc != 0) + return ERR_DEVICE; + + return SUCCESS; +} + +static const struct ratbag_cmd cmd_led_set_color = { + .name = "color", + .cmd = ratbag_cmd_led_set_color, + .flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE | FLAG_NEED_LED, + .subcommands = { + NULL, + }, +}; + +static int +ratbag_cmd_led_set_mode(const struct ratbag_cmd *cmd, + struct ratbag *ratbag, + struct ratbag_cmd_options *options, + int argc, char **argv) +{ + struct ratbag_device *device; + struct ratbag_led *led; + struct ratbag_color color; + char *str, *endptr; + int rc; + + if (argc < 1) + return ERR_USAGE; + + led = options->led; + str = argv[0]; + + enum ratbag_led_mode mode; + + if (streq(str, "off")) + mode = RATBAG_LED_OFF; + else if (streq(str, "on")) + mode = RATBAG_LED_ON; + else if (streq(str, "cycle")) + mode = RATBAG_LED_CYCLE; + else if (streq(str, "breathing")) + mode = RATBAG_LED_BREATHING; + else { + usage(); + return ERR_USAGE; + } + + /* set default rate and brightness */ + switch (mode) { + case RATBAG_LED_ON: + color.red = 255; + color.green = 255; + color.blue = 255; + ratbag_led_set_color(led, color); + break; + case RATBAG_LED_CYCLE: + case RATBAG_LED_BREATHING: + ratbag_led_set_effect_rate(led, 20); + ratbag_led_set_brightness(led, 100); + } + + rc = ratbag_led_set_mode(led, mode); + if (rc != 0) + return ERR_DEVICE; + + return SUCCESS; +} + +static const struct ratbag_cmd cmd_led_set_mode = { + .name = "mode", + .cmd = ratbag_cmd_led_set_mode, + .flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE | FLAG_NEED_LED, + .subcommands = { + NULL, + }, +}; + +static int +ratbag_cmd_led_set(const struct ratbag_cmd *cmd, + struct ratbag *ratbag, + struct ratbag_cmd_options *options, + int argc, char **argv) +{ + if (argc < 1) + return ERR_USAGE; + + return run_subcommand(argv[0], cmd, ratbag, options, + argc, argv); +} + +static const struct ratbag_cmd cmd_led_set = { + .name = "set", + .cmd = ratbag_cmd_led_set, + .flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE | FLAG_NEED_LED, + .subcommands = { + &cmd_led_set_mode, + &cmd_led_set_color, + &cmd_led_set_effect_rate, + &cmd_led_set_brightness, + NULL, + }, +}; + +static int +ratbag_cmd_led_get(const struct ratbag_cmd *cmd, + struct ratbag *ratbag, + struct ratbag_cmd_options *options, + int argc, char **argv) +{ + struct ratbag_led *led; + enum ratbag_led_mode mode; + struct ratbag_color color; + int hz; + int brightness; + enum ratbag_led_type type; + + led = options->led; + + type = ratbag_led_get_type(led); + mode = ratbag_led_get_mode(led); + color = ratbag_led_get_color(led); + hz = ratbag_led_get_effect_rate(led); + brightness = ratbag_led_get_brightness(led); + printf("type: %s, mode: %s, color: %02x%02x%02x, rate: %d, brightness: %d\n", + led_type_to_str(type), + led_mode_to_str(mode), + color.red, color.green, color.blue, + hz, brightness); + + return SUCCESS; +} + +static const struct ratbag_cmd cmd_led_get = { + .name = "get", + .cmd = ratbag_cmd_led_get, + .flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE | FLAG_NEED_LED, + .subcommands = { + NULL, + }, +}; + +static int +ratbag_cmd_led(const struct ratbag_cmd *cmd, + struct ratbag *ratbag, + struct ratbag_cmd_options *options, + int argc, char **argv) +{ + struct ratbag_profile *profile; + struct ratbag_led *led; + int rc, index; + + if (argc < 1) + return ERR_USAGE; + + profile = options->profile; + + index = atoi(argv[0]); + + led = ratbag_profile_get_led(profile, index); + if (!led) { + error("Invalid led %d\n", index); + return ERR_UNSUPPORTED; + } + options->led = led; + argc--; + argv++; + + rc = run_subcommand(argv[0], cmd, ratbag, options, + argc, argv); + + return rc; +} + +static const struct ratbag_cmd cmd_led = { + .name = "led", + .cmd = ratbag_cmd_led, + .flags = FLAG_NEED_DEVICE | FLAG_NEED_PROFILE, + .subcommands = { + &cmd_led_get, + &cmd_led_set, + NULL, + }, +}; + static int ratbag_cmd_profile_active_set(const struct ratbag_cmd *cmd, struct ratbag *ratbag, @@ -1674,6 +2002,7 @@ static const struct ratbag_cmd cmd_profile = { &cmd_profile_disable, &cmd_resolution, &cmd_button, + &cmd_led, NULL, }, }; @@ -1767,6 +2096,7 @@ main(int argc, char **argv) out: ratbag_resolution_unref(options.resolution); ratbag_button_unref(options.button); + ratbag_led_unref(options.led); ratbag_profile_unref(options.profile); ratbag_device_unref(options.device); ratbag_unref(ratbag); diff --git a/tools/shared.c b/tools/shared.c index 508d8d3e..745b1021 100644 --- a/tools/shared.c +++ b/tools/shared.c @@ -48,6 +48,48 @@ udev_device_from_path(struct udev *udev, const char *path) return udev_device; } +const char* +led_type_to_str(enum ratbag_led_type type) +{ + const char *str = "UNKNOWN"; + + switch(type) { + case RATBAG_LED_TYPE_UNKNOWN: + str = "unknown"; + break; + case RATBAG_LED_TYPE_LOGO: + str = "logo"; + break; + case RATBAG_LED_TYPE_SIDE: + str = "side"; + break; + } + + return str; +} + +const char * +led_mode_to_str(enum ratbag_led_mode mode) +{ + const char *str = "UNKNOWN"; + switch (mode) { + case RATBAG_LED_OFF: + str = "off"; + break; + case RATBAG_LED_ON: + str = "on"; + break; + case RATBAG_LED_CYCLE: + str = "cycle"; + break; + case RATBAG_LED_BREATHING: + str = "breath"; + break; + } + + return str; +} + const char* button_type_to_str(enum ratbag_button_type type) { diff --git a/tools/shared.h b/tools/shared.h index db6fc387..24df3499 100644 --- a/tools/shared.h +++ b/tools/shared.h @@ -59,6 +59,12 @@ udev_device_from_path(struct udev *udev, const char *path); const char* button_type_to_str(enum ratbag_button_type type); +const char* +led_type_to_str(enum ratbag_led_type type); + +const char * +led_mode_to_str(enum ratbag_led_mode mode); + const char * button_action_special_to_str(struct ratbag_button *button); diff --git a/tools/test-ratbag-command.sh b/tools/test-ratbag-command.sh index 08abe9bb..9a6ce5a0 100755 --- a/tools/test-ratbag-command.sh +++ b/tools/test-ratbag-command.sh @@ -58,7 +58,12 @@ cmds+=("profile 0 button 0 action set key KEY_ENTER") cmds+=("button 0 action set special doubleclick") cmds+=("profile 0 button 0 action set special doubleclick") cmds+=("profile 0 button 0 action set macro +KEY_ENTER t05 -KEY_ENTER") - +cmds+=("profile 0 led 0 get") +cmds+=("profile 0 led side get") +cmds+=("profile 0 led 0 set mode on") +cmds+=("profile 0 led 0 set color ffffff") +cmds+=("profile 0 led 0 set rate 1") +cmds+=("profile 0 led 0 set brightness 1") for i in "${cmds[@]}"; do echo "Testing arguments '$i $device'" eval $command "$i" $device