diff --git a/Makefile b/Makefile index 9c36e9b..bbfe34e 100644 --- a/Makefile +++ b/Makefile @@ -17,16 +17,20 @@ install: $(BIN) mkdir -p $(DESTDIR)$(PREFIX)/bin cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin/$(BIN) chmod 755 $(DESTDIR)$(PREFIX)/bin/$(BIN) + mkdir -p $(DESTDIR)$(MANPREFIX)/man1 + cp -f frcctrlmgr.1 $(DESTDIR)$(MANPREFIX)/man1/ + chmod 644 $(DESTDIR)$(MANPREFIX)/man1/frcctrlmgr.1 uninstall: - rm -f $(DESTDIR)$(PREFIX)/bin/$(BIN) + rm -f $(DESTDIR)$(PREFIX)/bin/$(BIN) \ + $(DESTDIR)$(MANPREFIX)/man1/frcctrlmgr.1 clean: rm -f $(OBJ) $(BIN) $(DIST).tar.gz dist: clean mkdir -p $(DIST) - cp -R src config.mk Makefile $(DIST) + cp -R src config.mk Makefile frcctrlmgr.1 LICENSE README $(DIST) tar -czf $(DIST).tar.gz $(DIST) rm -rf $(DIST) diff --git a/frcctrlmgr b/frcctrlmgr new file mode 100755 index 0000000..76a728a Binary files /dev/null and b/frcctrlmgr differ diff --git a/frcctrlmgr.1 b/frcctrlmgr.1 new file mode 100644 index 0000000..b4a06d1 --- /dev/null +++ b/frcctrlmgr.1 @@ -0,0 +1,27 @@ +.TH VXC "1" "April 2026" "frcctrlmgr v0.1" "User Commands" +.SH NAME +frcctrlmgr \- manual page for frcctrlmgr v0.1 +.SH SYNOPSIS +.B frcctrlmgr +[\fI\,OPTION\/\fR]... \fI\, \/\fR +.SH DESCRIPTION +A simple way to display the control schema of your robot. +.SH OPTIONS +.TP +\fB\-h, \-\-help\fR +print this help and exit +.TP +\fB\-v, \-\-version\fR +output version information +.TP +\fB\-D, --display\fR +displays a diagram of the Thrustmaster and the Xbox controller. +.TP +\fB\-j\fR +output the controls in a JSON format. +.TP +.SH COPYRIGHT +Copyright \(co 2025\-2026 fSD. +.br +This is free software; you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. diff --git a/src/frcctrlmgr.c b/src/frcctrlmgr.c index 503cea1..d9b6bd8 100644 --- a/src/frcctrlmgr.c +++ b/src/frcctrlmgr.c @@ -1,22 +1,301 @@ #include "frcctrlmgr.h" char *argv0; +bool use_json = false; -void usage(int code) { - printf("usage: %s: [-h help] [-v]\n", argv0); +static void usage(int code) +{ + printf("usage: %s: [--help] [--diagram] [-vhD]\n", argv0); exit(code); } +static void display_disgrams() +{ + puts("|1|2|3| 1234 |1|2|3|"); + puts("|4|5|6| |4|5|6|"); + exit(0); +} + +static void die(const char *fmt, ...) +{ + printf("%s: ", argv0); + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + putchar('\n'); + + exit(1); +} + +static char *join_path(const char *a, const char *b) { + if (!a) a = ""; + if (!b) b = ""; + size_t la = strlen(a), lb = strlen(b); + int a_has = la > 0 && a[la-1] == '/'; + int b_has = lb > 0 && b[0] == '/'; + + size_t need = la + lb + 2; + char *res = malloc(need); + if (!res) return NULL; + + if (la == 0) { + snprintf(res, need, "%s", b); + } else if (lb == 0) { + snprintf(res, need, "%s", a); + } else if (a_has && b_has) { + snprintf(res, need, "%s%s", a, b + 1); + } else if (!a_has && !b_has) { + snprintf(res, need, "%s/%s", a, b); + } else { + snprintf(res, need, "%s%s", a, b); + } + return res; +} + +static const char *controller_kind_str(ControllerKind k) +{ + switch (k) { + case JOYSTICK: return "JOYSTICK"; + case XBOX: return "XBOX"; + default: return "UNKNOWN"; + } +} + +static const char *controller_action_str(ControllerAction a) +{ + switch (a) { + case JOYSTICK_ONE: return "JOYSTICK_ONE"; + case JOYSTICK_TWO: return "JOYSTICK_TWO"; + case JOYSTICK_THREE: return "JOYSTICK_THREE"; + case JOYSTICK_FOUR: return "JOYSTICK_FOUR"; + case JOYSTICK_FIVE: return "JOYSTICK_FIVE"; + case JOYSTICK_SIX: return "JOYSTICK_SIX"; + case JOYSTICK_SEVEN: return "JOYSTICK_SEVEN"; + case JOYSTICK_EIGHT: return "JOYSTICK_EIGHT"; + case JOYSTICK_NINE: return "JOYSTICK_NINE"; + case JOYSTICK_TEN: return "JOYSTICK_TEN"; + case JOYSTICK_ELEVEN: return "JOYSTICK_ELEVEN"; + case JOYSTICK_TWELVE: return "JOYSTICK_TWELVE"; + case JOYSTICK_THIRTEEN: return "JOYSTICK_THIRTEEN"; + case JOYSTICK_FOURTEEN: return "JOYSTICK_FOURTEEN"; + case JOYSTICK_FIFTEEN: return "JOYSTICK_FIFTEEN"; + case JOYSTICK_SIXTEEN: return "JOYSTICK_SIXTEEN"; + case XBOX_BACK: return "XBOX_BACK"; + case XBOX_START: return "XBOX_START"; + case XBOX_X: return "XBOX_X"; + case XBOX_Y: return "XBOX_Y"; + case XBOX_B: return "XBOX_B"; + case XBOX_A: return "XBOX_A"; + case XBOX_LEFTBUMPER: return "XBOX_LEFTBUMPER"; + case XBOX_RIGHTBUMPER: return "XBOX_RIGHTBUMPER"; + case XBOX_LEFTSTICK: return "XBOX_LEFTSTICK"; + case XBOX_RIGHTSTICK: return "XBOX_RIGHTSTICK"; + case XBOX_LEFTTRIGGER: return "XBOX_LEFTTRIGGER"; + case XBOX_RIGHTTRIGGER: return "XBOX_RIGHTTRIGGER"; + case XBOX_UP: return "XBOX_UP"; + case XBOX_DOWN: return "XBOX_DOWN"; + case XBOX_LEFT: return "XBOX_LEFT"; + case XBOX_RIGHT: return "XBOX_RIGHT"; + case XBOX_NORTH: return "XBOX_NORTH"; + case XBOX_NORTHEAST: return "XBOX_NORTHEAST"; + case XBOX_EAST: return "XBOX_EAST"; + case XBOX_SOUTHEAST: return "XBOX_SOUTHEAST"; + case XBOX_SOUTH: return "XBOX_SOUTH"; + case XBOX_SOUTHWEST: return "XBOX_SOUTHWEST"; + case XBOX_WEST: return "XBOX_WEST"; + case XBOX_NORTHWEST: return "XBOX_NORTHWEST"; + default: return "UNKNOWN"; + } +} + +static ControllerAction controller_str_action(char *a) +{ + if (strcmp(a, "JOYSTICK_ONE") == 0) + return JOYSTICK_ONE; + else if (strcmp(a, "JOYSTICK_TWO") == 0) + return JOYSTICK_TWO; + else if (strcmp(a, "JOYSTICK_THREE") == 0) + return JOYSTICK_THREE; + else if (strcmp(a, "JOYSTICK_FOUR") == 0) + return JOYSTICK_FOUR; + else if (strcmp(a, "JOYSTICK_FIVE") == 0) + return JOYSTICK_FIVE; + else if (strcmp(a, "JOYSTICK_SIX") == 0) + return JOYSTICK_SIX; + else if (strcmp(a, "JOYSTICK_SEVEN") == 0) + return JOYSTICK_SEVEN; + else if (strcmp(a, "JOYSTICK_EIGHT") == 0) + return JOYSTICK_EIGHT; + else if (strcmp(a, "JOYSTICK_NINE") == 0) + return JOYSTICK_NINE; + else if (strcmp(a, "JOYSTICK_TEN") == 0) + return JOYSTICK_TEN; + else if (strcmp(a, "JOYSTICK_ELEVEN") == 0) + return JOYSTICK_ELEVEN; + else if (strcmp(a, "JOYSTICK_TWELVE") == 0) + return JOYSTICK_TWELVE; + else if (strcmp(a, "JOYSTICK_THIRTEEN") == 0) + return JOYSTICK_THIRTEEN; + else if (strcmp(a, "JOYSTICK_FOURTEEN") == 0) + return JOYSTICK_FOURTEEN; + else if (strcmp(a, "JOYSTICK_FIFTEEN") == 0) + return JOYSTICK_FIFTEEN; + else if (strcmp(a, "JOYSTICK_SIXTEEN") == 0) + return JOYSTICK_SIXTEEN; + else if (strcmp(a, "XBOX_BACK") == 0) + return XBOX_BACK; + else if (strcmp(a, "XBOX_START") == 0) + return XBOX_START; + else if (strcmp(a, "XBOX_X") == 0) + return XBOX_X; + else if (strcmp(a, "XBOX_Y") == 0) + return XBOX_Y; + else if (strcmp(a, "XBOX_B") == 0) + return XBOX_B; + else if (strcmp(a, "XBOX_A") == 0) + return XBOX_A; + else if (strcmp(a, "XBOX_LEFTBUMPER") == 0) + return XBOX_LEFTBUMPER; + else if (strcmp(a, "XBOX_RIGHTBUMPER") == 0) + return XBOX_RIGHTBUMPER; + else if (strcmp(a, "XBOX_LEFTSTICK") == 0) + return XBOX_LEFTSTICK; + else if (strcmp(a, "XBOX_RIGHTSTICK") == 0) + return XBOX_RIGHTSTICK; + else if (strcmp(a, "XBOX_LEFTTRIGGER") == 0) + return XBOX_LEFTTRIGGER; + else if (strcmp(a, "XBOX_RIGHTTRIGGER") == 0) + return XBOX_RIGHTTRIGGER; + else if (strcmp(a, "XBOX_UP") == 0) + return XBOX_UP; + else if (strcmp(a, "XBOX_DOWN") == 0) + return XBOX_DOWN; + else if (strcmp(a, "XBOX_LEFT") == 0) + return XBOX_LEFT; + else if (strcmp(a, "XBOX_RIGHT") == 0) + return XBOX_RIGHT; + else if (strcmp(a, "XBOX_NORTH") == 0) + return XBOX_NORTH; + else if (strcmp(a, "XBOX_NORTHEAST") == 0) + return XBOX_NORTHEAST; + else if (strcmp(a, "XBOX_EAST") == 0) + return XBOX_EAST; + else if (strcmp(a, "XBOX_SOUTHEAST") == 0) + return XBOX_SOUTHEAST; + else if (strcmp(a, "XBOX_SOUTH") == 0) + return XBOX_SOUTH; + else if (strcmp(a, "XBOX_SOUTHWEST") == 0) + return XBOX_SOUTHWEST; + else if (strcmp(a, "XBOX_WEST") == 0) + return XBOX_WEST; + else if (strcmp(a, "XBOX_NORTHWEST") == 0) + return XBOX_NORTHWEST; + die("%s:%s", __FILE__, __LINE__); + return XBOX_A; // dummy +} + +int print_control(Control control, bool fmt_json) +{ + if (fmt_json) { + return printf( + "{\"controller\":\"%s\",\"button\":\"%s\",\"action\":\"%s\"}\n", + controller_kind_str(control.controller), + controller_action_str(control.button), + control.action ? control.action : "" + ); + } + + return printf( + "controller=%s button=%s action=%s\n", + controller_kind_str(control.controller), + controller_action_str(control.button), + control.action ? control.action : "" + ); +} + +static char *trim_string(char *str) { + if (!str) return NULL; + + size_t len = strlen(str); + size_t start = 0; + size_t end = len - 1; + + while (isspace(str[start])) start++; + while (end > start && isspace(str[end])) end--; + + char *result = malloc(end - start + 2); + if (!result) return NULL; + + strncpy(result, str + start, end - start + 1); + result[end - start + 1] = '\0'; + return result; +} + +int read_wpiproject(Control *output, char *root) +{ + FILE *fp = fopen(join_path(root, "src/main/java/com/adambots/RobotContainer.java"), "r"); + char buf[BUFSIZ]; + bool found_configure_bindings_start = false; + int output_i = 0; + + if (!fp) + die("failed to read: %s", root); + + while (fgets(buf, sizeof(buf), fp)) { + char *p = buf; + + while (*p && isspace((unsigned char)*p)) + p++; + + if (strncmp(p, "Buttons.", 8) == 0) { + unsigned char c = p[8]; + + if (c && isupper(c)) { + // Buttons.XboxStartButton.onTrue( + // 17^ + ControllerKind controller = XBOX; + ControllerAction button = controller_str_action("XBOX_A"); + print_control((Control){ + .controller = controller, + .button = button, + .action = "" + }, use_json); + } + } + } + + + fclose(fp); + return 0; +} + int main(int argc, char *argv[]) { - argv0 = argv[0]; + argv0 = basename(argv[0]); + char *project; + + if (argc < 2) + usage(1); for (int i = 0; i < argc; ++i) { if (STRCMP("--help")) usage(0); - if (STRCMP("-h")) + else if (STRCMP("-h")) usage(0); - if (STRCMP("-v")) + else if (STRCMP("-v")) printf("%s/%s\n", argv0, VERSION); + else if (STRCMP("-j")) + use_json = true; + else if (STRCMP("--diagram") || STRCMP("-D")) + display_disgrams(); + else if (argv[i][0] == '-') + die("unknown option: %s", argv[i]); + else + project = argv[i]; } + + Control *output = malloc(sizeof(Control) * 40); + read_wpiproject(output, project); + return 0; } diff --git a/src/frcctrlmgr.h b/src/frcctrlmgr.h index ab29a0a..0b16d10 100644 --- a/src/frcctrlmgr.h +++ b/src/frcctrlmgr.h @@ -3,10 +3,72 @@ #define VERSION "0.1" +#include +#include +#include +#include #include #include #include #define STRCMP(x) !strcmp(argv[i], x) +typedef enum { + JOYSTICK, + XBOX, +} ControllerKind; + +typedef enum { + JOYSTICK_ONE, + JOYSTICK_TWO, + JOYSTICK_THREE, + JOYSTICK_FOUR, + JOYSTICK_FIVE, + JOYSTICK_SIX, + JOYSTICK_SEVEN, + JOYSTICK_EIGHT, + JOYSTICK_NINE, + JOYSTICK_TEN, + JOYSTICK_ELEVEN, + JOYSTICK_TWELVE, + JOYSTICK_THIRTEEN, + JOYSTICK_FOURTEEN, + JOYSTICK_FIFTEEN, + JOYSTICK_SIXTEEN, + + XBOX_BACK, + XBOX_START, + XBOX_X, + XBOX_Y, + XBOX_B, + XBOX_A, + XBOX_LEFTBUMPER, + XBOX_RIGHTBUMPER, + XBOX_LEFTSTICK, + XBOX_RIGHTSTICK, + XBOX_LEFTTRIGGER, + XBOX_RIGHTTRIGGER, + XBOX_UP, + XBOX_DOWN, + XBOX_LEFT, + XBOX_RIGHT, + XBOX_NORTH, + XBOX_NORTHEAST, + XBOX_EAST, + XBOX_SOUTHEAST, + XBOX_SOUTH, + XBOX_SOUTHWEST, + XBOX_WEST, + XBOX_NORTHWEST, +} ControllerAction; + +typedef struct { + ControllerKind controller; + ControllerAction button; + char *action; +} Control; + +int print_control(Control, bool); +int read_wpiproject(Control*, char *); + #endif // FRCTRLMGR_H_ diff --git a/src/frcctrlmgr.o b/src/frcctrlmgr.o new file mode 100644 index 0000000..fdfa7c7 Binary files /dev/null and b/src/frcctrlmgr.o differ