vrpn 07.35
Virtual Reality Peripheral Network
Loading...
Searching...
No Matches
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
26vrpn_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"
92unsigned __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
98void 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
129vrpn_Nidaq::~vrpn_Nidaq() {
130 fStop=1;
131 WaitForSingleObject(hDAQThread,INFINITE);
132 if (fNice) {
133 timeEndPeriod(1);
134 }
135 try {
136 delete pDAQ;
137 } catch (...) {
138 fprintf(stderr, "vrpn_Nidaq::~vrpn_Nidaq(): delete failed\n");
139 return;
140 }
141}
142
143void vrpn_Nidaq::mainloop(void) {
144 server_mainloop();
145 report_changes();
146}
147
148int vrpn_Nidaq::doing_okay() {
149 return (pDAQ->status()==DAQ::RUNNING);
150}
151
152void vrpn_Nidaq::report_changes() {
153 // always service the nidaq, but only pack messages if there is
154 // a new report and we have a connection.
155
156 // getSample will fill in the report with most recent valid
157 // data and the time of that data.
158 // return value is the number of reports processed by
159 // the a/d card since the last getSample call.
160 // (if > 1, then we missed a report; if 0, then no new data)
161 // if gfAllInertial is filled in, then we will grab the intervening
162 // reports as well (note: gfAllInertial does not work properly as
163 // of 1/29/99 weberh).
164#ifdef VERBOSE
165 int fHadNew=0;
166#endif
167 if (d_connection) {
168 // there is a reading and a connection ... so package it
169
170 EnterCriticalSection(&csAnalogBuffer);
171
172#ifdef VERBOSE
173 fHadNew=fNewData;
174#endif
175 if (fNewData) {
176 fNewData=0;
177 // It will actually be sent out when the server calls
178 // mainloop() on the connection object this device uses.
179 char rgch[1000];
180 int cChars = vrpn_Analog::encode_to(rgch);
181 double dTime = dSampleTime;
182 LeaveCriticalSection(&csAnalogBuffer);
183
184 struct timeval tv;
185 tv = vrpn_TimevalSum(vrpn_MsecsTimeval(dTime*1000.0),
186 tvOffset);
187
188 if (d_connection->pack_message(cChars, tv, channel_m_id, d_sender_id, rgch,
190 cerr << "vrpn_Nidaq::report_changes: cannot write message: tossing.\n";
191 }
192 } else {
193 LeaveCriticalSection(&csAnalogBuffer);
194 }
195#ifdef VERBOSE
196 if (fHadNew) {
197 print();
198 }
199#endif
200
201 } else {
202 cerr << "vrpn_Nidaq::report_changes: no valid connection.\n";
203 }
204}
205#endif // def(VRPN_USE_NIDAQ)
206#endif // def(WIN32) || def(_WIN32)
virtual vrpn_int32 encode_to(char *buf)
Definition vrpn_Analog.C:54
Generic connection class not specific to the transport mechanism.
#define vrpn_CHANNEL_MAX
Definition vrpn_Analog.h:16
const vrpn_uint32 vrpn_CONNECTION_LOW_LATENCY
timeval vrpn_TimevalDiff(const timeval &tv1, const timeval &tv2)
timeval vrpn_MsecsTimeval(const double dMsecs)
timeval vrpn_TimevalSum(const timeval &tv1, const timeval &tv2)
Definition vrpn_Shared.C:54
#define vrpn_gettimeofday
Definition vrpn_Shared.h:99