1 Star 0 Fork 1

upczap/vrpn

forked from ianaxe/vrpn 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
vrpn_LUDL.C 22.31 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
// Device drivers for the LUDL family of translation stage controllers.
// XXX I think we're using ASCII send and response because Ryan had some kind of trouble
// with the binary send/response. Not sure about this, though. It sure would be
// faster to read and easier to parse the binary ones, which all have the same length.
// XXX If we don't recenter, then we definitely need a way to figure out where
// our analogs are.
// XXX Need to parse more than one report if there is more than one in the buffer
// Also, need to clear _inbuf after each parsing.
// XXX Switch the reads (at least) to be asynchronous transfers.
// XXX Consider querying/parsing the position rather than just the status.
// XXX Make sure that we get notified if the user moves the stage with the knobs.
// XXX Check for running into the limits.
#include "vrpn_LUDL.h"
VRPN_SUPPRESS_EMPTY_OBJECT_WARNING()
#if defined(VRPN_USE_LIBUSB_1_0)
#include <stdio.h> // for fprintf, stderr, sprintf, etc
#include <string.h> // for NULL, memset, strlen
#include "libusb.h"
#include "vrpn_BaseClass.h" // for ::vrpn_TEXT_ERROR
#define REPORT_ERROR(msg) { send_text_message(msg, timestamp, vrpn_TEXT_ERROR) ; if (d_connection && d_connection->connected()) d_connection->send_pending_reports(); }
// USB vendor and product IDs for the models we support
static const vrpn_uint16 LUDL_VENDOR = 0x6969;
static const vrpn_uint16 LUDL_USBMAC6000 = 0x1235;
// Constants used in the LUDL commands and responses.
static const vrpn_uint16 LUDL_GET_LONG_DATA = 84;
static const vrpn_uint16 LUDL_SET_LONG_DATA = 83;
static const vrpn_uint16 LUDL_MOTOR_ACTION = 65;
// Index constants used by the above commands and responses.
static const vrpn_uint16 LUDL_MOTOR_POSITION = 5;
static const vrpn_uint16 LUDL_MODULE_BUSY = 63;
static const vrpn_uint16 LUDL_START_MOTOR_TARGET = 0;
static const vrpn_uint16 LUDL_CENTER_HOME = 7;
static const vrpn_uint16 SERVO_CHECKING = 241;
// Device number for the interface we're connected to.
static const vrpn_uint16 LUDL_INTERFACE_ADDRESS = 32;
vrpn_LUDL_USBMAC6000::vrpn_LUDL_USBMAC6000(const char *name, vrpn_Connection *c, bool do_recenter)
: vrpn_Analog(name, c)
, vrpn_Analog_Output(name, c)
, _device_handle(NULL)
, _endpoint(2) // All communications is with Endpoint 2 for the MAC6000
, _incount(0)
{
// Open and claim a device with the expected vendor and product ID.
if ( libusb_init(&_context) != 0) {
fprintf(stderr,"vrpn_LUDL_USBMAC6000: can't init LibUSB\n");
return;
}
//printf("dbg: Opening device\n");
if ( (_device_handle = libusb_open_device_with_vid_pid(_context, LUDL_VENDOR, LUDL_USBMAC6000)) == NULL) {
fprintf(stderr,"vrpn_LUDL_USBMAC6000: can't find any USBMac6000 devices\n");
#ifdef _WIN32
fprintf(stderr," (Did you install a Zadig.exe or other LibUSB-compatible driver?)\n");
#endif
#ifdef linux
fprintf(stderr," (Did you remember to run as root?)\n");
#endif
return;
}
//printf("dbg: Claiming interface\n");
if ( libusb_claim_interface(_device_handle, 0) != 0) {
fprintf(stderr,"vrpn_LUDL_USBMAC6000: can't claim interface for this device\n");
#ifdef linux
fprintf(stderr," (Did you remember to run as root?)\n");
#endif
libusb_close(_device_handle);
_device_handle = NULL;
libusb_exit(_context);
_context = NULL;
return;
}
// Initialize our analog values.
vrpn_Analog::num_channel = 4;
memset(channel, 0, sizeof(channel));
memset(last, 0, sizeof(last));
// Initialize our analog output values
vrpn_Analog_Output::o_num_channel = 2;
memset(o_channel, 0, sizeof(o_channel));
// Recenter if we have been asked to. This takes a long time, during which the
// constructor is locked up.
if (do_recenter) {
//printf("dbg: Recentering\n");
recenter();
}
// Tell the X and Y channel to do servo checking, which means that it will
// cause the system to actively work to hold the system in place when it
// has reached its destination. This turns out to greatly improve the
// precision of motion, and make the precision uniform across particular
// locations. Before this was turned on, there was a positional dependence
// to the amount of error in moving the stage.
if (!send_usbmac_command(1, LUDL_SET_LONG_DATA, SERVO_CHECKING, 1)) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::vrpn_LUDL_USBMAC6000(): Could not send command 1");
}
if (!send_usbmac_command(2, LUDL_SET_LONG_DATA, SERVO_CHECKING, 1)) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::vrpn_LUDL_USBMAC6000(): Could not send command 2");
}
// Wait for these commands to take effect and then clear any return
// values
vrpn_SleepMsecs(100);
flush_input_from_ludl();
// Register to receive the message to request changes and to receive connection
// messages.
if (d_connection != NULL) {
if (register_autodeleted_handler(request_m_id, handle_request_message,
this, d_sender_id)) {
fprintf(stderr,"vrpn_LUDL_USBMAC6000: can't register handler\n");
d_connection = NULL;
}
if (register_autodeleted_handler(request_channels_m_id, handle_request_channels_message,
this, d_sender_id)) {
fprintf(stderr,"vrpn_LUDL_USBMAC6000: can't register handler\n");
d_connection = NULL;
}
if (register_autodeleted_handler(d_ping_message_id, handle_connect_message,
this, d_sender_id)) {
fprintf(stderr,"vrpn_LUDL_USBMAC6000: can't register handler\n");
d_connection = NULL;
}
} else {
fprintf(stderr,"vrpn_LUDL_USBMAC6000: Can't get connection!\n");
}
// Allocate space to store the axis status and record that the axes are stopped.
_axis_moving = new bool[o_num_channel];
_axis_destination = new vrpn_float64[o_num_channel];
int i;
for (i = 0; i < o_num_channel; i++) {
_axis_moving[i] = false;
}
}
vrpn_LUDL_USBMAC6000::~vrpn_LUDL_USBMAC6000()
{
if (_device_handle) {
libusb_close(_device_handle);
_device_handle = NULL;
}
if (_context) {
libusb_exit(_context);
_context = NULL;
}
// Get rid of the arrays we allocated in the constructor
if (_axis_moving != NULL) { delete [] _axis_moving; _axis_moving = NULL; }
if (_axis_destination != NULL) { delete [] _axis_destination; _axis_destination = NULL; }
}
bool vrpn_LUDL_USBMAC6000::check_for_data(void)
{
if (_device_handle == NULL) {
return false;
}
// Let libusb handle any outstanding events
struct timeval zerotime;
zerotime.tv_sec = 0;
zerotime.tv_usec = 0;
libusb_handle_events_timeout(_context, &zerotime);
// Try to read as many characters as are left in the buffer from
// the device. Keep track of how many we get.
int chars_to_read = _INBUFFER_SIZE - _incount;
int chars_read = 0;
int ret;
//printf("dbg: Starting bulk receive\n");
ret = libusb_bulk_transfer(_device_handle, _endpoint | LIBUSB_ENDPOINT_IN,
&_inbuffer[_incount], chars_to_read, &chars_read, 1);
//printf("dbg: Finished bulk receive\n");
if ( (ret != LIBUSB_SUCCESS) && (ret != LIBUSB_ERROR_TIMEOUT) ) {
#ifdef libusb_strerror
fprintf(stderr, "vrpn_LUDL_USBMAC6000::check_for_data(): Could not read data: %s\n",
libusb_strerror(static_cast<libusb_error>(ret)));
#else
fprintf(stderr, "vrpn_LUDL_USBMAC6000::check_for_data(): Could not read data: code %d\n",
ret);
#endif
return false;
}
_incount += chars_read;
return true;
}
void vrpn_LUDL_USBMAC6000::mainloop()
{
if (_device_handle == NULL) {
return;
}
// Let libusb handle any outstanding events
struct timeval zerotime;
zerotime.tv_sec = 0;
zerotime.tv_usec = 0;
libusb_handle_events_timeout(_context, &zerotime);
// If one of the axes is moving, check to see whether it has stopped.
// If so, report its new position.
// XXX Would like to change this to poll (or have the device send
// continuously) the actual position, rather than relying on it having
// gotten where we asked it to go).
if (!_axis_moving || !_axis_destination) { return; }
int i;
for (i = 0; i < o_num_channel; i++) {
if (_axis_moving[i]) {
if (!ludl_axis_moving(i+1)) {
vrpn_Analog::channel[i] = _axis_destination[i];
_axis_moving[i] = false;
}
}
}
// Ask for and record the positions of the two axes.
// Remember that the axes are numbered starting from 1 on the
// LUDL controller but they go in Analog channels 2 and 3.
vrpn_int32 position;
if (ludl_axis_position(1, &position)) {
channel[2] = position;
}
if (ludl_axis_position(2, &position)) {
channel[3] = position;
}
// Let all of the servers do their thing.
server_mainloop();
vrpn_gettimeofday(&_timestamp, NULL);
report_changes();
// Call the server_mainloop on our unique base class.
server_mainloop();
}
void vrpn_LUDL_USBMAC6000::report(vrpn_uint32 class_of_service)
{
vrpn_Analog::timestamp = _timestamp;
vrpn_Analog::report(class_of_service);
}
void vrpn_LUDL_USBMAC6000::report_changes(vrpn_uint32 class_of_service)
{
vrpn_Analog::timestamp = _timestamp;
vrpn_Analog::report_changes(class_of_service);
}
void vrpn_LUDL_USBMAC6000::flush_input_from_ludl(void)
{
// Clear the input buffer, read all available characters
// from the endpoint we're supposed to use, then clear it
// again -- throwing away all data that was coming from the device.
_incount = 0;
check_for_data();
_incount = 0;
}
// Construct a command using the specific language of the USBMAC6000
// and send the message to the device.
// I got the format for this message from the code in USBMAC6000.cpp from
// the video project, as implemented by Ryan Schubert at UNC.
bool vrpn_LUDL_USBMAC6000::send_usbmac_command(unsigned device, unsigned command, unsigned index, int value)
{
if (_device_handle == NULL) {
return false;
}
// Let libusb handle any outstanding events
struct timeval zerotime;
zerotime.tv_sec = 0;
zerotime.tv_usec = 0;
libusb_handle_events_timeout(_context, &zerotime);
char msg[1024];
sprintf(msg, "can %u %u %u %i\n", device, command, index, value);
int len = strlen(msg);
int sent_len = 0;
msg[len-1] = 0xD;
//printf("dbg: Starting bulk send command\n");
int ret = libusb_bulk_transfer(_device_handle, _endpoint | LIBUSB_ENDPOINT_OUT,
static_cast<vrpn_uint8 *>(static_cast<void*>(msg)),
len, &sent_len, 50);
//printf("dbg: Finished bulk send command\n");
if ((ret != 0) || (sent_len != len)) {
#ifdef libusb_strerror
fprintf(stderr,"vrpn_LUDL_USBMAC6000::send_usbmac_command(): Could not send: %s\n",
libusb_strerror(static_cast<libusb_error>(ret)));
#else
fprintf(stderr,"vrpn_LUDL_USBMAC6000::send_usbmac_command(): Could not send: code %d\n",
ret);
#endif
return false;
}
return true;
}
// Interpret one response from the device and place its resulting value
// in the return parameter.
// I got the format for this message from the code in USBMAC6000.cpp from
// the video project, as implemented by Ryan Schubert at UNC.
bool vrpn_LUDL_USBMAC6000::interpret_usbmac_ascii_response(const vrpn_uint8 *buffer,
int *device_return,
int *command_return,
int *index_return,
int *value_return)
{
if (buffer == NULL) { return false; }
const char *charbuf = static_cast<const char *>(static_cast<const void *>(buffer));
char acolon[32], can[32];
int device = 0, command = 0, index = 0, value = 0;
if (sscanf(charbuf, "%s %s %i %i %i %i", acolon, can, &device, &command, &index, &value) <= 0) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::interpret_usbmac_ascii_response(): Could not parse response");
return false;
}
*device_return = device;
*command_return = command;
*index_return = index;
*value_return = value;
return true;
}
// I got the algorithm for recentering from the code in USBMAC6000.cpp from
// the video project, as implemented by Ryan Schubert at UNC.
// XXX This takes a LONG TIME to finish and relies on messages coming back;
// consider making it asynchronous.
bool vrpn_LUDL_USBMAC6000::recenter(void)
{
// Send the command to make the X axis go to both ends of its
// range and then move into the center.
if (!send_usbmac_command(1, LUDL_MOTOR_ACTION, LUDL_CENTER_HOME, 100000)) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::recenter(): Could not send command 1");
return false;
}
printf("vrpn_LUDL_USBMAC6000::recenter(): Waiting for X-axis center\n");
vrpn_SleepMsecs(500); // XXX Why sleep?
// Let libusb handle any outstanding events
struct timeval zerotime;
zerotime.tv_sec = 0;
zerotime.tv_usec = 0;
libusb_handle_events_timeout(_context, &zerotime);
flush_input_from_ludl();
// First we need to wait for the axis to start moving, then we need
// to wait for it to stop moving. This is because sometimes the
// X axis (at least) claims to be not moving even though we just
// told it to and flushed the buffer
while(!ludl_axis_moving(1)) {
vrpn_SleepMsecs(10);
libusb_handle_events_timeout(_context, &zerotime);
}
while(ludl_axis_moving(1)) {
vrpn_SleepMsecs(10);
libusb_handle_events_timeout(_context, &zerotime);
}
// Send the command to record the value at the center of the X axis as
// 694576 ticks. This magic number comes from the dividing by two the
// range on the UNC Monoptes system between the stops set to keep the
// objective from running into the walls of the plate. XXX Replace this
// with a more meaningful constant, perhaps 0.
if (!send_usbmac_command(1, LUDL_SET_LONG_DATA, LUDL_MOTOR_POSITION, 694576)) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::recenter(): Could not send command 2");
return false;
}
channel[0] = 694576;
// Send the command to make the Y axis go to both ends of its
// range and then move into the center.
if (!send_usbmac_command(2, LUDL_MOTOR_ACTION, LUDL_CENTER_HOME, 100000)) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::recenter(): Could not send command 3");
return false;
}
printf("vrpn_LUDL_USBMAC6000::recenter(): Waiting for Y-axis center\n");
vrpn_SleepMsecs(500); // XXX Why sleep?
// Let libusb handle any outstanding events
libusb_handle_events_timeout(_context, &zerotime);
flush_input_from_ludl();
// First we need to wait for the axis to start moving, then we need
// to wait for it to stop moving. This is because sometimes the
// X axis (at least) claims to be not moving even though we just
// told it to and flushed the buffer
while(!ludl_axis_moving(2)) {
vrpn_SleepMsecs(10);
libusb_handle_events_timeout(_context, &zerotime);
}
while(ludl_axis_moving(2)) {
vrpn_SleepMsecs(10);
libusb_handle_events_timeout(_context, &zerotime);
}
// Send the command to record the value at the center of the Y axis as
// 1124201 ticks. This magic number comes from the dividing by two the
// range on the UNC Monoptes system between the stops set to keep the
// objective from running into the walls of the plate. XXX Replace this
// with a more meaningful constant, perhaps 0.
if (!send_usbmac_command(2, LUDL_SET_LONG_DATA, LUDL_MOTOR_POSITION, 1124201)) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::recenter(): Could not send command 4");
return false;
}
channel[1] = 1124201;
return true;
}
// I got the algorithm for checking if the axis is moving
// from the code in USBMAC6000.cpp from
// the video project, as implemented by Ryan Schubert at UNC.
// The first axis is 1 in this function.
bool vrpn_LUDL_USBMAC6000::ludl_axis_moving(unsigned axis)
{
// Request the status of the axis. In particular, we look at the
// bits telling whether each axis is busy.
flush_input_from_ludl();
if (!send_usbmac_command(LUDL_INTERFACE_ADDRESS, LUDL_GET_LONG_DATA, LUDL_MODULE_BUSY, 0)) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_moving(): Could not send command 1");
return false;
}
// Read from the device to find the status. We call the check_for_data() method
// to look for a response.
unsigned watchdog = 0;
while (_incount == 0) {
if (!check_for_data()) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_moving(): Could not get report");
return false;
}
// If it has been too long, re-send the request to the stage.
// XXX We should not be losing characters... figure out what is causing us to
// have to resend.
if (++watchdog == 25) { // 25 ms (timeout is 1ms)
if (!send_usbmac_command(LUDL_INTERFACE_ADDRESS, LUDL_GET_LONG_DATA, LUDL_MODULE_BUSY, 0)) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_moving(): Could not resend command 1");
return false;
}
watchdog = 0;
}
}
int status = 0;
int device, command, index;
if (!interpret_usbmac_ascii_response(_inbuffer, &device, &command, &index, &status)) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_moving(): Could not parse report");
return false;
}
_incount = 0; // XXX Should parse more than one report if there is one.
int axisMaskBit = 0x0001 << axis;
return (status & axisMaskBit) != 0;
}
// The first axis is 1 in this function.
bool vrpn_LUDL_USBMAC6000::ludl_axis_position(unsigned axis, vrpn_int32 *position_return)
{
// Request the position of the axis.
flush_input_from_ludl();
if (!send_usbmac_command(axis, LUDL_GET_LONG_DATA, LUDL_MOTOR_POSITION, 0)) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Could not send command 1");
return false;
}
// Read from the device to find the status. We call the check_for_data() method
// to look for a response.
unsigned watchdog = 0;
while (_incount == 0) {
if (!check_for_data()) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Could not get report");
return false;
}
// If it has been too long, re-send the request to the stage.
// XXX We should not be losing characters... figure out what is causing us to
// have to resend.
if (++watchdog == 25) { // 25 ms (timeout is 1ms)
if (!send_usbmac_command(axis, LUDL_GET_LONG_DATA, LUDL_MOTOR_POSITION, 0)) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Could not resend command 1");
return false;
}
watchdog = 0;
}
}
int position = 0;
int device, command, index;
if (!interpret_usbmac_ascii_response(_inbuffer, &device, &command, &index, &position)) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Could not parse report");
return false;
}
_incount = 0; // XXX Should parse more than one report if there is one.
if ( (command != LUDL_GET_LONG_DATA) || (index != LUDL_MOTOR_POSITION) ) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::ludl_axis_position(): Bad command or index in report");
return false;
}
*position_return = position;
return true;
}
bool vrpn_LUDL_USBMAC6000::move_axis_to_position(int axis, int position)
{
if (!_device_handle) { return false; }
if (!_axis_destination || !_axis_moving) { return false; }
// If we're already at the place we're being asked to move to,
// then we just go ahead and return. Otherwise, the code below
// that waits for us to start moving hangs.
if (_axis_destination[axis-1] == position) {
return true;
}
// Send the command to the device asking it to move.
if (!send_usbmac_command(axis, LUDL_MOTOR_ACTION, LUDL_START_MOTOR_TARGET, position)) {
REPORT_ERROR("vrpn_LUDL_USBMAC6000::move_axis_to_position(): Could not send command");
return false;
}
// Wait until that axis starts to move. If we don't do this, then
// sometimes we hear back that there are no axes moving even though
// we told them to. Just waiting a while after we told them to move
// does not help; there is still a report saying that they are not moving.
// If the stage is at its limits or if we asked it to go where it already
// is, then we'll wait forever here because it will not move. So this
// needs to time out and not set the axis to moving if we never see
// it start to move.
struct timeval start, now;
vrpn_gettimeofday(&start, NULL);
while (!ludl_axis_moving(axis)) {
vrpn_gettimeofday(&now, NULL);
struct timeval diff = vrpn_TimevalDiff(now, start);
if (diff.tv_sec > 1) {
// Say that we moved there, but don't say that the axis is
// moving.
_axis_destination[axis-1] = position;
return true;
}
};
// Indicate that we're expecting this axis to be moving and where we think it is
// going, so that when the axis becomes no longer busy we know that we have gotten
// there.
_axis_destination[axis-1] = position;
_axis_moving[axis-1] = true;
return true;
}
int vrpn_LUDL_USBMAC6000::handle_request_message(void *userdata, vrpn_HANDLERPARAM p)
{
const char *bufptr = p.buffer;
vrpn_int32 chan_num;
vrpn_int32 pad;
vrpn_float64 value;
vrpn_LUDL_USBMAC6000 *me = (vrpn_LUDL_USBMAC6000 *)userdata;
// Read the parameters from the buffer
vrpn_unbuffer(&bufptr, &chan_num);
vrpn_unbuffer(&bufptr, &pad);
vrpn_unbuffer(&bufptr, &value);
// Set the position to the appropriate value, if the channel number is in the
// range of the ones we have.
if ( (chan_num < 0) || (chan_num >= me->o_num_channel) ) {
char msg[1024];
sprintf(msg,"vrpn_LUDL_USBMAC6000::handle_request_message(): Index out of bounds (%d of %d), value %lg\n",
chan_num, me->o_num_channel, value);
me->send_text_message(msg, me->timestamp, vrpn_TEXT_ERROR);
return 0;
}
me->move_axis_to_position(chan_num + 1, static_cast<int>(value));
return 0;
}
int vrpn_LUDL_USBMAC6000::handle_request_channels_message(void* userdata, vrpn_HANDLERPARAM p)
{
int i;
const char* bufptr = p.buffer;
vrpn_int32 num;
vrpn_int32 pad;
vrpn_LUDL_USBMAC6000* me = (vrpn_LUDL_USBMAC6000 *)userdata;
// Read the values from the buffer
vrpn_unbuffer(&bufptr, &num);
vrpn_unbuffer(&bufptr, &pad);
if (num > me->o_num_channel) {
char msg[1024];
sprintf(msg,"vrpn_LUDL_USBMAC6000::handle_request_channels_message(): Index out of bounds (%d of %d), clipping\n",
num, me->o_num_channel);
me->send_text_message(msg, me->timestamp, vrpn_TEXT_ERROR);
num = me->o_num_channel;
}
for (i = 0; i < num; i++) {
vrpn_unbuffer(&bufptr, &(me->o_channel[i]));
me->move_axis_to_position(i + 1, static_cast<int>(me->o_channel[i]));
}
return 0;
}
/** When we get a connection request from a remote object, send our state so
they will know it to start with. */
int vrpn_LUDL_USBMAC6000::handle_connect_message(void *userdata, vrpn_HANDLERPARAM)
{
vrpn_LUDL_USBMAC6000 *me = (vrpn_LUDL_USBMAC6000 *)userdata;
me->report(vrpn_CONNECTION_RELIABLE);
return 0;
}
// End of VRPN_USE_HID
#endif
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/jari/vrpn.git
[email protected]:jari/vrpn.git
jari
vrpn
vrpn
master

搜索帮助