implemented the touchscreen device events

This commit is contained in:
Amy G. Bowersox 2019-12-07 00:46:27 -07:00
parent 0dc56d49e5
commit dfe9991496
7 changed files with 158 additions and 29 deletions

View File

@ -10,10 +10,11 @@
static const struct option long_options[] = { static const struct option long_options[] = {
{"framebuffer", required_argument, 0, 'F'}, {"framebuffer", required_argument, 0, 'F'},
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"touchscreen", required_argument, 0, 'T'},
{ NULL, 0, 0, 0 } { NULL, 0, 0, 0 }
}; };
static const char *short_options = "F:h"; static const char *short_options = "F:hT:";
static const char *helptext = static const char *helptext =
"UPIWIN - Micro Pi Windows server program\n\n" "UPIWIN - Micro Pi Windows server program\n\n"
@ -21,6 +22,7 @@ static const char *helptext =
"Available options:\n" "Available options:\n"
" -F,--framebuffer [devname] - Specifies the framebuffer device name\n" " -F,--framebuffer [devname] - Specifies the framebuffer device name\n"
" -h,--help - Displays this help message.\n" " -h,--help - Displays this help message.\n"
" -T,--touchscreen - Specifies the touchscreen device name\n"
""; "";
#define EXITFUNCBLOCK_FUNCCOUNT 64 #define EXITFUNCBLOCK_FUNCCOUNT 64
@ -58,6 +60,7 @@ static void run_exit_funcs(void)
static void init_defaults(void) static void init_defaults(void)
{ {
Gconfig.framebuffer_device = "/dev/fb1"; Gconfig.framebuffer_device = "/dev/fb1";
Gconfig.touchscreen_device = "/dev/input/touchscreen";
Gconfig.button_debounce = 100; Gconfig.button_debounce = 100;
Gconfig.sys_mq_length = 64; Gconfig.sys_mq_length = 64;
} }
@ -92,6 +95,18 @@ static HRESULT parse_cmdline(int argc, char *argv[], GLOBAL_CONFIG *parsed)
help = TRUE; help = TRUE;
break; break;
case 'T':
pstr = strdup(optarg);
if (!pstr)
{
Log(LERROR, "Out of memory in parse_cmdline");
return E_OUTOFMEMORY;
}
if (parsed->touchscreen_device)
free((PVOID)(parsed->touchscreen_device));
parsed->touchscreen_device = pstr;
break;
default: default:
fprintf(stderr, "%s: unexpected option -%c\n", argv[0], c); fprintf(stderr, "%s: unexpected option -%c\n", argv[0], c);
return E_UNEXPECTED; return E_UNEXPECTED;
@ -109,6 +124,8 @@ static void overlay_config(GLOBAL_CONFIG *p)
{ {
if (p->framebuffer_device) if (p->framebuffer_device)
Gconfig.framebuffer_device = p->framebuffer_device; Gconfig.framebuffer_device = p->framebuffer_device;
if (p->touchscreen_device)
Gconfig.touchscreen_device = p->touchscreen_device;
} }
HRESULT Config_setup(int argc, char *argv[]) HRESULT Config_setup(int argc, char *argv[])

View File

@ -7,6 +7,7 @@ typedef void (*PEXITFUNC)(void);
typedef struct tagGLOBAL_CONFIG { typedef struct tagGLOBAL_CONFIG {
PCSTR framebuffer_device; PCSTR framebuffer_device;
PCSTR touchscreen_device;
UINT32 button_debounce; UINT32 button_debounce;
UINT32 sys_mq_length; UINT32 sys_mq_length;
} GLOBAL_CONFIG; } GLOBAL_CONFIG;

View File

@ -20,6 +20,11 @@ static void do_draw(void)
Fb_filled_rectangle(110, 60, 150, 100, FBPRIMCLR_YELLOW, FALSE); Fb_filled_rectangle(110, 60, 150, 100, FBPRIMCLR_YELLOW, FALSE);
} }
static void log_touch(const char *event, UINT_PTR x, UINT_PTR y)
{
Log(LINFO, "Touch %s at (%u, %u)", event, x, y);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
HRESULT hr; HRESULT hr;
@ -77,6 +82,18 @@ int main(int argc, char *argv[])
} }
break; break;
case WM_TOUCHDOWN:
log_touch("DOWN", msg.attrs[0], msg.attrs[1]);
break;
case WM_TOUCHMOVE:
log_touch("MOVE", msg.attrs[0], msg.attrs[1]);
break;
case WM_TOUCHUP:
log_touch("UP", msg.attrs[0], msg.attrs[1]);
break;
default: default:
break; break;
} }

View File

