HID & two SpaceNavigators

Post questions, comments and feedback to our 3Dconnexion Windows Development Team.

Moderator: Moderators

Post Reply
sochm
Posts: 5
Joined: Thu Jul 10, 2008 1:04 am
Location: Czech Republic

HID & two SpaceNavigators

Post by sochm »

Hello,

we have developed SW that reads data from two SpaceNavigators (SN) via USB. Reading from each SN is handled in a separate thread. We are using HID library for reading. Data are read asynchronously using MS-Win API functions: ReadFile, WaitForSingleObject and GetOverlappedResult (we used code snippets posted it this forum).

When the SW starts everything is fine and we are receiving data from both SN.

But when we are working only with one SN (both are connected and ready but we are working/touching only one SN) after some time (15-20 minutes) we receive hardly any data from SN we are working with; number of received messages decreases from "many" to one per sec and sometimes to no message. Touching the second SN sometimes causes getting to the original state (after start). This behavior was found on MS-Win XP 32 Professional.

We have also tried to test the SW on MS-Win Vista Business. The behavior is different there. Again the problem occurs when we are working only with one SN (both are connected and ready but we are working/touching only one SN). Here we are still receiving data from SN we are working with and no slowing down of number of received messages occurs. But again after some time (again cca 20 minutes) when we touch the second SN (we expect to receive some data from it then) but no data are received. We receive data from 2nd SN about one or two minutes later - during this time we are touching both SN (we expect that both should send some data).

We used MS-Visual Studio 2005 IDE and VC++ compiler.

Any help/advice is highly appreciated
Thank you
Martin
jwick
Moderator
Moderator
Posts: 3342
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

Hello sochm,

There is nothing inherent in the devices that would be causing this behavior. IOW, they don't go to sleep or anything like that.

I'd look at what is happening to your threads and your ReadFile / GetOverlappedResult calls. Do they really take 1 minute to wake up? How likely is it that your threads are getting swapped out and are having a difficult time getting fully swapped back in?

The device sends data at a ferocious rate. Make sure you aren't spending a minute eating through all the buffered up data.

Please let us know what you find, so others may benefit from it.

Jim
3Dx Software Development
rodrigo.seabra
Posts: 44
Joined: Fri Apr 04, 2008 7:03 am

Post by rodrigo.seabra »

Hi sochm,

I'm trying to do exactly the same as you did in your application, including the asynchronous handling of device, but I am working with only one.

I have tried several combinations of parameters of methods ReadFile, WaitForSingleObject and GetOverlappedResult, however, no sucess.

During the execution, I do reading the device each update of frames of my application. Could you explain to me how you implemented the methods for its application? It would be a great help to me...

Thank you,

Rodrigo.
sochm
Posts: 5
Joined: Thu Jul 10, 2008 1:04 am
Location: Czech Republic

Post by sochm »

Hello,

thank you for your comments.

to Jim: on Win-Vista it really takes about 1 min to swap in the second thread, on Win-XP we receive no data after cca 20min and it is nearly regular

to Rodrigo: we have also tried our SW connected just with one SN and we have had no problems

anyway, there can be some problems in our code or in HID library or in operating system (hardly)
the code we use for reading data is attached at the end of this post, it is a body of the thread which handles one SN
we will probably try another way to handle USB devices instead of HID library and check our code for possible causes

Thank you for your time again
Martin Soch


// some definitions:
typedef struct _HidDevice {
PSP_DEVICE_INTERFACE_DETAIL_DATA pDevInterfaceDetailData;
HANDLE handle;
PHIDP_PREPARSED_DATA pPreparsedData;
HIDP_CAPS capabilities;
PHIDP_BUTTON_CAPS pInButCaps,pOutButCaps,pFeatButCaps;
PHIDP_VALUE_CAPS pInValCaps,pOutValCaps,pFeatValCaps;
char *buf;
BOOL bGotTranslationVector, bGotRotationVector;
int allDOFs[7];
} HidDevice;
HidDevice m_hidDevice;


