guowenxue
2024-09-27 10a1a347aa6fa60aa0dd667a4d892aaced108121
commit | author | age
1e563e 1 /*********************************************************************************
G 2  *      Copyright:  (C) 2024 LingYun IoT System Studio
3  *                  All rights reserved.
4  *
5  *       Filename:  led.c
6  *    Description:  This file is used to control RGB 3-colors LED
7  *
8  *
9  * Pin connection:
10  *               RGB Led Module           IGKBoard
11  *                   R        <----->      #Pin33
12  *                   G        <----->      #Pin35
13  *                   B        <----->      #Pin37
14  *                  GND       <----->      GND
15  *
16  ********************************************************************************/
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <dirent.h>
23 #include <string.h>
24 #include <time.h>
25 #include <errno.h>
26 #include <signal.h>
27
28 #include <gpiod.h>
29
30 #define DELAY     300
31
32 #define ON        1
33 #define OFF       0
34
35 /* Three LEDs number */
36 enum
37 {
38     LED_R = 0,
39     LED_G,
40     LED_B,
41     LEDCNT,
42 };
43
44 enum
45 {
46     ACTIVE_HIGH, /* High level will turn led on */
47     ACTIVE_LOW,  /* Low level will turn led on */
48 };
49
50 /* Three LEDs hardware information */
51 typedef struct led_s
52 {
53     const char               *name;      /* RGB 3-color LED name  */
54     int                       chip_num;  /* RGB 3-color LED connect chip */
55     int                       gpio_num;  /* RGB 3-color LED connect line */
56     int                       active;    /* RGB 3-color LED active level */
57     struct gpiod_line_request *request;  /* libgpiod gpio request handler */
58 } led_t;
59
60 static led_t leds_info[LEDCNT] =
61 {
62     {"red",   0, 23, ACTIVE_HIGH, NULL }, /* GPIO1_IO23 on chip0 line 23, active high */
63     {"green", 4, 1,  ACTIVE_HIGH, NULL }, /* GPIO5_IO01 on chip4 line 1, active high */
64     {"blue",  4, 8,  ACTIVE_HIGH, NULL }, /* GPIO5_IO08 on chip4 line 8, active high */
65 };
66
67 /* Three LEDs API context */
68 typedef struct leds_s
69 {
70     led_t               *leds;  /* led pointer to leds_info */
71     int                  count; /* led count */
72 } leds_t;
73
74
75 /* function declaration  */
76 int init_led(leds_t *leds);
77 int term_led(leds_t *leds);
78 int turn_led(leds_t *leds, int which, int cmd);
79 static inline void msleep(unsigned long ms);
80
81
82 int g_stop = 0;
83
84 void sig_handler(int signum)
85 {
86     switch( signum )
87     {
88         case SIGINT:
89         case SIGTERM:
90             g_stop = 1;
91
92         default:
93             break;
94     }
95
96     return ;
97 }
98
99 int main(int argc, char *argv[])
100 {
101     int                 rv;
102     leds_t              leds =
103     {
104         .leds  = leds_info,
105         .count = LEDCNT,
106     };
107
108     if( (rv=init_led(&leds)) < 0 )
109     {
110         printf("initial leds gpio failure, rv=%d\n", rv);
111         return 1;
112     }
113     printf("initial RGB Led gpios okay\n");
114
115     signal(SIGINT,  sig_handler);
116     signal(SIGTERM, sig_handler);
117
118     while( !g_stop )
119     {
120         turn_led(&leds, LED_R, ON);
121         msleep(DELAY);
122         turn_led(&leds, LED_R, OFF);
123         msleep(DELAY);
124
125         turn_led(&leds, LED_G, ON);
126         msleep(DELAY);
127         turn_led(&leds, LED_G, OFF);
128         msleep(DELAY);
129
130         turn_led(&leds, LED_B, ON);
131         msleep(DELAY);
132         turn_led(&leds, LED_B, OFF);
133         msleep(DELAY);
134     }
135
136     term_led(&leds);
137     return 0;
138 }
139
140 int term_led(leds_t *leds)
141 {
142     int            i;
143     led_t         *led;
144
145     printf("terminate RGB Led gpios\n");
146
147     if( !leds )
148     {
149         printf("Invalid input arguments\n");
150         return -1;
151     }
152
153     for(i=0; i<leds->count; i++)
154     {
155         led = &leds->leds[i];
156
157         if( led->request )
158         {
159             turn_led(leds, i, OFF);
160             gpiod_line_request_release(led->request);
161         }
162     }
163
164     return 0;
165 }
166
167
168 int init_led(leds_t *leds)
169 {
170     led_t                       *led;
171     int                          i, rv = 0;
172     char                         chip_dev[32];
173     struct gpiod_chip           *chip;      /* gpio chip */
174     struct gpiod_line_settings  *settings;  /* gpio direction, bias, active_low, value */
175     struct gpiod_line_config    *line_cfg;  /* gpio line */
176     struct gpiod_request_config *req_cfg;   /* gpio consumer, it can be NULL */
177
178
179     if( !leds )
180     {
181         printf("Invalid input arguments\n");
182         return -1;
183     }
184
185
186     /* defined in libgpiod-2.0/lib/line-settings.c:
187
188         struct gpiod_line_settings {
189             enum gpiod_line_direction direction;
190             enum gpiod_line_edge edge_detection;
191             enum gpiod_line_drive drive;
192             enum gpiod_line_bias bias;
193             bool active_low;
194             enum gpiod_line_clock event_clock;
195             long debounce_period_us;
196             enum gpiod_line_value output_value;
197         };
198      */
199     settings = gpiod_line_settings_new();
200     if (!settings)
201     {
202         printf("unable to allocate line settings\n");
203         rv = -2;
204         goto cleanup;
205     }
206
207     /* defined in libgpiod-2.0/lib/line-config.c
208
209         struct gpiod_line_config {
210             struct per_line_config line_configs[LINES_MAX];
211             size_t num_configs;
212             enum gpiod_line_value output_values[LINES_MAX];
213             size_t num_output_values;
214             struct settings_node *sref_list;
215         };
216     */
217
218     line_cfg = gpiod_line_config_new();
219     if (!line_cfg)
220     {
221         printf("unable to allocate the line config structure");
222         rv = -2;
223         goto cleanup;
224     }
225
226
227     /* defined in libgpiod-2.0/lib/request-config.c:
228
229         struct gpiod_request_config {
230             char consumer[GPIO_MAX_NAME_SIZE];
231             size_t event_buffer_size;
232         };
233      */
234     req_cfg = gpiod_request_config_new();
235     if (!req_cfg)
236     {
237         printf("unable to allocate the request config structure");
238         rv = -2;
239         goto cleanup;
240     }
241
242     for(i=0; i<leds->count; i++)
243     {
244         led = &leds->leds[i];
245
246         snprintf(chip_dev, sizeof(chip_dev), "/dev/gpiochip%d", led->chip_num);
247         chip = gpiod_chip_open(chip_dev);
248         if( !chip )
249         {
250             printf("open gpiochip failure, maybe you need running as root\n");
251             rv = -3;
252             goto cleanup;
253         }
254
255         /* Set as output direction, active low and default level as inactive */
256         gpiod_line_settings_reset(settings);
257         gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_OUTPUT);
258         gpiod_line_settings_set_active_low(settings, led->active);
259         gpiod_line_settings_set_output_value(settings, GPIOD_LINE_VALUE_INACTIVE);
260
261         /* set gpio line */
262         gpiod_line_config_reset(line_cfg);
263         gpiod_line_config_add_line_settings(line_cfg, &led->gpio_num, 1, settings);
264
265         /* Can be NULL for default settings. */
266         gpiod_request_config_set_consumer(req_cfg, led->name);
267
268         /* Request a set of lines for exclusive usage. */
269         led->request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);
270
271         gpiod_chip_close(chip);
272         //printf("request %5s led[%d] for gpio output okay\n", led->name, led->gpio);
273     }
274
275 cleanup:
276
277     if( rv< 0 )
278         term_led(leds);
279
280     if( line_cfg )
281         gpiod_line_config_free(line_cfg);
282
283     if( req_cfg )
284         gpiod_request_config_free(req_cfg);
285
286     if( settings )
287         gpiod_line_settings_free(settings);
288
289     return rv;
290 }
291
292 int turn_led(leds_t *leds, int which, int cmd)
293 {
294     led_t         *led;
295     int            rv = 0;
296     int            value = 0;
297
298     if( !leds || which<0 || which>=leds->count )
299     {
300         printf("Invalid input arguments\n");
301         return -1;
302     }
303
304     led = &leds->leds[which];
305
306     value = OFF==cmd ? GPIOD_LINE_VALUE_INACTIVE : GPIOD_LINE_VALUE_ACTIVE;
307
308     gpiod_line_request_set_value(led->request, led->gpio_num, value);
309
310     return 0;
311 }
312
313 static inline void msleep(unsigned long ms)
314 {
315     struct timespec cSleep;
316     unsigned long ulTmp;
317
318     cSleep.tv_sec = ms / 1000;
319     if (cSleep.tv_sec == 0)
320     {
321         ulTmp = ms * 10000;
322         cSleep.tv_nsec = ulTmp * 100;
323     }
324     else
325     {
326         cSleep.tv_nsec = 0;
327     }
328
329     nanosleep(&cSleep, 0);
330
331     return ;
332 }