@ -17,4 +17,8 @@ typedef struct tagMSG {
#define WM_HWBUTTONDOWN 0x0020 #define WM_HWBUTTONDOWN 0x0020
#define WM_HWBUTTONUP 0x0021 #define WM_HWBUTTONUP 0x0021
#define WM_TOUCHDOWN 0x0030
#define WM_TOUCHMOVE 0x0031
#define WM_TOUCHUP 0x0032
#endif /* __MSG_H_INCLUDED */ #endif /* __MSG_H_INCLUDED */

View File

@ -61,7 +61,7 @@ void Mq_post(PMSG_QUEUE queue, HANDLE target, UINT32 message, const UINT_PTR *at
post_internal(queue, &tmpmsg); post_internal(queue, &tmpmsg);
} }
void Mq_post1(PMSG_QUEUE queue, HANDLE target, UINT32 message, UINT_PTR attr1) void Mq_post2(PMSG_QUEUE queue, HANDLE target, UINT32 message, UINT_PTR attr1, UINT_PTR attr2)
{ {
MSG tmpmsg; MSG tmpmsg;
@ -69,6 +69,7 @@ void Mq_post1(PMSG_QUEUE queue, HANDLE target, UINT32 message, UINT_PTR attr1)
tmpmsg.target = target; tmpmsg.target = target;
tmpmsg.message = message; tmpmsg.message = message;
tmpmsg.attrs[0] = attr1; tmpmsg.attrs[0] = attr1;
tmpmsg.attrs[1] = attr2;
tmpmsg.timestamp = Time_since_start(); tmpmsg.timestamp = Time_since_start();
post_internal(queue, &tmpmsg); post_internal(queue, &tmpmsg);
} }

View File

