Accessing LEDs and the LCD display on a SpacePilot
Moderator: Moderators
Accessing LEDs and the LCD display on a SpacePilot
Back in early April, I posted a message asking for information about how I would go about writing a vxWorks device driver for the SpacePilot to be used with our 3D digital effect processor. I have now bought a spacepilot and, as predicted by jwick, the sensor and buttons proved to be trivial to get working.
I'm now trying to get control of the blue LEDs behind the knob and the LCD bitmap display.
For the LEDs, I've been trying to use the SET_REPORT command (similar to the LEDs in my USB keyboard driver) for Report ID 4 which appears to be the LED usage page, but I can't seem to get any change. When I use the GET_REPORT command, it returns 4 in the first byte (report ID) and zero in the second byte, no matter what I have sent in the SET_REPORT command.
I can't seem to find any reference to the LCD bitmap in the HID descriptor information, but there are report IDs 5 through 18 which are "feature" descriptions. I'm assuming that these features allow things like recentering of axes.
I'd be grateful for any assistance that anyone could offer in helping me getting the LEDs and LCD display working, and in finding out what those 14 feature descriptors do.
Thanks
Dave Pugh
I'm now trying to get control of the blue LEDs behind the knob and the LCD bitmap display.
For the LEDs, I've been trying to use the SET_REPORT command (similar to the LEDs in my USB keyboard driver) for Report ID 4 which appears to be the LED usage page, but I can't seem to get any change. When I use the GET_REPORT command, it returns 4 in the first byte (report ID) and zero in the second byte, no matter what I have sent in the SET_REPORT command.
I can't seem to find any reference to the LCD bitmap in the HID descriptor information, but there are report IDs 5 through 18 which are "feature" descriptions. I'm assuming that these features allow things like recentering of axes.
I'd be grateful for any assistance that anyone could offer in helping me getting the LEDs and LCD display working, and in finding out what those 14 feature descriptors do.
Thanks
Dave Pugh
Last edited by DavePugh on Wed May 30, 2007 9:01 am, edited 1 time in total.
Partial success
I was right about the LEDs. They now work. Please ignore that part of the original post. I've still got no idea where to start with writing to the LCD display though.
Here is some info and pseudocode on the SpacePilot LCD.
The LCD is 64x240 but is addressed one row of eight bits high at a time.
The LCD is filled 7 columns at a time from left to right in one of the 8 rows.
If the start position is (0,0), the first byte sent fills the following bits:
----------------------------------- ...
|1
|2
|3
|4
|5 ------>
|6
|7
|8
|Start of the second row
...
The next byte fills the column to the right of that one.
If there are less than 7 columns left in the row, you must send a packed structure for the remaining rows.
The packed structure is a count, value structure. You can have up to 3 values that can be repeated up to 255 times.
Of course, there are only 240 columns per row. This can fill patterns or empty space quickly.
We make extensive use of this packet, testing all data to see if it is more efficient to send it packed before sending it unpacked.
This is the relevant data structure.
typedef struct PackedDataState
{
int count[3]; // Count of each pattern in the data array
unsigned char bits[3]; // Up to 3 patterns of data bytes
} PackedDataState;
#define RPTID_LCD_POS 0x0c
#define RPTID_LCD_DATA 0x0d
#define RPTID_LCD_DATA_PACK 0x0e
void LCDStartPos(int row, int column)
/*
* Sets position at which subsequent bits will be filled.
* Note that row is one of 8 rows of 8 bit tall columns.
* There is a problem if you try to start after column 120.
*/
{
unsigned char *buffer = new unsigned char[4];
// Set start position
buffer[0] = RPTID_LCD_POS; // report ID 0x0c for LCD_POS
buffer[1] = row; // 0-7
buffer[2] = column; // 0-239
buffer[3] = 0;
// Send the buffer to the device
EnqueueCommand( buffer, 4 ); // buffer is free'd by EnqueueCommand after it is transmitted
}
LCDSendBitsUnpacked(unsigned char bits[][])
{
unsigned char *buffer = new unsigned char[8];
buffer[0] = RPTID_LCD_DATA; // report ID 0x0d for LCD_DATA
buffer[1] = bits[j++];
buffer[2] = bits[j++];
buffer[3] = bits[j++];
buffer[4] = bits[j++];
buffer[5] = bits[j++];
buffer[6] = bits[j++];
buffer[7] = bits[j++];
EnqueueCommand( buffer, 8 );
}
LCDSendBitsPacked( PackedDataState pds )
{
unsigned char *buffer = new unsigned char[7];
buffer[0] = RPTID_LCD_DATA_PACK; // report ID 0x0e for packed data packet
buffer[1] = pds.count[0];
buffer[2] = pds.bits [0];
buffer[3] = pds.count[1];
buffer[4] = pds.bits [1];
buffer[5] = pds.count[2];
buffer[6] = pds.bits [2];
// Queue up the command for transmission to the device
EnqueueCommand( buffer, 7 );
}
The LCD is 64x240 but is addressed one row of eight bits high at a time.
The LCD is filled 7 columns at a time from left to right in one of the 8 rows.
If the start position is (0,0), the first byte sent fills the following bits:
----------------------------------- ...
|1
|2
|3
|4
|5 ------>
|6
|7
|8
|Start of the second row
...
The next byte fills the column to the right of that one.
If there are less than 7 columns left in the row, you must send a packed structure for the remaining rows.
The packed structure is a count, value structure. You can have up to 3 values that can be repeated up to 255 times.
Of course, there are only 240 columns per row. This can fill patterns or empty space quickly.
We make extensive use of this packet, testing all data to see if it is more efficient to send it packed before sending it unpacked.
This is the relevant data structure.
typedef struct PackedDataState
{
int count[3]; // Count of each pattern in the data array
unsigned char bits[3]; // Up to 3 patterns of data bytes
} PackedDataState;
#define RPTID_LCD_POS 0x0c
#define RPTID_LCD_DATA 0x0d
#define RPTID_LCD_DATA_PACK 0x0e
void LCDStartPos(int row, int column)
/*
* Sets position at which subsequent bits will be filled.
* Note that row is one of 8 rows of 8 bit tall columns.
* There is a problem if you try to start after column 120.
*/
{
unsigned char *buffer = new unsigned char[4];
// Set start position
buffer[0] = RPTID_LCD_POS; // report ID 0x0c for LCD_POS
buffer[1] = row; // 0-7
buffer[2] = column; // 0-239
buffer[3] = 0;
// Send the buffer to the device
EnqueueCommand( buffer, 4 ); // buffer is free'd by EnqueueCommand after it is transmitted
}
LCDSendBitsUnpacked(unsigned char bits[][])
{
unsigned char *buffer = new unsigned char[8];
buffer[0] = RPTID_LCD_DATA; // report ID 0x0d for LCD_DATA
buffer[1] = bits[j++];
buffer[2] = bits[j++];
buffer[3] = bits[j++];
buffer[4] = bits[j++];
buffer[5] = bits[j++];
buffer[6] = bits[j++];
buffer[7] = bits[j++];
EnqueueCommand( buffer, 8 );
}
LCDSendBitsPacked( PackedDataState pds )
{
unsigned char *buffer = new unsigned char[7];
buffer[0] = RPTID_LCD_DATA_PACK; // report ID 0x0e for packed data packet
buffer[1] = pds.count[0];
buffer[2] = pds.bits [0];
buffer[3] = pds.count[1];
buffer[4] = pds.bits [1];
buffer[5] = pds.count[2];
buffer[6] = pds.bits [2];
// Queue up the command for transmission to the device
EnqueueCommand( buffer, 7 );
}
Thanks
Thanks Jwick. That looks like exactly what I need. I have spent this morning staring at the output from a USB protocol analyser, trying to work out the syntax. I had correctly assumed that the C, D and E reports were the correct ones, but couldn't work out the data format.
I'll let you know how I get on.
Thanks
Dave
I'll let you know how I get on.
Thanks
Dave
Hi,jwick wrote:void LCDStartPos(int row, int column)
/*
* Sets position at which subsequent bits will be filled.
* Note that row is one of 8 rows of 8 bit tall columns.
* There is a problem if you try to start after column 120.
*/
Could you elaborate on the problems of starting after column 120? Is that value a typo?
Thanks
-- mew
Re: Partial success
Is there a way to control the LEDs on the SpaceNavigator using DirectX? I have found the DirectX far easier to implement into software than the COM samples provided.DavePugh wrote: I was right about the LEDs. They now work. Please ignore that part of the original post. I've still got no idea where to start with writing to the LCD display though.
Dave & jwick,
I have the same wish, I'd like to control the LCD from within my application. I saw the pseudo code posted in this thread and I have absolutely no idea how to use it Can you give any hint how to communicate to the spacepilot? Dave are you willing to share some of your code? I'm working in (Managed) C++. I'm working on a .NET control wrapping all functions of the spacepilot. If I can get the LCD working I'm willing to share the control so everybody can use it in .NET applications.
Thanks!
Michel
I have the same wish, I'd like to control the LCD from within my application. I saw the pseudo code posted in this thread and I have absolutely no idea how to use it Can you give any hint how to communicate to the spacepilot? Dave are you willing to share some of your code? I'm working in (Managed) C++. I'm working on a .NET control wrapping all functions of the spacepilot. If I can get the LCD working I'm willing to share the control so everybody can use it in .NET applications.
Thanks!
Michel
Hi Jim,
Maybe I can help you integrate it in .NET code. It's just that I don't have the slightest idea what you were talking about in the previous posting with the pseudo-code. Should the communication work in a low-level way where a device is opened and messages are send to it?
How comes everything is done through a nice COM except for the LCD?
If you have some non-.NET stuff working please send it to me, I'll see how I can integrate it ...
Thanks!
Michel
Maybe I can help you integrate it in .NET code. It's just that I don't have the slightest idea what you were talking about in the previous posting with the pseudo-code. Should the communication work in a low-level way where a device is opened and messages are send to it?
How comes everything is done through a nice COM except for the LCD?
If you have some non-.NET stuff working please send it to me, I'll see how I can integrate it ...
Thanks!
Michel
Hi Michel,
That isn't pseudo-code, it IS the code that manages the LCD (with a lot of synchronization and optimization code left out). The LCD is a bitmap. Everything you see on it is constructed by the driver one bit at a time. There is an interface to the driver to set strings on it via the old C/C++ SDK (GUI Synch API), but that has not yet been ported to the COM API (3DxInput). Why hasn't that been done? Not enough call for it to rise to the top of the priority list.
Also, the LCD was not meant to be an arbitrary bitmap you can scribble on. It was meant to tell the user what the buttons do. If you want to sync in with the latter, it fits in with our scheme. If you want arbitrary control over the LCD, you are going to be fighting with the driver for control over it. In that case, it would be best to turn off the 3DxWare driver and use native MS APIs.
Jim
3Dx Software Development
That isn't pseudo-code, it IS the code that manages the LCD (with a lot of synchronization and optimization code left out). The LCD is a bitmap. Everything you see on it is constructed by the driver one bit at a time. There is an interface to the driver to set strings on it via the old C/C++ SDK (GUI Synch API), but that has not yet been ported to the COM API (3DxInput). Why hasn't that been done? Not enough call for it to rise to the top of the priority list.
Also, the LCD was not meant to be an arbitrary bitmap you can scribble on. It was meant to tell the user what the buttons do. If you want to sync in with the latter, it fits in with our scheme. If you want arbitrary control over the LCD, you are going to be fighting with the driver for control over it. In that case, it would be best to turn off the 3DxWare driver and use native MS APIs.
Jim
3Dx Software Development
Hi Jim,
Well .. I'm not looking for playing AVI's on the LCD or anything, but I would like to change the text (that describes the buttons functions)dynamically, so from withing my program. A workaround could be by changing the configuration but that doesn't seem to work (I posted that issue as well in this forum)
Michel
Well .. I'm not looking for playing AVI's on the LCD or anything, but I would like to change the text (that describes the buttons functions)dynamically, so from withing my program. A workaround could be by changing the configuration but that doesn't seem to work (I posted that issue as well in this forum)
Michel