/********************************************************************************* * Copyright: (C) 2024 LingYun IoT System Studio * All rights reserved. * * Filename: led.c * Description: This file is used to control RGB 3-colors LED * * * Pin connection: * RGB Led Module IGKBoard * R <-----> #Pin33 * G <-----> #Pin35 * B <-----> #Pin37 * GND <-----> GND * ********************************************************************************/ #include #include #include #include #include #include #include #include #include #include #define DELAY 300 #define ON 1 #define OFF 0 /* Three LEDs number */ enum { LED_R = 0, LED_G, LED_B, LEDCNT, }; enum { ACTIVE_HIGH, /* High level will turn led on */ ACTIVE_LOW, /* Low level will turn led on */ }; /* Three LEDs hardware information */ typedef struct led_s { const char *name; /* RGB 3-color LED name */ int chip_num; /* RGB 3-color LED connect chip */ int gpio_num; /* RGB 3-color LED connect line */ int active; /* RGB 3-color LED active level */ struct gpiod_line_request *request; /* libgpiod gpio request handler */ } led_t; static led_t leds_info[LEDCNT] = { {"red", 0, 23, ACTIVE_HIGH, NULL }, /* GPIO1_IO23 on chip0 line 23, active high */ {"green", 4, 1, ACTIVE_HIGH, NULL }, /* GPIO5_IO01 on chip4 line 1, active high */ {"blue", 4, 8, ACTIVE_HIGH, NULL }, /* GPIO5_IO08 on chip4 line 8, active high */ }; /* Three LEDs API context */ typedef struct leds_s { led_t *leds; /* led pointer to leds_info */ int count; /* led count */ } leds_t; /* function declaration */ int init_led(leds_t *leds); int term_led(leds_t *leds); int turn_led(leds_t *leds, int which, int cmd); static inline void msleep(unsigned long ms); int g_stop = 0; void sig_handler(int signum) { switch( signum ) { case SIGINT: case SIGTERM: g_stop = 1; default: break; } return ; } int main(int argc, char *argv[]) { int rv; leds_t leds = { .leds = leds_info, .count = LEDCNT, }; if( (rv=init_led(&leds)) < 0 ) { printf("initial leds gpio failure, rv=%d\n", rv); return 1; } printf("initial RGB Led gpios okay\n"); signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); while( !g_stop ) { turn_led(&leds, LED_R, ON); msleep(DELAY); turn_led(&leds, LED_R, OFF); msleep(DELAY); turn_led(&leds, LED_G, ON); msleep(DELAY); turn_led(&leds, LED_G, OFF); msleep(DELAY); turn_led(&leds, LED_B, ON); msleep(DELAY); turn_led(&leds, LED_B, OFF); msleep(DELAY); } term_led(&leds); return 0; } int term_led(leds_t *leds) { int i; led_t *led; printf("terminate RGB Led gpios\n"); if( !leds ) { printf("Invalid input arguments\n"); return -1; } for(i=0; icount; i++) { led = &leds->leds[i]; if( led->request ) { turn_led(leds, i, OFF); gpiod_line_request_release(led->request); } } return 0; } int init_led(leds_t *leds) { led_t *led; 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 */ if( !leds ) { printf("Invalid input arguments\n"); return -1; } /* 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; icount; i++) { led = &leds->leds[i]; snprintf(chip_dev, sizeof(chip_dev), "/dev/gpiochip%d", led->chip_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, led->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, &led->gpio_num, 1, settings); /* Can be NULL for default settings. */ gpiod_request_config_set_consumer(req_cfg, led->name); /* Request a set of lines for exclusive usage. */ led->request = gpiod_chip_request_lines(chip, req_cfg, line_cfg); gpiod_chip_close(chip); //printf("request %5s led[%d] for gpio output okay\n", led->name, led->gpio); } cleanup: if( rv< 0 ) term_led(leds); 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 turn_led(leds_t *leds, int which, int cmd) { led_t *led; int rv = 0; int value = 0; if( !leds || which<0 || which>=leds->count ) { printf("Invalid input arguments\n"); return -1; } led = &leds->leds[which]; value = OFF==cmd ? GPIOD_LINE_VALUE_INACTIVE : GPIOD_LINE_VALUE_ACTIVE; gpiod_line_request_set_value(led->request, led->gpio_num, value); return 0; } 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 ; }