Scale axis inputs; clear trackpad/joystick on release

This commit is contained in:
Justin Berger 2020-09-01 12:13:48 -06:00
parent c2e6c7b69a
commit 3c0eccb360
14 changed files with 94 additions and 68 deletions

View file

@ -143,6 +143,10 @@ if(DOTNET)
install(FILES ${CS_BINDINGS} DESTINATION "lib")
endif()
if(EXISTS /etc/bash_completion.d)
install(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/survive_autocomplete.sh DESTINATION "/etc/bash_completion.d")
endif()
install(DIRECTORY include/libsurvive DESTINATION include)
file(GLOB REDIST_HEADERS

View file

@ -65,7 +65,7 @@ int main(int argc, char **argv) {
button_event->button_id);
}
for (int i = 0; i < button_event->axis_count; i++) {
printf(" %20s (%2d) %8d ", SurviveAxisStr(subtype, button_event->axis_ids[i]),
printf(" %20s (%2d) %+5.4f ", SurviveAxisStr(subtype, button_event->axis_ids[i]),
button_event->axis_ids[i], button_event->axis_val[i]);
}
printf("\n");

View file

@ -48,7 +48,7 @@ namespace libsurvive
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public UInt32[] axis_ids;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public Int32[] axis_values;
public float[] axis_values;
}
class Cfunctions

View file

