diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | freeonebook.c | 88 | ||||
-rw-r--r-- | gpio.c | 70 | ||||
-rw-r--r-- | gpio.h | 13 |
4 files changed, 146 insertions, 26 deletions
@@ -1,5 +1,6 @@ CC=arm-linux-gnueabihf-gcc CFLAGS=-Wall -Wextra +LDFLAGS=-lpthread freeonebook: freeonebook.o gpio.o diff --git a/freeonebook.c b/freeonebook.c index 86cf470..ada4c3a 100644 --- a/freeonebook.c +++ b/freeonebook.c @@ -1,32 +1,98 @@ -#include <stdint.h> +#include <fcntl.h> +#include <limits.h> #include <stdio.h> #include <string.h> -#include <fcntl.h> +#include <stdlib.h> +#include <sys/mman.h> #include <unistd.h> #include "gpio.h" -#define BUTTON_SPECIAL 89 -#define BUTTON_PREVBOOK 91 -#define BUTTON_PREVPAGE 92 -#define BUTTON_NEXTPAGE 95 -#define BUTTON_NEXTCHAPTER 96 -#define BUTTON_NEXTBOOK 100 - -#define ENABLE_LEFT_DISPLAY 5 -#define ENABLE_RIGHT_DISPLAY 4 +#define FBSIZE (1186848 * 2) +#define SDPATH "/run/media/mmcblk0p1" void enable_displays(void) { + printf("enabling displays\n"); gpio_set(ENABLE_LEFT_DISPLAY); gpio_set(ENABLE_RIGHT_DISPLAY); } +void halt(void) +{ + char *halt[] = { "shutdown", "-h", "now", NULL }; + execvp(halt[0], halt); +} + +void poweroff(int reason) +{ + static int halting = 0; + if (halting) { + return; + } + halting = 1; + + printf("shutting down (%d)\n", reason); + + if (reason == GPIO_LOWBATTERY) { + printf("low battery\n"); + } + + exit(0); +} + +void buttonpress(int button) +{ + switch (button) { + case BUTTON_SPECIAL: + printf("special\n"); + break; + + case BUTTON_NEXTCHAPTER: + printf("next chapter\n"); + break; + + case BUTTON_PREVBOOK: + printf("previous book\n"); + break; + + case BUTTON_NEXTBOOK: + printf("next book\n"); + break; + + case BUTTON_PREVPAGE: + printf("previous page\n"); + break; + + case BUTTON_NEXTPAGE: + printf("next page\n"); + break; + + default: + printf("button %d pressed\n", button); + } +} + int main(int argc, char *argv[]) { (void)argc; (void)argv; + atexit(halt); + gpio_init(); + gpio_watch(GPIO_LOWBATTERY, poweroff); + gpio_watch(GPIO_SHUTDOWN, poweroff); + gpio_watch(BUTTON_SPECIAL, buttonpress); + gpio_watch(BUTTON_PREVBOOK, buttonpress); + gpio_watch(BUTTON_PREVPAGE, buttonpress); + gpio_watch(BUTTON_NEXTPAGE, buttonpress); + gpio_watch(BUTTON_NEXTCHAPTER, buttonpress); + gpio_watch(BUTTON_NEXTBOOK, buttonpress); + enable_displays(); + + for (;;) { + sleep(INT_MAX); + } return 0; } @@ -1,6 +1,9 @@ #include "gpio.h" #include <fcntl.h> +#include <poll.h> +#include <pthread.h> +#include <stdlib.h> #include <stdint.h> #include <stdio.h> #include <string.h> @@ -43,35 +46,36 @@ void gpio_clear(int port) close(fd); } -static void gpio_enable(int export_fd, int port, const char *state) +static void gpio_enable_multi(int export_fd, int port, const char *state) { + printf("enabling GPIO %d, state '%s'\n", port, state); + dprintf(export_fd, "%d", port); int fd = gpio_open(port, "direction", O_WRONLY); write(fd, "direction", strlen(state)); close(fd); } +static void gpio_enable(int port, const char *state) +{ + int fd = open(GPIO_EXPORT, O_WRONLY); + gpio_enable_multi(fd, port, state); + close(fd); +} + void gpio_init(void) { struct { uint8_t port; const char *initstate; } ports[] = { - { 100, GPIO_IN }, - { 91, GPIO_IN }, - { 96, GPIO_IN }, - { 89, GPIO_IN }, - { 95, GPIO_IN }, - { 92, GPIO_IN }, - { 108, GPIO_INIT_LOW }, - { 94, GPIO_INIT_LOW }, - { 101, GPIO_INIT_LOW }, /* 95, 92 */ + { 108, GPIO_INIT_LOW }, + { 94, GPIO_INIT_LOW }, + { 101, GPIO_INIT_LOW }, { 5, GPIO_INIT_LOW }, { 4, GPIO_INIT_LOW }, - { 93, GPIO_IN }, { 98, GPIO_INIT_HIGH }, - { 90, GPIO_INIT_HIGH }, /* 108, 94, 101 */ - { 88, GPIO_IN }, + { 90, GPIO_INIT_HIGH }, { 0, GPIO_INIT_LOW }, { 1, GPIO_INIT_LOW }, { 2, GPIO_INIT_LOW }, @@ -111,7 +115,7 @@ void gpio_init(void) { 72, GPIO_INIT_LOW }, { 73, GPIO_INIT_LOW }, { 74, GPIO_INIT_LOW }, - { 75, GPIO_INIT_LOW }, /* not enabled */ + { 75, GPIO_INIT_LOW }, { 78, GPIO_INIT_LOW }, { 79, GPIO_INIT_LOW }, { 86, GPIO_INIT_LOW }, @@ -150,7 +154,43 @@ void gpio_init(void) int gpio_export = open(GPIO_EXPORT, O_WRONLY); for (size_t i = 0; i < sizeof(ports) / sizeof(ports[0]); i++) { - gpio_enable(gpio_export, ports[i].port, ports[i].initstate); + gpio_enable_multi(gpio_export, ports[i].port, ports[i].initstate); } close(gpio_export); } + +struct gpio_watcher { + int port; + void (*fn)(int); +}; + +void *gpio_watch_thread(void *arg) +{ + struct gpio_watcher *w = arg; + int fd = gpio_open(w->port, "value", O_RDONLY); + for (;;) { + struct pollfd fds[] = { { fd, POLLPRI | POLLERR, 0 } }; + if (poll(fds, 1, -1) == 1) { + if (gpio_get(w->port)) { + w->fn(w->port); + } + } + } + close(fd); + return NULL; +} + +void gpio_watch(int port, void (*fn)(int)) +{ + printf("starting watcher for %d\n", port); + gpio_enable(port, "in"); + int edge = gpio_open(port, "edge", O_WRONLY); + write(edge, "both", 4); + close(edge); + + pthread_t thread; + struct gpio_watcher *watcher = malloc(sizeof(*watcher)); + watcher->port = port; + watcher->fn = fn; + pthread_create(&thread, NULL, gpio_watch_thread, watcher); +} @@ -1,9 +1,22 @@ #ifndef GPIO_H #define GPIO_H +#define ENABLE_RIGHT_DISPLAY 4 +#define ENABLE_LEFT_DISPLAY 5 + +#define GPIO_LOWBATTERY 88 +#define BUTTON_SPECIAL 89 +#define BUTTON_PREVBOOK 91 +#define BUTTON_PREVPAGE 92 +#define GPIO_SHUTDOWN 93 +#define BUTTON_NEXTPAGE 95 +#define BUTTON_NEXTCHAPTER 96 +#define BUTTON_NEXTBOOK 100 + int gpio_get(int port); void gpio_set(int port); void gpio_clear(int port); void gpio_init(void); +void gpio_watch(int port, void (*fn)(int)); #endif |