// method that handles reading from USB port:
DWORD USBThread::execute( LPVOID pParam )
{
DWORD nread, waitResult;
OVERLAPPED hidOverlapped;
HANDLE reportEvent;

/* Create a new event for report capture */
reportEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

/* fill the HidOverlapped structure so that Windows knows which
event to cause when the device sends an IN report */
hidOverlapped.hEvent = reportEvent;
hidOverlapped.Offset = 0;
hidOverlapped.OffsetHigh = 0;

while(!this->IsStopping())
{
// asynchronous read
ReadFile(m_hidDevice.handle,
m_hidDevice.buf,
m_hidDevice.capabilities.InputReportByteLength,
&nread,
(LPOVERLAPPED) &hidOverlapped);

waitResult = WaitForSingleObject( reportEvent, 250); //wait for data

/* if the transaction timed out, then we have to manually cancel the request */
if(waitResult == WAIT_TIMEOUT || waitResult == WAIT_ABANDONED)
CancelIo(&m_hidDevice.handle);

if(waitResult == WAIT_OBJECT_0)
{
GetOverlappedResult(m_hidDevice.handle, (LPOVERLAPPED) &hidOverlapped, &nread, true );

switch ( m_hidDevice.buf[0] )
{
case 0x01: //Translation vector
if (nread != 7)
{
// LOG_ERROR
break; // something is wrong
}
//printf("Device %d Got Translation vector\n", index);
m_hidDevice.bGotTranslationVector = TRUE;
m_hidDevice.allDOFs[0] = (m_hidDevice.buf[1] & 0x000000ff) | ((int)m_hidDevice.buf[2]<<8 & 0xffffff00);
m_hidDevice.allDOFs[1] = (m_hidDevice.buf[3] & 0x000000ff) | ((int)m_hidDevice.buf[4]<<8 & 0xffffff00);
m_hidDevice.allDOFs[2] = (m_hidDevice.buf[5] & 0x000000ff) | ((int)m_hidDevice.buf[6]<<8 & 0xffffff00);
break;

case 0x02: //Rotation vector
if (nread != 7)
{
// LOG_ERROR
break; // something is wrong
}
//printf("Device %d Got Rotation vector\n", index);
m_hidDevice.bGotRotationVector = TRUE;
m_hidDevice.allDOFs[3] = (m_hidDevice.buf[1] & 0x000000ff) | ((int)m_hidDevice.buf[2]<<8 & 0xffffff00);
m_hidDevice.allDOFs[4] = (m_hidDevice.buf[3] & 0x000000ff) | ((int)m_hidDevice.buf[4]<<8 & 0xffffff00);
m_hidDevice.allDOFs[5] = (m_hidDevice.buf[5] & 0x000000ff) | ((int)m_hidDevice.buf[6]<<8>WriteChannel(m_plcDriver->GetChannels()[m_channelNum - 1], new IntValue(m_hidDevice.allDOFs[6]), 6);
break;

default:
LOG_ERROR("Wrong vector.");
break;
}

// Translation and Rotation values come in two different packets. Wait until we have both of them.
if ( m_hidDevice.bGotTranslationVector && m_hidDevice.bGotRotationVector)
{
m_hidDevice.bGotTranslationVector = m_hidDevice.bGotRotationVector = FALSE;

m_channelValue.clear();
for(int i = 0; i < 6; i++)
{
m_channelValue.push_back(new IntValue(m_hidDevice.allDOFs));
}
// pass data to another thread which consumes it
m_plcDriver->WriteChannel(m_plcDriver->GetChannels()[m_channelNum - 1], m_channelValue, (unsigned int)0, (size_t)6, REWRITE);
}
}
}

CloseHandle(reportEvent);
return (DWORD) 0;
}
rodrigo.seabra
Posts: 44
Joined: Fri Apr 04, 2008 7:03 am

Post by rodrigo.seabra »

Hi Martin Soch,

Where is the definition of the method IsStopping()? I would like to know what this method means in your code...

Thank you very much for your attention help me...

Rodrigo.
rodrigo.seabra
Posts: 44
Joined: Fri Apr 04, 2008 7:03 am

Post by rodrigo.seabra »

Hi Martin,

I believe that you didn't see my previous message ... Could you give me the definition of the method IsStopping?

Thank you very much...

Rodrigo.
sochm
Posts: 5
Joined: Thu Jul 10, 2008 1:04 am
Location: Czech Republic

Post by sochm »

hello Rodrigo,

it works in the following way:
thread that handles reading from SN device is extended from CWThread class (code snippet at the end)
within its execute method (posted in previous post) thread periodically check the m_bStopping flag with IsStopping() method
when a thread is started its m_bStopping flag is set to FALSE
when we want to stop the thread, we just call the Stop() method on a particular thread, then when the thread reaches the point with the test IsStopping() it leaves the while loop and finish the method execute which means that thread has finished

regards
ms


code is lake this:

class CWThread
{
public:
DWORD CWThread::Stop(){ m_bStopping = true; }
bool IsStopping() { return m_bStopping; }

protected:
virtual DWORD execute(LPVOID) = 0;

private:
//flag to stopping thread
bool m_bStopping;

}
rodrigo.seabra
Posts: 44
Joined: Fri Apr 04, 2008 7:03 am

Post by rodrigo.seabra »

Hello Martin,

Right. Now, my comprehension improved. But is not lacking in its previous code set the variable m_bStopping flag to FALSE, at start of thread?

What is the exact point where this should be done?

Thanks,

Rodrigo.
rodrigo.seabra
Posts: 44
Joined: Fri Apr 04, 2008 7:03 am

Post by rodrigo.seabra »

Hi Martin,

How you defined the method that initializes the device?

Thanks,

Rodrigo.
sochm
Posts: 5
Joined: Thu Jul 10, 2008 1:04 am
Location: Czech Republic

Post by sochm »

Hello,
we have switched from using HID library to Direct Input (DirectX) when reading data from SNs. It works for us.
MS
Post Reply