diff --git a/src/06-mini-project/daemon/gpio/button.c b/src/06-mini-project/daemon/gpio/button.c index 87d329b..983c98a 100644 --- a/src/06-mini-project/daemon/gpio/button.c +++ b/src/06-mini-project/daemon/gpio/button.c @@ -1,16 +1,53 @@ #include "button.h" #include +#include #include #include #include #include - +#include +#include +#include +#include #define GPIO_EXPORT "/sys/class/gpio/export" #define GPIO_UNEXPORT "/sys/class/gpio/unexport" +#define GPIO_BTN_BASE "/sys/class/gpio/gpio" + +#define MAX_EVENTS 10 +atomic_int ev_tail = 0; + +int epoll_fd; +struct epoll_event ev[MAX_EVENTS]; +pthread_t epoll_thread_id; + +int btn_add_epoll_event(btn_t* btn); +void epoll_init(); +static void* epoll_thread(void* arg); + +btn_t* btn_init(btn_type_t type) { + btn_t* btn = malloc(sizeof(btn_t)); + if (btn == NULL) return NULL; + + char gpio_path[32] = GPIO_BTN_BASE; + char pin[32]; + switch (type) { + case BTN_INCREASE: + strcpy(pin, GPIO_BTN_INCREASE); + break; + case BTN_DECREASE: + strcpy(pin, GPIO_BTN_DECREASE); + break; + case BTN_MODE: + strcpy(pin, GPIO_BTN_MODE); + break; + default: + printf("Invalid button type\n"); + return NULL; + } + strcat(gpio_path, pin); -int btn_open(const char* gpio_path, const char* pin) { int f = open(GPIO_UNEXPORT, O_WRONLY); write(f, pin, strlen(pin)); close(f); @@ -40,5 +77,74 @@ int btn_open(const char* gpio_path, const char* pin) { strcat(value_path, "/value"); f = open(value_path, O_RDONLY); - return f; + if (f == -1) { + printf("Failed to setup button on pin %s\n", pin); + return NULL; + } + btn->gpio = f; + + // Dummy read to clear initial state before waiting + char buf[2]; + pread(btn->gpio, buf, sizeof(buf), 0); + + btn_add_epoll_event(btn); + + return btn; +} + +void btn_set_callback(btn_t* btn, btn_callback_t callback) { + btn->callback = callback; +} + +// TODO add mutex to protect this function +int btn_add_epoll_event(btn_t* btn) { + int tail = atomic_fetch_add(&ev_tail, 1); + if (tail >= MAX_EVENTS-1) { + perror("Failed to add epoll event"); + return -1; + } + + if (tail == 0) { + epoll_init(); + } + + // EPOLLIN is working well as EPOLLPRI (which is more used for priority data) + // EPOLLERR is used to detect if there is an error + // EPOLLET is for edge triggered mode (non-blocking) + ev[tail].events = EPOLLIN | EPOLLERR | EPOLLET; + ev[tail].data.fd = btn->gpio; + int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, btn->gpio, &ev[tail]); + if (ret < 0) { + perror("Failed to add epoll event"); + return -1; + } + return tail; +} + +void epoll_init(){ + if (pthread_create(&epoll_thread_id, NULL, epoll_thread, NULL) != 0) { + perror("Failed to create timer thread"); + exit(30); + } +} + +static void* epoll_thread(void* arg) { + int epfd = epoll_create1(0); + if (epfd < 0) { + perror("Failed to create epoll instance"); + exit(EXIT_FAILURE); + } + epoll_fd = epfd; + + while (1) { + struct epoll_event events[MAX_EVENTS]; + int n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); + if (n < 0) { + perror("epoll_wait"); + continue; + } + for (int i = 0; i < n; i++) { + + } + } } diff --git a/src/06-mini-project/daemon/gpio/led.c b/src/06-mini-project/daemon/gpio/led.c index 701ee0b..dcee127 100644 --- a/src/06-mini-project/daemon/gpio/led.c +++ b/src/06-mini-project/daemon/gpio/led.c @@ -8,8 +8,33 @@ #include #include #include +#include -int led_open(const char* gpio_path, const char* pin) { +#define GPIO_EXPORT "/sys/class/gpio/export" +#define GPIO_UNEXPORT "/sys/class/gpio/unexport" +#define GPIO_LED_BASE "/sys/class/gpio/gpio" + +#include + +led_t* led_init(led_type_t type) { + led_t* led = malloc(sizeof(led_t)); + if (led == NULL) return NULL; + + // Concatenate GPIO LED path based on type + char gpio_path[32] = GPIO_LED_BASE; + char pin[32]; + switch (type) { + case LED_STATUS: + strcpy(pin, GPIO_LED_STATUS); + break; + case LED_POWER: + strcpy(pin, GPIO_LED_POWER); + break; + default: + printf("Invalid LED type\n"); + return NULL; + } + strcat(gpio_path, pin); // unexport pin out of sysfs (reinitialization) int f = open(GPIO_UNEXPORT, O_WRONLY); @@ -36,13 +61,38 @@ int led_open(const char* gpio_path, const char* pin) { strcat(value_path, "/value"); f = open(value_path, O_RDWR); - return f; + if (f == -1) { + printf("Failed to setup led on pin %s\n", pin); + return NULL; + } + + led->gpio = f; + return led; } -void led_on(int led) { - pwrite(led, "1", sizeof("1"), 0); +void led_on(led_t* led) { + if (led == NULL) { + return; + } + pwrite(led->gpio, "1", sizeof("1"), 0); } -void led_off(int led) { - pwrite(led, "0", sizeof("0"), 0); +void led_off(led_t* led) { + if (led == NULL) { + return; + } + pwrite(led->gpio, "0", sizeof("0"), 0); +} + +void led_toggle(led_t* led) { + if (led == NULL) { + return; + } + char value[2]; + pread(led->gpio, value, sizeof(value), 0); + if (value[0] == '0') { + led_on(led); + } else { + led_off(led); + } } diff --git a/src/06-mini-project/daemon/main.c b/src/06-mini-project/daemon/main.c index 3c2acc9..5b299c3 100644 --- a/src/06-mini-project/daemon/main.c +++ b/src/06-mini-project/daemon/main.c @@ -14,13 +14,7 @@ #include "gpio/led.h" #include "gpio/button.h" -/* - * status led - gpioa.10 --> gpio10 - * power led - gpiol.10 --> gpio362 - */ -#define GPIO_LED "/sys/class/gpio/gpio10" -#define LED "10" #define GPIO_BTN1 "/sys/class/gpio/gpio0" #define BTN1 "0" @@ -49,33 +43,10 @@ const char* BTN[NBR_BTN] = {BTN1, BTN2, BTN3}; void* btn_thread(void* arg) { ThreadData* data = (ThreadData*)arg; - // Open all button with the right flags - int btn[NBR_BTN] = {0}; - for(int i=0; i