summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--freeonebook.c88
-rw-r--r--gpio.c70
-rw-r--r--gpio.h13
4 files changed, 146 insertions, 26 deletions
diff --git a/Makefile b/Makefile
index 2839e99..8951600 100644
--- a/Makefile
+++ b/Makefile
@@ -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;
}
diff --git a/gpio.c b/gpio.c
index c381be1..64d79f3 100644
--- a/gpio.c
+++ b/gpio.c
@@ -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);
+}
diff --git a/gpio.h b/gpio.h
index a0d3271..1f66586 100644
--- a/gpio.h
+++ b/gpio.h
@@ -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