@ -21,7 +21,10 @@ typedef struct tagMSG_QUEUE {
extern PMSG_QUEUE Mq_alloc(UINT32 nentries); extern PMSG_QUEUE Mq_alloc(UINT32 nentries);
extern void Mq_destroy(PMSG_QUEUE queue); extern void Mq_destroy(PMSG_QUEUE queue);
extern void Mq_post(PMSG_QUEUE queue, HANDLE target, UINT32 message, const UINT_PTR *attrs, int nattrs); extern void Mq_post(PMSG_QUEUE queue, HANDLE target, UINT32 message, const UINT_PTR *attrs, int nattrs);
extern void Mq_post1(PMSG_QUEUE queue, HANDLE target, UINT32 message, UINT_PTR attr1); extern void Mq_post2(PMSG_QUEUE queue, HANDLE target, UINT32 message, UINT_PTR attr1, UINT_PTR attr2);
extern BOOL Mq_peek(PMSG_QUEUE queue, PMSG msg, UINT32 flags); extern BOOL Mq_peek(PMSG_QUEUE queue, PMSG msg, UINT32 flags);
#define Mq_post0(q, tgt, msg) Mq_post2(q, tgt, msg, 0, 0)
#define Mq_post1(q, tgt, msg, attr) Mq_post2(q, tgt, msg, attr, 0)
#endif /* __MSG_QUEUE_H_INCLUDED */ #endif /* __MSG_QUEUE_H_INCLUDED */

View File

@ -1,7 +1,11 @@
#include <stddef.h> #include <stddef.h>
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h> #include <pthread.h>
#include <linux/input.h>
#include "scode.h" #include "scode.h"
#include "config.h" #include "config.h"
#include "log.h" #include "log.h"
@ -9,46 +13,113 @@
#include "gpio.h" #include "gpio.h"
#include "time_func.h" #include "time_func.h"
#define INPUT_EVENT_BATCH 16
PMSG_QUEUE Sys_Queue = NULL; PMSG_QUEUE Sys_Queue = NULL;
static pthread_t ithread; static pthread_t ithread;
static volatile sig_atomic_t running = 1; static volatile sig_atomic_t running = 1;
static UINT32 last_bstate = 0; static int ts_fd = 0;
static void *input_thread(void *arg) static UINT32 last_bstate = 0;
static TIMESTAMP button_event_ok[GPIO_BUTTON_COUNT];
static UINT_PTR touch_x = 0;
static UINT_PTR touch_y = 0;
static UINT32 touch_nextmsg = WM_TOUCHMOVE;
static void poll_buttons(void)
{ {
UINT32 st, down, up, mask; UINT32 st, down, up, mask;
UINT_PTR attr; UINT_PTR attr;
TIMESTAMP now; TIMESTAMP now;
TIMESTAMP button_event_ok[GPIO_BUTTON_COUNT];
/* poll hardware buttons */
st = Gpio_read_buttons();
if (st != last_bstate)
{
now = Time_since_start();
up = last_bstate & ~st;
down = st & ~last_bstate;
for (attr = 1, mask = GRB_STATE_BUTTON1; attr <= GPIO_BUTTON_COUNT; attr++, mask <<= 1)
{
if (now < button_event_ok[attr - 1])
continue;
if (up & mask)
{
button_event_ok[attr - 1] = now + Gconfig.button_debounce;
Mq_post1(Sys_Queue, 0, WM_HWBUTTONUP, attr);
}
else if (down & mask)
Mq_post1(Sys_Queue, 0, WM_HWBUTTONDOWN, attr);
}
last_bstate = st;
}
}
static void poll_touchscreen(void)
{
int nb, nev, xerrno, i;
struct input_event buffer[INPUT_EVENT_BATCH];
nb = read(ts_fd, buffer, INPUT_EVENT_BATCH * sizeof(struct input_event));
if (nb == -1)
{
xerrno = errno;
if ((xerrno != EAGAIN) && (xerrno != EWOULDBLOCK))
Log(LERROR, "Error reading from touchscreen device (%d)", xerrno);
return;
}
else if (nb == 0)
{
Log(LERROR, "Unexpected end of file reading from touchscreen device");
return;
}
nev = nb / sizeof(struct input_event);
xerrno = nev * sizeof(struct input_event);
if (nb > xerrno)
Log(LERROR, "read %d bytes from touchscreen but we can only use %d", nb, xerrno);
for (i=0; i<nev; i++)
{
switch (buffer[i].type)
{
case EV_SYN:
if (buffer[i].code == SYN_REPORT)
{
Mq_post2(Sys_Queue, 0, touch_nextmsg, touch_x, touch_y);
touch_nextmsg = WM_TOUCHMOVE;
}
break;
case EV_ABS:
if (buffer[i].code == ABS_X)
touch_x = buffer[i].value;
else if (buffer[i].code == ABS_Y)
touch_y = buffer[i].value;
break;
case EV_KEY:
if (buffer[i].code == BTN_TOUCH)
touch_nextmsg = (buffer[i].value ? WM_TOUCHDOWN : WM_TOUCHUP);
break;
default:
break;
}
}
}
static void *input_thread(void *arg)
{
last_bstate = 0;
memset(button_event_ok, 0, GPIO_BUTTON_COUNT * sizeof(TIMESTAMP)); memset(button_event_ok, 0, GPIO_BUTTON_COUNT * sizeof(TIMESTAMP));
touch_x = touch_y = 0;
touch_nextmsg = WM_TOUCHMOVE;
while (running) while (running)
{ {
/* poll hardware buttons */ poll_buttons();
st = Gpio_read_buttons(); poll_touchscreen();
if (st != last_bstate)
{
now = Time_since_start();
up = last_bstate & ~st;
down = st & ~last_bstate;
for (attr = 1, mask = GRB_STATE_BUTTON1; attr <= GPIO_BUTTON_COUNT; attr++, mask <<= 1)
{
if (now < button_event_ok[attr - 1])
continue;
if (up & mask)
{
button_event_ok[attr - 1] = now + Gconfig.button_debounce;
Mq_post1(Sys_Queue, 0, WM_HWBUTTONUP, attr);
}
else if (down & mask)
Mq_post1(Sys_Queue, 0, WM_HWBUTTONDOWN, attr);
}
last_bstate = st;
}
/* additional poll activity here */
} }
return NULL; return NULL;
} }
@ -57,6 +128,8 @@ static void do_disable_input(void)
{ {
running = 0; running = 0;
pthread_join(ithread, NULL); pthread_join(ithread, NULL);
close(ts_fd);
ts_fd = -1;
Mq_destroy(Sys_Queue); Mq_destroy(Sys_Queue);
Sys_Queue = NULL; Sys_Queue = NULL;
} }
@ -72,11 +145,24 @@ HRESULT Sys_enable_input(void)
Log(LFATAL, "Unable to allocate system message queue."); Log(LFATAL, "Unable to allocate system message queue.");
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
} }
ts_fd = open(Gconfig.touchscreen_device, O_RDONLY|O_NONBLOCK);
if (ts_fd < 0)
{
rc = ERRNO_AS_SCODE;
Mq_destroy(Sys_Queue);
Log(LFATAL, "Unable to open touchscreen device (%08X).", rc);
return rc;
}
running = 1; running = 1;
threadrc = pthread_create(&ithread, NULL, input_thread, NULL); threadrc = pthread_create(&ithread, NULL, input_thread, NULL);
if (threadrc != 0) if (threadrc != 0)
{ {
rc = SCODE_FROM_ERRNO(threadrc); rc = SCODE_FROM_ERRNO(threadrc);
close(ts_fd);
ts_fd = -1;
Mq_destroy(Sys_Queue);
Log(LFATAL, "Unable to start system input thread (%08X).", rc); Log(LFATAL, "Unable to start system input thread (%08X).", rc);
} }
if (SUCCEEDED(rc)) if (SUCCEEDED(rc))