/*********************************************************************************
|
* Copyright: (C) 2021 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 Raspberry Pi Board
|
* R <-----> #Pin33(BCM GPIO13)
|
* G <-----> #Pin35(BCM GPIO19)
|
* B <-----> #Pin37(BCM GPIO26)
|
* GND <-----> GND
|
*
|
* System install:
|
* sudo apt install -y libgpiod-dev gpiod
|
*
|
*
|
********************************************************************************/
|
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <unistd.h>
|
#include <fcntl.h>
|
#include <dirent.h>
|
#include <string.h>
|
#include <time.h>
|
#include <errno.h>
|
#include <signal.h>
|
|
#include <gpiod.h>
|
|
#define DELAY 500
|
|
#define ON 1
|
#define OFF 0
|
|
/* Three LEDs code */
|
enum
|
{
|
LED_R = 0,
|
LED_G,
|
LED_B,
|
LEDCNT,
|
};
|
|
/* Three LEDs hardware information */
|
typedef struct led_info_s
|
{
|
const char *name; /* RGB 3-color LED name */
|
int gpio; /* RGB 3-color LED BCM pin number */
|
int active;/* RGB 3-color LED active GPIO level: 0->low 1->high */
|
struct gpiod_line *line; /* libgpiod line */
|
} led_info_t;
|
|
static led_info_t leds_info[LEDCNT] =
|
{
|
{"red", 13, 1, NULL },
|
{"green", 19, 1, NULL },
|
{"blue", 26, 1, NULL },
|
};
|
|
/* Three LEDs API context */
|
typedef struct led_ctx_s
|
{
|
struct gpiod_chip *chip;
|
led_info_t *leds;
|
int count;
|
} led_ctx_t;
|
|
int init_led(led_ctx_t *ctx);
|
int term_led(led_ctx_t *ctx);
|
int turn_led(led_ctx_t *ctx, 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;
|
led_ctx_t led_ctx =
|
{
|
.chip = NULL,
|
.leds = leds_info,
|
.count = LEDCNT,
|
};
|
|
if( (rv=init_led(&led_ctx)) < 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(&led_ctx, LED_R, ON);
|
msleep(DELAY);
|
turn_led(&led_ctx, LED_R, OFF);
|
msleep(DELAY);
|
|
turn_led(&led_ctx, LED_G, ON);
|
msleep(DELAY);
|
turn_led(&led_ctx, LED_G, OFF);
|
msleep(DELAY);
|
|
turn_led(&led_ctx, LED_B, ON);
|
msleep(DELAY);
|
turn_led(&led_ctx, LED_B, OFF);
|
msleep(DELAY);
|
}
|
|
term_led(&led_ctx);
|
return 0;
|
}
|
|
int term_led(led_ctx_t *ctx)
|
{
|
int i;
|
led_info_t *led;
|
|
printf("terminate RGB Led gpios\n");
|
|
if( !ctx )
|
{
|
printf("Invalid input arguments\n");
|
return -1;
|
}
|
|
if( !ctx->chip )
|
return 0;
|
|
for(i=0; i<ctx->count; i++)
|
{
|
led = &ctx->leds[i];
|
|
if( led->line )
|
gpiod_line_release(led->line);
|
}
|
|
gpiod_chip_close(ctx->chip);
|
return 0;
|
}
|
|
|
int init_led(led_ctx_t *ctx)
|
{
|
int i, rv;
|
led_info_t *led;
|
|
if( !ctx )
|
{
|
printf("Invalid input arguments\n");
|
return -1;
|
}
|
|
ctx->chip = gpiod_chip_open_by_name("gpiochip0");
|
if( !ctx->chip )
|
{
|
printf("open gpiochip failure, maybe you need running as root\n");
|
return -2;
|
}
|
|
|
for(i=0; i<ctx->count; i++)
|
{
|
led = &ctx->leds[i];
|
|
led->line = gpiod_chip_get_line(ctx->chip, led->gpio);
|
if( !led->line )
|
{
|
printf("open gpioline for %s[%d] failed\n", led->name, led->gpio);
|
rv = -3;
|
goto failed;
|
}
|
|
rv = gpiod_line_request_output(led->line, led->name, !led->active);
|
if( rv )
|
{
|
printf("request gpio output for %5s[%d] failed\n", led->name, led->gpio);
|
rv = -4;
|
goto failed;
|
}
|
|
//printf("request %5s led[%d] for gpio output okay\n", led->name, led->gpio);
|
}
|
|
return 0;
|
|
failed:
|
term_led(ctx);
|
return rv;
|
}
|
|
int turn_led(led_ctx_t *ctx, int which, int cmd)
|
{
|
int rv = 0;
|
led_info_t *led;
|
|
if( !ctx || which<0 || which>=ctx->count )
|
{
|
printf("Invalid input arguments\n");
|
return -1;
|
}
|
|
led = &ctx->leds[which];
|
|
if( OFF == cmd )
|
{
|
gpiod_line_set_value(led->line, !led->active);
|
}
|
else
|
{
|
gpiod_line_set_value(led->line, led->active);
|
}
|
|
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 ;
|
}
|