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
HID & two SpaceNavigators
Moderator: Moderators
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
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
-
- Posts: 44
- Joined: Fri Apr 04, 2008 7:03 am
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.
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.
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;
}
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;
}
-
- Posts: 44
- Joined: Fri Apr 04, 2008 7:03 am
-
- Posts: 44
- Joined: Fri Apr 04, 2008 7:03 am
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;
}
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;
}
-
- Posts: 44
- Joined: Fri Apr 04, 2008 7:03 am
-
- Posts: 44
- Joined: Fri Apr 04, 2008 7:03 am