aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Allen <axlecrusher@gmail.com>2017-03-15 19:26:46 -0400
committerJoshua Allen <axlecrusher@gmail.com>2017-03-15 19:26:46 -0400
commit1388d54117ff780b7fadd4fd682b6def569838fa (patch)
tree3737760c889eeaf0bd7305becc943d859ae65d96
parent62cef8aec06638bd006eaef46700f491750fc108 (diff)
parent9bd0a0d949639b516d28091f57862ac5e59e65da (diff)
downloadlibsurvive-1388d54117ff780b7fadd4fd682b6def569838fa.tar.gz
libsurvive-1388d54117ff780b7fadd4fd682b6def569838fa.tar.bz2
Merge branch 'master' of github.com:cnlohr/libsurvive
Conflicts: src/survive_data.c
-rw-r--r--.gitignore4
-rw-r--r--Makefile6
-rw-r--r--calibrate.c2
-rw-r--r--include/libsurvive/survive.h2
-rw-r--r--redist/glutil.c (renamed from glutil.c)0
-rw-r--r--redist/glutil.h (renamed from glutil.h)0
-rw-r--r--redist/linmath.c2
-rw-r--r--redist/linmath.h9
-rw-r--r--redist/mymath.c550
-rw-r--r--redist/os_generic.h2
-rw-r--r--redist/puff.c955
-rw-r--r--redist/puff.h31
-rw-r--r--redist/symbol_enumerator.c241
-rw-r--r--redist/symbol_enumerator.h12
-rw-r--r--src/ootx_decoder.c10
-rwxr-xr-xsrc/survive.c71
-rwxr-xr-xsrc/survive_cal.c8
-rw-r--r--src/survive_cal_lhfind.c298
-rw-r--r--src/survive_data.c2
-rw-r--r--src/survive_internal.h1
-rw-r--r--src/survive_process.c1
-rwxr-xr-xsrc/survive_vive.c298
-rw-r--r--useful_files/lib_survive_logo3.svg236
-rw-r--r--windows/build_tcc.bat14
-rw-r--r--windows/custom_msvcrt.def1400
-rw-r--r--windows/hid.c996
-rw-r--r--windows/hidapi.h405
-rw-r--r--windows/tcc_stubs.c59
28 files changed, 5248 insertions, 367 deletions
diff --git a/.gitignore b/.gitignore
index 3b956a5..cb8f780 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,7 @@
*.o
lib
test
+windows/calibrate.exe
+windows/calinfo/1.json.gz
+windows/calibrate.def
+windows/calinfo/3.json.gz
diff --git a/Makefile b/Makefile
index 29b2164..19f7c40 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ all : lib data_recorder test calibrate calibrate_client
CC:=gcc
-CFLAGS:=-Iinclude/libsurvive -I. -fPIC -g -O0 -Iredist -flto -DUSE_DOUBLE -std=gnu99
+CFLAGS:=-Iinclude/libsurvive -I. -fPIC -g -O0 -Iredist -flto -DUSE_DOUBLE -std=gnu99 -rdynamic
LDFLAGS:=-lpthread -lusb-1.0 -lz -lX11 -lm -flto -g
POSERS:=src/poser_dummy.o src/poser_daveortho.o src/poser_charlesslow.o
@@ -37,6 +37,10 @@ lib:
lib/libsurvive.so : $(LIBSURVIVE_O)
$(CC) -o $@ $^ $(LDFLAGS) -shared
+
+calibrate_tcc : $(LIBSURVIVE_C)
+ tcc -DRUNTIME_SYMNUM $(CFLAGS) -o $@ $^ $(LDFLAGS) calibrate.c redist/XDriver.c redist/os_generic.c redist/DrawFunctions.c redist/symbol_enumerator.c
+
clean :
rm -rf *.o src/*.o *~ src/*~ test data_recorder lib/libsurvive.so redist/*.o redist/*~
diff --git a/calibrate.c b/calibrate.c
index eb1a446..b6671b5 100644
--- a/calibrate.c
+++ b/calibrate.c
@@ -1,6 +1,5 @@
//Data recorder mod with GUI showing light positions.
-#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -52,7 +51,6 @@ void my_light_process( struct SurviveObject * so, int sensor_id, int acode, int
{
// if( timeinsweep < 0 ) return;
survive_default_light_process( so, sensor_id, acode, timeinsweep, timecode, length );
-
if( sensor_id < 0 ) return;
if( acode == -1 ) return;
//return;
diff --git a/include/libsurvive/survive.h b/include/libsurvive/survive.h
index fb69582..132480f 100644
--- a/include/libsurvive/survive.h
+++ b/include/libsurvive/survive.h
@@ -139,7 +139,7 @@ void survive_default_angle_process( SurviveObject * so, int sensor_id, int acode
void RegisterDriver( const char * name, void * data );
#define REGISTER_LINKTIME( func ) \
- void __attribute__((constructor)) LTRegister##func() { RegisterDriver( #func, &func ); }
+ void __attribute__((constructor)) REGISTER##func() { RegisterDriver( #func, &func ); }
diff --git a/glutil.c b/redist/glutil.c
index 6b0d0f3..6b0d0f3 100644
--- a/glutil.c
+++ b/redist/glutil.c
diff --git a/glutil.h b/redist/glutil.h
index bb40174..bb40174 100644
--- a/glutil.h
+++ b/redist/glutil.h
diff --git a/redist/linmath.c b/redist/linmath.c
index 41fa18f..dd6bd15 100644
--- a/redist/linmath.c
+++ b/redist/linmath.c
@@ -1,7 +1,7 @@
//Copyright 2013,2016 <>< C. N. Lohr. This file licensed under the terms of the MIT license.
-#include "linmath.h"
#include <math.h>
+#include "linmath.h"
#include <float.h>
#include <string.h>
diff --git a/redist/linmath.h b/redist/linmath.h
index 66a38ed..4e0cb77 100644
--- a/redist/linmath.h
+++ b/redist/linmath.h
@@ -25,7 +25,7 @@
#define FLT_ACOS acos
#define FLT_ASIN asin
#define FLT_ATAN2 atan2
-#define FLT_FABS fabs
+#define FLT_FABS__ fabs
#else
@@ -37,10 +37,15 @@
#define FLT_ACOS acosf
#define FLT_ASIN asinf
#define FLT_ATAN2 atan2f
-#define FLT_FABS fabsf
+#define FLT_FABS__ fabsf
#endif
+#ifdef TCC
+#define FLT_FABS(x) (((x)<0)?(-(x)):(x))
+#else
+#define FLT_FABS FLT_FABS__
+#endif
//NOTE: Inputs may never be output with cross product.
diff --git a/redist/mymath.c b/redist/mymath.c
new file mode 100644
index 0000000..17dcc96
--- /dev/null
+++ b/redist/mymath.c
@@ -0,0 +1,550 @@
+//Copyright 2013,2016 <>< C. N. Lohr. This file licensed under the terms of the MIT license.
+
+#include <math.h>
+#include <float.h>
+#include <string.h>
+#include "linmath.h"
+
+#define FLT float
+#define LINMATHPI ((FLT)3.141592653589)
+#define DEFAULT_EPSILON 0.001
+void quatnormalize( FLT * qout, const FLT * qin );
+void quatscale( FLT * qout, const FLT * qin, FLT s );
+void quatfrom2vectors(FLT *q, const FLT *src, const FLT *dest);
+
+
+void cross3d( FLT * out, const FLT * a, const FLT * b )
+{
+ out[0] = a[1]*b[2] - a[2]*b[1];
+ out[1] = a[2]*b[0] - a[0]*b[2];
+ out[2] = a[0]*b[1] - a[1]*b[0];
+}
+
+void sub3d( FLT * out, const FLT * a, const FLT * b )
+{
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+}
+
+void add3d( FLT * out, const FLT * a, const FLT * b )
+{
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+}
+
+void scale3d( FLT * out, const FLT * a, FLT scalar )
+{
+ out[0] = a[0] * scalar;
+ out[1] = a[1] * scalar;
+ out[2] = a[2] * scalar;
+}
+
+void normalize3d( FLT * out, const FLT * in )
+{
+ FLT r = ((FLT)1.) / FLT_SQRT(in[0] * in[0] + in[1] * in[1] + in[2] * in[2]);
+ out[0] = in[0] * r;
+ out[1] = in[1] * r;
+ out[2] = in[2] * r;
+}
+
+FLT dot3d( const FLT * a, const FLT * b )
+{
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+}
+
+int compare3d( const FLT * a, const FLT * b, FLT epsilon )
+{
+ if( !a || !b ) return 0;
+ if( a[2] - b[2] > epsilon ) return 1;
+ if( b[2] - a[2] > epsilon ) return -1;
+ if( a[1] - b[1] > epsilon ) return 1;
+ if( b[1] - a[1] > epsilon ) return -1;
+ if( a[0] - b[0] > epsilon ) return 1;
+ if( b[0] - a[0] > epsilon ) return -1;
+ return 0;
+}
+
+void copy3d( FLT * out, const FLT * in )
+{
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+}
+
+FLT magnitude3d(const FLT * a )
+{
+ return FLT_SQRT(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
+}
+
+FLT anglebetween3d( FLT * a, FLT * b )
+{
+ FLT an[3];
+ FLT bn[3];
+ normalize3d( an, a );
+ normalize3d( bn, b );
+ FLT dot = dot3d(an, bn);
+ if( dot < -0.9999999 ) return LINMATHPI;
+ if( dot > 0.9999999 ) return 0;
+ return FLT_ACOS(dot);
+}
+
+/////////////////////////////////////QUATERNIONS//////////////////////////////////////////
+//Originally from Mercury (Copyright (C) 2009 by Joshua Allen, Charles Lohr, Adam Lowman)
+//Under the mit/X11 license.
+
+
+
+
+void quatsetnone(FLT * q)
+{
+ q[0] = 1; q[1] = 0; q[2] = 0; q[3] = 0;
+}
+
+void quatcopy(FLT * qout, const FLT * qin)
+{
+ qout[0] = qin[0];
+ qout[1] = qin[1];
+ qout[2] = qin[2];
+ qout[3] = qin[3];
+}
+
+void quatfromeuler( FLT * q, const FLT * euler )
+{
+ FLT X = euler[0]/2.0f; //roll
+ FLT Y = euler[1]/2.0f; //pitch
+ FLT Z = euler[2]/2.0f; //yaw
+
+ FLT cx = FLT_COS(X);
+ FLT sx = FLT_SIN(X);
+ FLT cy = FLT_COS(Y);
+ FLT sy = FLT_SIN(Y);
+ FLT cz = FLT_COS(Z);
+ FLT sz = FLT_SIN(Z);
+
+ //Correct according to
+ //http://en.wikipedia.org/wiki/Conversion_between_MQuaternions_and_Euler_angles
+ q[0] = cx*cy*cz+sx*sy*sz;//q1
+ q[1] = sx*cy*cz-cx*sy*sz;//q2
+ q[2] = cx*sy*cz+sx*cy*sz;//q3
+ q[3] = cx*cy*sz-sx*sy*cz;//q4
+ quatnormalize( q, q );
+}
+
+void quattoeuler( FLT * euler, const FLT * q )
+{
+ //According to http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles (Oct 26, 2009)
+ euler[0] = FLT_ATAN2(2 * (q[0] * q[1] + q[2] * q[3]), 1 - 2 * (q[1] * q[1] + q[2] * q[2]));
+ euler[1] = FLT_ASIN(2 * (q[0] * q[2] - q[3] * q[1]));
+ euler[2] = FLT_ATAN2(2 * (q[0] * q[3] + q[1] * q[2]), 1 - 2 * (q[2] * q[2] + q[3] * q[3]));
+}
+
+void quatfromaxisangle( FLT * q, const FLT * axis, FLT radians )
+{
+ FLT v[3];
+ normalize3d( v, axis );
+
+ FLT sn = FLT_SIN(radians / 2.0f);
+ q[0] = FLT_COS(radians / 2.0f);
+ q[1] = sn * v[0];
+ q[2] = sn * v[1];
+ q[3] = sn * v[2];
+
+ quatnormalize( q, q );
+}
+
+FLT quatmagnitude( const FLT * q )
+{
+ return FLT_SQRT((q[0] * q[0]) + (q[1] * q[1]) + (q[2] * q[2]) + (q[3] * q[3]));
+}
+
+FLT quatinvsqmagnitude( const FLT * q )
+{
+ return ((FLT)1.)/FLT_SQRT((q[0]*q[0])+(q[1]*q[1])+(q[2]*q[2])+(q[3]*q[3]));
+}
+
+
+void quatnormalize( FLT * qout, const FLT * qin )
+{
+ FLT imag = quatinvsqmagnitude( qin );
+ quatscale( qout, qin, imag );
+}
+
+void quattomatrix(FLT * matrix44, const FLT * qin)
+{
+ FLT q[4];
+ quatnormalize(q, qin);
+
+ //Reduced calulation for speed
+ FLT xx = 2 * q[1] * q[1];
+ FLT xy = 2 * q[1] * q[2];
+ FLT xz = 2 * q[1] * q[3];
+ FLT xw = 2 * q[1] * q[0];
+
+ FLT yy = 2 * q[2] * q[2];
+ FLT yz = 2 * q[2] * q[3];
+ FLT yw = 2 * q[2] * q[0];
+
+ FLT zz = 2 * q[3] * q[3];
+ FLT zw = 2 * q[3] * q[0];
+
+ //opengl major
+ matrix44[0] = 1 - yy - zz;
+ matrix44[1] = xy - zw;
+ matrix44[2] = xz + yw;
+ matrix44[3] = 0;
+
+ matrix44[4] = xy + zw;
+ matrix44[5] = 1 - xx - zz;
+ matrix44[6] = yz - xw;
+ matrix44[7] = 0;
+
+ matrix44[8] = xz - yw;
+ matrix44[9] = yz + xw;
+ matrix44[10] = 1 - xx - yy;
+ matrix44[11] = 0;
+
+ matrix44[12] = 0;
+ matrix44[13] = 0;
+ matrix44[14] = 0;
+ matrix44[15] = 1;
+}
+
+
+void quatfrommatrix( FLT * q, const FLT * matrix44 )
+{
+ //Algorithm from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
+ float tr = matrix44[0] + matrix44[5] + matrix44[10];
+
+ if (tr > 0) {
+ float S = sqrt(tr+1.0) * 2; // S=4*qw
+ q[0] = 0.25 * S;
+ q[1] = (matrix44[9] - matrix44[6]) / S;
+ q[2] = (matrix44[2] - matrix44[8]) / S;
+ q[3] = (matrix44[4] - matrix44[1]) / S;
+ } else if ((matrix44[0] > matrix44[5])&(matrix44[0] > matrix44[10])) {
+ float S = sqrt(1.0 + matrix44[0] - matrix44[5] - matrix44[10]) * 2; // S=4*qx
+ q[0] = (matrix44[9] - matrix44[6]) / S;
+ q[1] = 0.25 * S;
+ q[2] = (matrix44[1] + matrix44[4]) / S;
+ q[3] = (matrix44[2] + matrix44[8]) / S;
+ } else if (matrix44[5] > matrix44[10]) {
+ float S = sqrt(1.0 + matrix44[5] - matrix44[0] - matrix44[10]) * 2; // S=4*qy
+ q[0] = (matrix44[2] - matrix44[8]) / S;
+ q[1] = (matrix44[1] + matrix44[4]) / S;
+ q[2] = 0.25 * S;
+ q[3] = (matrix44[6] + matrix44[9]) / S;
+ } else {
+ float S = sqrt(1.0 + matrix44[10] - matrix44[0] - matrix44[5]) * 2; // S=4*qz
+ q[0] = (matrix44[4] - matrix44[1]) / S;
+ q[1] = (matrix44[2] + matrix44[8]) / S;
+ q[2] = (matrix44[6] + matrix44[9]) / S;
+ q[3] = 0.25 * S;
+ }
+}
+
+
+void quattomatrix33(FLT * matrix33, const FLT * qin)
+{
+ FLT q[4];
+ quatnormalize(q, qin);
+
+ //Reduced calulation for speed
+ FLT xx = 2 * q[0] * q[0];
+ FLT xy = 2 * q[0] * q[1];
+ FLT xz = 2 * q[0] * q[2];
+ FLT xw = 2 * q[0] * q[3];
+
+ FLT yy = 2 * q[1] * q[1];
+ FLT yz = 2 * q[1] * q[2];
+ FLT yw = 2 * q[1] * q[3];
+
+ FLT zz = 2 * q[2] * q[2];
+ FLT zw = 2 * q[2] * q[3];
+
+ //opengl major
+ matrix33[0] = 1 - yy - zz;
+ matrix33[1] = xy - zw;
+ matrix33[2] = xz + yw;
+
+ matrix33[3] = xy + zw;
+ matrix33[4] = 1 - xx - zz;
+ matrix33[5] = yz - xw;
+
+ matrix33[6] = xz - yw;
+ matrix33[7] = yz + xw;
+ matrix33[8] = 1 - xx - yy;
+}
+
+void quatgetconjugate(FLT * qout, const FLT * qin)
+{
+ qout[0] = qin[0];
+ qout[1] = -qin[1];
+ qout[2] = -qin[2];
+ qout[3] = -qin[3];
+}
+
+void quatgetreciprocal( FLT * qout, const FLT * qin )
+{
+ FLT m = quatinvsqmagnitude(qin);
+ quatgetconjugate( qout, qin );
+ quatscale( qout, qout, m );
+}
+
+void quatsub( FLT * qout, const FLT * a, const FLT * b )
+{
+ qout[0] = a[0] - b[0];
+ qout[1] = a[1] - b[1];
+ qout[2] = a[2] - b[2];
+ qout[3] = a[3] - b[3];
+}
+
+void quatadd( FLT * qout, const FLT * a, const FLT * b )
+{
+ qout[0] = a[0] + b[0];
+ qout[1] = a[1] + b[1];
+ qout[2] = a[2] + b[2];
+ qout[3] = a[3] + b[3];
+}
+
+void quatrotateabout( FLT * qout, const FLT * q1, const FLT * q2 )
+{
+ //NOTE: Does not normalize
+ qout[0] = (q1[0]*q2[0])-(q1[1]*q2[1])-(q1[2]*q2[2])-(q1[3]*q2[3]);
+ qout[1] = (q1[0]*q2[1])+(q1[1]*q2[0])+(q1[2]*q2[3])-(q1[3]*q2[2]);
+ qout[2] = (q1[0]*q2[2])-(q1[1]*q2[3])+(q1[2]*q2[0])+(q1[3]*q2[1]);
+ qout[3] = (q1[0]*q2[3])+(q1[1]*q2[2])-(q1[2]*q2[1])+(q1[3]*q2[0]);
+}
+
+void quatscale( FLT * qout, const FLT * qin, FLT s )
+{
+ qout[0] = qin[0] * s;
+ qout[1] = qin[1] * s;
+ qout[2] = qin[2] * s;
+ qout[3] = qin[3] * s;
+}
+
+
+FLT quatinnerproduct( const FLT * qa, const FLT * qb )
+{
+ return (qa[0]*qb[0])+(qa[1]*qb[1])+(qa[2]*qb[2])+(qa[3]*qb[3]);
+}
+
+void quatouterproduct( FLT * outvec3, FLT * qa, FLT * qb )
+{
+ outvec3[0] = (qa[0]*qb[1])-(qa[1]*qb[0])-(qa[2]*qb[3])+(qa[3]*qb[2]);
+ outvec3[1] = (qa[0]*qb[2])+(qa[1]*qb[3])-(qa[2]*qb[0])-(qa[3]*qb[1]);
+ outvec3[2] = (qa[0]*qb[3])-(qa[1]*qb[2])+(qa[2]*qb[1])-(qa[3]*qb[0]);
+}
+
+void quatevenproduct( FLT * q, FLT * qa, FLT * qb )
+{
+ q[0] = (qa[0]*qb[0])-(qa[1]*qb[1])-(qa[2]*qb[2])-(qa[3]*qb[3]);
+ q[1] = (qa[0]*qb[1])+(qa[1]*qb[0]);
+ q[2] = (qa[0]*qb[2])+(qa[2]*qb[0]);
+ q[3] = (qa[0]*qb[3])+(qa[3]*qb[0]);
+}
+
+void quatoddproduct( FLT * outvec3, FLT * qa, FLT * qb )
+{
+ outvec3[0] = (qa[2]*qb[3])-(qa[3]*qb[2]);
+ outvec3[1] = (qa[3]*qb[1])-(qa[1]*qb[3]);
+ outvec3[2] = (qa[1]*qb[2])-(qa[2]*qb[1]);
+}
+
+void quatslerp( FLT * q, const FLT * qa, const FLT * qb, FLT t )
+{
+ FLT an[4];
+ FLT bn[4];
+ quatnormalize( an, qa );
+ quatnormalize( bn, qb );
+ FLT cosTheta = quatinnerproduct(an,bn);
+ FLT sinTheta;
+
+ //Careful: If cosTheta is exactly one, or even if it's infinitesimally over, it'll
+ // cause SQRT to produce not a number, and screw everything up.
+ if ( 1 - (cosTheta*cosTheta) <= 0 )
+ sinTheta = 0;
+ else
+ sinTheta = FLT_SQRT(1 - (cosTheta*cosTheta));
+
+ FLT Theta = FLT_ACOS(cosTheta); //Theta is half the angle between the 2 MQuaternions
+
+ if (FLT_FABS(Theta) < DEFAULT_EPSILON)
+ quatcopy( q, qa );
+ else if (FLT_FABS(sinTheta) < DEFAULT_EPSILON)
+ {
+ quatadd( q, qa, qb );
+ quatscale( q, q, 0.5 );
+ }
+ else
+ {
+ FLT aside[4];
+ FLT bside[4];
+ quatscale( bside, qb, FLT_SIN(t * Theta));
+ quatscale( aside, qa, FLT_SIN((1 - t)*Theta));
+ quatadd( q, aside, bside );
+ quatscale( q, q, ((FLT)1.)/sinTheta );
+ }
+}
+
+void quatrotatevector( FLT * vec3out, const FLT * quat, const FLT * vec3in )
+{
+ FLT tquat[4];
+ FLT vquat[4];
+ FLT qrecp[4];
+ vquat[0] = 0;
+ vquat[1] = vec3in[0];
+ vquat[2] = vec3in[1];
+ vquat[3] = vec3in[2];
+
+ quatrotateabout( tquat, quat, vquat );
+ quatgetconjugate( qrecp, quat );
+ quatrotateabout( vquat, tquat, qrecp );
+
+ vec3out[0] = vquat[1];
+ vec3out[1] = vquat[2];
+ vec3out[2] = vquat[3];
+}
+
+
+// Matrix Stuff
+
+Matrix3x3 inverseM33(const Matrix3x3 mat)
+{
+ Matrix3x3 newMat;
+ for (int a = 0; a < 3; a++)
+ {
+ for (int b = 0; b < 3; b++)
+ {
+ newMat.val[a][b] = mat.val[a][b];
+ }
+ }
+
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = i + 1; j < 3; j++)
+ {
+ FLT tmp = newMat.val[i][j];
+ newMat.val[i][j] = newMat.val[j][i];
+ newMat.val[j][i] = tmp;
+ }
+ }
+
+ return newMat;
+}
+
+void rotation_between_vecs_to_m3(Matrix3x3 *m, const FLT v1[3], const FLT v2[3])
+{
+ FLT q[4];
+
+ quatfrom2vectors(q, v1, v2);
+
+ quattomatrix33(&(m->val[0][0]), q);
+}
+
+void rotate_vec(FLT *out, const FLT *in, Matrix3x3 rot)
+{
+ out[0] = rot.val[0][0] * in[0] + rot.val[1][0] * in[1] + rot.val[2][0] * in[2];
+ out[1] = rot.val[0][1] * in[0] + rot.val[1][1] * in[1] + rot.val[2][1] * in[2];
+ out[2] = rot.val[0][2] * in[0] + rot.val[1][2] * in[1] + rot.val[2][2] * in[2];
+
+ return;
+}
+
+
+// This function based on code from Object-oriented Graphics Rendering Engine
+// Copyright(c) 2000 - 2012 Torus Knot Software Ltd
+// under MIT license
+// http://www.ogre3d.org/docs/api/1.9/_ogre_vector3_8h_source.html
+
+/** Gets the shortest arc quaternion to rotate this vector to the destination
+vector.
+@remarks
+If you call this with a dest vector that is close to the inverse
+of this vector, we will rotate 180 degrees around a generated axis if
+since in this case ANY axis of rotation is valid.
+*/
+void quatfrom2vectors(FLT *q, const FLT *src, const FLT *dest)
+{
+ // Based on Stan Melax's article in Game Programming Gems
+
+ // Copy, since cannot modify local
+ FLT v0[3];
+ FLT v1[3];
+ normalize3d(v0, src);
+ normalize3d(v1, dest);
+
+ FLT d = dot3d(v0, v1);// v0.dotProduct(v1);
+ // If dot == 1, vectors are the same
+ if (d >= 1.0f)
+ {
+ quatsetnone(q);
+ return;
+ }
+ if (d < (1e-6f - 1.0f))
+ {
+ // Generate an axis
+ FLT unitX[3] = { 1, 0, 0 };
+ FLT unitY[3] = { 0, 1, 0 };
+
+ FLT axis[3];
+ cross3d(axis, unitX, src); // pick an angle
+ if ((axis[0] < 1.0e-35f) &&
+ (axis[1] < 1.0e-35f) &&
+ (axis[2] < 1.0e-35f)) // pick another if colinear
+ {
+ cross3d(axis, unitY, src);
+ }
+ normalize3d(axis, axis);
+ quatfromaxisangle(q, axis, LINMATHPI);
+ }
+ else
+ {
+ FLT s = FLT_SQRT((1 + d) * 2);
+ FLT invs = 1 / s;
+
+ FLT c[3];
+ //cross3d(c, v0, v1);
+ cross3d(c, v1, v0);
+
+ q[0] = c[0] * invs;
+ q[1] = c[1] * invs;
+ q[2] = c[2] * invs;
+ q[3] = s * 0.5f;
+
+ quatnormalize(q, q);
+ }
+
+}
+
+void matrix44copy(FLT * mout, const FLT * minm )
+{
+ memcpy( mout, minm, sizeof( FLT ) * 16 );
+}
+
+void matrix44transpose(FLT * mout, const FLT * minm )
+{
+ mout[0] = minm[0];
+ mout[1] = minm[4];
+ mout[2] = minm[8];
+ mout[3] = minm[12];
+
+ mout[4] = minm[1];
+ mout[5] = minm[5];
+ mout[6] = minm[9];
+ mout[7] = minm[13];
+
+ mout[8] = minm[2];
+ mout[9] = minm[6];
+ mout[10] = minm[10];
+ mout[11] = minm[14];
+
+ mout[12] = minm[3];
+ mout[13] = minm[7];
+ mout[14] = minm[11];
+ mout[15] = minm[15];
+
+}
+
diff --git a/redist/os_generic.h b/redist/os_generic.h
index 7ce22f2..aac425b 100644
--- a/redist/os_generic.h
+++ b/redist/os_generic.h
@@ -1,7 +1,7 @@
#ifndef _OS_GENERIC_H
#define _OS_GENERIC_H
-#ifdef WIN32
+#if defined( WIN32 ) || defined (WINDOWS)
#define USE_WINDOWS
#endif
diff --git a/redist/puff.c b/redist/puff.c
new file mode 100644
index 0000000..fdbf6de
--- /dev/null
+++ b/redist/puff.c
@@ -0,0 +1,955 @@
+/*
+ * puff.c
+ * Copyright (C) 2002-2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in puff.h
+ * version 2.1, 4 Apr 2010
+ *
+ * puff.c is a simple inflate written to be an unambiguous way to specify the
+ * deflate format. It is not written for speed but rather simplicity. As a
+ * side benefit, this code might actually be useful when small code is more
+ * important than speed, such as bootstrap applications. For typical deflate
+ * data, zlib's inflate() is about four times as fast as puff(). zlib's
+ * inflate compiles to around 20K on my machine, whereas puff.c compiles to
+ * around 4K on my machine (a PowerPC using GNU cc). If the faster decode()
+ * function here is used, then puff() is only twice as slow as zlib's
+ * inflate().
+ *
+ * All dynamically allocated memory comes from the stack. The stack required
+ * is less than 2K bytes. This code is compatible with 16-bit int's and
+ * assumes that long's are at least 32 bits. puff.c uses the short data type,
+ * assumed to be 16 bits, for arrays in order to to conserve memory. The code
+ * works whether integers are stored big endian or little endian.
+ *
+ * In the comments below are "Format notes" that describe the inflate process
+ * and document some of the less obvious aspects of the format. This source
+ * code is meant to supplement RFC 1951, which formally describes the deflate
+ * format:
+ *
+ * http://www.zlib.org/rfc-deflate.html
+ */
+
+/*
+ * Change history:
+ *
+ * 1.0 10 Feb 2002 - First version
+ * 1.1 17 Feb 2002 - Clarifications of some comments and notes
+ * - Update puff() dest and source pointers on negative
+ * errors to facilitate debugging deflators
+ * - Remove longest from struct huffman -- not needed
+ * - Simplify offs[] index in construct()
+ * - Add input size and checking, using longjmp() to
+ * maintain easy readability
+ * - Use short data type for large arrays
+ * - Use pointers instead of long to specify source and
+ * destination sizes to avoid arbitrary 4 GB limits
+ * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!),
+ * but leave simple version for readabilty
+ * - Make sure invalid distances detected if pointers
+ * are 16 bits
+ * - Fix fixed codes table error
+ * - Provide a scanning mode for determining size of
+ * uncompressed data
+ * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Jean-loup]
+ * - Add a puff.h file for the interface
+ * - Add braces in puff() for else do [Jean-loup]
+ * - Use indexes instead of pointers for readability
+ * 1.4 31 Mar 2002 - Simplify construct() code set check
+ * - Fix some comments
+ * - Add FIXLCODES #define
+ * 1.5 6 Apr 2002 - Minor comment fixes
+ * 1.6 7 Aug 2002 - Minor format changes
+ * 1.7 3 Mar 2003 - Added test code for distribution
+ * - Added zlib-like license
+ * 1.8 9 Jan 2004 - Added some comments on no distance codes case
+ * 1.9 21 Feb 2008 - Fix bug on 16-bit integer architectures [Pohland]
+ * - Catch missing end-of-block symbol error
+ * 2.0 25 Jul 2008 - Add #define to permit distance too far back
+ * - Add option in TEST code for puff to write the data
+ * - Add option in TEST code to skip input bytes
+ * - Allow TEST code to read from piped stdin
+ * 2.1 4 Apr 2010 - Avoid variable initialization for happier compilers
+ * - Avoid unsigned comparisons for even happier compilers
+ */
+
+#include <setjmp.h> /* for setjmp(), longjmp(), and jmp_buf */
+#include "puff.h" /* prototype for puff() */
+
+#define local static /* for local function definitions */
+#define NIL ((unsigned char *)0) /* for no output option */
+
+/*
+ * Maximums for allocations and loops. It is not useful to change these --
+ * they are fixed by the deflate format.
+ */
+#define MAXBITS 15 /* maximum bits in a code */
+#define MAXLCODES 286 /* maximum number of literal/length codes */
+#define MAXDCODES 30 /* maximum number of distance codes */
+#define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */
+#define FIXLCODES 288 /* number of fixed literal/length codes */
+
+/* input and output state */
+struct state {
+ /* output state */
+ unsigned char *out; /* output buffer */
+ unsigned long outlen; /* available space at out */
+ unsigned long outcnt; /* bytes written to out so far */
+
+ /* input state */
+ const unsigned char *in; /* input buffer */
+ unsigned long inlen; /* available input at in */
+ unsigned long incnt; /* bytes read so far */
+ int bitbuf; /* bit buffer */
+ int bitcnt; /* number of bits in bit buffer */
+
+ /* input limit error return state for bits() and decode() */
+ jmp_buf env;
+};
+
+/*
+ * Return need bits from the input stream. This always leaves less than
+ * eight bits in the buffer. bits() works properly for need == 0.
+ *
+ * Format notes:
+ *
+ * - Bits are stored in bytes from the least significant bit to the most
+ * significant bit. Therefore bits are dropped from the bottom of the bit
+ * buffer, using shift right, and new bytes are appended to the top of the
+ * bit buffer, using shift left.
+ */
+local int bits(struct state *s, int need)
+{
+ long val; /* bit accumulator (can use up to 20 bits) */
+
+ /* load at least need bits into val */
+ val = s->bitbuf;
+ while (s->bitcnt < need) {
+ if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */
+ val |= (long)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */
+ s->bitcnt += 8;
+ }
+
+ /* drop need bits and update buffer, always zero to seven bits left */
+ s->bitbuf = (int)(val >> need);
+ s->bitcnt -= need;
+
+ /* return need bits, zeroing the bits above that */
+ return (int)(val & ((1L << need) - 1));
+}
+
+/*
+ * Process a stored block.
+ *
+ * Format notes:
+ *
+ * - After the two-bit stored block type (00), the stored block length and
+ * stored bytes are byte-aligned for fast copying. Therefore any leftover
+ * bits in the byte that has the last bit of the type, as many as seven, are
+ * discarded. The value of the discarded bits are not defined and should not
+ * be checked against any expectation.
+ *
+ * - The second inverted copy of the stored block length does not have to be
+ * checked, but it's probably a good idea to do so anyway.
+ *
+ * - A stored block can have zero length. This is sometimes used to byte-align
+ * subsets of the compressed data for random access or partial recovery.
+ */
+local int stored(struct state *s)
+{
+ unsigned len; /* length of stored block */
+
+ /* discard leftover bits from current byte (assumes s->bitcnt < 8) */
+ s->bitbuf = 0;
+ s->bitcnt = 0;
+
+ /* get length and check against its one's complement */
+ if (s->incnt + 4 > s->inlen) return 2; /* not enough input */
+ len = s->in[s->incnt++];
+ len |= s->in[s->incnt++] << 8;
+ if (s->in[s->incnt++] != (~len & 0xff) ||
+ s->in[s->incnt++] != ((~len >> 8) & 0xff))
+ return -2; /* didn't match complement! */
+
+ /* copy len bytes from in to out */
+ if (s->incnt + len > s->inlen) return 2; /* not enough input */
+ if (s->out != NIL) {
+ if (s->outcnt + len > s->outlen)
+ return 1; /* not enough output space */
+ while (len--)
+ s->out[s->outcnt++] = s->in[s->incnt++];
+ }
+ else { /* just scanning */
+ s->outcnt += len;
+ s->incnt += len;
+ }
+
+ /* done with a valid stored block */
+ return 0;
+}
+
+/*
+ * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of
+ * each length, which for a canonical code are stepped through in order.
+ * symbol[] are the symbol values in canonical order, where the number of
+ * entries is the sum of the counts in count[]. The decoding process can be
+ * seen in the function decode() below.
+ */
+struct huffman {
+ short *count; /* number of symbols of each length */
+ short *symbol; /* canonically ordered symbols */
+};
+
+/*
+ * Decode a code from the stream s using huffman table h. Return the symbol or
+ * a negative value if there is an error. If all of the lengths are zero, i.e.
+ * an empty code, or if the code is incomplete and an invalid code is received,
+ * then -10 is returned after reading MAXBITS bits.
+ *
+ * Format notes:
+ *
+ * - The codes as stored in the compressed data are bit-reversed relative to
+ * a simple integer ordering of codes of the same lengths. Hence below the
+ * bits are pulled from the compressed data one at a time and used to
+ * build the code value reversed from what is in the stream in order to
+ * permit simple integer comparisons for decoding. A table-based decoding
+ * scheme (as used in zlib) does not need to do this reversal.
+ *
+ * - The first code for the shortest length is all zeros. Subsequent codes of
+ * the same length are simply integer increments of the previous code. When
+ * moving up a length, a zero bit is appended to the code. For a complete
+ * code, the last code of the longest length will be all ones.
+ *
+ * - Incomplete codes are handled by this decoder, since they are permitted
+ * in the deflate format. See the format notes for fixed() and dynamic().
+ */
+#ifdef SLOW
+local int decode(struct state *s, struct huffman *h)
+{
+ int len; /* current number of bits in code */
+ int code; /* len bits being decoded */
+ int first; /* first code of length len */
+ int count; /* number of codes of length len */
+ int index; /* index of first code of length len in symbol table */
+
+ code = first = index = 0;
+ for (len = 1; len <= MAXBITS; len++) {
+ code |= bits(s, 1); /* get next bit */
+ count = h->count[len];
+ if (code - count < first) /* if length len, return symbol */
+ return h->symbol[index + (code - first)];
+ index += count; /* else update for next length */
+ first += count;
+ first <<= 1;
+ code <<= 1;
+ }
+ return -10; /* ran out of codes */
+}
+
+/*
+ * A faster version of decode() for real applications of this code. It's not
+ * as readable, but it makes puff() twice as fast. And it only makes the code
+ * a few percent larger.
+ */
+#else /* !SLOW */
+local int decode(struct state *s, struct huffman *h)
+{
+ int len; /* current number of bits in code */
+ int code; /* len bits being decoded */
+ int first; /* first code of length len */
+ int count; /* number of codes of length len */
+ int index; /* index of first code of length len in symbol table */
+ int bitbuf; /* bits from stream */
+ int left; /* bits left in next or left to process */
+ short *next; /* next number of codes */
+
+ bitbuf = s->bitbuf;
+ left = s->bitcnt;
+ code = first = index = 0;
+ len = 1;
+ next = h->count + 1;
+ while (1) {
+ while (left--) {
+ code |= bitbuf & 1;
+ bitbuf >>= 1;
+ count = *next++;
+ if (code - count < first) { /* if length len, return symbol */
+ s->bitbuf = bitbuf;
+ s->bitcnt = (s->bitcnt - len) & 7;
+ return h->symbol[index + (code - first)];
+ }
+ index += count; /* else update for next length */
+ first += count;
+ first <<= 1;
+ code <<= 1;
+ len++;
+ }
+ left = (MAXBITS+1) - len;
+ if (left == 0) break;
+ if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */
+ bitbuf = s->in[s->incnt++];
+ if (left > 8) left = 8;
+ }
+ return -10; /* ran out of codes */
+}
+#endif /* SLOW */
+
+/*
+ * Given the list of code lengths length[0..n-1] representing a canonical
+ * Huffman code for n symbols, construct the tables required to decode those
+ * codes. Those tables are the number of codes of each length, and the symbols
+ * sorted by length, retaining their original order within each length. The
+ * return value is zero for a complete code set, negative for an over-
+ * subscribed code set, and positive for an incomplete code set. The tables
+ * can be used if the return value is zero or positive, but they cannot be used
+ * if the return value is negative. If the return value is zero, it is not
+ * possible for decode() using that table to return an error--any stream of
+ * enough bits will resolve to a symbol. If the return value is positive, then
+ * it is possible for decode() using that table to return an error for received
+ * codes past the end of the incomplete lengths.
+ *
+ * Not used by decode(), but used for error checking, h->count[0] is the number
+ * of the n symbols not in the code. So n - h->count[0] is the number of
+ * codes. This is useful for checking for incomplete codes that have more than
+ * one symbol, which is an error in a dynamic block.
+ *
+ * Assumption: for all i in 0..n-1, 0 <= length[i] <= MAXBITS
+ * This is assured by the construction of the length arrays in dynamic() and
+ * fixed() and is not verified by construct().
+ *
+ * Format notes:
+ *
+ * - Permitted and expected examples of incomplete codes are one of the fixed
+ * codes and any code with a single symbol which in deflate is coded as one
+ * bit instead of zero bits. See the format notes for fixed() and dynamic().
+ *
+ * - Within a given code length, the symbols are kept in ascending order for
+ * the code bits definition.
+ */
+local int construct(struct huffman *h, short *length, int n)
+{
+ int symbol; /* current symbol when stepping through length[] */
+ int len; /* current length when stepping through h->count[] */
+ int left; /* number of possible codes left of current length */
+ short offs[MAXBITS+1]; /* offsets in symbol table for each length */
+
+ /* count number of codes of each length */
+ for (len = 0; len <= MAXBITS; len++)
+ h->count[len] = 0;
+ for (symbol = 0; symbol < n; symbol++)
+ (h->count[length[symbol]])++; /* assumes lengths are within bounds */
+ if (h->count[0] == n) /* no codes! */
+ return 0; /* complete, but decode() will fail */
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1; /* one possible code of zero length */
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1; /* one more bit, double codes left */
+ left -= h->count[len]; /* deduct count from possible codes */
+ if (left < 0) return left; /* over-subscribed--return negative */
+ } /* left > 0 means incomplete */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + h->count[len];
+
+ /*
+ * put symbols in table sorted by length, by symbol order within each
+ * length
+ */
+ for (symbol = 0; symbol < n; symbol++)
+ if (length[symbol] != 0)
+ h->symbol[offs[length[symbol]]++] = symbol;
+
+ /* return zero for complete set, positive for incomplete set */
+ return left;
+}
+
+/*
+ * Decode literal/length and distance codes until an end-of-block code.
+ *
+ * Format notes:
+ *
+ * - Compressed data that is after the block type if fixed or after the code
+ * description if dynamic is a combination of literals and length/distance
+ * pairs terminated by and end-of-block code. Literals are simply Huffman
+ * coded bytes. A length/distance pair is a coded length followed by a
+ * coded distance to represent a string that occurs earlier in the
+ * uncompressed data that occurs again at the current location.
+ *
+ * - Literals, lengths, and the end-of-block code are combined into a single
+ * code of up to 286 symbols. They are 256 literals (0..255), 29 length
+ * symbols (257..285), and the end-of-block symbol (256).
+ *
+ * - There are 256 possible lengths (3..258), and so 29 symbols are not enough
+ * to represent all of those. Lengths 3..10 and 258 are in fact represented
+ * by just a length symbol. Lengths 11..257 are represented as a symbol and
+ * some number of extra bits that are added as an integer to the base length
+ * of the length symbol. The number of extra bits is determined by the base
+ * length symbol. These are in the static arrays below, lens[] for the base
+ * lengths and lext[] for the corresponding number of extra bits.
+ *
+ * - The reason that 258 gets its own symbol is that the longest length is used
+ * often in highly redundant files. Note that 258 can also be coded as the
+ * base value 227 plus the maximum extra value of 31. While a good deflate
+ * should never do this, it is not an error, and should be decoded properly.
+ *
+ * - If a length is decoded, including its extra bits if any, then it is
+ * followed a distance code. There are up to 30 distance symbols. Again
+ * there are many more possible distances (1..32768), so extra bits are added
+ * to a base value represented by the symbol. The distances 1..4 get their
+ * own symbol, but the rest require extra bits. The base distances and
+ * corresponding number of extra bits are below in the static arrays dist[]
+ * and dext[].
+ *
+ * - Literal bytes are simply written to the output. A length/distance pair is
+ * an instruction to copy previously uncompressed bytes to the output. The
+ * copy is from distance bytes back in the output stream, copying for length
+ * bytes.
+ *
+ * - Distances pointing before the beginning of the output data are not
+ * permitted.
+ *
+ * - Overlapped copies, where the length is greater than the distance, are
+ * allowed and common. For example, a distance of one and a length of 258
+ * simply copies the last byte 258 times. A distance of four and a length of
+ * twelve copies the last four bytes three times. A simple forward copy
+ * ignoring whether the length is greater than the distance or not implements
+ * this correctly. You should not use memcpy() since its behavior is not
+ * defined for overlapped arrays. You should not use memmove() or bcopy()
+ * since though their behavior -is- defined for overlapping arrays, it is
+ * defined to do the wrong thing in this case.
+ */
+local int codes(struct state *s,
+ struct huffman *lencode,
+ struct huffman *distcode)
+{
+ int symbol; /* decoded symbol */
+ int len; /* length for copy */
+ unsigned dist; /* distance for copy */
+ static const short lens[29] = { /* Size base for length codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
+ static const short lext[29] = { /* Extra bits for length codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
+ static const short dists[30] = { /* Offset base for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+ static const short dext[30] = { /* Extra bits for distance codes 0..29 */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+ /* decode literals and length/distance pairs */
+ do {
+ symbol = decode(s, lencode);
+ if (symbol < 0) return symbol; /* invalid symbol */
+ if (symbol < 256) { /* literal: symbol is the byte */
+ /* write out the literal */
+ if (s->out != NIL) {
+ if (s->outcnt == s->outlen) return 1;
+ s->out[s->outcnt] = symbol;
+ }
+ s->outcnt++;
+ }
+ else if (symbol > 256) { /* length */
+ /* get and compute length */
+ symbol -= 257;
+ if (symbol >= 29) return -10; /* invalid fixed code */
+ len = lens[symbol] + bits(s, lext[symbol]);
+
+ /* get and check distance */
+ symbol = decode(s, distcode);
+ if (symbol < 0) return symbol; /* invalid symbol */
+ dist = dists[symbol] + bits(s, dext[symbol]);
+#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ if (dist > s->outcnt)
+ return -11; /* distance too far back */
+#endif
+
+ /* copy length bytes from distance bytes back */
+ if (s->out != NIL) {
+ if (s->outcnt + len > s->outlen) return 1;
+ while (len--) {
+ s->out[s->outcnt] =
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ dist > s->outcnt ? 0 :
+#endif
+ s->out[s->outcnt - dist];
+ s->outcnt++;
+ }
+ }
+ else
+ s->outcnt += len;
+ }
+ } while (symbol != 256); /* end of block symbol */
+
+ /* done with a valid fixed or dynamic block */
+ return 0;
+}
+
+/*
+ * Process a fixed codes block.
+ *
+ * Format notes:
+ *
+ * - This block type can be useful for compressing small amounts of data for
+ * which the size of the code descriptions in a dynamic block exceeds the
+ * benefit of custom codes for that block. For fixed codes, no bits are
+ * spent on code descriptions. Instead the code lengths for literal/length
+ * codes and distance codes are fixed. The specific lengths for each symbol
+ * can be seen in the "for" loops below.
+ *
+ * - The literal/length code is complete, but has two symbols that are invalid
+ * and should result in an error if received. This cannot be implemented
+ * simply as an incomplete code since those two symbols are in the "middle"
+ * of the code. They are eight bits long and the longest literal/length\
+ * code is nine bits. Therefore the code must be constructed with those
+ * symbols, and the invalid symbols must be detected after decoding.
+ *
+ * - The fixed distance codes also have two invalid symbols that should result
+ * in an error if received. Since all of the distance codes are the same
+ * length, this can be implemented as an incomplete code. Then the invalid
+ * codes are detected while decoding.
+ */
+local int fixed(struct state *s)
+{
+ static int virgin = 1;
+ static short lencnt[MAXBITS+1], lensym[FIXLCODES];
+ static short distcnt[MAXBITS+1], distsym[MAXDCODES];
+ static struct huffman lencode, distcode;
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ int symbol;
+ short lengths[FIXLCODES];
+
+ /* literal/length table */
+ for (symbol = 0; symbol < 144; symbol++)
+ lengths[symbol] = 8;
+ for (; symbol < 256; symbol++)
+ lengths[symbol] = 9;
+ for (; symbol < 280; symbol++)
+ lengths[symbol] = 7;
+ for (; symbol < FIXLCODES; symbol++)
+ lengths[symbol] = 8;
+ construct(&lencode, lengths, FIXLCODES);
+
+ /* distance table */
+ for (symbol = 0; symbol < MAXDCODES; symbol++)
+ lengths[symbol] = 5;
+ construct(&distcode, lengths, MAXDCODES);
+
+ /* construct lencode and distcode */
+ lencode.count = lencnt;
+ lencode.symbol = lensym;
+ distcode.count = distcnt;
+ distcode.symbol = distsym;
+
+ /* do this just once */
+ virgin = 0;
+ }
+
+ /* decode data until end-of-block code */
+ return codes(s, &lencode, &distcode);
+}
+
+/*
+ * Process a dynamic codes block.
+ *
+ * Format notes:
+ *
+ * - A dynamic block starts with a description of the literal/length and
+ * distance codes for that block. New dynamic blocks allow the compressor to
+ * rapidly adapt to changing data with new codes optimized for that data.
+ *
+ * - The codes used by the deflate format are "canonical", which means that
+ * the actual bits of the codes are generated in an unambiguous way simply
+ * from the number of bits in each code. Therefore the code descriptions
+ * are simply a list of code lengths for each symbol.
+ *
+ * - The code lengths are stored in order for the symbols, so lengths are
+ * provided for each of the literal/length symbols, and for each of the
+ * distance symbols.
+ *
+ * - If a symbol is not used in the block, this is represented by a zero as
+ * as the code length. This does not mean a zero-length code, but rather
+ * that no code should be created for this symbol. There is no way in the
+ * deflate format to represent a zero-length code.
+ *
+ * - The maximum number of bits in a code is 15, so the possible lengths for
+ * any code are 1..15.
+ *
+ * - The fact that a length of zero is not permitted for a code has an
+ * interesting consequence. Normally if only one symbol is used for a given
+ * code, then in fact that code could be represented with zero bits. However
+ * in deflate, that code has to be at least one bit. So for example, if
+ * only a single distance base symbol appears in a block, then it will be
+ * represented by a single code of length one, in particular one 0 bit. This
+ * is an incomplete code, since if a 1 bit is received, it has no meaning,
+ * and should result in an error. So incomplete distance codes of one symbol
+ * should be permitted, and the receipt of invalid codes should be handled.
+ *
+ * - It is also possible to have a single literal/length code, but that code
+ * must be the end-of-block code, since every dynamic block has one. This
+ * is not the most efficient way to create an empty block (an empty fixed
+ * block is fewer bits), but it is allowed by the format. So incomplete
+ * literal/length codes of one symbol should also be permitted.
+ *
+ * - If there are only literal codes and no lengths, then there are no distance
+ * codes. This is represented by one distance code with zero bits.
+ *
+ * - The list of up to 286 length/literal lengths and up to 30 distance lengths
+ * are themselves compressed using Huffman codes and run-length encoding. In
+ * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means
+ * that length, and the symbols 16, 17, and 18 are run-length instructions.
+ * Each of 16, 17, and 18 are follwed by extra bits to define the length of
+ * the run. 16 copies the last length 3 to 6 times. 17 represents 3 to 10
+ * zero lengths, and 18 represents 11 to 138 zero lengths. Unused symbols
+ * are common, hence the special coding for zero lengths.
+ *
+ * - The symbols for 0..18 are Huffman coded, and so that code must be
+ * described first. This is simply a sequence of up to 19 three-bit values
+ * representing no code (0) or the code length for that symbol (1..7).
+ *
+ * - A dynamic block starts with three fixed-size counts from which is computed
+ * the number of literal/length code lengths, the number of distance code
+ * lengths, and the number of code length code lengths (ok, you come up with
+ * a better name!) in the code descriptions. For the literal/length and
+ * distance codes, lengths after those provided are considered zero, i.e. no
+ * code. The code length code lengths are received in a permuted order (see
+ * the order[] array below) to make a short code length code length list more
+ * likely. As it turns out, very short and very long codes are less likely
+ * to be seen in a dynamic code description, hence what may appear initially
+ * to be a peculiar ordering.
+ *
+ * - Given the number of literal/length code lengths (nlen) and distance code
+ * lengths (ndist), then they are treated as one long list of nlen + ndist
+ * code lengths. Therefore run-length coding can and often does cross the
+ * boundary between the two sets of lengths.
+ *
+ * - So to summarize, the code description at the start of a dynamic block is
+ * three counts for the number of code lengths for the literal/length codes,
+ * the distance codes, and the code length codes. This is followed by the
+ * code length code lengths, three bits each. This is used to construct the
+ * code length code which is used to read the remainder of the lengths. Then
+ * the literal/length code lengths and distance lengths are read as a single
+ * set of lengths using the code length codes. Codes are constructed from
+ * the resulting two sets of lengths, and then finally you can start
+ * decoding actual compressed data in the block.
+ *
+ * - For reference, a "typical" size for the code description in a dynamic
+ * block is around 80 bytes.
+ */
+local int dynamic(struct state *s)
+{
+ int nlen, ndist, ncode; /* number of lengths in descriptor */
+ int index; /* index of lengths[] */
+ int err; /* construct() return value */
+ short lengths[MAXCODES]; /* descriptor code lengths */
+ short lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */
+ short distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */
+ struct huffman lencode, distcode; /* length and distance codes */
+ static const short order[19] = /* permutation of code length codes */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ /* construct lencode and distcode */
+ lencode.count = lencnt;
+ lencode.symbol = lensym;
+ distcode.count = distcnt;
+ distcode.symbol = distsym;
+
+ /* get number of lengths in each table, check lengths */
+ nlen = bits(s, 5) + 257;
+ ndist = bits(s, 5) + 1;
+ ncode = bits(s, 4) + 4;
+ if (nlen > MAXLCODES || ndist > MAXDCODES)
+ return -3; /* bad counts */
+
+ /* read code length code lengths (really), missing lengths are zero */
+ for (index = 0; index < ncode; index++)
+ lengths[order[index]] = bits(s, 3);
+ for (; index < 19; index++)
+ lengths[order[index]] = 0;
+
+ /* build huffman table for code lengths codes (use lencode temporarily) */
+ err = construct(&lencode, lengths, 19);
+ if (err != 0) return -4; /* require complete code set here */
+
+ /* read length/literal and distance code length tables */
+ index = 0;
+ while (index < nlen + ndist) {
+ int symbol; /* decoded value */
+ int len; /* last length to repeat */
+
+ symbol = decode(s, &lencode);
+ if (symbol < 16) /* length in 0..15 */
+ lengths[index++] = symbol;
+ else { /* repeat instruction */
+ len = 0; /* assume repeating zeros */
+ if (symbol == 16) { /* repeat last length 3..6 times */
+ if (index == 0) return -5; /* no last length! */
+ len = lengths[index - 1]; /* last length */
+ symbol = 3 + bits(s, 2);
+ }
+ else if (symbol == 17) /* repeat zero 3..10 times */
+ symbol = 3 + bits(s, 3);
+ else /* == 18, repeat zero 11..138 times */
+ symbol = 11 + bits(s, 7);
+ if (index + symbol > nlen + ndist)
+ return -6; /* too many lengths! */
+ while (symbol--) /* repeat last or zero symbol times */
+ lengths[index++] = len;
+ }
+ }
+
+ /* check for end-of-block code -- there better be one! */
+ if (lengths[256] == 0)
+ return -9;
+
+ /* build huffman table for literal/length codes */
+ err = construct(&lencode, lengths, nlen);
+ if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1))
+ return -7; /* only allow incomplete codes if just one code */
+
+ /* build huffman table for distance codes */
+ err = construct(&distcode, lengths + nlen, ndist);
+ if (err < 0 || (err > 0 && ndist - distcode.count[0] != 1))
+ return -8; /* only allow incomplete codes if just one code */
+
+ /* decode data until end-of-block code */
+ return codes(s, &lencode, &distcode);
+}
+
+/*
+ * Inflate source to dest. On return, destlen and sourcelen are updated to the
+ * size of the uncompressed data and the size of the deflate data respectively.
+ * On success, the return value of puff() is zero. If there is an error in the
+ * source data, i.e. it is not in the deflate format, then a negative value is
+ * returned. If there is not enough input available or there is not enough
+ * output space, then a positive error is returned. In that case, destlen and
+ * sourcelen are not updated to facilitate retrying from the beginning with the
+ * provision of more input data or more output space. In the case of invalid
+ * inflate data (a negative error), the dest and source pointers are updated to
+ * facilitate the debugging of deflators.
+ *
+ * puff() also has a mode to determine the size of the uncompressed output with
+ * no output written. For this dest must be (unsigned char *)0. In this case,
+ * the input value of *destlen is ignored, and on return *destlen is set to the
+ * size of the uncompressed output.
+ *
+ * The return codes are:
+ *
+ * 2: available inflate data did not terminate
+ * 1: output space exhausted before completing inflate
+ * 0: successful inflate
+ * -1: invalid block type (type == 3)
+ * -2: stored block length did not match one's complement
+ * -3: dynamic block code description: too many length or distance codes
+ * -4: dynamic block code description: code lengths codes incomplete
+ * -5: dynamic block code description: repeat lengths with no first length
+ * -6: dynamic block code description: repeat more than specified lengths
+ * -7: dynamic block code description: invalid literal/length code lengths
+ * -8: dynamic block code description: invalid distance code lengths
+ * -9: dynamic block code description: missing end-of-block code
+ * -10: invalid literal/length or distance code in fixed or dynamic block
+ * -11: distance is too far back in fixed or dynamic block
+ *
+ * Format notes:
+ *
+ * - Three bits are read for each block to determine the kind of block and
+ * whether or not it is the last block. Then the block is decoded and the
+ * process repeated if it was not the last block.
+ *
+ * - The leftover bits in the last byte of the deflate data after the last
+ * block (if it was a fixed or dynamic block) are undefined and have no
+ * expected values to check.
+ */
+int puff(unsigned char *dest, /* pointer to destination pointer */
+ unsigned long *destlen, /* amount of output space */
+ const unsigned char *source, /* pointer to source data pointer */
+ unsigned long *sourcelen) /* amount of input available */
+{
+ struct state s; /* input/output state */
+ int last, type; /* block information */
+ int err; /* return value */
+
+ /* initialize output state */
+ s.out = dest;
+ s.outlen = *destlen; /* ignored if dest is NIL */
+ s.outcnt = 0;
+
+ /* initialize input state */
+ s.in = source;
+ s.inlen = *sourcelen;
+ s.incnt = 0;
+ s.bitbuf = 0;
+ s.bitcnt = 0;
+
+ /* return if bits() or decode() tries to read past available input */
+ if (setjmp(s.env) != 0) /* if came back here via longjmp() */
+ err = 2; /* then skip do-loop, return error */
+ else {
+ /* process blocks until last block or error */
+ do {
+ last = bits(&s, 1); /* one if last block */
+ type = bits(&s, 2); /* block type 0..3 */
+ err = type == 0 ? stored(&s) :
+ (type == 1 ? fixed(&s) :
+ (type == 2 ? dynamic(&s) :
+ -1)); /* type == 3, invalid */
+ if (err != 0) break; /* return with error */
+ } while (!last);
+ }
+
+ /* update the lengths and return */
+ if (err <= 0) {
+ *destlen = s.outcnt;
+ *sourcelen = s.incnt;
+ }
+ return err;
+}
+
+#ifdef TEST
+/* Examples of how to use puff().
+
+ Usage: puff [-w] [-nnn] file
+ ... | puff [-w] [-nnn]
+
+ where file is the input file with deflate data, nnn is the number of bytes
+ of input to skip before inflating (e.g. to skip a zlib or gzip header), and
+ -w is used to write the decompressed data to stdout */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Return size times approximately the cube root of 2, keeping the result as 1,
+ 3, or 5 times a power of 2 -- the result is always > size, until the result
+ is the maximum value of an unsigned long, where it remains. This is useful
+ to keep reallocations less than ~33% over the actual data. */
+local size_t bythirds(size_t size)
+{
+ int n;
+ size_t m;
+
+ m = size;
+ for (n = 0; m; n++)
+ m >>= 1;
+ if (n < 3)
+ return size + 1;
+ n -= 3;
+ m = size >> n;
+ m += m == 6 ? 2 : 1;
+ m <<= n;
+ return m > size ? m : (size_t)(-1);
+}
+
+/* Read the input file *name, or stdin if name is NULL, into allocated memory.
+ Reallocate to larger buffers until the entire file is read in. Return a
+ pointer to the allocated data, or NULL if there was a memory allocation
+ failure. *len is the number of bytes of data read from the input file (even
+ if load() returns NULL). If the input file was empty or could not be opened
+ or read, *len is zero. */
+local void *load(char *name, size_t *len)
+{
+ size_t size;
+ void *buf, *swap;
+ FILE *in;
+
+ *len = 0;
+ buf = malloc(size = 4096);
+ if (buf == NULL)
+ return NULL;
+ in = name == NULL ? stdin : fopen(name, "rb");
+ if (in != NULL) {
+ for (;;) {
+ *len += fread((char *)buf + *len, 1, size - *len, in);
+ if (*len < size) break;
+ size = bythirds(size);
+ if (size == *len || (swap = realloc(buf, size)) == NULL) {
+ free(buf);
+ buf = NULL;
+ break;
+ }
+ buf = swap;
+ }
+ fclose(in);
+ }
+ return buf;
+}
+
+int main(int argc, char **argv)
+{
+ int ret, put = 0;
+ unsigned skip = 0;
+ char *arg, *name = NULL;
+ unsigned char *source = NULL, *dest;
+ size_t len = 0;
+ unsigned long sourcelen, destlen;
+
+ /* process arguments */
+ while (arg = *++argv, --argc)
+ if (arg[0] == '-') {
+ if (arg[1] == 'w' && arg[2] == 0)
+ put = 1;
+ else if (arg[1] >= '0' && arg[1] <= '9')
+ skip = (unsigned)atoi(arg + 1);
+ else {
+ fprintf(stderr, "invalid option %s\n", arg);
+ return 3;
+ }
+ }
+ else if (name != NULL) {
+ fprintf(stderr, "only one file name allowed\n");
+ return 3;
+ }
+ else
+ name = arg;
+ source = load(name, &len);
+ if (source == NULL) {
+ fprintf(stderr, "memory allocation failure\n");
+ return 4;
+ }
+ if (len == 0) {
+ fprintf(stderr, "could not read %s, or it was empty\n",
+ name == NULL ? "<stdin>" : name);
+ free(source);
+ return 3;
+ }
+ if (skip >= len) {
+ fprintf(stderr, "skip request of %d leaves no input\n", skip);
+ free(source);
+ return 3;
+ }
+
+ /* test inflate data with offset skip */
+ len -= skip;
+ sourcelen = (unsigned long)len;
+ ret = puff(NIL, &destlen, source + skip, &sourcelen);
+ if (ret)
+ fprintf(stderr, "puff() failed with return code %d\n", ret);
+ else {
+ fprintf(stderr, "puff() succeeded uncompressing %lu bytes\n", destlen);
+ if (sourcelen < len) fprintf(stderr, "%lu compressed bytes unused\n",
+ len - sourcelen);
+ }
+
+ /* if requested, inflate again and write decompressd data to stdout */
+ if (put) {
+ dest = malloc(destlen);
+ if (dest == NULL) {
+ fprintf(stderr, "memory allocation failure\n");
+ free(source);
+ return 4;
+ }
+ puff(dest, &destlen, source + skip, &sourcelen);
+ fwrite(dest, 1, destlen, stdout);
+ free(dest);
+ }
+
+ /* clean up */
+ free(source);
+ return ret;
+}
+#endif
diff --git a/redist/puff.h b/redist/puff.h
new file mode 100644
index 0000000..eef7139
--- /dev/null
+++ b/redist/puff.h
@@ -0,0 +1,31 @@
+/* puff.h
+ Copyright (C) 2002-2010 Mark Adler, all rights reserved
+ version 2.1, 4 Apr 2010
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Mark Adler madler@alumni.caltech.edu
+ */
+
+
+/*
+ * See puff.c for purpose and usage.
+ */
+int puff(unsigned char *dest, /* pointer to destination pointer */
+ unsigned long *destlen, /* amount of output space */
+ const unsigned char *source, /* pointer to source data pointer */
+ unsigned long *sourcelen); /* amount of input available */ \ No newline at end of file
diff --git a/redist/symbol_enumerator.c b/redist/symbol_enumerator.c
new file mode 100644
index 0000000..eddddb9
--- /dev/null
+++ b/redist/symbol_enumerator.c
@@ -0,0 +1,241 @@
+#include <stdio.h>
+#include "symbol_enumerator.h"
+
+#if defined( WIN32 ) || defined( WINDOWS ) || defined( USE_WINDOWS )
+
+#include <windows.h>
+
+typedef struct _SYMBOL_INFO {
+ ULONG SizeOfStruct;
+ ULONG TypeIndex;
+ ULONG64 Reserved[2];
+ ULONG Index;
+ ULONG Size;
+ ULONG64 ModBase;
+ ULONG Flags;
+ ULONG64 Value;
+ ULONG64 Address;
+ ULONG Register;
+ ULONG Scope;
+ ULONG Tag;
+ ULONG NameLen;
+ ULONG MaxNameLen;
+ TCHAR Name[1];
+} SYMBOL_INFO, *PSYMBOL_INFO;
+typedef struct _IMAGEHLP_STACK_FRAME {
+ ULONG64 InstructionOffset;
+ ULONG64 ReturnOffset;
+ ULONG64 FrameOffset;
+ ULONG64 StackOffset;
+ ULONG64 BackingStoreOffset;
+ ULONG64 FuncTableEntry;
+ ULONG64 Params[4];
+ ULONG64 Reserved[5];
+ BOOL Virtual;
+ ULONG Reserved2;
+} IMAGEHLP_STACK_FRAME, *PIMAGEHLP_STACK_FRAME;
+
+
+typedef BOOL (*PSYM_ENUMERATESYMBOLS_CALLBACK)(
+ PSYMBOL_INFO pSymInfo,
+ ULONG SymbolSize,
+ PVOID UserContext
+ );
+
+BOOL WINAPI SymEnumSymbols(
+ HANDLE hProcess,
+ ULONG64 BaseOfDll,
+ PCTSTR Mask,
+ PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
+ const PVOID UserContext
+);
+
+BOOL WINAPI SymInitialize(
+ HANDLE hProcess,
+ PCTSTR UserSearchPath,
+ BOOL fInvadeProcess
+);
+
+BOOL CALLBACK __cdecl mycb(
+ PSYMBOL_INFO pSymInfo,
+ ULONG SymbolSize,
+ PVOID UserContext
+ ){
+ SymEnumeratorCallback cb = (SymEnumeratorCallback)UserContext;
+ return !cb( "", &pSymInfo->Name[0], (void*)pSymInfo->Address, (long) pSymInfo->Size );
+ }
+
+int EnumerateSymbols( SymEnumeratorCallback cb )
+{
+ HANDLE proc = GetCurrentProcess();
+ if( !SymInitialize( proc, 0, 1 ) ) return -1;
+ if( !SymEnumSymbols( proc, 0, "*!*", &mycb, (void*)cb ) )
+ {
+ SymCleanup(proc);
+ return -2;
+ }
+ SymCleanup(proc);
+ return 0;
+}
+
+#else
+
+
+#include <stdio.h>
+#include <dlfcn.h>
+#include <stdint.h>
+#include <limits.h>
+#include <string.h>
+
+#ifndef __GNUC__
+#define __int128_t long long long
+#endif
+
+#include <link.h>
+#include <elf.h>
+
+#define UINTS_PER_WORD (__WORDSIZE / (CHAR_BIT * sizeof (unsigned int)))
+
+
+ struct dl_phdr_info {
+ ElfW(Addr) dlpi_addr; /* Base address of object */
+ const char *dlpi_name; /* (Null-terminated) name of
+ object */
+ const ElfW(Phdr) *dlpi_phdr; /* Pointer to array of
+ ELF program headers
+ for this object */
+ ElfW(Half) dlpi_phnum; /* # of items in dlpi_phdr */
+ };
+
+
+
+void dl_iterate_phdr( void*, void*);
+
+
+static ElfW(Word) gnu_hashtab_symbol_count(const unsigned int *const table)
+{
+ const unsigned int *const bucket = table + 4 + table[2] * (unsigned int)(UINTS_PER_WORD);
+ unsigned int b = table[0];
+ unsigned int max = 0U;
+
+ while (b-->0U)
+ if (bucket[b] > max)
+ max = bucket[b];
+
+ return (ElfW(Word))max;
+}
+
+static static void *dynamic_pointer(const ElfW(Addr) addr,
+ const ElfW(Addr) base, const ElfW(Phdr) *const header, const ElfW(Half) headers)
+{
+ if (addr) {
+ ElfW(Half) h;
+
+ for (h = 0; h < headers; h++)
+ if (header[h].p_type == PT_LOAD)
+ if (addr >= base + header[h].p_vaddr &&
+ addr < base + header[h].p_vaddr + header[h].p_memsz)
+ return (void *)addr;
+ }
+
+ return NULL;
+}
+
+//Mostly based off of http://stackoverflow.com/questions/29903049/get-names-and-addresses-of-exported-functions-from-in-linux
+static int callback(struct dl_phdr_info *info,
+ size_t size, void *data)
+{
+ SymEnumeratorCallback cb = (SymEnumeratorCallback)data;
+ const ElfW(Addr) base = info->dlpi_addr;
+ const ElfW(Phdr) *const header = info->dlpi_phdr;
+ const ElfW(Half) headers = info->dlpi_phnum;
+ const char *libpath, *libname;
+ ElfW(Half) h;
+
+ if (info->dlpi_name && info->dlpi_name[0])
+ libpath = info->dlpi_name;
+ else
+ libpath = "";
+
+ libname = strrchr(libpath, '/');
+
+ if (libname && libname[0] == '/' && libname[1])
+ libname++;
+ else
+ libname = libpath;
+
+ for (h = 0; h < headers; h++)
+ {
+ if (header[h].p_type == PT_DYNAMIC)
+ {
+ const ElfW(Dyn) *entry = (const ElfW(Dyn) *)(base + header[h].p_vaddr);
+ const ElfW(Word) *hashtab;
+ const ElfW(Sym) *symtab = NULL;
+ const char *strtab = NULL;
+ ElfW(Word) symbol_count = 0;
+
+ for (; entry->d_tag != DT_NULL; entry++)
+ {
+ switch (entry->d_tag)
+ {
+ case DT_HASH:
+ hashtab = dynamic_pointer(entry->d_un.d_ptr, base, header, headers);
+ if (hashtab)
+ symbol_count = hashtab[1];
+ break;
+ case DT_GNU_HASH:
+ hashtab = dynamic_pointer(entry->d_un.d_ptr, base, header, headers);
+ if (hashtab)
+ {
+ ElfW(Word) count = gnu_hashtab_symbol_count(hashtab);
+ if (count > symbol_count)
+ symbol_count = count;
+ }
+ break;
+ case DT_STRTAB:
+ strtab = dynamic_pointer(entry->d_un.d_ptr, base, header, headers);
+ break;
+ case DT_SYMTAB:
+ symtab = dynamic_pointer(entry->d_un.d_ptr, base, header, headers);
+ break;
+ }
+ }
+
+ if (symtab && strtab && symbol_count > 0) {
+ ElfW(Word) s;
+
+ for (s = 0; s < symbol_count; s++) {
+ const char *name;
+ void *const ptr = dynamic_pointer(base + symtab[s].st_value, base, header, headers);
+ int result;
+
+ if (!ptr)
+ continue;
+
+ if (symtab[s].st_name)
+ name = strtab + symtab[s].st_name;
+ else
+ name = "";
+
+ result = cb( libpath, name, ptr, symtab[s].st_size );
+ if( result ) return result; //Bail early.
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+
+
+int EnumerateSymbols( SymEnumeratorCallback cb )
+{
+ dl_iterate_phdr( callback, cb );
+}
+
+
+
+
+#endif
diff --git a/redist/symbol_enumerator.h b/redist/symbol_enumerator.h
new file mode 100644
index 0000000..87e033b
--- /dev/null
+++ b/redist/symbol_enumerator.h
@@ -0,0 +1,12 @@
+#ifndef _SYMBOL_ENUMERATOR_H
+#define _SYMBOL_ENUMERATOR_H
+
+//Enumerates all symbols in the currently loaded excutable.
+//Don't forget to compile with -rdynamic!
+
+//Return 0 to continue search. 1 to stop.
+typedef int (*SymEnumeratorCallback)( const char * path, const char * name, void * location, long size );
+
+int EnumerateSymbols( SymEnumeratorCallback cb );
+
+#endif
diff --git a/src/ootx_decoder.c b/src/ootx_decoder.c
index e35c24d..f7a7938 100644
--- a/src/ootx_decoder.c
+++ b/src/ootx_decoder.c
@@ -6,10 +6,14 @@
#include <stdio.h>
#include <stdlib.h>
-#include <zlib.h>
#include <assert.h>
#include "ootx_decoder.h"
-//#include "crc32.h"
+
+#ifdef NOZLIB
+#include "crc32.h"
+#else
+#include <zlib.h>
+#endif
//char* fmt_str = "L Y HMD %d 5 1 206230 %d\n";
@@ -145,7 +149,7 @@ void ootx_pump_bit(ootx_decoder_context *ctx, uint8_t dbit) {
op.data = ctx->buffer+2;
op.crc32 = *(uint32_t*)(op.data+padded_length);
- uint32_t crc = crc32( 0L, Z_NULL, 0 );
+ uint32_t crc = crc32( 0L, 0 /*Z_NULL*/, 0 );
crc = crc32( crc, op.data,op.length);
if (crc != op.crc32) {
diff --git a/src/survive.c b/src/survive.c
index 6d49d55..1b5bed1 100755
--- a/src/survive.c
+++ b/src/survive.c
@@ -6,10 +6,25 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <zlib.h>
#include "survive_config.h"
+#ifdef RUNTIME_SYMNUM
+#include <symbol_enumerator.h>
+static int did_runtime_symnum;
+int SymnumCheck( const char * path, const char * name, void * location, long size )
+{
+ if( strncmp( name, "REGISTER", 8 ) == 0 )
+ {
+ typedef void (*sf)();
+ sf fn = (sf)location;
+ fn();
+ }
+ return 0;
+}
+
+#endif
+
static void survivefault( struct SurviveContext * ctx, const char * fault )
{
fprintf( stderr, "Error: %s\n", fault );
@@ -24,6 +39,14 @@ static void survivenote( struct SurviveContext * ctx, const char * fault )
SurviveContext * survive_init( int headless )
{
+#ifdef RUNTIME_SYMNUM
+ if( !did_runtime_symnum )
+ {
+ EnumerateSymbols( SymnumCheck );
+ did_runtime_symnum = 1;
+ }
+#endif
+
int r = 0;
int i = 0;
SurviveContext * ctx = calloc( 1, sizeof( SurviveContext ) );
@@ -211,6 +234,40 @@ int survive_poll( struct SurviveContext * ctx )
}
+struct SurviveObject * survive_get_so_by_name( struct SurviveContext * ctx, const char * name )
+{
+ int i;
+ for( i = 0; i < ctx->objs_ct; i++ )
+ {
+ if( strcmp( ctx->objs[i]->codename, name ) == 0 )
+ return ctx->objs[i];
+ }
+ return 0;
+}
+
+#ifdef NOZLIB
+
+#include <puff.h>
+
+
+int survive_simple_inflate( struct SurviveContext * ctx, const char * input, int inlen, char * output, int outlen )
+{
+ unsigned long ol = outlen;
+ unsigned long il = inlen;
+ int ret = puff( output, &ol, input, &il );
+ if( ret == 0 )
+ return ol;
+ else
+ {
+ SV_INFO( "puff returned error code %d\n", ret );
+ return -5;
+ }
+}
+
+#else
+
+#include <zlib.h>
+
int survive_simple_inflate( struct SurviveContext * ctx, const char * input, int inlen, char * output, int outlen )
{
z_stream zs; //Zlib stream. May only be used by configuration at beginning and by USB thread periodically.
@@ -233,14 +290,4 @@ int survive_simple_inflate( struct SurviveContext * ctx, const char * input, int
return len;
}
-struct SurviveObject * survive_get_so_by_name( struct SurviveContext * ctx, const char * name )
-{
- int i;
- for( i = 0; i < ctx->objs_ct; i++ )
- {
- if( strcmp( ctx->objs[i]->codename, name ) == 0 )
- return ctx->objs[i];
- }
- return 0;
-}
-
+#endif
diff --git a/src/survive_cal.c b/src/survive_cal.c
index ce8fd89..0ea9337 100755
--- a/src/survive_cal.c
+++ b/src/survive_cal.c
@@ -168,7 +168,7 @@ void survive_cal_light( struct SurviveObject * so, int sensor_id, int acode, int
struct SurviveCalData * cd = ctx->calptr;
if( !cd ) return;
-
+
switch( cd->stage )
{
default:
@@ -193,6 +193,7 @@ void survive_cal_light( struct SurviveObject * so, int sensor_id, int acode, int
}
break;
}
+
}
void survive_cal_angle( struct SurviveObject * so, int sensor_id, int acode, uint32_t timecode, FLT length, FLT angle )
@@ -347,8 +348,11 @@ static void handle_calibration( struct SurviveCalData *cd )
//Either advance to stage 4 or go resetting will go back to stage 2.
//What is stage 4? Are we done then?
-
+#ifdef WINDOWS
+ mkdir( "calinfo" );
+#else
mkdir( "calinfo", 0755 );
+#endif
FILE * hists = fopen( "calinfo/histograms.csv", "w" );
FILE * ptinfo = fopen( "calinfo/ptinfo.csv", "w" );
int sen, axis, lh;
diff --git a/src/survive_cal_lhfind.c b/src/survive_cal_lhfind.c
deleted file mode 100644
index cc32154..0000000
--- a/src/survive_cal_lhfind.c
+++ /dev/null
@@ -1,298 +0,0 @@
-#include "survive_cal.h"
-#include <math.h>
-#include <string.h>
-#include "linmath.h"
-
-#define MAX_CHECKS 40000
-#define MIN_HITS_FOR_VALID 10
-
-
-FLT static RunOpti( SurviveCalData * cd, int lh, int print, FLT * LighthousePos, FLT * LighthouseQuat );
-
-//Values used for RunTest()
-
-int survive_cal_lhfind( SurviveCalData * cd )
-{
- SurviveContext * ctx = cd->ctx;
- int cycle, i;
- int lh = 0;
- FLT dx, dy, dz;
-
- //Use the following:
- // FLT avgsweeps[MAX_CAL_PT_DAT];
- // FLT avglens[MAX_CAL_PT_DAT];
- // FLT stdsweeps[MAX_CAL_PT_DAT];
- // FLT stdlens[MAX_CAL_PT_DAT];
- // int ctsweeps[MAX_CAL_PT_DAT];
- //
- // Check your solution against point: senid_of_checkpt's data.
-
-
-
- for( lh = 0; lh < 2; lh++ )
- {
- FLT beste = 1e20;
-
- FLT LighthousePos[3];
- FLT LighthouseQuat[4];
-
- LighthousePos[0] = 0;
- LighthousePos[1] = 0;
- LighthousePos[2] = 0;
- LighthouseQuat[0] = 1;
- LighthouseQuat[1] = 1;
- LighthouseQuat[2] = 1;
- LighthouseQuat[3] = 1;
-
- FLT bestxyz[3];
- memcpy( bestxyz, LighthousePos, sizeof( LighthousePos ) );
-
- //STAGE1 1: Detemine vectoral position from lighthouse to target. Does not determine lighthouse-target distance.
- //This also is constantly optimizing the lighthouse quaternion for optimal spotting.
- FLT fullrange = 5; //Maximum search space for positions. (Relative to HMD)
-
-
- //Sweep whole area 30 times
- for( cycle = 0; cycle < 30; cycle ++ )
- {
-
- //Adjust position, one axis at a time, over and over until we zero in.
- {
- FLT bestxyzrunning[3];
- beste = 1e20;
-
- FILE * f;
- if( cycle == 0 )
- {
- char filename[1024];
- sprintf( filename, "calinfo/%d_lighthouse.dat", lh );
- f = fopen( filename, "wb" );
- }
-
- //We split the space into this many groups (times 2) and
- //if we're on the first cycle, we want to do a very linear
- //search. As we refine our search we can then use a more
- //binary search technique.
- FLT splits = 4;
- if( cycle == 0 ) splits = 32;
- if( cycle == 1 ) splits = 13;
- if( cycle == 2 ) splits = 10;
- if( cycle == 3 ) splits = 8;
- if( cycle == 4 ) splits = 5;
-
- //Wwe search throug the whole space.
- for( dz = 0; dz < fullrange; dz += fullrange/splits )
- for( dy = -fullrange; dy < fullrange; dy += fullrange/splits )
- for( dx = -fullrange; dx < fullrange; dx += fullrange/splits )
- {
- //Specificially adjust one axis at a time, searching for the best.
- memcpy( LighthousePos, bestxyz, sizeof( LighthousePos ) );
- LighthousePos[0] += dx; //These are adjustments to the "best" from last frame.
- LighthousePos[1] += dy;
- LighthousePos[2] += dz;
-
- FLT ft;
- //Try refining the search for the best orientation several times.
- ft = RunOpti(cd, lh, 0, LighthousePos, LighthouseQuat);
- if( cycle == 0 )
- {
- float sk = ft*10.;
- if( sk > 1 ) sk = 1;
- uint8_t cell = (1.0 - sk) * 255;
- FLT epsilon = 0.1;
-
- if( dz == 0 ) { /* Why is dz special? ? */
- if ( dx > -epsilon && dx < epsilon )
- cell = 255;
- if ( dy > -epsilon && dy < epsilon )
- cell = 128;
- }
-
- fprintf( f, "%c", cell );
- }
-
- if( ft < beste ) { beste = ft; memcpy( bestxyzrunning, LighthousePos, sizeof( LighthousePos ) ); }
- }
-
- if( cycle == 0 )
- {
- fclose( f );
- }
- memcpy( bestxyz, bestxyzrunning, sizeof( bestxyz ) );
-
- //Print out the quality of the lock this time.
- FLT dist = sqrt(bestxyz[0]*bestxyz[0] + bestxyz[1]*bestxyz[1] + bestxyz[2]*bestxyz[2]);
- printf( "%f %f %f (%f) = %f\n", bestxyz[0], bestxyz[1], bestxyz[2], dist, beste );
- }
-
- //Every cycle, tighten up the search area.
- fullrange *= 0.25;
- }
-
- if( beste > 0.1 )
- {
- //Error too high
- SV_ERROR( "LH: %d / Best E %f Error too high\n", lh, beste );
- return -1;
- }
-
- RunOpti(cd, lh, 1, LighthousePos, LighthouseQuat);
-
- cd->ctx->bsd[lh].PositionSet = 1;
- copy3d( cd->ctx->bsd[lh].Pose.Pos, LighthousePos );
- quatcopy( cd->ctx->bsd[lh].Pose.Rot, LighthouseQuat );
- }
-
- return 0; //Return 0 if success.
-}
-
-
-
-
-
-
-static FLT RunOpti( SurviveCalData * cd, int lh, int print, FLT * LighthousePos, FLT * LighthouseQuat )
-{
- int i, p;
- FLT UsToTarget[3];
- FLT LastUsToTarget[3];
- FLT mux = .9;
- quatsetnone( LighthouseQuat );
- SurviveObject * hmd = cd->hmd;
- FLT * hmd_points = hmd->sensor_locations;
- FLT * hmd_normals = hmd->sensor_normals;
-
- int first = 1, second = 0;
-
- //First check to see if this is a valid viewpoint.
- //If a sensor is pointed away from where we are testing a possible lighthouse position.
- //BUT We get data from that light house, then we KNOW this is not a possible
- //lighthouse position.
- for( p = 0; p < 32; p++ )
- {
- int dataindex = p*(2*NUM_LIGHTHOUSES)+lh*2;
- if( cd->ctsweeps[dataindex+0] < MIN_HITS_FOR_VALID || cd->ctsweeps[dataindex+1] < MIN_HITS_FOR_VALID ) continue;
- FLT me_to_dot[3];
- sub3d( me_to_dot, LighthousePos, &hmd_points[p*3] );
- float dot = dot3d( &hmd_normals[p*3], me_to_dot );
- if( dot < -.01 ) { return 1000; }
- }
- int iters = 6;
-
- //Iterate over a refinement of the quaternion that constitutes the
- //lighthouse.
- for( i = 0; i < iters; i++ )
- {
- first = 1;
- for( p = 0; p < 32; p++ )
- {
- int dataindex = p*(2*NUM_LIGHTHOUSES)+lh*2;
- if( cd->ctsweeps[dataindex+0] < MIN_HITS_FOR_VALID || cd->ctsweeps[dataindex+1] < MIN_HITS_FOR_VALID ) continue;
-
- //Find out where our ray shoots forth from.
- FLT ax = cd->avgsweeps[dataindex+0];
- FLT ay = cd->avgsweeps[dataindex+1];
-
- //NOTE: Inputs may never be output with cross product.
- //Create a fictitious normalized ray. Imagine the lighthouse is pointed
- //straight in the +z direction, this is the lighthouse ray to the point.
- FLT RayShootOut[3] = { sin(ax), sin(ay), 0 };
- RayShootOut[2] = sqrt( 1 - (RayShootOut[0]*RayShootOut[0] + RayShootOut[1]*RayShootOut[1]) );
- FLT RayShootOutWorld[3];
-
- quatnormalize( LighthouseQuat, LighthouseQuat );
- //Rotate that ray by the current rotation estimation.
- quatrotatevector( RayShootOutWorld, LighthouseQuat, RayShootOut );
-
- //Find a ray from us to the target point.
- sub3d( UsToTarget, &hmd_points[p*3], LighthousePos );
- if( magnitude3d( UsToTarget ) < 0.0001 ) { continue; }
- normalize3d( UsToTarget, UsToTarget );
-
- FLT RotatedLastUs[3];
- quatnormalize( LighthouseQuat, LighthouseQuat );
- quatrotatevector( RotatedLastUs, LighthouseQuat, LastUsToTarget );
-
- //Rotate the lighthouse around this axis to point at the HMD.
- //If it's the first time, the axis is synthesized, if it's after that, use most recent point.
- FLT ConcatQuat[4];
- FLT AxisToRotate[3];
- if( first )
- {
- cross3d( AxisToRotate, RayShootOutWorld, UsToTarget );
- if( magnitude3d(AxisToRotate) < 0.0001 ) break;
- normalize3d( AxisToRotate, AxisToRotate );
- //Don't need to worry about being negative, cross product will fix it.
- FLT RotateAmount = anglebetween3d( RayShootOutWorld, UsToTarget );
- quatfromaxisangle( ConcatQuat, AxisToRotate, RotateAmount );
- quatnormalize( ConcatQuat, ConcatQuat );
- }
- else
- {
- FLT Target[3];
- FLT Actual[3];
-
- copy3d( AxisToRotate, LastUsToTarget );
- //Us to target = normalized ray from us to where we should be.
- //RayShootOut = where we would be pointing.
- sub3d( Target, UsToTarget, AxisToRotate ); //XXX XXX XXX WARNING THIS MESSES STUFF UP.
- sub3d( Actual, RayShootOutWorld, AxisToRotate );
- if( magnitude3d( Actual ) < 0.0001 || magnitude3d( Target ) < 0.0001 ) { continue; }
- normalize3d( Target, Target );
- normalize3d( Actual, Actual );
-
- cross3d( AxisToRotate, Actual, Target ); //XXX Check: AxisToRotate should be equal to LastUsToTarget.
- if( magnitude3d( AxisToRotate ) < 0.000001 ) { continue; }
- normalize3d( AxisToRotate,AxisToRotate );
-
- //printf( "%f %f %f === %f %f %f : ", PFTHREE( AxisToRotate ), PFTHREE( LastUsToTarget ) );
- FLT RotateAmount = anglebetween3d( Actual, Target ) * mux;
- //printf( "FA: %f (O:%f)\n", acos( dot3d( Actual, Target ) ), RotateAmount );
- quatfromaxisangle( ConcatQuat, AxisToRotate, RotateAmount );
- quatnormalize( ConcatQuat, ConcatQuat );
- }
-
-
- quatnormalize( ConcatQuat, ConcatQuat );
- quatnormalize( LighthouseQuat, LighthouseQuat );
- quatrotateabout( LighthouseQuat, ConcatQuat, LighthouseQuat ); //Checked. This appears to be
-
- mux = mux * 0.94;
- if( second ) { second = 0; }
- if( first ) { first = 0; second = 1; }
- copy3d( LastUsToTarget, RayShootOutWorld );
- }
- }
-
- //Step 2: Determine error.
- float errorsq = 0.0;
- int count = 0;
- for( p = 0; p < 32; p++ )
- {
- int dataindex = p*(2*NUM_LIGHTHOUSES)+lh*2;
- if( cd->ctsweeps[dataindex+0] < MIN_HITS_FOR_VALID || cd->ctsweeps[dataindex+1] < MIN_HITS_FOR_VALID ) continue;
-
- //Find out where our ray shoots forth from.
- FLT ax = cd->avgsweeps[dataindex+0];
- FLT ay = cd->avgsweeps[dataindex+1];
- FLT RayShootOut[3] = { sin(ax), sin(ay), 0 };
- RayShootOut[2] = sqrt( 1 - (RayShootOut[0]*RayShootOut[0] + RayShootOut[1]*RayShootOut[1]) );
-
- //Rotate that ray by the current rotation estimation.
- quatrotatevector( RayShootOut, LighthouseQuat, RayShootOut );
-
- //Point-line distance.
- //Line defined by LighthousePos & Direction: RayShootOut
-
- //Find a ray from us to the target point.
- sub3d( UsToTarget, &hmd_points[p*3], LighthousePos );
- FLT xproduct[3];
- cross3d( xproduct, UsToTarget, RayShootOut );
- FLT dist = magnitude3d( xproduct );
- errorsq += dist*dist;
- if( print ) printf( "%f (%d(%d/%d))\n", dist, p, cd->ctsweeps[dataindex+0], cd->ctsweeps[dataindex+1] );
- }
- if( print ) printf( " = %f\n", sqrt( errorsq ) );
- return sqrt(errorsq);
-}
-
diff --git a/src/survive_data.c b/src/survive_data.c
index ac397b9..e51de8e 100644
--- a/src/survive_data.c
+++ b/src/survive_data.c
@@ -13,12 +13,12 @@ void handle_lightcap( SurviveObject * so, LightcapElement * le )
//if( so->codename[0] != 'H' )
+
if( le->sensor_id > SENSORS_PER_OBJECT )
{
return;
}
-
so->tsl = le->timestamp;
if( le->length < 20 ) return; ///Assuming 20 is an okay value for here.
diff --git a/src/survive_internal.h b/src/survive_internal.h
index 392104a..e1a733d 100644
--- a/src/survive_internal.h
+++ b/src/survive_internal.h
@@ -7,7 +7,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
-#include <zlib.h>
#include <survive.h>
diff --git a/src/survive_process.c b/src/survive_process.c
index 2fea99d..8dc849a 100644
--- a/src/survive_process.c
+++ b/src/survive_process.c
@@ -11,7 +11,6 @@ void survive_default_light_process( SurviveObject * so, int sensor_id, int acode
SurviveContext * ctx = so->ctx;
int base_station = acode >> 2;
int axis = acode & 1;
-
if( ctx->calptr )
{
survive_cal_light( so, sensor_id, acode, timeinsweep, timecode, length );
diff --git a/src/survive_vive.c b/src/survive_vive.c
index 0cae6f0..fc05647 100755
--- a/src/survive_vive.c
+++ b/src/survive_vive.c
@@ -12,14 +12,24 @@
#include <survive.h>
#include <jsmn.h>
-#include <libusb-1.0/libusb.h>
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
+
+#ifdef HIDAPI
+#include <os_generic.h>
+#if defined(WINDOWS) || defined(WIN32)
+#include <windows.h>
+#undef WCHAR_MAX
+#endif
+#include <hidapi.h>
+#else
+#include <libusb-1.0/libusb.h>
+#endif
+
struct SurviveViveData;
const short vidpids[] = {
@@ -28,6 +38,9 @@ const short vidpids[] = {
0x28de, 0x2101, 0, //Valve Watchman
0x28de, 0x2101, 1, //Valve Watchman
0x28de, 0x2022, 0, //HTC Tracker
+#ifdef HIDAPI
+ 0x28de, 0x2000, 1, //Valve lighthouse(B) (only used on HIDAPI, for lightcap)
+#endif
}; //length MAX_USB_INTERFACES*2
const char * devnames[] = {
@@ -36,6 +49,9 @@ const char * devnames[] = {
"Watchman 1",
"Watchman 2",
"Tracker 0",
+#ifdef HIDAPI
+ "Lightcap",
+#endif
}; //length MAX_USB_INTERFACES
@@ -44,7 +60,8 @@ const char * devnames[] = {
#define USB_DEV_WATCHMAN1 2
#define USB_DEV_WATCHMAN2 3
#define USB_DEV_TRACKER0 4
-#define MAX_USB_DEVS 5
+#define USB_DEV_LIGHTHOUSEB 5
+#define MAX_USB_DEVS 6
#define USB_IF_HMD 0
@@ -60,12 +77,22 @@ typedef struct SurviveViveData SurviveViveData;
typedef void (*usb_callback)( SurviveUSBInterface * ti );
+#ifdef HIDAPI
+#define USBHANDLE hid_device *
+#else
+#define USBHANDLE libusb_device_handle *
+#endif
+
struct SurviveUSBInterface
{
SurviveViveData * sv;
SurviveContext * ctx;
+#ifdef HIDAPI
+ USBHANDLE uh;
+#else
struct libusb_transfer * transfer;
+#endif
SurviveObject * assoc_obj;
int actual_len;
uint8_t buffer[INTBUFFSIZE];
@@ -78,14 +105,20 @@ struct SurviveViveData
{
SurviveContext * ctx;
- //XXX TODO: UN-STATICIFY THIS.
SurviveUSBInterface uiface[MAX_INTERFACES];
- //USB Subsystem
- struct libusb_context* usbctx;
- struct libusb_device_handle * udev[MAX_USB_DEVS];
+ USBHANDLE udev[MAX_USB_DEVS];
+#ifdef HIDAPI
+ og_thread_t servicethread[MAX_USB_DEVS];
+#else
+ struct libusb_context* usbctx;
+#endif
};
+#ifdef HIDAPI
+og_mutex_t GlobalRXUSBMutx;
+#endif
+
void survive_data_cb( SurviveUSBInterface * si );
//USB Subsystem
@@ -95,7 +128,37 @@ int survive_usb_poll( SurviveContext * ctx );
int survive_get_config( char ** config, SurviveViveData * ctx, int devno, int interface, int send_extra_magic );
int survive_vive_send_magic(struct SurviveContext * ctx, void * drv, int magic_code, void * data, int datalen );
+#ifdef HIDAPI
+void * HAPIReceiver( void * v )
+{
+ char buf[65];
+ int res;
+
+ SurviveUSBInterface * iface = v;
+ USBHANDLE * hp = &iface->uh;
+
+ while( (iface->actual_len = hid_read( *hp, iface->buffer, sizeof( iface->buffer ) )) > 0 )
+ {
+ //if( iface->actual_len == 52 ) continue;
+ OGLockMutex( GlobalRXUSBMutx );
+#if 0
+ printf( "%d %d: ", iface->which_interface_am_i, iface->actual_len );
+ int i;
+ for( i = 0; i < iface->actual_len; i++ )
+ {
+ printf( "%02x ", iface->buffer[i] );
+ }
+ printf("\n" );
+#endif
+ survive_data_cb( iface );
+ OGUnlockMutex( GlobalRXUSBMutx );
+ }
+ //XXX TODO: Mark device as failed.
+ *hp = 0;
+ return 0;
+}
+#else
static void handle_transfer(struct libusb_transfer* transfer)
{
struct SurviveUSBInterface * iface = transfer->user_data;
@@ -117,10 +180,10 @@ static void handle_transfer(struct libusb_transfer* transfer)
SV_KILL();
}
}
+#endif
-
-static int AttachInterface( SurviveViveData * sv, SurviveObject * assocobj, int which_interface_am_i, libusb_device_handle * devh, int endpoint, usb_callback cb, const char * hname )
+static int AttachInterface( SurviveViveData * sv, SurviveObject * assocobj, int which_interface_am_i, USBHANDLE devh, int endpoint, usb_callback cb, const char * hname )
{
SurviveContext * ctx = sv->ctx;
SurviveUSBInterface * iface = &sv->uiface[which_interface_am_i];
@@ -129,8 +192,15 @@ static int AttachInterface( SurviveViveData * sv, SurviveObject * assocobj, int
iface->which_interface_am_i = which_interface_am_i;
iface->assoc_obj = assocobj;
iface->hname = hname;
- struct libusb_transfer * tx = iface->transfer = libusb_alloc_transfer(0);
iface->cb = cb;
+
+#ifdef HIDAPI
+ //What do here?
+ iface->uh = devh;
+ sv->servicethread[which_interface_am_i] = OGCreateThread( HAPIReceiver, iface );
+ OGUSleep(100000);
+#else
+ struct libusb_transfer * tx = iface->transfer = libusb_alloc_transfer(0);
//printf( "%p %d %p %p\n", iface, which_interface_am_i, tx, devh );
if (!iface->transfer)
@@ -147,7 +217,7 @@ static int AttachInterface( SurviveViveData * sv, SurviveObject * assocobj, int
SV_ERROR( "Error: Could not submit transfer for %s (Code %d)", hname, rc );
return 6;
}
-
+#endif
return 0;
}
@@ -166,6 +236,25 @@ static void debug_cb( struct SurviveUSBInterface * si )
//XXX TODO: Redo this subsystem for setting/updating feature reports.
+
+#ifdef HIDAPI
+
+static inline int update_feature_report(USBHANDLE dev, uint16_t interface, uint8_t * data, int datalen )
+{
+ int r = hid_send_feature_report( dev, data, datalen );
+// printf( "HUR: (%p) %d (%d) [%d]\n", dev, r, datalen, data[0] );
+ return r;
+}
+static inline int getupdate_feature_report(USBHANDLE dev, uint16_t interface, uint8_t * data, int datalen )
+{
+ int r = hid_get_feature_report( dev, data, datalen );
+// printf( "HGR: (%p) %d (%d) (%d)\n", dev, r, datalen, data[0] );
+ if( r == -1 ) return -9; //Pretend it's not a critical error
+ return r;
+}
+
+#else
+
static inline int update_feature_report(libusb_device_handle* dev, uint16_t interface, uint8_t * data, int datalen ) {
// int xfer;
// int r = libusb_interrupt_transfer(dev, 0x01, data, datalen, &xfer, 1000);
@@ -186,26 +275,88 @@ static inline int getupdate_feature_report(libusb_device_handle* dev, uint16_t i
return ret;
}
+#endif
-
-static inline int hid_get_feature_report_timeout(libusb_device_handle* device, uint16_t interface, unsigned char *buf, size_t len )
+static inline int hid_get_feature_report_timeout(USBHANDLE device, uint16_t interface, unsigned char *buf, size_t len )
{
int ret;
uint8_t i = 0;
- for (i = 0; i < 100; i++)
+ for (i = 0; i < 50; i++)
{
ret = getupdate_feature_report(device, interface, buf, len);
if( ret != -9 && ( ret != -1 || errno != EPIPE ) ) return ret;
- usleep( 1000 );
+ OGUSleep( 1000 );
}
return -1;
}
-
int survive_usb_init( struct SurviveViveData * sv, struct SurviveObject * hmd, struct SurviveObject *wm0, struct SurviveObject * wm1, struct SurviveObject * tr0 )
{
struct SurviveContext * ctx = sv->ctx;
+#ifdef HIDAPI
+ if( !GlobalRXUSBMutx )
+ {
+ GlobalRXUSBMutx = OGCreateMutex();
+ OGLockMutex( GlobalRXUSBMutx );
+ }
+ int res, i;
+ res = hid_init();
+ if( res )
+ {
+ SV_ERROR( "Could not setup hidapi." );
+ return res;
+ }
+
+ for( i = 0; i < MAX_USB_DEVS; i++ )
+ {
+ int enumid = vidpids[i*3+2];
+ int vendor_id = vidpids[i*3+0];
+ int product_id = vidpids[i*3+1];
+ struct hid_device_info * devs = hid_enumerate(vendor_id, product_id);
+ struct hid_device_info * cur_dev = devs;
+ const char *path_to_open = NULL;
+ hid_device *handle = NULL;
+ int menum = 0;
+
+ cur_dev = devs;
+ while (cur_dev) {
+ if (cur_dev->vendor_id == vendor_id &&
+ cur_dev->product_id == product_id)
+ {
+ if( menum == enumid )
+ {
+ path_to_open = cur_dev->path;
+ break;
+ }
+ menum++;
+ }
+ cur_dev = cur_dev->next;
+ }
+
+ if (path_to_open) {
+ handle = hid_open_path(path_to_open);
+ }
+
+ hid_free_enumeration(devs);
+
+ if( !handle )
+ {
+ SV_INFO( "Warning: Could not find vive device %04x:%04x", vendor_id, product_id );
+ continue;
+ }
+
+ // Read the Serial Number String
+ wchar_t wstr[255];
+
+ res = hid_get_serial_number_string(handle, wstr, 255);
+ wprintf(L"Serial Number String: (%d) %s for %04x:%04x@%d (Dev: %p)\n", wstr[0], wstr,vendor_id, product_id, menum, handle);
+
+ sv->udev[i] = handle;
+
+ }
+
+#else
int r = libusb_init( &sv->usbctx );
if( r )
{
@@ -294,15 +445,21 @@ int survive_usb_init( struct SurviveViveData * sv, struct SurviveObject * hmd, s
SV_INFO( "Successfully enumerated %s (%d, %d)", devnames[i], did, conf->bNumInterfaces );
}
+
libusb_free_device_list( devs, 1 );
+#endif
if( sv->udev[USB_DEV_HMD] && AttachInterface( sv, hmd, USB_IF_HMD, sv->udev[USB_DEV_HMD], 0x81, survive_data_cb, "Mainboard" ) ) { return -6; }
if( sv->udev[USB_DEV_LIGHTHOUSE] && AttachInterface( sv, hmd, USB_IF_LIGHTHOUSE, sv->udev[USB_DEV_LIGHTHOUSE], 0x81, survive_data_cb, "Lighthouse" ) ) { return -7; }
if( sv->udev[USB_DEV_WATCHMAN1] && AttachInterface( sv, wm0, USB_IF_WATCHMAN1, sv->udev[USB_DEV_WATCHMAN1], 0x81, survive_data_cb, "Watchman 1" ) ) { return -8; }
if( sv->udev[USB_DEV_WATCHMAN2] && AttachInterface( sv, wm1, USB_IF_WATCHMAN2, sv->udev[USB_DEV_WATCHMAN2], 0x81, survive_data_cb, "Watchman 2")) { return -9; }
if( sv->udev[USB_DEV_TRACKER0] && AttachInterface( sv, tr0, USB_IF_TRACKER0, sv->udev[USB_DEV_TRACKER0], 0x81, survive_data_cb, "Tracker 1")) { return -10; }
+#ifdef HIDAPI
+ //Tricky: use other interface for actual lightcap. XXX THIS IS NOT YET RIGHT!!!
+ if( sv->udev[USB_DEV_LIGHTHOUSEB] && AttachInterface( sv, hmd, USB_IF_LIGHTCAP, sv->udev[USB_DEV_LIGHTHOUSEB], 0x82, survive_data_cb, "Lightcap")) { return -12; }
+#else
if( sv->udev[USB_DEV_LIGHTHOUSE] && AttachInterface( sv, hmd, USB_IF_LIGHTCAP, sv->udev[USB_DEV_LIGHTHOUSE], 0x82, survive_data_cb, "Lightcap")) { return -12; }
-
+#endif
SV_INFO( "All enumerated devices attached." );
survive_vive_send_magic(ctx, sv, 1, 0, 0 );
@@ -351,7 +508,7 @@ int survive_vive_send_magic(struct SurviveContext * ctx, void * drv, int magic_c
if (sv->udev[USB_DEV_LIGHTHOUSE])
{
static uint8_t vive_magic_enable_lighthouse[64] = { 0x04 }; //[64] wat? Why did that fix it?
- r = update_feature_report( sv->udev[USB_DEV_LIGHTHOUSE], 0, vive_magic_enable_lighthouse, sizeof( vive_magic_enable_lighthouse ) );
+ r = update_feature_report( sv->udev[USB_DEV_LIGHTHOUSE], 0, vive_magic_enable_lighthouse, sizeof( vive_magic_enable_lighthouse ) ); ///XXX TODO: Shouldn't this be LIGHTHOUSEB for hidapi?
if( r != sizeof( vive_magic_enable_lighthouse ) ) return 5;
}
@@ -362,7 +519,7 @@ int survive_vive_send_magic(struct SurviveContext * ctx, void * drv, int magic_c
r = update_feature_report( sv->udev[USB_DEV_WATCHMAN1], 0, vive_controller_haptic_pulse, sizeof( vive_controller_haptic_pulse ) );
SV_INFO( "UCR: %d", r );
if( r != sizeof( vive_controller_haptic_pulse ) ) return 5;
- usleep( 1000 );
+ OGUSleep( 1000 );
}
#endif
SV_INFO( "Powered unit on." );
@@ -403,15 +560,35 @@ int survive_vive_send_magic(struct SurviveContext * ctx, void * drv, int magic_c
void survive_vive_usb_close( struct SurviveViveData * sv )
{
int i;
+#ifdef HIDAPI
+ for( i = 0; i < MAX_USB_DEVS; i++ )
+ {
+ if( sv->udev[i] )
+ hid_close( sv->udev[i] );
+ }
+ for( i = 0; i < MAX_USB_DEVS; i++ )
+ {
+ OGJoinThread( sv->servicethread[i] );
+ }
+ //This is global, don't do it on account of other tasks.
+ //hid_exit();
+
+#else
for( i = 0; i < MAX_USB_DEVS; i++ )
{
libusb_close( sv->udev[i] );
}
libusb_exit(sv->usbctx);
+#endif
}
int survive_vive_usb_poll( struct SurviveContext * ctx, void * v )
{
+#ifdef HIDAPI
+ OGUnlockMutex( GlobalRXUSBMutx );
+ OGUSleep( 100 );
+ OGUnlockMutex( GlobalRXUSBMutx );
+#else
struct SurviveViveData * sv = v;
int r = libusb_handle_events( sv->usbctx );
if( r )
@@ -420,6 +597,7 @@ int survive_vive_usb_poll( struct SurviveContext * ctx, void * v )
SV_ERROR( "Libusb poll failed." );
}
return r;
+#endif
}
@@ -430,7 +608,7 @@ int survive_get_config( char ** config, struct SurviveViveData * sv, int devno,
uint8_t cfgbuff[64];
uint8_t compressed_data[8192];
uint8_t uncompressed_data[65536];
- struct libusb_device_handle * dev = sv->udev[devno];
+ USBHANDLE dev = sv->udev[devno];
if( send_extra_magic )
{
@@ -439,13 +617,10 @@ int survive_get_config( char ** config, struct SurviveViveData * sv, int devno,
memset( cfgbuffwide, 0, sizeof( cfgbuff ) );
cfgbuffwide[0] = 0x01;
ret = hid_get_feature_report_timeout( dev, iface, cfgbuffwide, sizeof( cfgbuffwide ) );
- usleep(1000);
+ OGUSleep(1000);
int k;
-
- //Switch mode to pull config?
- for( k = 0; k < 10; k++ )
- {
+
uint8_t cfgbuff_send[64] = {
0xff, 0x83, 0x00, 0xb6, 0x5b, 0xb0, 0x78, 0x69,
0x0f, 0xf8, 0x78, 0x69, 0x0f, 0xa0, 0xf3, 0x18,
@@ -456,15 +631,28 @@ int survive_get_config( char ** config, struct SurviveViveData * sv, int devno,
0x0f, 0x00, 0x00, 0xa0, 0x0f, 0xa0, 0x9b, 0x0a,
0x01, 0x00, 0x00, 0x35, 0x00, 0x34, 0x02, 0x00
};
-
+
+ #ifdef HIDAPI
+ //XXX TODO WRITEME
+ for( k = 0; k < 10; k++ )
+ {
+ OGUSleep( 1000);
+ }
+
+ #else
+ //Switch mode to pull config?
+ SV_INFO( "XXX TODO See if this can be update_feature_report" );
+ for( k = 0; k < 10; k++ )
+ {
int rk = libusb_control_transfer(dev, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
0x09, 0x300 | cfgbuff_send[0], iface, cfgbuff_send, 64, 1000 );
- usleep(1000);
+ OGUSleep(1000);
}
+ #endif
cfgbuffwide[0] = 0xff;
ret = hid_get_feature_report_timeout( dev, iface, cfgbuffwide, sizeof( cfgbuffwide ) );
- usleep(1000);
+ OGUSleep(1000);
}
memset( cfgbuff, 0, sizeof( cfgbuff ) );
@@ -514,6 +702,12 @@ int survive_get_config( char ** config, struct SurviveViveData * sv, int devno,
SV_INFO( "Got config data length %d", count );
+ char fstname[128];
+ sprintf( fstname, "calinfo/%d.json.gz", devno );
+ FILE * f = fopen( fstname, "wb" );
+ fwrite( compressed_data, count, 1, f );
+ fclose( f );
+
int len = survive_simple_inflate( ctx, compressed_data, count, uncompressed_data, sizeof(uncompressed_data)-1 );
if( len <= 0 )
{
@@ -776,16 +970,6 @@ void survive_data_cb( SurviveUSBInterface * si )
{
int size = si->actual_len;
SurviveContext * ctx = si->ctx;
-#if 0
- int i;
- printf( "%16s: %d: ", si->hname, len );
- for( i = 0; i < size; i++ )
- {
- printf( "%02x ", si->buffer[i] );
- }
- printf( "\n" );
- return;
-#endif
int iface = si->which_interface_am_i;
SurviveObject * obj = si->assoc_obj;
@@ -795,6 +979,20 @@ void survive_data_cb( SurviveUSBInterface * si )
// printf( "%16s Size: %2d ID: %d / %d\n", si->hname, size, id, iface );
+#if 0
+ if( si->which_interface_am_i == 5 )
+ {
+ int i;
+ printf( "%16s: %d: %d: %d: ", si->hname, id, size, sizeof(LightcapElement) );
+ for( i = 0; i < size-1; i++ )
+ {
+ printf( "%02x ", readdata[i] );
+ }
+ printf( "\n" );
+
+ }
+#endif
+
switch( si->which_interface_am_i )
{
case USB_IF_HMD:
@@ -883,13 +1081,25 @@ void survive_data_cb( SurviveUSBInterface * si )
}
case USB_IF_LIGHTCAP:
{
- //Done!
int i;
+ #ifdef HIDAPI
+ for( i = 0; i < 7; i++ )
+ {
+ LightcapElement le;
+ le.sensor_id = POP1;
+ le.type = 0xfe;
+ le.length = POP2;
+ le.timestamp = POP4;
+ if( le.sensor_id == 0xff ) break;
+ handle_lightcap( obj, &le );
+ }
+ #else
for( i = 0; i < 7; i++ )
{
handle_lightcap( obj, (LightcapElement*)&readdata[i*8] );
}
break;
+ #endif
}
}
}
@@ -962,7 +1172,7 @@ static int LoadConfig( SurviveViveData * sv, SurviveObject * so, int devno, int
SurviveContext * ctx = sv->ctx;
char * ct0conf = 0;
int len = survive_get_config( &ct0conf, sv, devno, iface, extra_magic );
-
+printf( "Loading config: %d\n", len );
#if 0
char fname[100];
sprintf( fname, "%s_config.json", so->codename );
@@ -1022,7 +1232,6 @@ static int LoadConfig( SurviveViveData * sv, SurviveObject * so, int devno, int
}
char fname[20];
- mkdir( "calinfo", 0755 );
sprintf( fname, "calinfo/%s_points.csv", so->codename );
FILE * f = fopen( fname, "w" );
@@ -1063,6 +1272,13 @@ int DriverRegHTCVive( SurviveContext * ctx )
SurviveViveData * sv = calloc( 1, sizeof( SurviveViveData ) );
sv->ctx = ctx;
+
+ #ifdef WINDOWS
+ mkdir( "calinfo" );
+ #else
+ mkdir( "calinfo", 0755 );
+ #endif
+
hmd->ctx = ctx;
memcpy( hmd->codename, "HMD", 4 );
diff --git a/useful_files/lib_survive_logo3.svg b/useful_files/lib_survive_logo3.svg
new file mode 100644
index 0000000..a6d003e
--- /dev/null
+++ b/useful_files/lib_survive_logo3.svg
@@ -0,0 +1,236 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="238.93333"
+ height="238.93333"
+ viewBox="0 0 210 210"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="lib_survive_logo2(1).svg"
+ inkscape:export-filename="lib_survive_logo_sm.png"
+ inkscape:export-xdpi="13.499999"
+ inkscape:export-ydpi="13.499999">
+ <defs
+ id="defs4">
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4339">
+ <stop
+ style="stop-color:#ff0000;stop-opacity:1;"
+ offset="0"
+ id="stop4341" />
+ <stop
+ style="stop-color:#ff0000;stop-opacity:0;"
+ offset="1"
+ id="stop4343" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="304.07246 : 374.52182 : 1"
+ inkscape:vp_y="0 : 999.99998 : 0"
+ inkscape:vp_z="97.924826 : 490.48422 : 1"
+ inkscape:persp3d-origin="282.04724 : 396.50169 : 1"
+ id="perspective4191" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4339"
+ id="linearGradient4345"
+ x1="205.13866"
+ y1="791.02484"
+ x2="130.30968"
+ y2="856.89771"
+ gradientUnits="userSpaceOnUse" />
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3493">
+ <rect
+ style="fill:#666666;fill-opacity:1;stroke:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3495"
+ width="146.20735"
+ height="147.45538"
+ x="115.33373"
+ y="738.79926"
+ ry="6.3883986" />
+ </clipPath>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="2.8"
+ inkscape:cx="133.52724"
+ inkscape:cy="93.936777"
+ inkscape:document-units="px"
+ inkscape:current-layer="g4414"
+ showgrid="false"
+ fit-margin-left="5"
+ fit-margin-top="5"
+ fit-margin-right="5"
+ fit-margin-bottom="5"
+ units="px"
+ inkscape:window-width="1920"
+ inkscape:window-height="905"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:snap-global="false"
+ showguides="false" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Ebene 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(5.0000003,-847.36221)">
+ <g
+ id="g4433"
+ transform="translate(-60.902386,119.96554)">
+ <rect
+ ry="8.6648569"
+ y="732.39667"
+ x="60.902386"
+ height="200"
+ width="200"
+ id="rect4412"
+ style="fill:#666666;fill-opacity:1;stroke:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <g
+ id="g4414"
+ transform="matrix(1.3679202,0,0,1.3563425,-96.864952,-269.66815)"
+ clip-path="url(#clipPath3493)">
+ <g
+ id="g4364"
+ transform="matrix(1.2848586,0,0,1.2848586,-47.09026,-225.40973)">
+ <g
+ transform="matrix(0.70521296,0.07124105,0,0.70521296,22.935416,485.79994)"
+ id="g4326">
+ <rect
+ style="fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.35"
+ id="rect4277"
+ width="48.565189"
+ height="50.670372"
+ x="242.52609"
+ y="315.56894"
+ ry="12.130823"
+ transform="matrix(0.97464031,0.22377727,0,1,0,0)" />
+ <rect
+ style="fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.35"
+ id="rect4277-7"
+ width="48.565189"
+ height="50.670372"
+ x="262.80905"
+ y="292.12814"
+ ry="12.130823"
+ transform="matrix(0.97464031,0.22377727,0,1,0,0)" />
+ <rect
+ style="fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.35"
+ id="rect4294"
+ width="29.069714"
+ height="15.917919"
+ x="-73.198318"
+ y="437.03619"
+ ry="0"
+ transform="matrix(0.7329244,-0.68031009,0.66822927,0.7439554,0,0)" />
+ <rect
+ style="fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.35"
+ id="rect4294-3"
+ width="27.907652"
+ height="15.532421"
+ x="-54.329411"
+ y="487.7229"
+ ry="0"
+ transform="matrix(0.70821685,-0.70599496,0.63527567,0.77228545,0,0)" />
+ <rect
+ style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2.37930703;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect4277-78"
+ width="47.474747"
+ height="49.333805"
+ x="243.31599"
+ y="316.28986"
+ ry="11.810841"
+ transform="matrix(0.97494341,0.22245301,0,1,0,0)" />
+ </g>
+ <path
+ sodipodi:nodetypes="czcc"
+ inkscape:connector-curvature="0"
+ id="path4337"
+ d="m 84.852815,819.52204 c 0,0 111.599975,-40.64046 121.766705,-32.01632 10.16673,8.62414 -17.97354,123.43513 -17.97354,123.43513 z"
+ style="fill:url(#linearGradient4345);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ </g>
+ <g
+ id="g4377-2"
+ style="fill:none;stroke:#00ff00;stroke-width:2.54694843;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(1.6856173,0,0,1.6856173,-39.282189,-597.66653)">
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path4347-3"
+ d="m 106.31855,858.4553 15,0"
+ style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.54694843;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path4347-5-21"
+ d="m 113.81855,850.73652 0,15"
+ style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.54694843;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ <g
+ id="g4377-2-3"
+ style="fill:none;stroke:#00ff00;stroke-width:2.54694843;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(1.6856173,0,0,1.6856173,-15.550497,-631.83198)">
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path4347-3-6"
+ d="m 106.31855,858.4553 15,0"
+ style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.54694843;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path4347-5-21-7"
+ d="m 113.81855,850.73652 0,15"
+ style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.54694843;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ <g
+ id="g4377-2-5"
+ style="fill:none;stroke:#00ff00;stroke-width:2.54694843;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(1.6856173,0,0,1.6856173,8.7357605,-597.93633)">
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path4347-3-3"
+ d="m 106.31855,858.4553 15,0"
+ style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.54694843;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ id="path4347-5-21-5"
+ d="m 113.81855,850.73652 0,15"
+ style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:2.54694843;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/windows/build_tcc.bat b/windows/build_tcc.bat
new file mode 100644
index 0000000..753ba7c
--- /dev/null
+++ b/windows/build_tcc.bat
@@ -0,0 +1,14 @@
+@echo off
+
+set TCC=C:\tcc\tcc.exe
+echo Be sure to have TinyCC installed to %TCC% (or change the TCC parameter.)
+
+set SR=..\src\
+set RD=..\redist\
+set SOURCES=%SR%ootx_decoder.c %SR%poser_charlesslow.c %SR%poser_daveortho.c %SR%poser_dummy.c %SR%survive.c %SR%survive_cal.c %SR%survive_config.c %SR%survive_data.c %SR%survive_driverman.c %SR%survive_process.c %SR%survive_vive.c
+set REDIST=%RD%crc32.c %RD%linmath.c %RD%puff.c %RD%jsmn.c %RD%json_helpers.c %RD%symbol_enumerator.c
+set EXEC=..\calibrate.c %RD%WinDriver.c %RD%os_generic.c %RD%DrawFunctions.c
+set CFLAGS=-DNOZLIB -DTCC -DWINDOWS -DHIDAPI -DWIN32 -DRUNTIME_SYMNUM -O0 -g -rdynamic -I..\redist -I..\include\libsurvive -I..\src -I.
+set LDFLAGS=-lkernel32 -lgdi32 -luser32 -lsetupapi -ldbghelp
+@echo on
+%TCC% -v %CFLAGS% %SOURCES% %REDIST% %EXEC% %LDFLAGS% tcc_stubs.c hid.c -o calibrate.exe
diff --git a/windows/custom_msvcrt.def b/windows/custom_msvcrt.def
new file mode 100644
index 0000000..f40884e
--- /dev/null
+++ b/windows/custom_msvcrt.def
@@ -0,0 +1,1400 @@
+LIBRARY msvcrt.dll
+
+EXPORTS
+$I10_OUTPUT
+??0__non_rtti_object@@QAE@ABV0@@Z
+??0__non_rtti_object@@QAE@PBD@Z
+??0bad_cast@@AAE@PBQBD@Z
+??0bad_cast@@QAE@ABQBD@Z
+??0bad_cast@@QAE@ABV0@@Z
+??0bad_cast@@QAE@PBD@Z
+??0bad_typeid@@QAE@ABV0@@Z
+??0bad_typeid@@QAE@PBD@Z
+??0exception@@QAE@ABQBD@Z
+??0exception@@QAE@ABQBDH@Z
+??0exception@@QAE@ABV0@@Z
+??0exception@@QAE@XZ
+??1__non_rtti_object@@UAE@XZ
+??1bad_cast@@UAE@XZ
+??1bad_typeid@@UAE@XZ
+??1exception@@UAE@XZ
+??1type_info@@UAE@XZ
+??2@YAPAXI@Z
+??2@YAPAXIHPBDH@Z
+??3@YAXPAX@Z
+??4__non_rtti_object@@QAEAAV0@ABV0@@Z
+??4bad_cast@@QAEAAV0@ABV0@@Z
+??4bad_typeid@@QAEAAV0@ABV0@@Z
+??4exception@@QAEAAV0@ABV0@@Z
+??8type_info@@QBEHABV0@@Z
+??9type_info@@QBEHABV0@@Z
+??_7__non_rtti_object@@6B@
+??_7bad_cast@@6B@
+??_7bad_typeid@@6B@
+??_7exception@@6B@
+??_E__non_rtti_object@@UAEPAXI@Z
+??_Ebad_cast@@UAEPAXI@Z
+??_Ebad_typeid@@UAEPAXI@Z
+??_Eexception@@UAEPAXI@Z
+??_Fbad_cast@@QAEXXZ
+??_Fbad_typeid@@QAEXXZ
+??_G__non_rtti_object@@UAEPAXI@Z
+??_Gbad_cast@@UAEPAXI@Z
+??_Gbad_typeid@@UAEPAXI@Z
+??_Gexception@@UAEPAXI@Z
+??_U@YAPAXI@Z
+??_U@YAPAXIHPBDH@Z
+??_V@YAXPAX@Z
+?_query_new_handler@@YAP6AHI@ZXZ
+?_query_new_mode@@YAHXZ
+?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z
+?_set_new_mode@@YAHH@Z
+?_set_se_translator@@YAP6AXIPAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z
+?before@type_info@@QBEHABV1@@Z
+?name@type_info@@QBEPBDXZ
+?raw_name@type_info@@QBEPBDXZ
+?set_new_handler@@YAP6AXXZP6AXXZ@Z
+?set_terminate@@YAP6AXXZP6AXXZ@Z
+?set_unexpected@@YAP6AXXZP6AXXZ@Z
+?terminate@@YAXXZ
+?unexpected@@YAXXZ
+?what@exception@@UBEPBDXZ
+_CIacos
+_CIasin
+_CIatan
+_CIatan2
+_CIcos
+_CIcosh
+_CIexp
+_CIfmod
+_CIlog
+_CIlog10
+_CIpow
+_CIsin
+_CIsinh
+_CIsqrt
+_CItan
+_CItanh
+_CrtCheckMemory
+_CrtDbgBreak
+_CrtDbgReport
+_CrtDbgReportV
+_CrtDbgReportW
+_CrtDbgReportWV
+_CrtDoForAllClientObjects
+_CrtDumpMemoryLeaks
+_CrtIsMemoryBlock
+_CrtIsValidHeapPointer
+_CrtIsValidPointer
+_CrtMemCheckpoint
+_CrtMemDifference
+_CrtMemDumpAllObjectsSince
+_CrtMemDumpStatistics
+_CrtReportBlockType
+_CrtSetAllocHook
+_CrtSetBreakAlloc
+_CrtSetDbgBlockType
+_CrtSetDbgFlag
+_CrtSetDumpClient
+_CrtSetReportFile
+_CrtSetReportHook
+_CrtSetReportHook2
+_CrtSetReportMode
+_CxxThrowException
+_EH_prolog
+_Getdays
+_Getmonths
+_Gettnames
+_HUGE
+_Strftime
+_XcptFilter
+__CppXcptFilter
+__CxxCallUnwindDelDtor
+__CxxCallUnwindDtor
+__CxxCallUnwindVecDtor
+__CxxDetectRethrow
+__CxxExceptionFilter
+__CxxFrameHandler
+__CxxFrameHandler2
+__CxxFrameHandler3
+__CxxLongjmpUnwind
+__CxxQueryExceptionSize
+__CxxRegisterExceptionObject
+__CxxUnregisterExceptionObject
+__DestructExceptionObject
+__RTCastToVoid
+__RTDynamicCast
+__RTtypeid
+__STRINGTOLD
+___lc_codepage_func
+___lc_collate_cp_func
+___lc_handle_func
+___mb_cur_max_func
+___setlc_active_func
+___unguarded_readlc_active_add_func
+__argc
+__argv
+__badioinfo
+__crtCompareStringA
+__crtCompareStringW
+__crtGetLocaleInfoW
+__crtGetStringTypeW
+__crtLCMapStringA
+__crtLCMapStringW
+__daylight
+__dllonexit
+__doserrno
+__dstbias
+__fpecode
+__getmainargs
+__initenv
+__iob_func
+__isascii
+__iscsym
+__iscsymf
+__lc_codepage
+__lc_collate_cp
+__lc_handle
+__lconv_init
+__libm_sse2_acos
+__libm_sse2_acosf
+__libm_sse2_asin
+__libm_sse2_asinf
+__libm_sse2_atan
+__libm_sse2_atan2
+__libm_sse2_atanf
+__libm_sse2_cos
+__libm_sse2_cosf
+__libm_sse2_exp
+__libm_sse2_expf
+__libm_sse2_log
+__libm_sse2_log10
+__libm_sse2_log10f
+__libm_sse2_logf
+__libm_sse2_pow
+__libm_sse2_powf
+__libm_sse2_sin
+__libm_sse2_sinf
+__libm_sse2_tan
+__libm_sse2_tanf
+__mb_cur_max
+__p___argc
+__p___argv
+__p___initenv
+__p___mb_cur_max
+__p___wargv
+__p___winitenv
+__p__acmdln
+__p__amblksiz
+__p__commode
+__p__daylight
+__p__dstbias
+__p__environ
+__p__fileinfo
+__p__fmode
+__p__iob
+__p__mbcasemap
+__p__mbctype
+__p__osver
+__p__pctype
+__p__pgmptr
+__p__pwctype
+__p__timezone
+__p__tzname
+__p__wcmdln
+__p__wenviron
+__p__winmajor
+__p__winminor
+__p__winver
+__p__wpgmptr
+__pctype_func
+__pioinfo
+__pwctype_func
+__pxcptinfoptrs
+__set_app_type
+__setlc_active
+__setusermatherr
+__strncnt
+__threadhandle
+__threadid
+__toascii
+__unDName
+__unDNameEx
+__uncaught_exception
+__unguarded_readlc_active
+__wargv
+__wcserror
+__wcserror_s
+__wcsncnt
+__wgetmainargs
+__winitenv
+_abnormal_termination
+_abs64
+_access
+_access_s
+_acmdln
+_adj_fdiv_m16i
+_adj_fdiv_m32
+_adj_fdiv_m32i
+_adj_fdiv_m64
+_adj_fdiv_r
+_adj_fdivr_m16i
+_adj_fdivr_m32
+_adj_fdivr_m32i
+_adj_fdivr_m64
+_adj_fpatan
+_adj_fprem
+_adj_fprem1
+_adj_fptan
+_adjust_fdiv
+_aexit_rtn
+_aligned_free
+_aligned_free_dbg
+_aligned_malloc
+_aligned_malloc_dbg
+_aligned_offset_malloc
+_aligned_offset_malloc_dbg
+_aligned_offset_realloc
+_aligned_offset_realloc_dbg
+_aligned_realloc
+_aligned_realloc_dbg
+_amsg_exit
+_assert
+_atodbl
+_atodbl_l
+_atof_l
+_atoflt_l
+_atoi64
+_atoi64_l
+_atoi_l
+_atol_l
+_atoldbl
+_atoldbl_l
+_beep
+_beginthread
+_beginthreadex
+_c_exit
+_cabs
+_callnewh
+_calloc_dbg
+_cexit
+_cgets
+_cgets_s
+_cgetws
+_cgetws_s
+_chdir
+_chdrive
+_chgsign
+_chkesp
+_chmod
+_chsize
+_chsize_s
+_chvalidator
+_chvalidator_l
+_clearfp
+_close
+_commit
+_commode
+_control87
+_controlfp
+_controlfp_s
+_copysign
+_cprintf
+_cprintf_l
+_cprintf_p
+_cprintf_p_l
+_cprintf_s
+_cprintf_s_l
+_cputs
+_cputws
+_creat
+_crtAssertBusy
+_crtBreakAlloc
+_crtDbgFlag
+_cscanf
+_cscanf_l
+_cscanf_s
+_cscanf_s_l
+_ctime32
+_ctime32_s
+_ctime64
+_ctime64_s
+_ctype
+_cwait
+_cwprintf
+_cwprintf_l
+_cwprintf_p
+_cwprintf_p_l
+_cwprintf_s
+_cwprintf_s_l
+_cwscanf
+_cwscanf_l
+_cwscanf_s
+_cwscanf_s_l
+_daylight
+_difftime32
+_difftime64
+_dstbias
+_dup
+_dup2
+_ecvt
+_ecvt_s
+_endthread
+_endthreadex
+_environ
+_eof
+_errno
+_except_handler2
+_except_handler3
+_except_handler4_common
+_execl
+_execle
+_execlp
+_execlpe
+_execv
+_execve
+_execvp
+_execvpe
+_exit
+_expand
+_expand_dbg
+_fcloseall
+_fcvt
+_fcvt_s
+_fdopen
+_fgetchar
+_fgetwchar
+_filbuf
+_fileinfo
+_filelength
+_filelengthi64
+_fileno
+_findclose
+_findfirst
+_findfirst64
+_findfirsti64
+_findnext
+_findnext64
+_findnexti64
+_finite
+_flsbuf
+_flushall
+_fmode
+_fpclass
+_fpieee_flt
+_fpreset
+_fprintf_l
+_fprintf_p
+_fprintf_p_l
+_fprintf_s_l
+_fputchar
+_fputwchar
+_free_dbg
+_freea
+_freea_s
+_fscanf_l
+_fscanf_s_l
+_fseeki64
+_fsopen
+_fstat
+_fstat64
+_fstati64
+_ftime
+_ftime32
+_ftime32_s
+_ftime64
+_ftime64_s
+_ftol
+_ftol2
+_ftol2_sse
+_ftol2_sse_excpt
+_fullpath
+_fullpath_dbg
+_futime
+_futime32
+_futime64
+_fwprintf_l
+_fwprintf_p
+_fwprintf_p_l
+_fwprintf_s_l
+_fwscanf_l
+_fwscanf_s_l
+_gcvt
+_gcvt_s
+_get_doserrno
+_get_environ
+_get_errno
+_get_fileinfo
+_get_fmode
+_get_heap_handle
+_get_osfhandle
+_get_osplatform
+_get_osver
+_get_output_format
+_get_pgmptr
+_get_sbh_threshold
+_get_wenviron
+_get_winmajor
+_get_winminor
+_get_winver
+_get_wpgmptr
+_getch
+_getche
+_getcwd
+_getdcwd
+_getdiskfree
+_getdllprocaddr
+_getdrive
+_getdrives
+_getmaxstdio
+_getmbcp
+_getpid
+_getsystime
+_getw
+_getwch
+_getwche
+_getws
+_global_unwind2
+_gmtime32
+_gmtime32_s
+_gmtime64
+_gmtime64_s
+_heapadd
+_heapchk
+_heapmin
+_heapset
+_heapused
+_heapwalk
+_hypot
+_i64toa
+_i64toa_s
+_i64tow
+_i64tow_s
+_initterm
+_initterm_e
+_inp
+_inpd
+_inpw
+_invalid_parameter
+_iob
+_isalnum_l
+_isalpha_l
+_isatty
+_iscntrl_l
+_isctype
+_isctype_l
+_isdigit_l
+_isgraph_l
+_isleadbyte_l
+_islower_l
+_ismbbalnum
+_ismbbalnum_l
+_ismbbalpha
+_ismbbalpha_l
+_ismbbgraph
+_ismbbgraph_l
+_ismbbkalnum
+_ismbbkalnum_l
+_ismbbkana
+_ismbbkana_l
+_ismbbkprint
+_ismbbkprint_l
+_ismbbkpunct
+_ismbbkpunct_l
+_ismbblead
+_ismbblead_l
+_ismbbprint
+_ismbbprint_l
+_ismbbpunct
+_ismbbpunct_l
+_ismbbtrail
+_ismbbtrail_l
+_ismbcalnum
+_ismbcalnum_l
+_ismbcalpha
+_ismbcalpha_l
+_ismbcdigit
+_ismbcdigit_l
+_ismbcgraph
+_ismbcgraph_l
+_ismbchira
+_ismbchira_l
+_ismbckata
+_ismbckata_l
+_ismbcl0
+_ismbcl0_l
+_ismbcl1
+_ismbcl1_l
+_ismbcl2
+_ismbcl2_l
+_ismbclegal
+_ismbclegal_l
+_ismbclower
+_ismbclower_l
+_ismbcprint
+_ismbcprint_l
+_ismbcpunct
+_ismbcpunct_l
+_ismbcspace
+_ismbcspace_l
+_ismbcsymbol
+_ismbcsymbol_l
+_ismbcupper
+_ismbcupper_l
+_ismbslead
+_ismbslead_l
+_ismbstrail
+_ismbstrail_l
+_isnan
+_isprint_l
+_isspace_l
+_isupper_l
+_iswalnum_l
+_iswalpha_l
+_iswcntrl_l
+_iswctype_l
+_iswdigit_l
+_iswgraph_l
+_iswlower_l
+_iswprint_l
+_iswpunct_l
+_iswspace_l
+_iswupper_l
+_iswxdigit_l
+_isxdigit_l
+_itoa
+_itoa_s
+_itow
+_itow_s
+_j0
+_j1
+_jn
+_kbhit
+_lfind
+_lfind_s
+_loaddll
+_local_unwind2
+_local_unwind4
+_localtime32
+_localtime32_s
+_localtime64
+_localtime64_s
+_lock
+_locking
+_logb
+_longjmpex
+_lrotl
+_lrotr
+_lsearch
+_lsearch_s
+_lseek
+_lseeki64
+_ltoa
+_ltoa_s
+_ltow
+_ltow_s
+_makepath
+_makepath_s
+_malloc_dbg
+_mbbtombc
+_mbbtombc_l
+_mbbtype
+_mbcasemap
+_mbccpy
+_mbccpy_l
+_mbccpy_s
+_mbccpy_s_l
+_mbcjistojms
+_mbcjistojms_l
+_mbcjmstojis
+_mbcjmstojis_l
+_mbclen
+_mbclen_l
+_mbctohira
+_mbctohira_l
+_mbctokata
+_mbctokata_l
+_mbctolower
+_mbctolower_l
+_mbctombb
+_mbctombb_l
+_mbctoupper
+_mbctoupper_l
+_mbctype
+_mblen_l
+_mbsbtype
+_mbsbtype_l
+_mbscat
+_mbscat_s
+_mbscat_s_l
+_mbschr
+_mbschr_l
+_mbscmp
+_mbscmp_l
+_mbscoll
+_mbscoll_l
+_mbscpy
+_mbscpy_s
+_mbscpy_s_l
+_mbscspn
+_mbscspn_l
+_mbsdec
+_mbsdec_l
+_mbsdup
+_mbsicmp
+_mbsicmp_l
+_mbsicoll
+_mbsicoll_l
+_mbsinc
+_mbsinc_l
+_mbslen
+_mbslen_l
+_mbslwr
+_mbslwr_l
+_mbslwr_s
+_mbslwr_s_l
+_mbsnbcat
+_mbsnbcat_l
+_mbsnbcat_s
+_mbsnbcat_s_l
+_mbsnbcmp
+_mbsnbcmp_l
+_mbsnbcnt
+_mbsnbcnt_l
+_mbsnbcoll
+_mbsnbcoll_l
+_mbsnbcpy
+_mbsnbcpy_l
+_mbsnbcpy_s
+_mbsnbcpy_s_l
+_mbsnbicmp
+_mbsnbicmp_l
+_mbsnbicoll
+_mbsnbicoll_l
+_mbsnbset
+_mbsnbset_l
+_mbsnbset_s
+_mbsnbset_s_l
+_mbsncat
+_mbsncat_l
+_mbsncat_s
+_mbsncat_s_l
+_mbsnccnt
+_mbsnccnt_l
+_mbsncmp
+_mbsncmp_l
+_mbsncoll
+_mbsncoll_l
+_mbsncpy
+_mbsncpy_l
+_mbsncpy_s
+_mbsncpy_s_l
+_mbsnextc
+_mbsnextc_l
+_mbsnicmp
+_mbsnicmp_l
+_mbsnicoll
+_mbsnicoll_l
+_mbsninc
+_mbsninc_l
+_mbsnlen
+_mbsnlen_l
+_mbsnset
+_mbsnset_l
+_mbsnset_s
+_mbsnset_s_l
+_mbspbrk
+_mbspbrk_l
+_mbsrchr
+_mbsrchr_l
+_mbsrev
+_mbsrev_l
+_mbsset
+_mbsset_l
+_mbsset_s
+_mbsset_s_l
+_mbsspn
+_mbsspn_l
+_mbsspnp
+_mbsspnp_l
+_mbsstr
+_mbsstr_l
+_mbstok
+_mbstok_l
+_mbstok_s
+_mbstok_s_l
+_mbstowcs_l
+_mbstowcs_s_l
+_mbstrlen
+_mbstrlen_l
+_mbstrnlen
+_mbstrnlen_l
+_mbsupr
+_mbsupr_l
+_mbsupr_s
+_mbsupr_s_l
+_mbtowc_l
+_memccpy
+_memicmp
+_memicmp_l
+_mkdir
+_mkgmtime
+_mkgmtime32
+_mkgmtime64
+_mktemp
+_mktemp_s
+_mktime32
+_mktime64
+_msize
+_msize_debug
+_nextafter
+_onexit
+_open
+_open_osfhandle
+_osplatform
+_osver
+_outp
+_outpd
+_outpw
+_pclose
+_pctype
+_pgmptr
+_pipe
+_popen
+_printf_l
+_printf_p
+_printf_p_l
+_printf_s_l
+_purecall
+_putch
+_putenv
+_putenv_s
+_putw
+_putwch
+_putws
+_pwctype
+_read
+_realloc_dbg
+_resetstkoflw
+_rmdir
+_rmtmp
+_rotl
+_rotl64
+_rotr
+_rotr64
+_safe_fdiv
+_safe_fdivr
+_safe_fprem
+_safe_fprem1
+_scalb
+_scanf_l
+_scanf_s_l
+_scprintf
+_scprintf_l
+_scprintf_p_l
+_scwprintf
+_scwprintf_l
+_scwprintf_p_l
+_searchenv
+_searchenv_s
+_seh_longjmp_unwind
+_seh_longjmp_unwind4
+_set_SSE2_enable
+_set_controlfp
+_set_doserrno
+_set_errno
+_set_error_mode
+_set_fileinfo
+_set_fmode
+_set_output_format
+_set_sbh_threshold
+_seterrormode
+_setjmp
+_setjmp3
+_setmaxstdio
+_setmbcp
+_setmode
+_setsystime
+_sleep
+_snprintf
+_snprintf_c
+_snprintf_c_l
+_snprintf_l
+_snprintf_s
+_snprintf_s_l
+_snscanf
+_snscanf_l
+_snscanf_s
+_snscanf_s_l
+_snwprintf
+_snwprintf_l
+_snwprintf_s
+_snwprintf_s_l
+_snwscanf
+_snwscanf_l
+_snwscanf_s
+_snwscanf_s_l
+_sopen
+_sopen_s
+_spawnl
+_spawnle
+_spawnlp
+_spawnlpe
+_spawnv
+_spawnve
+_spawnvp
+_spawnvpe
+_splitpath
+_splitpath_s
+_sprintf_l
+_sprintf_p_l
+_sprintf_s_l
+_sscanf_l
+_sscanf_s_l
+_stat
+_stat64
+_stati64
+_statusfp
+_strcmpi
+_strcoll_l
+_strdate
+_strdate_s
+_strdup
+_strdup_dbg
+_strerror
+_strerror_s
+_stricmp
+_stricmp_l
+_stricoll
+_stricoll_l
+_strlwr
+_strlwr_l
+_strlwr_s
+_strlwr_s_l
+_strncoll
+_strncoll_l
+_strnicmp
+_strnicmp_l
+_strnicoll
+_strnicoll_l
+_strnset
+_strnset_s
+_strrev
+_strset
+_strset_s
+_strtime
+_strtime_s
+_strtod_l
+_strtoi64
+_strtoi64_l
+_strtol_l
+_strtoui64
+_strtoui64_l
+_strtoul_l
+_strupr
+_strupr_l
+_strupr_s
+_strupr_s_l
+_strxfrm_l
+_swab
+_swprintf
+_swprintf_c
+_swprintf_c_l
+_swprintf_p_l
+_swprintf_s_l
+_swscanf_l
+_swscanf_s_l
+_sys_errlist
+_sys_nerr
+_tell
+_telli64
+_tempnam
+_tempnam_dbg
+_time32
+_time64
+_timezone
+_tolower
+_tolower_l
+_toupper
+_toupper_l
+_towlower_l
+_towupper_l
+_tzname
+_tzset
+_ui64toa
+_ui64toa_s
+_ui64tow
+_ui64tow_s
+_ultoa
+_ultoa_s
+_ultow
+_ultow_s
+_umask
+_umask_s
+_ungetch
+_ungetwch
+_unlink
+_unloaddll
+_unlock
+_utime
+_utime32
+_utime64
+_vcprintf
+_vcprintf_l
+_vcprintf_p
+_vcprintf_p_l
+_vcprintf_s
+_vcprintf_s_l
+_vcwprintf
+_vcwprintf_l
+_vcwprintf_p
+_vcwprintf_p_l
+_vcwprintf_s
+_vcwprintf_s_l
+_vfprintf_l
+_vfprintf_p
+_vfprintf_p_l
+_vfprintf_s_l
+_vfwprintf_l
+_vfwprintf_p
+_vfwprintf_p_l
+_vfwprintf_s_l
+_vprintf_l
+_vprintf_p
+_vprintf_p_l
+_vprintf_s_l
+_vscprintf
+_vscprintf_l
+_vscprintf_p_l
+_vscwprintf
+_vscwprintf_l
+_vscwprintf_p_l
+_vsnprintf
+_vsnprintf_c
+_vsnprintf_c_l
+_vsnprintf_l
+_vsnprintf_s
+_vsnprintf_s_l
+_vsnwprintf
+_vsnwprintf_l
+_vsnwprintf_s
+_vsnwprintf_s_l
+_vsprintf_l
+_vsprintf_p
+_vsprintf_p_l
+_vsprintf_s_l
+_vswprintf
+_vswprintf_c
+_vswprintf_c_l
+_vswprintf_l
+_vswprintf_p_l
+_vswprintf_s_l
+_vwprintf_l
+_vwprintf_p
+_vwprintf_p_l
+_vwprintf_s_l
+_waccess
+_waccess_s
+_wasctime
+_wasctime_s
+_wassert
+_wchdir
+_wchmod
+_wcmdln
+_wcreat
+_wcscoll_l
+_wcsdup
+_wcsdup_dbg
+_wcserror
+_wcserror_s
+_wcsftime_l
+_wcsicmp
+_wcsicmp_l
+_wcsicoll
+_wcsicoll_l
+_wcslwr
+_wcslwr_l
+_wcslwr_s
+_wcslwr_s_l
+_wcsncoll
+_wcsncoll_l
+_wcsnicmp
+_wcsnicmp_l
+_wcsnicoll
+_wcsnicoll_l
+_wcsnset
+_wcsnset_s
+_wcsrev
+_wcsset
+_wcsset_s
+_wcstoi64
+_wcstoi64_l
+_wcstol_l
+_wcstombs_l
+_wcstombs_s_l
+_wcstoui64
+_wcstoui64_l
+_wcstoul_l
+_wcsupr
+_wcsupr_l
+_wcsupr_s
+_wcsupr_s_l
+_wcsxfrm_l
+_wctime
+_wctime32
+_wctime32_s
+_wctime64
+_wctime64_s
+_wctomb_l
+_wctomb_s_l
+_wctype
+_wenviron
+_wexecl
+_wexecle
+_wexeclp
+_wexeclpe
+_wexecv
+_wexecve
+_wexecvp
+_wexecvpe
+_wfdopen
+_wfindfirst
+_wfindfirst64
+_wfindfirsti64
+_wfindnext
+_wfindnext64
+_wfindnexti64
+_wfopen
+_wfopen_s
+_wfreopen
+_wfreopen_s
+_wfsopen
+_wfullpath
+_wfullpath_dbg
+_wgetcwd
+_wgetdcwd
+_wgetenv
+_wgetenv_s
+_winmajor
+_winminor
+_winput_s
+_winver
+_wmakepath
+_wmakepath_s
+_wmkdir
+_wmktemp
+_wmktemp_s
+_wopen
+_woutput_s
+_wperror
+_wpgmptr
+_wpopen
+_wprintf_l
+_wprintf_p
+_wprintf_p_l
+_wprintf_s_l
+_wputenv
+_wputenv_s
+_wremove
+_wrename
+_write
+_wrmdir
+_wscanf_l
+_wscanf_s_l
+_wsearchenv
+_wsearchenv_s
+_wsetlocale
+_wsopen
+_wsopen_s
+_wspawnl
+_wspawnle
+_wspawnlp
+_wspawnlpe
+_wspawnv
+_wspawnve
+_wspawnvp
+_wspawnvpe
+_wsplitpath
+_wsplitpath_s
+_wstat
+_wstat64
+_wstati64
+_wstrdate
+_wstrdate_s
+_wstrtime
+_wstrtime_s
+_wsystem
+_wtempnam
+_wtempnam_dbg
+_wtmpnam
+_wtmpnam_s
+_wtof
+_wtof_l
+_wtoi
+_wtoi64
+_wtoi64_l
+_wtoi_l
+_wtol
+_wtol_l
+_wunlink
+_wutime
+_wutime32
+_wutime64
+_y0
+_y1
+_yn
+abort
+abs
+acos
+asctime
+asctime_s
+asin
+atan
+atan2
+atexit
+atof
+atoi
+atol
+bsearch
+bsearch_s
+btowc
+calloc
+ceil
+clearerr
+clearerr_s
+clock
+cos
+cosh
+ctime
+difftime
+div
+exit
+exp
+fabs
+fclose
+feof
+ferror
+fflush
+fgetc
+fgetpos
+fgets
+fgetwc
+fgetws
+floor
+fmod
+fopen
+fopen_s
+fprintf
+fprintf_s
+fputc
+fputs
+fputwc
+fputws
+fread
+free
+freopen
+freopen_s
+frexp
+fscanf
+fscanf_s
+fseek
+fsetpos
+ftell
+fwprintf
+fwprintf_s
+fwrite
+fwscanf
+fwscanf_s
+getc
+getchar
+getenv
+getenv_s
+gets
+getwc
+getwchar
+gmtime
+is_wctype
+isalnum
+isalpha
+iscntrl
+isdigit
+isgraph
+isleadbyte
+islower
+isprint
+ispunct
+isspace
+isupper
+iswalnum
+iswalpha
+iswascii
+iswcntrl
+iswctype
+iswdigit
+iswgraph
+iswlower
+iswprint
+iswpunct
+iswspace
+iswupper
+iswxdigit
+isxdigit
+labs
+ldexp
+ldiv
+localeconv
+localtime
+log
+log10
+longjmp
+malloc
+mblen
+mbrlen
+mbrtowc
+mbsdup_dbg
+mbsrtowcs
+mbsrtowcs_s
+mbstowcs
+mbstowcs_s
+mbtowc
+memchr
+memcmp
+memcpy
+memcpy_s
+memmove
+memmove_s
+memset
+mktime
+modf
+perror
+pow
+printf
+printf_s
+putc
+putchar
+puts
+putwc
+putwchar
+qsort
+qsort_s
+raise
+rand
+rand_s
+realloc
+remove
+rename
+rewind
+scanf
+scanf_s
+setbuf
+setlocale
+setvbuf
+signal
+sin
+sinh
+sprintf
+sprintf_s
+sqrt
+srand
+sscanf
+sscanf_s
+strcat
+strcat_s
+strchr
+strcmp
+strcoll
+strcpy
+strcpy_s
+strcspn
+strerror
+strerror_s
+strftime
+strlen
+strncat
+strncat_s
+strncmp
+strncpy
+strncpy_s
+strnlen
+strpbrk
+strrchr
+strspn
+strstr
+strtod
+strtok
+strtok_s
+strtol
+strtoul
+strxfrm
+swprintf
+swprintf_s
+swscanf
+swscanf_s
+system
+tan
+tanh
+time
+tmpfile
+tmpfile_s
+tmpnam
+tmpnam_s
+tolower
+toupper
+towlower
+towupper
+ungetc
+ungetwc
+utime
+vfprintf
+vfprintf_s
+vfwprintf
+vfwprintf_s
+vprintf
+vprintf_s
+vsnprintf
+vsprintf
+vsprintf_s
+vswprintf
+vswprintf_s
+vwprintf
+vwprintf_s
+wcrtomb
+wcrtomb_s
+wcscat
+wcscat_s
+wcschr
+wcscmp
+wcscoll
+wcscpy
+wcscpy_s
+wcscspn
+wcsftime
+wcslen
+wcsncat
+wcsncat_s
+wcsncmp
+wcsncpy
+wcsncpy_s
+wcsnlen
+wcspbrk
+wcsrchr
+wcsrtombs
+wcsrtombs_s
+wcsspn
+wcsstr
+wcstod
+wcstok
+wcstok_s
+wcstol
+wcstombs
+wcstombs_s
+wcstoul
+wcsxfrm
+wctob
+wctomb
+wctomb_s
+wprintf
+wprintf_s
+wscanf
+wscanf_s
+vsprintf_s \ No newline at end of file
diff --git a/windows/hid.c b/windows/hid.c
new file mode 100644
index 0000000..8f80071
--- /dev/null
+++ b/windows/hid.c
@@ -0,0 +1,996 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 8/22/2009
+
+ Copyright 2009, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+ http://github.com/signal11/hidapi .
+********************************************************/
+
+
+/* Copy of LICENSE-orig.txt (compatible with MIT/x11 license)
+
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Copyright 2009, Alan Ott, Signal 11 Software.
+ All Rights Reserved.
+
+ This software may be used by anyone for any reason so
+ long as the copyright notice in the source files
+ remains intact.
+*/
+
+#include <windows.h>
+
+#ifndef _NTDEF_
+typedef LONG NTSTATUS;
+#endif
+
+#ifdef __MINGW32__
+#include <ntdef.h>
+#include <winbase.h>
+#endif
+
+#ifdef __CYGWIN__
+#include <ntdef.h>
+#define _wcsdup wcsdup
+#endif
+
+/* The maximum number of characters that can be passed into the
+ HidD_Get*String() functions without it failing.*/
+#define MAX_STRING_WCHARS 0xFFF
+
+/*#define HIDAPI_USE_DDK*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef TCC
+ typedef struct _SP_DEVINFO_DATA {
+ DWORD cbSize;
+ GUID ClassGuid;
+ DWORD DevInst;
+ ULONG_PTR Reserved;
+ } SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;
+ typedef struct _SP_DEVICE_INTERFACE_DATA {
+ DWORD cbSize;
+ GUID InterfaceClassGuid;
+ DWORD Flags;
+ ULONG_PTR Reserved;
+ } SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;
+ typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA {
+ DWORD cbSize;
+ CHAR DevicePath[ANYSIZE_ARRAY];
+ } SP_DEVICE_INTERFACE_DETAIL_DATA_A, *PSP_DEVICE_INTERFACE_DETAIL_DATA_A;
+ typedef PVOID HDEVINFO;
+
+ HDEVINFO WINAPI SetupDiGetClassDevsA(CONST GUID*,PCSTR,HWND,DWORD);
+
+ #define DIGCF_PRESENT 0x00000002
+ #define DIGCF_DEVICEINTERFACE 0x00000010
+ #define SPDRP_CLASS 7
+ #define SPDRP_DRIVER 9
+ #define FILE_DEVICE_KEYBOARD 0x0000000b
+ #define METHOD_OUT_DIRECT 2
+ enum
+ { FILE_ANY_ACCESS = 0x00000000UL,
+ FILE_SPECIAL_ACCESS = FILE_ANY_ACCESS,
+ FILE_READ_ACCESS = 0x00000001UL,
+ FILE_WRITE_ACCESS = 0x00000002UL
+ };
+ #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
+
+#else
+ #include <setupapi.h>
+ #include <winioctl.h>
+#endif
+ #ifdef HIDAPI_USE_DDK
+ #include <hidsdi.h>
+ #endif
+
+ /* Copied from inc/ddk/hidclass.h, part of the Windows DDK. */
+ #define HID_OUT_CTL_CODE(id) \
+ CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+ #define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100)
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#include "hidapi.h"
+
+#undef MIN
+#define MIN(x,y) ((x) < (y)? (x): (y))
+
+#ifdef _MSC_VER
+ /* Thanks Microsoft, but I know how to use strncpy(). */
+ #pragma warning(disable:4996)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef HIDAPI_USE_DDK
+ /* Since we're not building with the DDK, and the HID header
+ files aren't part of the SDK, we have to define all this
+ stuff here. In lookup_functions(), the function pointers
+ defined below are set. */
+ typedef struct _HIDD_ATTRIBUTES{
+ ULONG Size;
+ USHORT VendorID;
+ USHORT ProductID;
+ USHORT VersionNumber;
+ } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
+
+ typedef USHORT USAGE;
+ typedef struct _HIDP_CAPS {
+ USAGE Usage;
+ USAGE UsagePage;
+ USHORT InputReportByteLength;
+ USHORT OutputReportByteLength;
+ USHORT FeatureReportByteLength;
+ USHORT Reserved[17];
+ USHORT fields_not_used_by_hidapi[10];
+ } HIDP_CAPS, *PHIDP_CAPS;
+ typedef void* PHIDP_PREPARSED_DATA;
+ #define HIDP_STATUS_SUCCESS 0x110000
+
+ typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);
+ typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);
+ typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
+ typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
+ typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length);
+ typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length);
+ typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len);
+ typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);
+ typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);
+ typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps);
+ typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
+
+ static HidD_GetAttributes_ HidD_GetAttributes;
+ static HidD_GetSerialNumberString_ HidD_GetSerialNumberString;
+ static HidD_GetManufacturerString_ HidD_GetManufacturerString;
+ static HidD_GetProductString_ HidD_GetProductString;
+ static HidD_SetFeature_ HidD_SetFeature;
+ static HidD_GetFeature_ HidD_GetFeature;
+ static HidD_GetIndexedString_ HidD_GetIndexedString;
+ static HidD_GetPreparsedData_ HidD_GetPreparsedData;
+ static HidD_FreePreparsedData_ HidD_FreePreparsedData;
+ static HidP_GetCaps_ HidP_GetCaps;
+ static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers;
+
+ static HMODULE lib_handle = NULL;
+ static BOOLEAN initialized = FALSE;
+#endif /* HIDAPI_USE_DDK */
+
+struct hid_device_ {
+ HANDLE device_handle;
+ BOOL blocking;
+ USHORT output_report_length;
+ size_t input_report_length;
+ void *last_error_str;
+ DWORD last_error_num;
+ BOOL read_pending;
+ char *read_buf;
+ OVERLAPPED ol;
+};
+
+static hid_device *new_hid_device()
+{
+ hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
+ dev->device_handle = INVALID_HANDLE_VALUE;
+ dev->blocking = TRUE;
+ dev->output_report_length = 0;
+ dev->input_report_length = 0;
+ dev->last_error_str = NULL;
+ dev->last_error_num = 0;
+ dev->read_pending = FALSE;
+ dev->read_buf = NULL;
+ memset(&dev->ol, 0, sizeof(dev->ol));
+ dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
+
+ return dev;
+}
+
+static void free_hid_device(hid_device *dev)
+{
+ CloseHandle(dev->ol.hEvent);
+ CloseHandle(dev->device_handle);
+ LocalFree(dev->last_error_str);
+ free(dev->read_buf);
+ free(dev);
+}
+
+static void register_error(hid_device *device, const char *op)
+{
+ WCHAR *ptr, *msg;
+
+ FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPVOID)&msg, 0/*sz*/,
+ NULL);
+
+ /* Get rid of the CR and LF that FormatMessage() sticks at the
+ end of the message. Thanks Microsoft! */
+ ptr = msg;
+ while (*ptr) {
+ if (*ptr == '\r') {
+ *ptr = 0x0000;
+ break;
+ }
+ ptr++;
+ }
+
+ /* Store the message off in the Device entry so that
+ the hid_error() function can pick it up. */
+ LocalFree(device->last_error_str);
+ device->last_error_str = msg;
+}
+
+#ifndef HIDAPI_USE_DDK
+static int lookup_functions()
+{
+ lib_handle = LoadLibraryA("hid.dll");
+ if (lib_handle) {
+#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1;
+ RESOLVE(HidD_GetAttributes);
+ RESOLVE(HidD_GetSerialNumberString);
+ RESOLVE(HidD_GetManufacturerString);
+ RESOLVE(HidD_GetProductString);
+ RESOLVE(HidD_SetFeature);
+ RESOLVE(HidD_GetFeature);
+ RESOLVE(HidD_GetIndexedString);
+ RESOLVE(HidD_GetPreparsedData);
+ RESOLVE(HidD_FreePreparsedData);
+ RESOLVE(HidP_GetCaps);
+ RESOLVE(HidD_SetNumInputBuffers);
+#undef RESOLVE
+ }
+ else
+ return -1;
+
+ return 0;
+}
+#endif
+
+static HANDLE open_device(const char *path, BOOL enumerate)
+{
+ HANDLE handle;
+ DWORD desired_access = (enumerate)? 0: (GENERIC_WRITE | GENERIC_READ);
+ DWORD share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
+
+ handle = CreateFileA(path,
+ desired_access,
+ share_mode,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/
+ 0);
+
+ return handle;
+}
+
+int HID_API_EXPORT hid_init(void)
+{
+#ifndef HIDAPI_USE_DDK
+ if (!initialized) {
+ if (lookup_functions() < 0) {
+ hid_exit();
+ return -1;
+ }
+ initialized = TRUE;
+ }
+#endif
+ return 0;
+}
+
+int HID_API_EXPORT hid_exit(void)
+{
+#ifndef HIDAPI_USE_DDK
+ if (lib_handle)
+ FreeLibrary(lib_handle);
+ lib_handle = NULL;
+ initialized = FALSE;
+#endif
+ return 0;
+}
+
+struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
+{
+ BOOL res;
+ struct hid_device_info *root = NULL; /* return object */
+ struct hid_device_info *cur_dev = NULL;
+
+ /* Windows objects for interacting with the driver. */
+ GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} };
+ SP_DEVINFO_DATA devinfo_data;
+ SP_DEVICE_INTERFACE_DATA device_interface_data;
+ SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;
+ HDEVINFO device_info_set = INVALID_HANDLE_VALUE;
+ int device_index = 0;
+ int i;
+
+ if (hid_init() < 0)
+ return NULL;
+
+ /* Initialize the Windows objects. */
+ memset(&devinfo_data, 0x0, sizeof(devinfo_data));
+ devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
+ device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+
+ /* Get information for all the devices belonging to the HID class. */
+ device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+
+ /* Iterate over each device in the HID class, looking for the right one. */
+
+ for (;;) {
+ HANDLE write_handle = INVALID_HANDLE_VALUE;
+ DWORD required_size = 0;
+ HIDD_ATTRIBUTES attrib;
+
+ res = SetupDiEnumDeviceInterfaces(device_info_set,
+ NULL,
+ &InterfaceClassGuid,
+ device_index,
+ &device_interface_data);
+
+ if (!res) {
+ /* A return of FALSE from this function means that
+ there are no more devices. */
+ break;
+ }
+
+ /* Call with 0-sized detail size, and let the function
+ tell us how long the detail struct needs to be. The
+ size is put in &required_size. */
+ res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
+ &device_interface_data,
+ NULL,
+ 0,
+ &required_size,
+ NULL);
+
+ /* Allocate a long enough structure for device_interface_detail_data. */
+ device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size);
+ device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
+
+ /* Get the detailed data for this device. The detail data gives us
+ the device path for this device, which is then passed into
+ CreateFile() to get a handle to the device. */
+ res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
+ &device_interface_data,
+ device_interface_detail_data,
+ required_size,
+ NULL,
+ NULL);
+
+ if (!res) {
+ /* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");
+ Continue to the next device. */
+ goto cont;
+ }
+
+ /* Make sure this device is of Setup Class "HIDClass" and has a
+ driver bound to it. */
+ for (i = 0; ; i++) {
+ char driver_name[256];
+
+ /* Populate devinfo_data. This function will return failure
+ when there are no more interfaces left. */
+ res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
+ if (!res)
+ goto cont;
+
+ res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
+ SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
+ if (!res)
+ goto cont;
+
+ if (strcmp(driver_name, "HIDClass") == 0) {
+ /* See if there's a driver bound. */
+ res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
+ SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
+ if (res)
+ break;
+ }
+ }
+
+ //wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);
+
+ /* Open a handle to the device */
+ write_handle = open_device(device_interface_detail_data->DevicePath, TRUE);
+
+ /* Check validity of write_handle. */
+ if (write_handle == INVALID_HANDLE_VALUE) {
+ /* Unable to open the device. */
+ //register_error(dev, "CreateFile");
+ goto cont_close;
+ }
+
+
+ /* Get the Vendor ID and Product ID for this device. */
+ attrib.Size = sizeof(HIDD_ATTRIBUTES);
+ HidD_GetAttributes(write_handle, &attrib);
+ //wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);
+
+ /* Check the VID/PID to see if we should add this
+ device to the enumeration list. */
+ if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
+ (product_id == 0x0 || attrib.ProductID == product_id)) {
+
+ #define WSTR_LEN 512
+ const char *str;
+ struct hid_device_info *tmp;
+ PHIDP_PREPARSED_DATA pp_data = NULL;
+ HIDP_CAPS caps;
+ BOOLEAN res;
+ NTSTATUS nt_res;
+ wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */
+ size_t len;
+
+ /* VID/PID match. Create the record. */
+ tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
+ if (cur_dev) {
+ cur_dev->next = tmp;
+ }
+ else {
+ root = tmp;
+ }
+ cur_dev = tmp;
+
+ /* Get the Usage Page and Usage for this device. */
+ res = HidD_GetPreparsedData(write_handle, &pp_data);
+ if (res) {
+ nt_res = HidP_GetCaps(pp_data, &caps);
+ if (nt_res == HIDP_STATUS_SUCCESS) {
+ cur_dev->usage_page = caps.UsagePage;
+ cur_dev->usage = caps.Usage;
+ }
+
+ HidD_FreePreparsedData(pp_data);
+ }
+
+ /* Fill out the record */
+ cur_dev->next = NULL;
+ str = device_interface_detail_data->DevicePath;
+ if (str) {
+ len = strlen(str);
+ cur_dev->path = (char*) calloc(len+1, sizeof(char));
+ strncpy(cur_dev->path, str, len+1);
+ cur_dev->path[len] = '\0';
+ }
+ else
+ cur_dev->path = NULL;
+
+ /* Serial Number */
+ res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr));
+ wstr[WSTR_LEN-1] = 0x0000;
+ if (res) {
+ cur_dev->serial_number = _wcsdup(wstr);
+ }
+
+ /* Manufacturer String */
+ res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr));
+ wstr[WSTR_LEN-1] = 0x0000;
+ if (res) {
+ cur_dev->manufacturer_string = _wcsdup(wstr);
+ }
+
+ /* Product String */
+ res = HidD_GetProductString(write_handle, wstr, sizeof(wstr));
+ wstr[WSTR_LEN-1] = 0x0000;
+ if (res) {
+ cur_dev->product_string = _wcsdup(wstr);
+ }
+
+ /* VID/PID */
+ cur_dev->vendor_id = attrib.VendorID;
+ cur_dev->product_id = attrib.ProductID;
+
+ /* Release Number */
+ cur_dev->release_number = attrib.VersionNumber;
+
+ /* Interface Number. It can sometimes be parsed out of the path
+ on Windows if a device has multiple interfaces. See
+ http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or
+ search for "Hardware IDs for HID Devices" at MSDN. If it's not
+ in the path, it's set to -1. */
+ cur_dev->interface_number = -1;
+ if (cur_dev->path) {
+ char *interface_component = strstr(cur_dev->path, "&mi_");
+ if (interface_component) {
+ char *hex_str = interface_component + 4;
+ char *endptr = NULL;
+ cur_dev->interface_number = strtol(hex_str, &endptr, 16);
+ if (endptr == hex_str) {
+ /* The parsing failed. Set interface_number to -1. */
+ cur_dev->interface_number = -1;
+ }
+ }
+ }
+ }
+
+cont_close:
+ CloseHandle(write_handle);
+cont:
+ /* We no longer need the detail data. It can be freed */
+ free(device_interface_detail_data);
+
+ device_index++;
+
+ }
+
+ /* Close the device information handle. */
+ SetupDiDestroyDeviceInfoList(device_info_set);
+
+ return root;
+
+}
+
+void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
+{
+ /* TODO: Merge this with the Linux version. This function is platform-independent. */
+ struct hid_device_info *d = devs;
+ while (d) {
+ struct hid_device_info *next = d->next;
+ free(d->path);
+ free(d->serial_number);
+ free(d->manufacturer_string);
+ free(d->product_string);
+ free(d);
+ d = next;
+ }
+}
+
+
+HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
+{
+ /* TODO: Merge this functions with the Linux version. This function should be platform independent. */
+ struct hid_device_info *devs, *cur_dev;
+ const char *path_to_open = NULL;
+ hid_device *handle = NULL;
+
+ devs = hid_enumerate(vendor_id, product_id);
+ cur_dev = devs;
+ while (cur_dev) {
+ if (cur_dev->vendor_id == vendor_id &&
+ cur_dev->product_id == product_id) {
+ if (serial_number) {
+ if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
+ path_to_open = cur_dev->path;
+ break;
+ }
+ }
+ else {
+ path_to_open = cur_dev->path;
+ break;
+ }
+ }
+ cur_dev = cur_dev->next;
+ }
+
+ if (path_to_open) {
+ /* Open the device */
+ handle = hid_open_path(path_to_open);
+ }
+
+ hid_free_enumeration(devs);
+
+ return handle;
+}
+
+HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
+{
+ hid_device *dev;
+ HIDP_CAPS caps;
+ PHIDP_PREPARSED_DATA pp_data = NULL;
+ BOOLEAN res;
+ NTSTATUS nt_res;
+
+ if (hid_init() < 0) {
+ return NULL;
+ }
+
+ dev = new_hid_device();
+
+ /* Open a handle to the device */
+ dev->device_handle = open_device(path, FALSE);
+
+ /* Check validity of write_handle. */
+ if (dev->device_handle == INVALID_HANDLE_VALUE) {
+ /* Unable to open the device. */
+ register_error(dev, "CreateFile");
+ goto err;
+ }
+
+ /* Set the Input Report buffer size to 64 reports. */
+ res = HidD_SetNumInputBuffers(dev->device_handle, 64);
+ if (!res) {
+ register_error(dev, "HidD_SetNumInputBuffers");
+ goto err;
+ }
+
+ /* Get the Input Report length for the device. */
+ res = HidD_GetPreparsedData(dev->device_handle, &pp_data);
+ if (!res) {
+ register_error(dev, "HidD_GetPreparsedData");
+ goto err;
+ }
+ nt_res = HidP_GetCaps(pp_data, &caps);
+ if (nt_res != HIDP_STATUS_SUCCESS) {
+ register_error(dev, "HidP_GetCaps");
+ goto err_pp_data;
+ }
+ dev->output_report_length = caps.OutputReportByteLength;
+ dev->input_report_length = caps.InputReportByteLength;
+ HidD_FreePreparsedData(pp_data);
+
+ dev->read_buf = (char*) malloc(dev->input_report_length);
+
+ return dev;
+
+err_pp_data:
+ HidD_FreePreparsedData(pp_data);
+err:
+ free_hid_device(dev);
+ return NULL;
+}
+
+int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
+{
+ DWORD bytes_written;
+ BOOL res;
+
+ OVERLAPPED ol;
+ unsigned char *buf;
+ memset(&ol, 0, sizeof(ol));
+
+ /* Make sure the right number of bytes are passed to WriteFile. Windows
+ expects the number of bytes which are in the _longest_ report (plus
+ one for the report number) bytes even if the data is a report
+ which is shorter than that. Windows gives us this value in
+ caps.OutputReportByteLength. If a user passes in fewer bytes than this,
+ create a temporary buffer which is the proper size. */
+ if (length >= dev->output_report_length) {
+ /* The user passed the right number of bytes. Use the buffer as-is. */
+ buf = (unsigned char *) data;
+ } else {
+ /* Create a temporary buffer and copy the user's data
+ into it, padding the rest with zeros. */
+ buf = (unsigned char *) malloc(dev->output_report_length);
+ memcpy(buf, data, length);
+ memset(buf + length, 0, dev->output_report_length - length);
+ length = dev->output_report_length;
+ }
+
+ res = WriteFile(dev->device_handle, buf, length, NULL, &ol);
+
+ if (!res) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ /* WriteFile() failed. Return error. */
+ register_error(dev, "WriteFile");
+ bytes_written = -1;
+ goto end_of_function;
+ }
+ }
+
+ /* Wait here until the write is done. This makes
+ hid_write() synchronous. */
+ res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/);
+ if (!res) {
+ /* The Write operation failed. */
+ register_error(dev, "WriteFile");
+ bytes_written = -1;
+ goto end_of_function;
+ }
+
+end_of_function:
+ if (buf != data)
+ free(buf);
+
+ return bytes_written;
+}
+
+
+int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
+{
+ DWORD bytes_read = 0;
+ size_t copy_len = 0;
+ BOOL res;
+
+ /* Copy the handle for convenience. */
+ HANDLE ev = dev->ol.hEvent;
+
+ if (!dev->read_pending) {
+ /* Start an Overlapped I/O read. */
+ dev->read_pending = TRUE;
+ memset(dev->read_buf, 0, dev->input_report_length);
+ ResetEvent(ev);
+ res = ReadFile(dev->device_handle, dev->read_buf, dev->input_report_length, &bytes_read, &dev->ol);
+
+ if (!res) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ /* ReadFile() has failed.
+ Clean up and return error. */
+ CancelIo(dev->device_handle);
+ dev->read_pending = FALSE;
+ goto end_of_function;
+ }
+ }
+ }
+
+ if (milliseconds >= 0) {
+ /* See if there is any data yet. */
+ res = WaitForSingleObject(ev, milliseconds);
+ if (res != WAIT_OBJECT_0) {
+ /* There was no data this time. Return zero bytes available,
+ but leave the Overlapped I/O running. */
+ return 0;
+ }
+ }
+
+ /* Either WaitForSingleObject() told us that ReadFile has completed, or
+ we are in non-blocking mode. Get the number of bytes read. The actual
+ data has been copied to the data[] array which was passed to ReadFile(). */
+ res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
+
+ /* Set pending back to false, even if GetOverlappedResult() returned error. */
+ dev->read_pending = FALSE;
+
+ if (res && bytes_read > 0) {
+ if (dev->read_buf[0] == 0x0) {
+ /* If report numbers aren't being used, but Windows sticks a report
+ number (0x0) on the beginning of the report anyway. To make this
+ work like the other platforms, and to make it work more like the
+ HID spec, we'll skip over this byte. */
+ bytes_read--;
+ copy_len = length > bytes_read ? bytes_read : length;
+ memcpy(data, dev->read_buf+1, copy_len);
+ }
+ else {
+ /* Copy the whole buffer, report number and all. */
+ copy_len = length > bytes_read ? bytes_read : length;
+ memcpy(data, dev->read_buf, copy_len);
+ }
+ }
+
+end_of_function:
+ if (!res) {
+ register_error(dev, "GetOverlappedResult");
+ return -1;
+ }
+
+ return copy_len;
+}
+
+int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)
+{
+ return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
+}
+
+int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock)
+{
+ dev->blocking = !nonblock;
+ return 0; /* Success */
+}
+
+int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
+{
+ BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, length);
+ if (!res) {
+ register_error(dev, "HidD_SetFeature");
+ return -1;
+ }
+
+ return length;
+}
+
+
+int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
+{
+ BOOL res;
+#if 0
+ res = HidD_GetFeature(dev->device_handle, data, length);
+ if (!res) {
+ register_error(dev, "HidD_GetFeature");
+ return -1;
+ }
+ return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */
+#else
+ DWORD bytes_returned;
+
+ OVERLAPPED ol;
+ memset(&ol, 0, sizeof(ol));
+
+ res = DeviceIoControl(dev->device_handle,
+ IOCTL_HID_GET_FEATURE,
+ data, length,
+ data, length,
+ &bytes_returned, &ol);
+
+ if (!res) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ /* DeviceIoControl() failed. Return error. */
+ register_error(dev, "Send Feature Report DeviceIoControl");
+ return -1;
+ }
+ }
+
+ /* Wait here until the write is done. This makes
+ hid_get_feature_report() synchronous. */
+ res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
+ if (!res) {
+ /* The operation failed. */
+ register_error(dev, "Send Feature Report GetOverLappedResult");
+ return -1;
+ }
+
+ /* bytes_returned does not include the first byte which contains the
+ report ID. The data buffer actually contains one more byte than
+ bytes_returned. */
+ bytes_returned++;
+
+ return bytes_returned;
+#endif
+}
+
+void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
+{
+ if (!dev)
+ return;
+ CancelIo(dev->device_handle);
+ free_hid_device(dev);
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ BOOL res;
+
+ res = HidD_GetManufacturerString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
+ if (!res) {
+ register_error(dev, "HidD_GetManufacturerString");
+ return -1;
+ }
+
+ return 0;
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ BOOL res;
+
+ res = HidD_GetProductString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
+ if (!res) {
+ register_error(dev, "HidD_GetProductString");
+ return -1;
+ }
+
+ return 0;
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ BOOL res;
+
+ res = HidD_GetSerialNumberString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
+ if (!res) {
+ register_error(dev, "HidD_GetSerialNumberString");
+ return -1;
+ }
+
+ return 0;
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
+{
+ BOOL res;
+
+ res = HidD_GetIndexedString(dev->device_handle, string_index, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
+ if (!res) {
+ register_error(dev, "HidD_GetIndexedString");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
+{
+ return (wchar_t*)dev->last_error_str;
+}
+
+
+/*#define PICPGM*/
+/*#define S11*/
+#define P32
+#ifdef S11
+ unsigned short VendorID = 0xa0a0;
+ unsigned short ProductID = 0x0001;
+#endif
+
+#ifdef P32
+ unsigned short VendorID = 0x04d8;
+ unsigned short ProductID = 0x3f;
+#endif
+
+
+#ifdef PICPGM
+ unsigned short VendorID = 0x04d8;
+ unsigned short ProductID = 0x0033;
+#endif
+
+
+#if 0
+int __cdecl main(int argc, char* argv[])
+{
+ int res;
+ unsigned char buf[65];
+
+ UNREFERENCED_PARAMETER(argc);
+ UNREFERENCED_PARAMETER(argv);
+
+ /* Set up the command buffer. */
+ memset(buf,0x00,sizeof(buf));
+ buf[0] = 0;
+ buf[1] = 0x81;
+
+
+ /* Open the device. */
+ int handle = open(VendorID, ProductID, L"12345");
+ if (handle < 0)
+ printf("unable to open device\n");
+
+
+ /* Toggle LED (cmd 0x80) */
+ buf[1] = 0x80;
+ res = write(handle, buf, 65);
+ if (res < 0)
+ printf("Unable to write()\n");
+
+ /* Request state (cmd 0x81) */
+ buf[1] = 0x81;
+ write(handle, buf, 65);
+ if (res < 0)
+ printf("Unable to write() (2)\n");
+
+ /* Read requested state */
+ read(handle, buf, 65);
+ if (res < 0)
+ printf("Unable to read()\n");
+
+ /* Print out the returned buffer. */
+ for (int i = 0; i < 4; i++)
+ printf("buf[%d]: %d\n", i, buf[i]);
+
+ return 0;
+}
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
diff --git a/windows/hidapi.h b/windows/hidapi.h
new file mode 100644
index 0000000..43b8e7a
--- /dev/null
+++ b/windows/hidapi.h
@@ -0,0 +1,405 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 8/22/2009
+
+ Copyright 2009, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+ http://github.com/signal11/hidapi .
+********************************************************/
+
+/* Copy of LICENSE-orig.txt (compatible with MIT/x11 license)
+
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Copyright 2009, Alan Ott, Signal 11 Software.
+ All Rights Reserved.
+
+ This software may be used by anyone for any reason so
+ long as the copyright notice in the source files
+ remains intact.
+*/
+
+
+/** @file
+ * @defgroup API hidapi API
+ */
+
+#ifndef HIDAPI_H__
+#define HIDAPI_H__
+
+#include <wchar.h>
+
+#ifdef _WIN32
+ #define HID_API_EXPORT __declspec(dllexport)
+ #define HID_API_CALL
+#else
+ #define HID_API_EXPORT /**< API export macro */
+ #define HID_API_CALL /**< API call macro */
+#endif
+
+#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ struct hid_device_;
+ typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
+
+ /** hidapi info structure */
+ struct hid_device_info {
+ /** Platform-specific device path */
+ char *path;
+ /** Device Vendor ID */
+ unsigned short vendor_id;
+ /** Device Product ID */
+ unsigned short product_id;
+ /** Serial Number */
+ wchar_t *serial_number;
+ /** Device Release Number in binary-coded decimal,
+ also known as Device Version Number */
+ unsigned short release_number;
+ /** Manufacturer String */
+ wchar_t *manufacturer_string;
+ /** Product string */
+ wchar_t *product_string;
+ /** Usage Page for this Device/Interface
+ (Windows/Mac only). */
+ unsigned short usage_page;
+ /** Usage for this Device/Interface
+ (Windows/Mac only).*/
+ unsigned short usage;
+ /** The USB interface which this logical device
+ represents. Valid on both Linux implementations
+ in all cases, and valid on the Windows implementation
+ only if the device contains more than one interface. */
+ int interface_number;
+
+ /** Pointer to the next device */
+ struct hid_device_info *next;
+ };
+
+
+ /** @brief Initialize the HIDAPI library.
+
+ This function initializes the HIDAPI library. Calling it is not
+ strictly necessary, as it will be called automatically by
+ hid_enumerate() and any of the hid_open_*() functions if it is
+ needed. This function should be called at the beginning of
+ execution however, if there is a chance of HIDAPI handles
+ being opened by different threads simultaneously.
+
+ @ingroup API
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_init(void);
+
+ /** @brief Finalize the HIDAPI library.
+
+ This function frees all of the static data associated with
+ HIDAPI. It should be called at the end of execution to avoid
+ memory leaks.
+
+ @ingroup API
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_exit(void);
+
+ /** @brief Enumerate the HID Devices.
+
+ This function returns a linked list of all the HID devices
+ attached to the system which match vendor_id and product_id.
+ If @p vendor_id is set to 0 then any vendor matches.
+ If @p product_id is set to 0 then any product matches.
+ If @p vendor_id and @p product_id are both set to 0, then
+ all HID devices will be returned.
+
+ @ingroup API
+ @param vendor_id The Vendor ID (VID) of the types of device
+ to open.
+ @param product_id The Product ID (PID) of the types of
+ device to open.
+
+ @returns
+ This function returns a pointer to a linked list of type
+ struct #hid_device, containing information about the HID devices
+ attached to the system, or NULL in the case of failure. Free
+ this linked list by calling hid_free_enumeration().
+ */
+ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
+
+ /** @brief Free an enumeration Linked List
+
+ This function frees a linked list created by hid_enumerate().
+
+ @ingroup API
+ @param devs Pointer to a list of struct_device returned from
+ hid_enumerate().
+ */
+ void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
+
+ /** @brief Open a HID device using a Vendor ID (VID), Product ID
+ (PID) and optionally a serial number.
+
+ If @p serial_number is NULL, the first device with the
+ specified VID and PID is opened.
+
+ @ingroup API
+ @param vendor_id The Vendor ID (VID) of the device to open.
+ @param product_id The Product ID (PID) of the device to open.
+ @param serial_number The Serial Number of the device to open
+ (Optionally NULL).
+
+ @returns
+ This function returns a pointer to a #hid_device object on
+ success or NULL on failure.
+ */
+ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);
+
+ /** @brief Open a HID device by its path name.
+
+ The path name be determined by calling hid_enumerate(), or a
+ platform-specific path name can be used (eg: /dev/hidraw0 on
+ Linux).
+
+ @ingroup API
+ @param path The path name of the device to open
+
+ @returns
+ This function returns a pointer to a #hid_device object on
+ success or NULL on failure.
+ */
+ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);
+
+ /** @brief Write an Output report to a HID device.
+
+ The first byte of @p data[] must contain the Report ID. For
+ devices which only support a single report, this must be set
+ to 0x0. The remaining bytes contain the report data. Since
+ the Report ID is mandatory, calls to hid_write() will always
+ contain one more byte than the report contains. For example,
+ if a hid report is 16 bytes long, 17 bytes must be passed to
+ hid_write(), the Report ID (or 0x0, for devices with a
+ single report), followed by the report data (16 bytes). In
+ this example, the length passed in would be 17.
+
+ hid_write() will send the data on the first OUT endpoint, if
+ one exists. If it does not, it will send the data through
+ the Control Endpoint (Endpoint 0).
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data The data to send, including the report number as
+ the first byte.
+ @param length The length in bytes of the data to send.
+
+ @returns
+ This function returns the actual number of bytes written and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length);
+
+ /** @brief Read an Input report from a HID device with timeout.
+
+ Input reports are returned
+ to the host through the INTERRUPT IN endpoint. The first byte will
+ contain the Report number if the device uses numbered reports.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into.
+ @param length The number of bytes to read. For devices with
+ multiple reports, make sure to read an extra byte for
+ the report number.
+ @param milliseconds timeout in milliseconds or -1 for blocking wait.
+
+ @returns
+ This function returns the actual number of bytes read and
+ -1 on error. If no packet was available to be read within
+ the timeout period, this function returns 0.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
+
+ /** @brief Read an Input report from a HID device.
+
+ Input reports are returned
+ to the host through the INTERRUPT IN endpoint. The first byte will
+ contain the Report number if the device uses numbered reports.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into.
+ @param length The number of bytes to read. For devices with
+ multiple reports, make sure to read an extra byte for
+ the report number.
+
+ @returns
+ This function returns the actual number of bytes read and
+ -1 on error. If no packet was available to be read and
+ the handle is in non-blocking mode, this function returns 0.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length);
+
+ /** @brief Set the device handle to be non-blocking.
+
+ In non-blocking mode calls to hid_read() will return
+ immediately with a value of 0 if there is no data to be
+ read. In blocking mode, hid_read() will wait (block) until
+ there is data to read before returning.
+
+ Nonblocking can be turned on and off at any time.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param nonblock enable or not the nonblocking reads
+ - 1 to enable nonblocking
+ - 0 to disable nonblocking.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock);
+
+ /** @brief Send a Feature report to the device.
+
+ Feature reports are sent over the Control endpoint as a
+ Set_Report transfer. The first byte of @p data[] must
+ contain the Report ID. For devices which only support a
+ single report, this must be set to 0x0. The remaining bytes
+ contain the report data. Since the Report ID is mandatory,
+ calls to hid_send_feature_report() will always contain one
+ more byte than the report contains. For example, if a hid
+ report is 16 bytes long, 17 bytes must be passed to
+ hid_send_feature_report(): the Report ID (or 0x0, for
+ devices which do not use numbered reports), followed by the
+ report data (16 bytes). In this example, the length passed
+ in would be 17.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data The data to send, including the report number as
+ the first byte.
+ @param length The length in bytes of the data to send, including
+ the report number.
+
+ @returns
+ This function returns the actual number of bytes written and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length);
+
+ /** @brief Get a feature report from a HID device.
+
+ Set the first byte of @p data[] to the Report ID of the
+ report to be read. Make sure to allow space for this
+ extra byte in @p data[]. Upon return, the first byte will
+ still contain the Report ID, and the report data will
+ start in data[1].
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into, including
+ the Report ID. Set the first byte of @p data[] to the
+ Report ID of the report to be read, or set it to zero
+ if your device does not use numbered reports.
+ @param length The number of bytes to read, including an
+ extra byte for the report ID. The buffer can be longer
+ than the actual report.
+
+ @returns
+ This function returns the number of bytes read plus
+ one for the report ID (which is still in the first
+ byte), or -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length);
+
+ /** @brief Close a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ */
+ void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device);
+
+ /** @brief Get The Manufacturer String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get The Product String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get The Serial Number String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get a string from a HID device, based on its string index.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string_index The index of the string to get.
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen);
+
+ /** @brief Get a string describing the last error which occurred.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+
+ @returns
+ This function returns a string containing the last error
+ which occurred or NULL if none has occurred.
+ */
+ HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/windows/tcc_stubs.c b/windows/tcc_stubs.c
new file mode 100644
index 0000000..7872914
--- /dev/null
+++ b/windows/tcc_stubs.c
@@ -0,0 +1,59 @@
+
+#include <_mingw.h>
+
+#define REMATH(x) double __cdecl x( double f ); float x##f(float v) { return x(v); }
+
+REMATH( acos );
+REMATH( cos );
+REMATH( sin );
+REMATH( sqrt );
+REMATH( asin );
+
+double __cdecl strtod (const char* str, char** endptr);
+float strtof( const char* str, char** endptr)
+{
+ return strtod( str, endptr );
+}
+
+double __cdecl atan2(double a, double b);
+float atan2f(float a, float b)
+{
+ return atan2( a, b );
+}
+
+//From http://stackoverflow.com/questions/40159892/using-asprintf-on-windows
+int __cdecl vsprintf_s(
+ char *buffer,
+ size_t numberOfElements,
+ const char *format,
+ va_list argptr
+);
+
+int asprintf(char **strp, const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ int r = vasprintf(strp, fmt, ap);
+ va_end(ap);
+ return r;
+}
+
+int vasprintf(char **strp, const char *fmt, va_list ap) {
+ // _vscprintf tells you how big the buffer needs to be
+ int len = _vscprintf(fmt, ap);
+ if (len == -1) {
+ return -1;
+ }
+ size_t size = (size_t)len + 1;
+ char *str = (char*)malloc(size);
+ if (!str) {
+ return -1;
+ }
+ // _vsprintf_s is the "secure" version of vsprintf
+ int r = vsprintf_s(str, len + 1, fmt, ap);
+ if (r == -1) {
+ free(str);
+ return -1;
+ }
+ *strp = str;
+ return r;
+} \ No newline at end of file