aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libsurvive/survive.h40
-rwxr-xr-xsrc/survive.c55
-rwxr-xr-xsrc/survive_vive.c233
3 files changed, 301 insertions, 27 deletions
diff --git a/include/libsurvive/survive.h b/include/libsurvive/survive.h
index c4b2abe..f3a17c8 100644
--- a/include/libsurvive/survive.h
+++ b/include/libsurvive/survive.h
@@ -4,6 +4,7 @@
#include <stdint.h>
#include "survive_types.h"
#include "poser.h"
+#include "os_generic.h"
#ifdef __cplusplus
extern "C" {
@@ -18,7 +19,7 @@ struct SurviveObject
char codename[4]; //3 letters, null-terminated. Currently HMD, WM0, WM1.
char drivername[4]; //3 letters for driver. Currently "HTC"
- int16_t buttonmask;
+ int32_t buttonmask;
int16_t axis1;
int16_t axis2;
@@ -90,6 +91,37 @@ struct BaseStationData
struct config_group;
+#define BUTTON_QUEUE_MAX_LEN 32
+
+#define BUTTON_EVENT_BUTTON_NONE 0
+#define BUTTON_EVENT_BUTTON_DOWN 1
+#define BUTTON_EVENT_BUTTON_UP 2
+#define BUTTON_EVENT_AXIS_CHANGED 3
+
+// note: buttonId and axisId are 1-indexed values.
+// a value of 0 for an id means that no data is present in that value
+// additionally, when x and y values are both present in axis data,
+// axis1 will be x, axis2 will be y.
+typedef struct
+{
+ uint8_t isPopulated; //probably can remove this given the semaphore in the parent struct. helps with debugging
+ uint8_t eventType;
+ uint8_t buttonId;
+ uint8_t axis1Id;
+ uint16_t axis1Val;
+ uint8_t axis2Id;
+ uint16_t axis2Val;
+ SurviveObject *so;
+} ButtonQueueEntry;
+
+typedef struct
+{
+ uint8_t nextReadIndex; //init to 0
+ uint8_t nextWriteIndex; // init to 0
+ og_sema_t buttonservicesem;
+ ButtonQueueEntry entry[BUTTON_QUEUE_MAX_LEN];
+} ButtonQueue;
+
struct SurviveContext
{
text_feedback_func faultfunction;
@@ -114,6 +146,12 @@ struct SurviveContext
DeviceDriverCb * drivercloses;
DeviceDriverMagicCb * drivermagics;
int driver_ct;
+
+ uint8_t isClosing; // flag to indicate if threads should terminate themselves
+
+ og_thread_t buttonservicethread;
+ ButtonQueue buttonQueue;
+
};
SurviveContext * survive_init( int headless );
diff --git a/src/survive.c b/src/survive.c
index 97c839b..99b6648 100755
--- a/src/survive.c
+++ b/src/survive.c
@@ -40,6 +40,45 @@ static void survivenote( struct SurviveContext * ctx, const char * fault )
fprintf( stderr, "Info: %s\n", fault );
}
+static void button_servicer(void * context)
+{
+ SurviveContext *ctx = (SurviveContext*)context;
+
+ while (1)
+ {
+ OGLockSema(ctx->buttonQueue.buttonservicesem);
+
+ if (ctx->isClosing)
+ {
+ // we're shutting down. Close.
+ return;
+ }
+
+ ButtonQueueEntry *entry = &(ctx->buttonQueue.entry[ctx->buttonQueue.nextReadIndex]);
+ if (entry->isPopulated == 0)
+ {
+ // should never happen. indicates failure of code pushing stuff onto
+ // the buttonQueue
+ // if it does happen, it will kill all future button input
+ printf("ERROR: Unpopulated ButtonQueueEntry!");
+ return;
+ }
+
+ printf("ButtonEntry: eventType:%x, buttonId:%d, axis1:%d, axis1Val:%8.8x, axis2:%d, axis2Val:%8.8x\n",
+ entry->eventType,
+ entry->buttonId,
+ entry->axis1Id,
+ entry->axis1Val,
+ entry->axis2Id,
+ entry->axis2Val);
+
+ ctx->buttonQueue.nextReadIndex++;
+ if (ctx->buttonQueue.nextReadIndex >= BUTTON_QUEUE_MAX_LEN)
+ {
+ ctx->buttonQueue.nextReadIndex = 0;
+ }
+ };
+}
SurviveContext * survive_init( int headless )
{
@@ -66,6 +105,8 @@ SurviveContext * survive_init( int headless )
int i = 0;
SurviveContext * ctx = calloc( 1, sizeof( SurviveContext ) );
+ ctx->isClosing = 0;
+
ctx->global_config_values = malloc( sizeof(config_group) );
ctx->lh_config = malloc( sizeof(config_group) * NUM_LIGHTHOUSES);
@@ -123,6 +164,14 @@ SurviveContext * survive_init( int headless )
// saving the config extra to make sure that the user has a config file they can change.
config_save(ctx, "config.json");
+ // initialize the button queue
+ memset(&(ctx->buttonQueue), 0, sizeof(ctx->buttonQueue));
+
+ ctx->buttonQueue.buttonservicesem = OGCreateSema();
+
+ // start the thread to process button data
+ ctx->buttonservicethread = OGCreateThread(button_servicer, ctx);
+
return ctx;
}
@@ -205,6 +254,12 @@ void survive_close( SurviveContext * ctx )
{
const char * DriverName;
int r = 0;
+
+ ctx->isClosing = 1;
+
+ // unlock/ post to button service semaphore so the thread can kill itself
+ OGUnlockSema(ctx->buttonQueue.buttonservicesem);
+
while( ( DriverName = GetDriverNameMatching( "DriverUnreg", r++ ) ) )
{
DeviceDriver dd = GetDriver( DriverName );
diff --git a/src/survive_vive.c b/src/survive_vive.c
index ef150f6..146ea01 100755
--- a/src/survive_vive.c
+++ b/src/survive_vive.c
@@ -865,6 +865,162 @@ void calibrate_gyro(SurviveObject* so, FLT* agm) {
}
}
+typedef struct
+{
+ // could use a bitfield here, but since this data is short-lived,
+ // the space savings probably isn't worth the processing overhead.
+ uint8_t pressedButtonsValid;
+ uint8_t triggerOfBatteryValid;
+ uint8_t batteryChargeValid;
+ uint8_t hardwareIdValid;
+ uint8_t touchpadHorizontalValid;
+ uint8_t touchpadVerticalValid;
+ uint8_t triggerHighResValid;
+
+ uint32_t pressedButtons;
+ uint16_t triggerOrBattery;
+ uint8_t batteryCharge;
+ uint32_t hardwareId;
+ uint16_t touchpadHorizontal;
+ uint16_t touchpadVertical;
+ uint16_t triggerHighRes;
+} buttonEvent;
+
+void incrementAndPostButtonQueue(SurviveContext *ctx)
+{
+ ButtonQueueEntry *entry = &(ctx->buttonQueue.entry[ctx->buttonQueue.nextWriteIndex]);
+
+ if (OGGetSema(ctx->buttonQueue.buttonservicesem) >= BUTTON_QUEUE_MAX_LEN)
+ {
+ // There's not enough space to write this entry. Clear it out and move along
+ memset(entry, 0, sizeof(ButtonQueueEntry));
+ return;
+ }
+ entry->isPopulated = 1;
+ ctx->buttonQueue.nextWriteIndex++;
+ // if we've exceeded the size of the buffer, loop around to the beginning.
+ if (ctx->buttonQueue.nextWriteIndex >= BUTTON_QUEUE_MAX_LEN)
+ {
+ ctx->buttonQueue.nextWriteIndex = 0;
+ }
+ OGUnlockSema(ctx->buttonQueue.buttonservicesem);
+
+ // clear out any old data in the entry so we always start with a clean slate.
+ entry = &(ctx->buttonQueue.entry[ctx->buttonQueue.nextWriteIndex]);
+ memset(entry, 0, sizeof(ButtonQueueEntry));
+}
+
+// important! This must be the only place that we're posting to the buttonEntryQueue
+// if that ever needs to be changed, you will have to add locking so that only one
+// thread is posting at a time.
+void registerButtonEvent(SurviveObject *so, buttonEvent *event)
+{
+ ButtonQueueEntry *entry = &(so->ctx->buttonQueue.entry[so->ctx->buttonQueue.nextWriteIndex]);
+
+ memset(entry, 0, sizeof(ButtonQueueEntry));
+
+ entry->so = so;
+ if (event->pressedButtonsValid)
+ {
+ //printf("trigger %8.8x\n", event->triggerHighRes);
+ for (int a=0; a < 16; a++)
+ {
+ if (((event->pressedButtons) & (1<<a)) != ((so->buttonmask) & (1<<a)))
+ {
+ // Hey, the button did something
+ if (event->pressedButtons & (1 << a))
+ {
+ // it went down
+ entry->eventType = BUTTON_EVENT_BUTTON_DOWN;
+ }
+ else
+ {
+ // it went up
+ entry->eventType = BUTTON_EVENT_BUTTON_UP;
+ }
+ entry->buttonId = a;
+ incrementAndPostButtonQueue(so->ctx);
+ entry = &(so->ctx->buttonQueue.entry[so->ctx->buttonQueue.nextWriteIndex]);
+ }
+ }
+ // if the trigger button is depressed & it wasn't before
+ if ((((event->pressedButtons) & (0xff000000)) == 0xff000000) &&
+ ((so->buttonmask) & (0xff000000)) != 0xff000000)
+ {
+ entry->eventType = BUTTON_EVENT_BUTTON_DOWN;
+ entry->buttonId = 24;
+ incrementAndPostButtonQueue(so->ctx);
+ entry = &(so->ctx->buttonQueue.entry[so->ctx->buttonQueue.nextWriteIndex]);
+ }
+ // if the trigger button isn't depressed but it was before
+ else if ((((event->pressedButtons) & (0xff000000)) != 0xff000000) &&
+ ((so->buttonmask) & (0xff000000)) == 0xff000000)
+ {
+ entry->eventType = BUTTON_EVENT_BUTTON_UP;
+ entry->buttonId = 24;
+ incrementAndPostButtonQueue(so->ctx);
+ entry = &(so->ctx->buttonQueue.entry[so->ctx->buttonQueue.nextWriteIndex]);
+ }
+ }
+ if (event->triggerHighResValid)
+ {
+ if (so->axis1 != event->triggerHighRes)
+ {
+ entry->eventType = BUTTON_EVENT_AXIS_CHANGED;
+ entry->axis1Id = 1;
+ entry->axis1Val = event->triggerHighRes;
+ incrementAndPostButtonQueue(so->ctx);
+ entry = &(so->ctx->buttonQueue.entry[so->ctx->buttonQueue.nextWriteIndex]);
+
+ }
+ }
+ if ((event->touchpadHorizontalValid) && (event->touchpadVerticalValid))
+ {
+ if ((so->axis2 != event->touchpadHorizontal) ||
+ (so->axis3 != event->touchpadVertical))
+ {
+ entry->eventType = BUTTON_EVENT_AXIS_CHANGED;
+ entry->axis1Id = 2;
+ entry->axis1Val = event->touchpadHorizontal;
+ entry->axis2Id = 3;
+ entry->axis2Val = event->touchpadVertical;
+ incrementAndPostButtonQueue(so->ctx);
+ entry = &(so->ctx->buttonQueue.entry[so->ctx->buttonQueue.nextWriteIndex]);
+
+ }
+ }
+
+ if (event->pressedButtonsValid)
+ {
+ so->buttonmask = event->pressedButtons;
+ }
+ if (event->batteryChargeValid)
+ {
+ so->charge = event->batteryCharge;
+ }
+ if (event->touchpadHorizontalValid)
+ {
+ so->axis2 = event->touchpadHorizontal;
+ }
+ if (event->touchpadVerticalValid)
+ {
+ so->axis3 = event->touchpadVertical;
+ }
+ if (event->triggerHighResValid)
+ {
+ so->axis1 = event->triggerHighRes;
+ }
+}
+
+uint8_t isPopulated; //probably can remove this given the semaphore in the parent struct. helps with debugging
+uint8_t eventType;
+uint8_t buttonId;
+uint8_t axis1Id;
+uint16_t axis1Val;
+uint8_t axis2Id;
+uint16_t axis2Val;
+SurviveObject *so;
+
static void handle_watchman( SurviveObject * w, uint8_t * readdata )
{
@@ -885,6 +1041,8 @@ static void handle_watchman( SurviveObject * w, uint8_t * readdata )
uint8_t qty = POP1;
uint8_t time2 = POP1;
uint8_t type = POP1;
+
+
qty-=2;
int propset = 0;
int doimu = 0;
@@ -899,6 +1057,8 @@ static void handle_watchman( SurviveObject * w, uint8_t * readdata )
{
qty-=1;
w->buttonmask = POP1;
+
+ printf("buttonmask is %d\n", w->buttonmask);
type &= ~0x01;
}
if( type & 0x04 )
@@ -1237,7 +1397,7 @@ void survive_data_cb( SurviveUSBInterface * si )
}
else if( id == 38 )
{
- w->ison = 0;
+ w->ison = 0; // turning off
}
else
{
@@ -1304,32 +1464,53 @@ void survive_data_cb( SurviveUSBInterface * si )
//0x3E uint8 1 someBitFieldMaybe 0x00 : ping / 0x64 : user input
//0x3F ? 1 ? unknown
- typedef struct
- {
- //uint8_t reportId;
- uint16_t reportType;
- uint32_t reportCount;
- uint32_t pressedButtons;
- uint16_t triggerOrBattery;
- uint16_t batteryCharge;
- uint32_t hardwareId;
- int16_t touchpadHorizontal;
- int16_t touchpadVertical;
- uint16_t unknown1;
- uint16_t triggerHighRes;
- uint8_t unknown2;
- uint8_t unknown3;
- uint8_t unknown4;
- uint16_t triggerRaw;
- uint8_t unknown5;
- uint8_t unknown6; // maybe some bitfield?
- uint8_t unknown7;
- } usb_buttons_raw;
-
- usb_buttons_raw *raw = (usb_buttons_raw*) readdata;
- if (raw->reportType == 0x100)
+ //typedef struct
+ //{
+ // //uint8_t reportId;
+ // uint16_t reportType;
+ // uint32_t reportCount;
+ // uint32_t pressedButtons;
+ // uint16_t triggerOrBattery;
+ // uint8_t batteryCharge;
+ // uint32_t hardwareId;
+ // int16_t touchpadHorizontal;
+ // int16_t touchpadVertical;
+ // uint16_t unknown1;
+ // uint16_t triggerHighRes;
+ // uint8_t unknown2;
+ // uint8_t unknown3;
+ // uint8_t unknown4;
+ // uint16_t triggerRaw;
+ // uint8_t unknown5;
+ // uint8_t unknown6; // maybe some bitfield?
+ // uint8_t unknown7;
+ //} usb_buttons_raw;
+
+ //usb_buttons_raw *raw = (usb_buttons_raw*) readdata;
+ if (*((uint16_t*)(&(readdata[0x0]))) == 0x100)
{
- printf("Buttons: %8.8x\n", raw->pressedButtons);
+ buttonEvent bEvent;
+ memset(&bEvent, 0, sizeof(bEvent));
+
+ bEvent.pressedButtonsValid = 1;
+ bEvent.pressedButtons = *((uint32_t*)(&(readdata[0x07])));
+ bEvent.triggerHighResValid = 1;
+ //bEvent.triggerHighRes = raw->triggerHighRes;
+ //bEvent.triggerHighRes = (raw->pressedButtons & 0xff000000) >> 24; // this seems to provide the same data at 2x the resolution as above
+ //bEvent.triggerHighRes = raw->triggerRaw;
+
+ bEvent.triggerHighRes = *((uint16_t*)(&(readdata[0x19])));
+ bEvent.touchpadHorizontalValid = 1;
+ //bEvent.touchpadHorizontal = raw->touchpadHorizontal;
+ bEvent.touchpadHorizontal = *((int16_t*)(&(readdata[0x13])));
+ bEvent.touchpadVerticalValid = 1;
+ //bEvent.touchpadVertical = raw->touchpadVertical;
+ bEvent.touchpadVertical = *((int16_t*)(&(readdata[0x15])));
+
+ //printf("%4.4x\n", bEvent.triggerHighRes);
+ registerButtonEvent(obj, &bEvent);
+
+ //printf("Buttons: %8.8x\n", raw->pressedButtons);
}
int a = 0;
}