vrpn 07.36
Virtual Reality Peripheral Network
Loading...
Searching...
No Matches
vrpn_Tracker_JsonNet.C
Go to the documentation of this file.
2
3#if defined(VRPN_USE_JSONNET)
4
5#ifdef _WIN32
6 #ifdef VRPN_USE_WINSOCK2
7 #include <winsock2.h> // struct timeval is defined here
8 #else
9 #include <winsock.h> // struct timeval is defined here
10 #endif
11#else
12 #include <sys/socket.h>
13 #include <sys/time.h>
14 #include <netinet/in.h>
15 #include <unistd.h>
16 #define INVALID_SOCKET -1
17#endif
18
19#include "json/json.h"
20
21#include "quat.h"
22
24
25#include <stdlib.h> // for exit
26
27// These must match definitions in eu.ensam.ii.vrpn.Vrpn
28static const char* const MSG_KEY_TYPE = "type";
29//static const char* const MSG_KEY_SEQUENCE_NUMBER = "sn";
30//static const char* const MSG_KEY_TIMESTAMP = "ts";
31
32static const char* const MSG_KEY_TRACKER_ID = "id";
33static const char* const MSG_KEY_TRACKER_QUAT = "quat";
34static const char* const MSG_KEY_TRACKER_POS = "pos";
35
36static const char* const MSG_KEY_BUTTON_ID = "button";
37static const char* const MSG_KEY_BUTTON_STATUS = "state";
38
39static const char* const MSG_KEY_ANALOG_CHANNEL = "num";
40static const char* const MSG_KEY_ANALOG_DATA = "data";
41
42static const char* const MSG_KEY_TEXT_DATA = "data";
43
44// Message types (values for MSG_KEY_TYPE)
45static const int MSG_TYPE_TRACKER = 1;
46static const int MSG_TYPE_BUTTON = 2;
47static const int MSG_TYPE_ANALOG = 3;
48static const int MSG_TYPE_TEXT = 4;
49
50vrpn_Tracker_JsonNet::vrpn_Tracker_JsonNet(const char* name,vrpn_Connection* c,int udp_port) :
51 vrpn_Tracker(name, c),
52 vrpn_Button_Filter(name, c),
53 vrpn_Analog(name, c),
54 vrpn_Text_Sender(name, c),
55 _socket(INVALID_SOCKET),
56 _do_tracker_report(false),
57 _pJsonReader(0)
58{
59 fprintf(stderr, "vrpn_Tracker_JsonNet : Device %s listen on port udp port %d\n", name, udp_port);
60 if (! _network_init(udp_port)) {
61 exit(EXIT_FAILURE);
62 }
63
64 // Buttons part
65
66 num_buttons = vrpn_BUTTON_MAX_BUTTONS;
67 num_channel = vrpn_CHANNEL_MAX;
68
69 _pJsonReader = new Json::Reader();
70}
71
72vrpn_Tracker_JsonNet::~vrpn_Tracker_JsonNet(void)
73{
74 if (_pJsonReader != 0) {
75 try {
76 delete _pJsonReader;
77 } catch (...) {
78 fprintf(stderr, "vrpn_Tracker_JsonNet::~vrpn_Tracker_JsonNet(): delete failed\n");
79 return;
80 }
81 _pJsonReader = 0;
82 }
83 _network_release();
84}
85
86
87void vrpn_Tracker_JsonNet::mainloop()
88{
89 server_mainloop();
90 /*
91 * The original Dtrack code uses blocking call to select() in _network_receive with
92 * a 1 sec timeout. In Dtrack, the data is supposed to be continuously flowing (app. 60 Hz),
93 * so the timeout is unlikely to happen. However, the data from the Android device flow at a lower
94 * frequency and may not flow at all if the tilt tracker is disabled.
95 * Thus a 1 sec timeout here causes latency and jerky movements in Dtrack
96 */
97 const int timeout_us = 10 * 1000;
98 int received_length = _network_receive(_network_buffer, _NETWORK_BUFFER_SIZE, timeout_us);
99
100 if (received_length < 0) {
101 //fprintf(stderr, "vrpn_Tracker_JsonNet : receive error %d\n", received_length);
102 return;
103 }
104 _network_buffer[received_length] = '\0';
105 //fprintf(stderr, "got data : %.*s\n", received_length, _network_buffer);
106 if (!_parse(_network_buffer, received_length)) {
107 // whatever error
108
109 return;
110 }
111
112 // report trackerchanges
113 // TODO really use timestamps
114 struct timeval ts ;
115 vrpn_gettimeofday(&ts, NULL);
116 // from vrpn_Tracker_DTrack::dtrack2vrpnbody
117 if (d_connection && _do_tracker_report) {
118 char msgbuf[1000];
119 // Encode pos and d_quat
120 int len = vrpn_Tracker::encode_to(msgbuf);
121 if (d_connection->pack_message(len, ts, position_m_id, d_sender_id, msgbuf, vrpn_CONNECTION_LOW_LATENCY)) {
122 // error
123 return;
124 }
125 _do_tracker_report = false;
126 //fprintf(stderr, "Packed and sent\n");
127 }
128
131}
132
133bool vrpn_Tracker_JsonNet::_parse(const char* buffer, int /*length*/)
134{
135 Json::Value root; // will contains the root value after parsing.
136 // Beware collectcomment = true crashes
137 bool parsingSuccessful = _pJsonReader->parse( buffer, root , false);
138 if ( !parsingSuccessful ) {
139 // report to the user the failure and their locations in the document.
140 fprintf(stderr, "vrpn_Tracker_JsonNet parse error :%s\n",
141 _pJsonReader->getFormatedErrorMessages().c_str());
142 fprintf(stderr, "%s\n",buffer);
143 return false;
144 }
145
146 const Json::Value& constRoot = root;
147 // Find MessageType
148 const Json::Value& type = constRoot[MSG_KEY_TYPE];
149 int messageType;
150 if (!type.empty() && type.isConvertibleTo(Json::intValue)) {
151 messageType = type.asInt();
152 // HACK
153 } else {
154 fprintf(stderr, "vrpn_Tracker_JsonNet parse error : missing message type\n");
155 return false;
156 }
157 switch (messageType) {
158 // TODO cleanup
159 case MSG_TYPE_TRACKER:
160 return _parse_tracker_data(root);
161 break;
162 case MSG_TYPE_BUTTON:
163 return _parse_button(root);
164 break;
165 case MSG_TYPE_ANALOG:
166 return _parse_analog(root);
167 break;
168 case MSG_TYPE_TEXT:
169 return _parse_text(root);
170 break;
171 default:
172 break;
173 }
174 return false;
175}
176
185bool vrpn_Tracker_JsonNet::_parse_tracker_data(const Json::Value& root)
186{
187 const Json::Value& constRoot = root;
188
189 // Id of the current tracker
190 const Json::Value& sensorId = constRoot[MSG_KEY_TRACKER_ID];
191 if (!sensorId.empty() && sensorId.isConvertibleTo(Json::intValue)){
192 this->d_sensor = sensorId.asInt();
193 } else {
194 return false;
195 }
196
197 /*
198 * mainloop calls vrpn_Tracker::encode_to, that will send d_sensor, d_pos and d_quat.
199 * velocity and acceleration are curretly not handled
200 */
201
202 const Json::Value& quatData = constRoot[MSG_KEY_TRACKER_QUAT];
203 if (!quatData.empty() && quatData.isArray() && quatData.size() == 4) {
204 this->d_quat[0] = quatData[0u].asDouble();
205 this->d_quat[1] = quatData[1].asDouble();
206 this->d_quat[2] = quatData[2].asDouble();
207 this->d_quat[3] = quatData[3].asDouble();
208 //q_vec_type ypr;
209 //q_to_euler(ypr, d_quat);
210 //fprintf(stderr, "yaw-rY %.3f pitch-rX %.3f roll-rZ %.3f \n", ypr[0], ypr[1], ypr[2]);
211 }
212
213 /*
214 * Look for a position
215 */
216 const Json::Value& posData = constRoot[MSG_KEY_TRACKER_POS];
217 if (!posData.empty() && posData.isArray() && posData.size() == 3) {
218 this->pos[0] = posData[0u].asDouble();
219 this->pos[1]= posData[1].asDouble();
220 this->pos[2]= posData[2].asDouble();
221 }
222
223 _do_tracker_report = true;
224 return true;
225}
226
235bool vrpn_Tracker_JsonNet::_parse_text(const Json::Value& root)
236{
237 const Json::Value& valueTextStatus = root[MSG_KEY_TEXT_DATA];
238 if (!valueTextStatus.empty() && valueTextStatus.isConvertibleTo(Json::stringValue)) {
239 send_text_message(vrpn_TEXT_NORMAL) << valueTextStatus.asString();
240 return true;
241 }
242 fprintf(stderr, "vrpn_Tracker_JsonNet::_parse_text parse error : missing text");
243 return false;
244}
253bool vrpn_Tracker_JsonNet::_parse_button(const Json::Value& root)
254{
255 const Json::Value& valueButtonStatus = root[MSG_KEY_BUTTON_STATUS];
256 bool buttonStatus;
257 if (!valueButtonStatus.empty() && valueButtonStatus.isConvertibleTo(Json::booleanValue)) {
258 buttonStatus = valueButtonStatus.asBool();
259 } else {
260 fprintf(stderr, "vrpn_Tracker_JsonNet::_parse_button parse error : missing status");
261 return false;
262 }
263 const Json::Value& valueButtonId = root[MSG_KEY_BUTTON_ID];
264 int buttonId; // buttonId embedded in the message.
265 if (!valueButtonId.empty() && valueButtonId.isConvertibleTo(Json::intValue)) {
266 buttonId = valueButtonId.asInt();
267 } else {
268 fprintf(stderr, "vrpn_Tracker_JsonNet::_parse_button parse error : missing id\n");
269 return false;
270 }
271
272 if (buttonId < 0 || buttonId > num_buttons) {
273 fprintf(stderr, "invalid button Id %d (max : %d)\n", buttonId, num_buttons);
274 } else {
275 buttons[buttonId] = (int)buttonStatus;
276 }
277
278 return true;
279}
280
289
290bool vrpn_Tracker_JsonNet::_parse_analog(const Json::Value& root)
291{
292 const Json::Value& valueData = root[MSG_KEY_ANALOG_DATA];
293 double data;
294 if (!valueData.empty() && valueData.isConvertibleTo(Json::realValue)) {
295 data = valueData.asDouble();
296 } else {
297 fprintf(stderr, "vrpn_Tracker_JsonNet::_parse_analog parse error : missing status");
298 return false;
299 }
300
301 const Json::Value& channelNumberId = root[MSG_KEY_ANALOG_CHANNEL];
302 int channelNumber;
303 if (!channelNumberId.empty() && channelNumberId.isConvertibleTo(Json::intValue)) {
304 channelNumber = channelNumberId.asInt();
305 } else {
306 fprintf(stderr, "vrpn_Tracker_JsonNet::_parse_analog parse error : missing id\n");
307 return false;
308 }
309
310 if (channelNumber < 0 || channelNumber >= num_channel) {
311 fprintf(stderr, "vrpn_Tracker_JsonNet::_parse_analog id out of bounds %d/%d\n", channelNumber, num_channel);
312 } else {
313 channel[channelNumber] = data;
314 }
315
316 return true;
317}
318
323bool vrpn_Tracker_JsonNet::_network_init(int udp_port)
324{
325 int iResult;
326#ifdef _WIN32
327 {
328 // Initialize Winsock
329 WORD versionRequested = MAKEWORD(2,2);
330 WSADATA wsaData;
331
332 iResult = WSAStartup(versionRequested, &wsaData);
333 if (iResult != 0) {
334 printf("WSAStartup failed with error: %d\n", iResult);
335 return false;
336 }
337 }
338#endif
339
340#ifdef _WIN32
341 {
342 // Create a vrpn_SOCKET for connecting to server
343 _socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
344 if (_socket == INVALID_SOCKET) {
345 printf("socket failed with error: %ld\n", WSAGetLastError());
346 //freeaddrinfo(result);
347 WSACleanup();
348 return false;
349 }
350 }
351#else
352 {
353 int usock;
354
355 usock = socket(PF_INET, SOCK_DGRAM, 0);
356
357 if (usock < 0){
358 return false;
359 }
360 _socket = usock;
361 }
362#endif
363 struct sockaddr_in localSocketAddress;
364 memset((void *)&localSocketAddress, 0, sizeof(localSocketAddress));
365 localSocketAddress.sin_family = AF_INET;
366 localSocketAddress.sin_addr.s_addr = htonl(INADDR_ANY);
367 localSocketAddress.sin_port = htons(udp_port);
368
369 // Setup the listening socket
370 iResult = bind( _socket, (struct sockaddr*)&localSocketAddress, sizeof(localSocketAddress));
371 if (iResult < 0) {
372#ifdef _WIN32
373 printf("bind failed with error: %d\n", WSAGetLastError());
374#else
375 printf("bind failed.");
376#endif
377 //freeaddrinfo(result);
378 _network_release();
379 return false;
380 }
381
382 //freeaddrinfo(result);
383 return true;
384
385}
386
396int vrpn_Tracker_JsonNet::_network_receive(void *buffer, int maxlen, int tout_us)
397{
398 int nbytes, err;
399 fd_set set;
400 struct timeval tout;
401
402 // waiting for data:
403
404 FD_ZERO(&set);
405 FD_SET(_socket, &set);
406
407 tout.tv_sec = tout_us / 1000000;
408 tout.tv_usec = tout_us % 1000000;
409
410 switch((err = select(FD_SETSIZE, &set, NULL, NULL, &tout))){
411 case 1:
412 break; // data available
413 case 0:
414 //fprintf(stderr, "net_receive: select timeout (err = 0)\n");
415 return -1; // timeout
416 break;
417 default:
418 //fprintf(stderr, "net_receive: select error %d\n", err);
419 return -2; // error
420
421 }
422
423 // receiving packet:
424 while(1){
425
426 // receive one packet:
427 nbytes = recv(_socket, (char *)buffer, maxlen, 0);
428 if(nbytes < 0){ // receive error
429 //fprintf(stderr, "recv_receive: select error %d\n", err);
430 return -3;
431 }
432
433 // check, if more data available: if so, receive another packet
434 FD_ZERO(&set);
435 FD_SET(_socket, &set);
436
437 tout.tv_sec = 0; // timeout with value of zero, thus no waiting
438 tout.tv_usec = 0;
439
440 if(select(FD_SETSIZE, &set, NULL, NULL, &tout) != 1){
441 // no more data available: check length of received packet and return
442 if(nbytes >= maxlen){ // buffer overflow
443 return -4;
444 }
445 return nbytes;
446 }
447 }
448}
449
453void vrpn_Tracker_JsonNet::_network_release()
454{
455#ifdef _WIN32
456 closesocket(_socket);
457 WSACleanup();
458#else
459 close(_socket);
460#endif
461}
462
463#endif // defined VRPN_USE_JSONNET
464
virtual void report_changes(vrpn_uint32 class_of_service=vrpn_CONNECTION_LOW_LATENCY, const struct timeval time=vrpn_ANALOG_NOW)
Send a report only if something has changed (for servers) Optionally, tell what time to stamp the val...
Definition vrpn_Analog.C:71
All button servers should derive from this class, which provides the ability to turn any of the butto...
Definition vrpn_Button.h:66
virtual void report_changes(void)
Generic connection class not specific to the transport mechanism.
Allows a user to send text messages from a device (usually,.
Definition vrpn_Text.h:40
virtual int encode_to(char *buf)
#define vrpn_CHANNEL_MAX
Definition vrpn_Analog.h:16
@ vrpn_TEXT_NORMAL
const int vrpn_BUTTON_MAX_BUTTONS
Definition vrpn_Button.h:13
#define INVALID_SOCKET
const vrpn_uint32 vrpn_CONNECTION_LOW_LATENCY
Header allowing use of a output stream-style method of sending text messages from devices.
#define vrpn_gettimeofday