diff --git a/src/Makefile b/src/Makefile index ca829a2..d77522a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,4 +1,4 @@ -OBJS=main.o log.o gpio.o +OBJS=main.o sysinput.o log.o gpio.o msg_queue.o time_func.o LIBS= upiwin: $(OBJS) diff --git a/src/gpio.c b/src/gpio.c index 02f5e52..1e2f902 100644 --- a/src/gpio.c +++ b/src/gpio.c @@ -182,9 +182,23 @@ void Gpio_cleanup(void) } } +int Gpio_read_buttons(void) +{ + int rc = 0; + + if (gpio_input(GLINE_BUTTON1) == 0) + rc |= STATE_BUTTON1; + if (gpio_input(GLINE_BUTTON2) == 0) + rc |= STATE_BUTTON2; + if (gpio_input(GLINE_BUTTON3) == 0) + rc |= STATE_BUTTON3; + if (gpio_input(GLINE_BUTTON4) == 0) + rc |= STATE_BUTTON4; +} + int Gpio_poll_buttons(void) { - int new_state = 0; + int new_state = Gpio_read_buttons(); int tmp, ndx, mask; if (gpio_input(GLINE_BUTTON1) == 0) diff --git a/src/gpio.h b/src/gpio.h index a1d48b7..416d4bc 100644 --- a/src/gpio.h +++ b/src/gpio.h @@ -3,6 +3,7 @@ extern int Gpio_setup(void); extern void Gpio_cleanup(void); +extern int Gpio_read_buttons(void); extern int Gpio_poll_buttons(void); #endif /* __GPIO_H_INCLUDED */ diff --git a/src/main.c b/src/main.c index 0781b05..1490722 100644 --- a/src/main.c +++ b/src/main.c @@ -1,16 +1,42 @@ #include #include "gpio.h" #include "log.h" +#include "time_func.h" +#include "sysinput.h" int main(int argc, char *argv[]) { + MSG msg; + + TimeInit(); if (Gpio_setup() != 0) return EXIT_FAILURE; atexit(Gpio_cleanup); + if (SysEnableInput() != 0) + return EXIT_FAILURE; + atexit(SysDisableInput); Log(LINFO, "System ready."); - for (;;) { - Gpio_poll_buttons(); + for (;;) + { + if (MqPeek(Sys_Queue, &msg, PEEK_REMOVE)) + { + switch (msg.message) + { + case WM_HWBUTTONDOWN: + Log(LINFO, "Button %d was pressed.", (int)(msg.attrs[0])); + break; + + case WM_HWBUTTONUP: + Log(LINFO, "Button %d was released.", (int)(msg.attrs[0])); + break; + + default: + break; + } + } } + + return EXIT_SUCCESS; } diff --git a/src/msg.h b/src/msg.h new file mode 100644 index 0000000..c880d76 --- /dev/null +++ b/src/msg.h @@ -0,0 +1,20 @@ +#ifndef __MSG_H_INCLUDED +#define __MSG_H_INCLUDED + +#include "wintype.h" + +#define MSG_ATTRCOUNT 2 + +typedef tagMSG { + uintptr_t target; + unsigned message; + uintptr_t attrs[MSG_ATTRCOUNT]; + TIMESTAMP timestamp; +} MSG, *PMSG; + +#define WM_NULL 0x0000 + +#define WM_HWBUTTONDOWN 0x0020 +#define WM_HWBUTTONUP 0x0021 + +#endif /* __MSG_H_INCLUDED */ diff --git a/src/msg_queue.c b/src/msg_queue.c new file mode 100644 index 0000000..9d89ae3 --- /dev/null +++ b/src/msg_queue.c @@ -0,0 +1,92 @@ +#include +#include +#include "wintype.h" +#include "time_func.h" +#include "msg_queue.h" + +PMSG_QUEUE MqAlloc(int nentries) +{ + int sz = sizeof(MSG_QUEUE) + (nentries * sizeof(MSG)); + PMSG_QUEUE rc; + + rc = (PMSG_QUEUE)malloc(sz); + if (!rc) + return NULL; + memset(rc, 0 sz); + rc->startbound = &(rc->messagestore); + rc->endbound = rc->startbound + nentries; + rc->head = rc->tail = rc->startbound; + rc->nentries = nentries; + pthread_mutex_init(&(rc->mutex), NULL); + return rc; +} + +void MqDestroy(PMSG_QUEUE queue) +{ + pthread_mutex_destroy(&(queue->mutex)); + free(queue); +} + +static void post_internal(PMSG_QUEUE queue, PMSG msg) +{ + PMSG nexttail; + + pthread_mutex_lock(&(queue->mutex)); + nexttail = queue->tail + 1; + if (nexttail == queue->endbound) + nexttail = queue->startbound; + if (nexttail != queue->head) + { + memcpy(queue->tail, msg, sizeof(MSG)); + queue->tail = nexttail; + } + /* else drop the message silently */ + + pthread_mutex_unlock(&(queue->mutex)); +} + +void MqPost(PMSG_QUEUE queue, uintptr_t target, unsigned message, const uintptr_t *attrs, int nattrs) +{ + MSG tmpmsg; + + memset(&tmpmsg, 0, sizeof(MSG)); + tmpmsg.target = target; + tmpmsg.message = message; + if (nattrs > MSG_ATTRCOUNT) + nattrs = MSG_ATTRCOUNT; + if (nattrs > 0) + memcpy(&(tmpmsg.attrs), attrs, sizeof(uintptr_t) * nattrs); + tmpmsg.timestamp = TimeSinceStart(); + post_internal(queue, &tmpmsg); +} + +void MqPost1(PMSG_QUEUE queue, uintptr_t target, unsigned message, uintptr_t attr1) +{ + MSG tmpmsg; + + memset(&tmpmsg, 0, sizeof(MSG)); + tmpmsg.target = target; + tmpmsg.message = message; + tmpmsg.attrs[0] = attr1; + tmpmsg.timestamp = TimeSinceStart(); + post_internal(queue, &tmpmsg); +} + +int MqPeek(PMSG_QUEUE queue, PMSG msg, unsigned flags) +{ + int rc = 0; + PMSG nexthead; + + pthread_mutex_lock(&(queue->mutex)); + if (queue->head != queue->tail) + { + nexthead = queue->head + 1; + if (nexthead == queue->endbound) + nexthead = queue->startbound; + memcpy(msg, queue->head, sizeof(MSG)); + if (flags & PEEK_REMOVE) + queue->head = nexthead; + } + pthread_mutex_unlock(&(queue->mutex)); + return rc; +} diff --git a/src/msg_queue.h b/src/msg_queue.h new file mode 100644 index 0000000..4b0ddc5 --- /dev/null +++ b/src/msg_queue.h @@ -0,0 +1,27 @@ +#ifndef __MSG_QUEUE_H_INCLUDED +#define __MSG_QUEUE_H_INCLUDED + +#include "wintype.h" +#include "msg.h" + +typedef struct tagMSG_QUEUE { + struct tagMSG_QUEUE *next; + PMSG startbound; + PMSG endbound; + PMSG head; + PMSG tail; + int nentries; + pthread_mutex_t mutex; + MSG messagestore[0]; +} MSG_QUEUE, *PMSG_QUEUE; + +#define PEEK_REMOVE 0x0001 +#define PEEK_NOREMOVE 0x0000 + +extern PMSG_QUEUE MqAlloc(int nentries); +extern void MqDestroy(PMSG_QUEUE queue); +extern void MqPost(PMSG_QUEUE queue, uintptr_t target, unsigned message, const uintptr_t *attrs, int nattrs); +extern void MqPost1(PMSG_QUEUE queue, uintptr_t target, unsigned message, uintptr_t attr1); +extern int MqPeek(PMSG_QUEUE queue, PMSG msg, unsigned flags); + +#endif /* __MSG_QUEUE_H_INCLUDED */ diff --git a/src/sysinput.c b/src/sysinput.c new file mode 100644 index 0000000..27fda6c --- /dev/null +++ b/src/sysinput.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include "log.h" +#include "msg_queue.h" +#include "gpio.h" + +PMSG_QUEUE Sys_Queue = NULL; + +static pthread_t ithread; +static volatile sig_atomic_t running = 1; +static int last_bstate = 0; + +static void *input_thread(void *arg) +{ + int st, tmp, mask; + uintptr_t attr; + + while (running) + { + /* poll hardware buttons */ + st = Gpio_read_buttons(); + if (st != last_bstate) + { + tmp = last_state & ~st; + for (attr = 1, mask = 1; attr <= 4; attr++, mask <<= 1) + { + if (tmp & mask) + MqPost1(Sys_Queue, 0, WM_HWBUTTONUP, attr); + } + tmp = st & ~last_state; + for (attr = 1, mask = 1; attr <= 4; attr++, mask <<= 1) + { + if (tmp & mask) + MqPost1(Sys_Queue, 0, WM_HWBUTTONDOWN, attr); + } + last_bstate = st; + } + + /* additional poll activity here */ + } + return NULL; +} + +int SysEnableInput(void) +{ + int rc; + + Sys_Queue = MqAlloc(64); + if (!Sys_Queue) + { + Log(LFATAL, "Unable to allocate system message queue."); + return 1; + } + running = 1; + rc = pthread_create(&ithread, NULL, input_thread, NULL); + if (rc != 0) + Log(LFATAL, "Unable to start system input thread (%d).", rc); + return rc; +} + +void SysDisableInput(void) +{ + running = 0; + pthread_join(ithread, NULL); + MqDestroy(Sys_Queue); + Sys_Queue = NULL; +} diff --git a/src/sysinput.h b/src/sysinput.h new file mode 100644 index 0000000..29b5a18 --- /dev/null +++ b/src/sysinput.h @@ -0,0 +1,11 @@ +#ifndef __SYSINPUT_H_INCLUDED +#define __SYSINPUT_H_INCLUDED + +#include "msg_queue.h" + +extern PMSG_QUEUE Sys_Queue; + +extern int SysEnableInput(void); +extern void SysDisableInput(void); + +#endif /* __SYSINPUT_H_INCLUDED */ diff --git a/src/time_func.c b/src/time_func.c new file mode 100644 index 0000000..1ca8487 --- /dev/null +++ b/src/time_func.c @@ -0,0 +1,25 @@ +#include +#include +#include "time_func.h" + +static TIMESTAMP start_timestamp = 0; + +TIMESTAMP TimeSinceEpoch(void) +{ + TIMESTAMP rc; + struct timeval tv; + + gettimeofday(&tv, NULL); + rc = (tv.tv_sec * (TIMESTAMP)1000) + (tv.tv_usec / (TIMESTAMP)1000); + return rc; +} + +TIMESTAMP TimeSinceStart(void) +{ + return TimeSinceEpoch() - start_timestamp; +} + +void TimeInit(void) +{ + start_timestamp = TimeSinceEpoch(); +} diff --git a/src/time_func.h b/src/time_func.h new file mode 100644 index 0000000..80e0b14 --- /dev/null +++ b/src/time_func.h @@ -0,0 +1,10 @@ +#ifndef __TIMEFUNC_H_INCLUDED +#define __TIMEFUNC_H_INCLUDED + +#include "wintype.h" + +extern TIMESTAMP TimeSinceEpoch(void); +extern TIMESTAMP TimeSinceStart(void); +extern void TimeInit(void); + +#endif /* __TIMEFUNC_H_INCLUDED */ diff --git a/src/wintype.h b/src/wintype.h new file mode 100644 index 0000000..08d921b --- /dev/null +++ b/src/wintype.h @@ -0,0 +1,8 @@ +#ifndef __WINTYPE_H_INCLUDED +#define __WINTYPE_H_INCLUDED + +#include + +typedef uint64_t TIMESTAMP; + +#endif /* __WINTYPE_H_INCLUDED */