/********************************************************************************* * Copyright: (C) 2019 LingYun IoT System Studio * All rights reserved. * * Filename: gpio.c * Description: This file is GPIO input/output functions * * Version: 1.0.0(2019年06月24日) * Author: Guo Wenxue * ChangeLog: 1, Release initial version on "2019年06月24日 23时46分47秒" * ********************************************************************************/ #include #include #include #include #include #include #include #include #include "logger.h" #include "util_proc.h" #include "gpio.h" #define RPI_GPIONAME "gpiochip0" static struct gpiod_chip *s_chip; static gpio_t *s_gpio = NULL; int gpio_init(gpio_t *gpio) { int i; int rv; s_gpio = gpio; if( !gpio ) { log_error("Invalid input arguments $gpio\n"); return -1; } if( !gpio->incnt && !gpio->outcnt ) { log_warn("WARNNING: No GPIO pins configured\n"); return 0; } /* gpiod open chip */ s_chip = gpiod_chip_open_by_name(RPI_GPIONAME); if( !s_chip ) { log_error("gpiod open chip failure, maybe you need running as root\n"); return -2; } log_info("gpiod initialise open chip ok\n"); /* gpiod request all output pins */ for(i=0; ioutcnt; i++) { gpio->output[i].line = gpiod_chip_get_line(s_chip, gpio->output[i].pin); if( !gpio->output[i].line ) { log_error("gpiod get line for '%s' pin[#%d] failure\n", gpio->output[i].name, gpio->output[i].pin ); return -2; } if( gpiod_line_request_output(gpio->output[i].line, gpio->output[i].name, !gpio->output[i].active_level) < 0 ) { log_error("gpiod request '%s' pin[#%d] output failure: %s\n", gpio->output[i].name, gpio->output[i].pin, strerror(errno)); } else { log_info("gpiod request '%s' pin[#%d] output ok\n", gpio->output[i].name, gpio->output[i].pin); } } /* gpiod request all input pins */ for(i=0; iincnt; i++) { gpio->input[i].line = gpiod_chip_get_line(s_chip, gpio->input[i].pin); if( !gpio->input[i].line ) { log_error("gpiod get line for '%s' pin[#%d] failure\n", gpio->input[i].name, gpio->input[i].pin ); return -2; } if( gpio->output[i].active_level ) rv = gpiod_line_request_rising_edge_events(gpio->input[i].line, gpio->input[i].name) ; else rv = gpiod_line_request_falling_edge_events(gpio->input[i].line, gpio->input[i].name) ; if( rv < 0 ) { log_error("gpiod request '%s' pin[#%d] event edge [%s] failure: %s\n", gpio->input[i].name, gpio->input[i].pin, gpio->output[i].active_level?"rising":"falling", strerror(errno)); } else { log_info("gpiod request '%s' pin[#%d] event edge [%s] ok\n", gpio->input[i].name, gpio->input[i].pin, gpio->output[i].active_level?"rising":"falling"); } } return 0; } void gpio_term(void) { int i; log_info("start teriminated GPIO\n"); if( !s_gpio->incnt && !s_gpio->outcnt ) { return ; } for(i=0; ioutcnt; i++) { gpiod_line_release(s_gpio->output[i].line); } for(i=0; iincnt; i++) { gpiod_line_release(s_gpio->input[i].line); } gpiod_chip_close(s_chip); } void gpio_out(char *name, char *cmd) { int i; int found = 0; for( i=0; ioutcnt; i++ ) { if( !strncasecmp(s_gpio->output[i].name, name, strlen(name))) { found = 1; break; } } if( !found ) { log_error("GPIO output for '%s' pin not found\n", name); return ; } if( strstr(cmd, "on") ) { gpiod_line_set_value(s_gpio->output[i].line, s_gpio->output[i].active_level); } else if( strstr(cmd, "off") ) { gpiod_line_set_value(s_gpio->output[i].line, !s_gpio->output[i].active_level); } return ; } void *light_on_worker(void *arg) { int i; int found = 0; char *name = (char *)arg; gpio_info_t *gpiout; if( !name ) { log_error("Invalid input arugment\n"); return NULL; } if( s_gpio->light_intval <= 0 ) { log_error("Invalid light_intval value[%d] in configure file\n", s_gpio->light_intval); return NULL; } for(i=0; ioutcnt; i++) { if( strstr(s_gpio->output[i].name, name) ) { gpiout = &(s_gpio->output[i]); found = 1; } } if( !found ) { log_error("Light '%s' not found\n", name); return NULL; } log_info("Trun on %s for [%d] seconds\n", gpiout->name, s_gpio->light_intval); gpio_out(gpiout->name, "on"); sleep(s_gpio->light_intval); gpio_out(gpiout->name, "off"); return NULL; } /* Return value: 0(LOW): Nobody detected, !0: indoor or hallway detected */ int infrared_detect(void) { int i; int rv = 0; int res = 0; struct gpiod_line_event ev; struct gpiod_line_bulk bulk, event_bulk; struct gpiod_line *line; int num_lines = 0; gpiod_line_bulk_init(&bulk); for(i=0; iincnt; i++) { if( strstr(s_gpio->input[i].name, "infrared")) { gpiod_line_bulk_add(&bulk, s_gpio->input[i].line); num_lines ++; } } if( !num_lines ) { log_error("No infrared detect gpiod lines found\n"); return 0; } log_debug("infrared start detect event now...\n"); rv = gpiod_line_event_wait_bulk(&bulk, NULL, &event_bulk); if( rv <= 0 ) { log_error("infrared gpiod line wait[%s] event failure!\n", s_gpio->input[i].name); return 0; } for (i=0; iincnt; i++) { if(line == s_gpio->input[i].line) { if( s_gpio->input[i].active_level != gpiod_line_get_value(line) ) { //log_debug("infrared '%s' detect get wrong power level\n", s_gpio->input[i].name); continue; } if( strstr(s_gpio->input[i].name, "indoor") ) { log_debug("indoor infrared gpiod wait get event.\n", s_gpio->input[i].name); res |= FLAG_INFRARED_INDOOR; } else if( strstr(s_gpio->input[i].name, "hallway") ) { log_debug("hallway infrared gpiod wait get event.\n", s_gpio->input[i].name); res |= FLAG_INFRARED_HALLWAY; } } } } return res; }