vrpn  07.33
Virtual Reality Peripheral Network
vrpn_Nidaq.C
Go to the documentation of this file.
1 /*****************************************************************************\
2  vrpn_Nidaq.C
3  --
4  Description :
5 
6  ----------------------------------------------------------------------------
7  Author: weberh
8  Created: Fri Jan 29 10:00:00 1999
9  Revised: Fri Mar 19 14:46:06 1999 by weberh
10 \*****************************************************************************/
11 
12 #include "vrpn_Nidaq.h"
13 #if defined(WIN32) || defined(_WIN32)
14 #if defined(VRPN_USE_NIDAQ)
15 #include <uptime.h>
16 
17 // for fNice stuff
18 #include <windows.h>
19 #include <mmsystem.h>
20 // link with winmm.lib
21 #include <process.h>
22 // must link to multithreaded libs
23 
24 
25 //#define VERBOSE
26 vrpn_Nidaq::vrpn_Nidaq(char *pchName, vrpn_Connection *pConnection,
27  double dSamplingRate, double dInterChannelRate,
28  short sDeviceNumber, int cChannels,
29  short rgsChan[], short rgsGain[],
30  short sInputMode, short sPolarity, int fNice)
31  : vrpn_Analog(pchName, pConnection), pDAQ(NULL), fNice(fNice), fStop(0),
32  fNewData(0), dSampleTime(0) {
33 
34  if (cChannels>vrpn_CHANNEL_MAX) {
35  cerr << "vrpn_Nidaq::vrpn_Nidaq: vrpn_Analog allows only "
36  << vrpn_CHANNEL_MAX << " channels (" << cChannels
37  << " requested). DAQ not initialized." << endl;
38  return;
39  }
40 
41  if (fNice) {
42  MMRESULT res = timeBeginPeriod(1);
43  if (res != TIMERR_NOERROR) {
44  cerr << "NidaqServer: timeBeginPeriod() failed!!!\n";
45  }
46  }
47 
48  num_channel = cChannels;
49  daqSample.resize(cChannels);
50 
51  // calc the approximate offset between the clock the daq class uses
52  // and the clock vrpn uses.
53 
54  // call each to get them in cache
55  struct timeval tv, tvUpTime;
56  double dTime1, dTime2;
57  vrpn_gettimeofday(&tv, NULL);
58  vrpn_gettimeofday(&tv, NULL);
59  UpTime::Now();
60  UpTime::Now();
61 
62  // Now calc offset
63  dTime1=UpTime::Now();
64  vrpn_gettimeofday(&tv, NULL);
65  dTime2=UpTime::Now();
66 
67  dTime1 = (dTime1 + dTime2)/2.0;
68  tvUpTime = vrpn_MsecsTimeval(dTime1*1000.0);
69  tvOffset = vrpn_TimevalDiff(tv, tvUpTime);
70 
71  // later, add this to tvUpTime to get into vrpn_gettimeofday time frame
72 
73  // alloc the daq (which also starts it up)
74  // args are:
75  // rate for set of channels
76  // rate between channels
77  // which device num the daq has been set up as
78  // the number of channels to read off of it
79  // the array of channels to read
80  // the gain to apply to each
81  // differential or single ended
82  // bipolar (+/-) or just unipolar (+)
83  pDAQ = new DAQ(dSamplingRate, dInterChannelRate, sDeviceNumber, cChannels,
84  rgsChan, rgsGain, sInputMode, sPolarity );
85 
86  // start the DAQ-only thread
87  InitializeCriticalSection(&csAnalogBuffer);
88  hDAQThread = (HANDLE) _beginthreadex(NULL, 0, runThread, this, 0, NULL);
89 }
90 
91 // threadshell for code which actually runs "Inertials"
92 unsigned __stdcall vrpn_Nidaq::runThread(void *pVrpnNidaq) {
93  ((vrpn_Nidaq *)pVrpnNidaq)->runNidaq();
94  return 0;
95 }
96 
97 // here is what Inertials does in its run thread
98 void vrpn_Nidaq::runNidaq() {
99  // always service the nidaq, but only pack messages if there is
100  // a new report and we have a connection.
101 
102  // getSample will fill in the report with most recent valid
103  // data and the time of that data.
104  // return value is the number of reports processed by
105  // the a/d card since the last getSample call.
106  // (if > 1, then we missed a report; if 0, then no new data)
107  // if gfAllInertial is filled in, then we will grab the intervening
108  // reports as well (note: gfAllInertial does not work properly as
109  // of 1/29/99 weberh).
110  while (!fStop) {
111  if (pDAQ->getSample(&daqSample)) {
112  // there is a reading and a connection ... so package it
113 
114  // copy daq channels to analog class data
115  EnterCriticalSection(&csAnalogBuffer);
116  for (int i=0;i<daqSample.cChannels;i++) {
117  channel[i]=daqSample.rgd[i];
118  }
119  fNewData=1;
120  dSampleTime=daqSample.dTime;
121  LeaveCriticalSection(&csAnalogBuffer);
122  }
123  if (fNice) {
124  Sleep(1);
125  }
126  }
127 }
128 
129 vrpn_Nidaq::~vrpn_Nidaq() {
130  fStop=1;
131  WaitForSingleObject(hDAQThread,INFINITE);
132  if (fNice) {
133  timeEndPeriod(1);
134  }
135  delete pDAQ;
136 }
137 
138 void vrpn_Nidaq::mainloop(void) {
139  server_mainloop();
140  report_changes();
141 }
142 
143 int vrpn_Nidaq::doing_okay() {
144  return (pDAQ->status()==DAQ::RUNNING);
145 }
146 
147 void vrpn_Nidaq::report_changes() {
148  // always service the nidaq, but only pack messages if there is
149  // a new report and we have a connection.
150 
151  // getSample will fill in the report with most recent valid
152  // data and the time of that data.
153  // return value is the number of reports processed by
154  // the a/d card since the last getSample call.
155  // (if > 1, then we missed a report; if 0, then no new data)
156  // if gfAllInertial is filled in, then we will grab the intervening
157  // reports as well (note: gfAllInertial does not work properly as
158  // of 1/29/99 weberh).
159 #ifdef VERBOSE
160  int fHadNew=0;
161 #endif
162  if (d_connection) {
163  // there is a reading and a connection ... so package it
164 
165  EnterCriticalSection(&csAnalogBuffer);
166 
167 #ifdef VERBOSE
168  fHadNew=fNewData;
169 #endif
170  if (fNewData) {
171  fNewData=0;
172  // It will actually be sent out when the server calls
173  // mainloop() on the connection object this device uses.
174  char rgch[1000];
175  int cChars = vrpn_Analog::encode_to(rgch);
176  double dTime = dSampleTime;
177  LeaveCriticalSection(&csAnalogBuffer);
178 
179  struct timeval tv;
180  tv = vrpn_TimevalSum(vrpn_MsecsTimeval(dTime*1000.0),
181  tvOffset);
182 
183  if (d_connection->pack_message(cChars, tv, channel_m_id, d_sender_id, rgch,
185  cerr << "vrpn_Nidaq::report_changes: cannot write message: tossing.\n";
186  }
187  } else {
188  LeaveCriticalSection(&csAnalogBuffer);
189  }
190 #ifdef VERBOSE
191  if (fHadNew) {
192  print();
193  }
194 #endif
195 
196  } else {
197  cerr << "vrpn_Nidaq::report_changes: no valid connection.\n";
198  }
199 }
200 #endif // def(VRPN_USE_NIDAQ)
201 #endif // def(WIN32) || def(_WIN32)
vrpn_Analog::encode_to
virtual vrpn_int32 encode_to(char *buf)
Definition: vrpn_Analog.C:54
vrpn_Analog
Definition: vrpn_Analog.h:28
vrpn_Nidaq.h
vrpn_CHANNEL_MAX
#define vrpn_CHANNEL_MAX
Definition: vrpn_Analog.h:16
vrpn_CONNECTION_LOW_LATENCY
const vrpn_uint32 vrpn_CONNECTION_LOW_LATENCY
Definition: vrpn_Connection.h:122
vrpn_TimevalDiff
timeval vrpn_TimevalDiff(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:92
vrpn_Connection
Generic connection class not specific to the transport mechanism.
Definition: vrpn_Connection.h:510
vrpn_gettimeofday
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
vrpn_MsecsTimeval
timeval vrpn_MsecsTimeval(const double dMsecs)
Definition: vrpn_Shared.C:146
vrpn_TimevalSum
timeval vrpn_TimevalSum(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:45