From 28aca798d1909129729565bfe9f86cf247f676ab Mon Sep 17 00:00:00 2001 From: Charlie <49533775+csev1755@users.noreply.github.com> Date: Sat, 8 Mar 2025 06:20:05 -0600 Subject: [PATCH] Consolidate motor packages - create gpio-motors (#1739) --- general/package/Config.in | 1 + general/package/gpio-motors/Config.in | 6 + general/package/gpio-motors/gpio-motors.mk | 18 ++ general/package/gpio-motors/src/Makefile | 3 + general/package/gpio-motors/src/gpio-motors.c | 190 ++++++++++++++++++ 5 files changed, 218 insertions(+) create mode 100644 general/package/gpio-motors/Config.in create mode 100644 general/package/gpio-motors/gpio-motors.mk create mode 100644 general/package/gpio-motors/src/Makefile create mode 100644 general/package/gpio-motors/src/gpio-motors.c diff --git a/general/package/Config.in b/general/package/Config.in index 69ad46f5..1703eaeb 100644 --- a/general/package/Config.in +++ b/general/package/Config.in @@ -22,6 +22,7 @@ source "$BR2_EXTERNAL_GENERAL_PATH/package/go2rtc/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/goke-osdrv-gk710x/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/goke-osdrv-gk7205v200/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/goke-osdrv-gk7205v500/Config.in" +source "$BR2_EXTERNAL_GENERAL_PATH/package/gpio-motors/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/grainmedia-osdrv-gm8136/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/hisi-gpio/Config.in" source "$BR2_EXTERNAL_GENERAL_PATH/package/hisilicon-opensdk/Config.in" diff --git a/general/package/gpio-motors/Config.in b/general/package/gpio-motors/Config.in new file mode 100644 index 00000000..adecf32d --- /dev/null +++ b/general/package/gpio-motors/Config.in @@ -0,0 +1,6 @@ +config BR2_PACKAGE_GPIO_MOTORS + bool "gpio-motors" + help + Control stepper motors via sysfs GPIO. This code was developed + on a GrainMedia GM8136 board with 24BYJ48 stepper motors and a ULN2803 + but should be portable to any other platform with sysfs GPIO access. diff --git a/general/package/gpio-motors/gpio-motors.mk b/general/package/gpio-motors/gpio-motors.mk new file mode 100644 index 00000000..f5a418c4 --- /dev/null +++ b/general/package/gpio-motors/gpio-motors.mk @@ -0,0 +1,18 @@ +################################################################################ +# +# gpio-motors +# +################################################################################ + +GPIO_MOTORS_SITE_METHOD = local +GPIO_MOTORS_SITE = $(GPIO_MOTORS_PKGDIR)/src + +define GPIO_MOTORS_BUILD_CMDS + $(MAKE) CC=$(TARGET_CC) -C $(@D) +endef + +define GPIO_MOTORS_INSTALL_TARGET_CMDS + $(INSTALL) -m 755 -t $(TARGET_DIR)/usr/bin $(@D)/output/* +endef + +$(eval $(generic-package)) diff --git a/general/package/gpio-motors/src/Makefile b/general/package/gpio-motors/src/Makefile new file mode 100644 index 00000000..56aa104c --- /dev/null +++ b/general/package/gpio-motors/src/Makefile @@ -0,0 +1,3 @@ +gpio-motors: + mkdir -p output + $(CC) $@.c -o output/$@ -s -Wall diff --git a/general/package/gpio-motors/src/gpio-motors.c b/general/package/gpio-motors/src/gpio-motors.c new file mode 100644 index 00000000..acda99cb --- /dev/null +++ b/general/package/gpio-motors/src/gpio-motors.c @@ -0,0 +1,190 @@ +#include +#include +#include +#include +#include +#include + +typedef struct { + char *name; + int pan[4]; + int tilt[4]; +} config; + +static config list[] = { + { "gk7205v200", { 52, 53, 56, 57 }, { 69, 70, 59, 58 } }, + { "gm8136-faleemi",{ 51, 52, 53, 54 }, { 55, 28, 29, 30 } }, + { "hi3516cv200-fdt",{ 60, 61, 37, 38 }, { 54, 55, 56, 57 } }, + { "ssc337de-foscam",{ 1, 2, 12, 13 }, { 62, 63, 64, 65 } }, +}; + +int PAN_PINS[4]; +int TILT_PINS[4]; + +int STEP_SEQUENCE[8][4] = { + {1, 0, 0, 0}, {1, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 1, 0}, + {0, 0, 1, 0}, {0, 0, 1, 1}, {0, 0, 0, 1}, {1, 0, 0, 1} +}; + +int REVERSE_STEP_SEQUENCE[8][4] = { + {1, 0, 0, 1}, {0, 0, 0, 1}, {0, 0, 1, 1}, {0, 0, 1, 0}, + {0, 1, 1, 0}, {0, 1, 0, 0}, {1, 1, 0, 0}, {1, 0, 0, 0} +}; + +void release_gpio(int pin) { + char path[50]; + snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin); + FILE *file = fopen(path, "w"); + if (file) { + fprintf(file, "%d", 0); + fclose(file); + } else { + printf("Unable to set value of GPIO %d to 0: [%d] %s\n", pin, errno, strerror(errno)); + } + + file = fopen("/sys/class/gpio/unexport", "w"); + if (file) { + fprintf(file, "%d", pin); + fclose(file); + } else { + printf("Unable to unexport GPIO %d: [%d] %s\n", pin, errno, strerror(errno)); + } +} + +void cleanup() { + + for (int i = 0; i < 4; i++) { + release_gpio(PAN_PINS[i]); + release_gpio(TILT_PINS[i]); + } + + exit(EXIT_FAILURE); +} + +void export_gpio(int pin) { + char path[50]; + FILE *file; + + file = fopen("/sys/class/gpio/export", "w"); + if (file) { + fprintf(file, "%d", pin); + fclose(file); + } else { + printf("Unable export GPIO %d: [%d] %s\n", pin, errno, strerror(errno)); + cleanup(); + } + + snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", pin); + file = fopen(path, "w"); + if (file) { + fprintf(file, "out"); + fclose(file); + } else { + printf("Unable to set direction of GPIO %d: [%d] %s\n", pin, errno, strerror(errno)); + cleanup(); + + } +} + +void unexport_gpio(int pin) { + FILE *file = fopen("/sys/class/gpio/unexport", "w"); + if (file) { + fprintf(file, "%d", pin); + fclose(file); + } else { + printf("Unable to unexport GPIO %d: [%d] %s\n", pin, errno, strerror(errno)); + cleanup(); + } +} + +void set_gpio(int pin, int value) { + char path[50]; + snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin); + FILE *file = fopen(path, "w"); + if (file) { + fprintf(file, "%d", value); + fclose(file); + } else { + printf("Unable to set value of GPIO %d: [%d] %s\n", pin, errno, strerror(errno)); + cleanup(); + } +} + +int main(int argc, char *argv[]) { + if (argc != 5) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + int pan_steps = atoi(argv[2]); + int tilt_steps = atoi(argv[3]); + int delay = atoi(argv[4]); + + config *selected_config = NULL; + int config_count = sizeof(list) / sizeof(list[0]); + for (int i = 0; i < config_count; i++) { + if (strcmp(list[i].name, argv[1]) == 0) { + selected_config = &list[i]; + break; + } + } + if (selected_config == NULL) { + fprintf(stderr, "Error: config '%s' not found.\n", argv[1]); + return 1; + } + + for (int i = 0; i < 4; i++) { + PAN_PINS[i] = selected_config->pan[i]; + TILT_PINS[i] = selected_config->tilt[i]; + } + + for (int i = 0; i < 4; i++) { + export_gpio(PAN_PINS[i]); + export_gpio(TILT_PINS[i]); + } + + int pan_remaining = abs(pan_steps); + int tilt_remaining = abs(tilt_steps); + int pan_reverse = (pan_steps < 0); + int tilt_reverse = (tilt_steps < 0); + int pan_micro = 0; + int tilt_micro = 0; + + while (pan_remaining > 0 || tilt_remaining > 0) { + int pan_has = pan_remaining > 0; + int tilt_has = tilt_remaining > 0; + + int pan_eff = pan_has ? (tilt_has ? delay : delay / 2) : 0; + int tilt_eff = tilt_has ? (pan_has ? delay : delay / 2) : 0; + int eff_delay = (pan_eff > tilt_eff) ? pan_eff : tilt_eff; + + if (pan_has) { + const int (*seq)[4] = pan_reverse ? REVERSE_STEP_SEQUENCE : STEP_SEQUENCE; + for (int k = 0; k < 4; k++) { + set_gpio(PAN_PINS[k], seq[pan_micro][k]); + } + if (++pan_micro >= 8) { + pan_micro = 0; + pan_remaining--; + } + } + + if (tilt_has) { + const int (*seq)[4] = tilt_reverse ? REVERSE_STEP_SEQUENCE : STEP_SEQUENCE; + for (int k = 0; k < 4; k++) { + set_gpio(TILT_PINS[k], seq[tilt_micro][k]); + } + if (++tilt_micro >= 8) { + tilt_micro = 0; + tilt_remaining--; + } + } + + usleep(eff_delay); + } + + for (int i = 0; i < 4; i++) { + release_gpio(PAN_PINS[i]); + release_gpio(TILT_PINS[i]); + } +}