3D VR Headset

Blitz3D Forums/Blitz3D Programming/3D VR Headset

MErren(Posted 2006) [#1]
Hi,
i try to use a Cybermaxx VR HMD with BB3D.
But my C++ is so Poor that i need your HELP.
I have the help of the LIB and the DLL

Here is what i have:

int AutoDetectComPort(void); Auto-Detects CyberMaxx on COM1 though COM4
returns COM0_ID if not found else COM1_ID though COM4_ID;
Parameters: NONE


BOOL OpenCom(const char*); Opens selected comm port and looks for CyberMaxx.
Auto-Detect calls OpenCom for each port.
If port opened successfully and CyberMaxx found,
function returns TRUE else comm port is closed
and return value is FALSE;
Parameters: COM1,...,COM4;

BOOL ReadFromPort(void); Reads data from port. Use Get_PYR(...) to
access the data. Returns TRUE if successful.

Void Get_PYR(int*, int*, int*); Get Pitch, Yaw, Roll
respectively +45<->-45, 359<->0, +45<->-45

char* Get_Version(void) Returns firmware version, else NULL if device not found

BOOL HardReset(void); HardReset sets CyberMaxx to power up default state

BOOL Set9600(void); Sets port and CyberMaxx to 9600 bps (default)
BOOL Set19200(void); Sets port and CyberMaxx to 19200 bps

BOOL SetHysteresisOn(void); Sets hysteresis on (prefered)
BOOL SetHysteresisOff(void); Sets hysteresis off (default)

BOOL CheckSumOn(void); Enables checksum on. If error occured, then last valid packet
will be used.
BOOL CheckSumOff(void); Enables checksum off (default)

char GetDataMode(void) Returns data transmission mode.
BINARY_MODE - faster (default)
ASCII_MODE - slower, used for debug
void SetDataMode(char) Sets data transmission mode. Same as above

char GetTransMode(void) Returns SAMPLE_UPON_REQUEST (default)
or CONTINOUS_SAMPLE_MODE
void SetTransMode(char) Sets transmission Mode. Same as above

void SetSamplingRate(int rate); Sets CyberMaxx packet sampling rate.
MINPACK <-> MAXPACK increments of 5
default rate is 40 pps
int GetSamplingRate(void) Returns current sampling rate that CyberMaxx is set to.

int GetCurrentSpeed(void) Returns current comm port speed. 9600 or 19200

int GetPortId(void) Returns port number to which CyberMaxx is attached.
COM1_ID,...,COM4_ID if found, else COM0_ID


Sample code:


// CyberMaxx 2.0 Win95 & NT SDK
// Copyright (©) 1996 VictorMaxx Technologies, Inc
// Author: Robert J. Gebis
// Date: 6 March 96 Ver 1.0

#include <conio.h>
#include <iostream.h>
#include "CyberMaxx.h"

// This has to be linked with MaxxCom.lib
// to use MaxxCom.dll

void main(void)
{
MaxxCom CyberHMD;
int Pitch, Yaw, Roll;

// Start by connecting to the CyberMaxx
if( !CyberHMD.AutoDetectComPort()) {

// ERROR CyberMaxx not Found
exit(-1);
}

// These are optional
CyberHMD.SetHysteresisOn(); // turn on the hysteresis filter to minimize jittering

char version[10];
strcpy( version, CyberHMD.Get_Version());

CyberHMD.SetSamplingRate(50); // Used only in continous mode
// defailt is 40 packets/s

// This is how you read
while( !_kbhit()) {

// if the CyberMaxx has supplied data, this returns true
if( CyberHMD.ReadFromPort()) {

CyberHMD.Get_PYR(&Pitch, &Yaw, &Roll); // Read data
cout << "Pitch -> " << Pitch << endl;
cout << "Yaw -> " << Yaw << endl;
cout << "Roll -> " << Roll << endl << endl;
}
else {
cout << "Error" << endl;
}

} // go until a key is hit

} // end of main

I need help to write my decls, here is my try:

.lib "maxxcom.dll"

AutoDetectComPort()
Get_PYR(pit%,yaw%,roll%)
OpenCom$()
ReadFromPort$()
Get_Version$()
HardReset$()
Set9600$()
Set19200$()
SetHysteresisOn$()
SetHysteresisOff$()
CheckSumOn$()
CheckSumOff$()
GetDataMode$()
SetDataMode($)
GetTransMode%()
SetTransMode($)
SetSamplingRate(%)
GetSamplingRate()
GetCurrentSpeed()
GetPortId()

Please Help me.


Greet's
MErren


jfk EO-11110(Posted 2006) [#2]
one thing: it seems to me:
void Get_PYR(int*, int*, int*);

wants some pointers to write the results to. So you need to use 3 blitz bank handles, each bank of 4 bytes size. Once executed the banks should contains pitch yaw and roll.

so in the decls you also need to use the pointer sign:Get_PYR%(pit*,yaw*,roll*)

Additionaly:
SetTransMode($)
SetSamplingRate(%)

AFAIK you need to use some kind of variable names here, at least:
SetTransMode(a$)
SetSamplingRate(b%)

And:
you need to define what type of return value will be used, so when it's gonna return a string (char) then you need to declare it as:
GetTransMode$()
the same for GetDataMode etc.


MErren(Posted 2006) [#3]
WOW , thank you very much.
I ll try my be a long night!!
I show results!!!


IPete2(Posted 2006) [#4]
Don't you just love the people on this fourm? Nice one JFK

IPete2.


MErren(Posted 2006) [#5]
No, sorry i am to stupid.
it won't return anything.
I can't read out PYR cause i don't know how to.

That's to high for me BB and C++


Dr. Wildrick(Posted 2006) [#6]
Hi
I think I can help you.
Your VR system requires a lot more than the detection routines and when turned on - will display in mono (2D) same image in both eyes. What you will need toi do is create a quad buffer system and use the system pointer to pointers to the sepretly rendered views in blitz 3D,
In this way, and only this way will you get true 3D.
Good luck.
Dr, Wildrick
Creator of the TruDimension 3D shutter glasses, 3D monitor and VR Headset add-on for Blitz 3D, Intel C++, Java and Add-on Bryce.


Dr. Wildrick(Posted 2006) [#7]
Oh, One final worrd.
You may wish to consider how much time you put into the developmet of the srivers as the image quality is BAD with a capital B - worse - its fiels sequential - meaning that you havlve the already very bad resolution rigt from the gate - if your intrested in a "Hey neat!" sort of thing - go for it - If toyr trying to develop a game - any text will be un=readable and forget someting like a HUD, We suppored them becase of popular request - but thety arebt even made any more as far as I know.
Let me know how your quest turns out. Best of luck to you.
Regards
Dr. WIldrick


MErren(Posted 2006) [#8]
You are Right, Dr. Wildrick.
But the Way is the Target. I want to learn more about Decls and DLL and my Projekt is to make my 3d Architekturprojekts viewable and get a better Feeling for the Dimentions.
The Way is the Target.
Do you know how to translate the C++ Part into BB? And do you have a Demo of the Interlace DLL u use in your 3dVU?


jfk EO-11110(Posted 2006) [#9]

it won't return anything.
I can't read out PYR cause i don't know how to.


Of course you first need to execute the commands to initialise the device. Then the PYR should work like this (assuming you have declared it in the decls)

my_pitch=createbank(4)
my_yaw=createbank(4)
my_roll=createbank(4)

Get_PYR(my_pitch, my_yaw, my_roll)
print peekint(my_pitch,0)
print peekint(my_yaw,0)
print peekint(my_roll,0)

as for the C++ code, it looks like everything is pretty simple to convert to blitz:


my_pitch=createbank(4)
my_yaw=createbank(4)
my_roll=createbank(4)


;// Start by connecting to the CyberMaxx
if AutoDetectComPort()=0
 ;// ERROR CyberMaxx not Found
 runtimeerror "ERROR CyberMaxx not Found"
endif

;// These are optional
;CyberHMD.SetHysteresisOn(); // turn on the hysteresis filter to minimize jittering (try this later)

my_version_adr=Get_Version%() ; returns a pointer to a string

SetSamplingRate(50); // Used only in continous mode
;// default is 40 packets/s

;// This is how you read
while keyhit(1)=0
 ;// if the CyberMaxx has supplied data, this returns true
 if  ReadFromPort()<>0
  Get_PYR(my_pitch, my_yaw, my_roll)
  print peekint(my_pitch,0)
  print peekint(my_yaw,0)
  print peekint(my_roll,0)
 else
  print "Error"
 endif
wend

Of course I doubt it will work right away, but probably it gives you the direction.

Again, make sure your decls are using the right function name return types, I see you have a lot of string return types, doublecheck if everything is right

void dothis() means it won't return anything
char dothis() means it will return a string. declare: dothis$()
char* dothis() means it will return a (32bit int) pointer to a string, use dothis%() (see below how to use a pointer)
int dothis() means it will return an int, use dothis%()
BOOL dothis() means it will return true or false, I think you can use an int here.

The function Get_Version is a bit special, it will return an adress (=Pointer) of a 10 Bytes string. You need to use RTLMemoryMove2 to copy the 10 bytes to a blitz bank. See code archives, userlibs, Avifil32 Frame grabber example on how to declare and use RTLMemoryMove.


jfk EO-11110(Posted 2006) [#10]
while I'm at it:
in a "kernel32.decls" the following lines are required:
.lib "kernel32.dll"
RtlMoveMemory2%(Destination*,Source,Length) : "RtlMoveMemory"

In the app you will have to make a 10 bytes bank ready to retrieve data from the returned adress:
my_buffer=createbank(10)

In blitz you would then:
adr=Get_Version()
rtlMoveMemory2(my_buffer,adr,10)
version$=""
for i=0 to 9
 version$=version$+chr$(peekbyte(my_buffer,i))
next
Print version$



MErren(Posted 2006) [#11]
Wow,
hey JFK EO-11110 you must come form the c++ Planet. Thank you so far.
But i think i must recompile the DLL cause the BB-Mainprogram say's "Function in Lib not found.". then i have downloded a Tool to check DLL's and the Function's are there. The DLLs are in the correct Folder, its a Cross to wear.
But I will do. Thank's to JFK.. again.


jfk EO-11110(Posted 2006) [#12]
I think the functions of the dll must be declared for shared use in the dll.


Panno(Posted 2006) [#13]
JFK comes from MARS !


jfk EO-11110(Posted 2006) [#14]
yeah, just escaped from area 51, btw.


MErren(Posted 2006) [#15]
OK OK,
i must call again.
I've downloaded "PE Explorer" and try to declare my dll as an
"shared" one. but noting the Gr#*%$%& Blitzbasic says " User lib function not found" and i have no Idea of how to handle.
Greet M.Erren


jfk EO-11110(Posted 2006) [#16]
It's many years ago since I stopped using C++, so my advice is far from competence.

In Purebasic one needs to declare a procedure in a special way to allow other apps to access it in a dll, there you have to say

ProcedureDLL() or ProcedureCDLL(), compared to the ordinary Procedure(), the function declaration. So maybe the functions have to be declared in a special way too. Sorry, I have no better advice. at least the Windows Api DLLs (kernel32.dll, user32.dll etc) can be accessed by blitz.

Please post your userlib and your blitz sourcecode.


MErren(Posted 2006) [#17]
At First I think its clever to give the Link to the
DLL
http://www.geocities.com/mellott124/CyberDrivers.htm

Here the User lib dir

09.03.2006 22:02 <DIR> ..
25.07.2002 21:36 1.069.056 3d2.exe
20.07.2003 04:45 1.666 blitz_extend.decls
20.07.2003 13:53 15.360 blitz_extend.dll
20.07.2003 13:53 4.741 blitz_extend.dpr
24.02.2003 07:42 564 dlportio.decls
27.09.1996 10:29 34.816 DLPORTIO.DLL
10.01.1999 11:00 3.584 DLPORTIO.SYS
13.10.2004 06:06 54 INPOUT.decl
03.12.1996 14:01 27.648 INPOUT32.DLL
13.10.2004 12:23 54 K8055d.decl
27.04.2004 21:35 46.592 K8055D.dll
13.10.2004 06:35 1.047 kernel32.dec
09.03.2006 23:09 848 kernel32.decls
09.11.2002 17:10 24.576 pbca3d2.dll
22.02.2005 06:58 26.998 User32.decls
11.02.2003 02:11 4.425 UserLibs.txt
09.03.2006 22:56 63 InpOut32.decls
28.03.1996 14:43 9.216 MaxxCom.dll
28.03.1996 14:43 32.658 MaxxCom.lib
26.04.1996 15:01 3.535 MaxxCom.txt
28.03.1996 11:30 4.174 MaxxCom.h
10.03.2006 08:46 364 MaxxCom.dec.txt
10.03.2006 20:44 4.903 newton.decls
10.03.2005 13:16 405.504 Newton.dll
29.11.2005 21:40 65.024 PEview.exe
19.03.2006 17:45 158 trak.decls
11.03.2006 22:46 2.352 trak.H
11.03.2006 20:08 141 MaxxCom.decls-
19.10.1995 15:26 32.256 TRAK-org.DLL
19.03.2006 17:44 32.256 TRAK.DLL
21.03.2006 16:35 0 dir.txt
39 Datei(en) 4.490.747 Bytes
And one BB sourcecode.

my_pitch=CreateBank(4)
my_yaw=CreateBank(4)
my_roll=CreateBank(4)

;// Start by connecting to the CyberMaxx
If AutoDetectComPort()=0

;// ERROR CyberMaxx not Found
RuntimeError "ERROR CyberMaxx not Found"
EndIf

;OpenCom(com1)
;// These are optional
;CyberHMD.SetHysteresisOn(); // turn on the hysteresis filter to minimize jittering (try this later)

;my_version_adr=Get_Version() ; returns a pointer to a string

SetSamplingRate(50); // Used only in continous mode
;// default is 40 packets/s

;// This is how you read
While KeyHit(1)=0
;// if the CyberMaxx has supplied data, this returns true
If ReadFromPort()<>0
Get_PYR(my_pitch, my_yaw, my_roll)
Print PeekInt(my_pitch,0)
Print PeekInt(my_yaw,0)
Print PeekInt(my_roll,0)
Else
Print "Error"
EndIf
Wend

And i found no way to use it.

GreetS
Micha


jfk EO-11110(Posted 2006) [#18]
I assume the DLL in question is "MaxxCom.dll" ?
MaxxCom.lib and MaxxCom.h are not required there, they are sourcecode (as far as I see). Now tell me why is the decls named: "MaxxCom.decls-" ? what's that minus at the end of the name? If it's really named like this then it's no surprise the functions are not found.

Please post the content of MaxxCom.decls. Could you upload the MaxxCom.dll somewhere, So I don't have to download the entire SDK thingy.

However, for debugging purposes first try to make the very first command work:

print AutoDetectComPort()
print "success"
waitkey()
end

if this is once working, you'll know the dll can be accessed.


MErren(Posted 2006) [#19]
Hi,
it was my false with the "MaxxCom.decls-" cause the maxxcom.dll contains then same functions like trak.dll so i rename the Maxxcom.decls.
I tryed the same like your little testprogi, but it's always the same error message.
The trak.dll is smaller and contains nearly the same functions. under www.erren3d.de/dll/trak.dll or www.erren3d.de/dll/maxxcom.dll you can download the DLLs. I hope i can help you, to help me.
It's very cool that you immolate your time and know how.

Greet's
Micha


jfk EO-11110(Posted 2006) [#20]
I tried it with the maxxcom dll, but it didn't work. As I said, I don't know much about C++, but I think it has something to do with the way the example makes use of object oriented parenting. As far as I see in cybermaxx.h a custom structure is declared, and an instance named CyberHMD is then created and used as the parent object of any further command calls. Maybe this structure is required, I'm not sure. A little help of one of our C++ gurus may b helpful here (hey!).

But somehow I also think there must be a way to use it without the object structure. However, could you post the content of cybermaxx.h ?


MErren(Posted 2006) [#21]
I don't have any cybermaxx.h

here are the *.h that i have

// MaxxCom.h -- header definitions for CyberMaxx Tracker
// Copyright (C) 1995 VictorMaxx Technologies, Inc.
// Author: Robert J. Gebis
// Date: 2 Oct 95 Ver 1.0
// Date: 19 Jan 96 1.0.1
// Date: 23 Jan 96 1.0.2
// Date: 24 Jan 96 1.0.4

#ifndef __MAXXCOM_H__
#define __MAXXCOM_H__

#define ABSOLUTE_MODE "C"
#define RAW_DATA_MODE "B"
#define ASCII_MODE "E"
#define BINARY_MODE "F"
#define SAMPLE_UPON_REQUEST "G"
#define CONTINOUS_SAMPLE_MODE "H"
#define TRANSITION_9600_19200 "K"
#define TRANSITION_19200_9600 "L"
#define CHECKSUM_ON "M"
#define CHECKSUM_OFF "N"
#define AVERAGE_FILTER_ON "T"
#define AVERAGE_FILTER_OFF "W"
#define HYSTERESIS_FILTER_ON "P"
#define HYSTERESIS_FILTER_OFF "O"
#define HARD_RESET "R"
#define REQUEST_HANDSHAKE "X"
#define REQUEST_VERSION_NUM "V"
#define SEND_CURRENT_COORDINATE "S"
#define SEND_CURRENT_SENSOR_DATA "S"

#define MAXPACK 75 // higher sampling mode
#define MINPACK 5 // lower sampling mode
#define DEFSAMPLE "40" // starting sampling speed

#define COM0_ID 0
#define COM1_ID 1
#define COM2_ID 2
#define COM3_ID 3
#define COM4_ID 4

// Number To Read IN Check Sum Mode
#define N2R_INCSM_ON 7
#define N2R_INCSM_OFF 6

const char COM1[5] = "COM1";
const char COM2[5] = "COM2";
const char COM3[5] = "COM3";
const char COM4[5] = "COM4";

#define DllExport __declspec( dllexport )

class DllExport MaxxCom {

public:
MaxxCom();
~MaxxCom();
int AutoDetectComPort(void);
BOOL OpenCom(const char*);
BOOL checkForCyberMaxx(void);
BOOL Set9600(void);
BOOL Set19200(void);
BOOL SetHysteresisOn(void);
BOOL SetHysteresisOff(void);
BOOL HardReset(void);
BOOL CheckSumOff(void);
BOOL CheckSumOn(void);
BOOL ReadFromPort(void);
char* Get_Version(void); // if not NULL then returns pointer to version
void Get_PYR(int*, int*, int*); // Get Pitch,Yaw,Roll
inline char GetTransMode(void){ return m_TransMode;}
inline void SetTransMode(char tp){ m_TransMode = tp;}
inline char GetDataMode(void){ return m_dataType;}
inline void SetDataMode(char tp){ m_dataType = tp;}
void CloseCom(void);
void SetSamplingRate(int rate); // MINPACK <-> MAXPACK increments of 5
inline int GetSamplingRate(void){return m_SamplingRate;}
inline int GetCurrentSpeed(void){return m_iPortSpeed;}
inline int GetPortId(void){return m_port_ID;}

// For internal use only
BOOL GetDCB(void);
BOOL DoCheckSum(void);
BOOL SendToPort(char*);
inline unsigned char* GetDataBuffer(void){return m_inBuffer;}
inline HANDLE GetTempComHandle(void){return m_hConTemp;}
inline BOOL CheckIfBusy(void){ return m_bPortInUse;}
inline BOOL GetCheckStatus(void){ return m_bChecksum;}
inline void SetPortId(int id){m_port_ID = id;}
inline void SetTempComHandle( void){m_hConTemp = m_hCom;}
inline void SetNewComHandle( void){m_hCom = m_hConTemp;}
inline void SetSpeedFlag(int speed){ m_iPortSpeed = speed;}
inline int GetBytesRead(void){return m_numOfBytesRead;}
inline HANDLE GetComHandle(void){return m_hCom;}
BOOL CloseCom(const HANDLE);
void errMsgBox(const char*);
void ResetFIFO(void);

private:
int m_port_ID, // COM1_ID, COM2_ID, .....
m_SamplingRate, // default 40 packet/s
m_iCheckSum, // contains actual checksum data
m_iPortSpeed, // 9600 | 19200, 9600 default
m_pitch, m_yaw, m_roll; // -45<->+45 , 0<->359, -45<->+45
char m_dataType; // used to flag binary or ascii mode (BINARY_MODE,ASCII_MODE)
char m_TransMode; // used to flag Transfer type (CONTINOUS_SAMPLE_MODE, SAMPLE_UPON_REQUEST)
char m_version[30]; // HMD version number
unsigned char m_inBuffer[30]; // Data read from HMD
BOOL m_bPortInUse, // True if Port is used
m_bChecksum; // True if chack sum enabled
DCB m_dcb;
HANDLE m_hCom, m_hConTemp;
DWORD m_numOfBytesRead; // number of bytes read from HMD

};

#endif // nothing else after this line



-----AND the


// CyberTrak.h : main header file for the CYBERTRAK application
//
#include "MaxxCom.h"

#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif

#include "resource.h" // main symbols

/////////////////////////////////////////////////////////////////////////////
// CCyberTrakApp:
// See CyberTrak.cpp for the implementation of this class
//

class CCyberTrakApp : public CWinApp
{
private:
MaxxCom maxxcom;
public:
CCyberTrakApp();

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CCyberTrakApp)
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
//}}AFX_VIRTUAL

// Implementation

//{{AFX_MSG(CCyberTrakApp)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};


/////////////////////////////////////////////////////////////////////////////

But there is no part to declare.


jfk EO-11110(Posted 2006) [#22]
I'd really like to help you here but it seems I don't really understand C++ (shame on me). All the functions are declared within a class, the MaxxCom Class. They are declared as public, which is good. But I don't know how to create an instance of MaxxCom() to be able to use the commands in blitz, and if this is required at all.

#define DllExport __declspec( dllexport )

class DllExport MaxxCom {

public:
MaxxCom();
~MaxxCom();
int AutoDetectComPort(void);
...
I also still don't see what MaxxCom() actually is, all I see is it's declared. It's not looking like a function declaration since there is not return type definition (even no void). I also wonder what's that ~ in "~MaxxCom();"

Sorry, cannot help you here. Somebody who's more familar with C++ is required. Maybe you need to ask in an other thread, eg. in "userlibs".


jfk EO-11110(Posted 2006) [#23]
Ok, of course it is highly recommended to use a userlib instead of the old CallDLL command, but could you test this:
b=CreateBank(1000)
c=CreateBank(1000)
CallDLL("maxxcom.dll","AutoDetectComPort",b,c)
Print PeekInt(c,0)

(save it as test_calldll.bb, maxxcom.dll must be in the same directory). I was able to run it without an error, whatever that means. Of course it returned zero because I ain't got the device. If it returns something other than zero on your machine, then there may be hope :)


MErren(Posted 2006) [#24]
Hi JFK,
i ve tested it, but there is allways a 0 returned.
then i have changed the Dll to trak.dll and the same.
i have made some tests but that calldll won't return anything.


MErren(Posted 2006) [#25]
OK, i cancel the way over DLL. It's to hard to get data from a extern DLL. Special thanx to JFK
The next Way is ro handel it over RS232, here is a system on start and i try to use it. I found in the Net the definition of the pack's and try now to read them out.
Just for Fun here ist the definition:

The CyberMaxx tracker interface, and a proposed extension

The CyberMaxx runs at 9600, 8 bit, no parity, 1 stop.

To reset the unit, send it an ascii 'R'; it should respond with a copyright
string. By default the tracker sends data in ascii, so send it an 'F' to go
into binary mode. By default it sends data continuously; if you want to poll
it, send it a 'G', then send an 'S' whenever you want to request a packet.

In binary, the packets consist of 8 bytes. The first two are 0xFF (to mark
the start of the packet). These are followed by 3 16-bit words (sent
high-byte first) giving the yaw, pitch and roll. The top bit of each
16-bit word is zero, so they're really 15-bit words; the fact that the
top bit is zero means that you don't have to worry about two consecutive
0xFF's occurring in the data and looking like the start of a new packet.

The yaw is 0-360 degrees (i.e. 0 is zero, and 0x7FFF is 359.959 degrees).
The pitch and roll are from -45 degrees to +45 degrees (i.e. 0 is -45,
and 0x7FFF is +45).

That's it. Pretty simple.

To summarize, the packet is:

1111 1111 1111 1111 (16 bits of 1's)
0yyy yyyy yyyy yyyy (15-bit yaw)
0ppp pppp pppp pppp (15-bit pitch)
0rrr rrrr rrrr rrrr (15-bit roll)

Software-wise, you send an 'R' followed by an 'F' to initialize the tracker
and put it into binary mode. Your serial interrupt routine should check for
two consecutive 0xFF's; when it sees them, it should reset its buffer pointer
to zero. After the number of bytes in the buffer hits 6, just pick up the
yaw/pitch/roll and convert. *Really* simple stuff.

Here's what I propose to do to extend the packet format:

Add additional 16-bit words (with the top bit clear, for backwards
compatability). In other words, after the "roll" value, just add
more data; old parsers will ignore everything up to the next
double 0xFF, and new parsers can use the additional data. New parsers
should probably check the copyright message, to see if they've got an
old-format device (like the current CyberMaxx), in which case they read
only the yaw/pitch/roll.

The first additional word (after the roll value) would be:

0knn nnnn cccc cccc

where the 6-bit 'n' value is the number of 16-bit values that follow, and
the 8-bit 'c' value is a channel id (in case the serial devices are
daisy-chained). The data for the additional channels would follow, 15
bits for each channel. The first three should be reserved for position
information, the rest will be device-specific (e.g. finger flexion).

If the 'k' bit is set, the software should expect a 16-bit (really 15-bit)
checksum to follow the data; the checksum would be the unsigned sum of all
the data values (not including the 0xFF's).