Browse Source

Merge pull request #72 from OpenHMD/digital-input-events

Digital input events (such as buttons, hat events, digital sticks)
TheOnlyJoey 8 years ago
parent
commit
a67f31fe1b

+ 1 - 0
CMakeLists.txt

@@ -23,6 +23,7 @@ set(openhmd_source_files
 	${CMAKE_CURRENT_LIST_DIR}/src/omath.c
 	${CMAKE_CURRENT_LIST_DIR}/src/platform-posix.c
 	${CMAKE_CURRENT_LIST_DIR}/src/fusion.c
+	${CMAKE_CURRENT_LIST_DIR}/src/queue.c
 )
 
 OPTION(OPENHMD_DRIVER_OCULUS_RIFT "Oculus Rift DK1 and DK2" ON)

+ 27 - 2
examples/simple/simple.c

@@ -17,12 +17,23 @@ void print_infof(ohmd_device* hmd, const char* name, int len, ohmd_float_value v
 {
 	float f[len];
 	ohmd_device_getf(hmd, val, f);
-	printf("%-20s", name);
+	printf("%-25s", name);
 	for(int i = 0; i < len; i++)
 		printf("%f ", f[i]);
 	printf("\n");
 }
 
+// gets int values from the device and prints them
+void print_infoi(ohmd_device* hmd, const char* name, int len, ohmd_int_value val)
+{
+	int iv[len];
+	ohmd_device_geti(hmd, val, iv);
+	printf("%-25s", name);
+	for(int i = 0; i < len; i++)
+		printf("%d ", iv[i]);
+	printf("\n");
+}
+
 int main(int argc, char** argv)
 {
 	ohmd_context* ctx = ohmd_ctx_create();
@@ -56,7 +67,7 @@ int main(int argc, char** argv)
 	int ivals[2];
 	ohmd_device_geti(hmd, OHMD_SCREEN_HORIZONTAL_RESOLUTION, ivals);
 	ohmd_device_geti(hmd, OHMD_SCREEN_VERTICAL_RESOLUTION, ivals + 1);
-	printf("resolution:         %i x %i\n", ivals[0], ivals[1]);
+	printf("resolution:              %i x %i\n", ivals[0], ivals[1]);
 
 	print_infof(hmd, "hsize:",            1, OHMD_SCREEN_HORIZONTAL_SIZE);
 	print_infof(hmd, "vsize:",            1, OHMD_SCREEN_VERTICAL_SIZE);
@@ -67,6 +78,8 @@ int main(int argc, char** argv)
 	print_infof(hmd, "left eye aspect:",  1, OHMD_LEFT_EYE_ASPECT_RATIO);
 	print_infof(hmd, "right eye aspect:", 1, OHMD_RIGHT_EYE_ASPECT_RATIO);
 	print_infof(hmd, "distortion k:",     6, OHMD_DISTORTION_K);
+	
+	print_infoi(hmd, "digital button count:", 1, OHMD_BUTTON_COUNT);
 
 	printf("\n");
 
@@ -79,6 +92,18 @@ int main(int argc, char** argv)
 		ohmd_device_setf(hmd, OHMD_POSITION_VECTOR, zero);
 
 		print_infof(hmd, "rotation quat:", 4, OHMD_ROTATION_QUAT);
+		print_infoi(hmd, "button event count:", 1, OHMD_BUTTON_EVENT_COUNT);
+		
+		int event_count = 0;
+
+		ohmd_device_geti(hmd, OHMD_BUTTON_EVENT_COUNT, &event_count);
+
+		for(int i = 0; i < event_count; i++){
+			int event[2] = {0, 0};
+			ohmd_device_geti(hmd, OHMD_BUTTON_POP_EVENT, event);
+			printf("button %d: %s", event[0], event[1] == OHMD_BUTTON_DOWN ? "down" : "up");
+		}
+
 		ohmd_sleep(.01);
 	}
 

+ 17 - 0
include/openhmd.h

@@ -44,6 +44,7 @@ typedef enum {
 	OHMD_S_UNKNOWN_ERROR = -1,
 	OHMD_S_INVALID_PARAMETER = -2,
 	OHMD_S_UNSUPPORTED = -3,
+	OHMD_S_INVALID_OPERATION = -4,
 
 	/** OHMD_S_USER_RESERVED and below can be used for user purposes, such as errors within ohmd wrappers, etc. */
 	OHMD_S_USER_RESERVED = -16384,
@@ -125,6 +126,14 @@ typedef enum {
 	/** int[1] (get): Physical vertical resolution of the device screen. */
 	OHMD_SCREEN_VERTICAL_RESOLUTION       =  1,
 
+	/** int[1] (get): Get number of events waiting in digital input event queue. */
+	OHMD_BUTTON_EVENT_COUNT               =  2,
+	/** int[1] (get): Get if the there was an overflow in the event queue causing events to be dropped. */
+	OHMD_BUTTON_EVENT_OVERFLOW            =  3,
+	/** int[1] (get): Get the number of physical digital input buttons on the device. */
+	OHMD_BUTTON_COUNT                     =  4,
+	/** int[2] (get): Performs an event pop action. Format: [button_index, button_state], where button_state is either OHMD_BUTTON_DOWN or OHMD_BUTTON_UP */
+	OHMD_BUTTON_POP_EVENT                 =  5,
 } ohmd_int_value;
 
 /** A collection of data information types used for setting information with ohmd_set_data(). */
@@ -146,6 +155,14 @@ typedef enum {
 	OHMD_IDS_AUTOMATIC_UPDATE = 0,
 } ohmd_int_settings;
 
+/** Button states for digital input events. */
+typedef enum {
+	/** Button was pressed. */
+	OHMD_BUTTON_DOWN = 0,
+	/** Button was released. */
+	OHMD_BUTTON_UP   = 1
+} ohmd_button_state;
+
 /** An opaque pointer to a context structure. */
 typedef struct ohmd_context ohmd_context;
 

+ 2 - 1
src/Makefile.am

@@ -9,7 +9,8 @@ libopenhmd_la_SOURCES = \
 	drv_dummy/dummy.c \
 	omath.c \
 	platform-posix.c \
-	fusion.c
+	fusion.c \
+	queue.c
 
 libopenhmd_la_LDFLAGS = -no-undefined -version-info 0:0:0
 libopenhmd_la_CPPFLAGS = -fPIC -I$(top_srcdir)/include -Wall 

+ 1 - 0
src/drv_dummy/dummy.c

@@ -70,6 +70,7 @@ static ohmd_device* open_device(ohmd_driver* driver, ohmd_device_desc* desc)
 	priv->base.properties.lens_vpos = 0.046800f;
 	priv->base.properties.fov = DEG_TO_RAD(125.5144f);
 	priv->base.properties.ratio = (1280.0f / 800.0f) / 2.0f;
+	priv->base.properties.digital_button_count = 4;
 
 	// calculate projection eye projection matrices from the device properties
 	ohmd_calc_default_proj_matrices(&priv->base.properties);

+ 48 - 10
src/openhmd.c

@@ -12,7 +12,9 @@
 #include <string.h>
 #include <stdio.h>
 
-// Running automatic updates at 144 Hz
+#define DIGITAL_INPUT_EVENT_QUEUE_SIZE 1024
+
+// Running automatic updates at 1000 Hz
 #define AUTOMATIC_UPDATE_SLEEP (1.0 / 1000.0)
 
 ohmd_context* OHMD_APIENTRY ohmd_ctx_create(void)
@@ -162,6 +164,9 @@ ohmd_device* OHMD_APIENTRY ohmd_list_open_device_s(ohmd_context* ctx, int index,
 		device->active_device_idx = ctx->num_active_devices;
 		ctx->active_devices[ctx->num_active_devices++] = device;
 
+		if(device->properties.digital_button_count > 0)
+			device->digital_input_event_queue = ohmdq_create(ctx, sizeof(ohmd_digital_input_event), DIGITAL_INPUT_EVENT_QUEUE_SIZE);
+
 		ohmd_unlock_mutex(ctx->update_mutex);
 
 		if(device->settings.automatic_update)
@@ -191,18 +196,22 @@ int OHMD_APIENTRY ohmd_close_device(ohmd_device* device)
 
 	ohmd_context* ctx = device->ctx;
 	int idx = device->active_device_idx;
+	ohmdq* dinq = device->digital_input_event_queue;
 
 	memmove(ctx->active_devices + idx, ctx->active_devices + idx + 1,
 		sizeof(ohmd_device*) * (ctx->num_active_devices - idx - 1));
 
 	device->close(device);
+	
+	if(dinq)
+		ohmdq_destroy(dinq);
 
 	ctx->num_active_devices--;
 
 	for(int i = idx; i < ctx->num_active_devices; i++)
 		ctx->active_devices[i]->active_device_idx--;
 
-	ohmd_unlock_mutex(device->ctx->update_mutex);
+	ohmd_unlock_mutex(ctx->update_mutex);
 
 	return OHMD_S_OK;
 }
@@ -372,15 +381,44 @@ int OHMD_APIENTRY ohmd_device_setf(ohmd_device* device, ohmd_float_value type, c
 
 int OHMD_APIENTRY ohmd_device_geti(ohmd_device* device, ohmd_int_value type, int* out)
 {
+	ohmdq* dinq = device->digital_input_event_queue;
+
 	switch(type){
-	case OHMD_SCREEN_HORIZONTAL_RESOLUTION:
-		*out = device->properties.hres;
-		return OHMD_S_OK;
-	case OHMD_SCREEN_VERTICAL_RESOLUTION:
-		*out = device->properties.vres;
-		return OHMD_S_OK;
-	default:
-		return OHMD_S_INVALID_PARAMETER;
+		case OHMD_SCREEN_HORIZONTAL_RESOLUTION:
+			*out = device->properties.hres;
+			return OHMD_S_OK;
+
+		case OHMD_SCREEN_VERTICAL_RESOLUTION:
+			*out = device->properties.vres;
+			return OHMD_S_OK;
+
+		case OHMD_BUTTON_EVENT_COUNT:
+			*out = dinq ? (int)ohmdq_get_size(dinq) : 0;
+			return OHMD_S_OK;
+
+		case OHMD_BUTTON_EVENT_OVERFLOW:
+			*out = dinq ? (ohmdq_get_size(dinq) == ohmdq_get_max(dinq)) : 0;
+			return OHMD_S_OK;
+
+		case OHMD_BUTTON_COUNT:
+			*out = device->properties.digital_button_count;
+			return OHMD_S_OK;
+
+		case OHMD_BUTTON_POP_EVENT: {
+				ohmd_digital_input_event event;
+
+				if(!ohmdq_pop(dinq, &event)){
+					return OHMD_S_INVALID_OPERATION;
+				}
+
+				out[0] = event.idx;
+				out[1] = event.state;
+
+				return OHMD_S_OK;
+			}
+
+		default:
+				return OHMD_S_INVALID_PARAMETER;
 	}
 }
 

+ 15 - 6
src/openhmdi.h

@@ -10,15 +10,16 @@
 #ifndef OPENHMDI_H
 #define OPENHMDI_H
 
-#include "openhmd.h"
-#include "omath.h"
-#include "platform.h"
-
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "openhmd.h"
+#include "omath.h"
+#include "platform.h"
+#include "queue.h"
+
 #define OHMD_MAX_DEVICES 16
 
 #define OHMD_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
@@ -28,8 +29,7 @@
 
 typedef struct ohmd_driver ohmd_driver;
 
-typedef struct
-{
+typedef struct {
 	char driver[OHMD_STR_SIZE];
 	char vendor[OHMD_STR_SIZE];
 	char product[OHMD_STR_SIZE];
@@ -43,6 +43,11 @@ typedef struct {
 	ohmd_device_desc devices[OHMD_MAX_DEVICES];
 } ohmd_device_list;
 
+typedef struct {
+	int idx;
+	ohmd_button_state state; 
+} ohmd_digital_input_event;
+
 struct ohmd_driver {
 	void (*get_device_list)(ohmd_driver* driver, ohmd_device_list* list);
 	ohmd_device* (*open_device)(ohmd_driver* driver, ohmd_device_desc* desc);
@@ -53,6 +58,8 @@ struct ohmd_driver {
 typedef struct {
 		int hres;
 		int vres;
+		int digital_button_count;
+
 		float hsize;
 		float vsize;
 
@@ -99,6 +106,8 @@ struct ohmd_device {
 
 	quatf rotation;
 	vec3f position;
+	
+	ohmdq* digital_input_event_queue;
 };
 
 

+ 97 - 0
src/queue.c

@@ -0,0 +1,97 @@
+/*
+ * OpenHMD - Free and Open Source API and drivers for immersive technology.
+ * Copyright (C) 2016 Fredrik Hultin.
+ * Distributed under the Boost 1.0 licence, see LICENSE for full text.
+ */
+
+/* Naive Thread Safe Circular Queue Implementation */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "queue.h"
+#include "openhmdi.h"
+
+struct ohmdq {
+	unsigned read_pos;
+	unsigned write_pos;
+	unsigned size;
+	unsigned max;
+	unsigned elem_size;
+	char* elems;
+	ohmd_mutex* mutex;
+};
+
+ohmdq* ohmdq_create(ohmd_context* ctx, unsigned elem_size, unsigned max)
+{
+	ohmdq* me = ohmd_alloc(ctx, sizeof(ohmdq));
+
+	me->elems = ohmd_alloc(ctx, elem_size * max);
+	me->max = max;
+	me->elem_size = elem_size;
+	me->read_pos = 0;
+	me->write_pos = 0;
+	me->size = 0;
+	me->mutex = ohmd_create_mutex(ctx);
+
+	return me;
+}
+
+bool ohmdq_push(ohmdq* me, const void* elem)
+{
+	bool ret = false;
+
+	ohmd_lock_mutex(me->mutex);	
+
+	if(me->size < me->max){
+		memcpy(me->elems + me->write_pos, elem, me->elem_size);
+		me->write_pos = (me->write_pos + me->elem_size) % (me->max * me->elem_size);
+		me->size++;
+		ret = true;
+	}
+
+	ohmd_unlock_mutex(me->mutex);	
+
+	return ret;
+}
+
+bool ohmdq_pop(ohmdq* me, void* out_elem)
+{
+	bool ret = false;
+	
+	ohmd_lock_mutex(me->mutex);	
+
+	if(me->size > 0){
+		memcpy(out_elem, me->elems + me->read_pos, me->elem_size);
+		me->read_pos = (me->read_pos + me->elem_size) % (me->max * me->elem_size);
+		me->size--;
+		ret = true;
+	}
+	
+	ohmd_unlock_mutex(me->mutex);	
+
+	return ret;
+}
+
+unsigned ohmdq_get_size(ohmdq* me)
+{
+	unsigned ret;
+
+	ohmd_lock_mutex(me->mutex);
+	ret = me->size;
+	ohmd_unlock_mutex(me->mutex);
+
+	return ret;
+}
+
+unsigned ohmdq_get_max(ohmdq* me)
+{
+	return me->max;
+}
+
+void ohmdq_destroy(ohmdq* me)
+{
+	free(me->elems);
+	ohmd_destroy_mutex(me->mutex);
+	free(me);
+}

+ 25 - 0
src/queue.h

@@ -0,0 +1,25 @@
+/*
+ * OpenHMD - Free and Open Source API and drivers for immersive technology.
+ * Copyright (C) 2016 Fredrik Hultin.
+ * Distributed under the Boost 1.0 licence, see LICENSE for full text.
+ */
+
+/* Naive Thread Safe Circular Queue */
+
+#ifndef OHMDQUEUE_H
+#define OHMDQUEUE_H
+
+#include <stdbool.h>
+
+typedef struct ohmdq ohmdq;
+typedef struct ohmd_context ohmd_context;
+
+ohmdq* ohmdq_create(ohmd_context* ctx, unsigned elem_size, unsigned max);
+void ohmdq_destroy(ohmdq* me);
+
+bool ohmdq_push(ohmdq* me, const void* elem);
+bool ohmdq_pop(ohmdq* me, void* out_elem);
+unsigned ohmdq_get_size(ohmdq* me);
+unsigned ohmdq_get_max(ohmdq* me);
+
+#endif

+ 1 - 1
tests/unittests/Makefile.am

@@ -1,5 +1,5 @@
 bin_PROGRAMS = unittests
 AM_CPPFLAGS = -Wall -Werror -I$(top_srcdir)/include -I$(top_srcdir)/src -DOHMD_STATIC
-unittests_SOURCES = main.c quat.c vec.c highlevel.c
+unittests_SOURCES = main.c quat.c vec.c highlevel.c queue.c
 unittests_LDADD = $(top_builddir)/src/libopenhmd.la -lm
 unittests_LDFLAGS = -static-libtool-libs

+ 4 - 0
tests/unittests/main.c

@@ -38,6 +38,10 @@ int main()
 	Test(test_highlevel_open_close_device);
 	Test(test_highlevel_open_close_many_devices);
 	printf("\n");
+	
+	printf("queue tests\n");
+	Test(test_ohmdq_push_pop);
+	printf("\n");
 
 	printf("all a-ok\n");
 	return 0;

+ 61 - 0
tests/unittests/queue.c

@@ -0,0 +1,61 @@
+/*
+ * OpenHMD - Free and Open Source API and drivers for immersive technology.
+ * Copyright (C) 2016 Fredrik Hultin.
+ * Distributed under the Boost 1.0 licence, see LICENSE for full text.
+ */
+
+/* Unit Tests - Queue */
+
+#include "tests.h"
+#include "openhmdi.h"
+
+void test_ohmdq_push_pop()
+{
+	ohmd_context* ctx = ohmd_ctx_create();
+	ohmdq* q = ohmdq_create(ctx, sizeof(int), 10);
+	
+	TAssert(ohmdq_get_max(q) == 10);
+
+	for(int i = 0; i < 10; i++){
+		bool ret = ohmdq_push(q, &i);
+		TAssert(ret);
+	}
+
+	TAssert(ohmdq_get_size(q) == 10);
+	
+	int val = 0;
+	bool ret = ohmdq_push(q, &val);
+	TAssert(!ret);
+
+	for(int i = 0; i < 10; i++){
+		int val = 0;
+		bool ret = ohmdq_pop(q, &val);
+		TAssert(ret);
+		TAssert(val == i);
+	}
+	
+	TAssert(ohmdq_get_size(q) == 0);
+	
+	for(int i = 0; i < 10; i++){
+		bool ret = ohmdq_push(q, &i);
+		TAssert(ret);
+	}
+
+	TAssert(ohmdq_get_size(q) == 10);
+	
+	val = 0;
+	ret = ohmdq_push(q, &val);
+	TAssert(!ret);
+
+	for(int i = 0; i < 10; i++){
+		int val = 0;
+		bool ret = ohmdq_pop(q, &val);
+		TAssert(ret);
+		TAssert(val == i);
+	}
+	
+	TAssert(ohmdq_get_size(q) == 0);
+
+	ohmdq_destroy(q);
+	ohmd_ctx_destroy(ctx);
+}

+ 3 - 0
tests/unittests/tests.h

@@ -44,4 +44,7 @@ void test_oquatf_get_mat4x4();
 void test_highlevel_open_close_device();
 void test_highlevel_open_close_many_devices();
 
+// queue tests
+void test_ohmdq_push_pop();
+
 #endif