@ -98,7 +98,7 @@ struct SurviveObject {
SurviveObjectSubtype object_subtype;
int32_t buttonmask;
int32_t touchmask;
int16_t axis[16];
SurviveAxisVal_t axis[16];
int8_t charge;
int8_t charging : 1;
@ -241,7 +241,7 @@ typedef struct {
uint8_t buttonId;
enum SurviveAxis ids[16];
int32_t axisValues[16];
SurviveAxisVal_t axisValues[16];
SurviveObject *so;
} ButtonQueueEntry;
@ -426,7 +426,7 @@ SURVIVE_EXPORT void survive_default_sweep_angle_process(SurviveObject *so, survi
survive_timecode timecode, int8_t plane, FLT angle);
SURVIVE_EXPORT void survive_default_button_process(SurviveObject *so, enum SurviveInputEvent eventType,
enum SurviveButton buttonId, const enum SurviveAxis *axisIds,
const int32_t *axisVals);
const SurviveAxisVal_t *axisVals);
SURVIVE_EXPORT void survive_default_imupose_process(SurviveObject *so, uint32_t timecode, const SurvivePose *imu2world);
SURVIVE_EXPORT void survive_default_pose_process(SurviveObject *so, survive_timecode timecode, const SurvivePose *pose);
SURVIVE_EXPORT void survive_default_velocity_process(SurviveObject *so, survive_timecode timecode,

View file

@ -38,7 +38,7 @@ typedef struct SurviveSimpleButtonEvent {
uint8_t axis_count;
enum SurviveAxis axis_ids[SURVIVE_MAX_AXIS_COUNT];
int32_t axis_val[SURVIVE_MAX_AXIS_COUNT];
SurviveAxisVal_t axis_val[SURVIVE_MAX_AXIS_COUNT];
} SurviveSimpleButtonEvent;
/***

View file

@ -156,6 +156,7 @@ enum SurviveAxis {
SURVIVE_AXIS_IPD = 0,
SURVIVE_AXIS_FACE_PROXIMITY = 1
};
typedef float SurviveAxisVal_t;
typedef enum {
SURVIVE_OBJECT_TYPE_UNKNOWN = 0,
@ -282,7 +283,7 @@ typedef void (*imu_process_func)(SurviveObject *so, int mask, FLT *accelgyro, su
* A general button press event
*/
typedef void (*button_process_func)(SurviveObject *so, enum SurviveInputEvent eventType, enum SurviveButton buttonId,
const enum SurviveAxis *axisIds, const int32_t *axisVals);
const enum SurviveAxis *axisIds, const SurviveAxisVal_t *axisVals);
/**
* Called when a pose is solved for at a given time. Given in 'tracking' coordinate frame.

View file

@ -835,8 +835,8 @@ int survive_vive_usb_poll(SurviveContext *ctx, void *v) {
struct SurviveUSBInfo *usbInfo = &sv->udev[i];
FLT now = OGRelativeTime();
if (usbInfo->device_info->pid == 0x2101 && usbInfo->so->conf == 0 && sv->requestPairing &&
(sv->lastPairTime + 1) < now && now > 3) {
if ((usbInfo->device_info->pid == 0x2102 || usbInfo->device_info->pid == 0x2101) && usbInfo->so->conf == 0 &&
sv->requestPairing && (sv->lastPairTime + 1) < now && now > 3) {
survive_release_ctx_lock(ctx);
int r = update_feature_report(usbInfo->handle, 0, vive_request_pairing, sizeof(vive_request_pairing));
survive_get_ctx_lock(ctx);
@ -1063,16 +1063,16 @@ typedef struct {
uint8_t proximityValid;
uint8_t rawAxisCnt;
int32_t rawAxis[16];
uint8_t proximity[6];
SurviveAxisVal_t rawAxis[16];
SurviveAxisVal_t /*uint8_t*/ proximity[6];
uint32_t pressedButtons;
uint32_t touchedButtons;
uint16_t triggerOrBattery;
uint8_t batteryCharge;
uint32_t hardwareId;
uint16_t touchpadHorizontal;
uint16_t touchpadVertical;
uint16_t triggerHighRes;
SurviveAxisVal_t /*uint16_t*/ touchpadHorizontal;
SurviveAxisVal_t /*uint16_t*/ touchpadVertical;
SurviveAxisVal_t /*uint16_t*/ triggerHighRes;
} buttonEvent;
void incrementAndPostButtonQueue(SurviveContext *ctx) {
@ -1116,6 +1116,8 @@ static void get_eventTypes_for_idx(const SurviveObject *so, uint8_t idx, uint8_t
switch (source) {
case BUTTON_EVENT_SOURCE_RF: {
switch (so->object_subtype) {
case SURVIVE_OBJECT_SUBTYPE_KNUCKLES_R:
case SURVIVE_OBJECT_SUBTYPE_KNUCKLES_L:
case SURVIVE_OBJECT_SUBTYPE_WAND: {
switch (idx) {
case 1:
@ -1160,6 +1162,7 @@ static uint8_t get_button_id_for_idx(const SurviveObject *so, uint8_t idx, enum
}
default: {
switch (so->object_subtype) {
case SURVIVE_OBJECT_SUBTYPE_TRACKER:
case SURVIVE_OBJECT_SUBTYPE_WAND: {
switch (idx) {
case 20:
@ -1254,20 +1257,33 @@ static void registerButtonEvent(SurviveObject *so, buttonEvent *event, enum Butt
}
if ((event->touchpadHorizontalValid) && (event->touchpadVerticalValid)) {
if ((so->axis[1] != event->touchpadHorizontal) || (so->axis[2] != event->touchpadVertical)) {
entry->eventType = SURVIVE_INPUT_EVENT_AXIS_CHANGED;
entry->axisValues[0] = (int16_t)event->touchpadHorizontal;
entry->axisValues[1] = (int16_t)event->touchpadVertical;
entry->ids[0] = 2;
entry->ids[1] = 3;
enum SurviveAxis ax = SURVIVE_AXIS_TRACKPAD_X;
enum SurviveAxis ay = SURVIVE_AXIS_TRACKPAD_Y;
if (so->object_subtype == SURVIVE_OBJECT_SUBTYPE_KNUCKLES_R ||
so->object_subtype == SURVIVE_OBJECT_SUBTYPE_KNUCKLES_L) {
if ((so->buttonmask & (1 << SURVIVE_BUTTON_TRACKPAD)) == 0) {
entry->ids[0] = SURVIVE_AXIS_JOYSTICK_X;
entry->ids[1] = SURVIVE_AXIS_JOYSTICK_Y;
if (so->object_subtype == SURVIVE_OBJECT_SUBTYPE_KNUCKLES_R ||
so->object_subtype == SURVIVE_OBJECT_SUBTYPE_KNUCKLES_L) {
if ((so->buttonmask & (1 << SURVIVE_BUTTON_TRACKPAD)) == 0) {
if ((so->axis[ax] != 0) || (so->axis[ay] != 0)) {
entry->eventType = SURVIVE_INPUT_EVENT_AXIS_CHANGED;
entry->axisValues[0] = so->axis[entry->ids[0] = ax] = 0;
entry->axisValues[1] = so->axis[entry->ids[1] = ay] = 0;
incrementAndPostButtonQueue(so->ctx);
entry = prepareNextButtonEvent(so);
}
ax = SURVIVE_AXIS_JOYSTICK_X;
ay = SURVIVE_AXIS_JOYSTICK_Y;
}
}
if ((so->axis[ax] != event->touchpadHorizontal) || (so->axis[ay] != event->touchpadVertical)) {
entry->eventType = SURVIVE_INPUT_EVENT_AXIS_CHANGED;
entry->axisValues[0] = so->axis[entry->ids[0] = ax] = event->touchpadHorizontal;
entry->axisValues[1] = so->axis[entry->ids[1] = ay] = event->touchpadVertical;
incrementAndPostButtonQueue(so->ctx);
entry = prepareNextButtonEvent(so);
@ -1310,12 +1326,6 @@ static void registerButtonEvent(SurviveObject *so, buttonEvent *event, enum Butt
if (event->triggerHighResValid) {
so->axis[0] = event->triggerHighRes;
}
if (event->touchpadHorizontalValid) {
so->axis[1] = event->touchpadHorizontal;
}
if (event->touchpadVerticalValid) {
so->axis[2] = event->touchpadVertical;
}
if (event->proximityValid) {
for (int i = 0; i < 6; i++) {
so->axis[3 + i] = event->proximity[i];
@ -1759,15 +1769,15 @@ static bool read_event(SurviveObject *w, uint16_t time, uint8_t **readPtr, uint8
if (flagTrigger) {
bEvent.triggerHighResValid = 1;
bEvent.triggerHighRes = POP_BYTE(payloadPtr) * 128;
bEvent.triggerHighRes = POP_BYTE(payloadPtr) / 255.;
}
if (flagMotion) {
bEvent.touchpadHorizontalValid = 1;
bEvent.touchpadVerticalValid = 1;
bEvent.touchpadHorizontal = POP_SHORT(payloadPtr);
bEvent.touchpadVertical = POP_SHORT(payloadPtr);
bEvent.touchpadHorizontal = (int16_t)POP_SHORT(payloadPtr) / 32768.;
bEvent.touchpadVertical = (int16_t)POP_SHORT(payloadPtr) / 32768.;
}
} else {
@ -1794,14 +1804,14 @@ static bool read_event(SurviveObject *w, uint16_t time, uint8_t **readPtr, uint8
bEvent.proximityValid = 1;
// Non-touching proximity to fingers
bEvent.proximity[0] = POP_BYTE(payloadPtr); // Middle finger
bEvent.proximity[1] = POP_BYTE(payloadPtr); // Ring finger
bEvent.proximity[2] = POP_BYTE(payloadPtr); // Pinky finger
bEvent.proximity[3] = POP_BYTE(payloadPtr); // Index finger (trigger)
bEvent.proximity[0] = POP_BYTE(payloadPtr) / 255.; // Middle finger
bEvent.proximity[1] = POP_BYTE(payloadPtr) / 255.; // Ring finger
bEvent.proximity[2] = POP_BYTE(payloadPtr) / 255.; // Pinky finger
bEvent.proximity[3] = POP_BYTE(payloadPtr) / 255.; // Index finger (trigger)
// Contact force (Squeeze strength)
bEvent.proximity[4] = POP_BYTE(payloadPtr);
bEvent.proximity[5] = POP_BYTE(payloadPtr);
bEvent.proximity[4] = POP_BYTE(payloadPtr) / 255.;
bEvent.proximity[5] = POP_BYTE(payloadPtr) / 255.;
} else {
SV_WARN("Unknown gen two event %s 0x%02hX 0b%s [Time:%04hX] [Payload: %s] <<ABORT FURTHER READ>>",
w->codename, *(payloadPtr - 1), byteToBin(*(payloadPtr - 1)), time,
@ -2052,7 +2062,7 @@ static bool handle_input(SurviveObject *w, uint8_t flags, uint8_t **payloadPtr,
if (flagTrigger) {
bEvent.triggerHighResValid = 1;
VERIFY_LENGTH_OR_FAIL(*payloadPtr, 1);
bEvent.triggerHighRes = POP_BYTE(*payloadPtr) * 128;
bEvent.triggerHighRes = POP_BYTE(*payloadPtr) / 255.;
}
if (flagMotion) {
@ -2060,8 +2070,8 @@ static bool handle_input(SurviveObject *w, uint8_t flags, uint8_t **payloadPtr,
bEvent.touchpadVerticalValid = 1;
VERIFY_LENGTH_OR_FAIL(*payloadPtr, 4);
bEvent.touchpadHorizontal = POP_SHORT(*payloadPtr);
bEvent.touchpadVertical = POP_SHORT(*payloadPtr);
bEvent.touchpadHorizontal = (int16_t)POP_SHORT(*payloadPtr) / 32768.;
bEvent.touchpadVertical = (int16_t)POP_SHORT(*payloadPtr) / 32768.;
}
SV_VERBOSE(150, "handle_input flags %d %d %d", flagButton, flagTrigger, flagMotion);
} else {
@ -2088,15 +2098,15 @@ static bool handle_input(SurviveObject *w, uint8_t flags, uint8_t **payloadPtr,
bEvent.proximityValid = 1;
// Non-touching proximity to fingers
bEvent.proximity[0] = POP_BYTE(*payloadPtr); // Middle finger
bEvent.proximity[1] = POP_BYTE(*payloadPtr); // Ring finger
bEvent.proximity[2] = POP_BYTE(*payloadPtr); // Pinky finger
bEvent.proximity[3] = POP_BYTE(*payloadPtr); // Index finger (trigger)
bEvent.proximity[0] = POP_BYTE(*payloadPtr) / 255.; // Middle finger
bEvent.proximity[1] = POP_BYTE(*payloadPtr) / 255.; // Ring finger
bEvent.proximity[2] = POP_BYTE(*payloadPtr) / 255.; // Pinky finger
bEvent.proximity[3] = POP_BYTE(*payloadPtr) / 255.; // Index finger (trigger)
// Contact force (Squeeze strength)
bEvent.proximity[4] = POP_BYTE(*payloadPtr);
bEvent.proximity[4] = POP_BYTE(*payloadPtr) / 255.;
// Trackpad force
bEvent.proximity[5] = POP_BYTE(*payloadPtr);
bEvent.proximity[5] = POP_BYTE(*payloadPtr) / 255.;
} else {
SV_WARN("Unknown gen two event 0x%02hX 0b%s [Payload: %s] <<ABORT FURTHER READ>>", *(*payloadPtr - 1),
byteToBin(*(*payloadPtr - 1)), packetToHex(*payloadPtr, payloadEndPtr));
@ -2106,7 +2116,7 @@ static bool handle_input(SurviveObject *w, uint8_t flags, uint8_t **payloadPtr,
}
}
registerButtonEvent(w, &bEvent, BUTTON_EVENT_SOURCE_DEFAULT);
registerButtonEvent(w, &bEvent, BUTTON_EVENT_SOURCE_RF);
return true;
exit_failure:
@ -2945,8 +2955,9 @@ void survive_data_cb_locked(SurviveUSBInterface *si) {
buttonEvent evt = {0};
evt.rawAxisCnt = 2;
evt.rawAxis[0] = IPD;
evt.rawAxis[1] = proximity;
evt.rawAxis[0] = IPD / 65536.;
evt.rawAxis[1] = proximity / 32768.;
evt.pressedButtonsValid = 1;
evt.pressedButtons = onFace;
registerButtonEvent(obj, &evt, BUTTON_EVENT_SOURCE_DEFAULT);
@ -2961,13 +2972,12 @@ void survive_data_cb_locked(SurviveUSBInterface *si) {
bEvent.pressedButtons = read_buffer32(readdata, 0x7);
bEvent.triggerHighResValid = 1;
bEvent.triggerHighRes = read_buffer16(readdata, 0x19);
bEvent.triggerHighRes = read_buffer16(readdata, 0x19) / 32768.;
bEvent.touchpadHorizontalValid = 1;
bEvent.touchpadHorizontal = read_buffer16(readdata, 0x13);
bEvent.touchpadVerticalValid = 1;
bEvent.touchpadVertical = read_buffer16(readdata, 0x15);
bEvent.touchpadHorizontal = (int16_t)read_buffer16(readdata, 0x13) / 32768.;
bEvent.touchpadVertical = (int16_t)read_buffer16(readdata, 0x15) / 32768.;
registerButtonEvent(obj, &bEvent, BUTTON_EVENT_SOURCE_DEFAULT);
}

View file

@ -190,7 +190,7 @@ static void lh_fn(SurviveContext *ctx, uint8_t lighthouse, SurvivePose *lighthou
}
static void button_fn(SurviveObject *so, enum SurviveInputEvent eventType, enum SurviveButton buttonId,
const enum SurviveAxis *axisIds, const int32_t *axisVals) {
const enum SurviveAxis *axisIds, const SurviveAxisVal_t *axisVals) {
SurviveSimpleContext *actx = so->ctx->user_ptr;
OGLockMutex(actx->poll_mutex);
survive_default_button_process(so, eventType, buttonId, axisIds, axisVals);

View file

@ -297,14 +297,18 @@ static int process_jsontok(scratch_space_t *scratch, char *d, stack_entry_t *sta
memcpy(scratch->so->serial_number, d + t->start, size);
} else if (jsoneq(d, stack->key, "model_number") == 0) {
if(strncmp("Knuckles Right", d + t->start, t->end - t->start) == 0) {
if (strncmp("Knuckles Right", d + t->start, t->end - t->start) == 0 ||
strncmp("Knuckles EV3.0 Right", d + t->start, t->end - t->start) == 0) {
scratch->so->object_subtype = SURVIVE_OBJECT_SUBTYPE_KNUCKLES_R;
} else if (strncmp("Knuckles Left", d + t->start, t->end - t->start) == 0) {
} else if (strncmp("Knuckles Left", d + t->start, t->end - t->start) == 0 ||
strncmp("Knuckles EV3.0 Left", d + t->start, t->end - t->start) == 0) {
scratch->so->object_subtype = SURVIVE_OBJECT_SUBTYPE_KNUCKLES_L;
} else if (strncmp("Utah MP", d + t->start, t->end - t->start) == 0) {
scratch->so->object_subtype = SURVIVE_OBJECT_SUBTYPE_INDEX;
} else if (strncmp("Vive Controller MV", d + t->start, t->end - t->start) == 0) {
scratch->so->object_subtype = SURVIVE_OBJECT_SUBTYPE_WAND;
} else if (strncmp("VIVE Tracker Pro MV", d + t->start, t->end - t->start) == 0) {
scratch->so->object_subtype = SURVIVE_OBJECT_SUBTYPE_TRACKER;
}
} else if (jsoneq(d, stack->key, "model_name") == 0) {
if (strncmp("Vive Tracker MV", d + t->start, t->end - t->start) == 0) {

View file

@ -119,7 +119,7 @@ void survive_default_lightcap_process(SurviveObject *so, const LightcapElement *
}
void survive_default_button_process(SurviveObject *so, enum SurviveInputEvent eventType, enum SurviveButton buttonId,
const enum SurviveAxis *axisIds, const int32_t *axisValues) {}
const enum SurviveAxis *axisIds, const SurviveAxisVal_t *axisValues) {}
STATIC_CONFIG_ITEM(REPORT_IN_IMU, "report-in-imu", 'i', "Debug option to output poses in IMU space.", 0)
void survive_default_imupose_process(SurviveObject *so, uint32_t timecode, const SurvivePose *imu2world) {
@ -193,6 +193,9 @@ int survive_default_config_process(SurviveObject *so, char *ct0conf, int len) {
FILE *f = fopen(raw_fname, "w");
fwrite(ct0conf, len, 1, f);
fclose(f);
SurviveContext *ctx = so->ctx;
SV_INFO("Wrote out %d bytes to %s", len, raw_fname);
}
}

View file

@ -204,7 +204,7 @@ void survive_recording_sweep_process(SurviveObject *so, survive_channel channel,
}
void survive_recording_button_process(SurviveObject *so, enum SurviveInputEvent eventType, enum SurviveButton buttonId,
const enum SurviveAxis *axisId, const int32_t *axisVals) {
const enum SurviveAxis *axisId, const float *axisVals) {
SurviveRecordingData *recordingData = so->ctx->recptr;
if (!recordingData) {

View file

@ -41,7 +41,7 @@ void survive_recording_info_process(SurviveContext *ctx, const char *fault);
void survive_recording_sweep_process(SurviveObject *so, survive_channel channel, int sensor_id,
survive_timecode timecode, bool flag);
void survive_recording_button_process(SurviveObject *so, enum SurviveInputEvent eventType, enum SurviveButton buttonId,
const enum SurviveAxis *axisIds, const int32_t *axisVals);
const enum SurviveAxis *axisIds, const SurviveAxisVal_t *axisVals);
void survive_recording_angle_process(struct SurviveObject *so, int sensor_id, int acode, uint32_t timecode, FLT length,
FLT angle, uint32_t lh);
void survive_recording_sweep_angle_process(SurviveObject *so, survive_channel channel, int sensor_id,

View file

@ -29,7 +29,7 @@ struct ObjectButtonInfo {
struct button_state buttons[32];
struct axis_state {
bool changed;
int32_t v;
SurviveAxisVal_t v;
} axes[16];
};
@ -51,7 +51,7 @@ FLT last_redraw = 0;
bool needsRedraw = true;
static void button_process(SurviveObject *so, enum SurviveInputEvent eventType, enum SurviveButton buttonId,
const enum SurviveAxis *axisIds, const int32_t *axisVals) {
const enum SurviveAxis *axisIds, const SurviveAxisVal_t *axisVals) {
struct SurviveContext *ctx = so->ctx;
survive_default_button_process(so, eventType, buttonId, axisIds, axisVals);
@ -116,7 +116,7 @@ static void redraw(SurviveContext *ctx) {
if (!buttonInfos[i].axes[k].changed)
continue;
printf("\33[2KAxis %24s (%2d) %8d\r\n", SurviveAxisStr(so->object_subtype, k), k,
printf("\33[2KAxis %24s (%2d) %+5.4f\r\n", SurviveAxisStr(so->object_subtype, k), k,
buttonInfos[i].axes[k].v);
}

View file

@ -3,7 +3,8 @@
#place this script in /etc/bash_completion.d/ for general use.
_script()
{
_script_commands=$(./survive-cli -m $1 $2 $3)
local cmd="${1##*/}"
_script_commands=$($cmd -m $1 $2 $3)
local cur prev
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
@ -12,10 +13,13 @@ _script()
return 0
}
complete -o nospace -F _script ./calibrate
complete -o nospace -F _script ./simple_pose_test
complete -o nospace -F _script ./data_recorder
complete -o nospace -F _script ./survive-buttons
complete -o nospace -F _script ./survive-cli
complete -o nospace -F _script ./survive-websocketd
complete -o nospace -F _script simple_pose_test
complete -o nospace -F _script survive-buttons
complete -o nospace -F _script survive-cli
complete -o nospace -F _script survive-websocketd