vrpn 07.35
Virtual Reality Peripheral Network
 
Loading...
Searching...
No Matches
vrpn_Imager.C
Go to the documentation of this file.
1#include <stdio.h> // for fprintf, stderr, printf
2#include <string.h> // for memcpy, NULL
3
4#include "vrpn_Imager.h"
5
7 : vrpn_BaseClass(name, c)
8 , d_nRows(0)
9 , d_nCols(0)
10 , d_nDepth(0)
11 , d_nChannels(0)
12{
14}
15
17{
19 d_connection->register_message_type("vrpn_Imager Description");
21 d_connection->register_message_type("vrpn_Imager Begin_Frame");
23 d_connection->register_message_type("vrpn_Imager End_Frame");
25 d_connection->register_message_type("vrpn_Imager Discarded_Frames");
27 d_connection->register_message_type("vrpn_Imager Throttle_Frames");
29 d_connection->register_message_type("vrpn_Imager Regionu8");
31 d_connection->register_message_type("vrpn_Imager Regionu16");
33 d_connection->register_message_type("vrpn_Imager Regionu12in16");
35 d_connection->register_message_type("vrpn_Imager Regionf32");
36 if ((d_description_m_id == -1) || (d_regionu8_m_id == -1) ||
37 (d_regionu16_m_id == -1) || (d_regionf32_m_id == -1) ||
38 (d_begin_frame_m_id == -1) || (d_end_frame_m_id == -1) ||
40 return -1;
41 }
42 else {
43 return 0;
44 }
45}
46
48 vrpn_int32 nCols, vrpn_int32 nRows,
49 vrpn_int32 nDepth)
50 : vrpn_Imager(name, c)
51 , d_description_sent(false)
54{
55 d_nRows = nRows;
56 d_nCols = nCols;
58
59 // Set up callback handler for ping message from client so that it
60 // sends the description. This will make sure that the other side has
61 // heard the descrption before it hears a region message. Also set this up
62 // to fire on the "new connection" system message.
63
67 d_connection->register_message_type(vrpn_got_connection),
69
70 // Set up a handler for the throttle message, which sets how many more
71 // frames to send before dropping them. Also set up a handler for the
72 // last-connection-dropped message, which will cause throttling to go
73 // back to -1.
77 d_connection->register_message_type(vrpn_dropped_last_connection),
79}
80
81int vrpn_Imager_Server::add_channel(const char *name, const char *units,
82 vrpn_float32 minVal, vrpn_float32 maxVal,
83 vrpn_float32 scale, vrpn_float32 offset)
84{
85 if (static_cast<unsigned>(d_nChannels) >= vrpn_IMAGER_MAX_CHANNELS) {
86 return -1;
87 }
89 vrpn_strcpy(d_channels[d_nChannels].units, units);
90 d_channels[d_nChannels].minVal = minVal;
91 d_channels[d_nChannels].maxVal = maxVal;
92 if (scale == 0) {
93 fprintf(
94 stderr,
95 "vrpn_Imager_Server::add_channel(): Scale was zero, set to 1\n");
96 scale = 1;
97 }
98 d_channels[d_nChannels].scale = scale;
99 d_channels[d_nChannels].offset = offset;
100 d_nChannels++;
101
102 // We haven't sent a proper description now
103 d_description_sent = false;
104 return d_nChannels - 1;
105}
106
108 const vrpn_uint16 cMin, const vrpn_uint16 cMax, const vrpn_uint16 rMin,
109 const vrpn_uint16 rMax, const vrpn_uint16 dMin, const vrpn_uint16 dMax,
110 const struct timeval *time)
111{
112 // msgbuf must be float64-aligned! It is the buffer to send to the client
113 vrpn_float64 fbuf[vrpn_CONNECTION_TCP_BUFLEN / sizeof(vrpn_float64)];
114 char *msgbuf = (char *)fbuf;
115 int buflen = sizeof(fbuf);
116 struct timeval timestamp;
117
118 // If we are throttling frames and the frame count has gone to zero,
119 // then increment the number of frames missed and return failure to
120 // send.
121 if (d_frames_to_send == 0) {
123 return false;
124 }
125
126 // If we missed some frames due to throttling, say so.
130 }
131
132 // If we are throttling, then decrement the number of frames
133 // left to send.
134 if (d_frames_to_send > 0) {
136 }
137
138 // Make sure the region request has indices all within the image size.
139 if ((rMax >= d_nRows) || (rMin > rMax)) {
140 fprintf(stderr, "vrpn_Imager_Server::send_begin_frame(): Invalid row "
141 "range (%d..%d)\n",
142 rMin, rMax);
143 return false;
144 }
145 if ((cMax >= d_nCols) || (cMin > cMax)) {
146 fprintf(stderr, "vrpn_Imager_Server::send_begin_frame(): Invalid "
147 "column range (%d..%d)\n",
148 cMin, cMax);
149 return false;
150 }
151 if ((dMax >= d_nDepth) || (dMin > dMax)) {
152 fprintf(stderr, "vrpn_Imager_Server::send_begin_frame(): Invalid depth "
153 "range (%d..%d)\n",
154 dMin, dMax);
155 return false;
156 }
157
158 // If the user didn't specify a time, assume they want "now" and look it up.
159 if (time != NULL) {
160 timestamp = *time;
161 }
162 else {
163 vrpn_gettimeofday(&timestamp, NULL);
164 }
165
166 // Tell what the borders of the region are.
167 if (vrpn_buffer(&msgbuf, &buflen, dMin) ||
168 vrpn_buffer(&msgbuf, &buflen, dMax) ||
169 vrpn_buffer(&msgbuf, &buflen, rMin) ||
170 vrpn_buffer(&msgbuf, &buflen, rMax) ||
171 vrpn_buffer(&msgbuf, &buflen, cMin) ||
172 vrpn_buffer(&msgbuf, &buflen, cMax)) {
173 return false;
174 }
175
176 // Pack the message
177 vrpn_int32 len = sizeof(fbuf) - buflen;
178 if (d_connection &&
179 d_connection->pack_message(len, timestamp, d_begin_frame_m_id,
180 d_sender_id, (char *)(void *)fbuf,
182 fprintf(stderr, "vrpn_Imager_Server::send_begin_frame(): cannot write "
183 "message: tossing\n");
184 return false;
185 }
186
187 return true;
188}
189
191 const vrpn_uint16 cMin, const vrpn_uint16 cMax, const vrpn_uint16 rMin,
192 const vrpn_uint16 rMax, const vrpn_uint16 dMin, const vrpn_uint16 dMax,
193 const struct timeval *time)
194{
195 // msgbuf must be float64-aligned! It is the buffer to send to the client
196 vrpn_float64 fbuf[vrpn_CONNECTION_TCP_BUFLEN / sizeof(vrpn_float64)];
197 char *msgbuf = (char *)fbuf;
198 int buflen = sizeof(fbuf);
199 struct timeval timestamp;
200
201 // If we are discarding frames, return failure to send.
203 return false;
204 }
205
206 // Make sure the region request has indices all within the image size.
207 if ((rMax >= d_nRows) || (rMin > rMax)) {
208 fprintf(stderr, "vrpn_Imager_Server::send_end_frame(): Invalid row "
209 "range (%d..%d)\n",
210 rMin, rMax);
211 return false;
212 }
213 if ((cMax >= d_nCols) || (cMin > cMax)) {
214 fprintf(stderr, "vrpn_Imager_Server::send_end_frame(): Invalid column "
215 "range (%d..%d)\n",
216 cMin, cMax);
217 return false;
218 }
219 if ((dMax >= d_nDepth) || (dMin > dMax)) {
220 fprintf(stderr, "vrpn_Imager_Server::send_end_frame(): Invalid depth "
221 "range (%d..%d)\n",
222 dMin, dMax);
223 return false;
224 }
225
226 // If the user didn't specify a time, assume they want "now" and look it up.
227 if (time != NULL) {
228 timestamp = *time;
229 }
230 else {
231 vrpn_gettimeofday(&timestamp, NULL);
232 }
233
234 // Tell what the borders of the region are.
235 if (vrpn_buffer(&msgbuf, &buflen, dMin) ||
236 vrpn_buffer(&msgbuf, &buflen, dMax) ||
237 vrpn_buffer(&msgbuf, &buflen, rMin) ||
238 vrpn_buffer(&msgbuf, &buflen, rMax) ||
239 vrpn_buffer(&msgbuf, &buflen, cMin) ||
240 vrpn_buffer(&msgbuf, &buflen, cMax)) {
241 return false;
242 }
243
244 // Pack the message
245 vrpn_int32 len = sizeof(fbuf) - buflen;
246 if (d_connection &&
247 d_connection->pack_message(len, timestamp, d_end_frame_m_id,
248 d_sender_id, (char *)(void *)fbuf,
250 fprintf(stderr, "vrpn_Imager_Server::send_end_frame(): cannot write "
251 "message: tossing\n");
252 return false;
253 }
254
255 return true;
256}
257
258bool vrpn_Imager_Server::send_discarded_frames(const vrpn_uint16 count,
259 const struct timeval *time)
260{
261 // msgbuf must be float64-aligned! It is the buffer to send to the client
262 vrpn_float64 fbuf[vrpn_CONNECTION_TCP_BUFLEN / sizeof(vrpn_float64)];
263 char *msgbuf = (char *)fbuf;
264 int buflen = sizeof(fbuf);
265 struct timeval timestamp;
266
267 // If the user didn't specify a time, assume they want "now" and look it up.
268 if (time != NULL) {
269 timestamp = *time;
270 }
271 else {
272 vrpn_gettimeofday(&timestamp, NULL);
273 }
274
275 // Tell how many frames were skipped.
276 if (vrpn_buffer(&msgbuf, &buflen, count)) {
277 return false;
278 }
279
280 // Pack the message
281 vrpn_int32 len = sizeof(fbuf) - buflen;
282 if (d_connection &&
283 d_connection->pack_message(len, timestamp, d_discarded_frames_m_id,
284 d_sender_id, (char *)(void *)fbuf,
286 fprintf(stderr, "vrpn_Imager_Server::send_discarded_frames(): cannot "
287 "write message: tossing\n");
288 return false;
289 }
290
291 return true;
292}
293
294// XXX Re-cast the memcpy loop in terms of offsets (the same way the per-element
295// loop is done) and share base calculation between the two; move the if
296// statement
297// into the inner loop, doing it memcpy or step-at-a-time.
298
319
321 vrpn_int16 chanIndex, vrpn_uint16 cMin, vrpn_uint16 cMax, vrpn_uint16 rMin,
322 vrpn_uint16 rMax, const vrpn_uint8 *data, vrpn_uint32 colStride,
323 vrpn_uint32 rowStride, vrpn_uint16 nRows, bool invert_rows,
324 vrpn_uint32 depthStride, vrpn_uint16 dMin, vrpn_uint16 dMax,
325 const struct timeval *time)
326{
327 // msgbuf must be float64-aligned! It is the buffer to send to the client;
328 vrpn_float64 fbuf[vrpn_CONNECTION_TCP_BUFLEN / sizeof(vrpn_float64)];
329 char *msgbuf = reinterpret_cast<char *>(fbuf);
330 int buflen = sizeof(fbuf);
331 struct timeval timestamp;
332
333 // If we are discarding frames, return failure to send.
335 return false;
336 }
337
338 // Make sure the region request has a valid channel, has indices all
339 // within the image size, and is not too large to fit into the data
340 // array (which is sized the way it is to make sure it can be sent in
341 // one VRPN reliable message).
342 if ((chanIndex < 0) || (chanIndex >= d_nChannels)) {
343 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
344 "Invalid channel index (%d)\n",
345 chanIndex);
346 return false;
347 }
348 if ((dMax >= d_nDepth) || (dMin > dMax)) {
349 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
350 "Invalid depth range (%d..%d)\n",
351 dMin, dMax);
352 return false;
353 }
354 if ((rMax >= d_nRows) || (rMin > rMax)) {
355 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
356 "Invalid row range (%d..%d)\n",
357 rMin, rMax);
358 return false;
359 }
360 if ((cMax >= d_nCols) || (cMin > cMax)) {
361 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
362 "Invalid column range (%d..%d)\n",
363 cMin, cMax);
364 return false;
365 }
366 if (static_cast<unsigned>((rMax - rMin + 1) * (cMax - cMin + 1) *
367 (dMax - dMin + 1)) > vrpn_IMAGER_MAX_REGIONu8) {
368 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
369 "Region too large (%d,%d,%d to %d,%d,%d)\n",
370 cMin, rMin, dMin, cMax, rMax, dMax);
371 return false;
372 }
373 if (invert_rows && (nRows < rMax)) {
374 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
375 "nRows must not be less than rMax\n");
376 return false;
377 }
378
379 // Make sure we've sent the description before we send any regions
380 if (!d_description_sent) {
382 d_description_sent = true;
383 }
384
385 // If the user didn't specify a time, assume they want "now" and look it up.
386 if (time != NULL) {
387 timestamp = *time;
388 }
389 else {
390 vrpn_gettimeofday(&timestamp, NULL);
391 }
392
393 // Check the compression status and prepare to do compression if it is
394 // called for.
395 if (d_channels[chanIndex].d_compression != vrpn_Imager_Channel::NONE) {
396 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
397 "Compression not implemented\n");
398 return false;
399 }
400
401 // Tell which channel this region is for, and what the borders of the
402 // region are.
403 if (vrpn_buffer(&msgbuf, &buflen, chanIndex) ||
404 vrpn_buffer(&msgbuf, &buflen, dMin) ||
405 vrpn_buffer(&msgbuf, &buflen, dMax) ||
406 vrpn_buffer(&msgbuf, &buflen, rMin) ||
407 vrpn_buffer(&msgbuf, &buflen, rMax) ||
408 vrpn_buffer(&msgbuf, &buflen, cMin) ||
409 vrpn_buffer(&msgbuf, &buflen, cMax) ||
410 vrpn_buffer(&msgbuf, &buflen, vrpn_IMAGER_VALTYPE_UINT8)) {
411 return false;
412 }
413
414 // Insert the data into the buffer, copying it as efficiently as possible
415 // from the caller's buffer into the buffer we are going to send. Note that
416 // the send buffer is going to be little-endian. The code looks a little
417 // complicated because it short-circuits the copying for the case where the
418 // column stride is one element long (using memcpy() on each row) but has to
419 // copy one element at a time otherwise.
420 // There is also the matter if deciding whether to invert the image in y,
421 // which complicates the index calculation and the calculation of the
422 // strides.
423 int cols = cMax - cMin + 1;
424 int linelen = cols * sizeof(data[0]);
425 if (colStride == 1) {
426 for (unsigned d = dMin; d <= dMax; d++) {
427 for (unsigned r = rMin; r <= rMax; r++) {
428 unsigned rActual;
429 if (invert_rows) {
430 rActual = (nRows - 1) - r;
431 }
432 else {
433 rActual = r;
434 }
435 if (buflen < linelen) {
436 return false;
437 }
438 memcpy(msgbuf,
439 &data[d * depthStride + rActual * rowStride + cMin],
440 linelen);
441 msgbuf += linelen;
442 buflen -= linelen;
443 }
444 }
445 }
446 else {
447 if (buflen < (int)(sizeof(data[0]) * (dMax - dMin + 1) * (rMax - rMin + 1) *
448 (cMax - cMin + 1))) {
449 return false;
450 }
451 long rowStep = rowStride;
452 if (invert_rows) {
453 rowStep *= -1;
454 }
455 for (unsigned d = dMin; d <= dMax; d++) {
456 // XXX Turn the depth calculation into start and += like the others
457 const vrpn_uint8 *rowStart =
458 &data[d * depthStride + rMin * rowStride + cMin];
459 if (invert_rows) {
460 rowStart = &data[d * depthStride +
461 (nRows - 1 - rMin) * rowStride + cMin];
462 }
463 const vrpn_uint8 *copyFrom = rowStart;
464 for (unsigned r = rMin; r <= rMax; r++) {
465 for (unsigned c = cMin; c <= cMax; c++) {
466 *reinterpret_cast<vrpn_uint8 *>(msgbuf) =
467 *copyFrom; //< Copy the current element
468 msgbuf++; //< Skip to the next buffer location
469 copyFrom +=
470 colStride; //< Skip appropriate number of elements
471 }
472 rowStart += rowStep; //< Skip to the start of the next row
473 copyFrom = rowStart;
474 }
475 }
476 buflen -= sizeof(data[0]) * (rMax - rMin + 1) * (cMax - cMin + 1);
477 }
478
479 // No need to swap endian-ness on single-byte elements.
480
481 // Pack the message
482 vrpn_int32 len = sizeof(fbuf) - buflen;
483 if (d_connection &&
484 d_connection->pack_message(len, timestamp, d_regionu8_m_id, d_sender_id,
485 (char *)(void *)fbuf,
487 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
488 "cannot write message: tossing\n");
489 return false;
490 }
491
492 return true;
493}
494
515
517 vrpn_int16 chanIndex, vrpn_uint16 cMin, vrpn_uint16 cMax, vrpn_uint16 rMin,
518 vrpn_uint16 rMax, const vrpn_uint16 *data, vrpn_uint32 colStride,
519 vrpn_uint32 rowStride, vrpn_uint16 nRows, bool invert_rows,
520 vrpn_uint32 depthStride, vrpn_uint16 dMin, vrpn_uint16 dMax,
521 const struct timeval *time)
522{
523 // msgbuf must be float64-aligned! It is the buffer to send to the client
524 vrpn_float64 fbuf[vrpn_CONNECTION_TCP_BUFLEN / sizeof(vrpn_float64)];
525 char *msgbuf = (char *)fbuf;
526 int buflen = sizeof(fbuf);
527 struct timeval timestamp;
528
529 // If we are discarding frames, return failure to send.
531 return false;
532 }
533
534 // Make sure the region request has a valid channel, has indices all
535 // within the image size, and is not too large to fit into the data
536 // array (which is sized the way it is to make sure it can be sent in
537 // one VRPN reliable message).
538 if ((chanIndex < 0) || (chanIndex >= d_nChannels)) {
539 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
540 "Invalid channel index (%d)\n",
541 chanIndex);
542 return false;
543 }
544 if ((dMax >= d_nDepth) || (dMin > dMax)) {
545 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
546 "Invalid depth range (%d..%d)\n",
547 dMin, dMax);
548 return false;
549 }
550 if ((rMax >= d_nRows) || (rMin > rMax)) {
551 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
552 "Invalid row range (%d..%d)\n",
553 rMin, rMax);
554 return false;
555 }
556 if ((cMax >= d_nCols) || (cMin > cMax)) {
557 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
558 "Invalid column range (%d..%d)\n",
559 cMin, cMax);
560 return false;
561 }
562 if (static_cast<unsigned>((rMax - rMin + 1) * (cMax - cMin + 1) *
563 (dMax - dMin + 1)) > vrpn_IMAGER_MAX_REGIONu16) {
564 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
565 "Region too large (%d,%d,%d to %d,%d,%d)\n",
566 cMin, rMin, dMin, cMax, rMax, dMax);
567 return false;
568 }
569 if (invert_rows && (nRows < rMax)) {
570 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
571 "nRows must not be less than rMax\n");
572 return false;
573 }
574
575 // Make sure we've sent the description before we send any regions
576 if (!d_description_sent) {
578 d_description_sent = true;
579 }
580
581 // If the user didn't specify a time, assume they want "now" and look it up.
582 if (time != NULL) {
583 timestamp = *time;
584 }
585 else {
586 vrpn_gettimeofday(&timestamp, NULL);
587 }
588
589 // Check the compression status and prepare to do compression if it is
590 // called for.
591 if (d_channels[chanIndex].d_compression != vrpn_Imager_Channel::NONE) {
592 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
593 "Compression not implemented\n");
594 return false;
595 }
596
597 // Tell which channel this region is for, and what the borders of the
598 // region are.
599 if (vrpn_buffer(&msgbuf, &buflen, chanIndex) ||
600 vrpn_buffer(&msgbuf, &buflen, dMin) ||
601 vrpn_buffer(&msgbuf, &buflen, dMax) ||
602 vrpn_buffer(&msgbuf, &buflen, rMin) ||
603 vrpn_buffer(&msgbuf, &buflen, rMax) ||
604 vrpn_buffer(&msgbuf, &buflen, cMin) ||
605 vrpn_buffer(&msgbuf, &buflen, cMax) ||
606 vrpn_buffer(&msgbuf, &buflen, vrpn_IMAGER_VALTYPE_UINT16)) {
607 return false;
608 }
609
610 // Insert the data into the buffer, copying it as efficiently as possible
611 // from the caller's buffer into the buffer we are going to send. Note that
612 // the send buffer is going to be little-endian. The code looks a little
613 // complicated because it short-circuits the copying for the case where the
614 // column stride is one element long (using memcpy() on each row) but has to
615 // copy one element at a time otherwise.
616 // There is also the matter if deciding whether to invert the image in y,
617 // which complicates the index calculation and the calculation of the
618 // strides.
619 int cols = cMax - cMin + 1;
620 int linelen = cols * sizeof(data[0]);
621 if (colStride == 1) {
622 for (unsigned d = dMin; d <= dMax; d++) {
623 for (unsigned r = rMin; r <= rMax; r++) {
624 unsigned rActual;
625 if (invert_rows) {
626 rActual = (nRows - 1) - r;
627 }
628 else {
629 rActual = r;
630 }
631 if (buflen < linelen) {
632 return false;
633 }
634 memcpy(msgbuf,
635 &data[d * depthStride + rActual * rowStride + cMin],
636 linelen);
637 msgbuf += linelen;
638 buflen -= linelen;
639 }
640 }
641 }
642 else {
643 if (buflen < (int)(sizeof(data[0]) * (dMax - dMin + 1) * (rMax - rMin + 1) *
644 (cMax - cMin + 1) )) {
645 return false;
646 }
647 long rowStep = rowStride;
648 if (invert_rows) {
649 rowStep *= -1;
650 }
651 for (unsigned d = dMin; d <= dMax; d++) {
652 // XXX Turn the depth calculation into start and += like the others
653 const vrpn_uint16 *rowStart =
654 &data[d * depthStride + rMin * rowStride + cMin];
655 if (invert_rows) {
656 rowStart = &data[d * depthStride +
657 (nRows - 1 - rMin) * rowStride + cMin];
658 }
659 const vrpn_uint16 *copyFrom = rowStart;
660 for (unsigned r = rMin; r <= rMax; r++) {
661 for (unsigned c = cMin; c <= cMax; c++) {
662 memcpy(msgbuf, copyFrom, sizeof(*copyFrom));
663 msgbuf +=
664 sizeof(*copyFrom); //< Skip to the next buffer location
665 copyFrom +=
666 colStride; //< Skip appropriate number of elements
667 }
668 rowStart += rowStep; //< Skip to the start of the next row
669 copyFrom = rowStart;
670 }
671 }
672 buflen -= sizeof(data[0]) * (rMax - rMin + 1) * (cMax - cMin + 1);
673 }
674
675 // Swap endian-ness of the buffer if we are on a big-endian machine.
676 if (vrpn_big_endian) {
677 fprintf(stderr, "XXX Imager Region needs swapping on Big-endian\n");
678 return false;
679 }
680
681 // Pack the message
682 vrpn_int32 len = sizeof(fbuf) - buflen;
683 if (d_connection &&
684 d_connection->pack_message(len, timestamp, d_regionu16_m_id,
685 d_sender_id, (char *)(void *)fbuf,
687 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
688 "cannot write message: tossing\n");
689 return false;
690 }
691
692 return true;
693}
694
715
717 vrpn_int16 chanIndex, vrpn_uint16 cMin, vrpn_uint16 cMax, vrpn_uint16 rMin,
718 vrpn_uint16 rMax, const vrpn_float32 *data, vrpn_uint32 colStride,
719 vrpn_uint32 rowStride, vrpn_uint16 nRows, bool invert_rows,
720 vrpn_uint32 depthStride, vrpn_uint16 dMin, vrpn_uint16 dMax,
721 const struct timeval *time)
722{
723 // msgbuf must be float64-aligned! It is the buffer to send to the client
724 vrpn_float64 fbuf[vrpn_CONNECTION_TCP_BUFLEN / sizeof(vrpn_float64)];
725 char *msgbuf = (char *)fbuf;
726 int buflen = sizeof(fbuf);
727 struct timeval timestamp;
728
729 // If we are discarding frames, return failure to send.
731 return false;
732 }
733
734 // Make sure the region request has a valid channel, has indices all
735 // within the image size, and is not too large to fit into the data
736 // array (which is sized the way it is to make sure it can be sent in
737 // one VRPN reliable message).
738 if ((chanIndex < 0) || (chanIndex >= d_nChannels)) {
739 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
740 "Invalid channel index (%d)\n",
741 chanIndex);
742 return false;
743 }
744 if ((dMax >= d_nDepth) || (dMin > dMax)) {
745 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
746 "Invalid depth range (%d..%d)\n",
747 dMin, dMax);
748 return false;
749 }
750 if ((rMax >= d_nRows) || (rMin > rMax)) {
751 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
752 "Invalid row range (%d..%d)\n",
753 rMin, rMax);
754 return false;
755 }
756 if ((cMax >= d_nCols) || (cMin > cMax)) {
757 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
758 "Invalid column range (%d..%d)\n",
759 cMin, cMax);
760 return false;
761 }
762 if (static_cast<unsigned>((rMax - rMin + 1) * (cMax - cMin + 1) *
763 (dMax - dMin + 1)) > vrpn_IMAGER_MAX_REGIONf32) {
764 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
765 "Region too large (%d,%d,%d to %d,%d,%d)\n",
766 cMin, rMin, dMin, cMax, rMax, dMax);
767 return false;
768 }
769 if (invert_rows && (nRows < rMax)) {
770 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
771 "nRows must not be less than rMax\n");
772 return false;
773 }
774
775 // Make sure we've sent the description before we send any regions
776 if (!d_description_sent) {
778 d_description_sent = true;
779 }
780
781 // If the user didn't specify a time, assume they want "now" and look it up.
782 if (time != NULL) {
783 timestamp = *time;
784 }
785 else {
786 vrpn_gettimeofday(&timestamp, NULL);
787 }
788
789 // Check the compression status and prepare to do compression if it is
790 // called for.
791 if (d_channels[chanIndex].d_compression != vrpn_Imager_Channel::NONE) {
792 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
793 "Compression not implemented\n");
794 return false;
795 }
796
797 // Tell which channel this region is for, and what the borders of the
798 // region are.
799 if (vrpn_buffer(&msgbuf, &buflen, chanIndex) ||
800 vrpn_buffer(&msgbuf, &buflen, dMin) ||
801 vrpn_buffer(&msgbuf, &buflen, dMax) ||
802 vrpn_buffer(&msgbuf, &buflen, rMin) ||
803 vrpn_buffer(&msgbuf, &buflen, rMax) ||
804 vrpn_buffer(&msgbuf, &buflen, cMin) ||
805 vrpn_buffer(&msgbuf, &buflen, cMax) ||
806 vrpn_buffer(&msgbuf, &buflen, vrpn_IMAGER_VALTYPE_FLOAT32)) {
807 return false;
808 }
809
810 // Insert the data into the buffer, copying it as efficiently as possible
811 // from the caller's buffer into the buffer we are going to send. Note that
812 // the send buffer is going to be little-endian. The code looks a little
813 // complicated because it short-circuits the copying for the case where the
814 // column stride is one element long (using memcpy() on each row) but has to
815 // copy one element at a time otherwise.
816 // There is also the matter if deciding whether to invert the image in y,
817 // which complicates the index calculation and the calculation of the
818 // strides.
819 int cols = cMax - cMin + 1;
820 int linelen = cols * sizeof(data[0]);
821 if (colStride == 1) {
822 for (unsigned d = dMin; d <= dMax; d++) {
823 for (unsigned r = rMin; r <= rMax; r++) {
824 unsigned rActual;
825 if (invert_rows) {
826 rActual = (nRows - 1) - r;
827 }
828 else {
829 rActual = r;
830 }
831 if (buflen < linelen) {
832 return false;
833 }
834 memcpy(msgbuf,
835 &data[d * depthStride + rActual * rowStride + cMin],
836 linelen);
837 msgbuf += linelen;
838 buflen -= linelen;
839 }
840 }
841 }
842 else {
843 if (buflen < (int)(sizeof(data[0]) * (dMax - dMin + 1) * (rMax - rMin + 1) *
844 (cMax - cMin + 1))) {
845 return false;
846 }
847 long rowStep = rowStride;
848 if (invert_rows) {
849 rowStep *= -1;
850 }
851 for (unsigned d = dMin; d <= dMax; d++) {
852 // XXX Turn the depth calculation into start and += like the others
853 const vrpn_float32 *rowStart =
854 &data[d * depthStride + rMin * rowStride + cMin];
855 if (invert_rows) {
856 rowStart = &data[d * depthStride +
857 (nRows - 1 - rMin) * rowStride + cMin];
858 }
859 const vrpn_float32 *copyFrom = rowStart;
860 for (unsigned r = rMin; r <= rMax; r++) {
861 for (unsigned c = cMin; c <= cMax; c++) {
862 memcpy(msgbuf, copyFrom, sizeof(*copyFrom));
863 msgbuf +=
864 sizeof(*copyFrom); //< Skip to the next buffer location
865 copyFrom +=
866 colStride; //< Skip appropriate number of elements
867 }
868 rowStart += rowStep; //< Skip to the start of the next row
869 copyFrom = rowStart;
870 }
871 }
872 buflen -= sizeof(data[0]) * (rMax - rMin + 1) * (cMax - cMin + 1);
873 }
874
875 // Swap endian-ness of the buffer if we are on a big-endian machine.
876 if (vrpn_big_endian) {
877 fprintf(stderr, "XXX Imager Region needs swapping on Big-endian\n");
878 return false;
879 }
880
881 // Pack the message
882 vrpn_int32 len = sizeof(fbuf) - buflen;
883 if (d_connection &&
884 d_connection->pack_message(len, timestamp, d_regionf32_m_id,
885 d_sender_id, (char *)(void *)fbuf,
887 fprintf(stderr, "vrpn_Imager_Server::send_region_using_base_pointer(): "
888 "cannot write message: tossing\n");
889 return false;
890 }
891
892 return true;
893}
894
916
918 vrpn_int16 chanIndex, vrpn_uint16 cMin, vrpn_uint16 cMax, vrpn_uint16 rMin,
919 vrpn_uint16 rMax, const vrpn_uint8 *data, vrpn_uint32 colStride,
920 vrpn_uint32 rowStride, vrpn_uint16 nRows, bool invert_rows,
921 vrpn_uint32 depthStride, vrpn_uint16 dMin, vrpn_uint16 dMax,
922 const struct timeval *time)
923{
924 // If we are discarding frames, return failure to send.
926 return false;
927 }
928
929 // Point the data pointer back before the first pointer, to the place it
930 // should be to make the index math work out.
931 const vrpn_uint8 *new_base =
932 data - (cMin + rowStride * rMin + depthStride * dMin);
934 chanIndex, cMin, cMax, rMin, rMax, new_base, colStride, rowStride,
935 nRows, invert_rows, depthStride, dMin, dMax, time)) {
936 return true;
937 }
938 else {
939 fprintf(stderr, "vrpn_Imager_Server::send_region_using_first_pointer():"
940 " Call to send using offset base_pointer failed.\n");
941 return false;
942 }
943}
944
966
968 vrpn_int16 chanIndex, vrpn_uint16 cMin, vrpn_uint16 cMax, vrpn_uint16 rMin,
969 vrpn_uint16 rMax, const vrpn_uint16 *data, vrpn_uint32 colStride,
970 vrpn_uint32 rowStride, vrpn_uint16 nRows, bool invert_rows,
971 vrpn_uint32 depthStride, vrpn_uint16 dMin, vrpn_uint16 dMax,
972 const struct timeval *time)
973{
974 // If we are discarding frames, return failure to send.
976 return false;
977 }
978
979 // Point the data pointer back before the first pointer, to the place it
980 // should be to make the index math work out.
981 const vrpn_uint16 *new_base =
982 data - (cMin + rowStride * rMin + depthStride * dMin);
984 chanIndex, cMin, cMax, rMin, rMax, new_base, colStride, rowStride,
985 nRows, invert_rows, depthStride, dMin, dMax, time)) {
986 return true;
987 }
988 else {
989 fprintf(stderr, "vrpn_Imager_Server::send_region_using_first_pointer():"
990 " Call to send using offset base_pointer failed.\n");
991 return false;
992 }
993}
994
1016
1018 vrpn_int16 chanIndex, vrpn_uint16 cMin, vrpn_uint16 cMax, vrpn_uint16 rMin,
1019 vrpn_uint16 rMax, const vrpn_float32 *data, vrpn_uint32 colStride,
1020 vrpn_uint32 rowStride, vrpn_uint16 nRows, bool invert_rows,
1021 vrpn_uint32 depthStride, vrpn_uint16 dMin, vrpn_uint16 dMax,
1022 const struct timeval *time)
1023{
1024 // If we are discarding frames, return failure to send.
1025 if (d_dropped_due_to_throttle > 0) {
1026 return false;
1027 }
1028
1029 // Point the data pointer back before the first pointer, to the place it
1030 // should be to make the index math work out.
1031 const vrpn_float32 *new_base =
1032 data - (cMin + rowStride * rMin + depthStride * dMin);
1034 chanIndex, cMin, cMax, rMin, rMax, new_base, colStride, rowStride,
1035 nRows, invert_rows, depthStride, dMin, dMax, time)) {
1036 return true;
1037 }
1038 else {
1039 fprintf(stderr, "vrpn_Imager_Server::send_region_using_first_pointer():"
1040 " Call to send using offset base_pointer failed.\n");
1041 return false;
1042 }
1043}
1044
1046{
1047 // msgbuf must be float64-aligned!
1048 vrpn_float64 fbuf[vrpn_CONNECTION_TCP_BUFLEN / sizeof(vrpn_float64)];
1049 char *msgbuf = (char *)fbuf;
1050 int buflen = sizeof(fbuf);
1051 struct timeval timestamp;
1052 int i;
1053
1054 // Pack the description of all of the fields in the imager into the buffer,
1055 // including the channel descriptions.
1056 if (vrpn_buffer(&msgbuf, &buflen, d_nDepth) ||
1057 vrpn_buffer(&msgbuf, &buflen, d_nRows) ||
1058 vrpn_buffer(&msgbuf, &buflen, d_nCols) ||
1059 vrpn_buffer(&msgbuf, &buflen, d_nChannels)) {
1060 fprintf(stderr, "vrpn_Imager_Server::send_description(): Can't pack "
1061 "message header, tossing\n");
1062 return false;
1063 }
1064 for (i = 0; i < d_nChannels; i++) {
1065 if (!d_channels[i].buffer(&msgbuf, &buflen)) {
1066 fprintf(stderr, "vrpn_Imager_Server::send_description(): Can't "
1067 "pack message channel, tossing\n");
1068 return false;
1069 }
1070 }
1071
1072 // Pack the buffer into the connection's outgoing reliable queue, if we have
1073 // a valid connection.
1074 vrpn_int32 len = sizeof(fbuf) - buflen;
1075 vrpn_gettimeofday(&timestamp, NULL);
1076 if (d_connection &&
1077 d_connection->pack_message(len, timestamp, d_description_m_id,
1078 d_sender_id, (char *)(void *)fbuf,
1080 fprintf(stderr, "vrpn_Imager_Server::send_description(): cannot write "
1081 "message: tossing\n");
1082 return false;
1083 }
1084
1085 d_description_sent = true;
1086 return true;
1087}
1088
1090 vrpn_int32 nDepth)
1091{
1092 if ((nCols <= 0) || (nRows <= 0) || (nDepth <= 0)) {
1093 fprintf(
1094 stderr,
1095 "vrpn_Imager_Server::set_resolution(): Invalid size (%d, %d, %d)\n",
1096 nCols, nRows, nDepth);
1097 return false;
1098 }
1099 d_nDepth = nDepth;
1100 d_nCols = nCols;
1101 d_nRows = nRows;
1102 return send_description();
1103}
1104
1106
1113
1116{
1117 const char *bufptr = p.buffer;
1119
1120 // Get the requested number of frames from the buffer
1121 vrpn_int32 frames_to_send;
1122 if (vrpn_unbuffer(&bufptr, &frames_to_send)) {
1123 return -1;
1124 }
1125
1126 // If the requested number of frames is negative, then we set
1127 // for unbounded sending. The next time a begin_frame message
1128 // is sent, it will start the process going again.
1129 if (frames_to_send < 0) {
1130 me->d_frames_to_send = -1;
1131 return 0;
1132 }
1133
1134 // If we were sending continuously, store the number of frames
1135 // to send.
1136 if (me->d_frames_to_send == -1) {
1137 me->d_frames_to_send = frames_to_send;
1138
1139 // If we already had a throttle limit set, then increment it
1140 // by the count.
1141 }
1142 else {
1143 me->d_frames_to_send += frames_to_send;
1144 }
1145
1146 return 0;
1147}
1148
1151{
1153
1154 // Last connection has dropped, so set the throttling behavior back to
1155 // the default, which is to send as fast as we can.
1156 me->d_frames_to_send = -1;
1158 return 0;
1159}
1160
1162 : vrpn_Imager(name, c)
1163 , d_got_description(false)
1164{
1165 // Register the handlers for the description message and the region change
1166 // messages
1168 this, d_sender_id);
1169
1170 // Register the region-handling messages for the different message types.
1171 // All of the types use the same handler, since the type of region is
1172 // encoded
1173 // in one of the parameters of the region function.
1175 d_sender_id);
1177 d_sender_id);
1179 d_sender_id);
1181 this, d_sender_id);
1183 this, d_sender_id);
1186 d_sender_id);
1187
1188 // Register the handler for the connection dropped message
1190 d_connection->register_message_type(vrpn_dropped_connection),
1192}
1193
1195{
1197 if (d_connection) {
1198 d_connection->mainloop();
1199 };
1200}
1201
1203{
1204 if (chanNum >= (unsigned)d_nChannels) {
1205 return NULL;
1206 }
1207 return &d_channels[chanNum];
1208}
1209
1212{
1213 const char *bufptr = p.buffer;
1215 int i;
1216
1217 // Get my new information from the buffer
1218 if (vrpn_unbuffer(&bufptr, &me->d_nDepth) ||
1219 vrpn_unbuffer(&bufptr, &me->d_nRows) ||
1220 vrpn_unbuffer(&bufptr, &me->d_nCols) ||
1221 vrpn_unbuffer(&bufptr, &me->d_nChannels)) {
1222 return -1;
1223 }
1224 for (i = 0; i < me->d_nChannels; i++) {
1225 if (!me->d_channels[i].unbuffer(&bufptr)) {
1226 return -1;
1227 }
1228 }
1229
1230 // Go down the list of callbacks that have been registered.
1231 // Fill in the parameter and call each.
1233
1234 me->d_got_description = true;
1235 return 0;
1236}
1237
1240{
1241 const char *bufptr = p.buffer;
1245
1246 // Create an instance of a region helper class and read its
1247 // parameters from the buffer (setting its _valBuf pointer at
1248 // the start of the data in the buffer). Set it to valid and then
1249 // call the user callback and then set it to invalid before
1250 // deleting it.
1251 if (vrpn_unbuffer(&bufptr, &reg.d_chanIndex) ||
1252 vrpn_unbuffer(&bufptr, &reg.d_dMin) ||
1253 vrpn_unbuffer(&bufptr, &reg.d_dMax) ||
1254 vrpn_unbuffer(&bufptr, &reg.d_rMin) ||
1255 vrpn_unbuffer(&bufptr, &reg.d_rMax) ||
1256 vrpn_unbuffer(&bufptr, &reg.d_cMin) ||
1257 vrpn_unbuffer(&bufptr, &reg.d_cMax) ||
1258 vrpn_unbuffer(&bufptr, &reg.d_valType)) {
1259 fprintf(stderr, "vrpn_Imager_Remote::handle_region_message(): Can't "
1260 "unbuffer parameters!\n");
1261 return -1;
1262 }
1263 reg.d_valBuf = bufptr;
1264 reg.d_valid = true;
1265
1266 // Check the compression status and prepare to do decompression if it is
1267 // called for.
1268 if (me->d_channels[reg.d_chanIndex].d_compression !=
1270 fprintf(stderr, "vrpn_Imager_Remote::handle_region_message(): "
1271 "Compression not implemented\n");
1272 return -1;
1273 }
1274
1275 // Fill in a user callback structure with the data
1276 rp.msg_time = p.msg_time;
1277 rp.region = &reg;
1278
1279 // ONLY if we have gotten a description message,
1280 // Go down the list of callbacks that have been registered.
1281 // Fill in the parameter and call each.
1282 if (me->d_got_description) {
1284 }
1285
1286 reg.d_valid = false;
1287 return 0;
1288}
1289
1292{
1293 const char *bufptr = p.buffer;
1296
1297 bf.msg_time = p.msg_time;
1298 if (vrpn_unbuffer(&bufptr, &bf.dMin) || vrpn_unbuffer(&bufptr, &bf.dMax) ||
1299 vrpn_unbuffer(&bufptr, &bf.rMin) || vrpn_unbuffer(&bufptr, &bf.rMax) ||
1300 vrpn_unbuffer(&bufptr, &bf.cMin) || vrpn_unbuffer(&bufptr, &bf.cMax)) {
1301 fprintf(stderr, "vrpn_Imager_Remote::handle_begin_frame_message(): "
1302 "Can't unbuffer parameters!\n");
1303 return -1;
1304 }
1305
1306 // ONLY if we have gotten a description message,
1307 // Go down the list of callbacks that have been registered.
1308 // Fill in the parameter and call each.
1309 if (me->d_got_description) {
1311 }
1312
1313 return 0;
1314}
1315
1318{
1319 const char *bufptr = p.buffer;
1322
1323 ef.msg_time = p.msg_time;
1324 if (vrpn_unbuffer(&bufptr, &ef.dMin) || vrpn_unbuffer(&bufptr, &ef.dMax) ||
1325 vrpn_unbuffer(&bufptr, &ef.rMin) || vrpn_unbuffer(&bufptr, &ef.rMax) ||
1326 vrpn_unbuffer(&bufptr, &ef.cMin) || vrpn_unbuffer(&bufptr, &ef.cMax)) {
1327 fprintf(stderr, "vrpn_Imager_Remote::handle_end_frame_message(): Can't "
1328 "unbuffer parameters!\n");
1329 return -1;
1330 }
1331
1332 // ONLY if we have gotten a description message,
1333 // Go down the list of callbacks that have been registered.
1334 // Fill in the parameter and call each.
1335 if (me->d_got_description) {
1337 }
1338
1339 return 0;
1340}
1341
1344{
1345 const char *bufptr = p.buffer;
1348
1349 df.msg_time = p.msg_time;
1350 if (vrpn_unbuffer(&bufptr, &df.count)) {
1351 fprintf(stderr, "vrpn_Imager_Remote::handle_discarded_frames_message():"
1352 " Can't unbuffer parameters!\n");
1353 return -1;
1354 }
1355
1356 // ONLY if we have gotten a description message,
1357 // Go down the list of callbacks that have been registered.
1358 // Fill in the parameter and call each.
1359 if (me->d_got_description) {
1361 }
1362
1363 return 0;
1364}
1365
1368{
1370
1371 // We have no description message, so don't call region callbacks
1372 me->d_got_description = false;
1373
1374 return 0;
1375}
1376
1378{
1379 // msgbuf must be float64-aligned!
1380 vrpn_float64 fbuf[vrpn_CONNECTION_TCP_BUFLEN / sizeof(vrpn_float64)];
1381 char *msgbuf = (char *)fbuf;
1382 int buflen = sizeof(fbuf);
1383 struct timeval timestamp;
1384
1385 // Pack the throttle count request.
1386 if (vrpn_buffer(&msgbuf, &buflen, N)) {
1387 fprintf(stderr, "vrpn_ImagerPose_Server::throttle_sender(): Can't pack "
1388 "message header, tossing\n");
1389 return false;
1390 }
1391
1392 // Pack the buffer into the connection's outgoing reliable queue, if we have
1393 // a valid connection.
1394 vrpn_int32 len = sizeof(fbuf) - buflen;
1395 vrpn_gettimeofday(&timestamp, NULL);
1396 if (d_connection &&
1397 d_connection->pack_message(len, timestamp, d_throttle_frames_m_id,
1398 d_sender_id, (char *)(void *)fbuf,
1400 fprintf(stderr, "vrpn_ImagerPose_Server::throttle_sender(): cannot "
1401 "write message: tossing\n");
1402 return false;
1403 }
1404
1405 return true;
1406}
1407
1440
1442 vrpn_uint8 *data, vrpn_uint32 colStride, vrpn_uint32 rowStride,
1443 vrpn_uint32 depthStride, vrpn_uint16 nRows, bool invert_rows,
1444 unsigned repeat) const
1445{
1446 // Make sure the parameters are reasonable
1447 if (colStride < repeat) {
1448 fprintf(stderr, "vrpn_Imager_Region::decode_unscaled_region_using_base_"
1449 "pointer(): colStride must be >= repeat\n");
1450 return false;
1451 }
1452
1453 if (invert_rows && (nRows < d_rMax)) {
1454 fprintf(stderr, "vrpn_Imager_Region::decode_unscaled_region_using_base_"
1455 "pointer(): nRows must not be less than _rMax\n");
1456 return false;
1457 }
1458
1459 // If the type of data in the buffer doesn't match the type of data the user
1460 // wants, we need to convert each element along the way.
1462 // The data type matches what we the user is asking for. No transcoding
1463 // needed.
1464 // Insert the data into the buffer, copying it as efficiently as
1465 // possible
1466 // from the network buffer into the caller's buffer . Note that
1467 // the network buffer is little-endian. The code looks a little
1468 // complicated because it short-circuits the copying for the case where
1469 // the
1470 // column stride and repeat are one element long (using memcpy() on each
1471 // row) but has to
1472 // copy one element at a time otherwise.
1473 int cols = d_cMax - d_cMin + 1;
1474 int linelen = cols * sizeof(data[0]);
1475 if ((colStride == 1) && (repeat == 1)) {
1476 const vrpn_uint8 *msgbuf = (const vrpn_uint8 *)d_valBuf;
1477 for (unsigned d = d_dMin; d <= d_dMax; d++) {
1478 for (unsigned r = d_rMin; r <= d_rMax; r++) {
1479 unsigned rActual;
1480 if (invert_rows) {
1481 rActual = (nRows - 1) - r;
1482 }
1483 else {
1484 rActual = r;
1485 }
1486 memcpy(
1487 &data[d * depthStride + rActual * rowStride + d_cMin],
1488 msgbuf, linelen);
1489 msgbuf += linelen;
1490 }
1491 }
1492 }
1493 else {
1494 long rowStep = rowStride;
1495 if (invert_rows) {
1496 rowStep *= -1;
1497 }
1498 const vrpn_uint8 *msgbuf = (const vrpn_uint8 *)d_valBuf;
1499 for (unsigned d = d_dMin; d <= d_dMax; d++) {
1500 vrpn_uint8 *rowStart =
1501 &data[d * depthStride + d_rMin * rowStride +
1502 d_cMin * repeat];
1503 if (invert_rows) {
1504 rowStart = &data[d * depthStride +
1505 (nRows - 1 - d_rMin) * rowStride +
1506 d_cMin * repeat];
1507 }
1508 vrpn_uint8 *copyTo = rowStart;
1509 for (unsigned r = d_rMin; r <= d_rMax; r++) {
1510 for (unsigned c = d_cMin; c <= d_cMax; c++) {
1511 for (unsigned rpt = 0; rpt < repeat; rpt++) {
1512 *(copyTo + rpt) =
1513 *msgbuf; //< Copy the current element
1514 }
1515 msgbuf++; //< Skip to the next buffer location
1516 copyTo +=
1517 colStride; //< Skip appropriate number of elements
1518 }
1519 rowStart += rowStep; //< Skip to the start of the next row
1520 copyTo = rowStart;
1521 }
1522 }
1523 }
1524 }
1526 // Transcode from 32-bit floating-point to 8-bit values during the
1527 // conversion process.
1528 // As this is unscaled, we do not adjust the values -- simply jam the
1529 // values in and
1530 // let C++ conversion do the work for us.
1531
1532 // Swap endian-ness of the buffer if we are on a big-endian machine.
1533 if (vrpn_big_endian) {
1534 fprintf(stderr, "XXX Imager Region needs swapping on Big-endian\n");
1535 return false;
1536 }
1537
1538 long rowStep = rowStride;
1539 if (invert_rows) {
1540 rowStep *= -1;
1541 }
1542 const vrpn_float32 *msgbuf = (const vrpn_float32 *)d_valBuf;
1543 for (unsigned d = d_dMin; d <= d_dMax; d++) {
1544 vrpn_uint8 *rowStart =
1545 &data[d * depthStride + d_rMin * rowStride + d_cMin * repeat];
1546 if (invert_rows) {
1547 rowStart =
1548 &data[d * depthStride + (nRows - 1 - d_rMin) * rowStride +
1549 d_cMin * repeat];
1550 }
1551 vrpn_uint8 *copyTo = rowStart;
1552 for (unsigned r = d_rMin; r <= d_rMax; r++) {
1553 for (unsigned c = d_cMin; c <= d_cMax; c++) {
1554 for (unsigned rpt = 0; rpt < repeat; rpt++) {
1555 *(copyTo + rpt) = static_cast<vrpn_uint8>(
1556 *msgbuf); //< Copy the current element
1557 }
1558 msgbuf++; //< Skip to the next buffer location
1559 copyTo += colStride; //< Skip appropriate number of elements
1560 }
1561 rowStart += rowStep; //< Skip to the start of the next row
1562 copyTo = rowStart;
1563 }
1564 }
1565 }
1567 // transcode from 16 bit image to 8 bit data for app
1568
1569 long rowStep = rowStride;
1570 if (invert_rows) {
1571 rowStep *= -1;
1572 }
1573 const vrpn_uint16 *msgbuf = (const vrpn_uint16 *)d_valBuf;
1574 for (unsigned d = d_dMin; d <= d_dMax; d++) {
1575 vrpn_uint8 *rowStart =
1576 &data[d * depthStride + d_rMin * rowStride + d_cMin * repeat];
1577 if (invert_rows) {
1578 rowStart =
1579 &data[d * depthStride + (nRows - 1 - d_rMin) * rowStride +
1580 d_cMin * repeat];
1581 }
1582 vrpn_uint8 *copyTo = rowStart;
1583 for (unsigned r = d_rMin; r <= d_rMax; r++) {
1584 for (unsigned c = d_cMin; c <= d_cMax; c++) {
1585 for (unsigned rpt = 0; rpt < repeat; rpt++) {
1586 *(copyTo + rpt) = static_cast<vrpn_uint8>(
1587 (*msgbuf) >>
1588 8); //< Copy the current element (take top 8 bits)
1589 }
1590 msgbuf++; //< Skip to the next buffer location
1591 copyTo += colStride; //< Skip appropriate number of elements
1592 }
1593 rowStart += rowStep; //< Skip to the start of the next row
1594 copyTo = rowStart;
1595 }
1596 }
1597 }
1598 else {
1599 printf("vrpn_Imager_Region::decode_unscaled_region_using_base_pointer()"
1600 ": Transcoding not implemented yet for this type\n");
1601 printf("d_valType = %i\n", d_valType);
1602 return false;
1603 }
1604
1605 // No need to swap endianness on single-byte entities.
1606 return true;
1607}
1608
1609// This routine handles both 16-bit and 12-bit-in-16 iamges.
1611 vrpn_uint16 *data, vrpn_uint32 colStride, vrpn_uint32 rowStride,
1612 vrpn_uint32 depthStride, vrpn_uint16 nRows, bool invert_rows,
1613 unsigned repeat) const
1614{
1615 // Make sure the parameters are reasonable
1616 if (colStride < repeat) {
1617 fprintf(stderr, "vrpn_Imager_Region::decode_unscaled_region_using_base_"
1618 "pointer(): colStride must be >= repeat\n");
1619 return false;
1620 }
1621 if (invert_rows && (nRows < d_rMax)) {
1622 fprintf(stderr, "vrpn_Imager_Region::decode_unscaled_region_using_base_"
1623 "pointer(): nRows must not be less than _rMax\n");
1624 return false;
1625 }
1626
1627 // If the type of data in the buffer matches the type of data the user
1628 // wants, no need to convert each element along the way.
1631
1632 // The data type matches what we the user is asking for. No transcoding
1633 // needed.
1634 // Insert the data into the buffer, copying it as efficiently as
1635 // possible
1636 // from the network buffer into the caller's buffer . Note that
1637 // the network buffer is little-endian. The code looks a little
1638 // complicated because it short-circuits the copying for the case where
1639 // the
1640 // column stride and repeat are one element long (using memcpy() on each
1641 // row) but has to
1642 // copy one element at a time otherwise.
1643 int cols = d_cMax - d_cMin + 1;
1644 int linelen = cols * sizeof(data[0]);
1645 if ((colStride == 1) && (repeat == 1)) {
1646 const vrpn_uint16 *msgbuf = (const vrpn_uint16 *)d_valBuf;
1647 for (unsigned d = d_dMin; d <= d_dMax; d++) {
1648 for (unsigned r = d_rMin; r <= d_rMax; r++) {
1649 unsigned rActual;
1650 if (invert_rows) {
1651 rActual = (nRows - 1) - r;
1652 }
1653 else {
1654 rActual = r;
1655 }
1656 memcpy(
1657 &data[d * depthStride + rActual * rowStride + d_cMin],
1658 msgbuf, linelen);
1659 msgbuf += cols;
1660 }
1661 }
1662 }
1663 else {
1664 long rowStep = rowStride;
1665 if (invert_rows) {
1666 rowStep *= -1;
1667 }
1668 const vrpn_uint16 *msgbuf = (const vrpn_uint16 *)d_valBuf;
1669 for (unsigned d = d_dMin; d <= d_dMax; d++) {
1670 vrpn_uint16 *rowStart =
1671 &data[d * depthStride + d_rMin * rowStride +
1672 d_cMin * repeat];
1673 if (invert_rows) {
1674 rowStart = &data[d * depthStride +
1675 (nRows - 1 - d_rMin) * rowStride +
1676 d_cMin * repeat];
1677 }
1678 vrpn_uint16 *copyTo = rowStart;
1679 for (unsigned r = d_rMin; r <= d_rMax; r++) {
1680 for (unsigned c = d_cMin; c <= d_cMax; c++) {
1681 for (unsigned rpt = 0; rpt < repeat; rpt++) {
1682 *(copyTo + rpt) =
1683 *msgbuf; //< Copy the current element
1684 }
1685 msgbuf++; //< Skip to the next buffer location
1686 copyTo +=
1687 colStride; //< Skip appropriate number of elements
1688 }
1689 rowStart += rowStep; //< Skip to the start of the next row
1690 copyTo = rowStart;
1691 }
1692 }
1693 }
1694
1695 // The data type sent does not match the type asked for. We will need
1696 // to trans-code
1697 // from the format it is in to the format they want.
1698 }
1700 // Convert from unsigned integer 8-bit to unsigned integer 16-bit
1701 // by shifting each left 8 bits (same as multiplying by 256). Note
1702 // that this does not map 255 to the maximum 16-bit value, but doing
1703 // that would require either floating-point math or precomputing that
1704 // math and using table look-up.
1705 long rowStep = rowStride;
1706 if (invert_rows) {
1707 rowStep *= -1;
1708 }
1709 const vrpn_uint8 *msgbuf = (const vrpn_uint8 *)d_valBuf;
1710 for (unsigned d = d_dMin; d <= d_dMax; d++) {
1711 vrpn_uint16 *rowStart =
1712 &data[d * depthStride + d_rMin * rowStride + d_cMin * repeat];
1713 if (invert_rows) {
1714 rowStart =
1715 &data[d * depthStride + (nRows - 1 - d_rMin) * rowStride +
1716 d_cMin * repeat];
1717 }
1718 vrpn_uint16 *copyTo = rowStart;
1719 for (unsigned r = d_rMin; r <= d_rMax; r++) {
1720 for (unsigned c = d_cMin; c <= d_cMax; c++) {
1721 for (unsigned rpt = 0; rpt < repeat; rpt++) {
1722 //< Shift and copy the current element
1723 *(copyTo + rpt) =
1724 (static_cast<vrpn_uint16>(*msgbuf) << 8);
1725 }
1726 msgbuf++; //< Skip to the next buffer location
1727 copyTo += colStride; //< Skip appropriate number of elements
1728 }
1729 rowStart += rowStep; //< Skip to the start of the next row
1730 copyTo = rowStart;
1731 }
1732 }
1733 }
1734 else {
1735 fprintf(stderr, "vrpn_Imager_Region::decode_unscaled_region_using_base_"
1736 "pointer(): XXX Transcoding this type not yet "
1737 "implemented\n");
1738 return false;
1739 }
1740
1741 // Swap endian-ness of the buffer if we are on a big-endian machine.
1742 if (vrpn_big_endian) {
1743 fprintf(stderr, "XXX Imager Region needs swapping on Big-endian\n");
1744 return false;
1745 }
1746
1747 return true;
1748}
1749
1751 vrpn_float32 *data, vrpn_uint32 colStride, vrpn_uint32 rowStride,
1752 vrpn_uint32 depthStride, vrpn_uint16 nRows, bool invert_rows,
1753 unsigned repeat) const
1754{
1755 // Make sure the parameters are reasonable
1756 if (colStride < repeat) {
1757 fprintf(stderr, "vrpn_Imager_Region::decode_unscaled_region_using_base_"
1758 "pointer(): colStride must be >= repeat\n");
1759 return false;
1760 }
1761
1762 // If the type of data in the buffer doesn't match the type of data the user
1763 // wants, we need to convert each element along the way.
1765 printf("vrpn_Imager_Region::decode_unscaled_region_using_base_pointer()"
1766 ": Transcoding not implemented yet\n");
1767 return false;
1768 }
1769 if (invert_rows && (nRows < d_rMax)) {
1770 fprintf(stderr, "vrpn_Imager_Region::decode_unscaled_region_using_base_"
1771 "pointer(): nRows must not be less than _rMax\n");
1772 return false;
1773 }
1774
1775 // The data type matches what we the user is asking for. No transcoding
1776 // needed.
1777 // Insert the data into the buffer, copying it as efficiently as possible
1778 // from the network buffer into the caller's buffer . Note that
1779 // the network buffer is little-endian. The code looks a little
1780 // complicated because it short-circuits the copying for the case where the
1781 // column stride and repeat are one element long (using memcpy() on each
1782 // row) but has to
1783 // copy one element at a time otherwise.
1784 int cols = d_cMax - d_cMin + 1;
1785 int linelen = cols * sizeof(data[0]);
1786 if ((colStride == 1) && (repeat == 1)) {
1787 const vrpn_float32 *msgbuf = (const vrpn_float32 *)d_valBuf;
1788 for (unsigned d = d_dMin; d <= d_dMax; d++) {
1789 for (unsigned r = d_rMin; r <= d_rMax; r++) {
1790 unsigned rActual;
1791 if (invert_rows) {
1792 rActual = (nRows - 1) - r;
1793 }
1794 else {
1795 rActual = r;
1796 }
1797 memcpy(&data[d * depthStride + rActual * rowStride + d_cMin],
1798 msgbuf, linelen);
1799 msgbuf += linelen;
1800 }
1801 }
1802 }
1803 else {
1804 long rowStep = rowStride;
1805 if (invert_rows) {
1806 rowStep *= -1;
1807 }
1808 const vrpn_float32 *msgbuf = (const vrpn_float32 *)d_valBuf;
1809 for (unsigned d = d_dMin; d <= d_dMax; d++) {
1810 vrpn_float32 *rowStart =
1811 &data[d * depthStride + d_rMin * rowStride + d_cMin * repeat];
1812 if (invert_rows) {
1813 rowStart =
1814 &data[d * depthStride + (nRows - 1 - d_rMin) * rowStride +
1815 d_cMin * repeat];
1816 }
1817 vrpn_float32 *copyTo = rowStart;
1818 for (unsigned r = d_rMin; r <= d_rMax; r++) {
1819 for (unsigned c = d_cMin; c <= d_cMax; c++) {
1820 for (unsigned rpt = 0; rpt < repeat; rpt++) {
1821 *(copyTo + rpt) = *msgbuf; //< Copy the current element
1822 }
1823 msgbuf++; //< Skip to the next buffer location
1824 copyTo += colStride; //< Skip appropriate number of elements
1825 }
1826 rowStart += rowStep; //< Skip to the start of the next row
1827 copyTo = rowStart;
1828 }
1829 }
1830 }
1831
1832 // Swap endian-ness of the buffer if we are on a big-endian machine.
1833 if (vrpn_big_endian) {
1834 fprintf(stderr, "XXX Imager Region needs swapping on Big-endian\n");
1835 return false;
1836 }
1837
1838 return true;
1839}
1840
1842 : vrpn_BaseClass(name, c)
1843{
1845
1846 d_origin[0] = d_origin[1] = d_origin[2] = 0.0;
1847 d_dCol[0] = d_dCol[1] = d_dCol[2] = 0.0;
1848 d_dRow[0] = d_dRow[1] = d_dRow[2] = 0.0;
1849 d_dDepth[0] = d_dDepth[1] = d_dDepth[2] = 0.0;
1850};
1851
1853{
1855 d_connection->register_message_type("vrpn_ImagerPose Description");
1856 if (d_description_m_id == -1) {
1857 return -1;
1858 }
1859 else {
1860 return 0;
1861 }
1862}
1863
1865 const vrpn_Imager &image,
1866 vrpn_uint16 col, vrpn_uint16 row,
1867 vrpn_uint16 depth)
1868{
1869 // Make sure we don't have a NULL pointer to fill our return into.
1870 if (center == NULL) {
1871 fprintf(
1872 stderr,
1873 "vrpn_ImagerPose::compute_pixel_center(): NULL center pointer\n");
1874 return false;
1875 }
1876
1877 // Ensure that the pixel coordinate is within bounds
1878 if ((col >= image.nCols()) || (row >= image.nRows()) ||
1879 (depth >= image.nDepth())) {
1880 fprintf(stderr, "vrpn_ImagerPose::compute_pixel_center(): Pixel index "
1881 "out of range\n");
1882 return false;
1883 }
1884
1885 // The pixel centers are located at the midpoint in row, column, and
1886 // depth space of each pixel. The pixel range is therefore half a
1887 // pixel past the centers of all pixels in the image. This means that
1888 // there is one extra pixel-step included in the range (half to the
1889 // negative of the origin, half to the positive of the last entry).
1890 // So, the pixel center is one half-step plus a number of whole steps
1891 // equal to its index.
1892 vrpn_float64 stepC = 1.0 / image.nCols();
1893 vrpn_float64 stepR = 1.0 / image.nRows();
1894 vrpn_float64 stepD = 1.0 / image.nDepth();
1895
1896 center[0] = d_origin[0] + (0.5 + col) * stepC * d_dCol[0] +
1897 (0.5 + row) * stepR * d_dRow[0] +
1898 (0.5 + depth) * stepD * d_dDepth[0];
1899 center[1] = d_origin[1] + (0.5 + col) * stepC * d_dCol[1] +
1900 (0.5 + row) * stepR * d_dRow[1] +
1901 (0.5 + depth) * stepD * d_dDepth[1];
1902 center[2] = d_origin[2] + (0.5 + col) * stepC * d_dCol[2] +
1903 (0.5 + row) * stepR * d_dRow[2] +
1904 (0.5 + depth) * stepD * d_dDepth[2];
1905
1906 return true;
1907}
1908
1910 const char *name, const vrpn_float64 origin[3], const vrpn_float64 dCol[3],
1911 const vrpn_float64 dRow[3], const vrpn_float64 *dDepth, vrpn_Connection *c)
1912 : vrpn_ImagerPose(name, c)
1913{
1914 memcpy(d_origin, origin, sizeof(d_origin));
1915 memcpy(d_dCol, dCol, sizeof(d_dCol));
1916 memcpy(d_dRow, dRow, sizeof(d_dRow));
1917 if (dDepth != NULL) {
1918 memcpy(d_dDepth, dDepth, sizeof(d_dDepth));
1919 }
1920
1921 // Set up callback handler for ping message from client so that it
1922 // sends the description. This will make sure that the other side has
1923 // heard the descrption before it hears a region message. Also set this up
1924 // to fire on the "new connection" system message.
1925
1927 d_sender_id);
1929 d_connection->register_message_type(vrpn_got_connection),
1931};
1932
1933bool vrpn_ImagerPose_Server::set_range(const vrpn_float64 origin[3],
1934 const vrpn_float64 dCol[3],
1935 const vrpn_float64 dRow[3],
1936 const vrpn_float64 *dDepth)
1937{
1938 memcpy(d_origin, origin, sizeof(d_origin));
1939 memcpy(d_dCol, dCol, sizeof(d_dCol));
1940 memcpy(d_dRow, dRow, sizeof(d_dRow));
1941 if (dDepth != NULL) {
1942 memcpy(d_dDepth, dDepth, sizeof(d_dDepth));
1943 }
1944 return send_description();
1945}
1946
1948{
1949 // msgbuf must be float64-aligned!
1950 vrpn_float64 fbuf[vrpn_CONNECTION_TCP_BUFLEN / sizeof(vrpn_float64)];
1951 char *msgbuf = (char *)fbuf;
1952 int buflen = sizeof(fbuf);
1953 struct timeval timestamp;
1954
1955 // Pack the description of all of the fields in the imager into the buffer,
1956 // including the channel descriptions.
1957 if (vrpn_buffer(&msgbuf, &buflen, d_origin[0]) ||
1958 vrpn_buffer(&msgbuf, &buflen, d_origin[1]) ||
1959 vrpn_buffer(&msgbuf, &buflen, d_origin[2]) ||
1960 vrpn_buffer(&msgbuf, &buflen, d_dDepth[0]) ||
1961 vrpn_buffer(&msgbuf, &buflen, d_dDepth[1]) ||
1962 vrpn_buffer(&msgbuf, &buflen, d_dDepth[2]) ||
1963 vrpn_buffer(&msgbuf, &buflen, d_dRow[0]) ||
1964 vrpn_buffer(&msgbuf, &buflen, d_dRow[1]) ||
1965 vrpn_buffer(&msgbuf, &buflen, d_dRow[2]) ||
1966 vrpn_buffer(&msgbuf, &buflen, d_dCol[0]) ||
1967 vrpn_buffer(&msgbuf, &buflen, d_dCol[1]) ||
1968 vrpn_buffer(&msgbuf, &buflen, d_dCol[2])) {
1969 fprintf(stderr, "vrpn_ImagerPose_Server::send_description(): Can't "
1970 "pack message header, tossing\n");
1971 return false;
1972 }
1973
1974 // Pack the buffer into the connection's outgoing reliable queue, if we have
1975 // a valid connection.
1976 vrpn_int32 len = sizeof(fbuf) - buflen;
1977 vrpn_gettimeofday(&timestamp, NULL);
1978 if (d_connection &&
1979 d_connection->pack_message(len, timestamp, d_description_m_id,
1980 d_sender_id, (char *)(void *)fbuf,
1982 fprintf(stderr, "vrpn_ImagerPose_Server::send_description(): cannot "
1983 "write message: tossing\n");
1984 return false;
1985 }
1986
1987 return true;
1988}
1989
1997
1999
2001 vrpn_Connection *c)
2002 : vrpn_ImagerPose(name, c)
2003{
2004 // Register the handlers for the description message
2006 this, d_sender_id);
2007}
2008
2011{
2012 const char *bufptr = p.buffer;
2014
2015 // Get my new information from the buffer
2016 if (vrpn_unbuffer(&bufptr, &me->d_origin[0]) ||
2017 vrpn_unbuffer(&bufptr, &me->d_origin[1]) ||
2018 vrpn_unbuffer(&bufptr, &me->d_origin[2]) ||
2019 vrpn_unbuffer(&bufptr, &me->d_dDepth[0]) ||
2020 vrpn_unbuffer(&bufptr, &me->d_dDepth[1]) ||
2021 vrpn_unbuffer(&bufptr, &me->d_dDepth[2]) ||
2022 vrpn_unbuffer(&bufptr, &me->d_dRow[0]) ||
2023 vrpn_unbuffer(&bufptr, &me->d_dRow[1]) ||
2024 vrpn_unbuffer(&bufptr, &me->d_dRow[2]) ||
2025 vrpn_unbuffer(&bufptr, &me->d_dCol[0]) ||
2026 vrpn_unbuffer(&bufptr, &me->d_dCol[1]) ||
2027 vrpn_unbuffer(&bufptr, &me->d_dCol[2])) {
2028 return -1;
2029 }
2030
2031 // Go down the list of callbacks that have been registered.
2032 // Fill in the parameter and call each.
2034
2035 return 0;
2036}
2037
2039{
2041 if (d_connection) {
2042 d_connection->mainloop();
2043 };
2044}
int register_autodeleted_handler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler, void *userdata, vrpn_int32 sender=vrpn_ANY_SENDER)
Registers a handler with the connection, and remembers to delete at destruction.
vrpn_Connection * d_connection
Connection that this object talks to.
void client_mainloop(void)
Handles functions that all clients should provide in their mainloop() (warning of no server,...
vrpn_int32 d_sender_id
Sender ID registered with the connection.
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
vrpn_int32 d_ping_message_id
Ask the server if they are there.
vrpn_BaseClass(const char *name, vrpn_Connection *c=NULL)
Names the device and assigns or opens connection, calls registration methods.
virtual int init(void)
Initialize things that the constructor can't. Returns 0 on success, -1 on failure.
void call_handlers(const CALLBACK_STRUCT &info)
This will pass the referenced parameter as a const to all the callbacks.
Generic connection class not specific to the transport mechanism.
vrpn_ImagerPose_Remote(const char *name, vrpn_Connection *c=NULL)
static int VRPN_CALLBACK handle_description_message(void *userdata, vrpn_HANDLERPARAM p)
Handler for resolution and channel list message from the server.
virtual void mainloop(void)
Call this each time through the program's main loop.
vrpn_Callback_List< struct timeval > d_description_list
static int VRPN_CALLBACK handle_ping_message(void *userdata, vrpn_HANDLERPARAM p)
bool send_description(void)
Sends a description of the imager so the remote can process the region messages.
bool set_range(const vrpn_float64 origin[3], const vrpn_float64 dCol[3], const vrpn_float64 dRow[3], const vrpn_float64 *dDepth=NULL)
Set the range or units. Return true on success.
vrpn_ImagerPose_Server(const char *name, const vrpn_float64 origin[3], const vrpn_float64 dCol[3], const vrpn_float64 dRow[3], const vrpn_float64 *dDepth=NULL, vrpn_Connection *c=NULL)
virtual void mainloop(void)
Handle baseclass ping/pong messages.
vrpn_float64 d_dRow[3]
vrpn_ImagerPose(const char *name, vrpn_Connection *c=NULL)
vrpn_int32 d_description_m_id
vrpn_float64 d_origin[3]
bool compute_pixel_center(vrpn_float64 *center, const vrpn_Imager &image, vrpn_uint16 col, vrpn_uint16 row, vrpn_uint16 depth=0)
This will return the location of the center of the specified.
vrpn_float64 d_dCol[3]
vrpn_float64 d_dDepth[3]
virtual int register_types(void)
Register the types of messages this device sends/receives. Return 0 on success, -1 on fail.
Holds the description needed to convert from raw data to values for a channel.
Definition vrpn_Imager.h:56
ChannelCompression d_compression
bool unbuffer(const char **buffer)
Definition vrpn_Imager.h:99
Helper function to convert data for a sub-region of one channel of.
vrpn_uint16 d_dMin
vrpn_int16 d_chanIndex
bool decode_unscaled_region_using_base_pointer(vrpn_uint8 *data, vrpn_uint32 colStride, vrpn_uint32 rowStride, vrpn_uint32 depthStride=0, vrpn_uint16 nRows=0, bool invert_rows=false, unsigned repeat=1) const
As efficiently as possible, pull the values out of the VRPN buffer and put them into the array whose ...
vrpn_uint16 d_valType
vrpn_uint16 d_rMax
vrpn_uint16 d_rMin
vrpn_uint16 d_cMin
vrpn_uint16 d_cMax
vrpn_uint16 d_dMax
const void * d_valBuf
static int VRPN_CALLBACK handle_begin_frame_message(void *userdata, vrpn_HANDLERPARAM p)
Handler for begin-frame message from the server.
static int VRPN_CALLBACK handle_discarded_frames_message(void *userdata, vrpn_HANDLERPARAM p)
Handler for discarded-frames message from the server.
vrpn_Callback_List< vrpn_IMAGERBEGINFRAMECB > d_begin_frame_list
const vrpn_Imager_Channel * channel(unsigned chanNum) const
Accessors for the member variables: can be queried in the handler for object changes.
virtual void mainloop(void)
XXX It could be nice to let the user specify separate callbacks for.
static int VRPN_CALLBACK handle_description_message(void *userdata, vrpn_HANDLERPARAM p)
Handler for resolution and channel list message from the server.
vrpn_Callback_List< vrpn_IMAGERENDFRAMECB > d_end_frame_list
vrpn_Callback_List< vrpn_IMAGERDISCARDEDFRAMESCB > d_discarded_frames_list
virtual bool throttle_sender(vrpn_int32 N)
Request that the server send at most N more frames until a new request is sent.
static int VRPN_CALLBACK handle_connection_dropped_message(void *userdata, vrpn_HANDLERPARAM p)
Handler for connection dropped message.
static int VRPN_CALLBACK handle_end_frame_message(void *userdata, vrpn_HANDLERPARAM p)
Handler for end-frame message from the server.
static int VRPN_CALLBACK handle_region_message(void *userdata, vrpn_HANDLERPARAM p)
Handler for region update message from the server.
vrpn_Imager_Remote(const char *name, vrpn_Connection *c=NULL)
vrpn_Callback_List< struct timeval > d_description_list
vrpn_Callback_List< vrpn_IMAGERREGIONCB > d_region_list
int add_channel(const char *name, const char *units="unsigned8bit", vrpn_float32 minVal=0, vrpn_float32 maxVal=255, vrpn_float32 scale=1, vrpn_float32 offset=0)
Add a channel to the server, returns index of the channel or -1 on failure.
Definition vrpn_Imager.C:81
vrpn_int32 d_frames_to_send
bool send_region_using_base_pointer(vrpn_int16 chanIndex, vrpn_uint16 cMin, vrpn_uint16 cMax, vrpn_uint16 rMin, vrpn_uint16 rMax, const vrpn_uint8 *data, vrpn_uint32 colStride, vrpn_uint32 rowStride, vrpn_uint16 nRows=0, bool invert_rows=false, vrpn_uint32 depthStride=0, vrpn_uint16 dMin=0, vrpn_uint16 dMax=0, const struct timeval *time=NULL)
Pack and send the region as efficiently as possible; strides are in steps of the element being sent.
bool set_resolution(vrpn_int32 nCols, vrpn_int32 nRows, vrpn_int32 nDepth=1)
Set the resolution to a different value than it had been before. Returns true on success.
vrpn_Imager_Server(const char *name, vrpn_Connection *c, vrpn_int32 nCols, vrpn_int32 nRows, vrpn_int32 nDepth=1)
Definition vrpn_Imager.C:47
static int VRPN_CALLBACK handle_throttle_message(void *userdata, vrpn_HANDLERPARAM p)
static int VRPN_CALLBACK handle_last_drop_message(void *userdata, vrpn_HANDLERPARAM p)
bool send_begin_frame(const vrpn_uint16 cMin, const vrpn_uint16 cMax, const vrpn_uint16 rMin, const vrpn_uint16 rMax, const vrpn_uint16 dMin=0, const vrpn_uint16 dMax=0, const struct timeval *time=NULL)
Servers must send begin/end frame pairs around contiguous sections of the image.
vrpn_uint16 d_dropped_due_to_throttle
bool send_end_frame(const vrpn_uint16 cMin, const vrpn_uint16 cMax, const vrpn_uint16 rMin, const vrpn_uint16 rMax, const vrpn_uint16 dMin=0, const vrpn_uint16 dMax=0, const struct timeval *time=NULL)
bool send_discarded_frames(const vrpn_uint16 count=0, const struct timeval *time=NULL)
bool send_description(void)
Sends a description of the imager so the remote can process the region messages.
bool send_region_using_first_pointer(vrpn_int16 chanIndex, vrpn_uint16 cMin, vrpn_uint16 cMax, vrpn_uint16 rMin, vrpn_uint16 rMax, const vrpn_uint8 *data, vrpn_uint32 colStride, vrpn_uint32 rowStride, vrpn_uint16 nRows=0, bool invert_rows=false, vrpn_uint32 depthStride=0, vrpn_uint16 dMin=0, vrpn_uint16 dMax=0, const struct timeval *time=NULL)
Pack and send the region as efficiently as possible; strides are in steps of the element being sent.
static int VRPN_CALLBACK handle_ping_message(void *userdata, vrpn_HANDLERPARAM p)
virtual void mainloop(void)
Handle baseclass ping/pong messages.
Base class for Imager class.
vrpn_int32 d_description_m_id
vrpn_int32 nDepth(void) const
vrpn_int32 d_regionf32_m_id
virtual int register_types(void)
Register the types of messages this device sends/receives. Return 0 on success, -1 on fail.
Definition vrpn_Imager.C:16
vrpn_int32 d_nCols
vrpn_int32 d_nRows
vrpn_int32 nCols(void) const
vrpn_Imager(const char *name, vrpn_Connection *c=NULL)
Definition vrpn_Imager.C:6
vrpn_int32 d_throttle_frames_m_id
vrpn_int32 d_begin_frame_m_id
vrpn_int32 d_regionu8_m_id
vrpn_int32 d_end_frame_m_id
vrpn_int32 d_regionu12in16_m_id
vrpn_int32 nRows(void) const
vrpn_int32 d_nChannels
vrpn_int32 d_regionu16_m_id
vrpn_int32 d_discarded_frames_m_id
vrpn_int32 d_nDepth
vrpn_Imager_Channel d_channels[vrpn_IMAGER_MAX_CHANNELS]
This structure is what is passed to a vrpn_Connection message callback.
const char * buffer
struct timeval msg_time
struct timeval msg_time
struct timeval msg_time
struct timeval msg_time
const vrpn_Imager_Region * region
const char * vrpn_dropped_last_connection
const char * vrpn_dropped_connection
const char * vrpn_got_connection
const vrpn_uint32 vrpn_CONNECTION_RELIABLE
Classes of service for messages, specify multiple by ORing them together Priority of satisfying these...
const int vrpn_ANY_SENDER
vrpn_ANY_SENDER can be used to register callbacks on a given message type from any sender.
const int vrpn_CONNECTION_TCP_BUFLEN
const unsigned vrpn_IMAGER_MAX_REGIONf32
Definition vrpn_Imager.h:48
const vrpn_uint16 vrpn_IMAGER_VALTYPE_FLOAT32
const unsigned vrpn_IMAGER_MAX_REGIONu8
Set of constants to tell how many points you can put into a region depending on the type you are putt...
Definition vrpn_Imager.h:37
const vrpn_uint16 vrpn_IMAGER_VALTYPE_UINT16
const unsigned vrpn_IMAGER_MAX_REGIONu16
Definition vrpn_Imager.h:42
const vrpn_uint16 vrpn_IMAGER_VALTYPE_UINT8
const vrpn_uint16 vrpn_IMAGER_VALTYPE_UINT12IN16
const unsigned vrpn_IMAGER_MAX_CHANNELS
Definition vrpn_Imager.h:32
VRPN_API int vrpn_unbuffer(const char **buffer, timeval *t)
Utility routine for taking a struct timeval from a buffer that was sent as a message.
VRPN_API int vrpn_buffer(char **insertPt, vrpn_int32 *buflen, const timeval t)
Utility routine for placing a timeval struct into a buffer that is to be sent as a message.
void vrpn_strcpy(char(&to)[charCount], const char *pSrc)
Null-terminated-string copy function that both guarantees not to overrun the buffer and guarantees th...
#define vrpn_gettimeofday
Definition vrpn_Shared.h:99