/********************************************************************************* * Copyright: (C) 2024 LingYun IoT System Studio * All rights reserved. * * Filename: relay.h * Description: This file is used to control relay * * * Pin connection: * Relay Module IGKBoard-IMX6ULL * VCC <-----> 5V * I <-----> #Pin31 * GND <-----> GND * ********************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "relay.h" static inline void msleep(unsigned long ms); static void program_usage(const char *progname) { printf("Usage: %s [OPTION]...\n", progname); printf(" This is relay control program. \n"); printf(" -r[relay ] Specify relay device, such as 0\n"); printf(" -s[status ] Specify relay status, 0 for open, 1 for close\n"); printf(" -h[help ] Display this help information\n"); printf("\n"); printf("%s program Version v1.0.0\n", progname); printf("Copyright (C) 2023 LingYun IoT System Studio.\n"); return; } int main(int argc, char *argv[]) { char *progname=NULL; int rv; int which = -1; int status = ON; struct option long_options[] = { {"relay", required_argument, NULL, 'r'}, {"status", required_argument, NULL, 's'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; progname = basename(argv[0]); /* Parser the command line parameters */ while ((rv = getopt_long(argc, argv, "r:s:h", long_options, NULL)) != -1) { switch (rv) { case 'r': /* Set relay number, such as 0...max */ which = atoi(optarg); break; case 's': /* Set relay status, 0 for open and 1 for close */ status = atoi(optarg); break; case 'h': /* Get help information */ program_usage(progname); return 0; default: break; } } if( (rv=init_relay()) < 0 ) { printf("initial relays gpio failure, rv=%d\n", rv); return 1; } turn_relay(which, status); return 0; } /*+----------------------------------+ *| Relay API based on libgpiod v2.0 | *+----------------------------------+*/ static relay_t relays_info[RELAY_CNT] = { {"relay1", 0, 22, ACTIVE_HIGH, 0, NULL}, /* #31, GPIO1_IO22 on chip0 line 22, active high */ }; /* relays context */ static relays_t relays = { .relays = relays_info, .count = RELAY_CNT, }; int init_relay(void) { relay_t *relay; int i, rv = 0; char chip_dev[32]; struct gpiod_chip *chip; /* gpio chip */ struct gpiod_line_settings *settings; /* gpio direction, bias, active_low, value */ struct gpiod_line_config *line_cfg; /* gpio line */ struct gpiod_request_config *req_cfg; /* gpio consumer, it can be NULL */ /* defined in libgpiod-2.0/lib/line-settings.c: struct gpiod_line_settings { enum gpiod_line_direction direction; enum gpiod_line_edge edge_detection; enum gpiod_line_drive drive; enum gpiod_line_bias bias; bool active_low; enum gpiod_line_clock event_clock; long debounce_period_us; enum gpiod_line_value output_value; }; */ settings = gpiod_line_settings_new(); if (!settings) { printf("unable to allocate line settings\n"); rv = -2; goto cleanup; } /* defined in libgpiod-2.0/lib/line-config.c struct gpiod_line_config { struct per_line_config line_configs[LINES_MAX]; size_t num_configs; enum gpiod_line_value output_values[LINES_MAX]; size_t num_output_values; struct settings_node *sref_list; }; */ line_cfg = gpiod_line_config_new(); if (!line_cfg) { printf("unable to allocate the line config structure"); rv = -2; goto cleanup; } /* defined in libgpiod-2.0/lib/request-config.c: struct gpiod_request_config { char consumer[GPIO_MAX_NAME_SIZE]; size_t event_buffer_size; }; */ req_cfg = gpiod_request_config_new(); if (!req_cfg) { printf("unable to allocate the request config structure"); rv = -2; goto cleanup; } for(i=0; ichip_num); chip = gpiod_chip_open(chip_dev); if( !chip ) { printf("open gpiochip failure, maybe you need running as root\n"); rv = -3; goto cleanup; } /* Set as output direction, active low and default level as inactive */ gpiod_line_settings_reset(settings); gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_OUTPUT); gpiod_line_settings_set_active_low(settings, relay->active); gpiod_line_settings_set_output_value(settings, GPIOD_LINE_VALUE_INACTIVE); /* set gpio line */ gpiod_line_config_reset(line_cfg); gpiod_line_config_add_line_settings(line_cfg, &relay->gpio_num, 1, settings); /* Can be NULL for default settings. */ gpiod_request_config_set_consumer(req_cfg, relay->name); /* Request a set of lines for exclusive usage. */ relay->request = gpiod_chip_request_lines(chip, req_cfg, line_cfg); gpiod_chip_close(chip); //printf("request %5s relay[%d] for gpio output okay\n", relay->name, relay->gpio); } cleanup: if( rv< 0 ) term_relay(); if( line_cfg ) gpiod_line_config_free(line_cfg); if( req_cfg ) gpiod_request_config_free(req_cfg); if( settings ) gpiod_line_settings_free(settings); return rv; } int term_relay(void) { int i; relay_t *relay; printf("terminate relay gpios\n"); for(i=0; irequest ) { turn_relay(i, OFF); gpiod_line_request_release(relay->request); } } return 0; } int turn_relay(int which, int cmd) { relay_t *relay; int rv = 0; int value = 0; if( which<0 || which>=relays.count ) { printf("Invalid input arguments\n"); return -1; } relay = &relays.relays[which]; value = OFF==cmd ? GPIOD_LINE_VALUE_INACTIVE : GPIOD_LINE_VALUE_ACTIVE; gpiod_line_request_set_value(relay->request, relay->gpio_num, value); relay->status = OFF==cmd ? OFF : ON; return 0; } int toggle_relay(int which) { relay_t *relay; if( which<0 || which>=relays.count ) { printf("Invalid input arguments\n"); return -1; } relay = &relays.relays[which]; return turn_relay(which, !relay->status); } /*+-------------------------------+ *| Misc functions API | *+-------------------------------+*/ static inline void msleep(unsigned long ms) { struct timespec cSleep; unsigned long ulTmp; cSleep.tv_sec = ms / 1000; if (cSleep.tv_sec == 0) { ulTmp = ms * 10000; cSleep.tv_nsec = ulTmp * 100; } else { cSleep.tv_nsec = 0; } nanosleep(&cSleep, 0); return ; }