void vrpn_DreamCheeky_Drum_Kit::decodePacket(size_t bytes, vrpn_uint8 *buffer) { // The reports are each 8 bytes long. Since there is only one type of // report for this device, the report type is not included (stripped by // the HIDAPI driver). The bytes are 8 identical reports. // There is one byte per report, and it holds a binary encoding of // the buttons. Button 0 is in the LSB, and the others proceed up // the bit chain. Parse each report and then send any changes on. // need to send between each report so we don't miss a button press/release // all in one packet. size_t i, r; // Truncate the count to an even number of 8 bytes. This will // throw out any partial reports (which is not necessarily what // we want, because this will start us off parsing at the wrong // place if the rest of the report comes next, but it is not // clear how to handle that cleanly). bytes -= (bytes % 8); // Decode all full reports, each of which is 8 bytes long. for (i = 0; i < (bytes / 8); i++) { // If we're debouncing the buttons, then we set the button // to "pressed" if it has 4 or more pressed events in the // set of 8 and to "released" if it has less than 4. if (d_debounce) { int btn; for (btn = 0; btn < vrpn_Button::num_buttons; btn++) { unsigned count = 0; vrpn_uint8 mask = 1 << btn; for (r = 0; r < 8; r++) { // Skip the all-zeroes byte vrpn_uint8 *report = buffer + 9*i + r; count += ((*report & mask) != 0); } buttons[btn] = (count >= 4); vrpn_gettimeofday(&_timestamp, NULL); report_changes(); } // If we're not debouncing, then we report each button event // independently. }else { for (r = 0; r < 8; r++) { // Skip the all-zeroes byte vrpn_uint8 *report = buffer + 9*i + r; int btn; for (btn = 0; btn < vrpn_Button::num_buttons; btn++) { vrpn_uint8 mask = 1 << btn; buttons[btn] = ((*report & mask) != 0); } vrpn_gettimeofday(&_timestamp, NULL); report_changes(); } } } }
void vrpn_DevInput::mainloop() { get_report(); server_mainloop(); report_changes(); }
void vrpn_Xkeys_Desktop::mainloop() { update(); server_mainloop(); vrpn_gettimeofday(&_timestamp, NULL); report_changes(); vrpn_Button::server_mainloop(); }
void vrpn_DreamCheeky_Drum_Kit::mainloop() { update(); server_mainloop(); vrpn_gettimeofday(&_timestamp, NULL); report_changes(); vrpn_Button::server_mainloop(); }
void vrpn_Xkeys_Pro::mainloop() { update(); server_mainloop(); vrpn_gettimeofday(&_timestamp, NULL); report_changes(); // Call the server_mainloop on our unique base class. server_mainloop(); }
void vrpn_Xkeys_Joystick::mainloop() { update(); server_mainloop(); vrpn_gettimeofday(&_timestamp, NULL); report_changes(); vrpn_Analog::server_mainloop(); vrpn_Button::server_mainloop(); }
void vrpn_3DConnexion::mainloop() { #if defined(VRPN_USE_HID) // Full reports are 7 bytes long. // XXX If we get a 2-byte report mixed in, then something is going to get // truncated. update(); #elif defined(linux) && !defined(VRPN_USE_HID) struct timeval zerotime; fd_set fdset; struct input_event ev; int i; zerotime.tv_sec = 0; zerotime.tv_usec = 0; FD_ZERO(&fdset); /* clear fdset */ FD_SET(fd, &fdset); /* include fd in fdset */ int moreData = 0; do { vrpn_noint_select(fd + 1, &fdset, NULL, NULL, &zerotime); moreData = 0; if (FD_ISSET(fd, &fdset)) { moreData = 1; if (vrpn_noint_block_read(fd, reinterpret_cast<char*>(&ev), sizeof(struct input_event)) != sizeof(struct input_event)) { send_text_message("Error reading from vrpn_3DConnexion", vrpn_Analog::timestamp, vrpn_TEXT_ERROR); if (d_connection) { d_connection->send_pending_reports(); } return; } switch (ev.type) { case EV_KEY: // button movement vrpn_gettimeofday((timeval *)&this->vrpn_Button::timestamp, NULL); buttons[ev.code & 0x0ff] = ev.value; break; case EV_REL: // axis movement case EV_ABS: // new kernels send more logical _ABS instead of _REL vrpn_gettimeofday((timeval *)&this->vrpn_Analog::timestamp, NULL); // Convert from short to int to avoid a short/double conversion // bug in GCC 3.2. i = ev.value; channel[ev.code] = static_cast<double>(i)/400.0; break; default: break; } } report_changes(); } while (moreData == 1); #endif server_mainloop(); vrpn_gettimeofday(&_timestamp, NULL); }
void vrpn_Griffin_PowerMate::mainloop(void) { update(); server_mainloop(); struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); if (vrpn_TimevalDuration(current_time, _timestamp) > POLL_INTERVAL ) { _timestamp = current_time; report_changes(); // Call the server_mainloop on our unique base class. server_mainloop(); } }
void vrpn_Analog_5dtUSB::on_data_received(size_t bytes, vrpn_uint8 *buffer) { if (bytes != 64) { std::ostringstream ss; ss << "Received a too-short report: " << bytes; struct timeval ts; vrpn_gettimeofday(&ts, NULL); send_text_message(ss.str().c_str(), ts, vrpn_TEXT_WARNING); return; } // Decode all full reports. const float scale = 1.0f / 4096.0f; vrpn_uint8 * bufptr = buffer; for (size_t i = 0; i < 16; i++) { _rawVals[i] = vrpn_unbuffer<vrpn_int16>(bufptr) * scale; } switch (vrpn_Analog::num_channel) { case 5: for (size_t i = 0; i < 5; ++i) { channel[i] = _rawVals[i * 3]; // Report this event before parsing the next. report_changes(); } break; case 14: for (size_t i = 0; i < 14; ++i) { channel[i] = _rawVals[i]; // Report this event before parsing the next. report_changes(); } break; default: std::cerr << "Internal error - should not happen: Unrecognized number of channels!" << std::endl; } }
void vrpn_Microsoft_SideWinder_Precision_2::mainloop(void) { update(); server_mainloop(); struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); if (vrpn_TimevalDuration(current_time, _timestamp) > POLL_INTERVAL) { _timestamp = current_time; report_changes(); // Call the server_mainloop on our unique base class. server_mainloop(); } }
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_XInputGamepad::mainloop() { XINPUT_STATE state; DWORD rv; server_mainloop(); if ((rv = XInputGetState(_controllerIndex, &state)) != ERROR_SUCCESS) { char errMsg[256]; struct timeval now; if (rv == ERROR_DEVICE_NOT_CONNECTED) sprintf(errMsg, "XInput device %u not connected", _controllerIndex); else sprintf(errMsg, "XInput device %u returned Windows error code %u", _controllerIndex, rv); vrpn_gettimeofday(&now, NULL); send_text_message(errMsg, now, vrpn_TEXT_ERROR); return; } // Set device state in VRPN_Analog channel[0] = normalize_axis(state.Gamepad.sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); channel[1] = normalize_axis(state.Gamepad.sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); channel[2] = normalize_axis(state.Gamepad.sThumbRX, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); channel[3] = normalize_axis(state.Gamepad.sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); channel[4] = normalize_dpad(state.Gamepad.wButtons); channel[5] = normalize_trigger(state.Gamepad.bLeftTrigger); channel[6] = normalize_trigger(state.Gamepad.bRightTrigger); // Set device state in VRPN_Button // Buttons are listed in DirectInput ordering buttons[0] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0; buttons[1] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0; buttons[2] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0; buttons[3] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0; buttons[4] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0; buttons[5] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0; buttons[6] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0; buttons[7] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0; buttons[8] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0; buttons[9] = (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0; vrpn_gettimeofday(&_timestamp, NULL); report_changes(); }
void vrpn_Logitech_Extreme_3D_Pro::mainloop(void) { update(); server_mainloop(); struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); if (vrpn_TimevalDuration(current_time, _timestamp) > POLL_INTERVAL) { _timestamp = current_time; report_changes(); vrpn_Analog::server_mainloop(); vrpn_Button::server_mainloop(); if (vrpn_Dial::num_dials > 0) { vrpn_Dial::server_mainloop(); } } }
void vrpn_Button_SerialMouse::mainloop() { // Call the generic server mainloop, since we are a server server_mainloop(); switch (status) { case BUTTON_READY: read(); report_changes(); break; case BUTTON_FAIL: { if (printed_error) break; printed_error = true; send_text_message("vrpn_Button_SerialMouse failure!", timestamp, vrpn_TEXT_ERROR); } break; } }
void vrpn_Microsoft_SideWinder_Precision_2::mainloop(void) { update(); server_mainloop(); struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); if (vrpn_TimevalDuration(current_time, _timestamp) > POLL_INTERVAL) { _timestamp = current_time; report_changes(); vrpn_Analog::server_mainloop(); vrpn_Button::server_mainloop(); if (vrpn_Dial::num_dials > 0) { vrpn_Dial::server_mainloop(); } } }
void vrpn_nVidia_shield_USB::mainloop(void) { update(); server_mainloop(); struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); if (vrpn_TimevalDuration(current_time, d_timestamp) > POLL_INTERVAL ) { d_timestamp = current_time; report_changes(); if (vrpn_Analog::num_channel > 0) { vrpn_Analog::server_mainloop(); } if (vrpn_Button::num_buttons > 0) { vrpn_Button::server_mainloop(); } } }
void vrpn_Analog_USDigital_A2::mainloop() { server_mainloop(); // let the server do its stuff #ifdef VRPN_USE_USDIGITAL long readErr, readVal ; // Read the data from the available channels for (vrpn_uint32 c=0 ; c<(vrpn_uint32) num_channel ; c++) { // see if there's really a readable device there. if (c<_numDevices && _devAddr[c]>=0) { readErr = A2GetPosition(_devAddr[c], &readVal) ; if (readErr) { fprintf(stderr, "vrpn_Analog_USDigital_A2: Error code %d received while reading channel %d.\n", readErr, c) ; fprintf(stderr, "vrpn_Analog_USDigital_A2: Attempting to reinitialize SEI bus...") ; readErr = ResetSEI() ; if (readErr) fprintf(stderr, "failed.") ; fprintf(stderr, "failed.") ; // don't flood the log, and give the reset time to work vrpn_SleepMsecs(1000) ; } else channel[c] = (vrpn_float64) readVal ; } else channel[c] = 0 ; // default to 0 for unreadable/unavailable. } // for #endif // Finally, the point of all this, deliver the data if (_reportChange) report_changes() ; else report() ; } // mainloop
int vrpn_Keyboard::get_report(void) { struct timeval time; vrpn_gettimeofday(&time, NULL); // set timestamp of this event timestamp = time; int i; #ifdef _WIN32 // Read one key state, which will read all of the events // and make it possible to read the state of all the keys; // We're ignoring the return for this particular key; it // will be read again as part of the 256-key read below. GetKeyState(1); // Read all 256 keys from the keyboard, then translate the // "virtual key" value from each into a scanline code and fill // in the appropriate entry with each value. BYTE virtual_keys[256]; if (GetKeyboardState(virtual_keys) == 0) { fprintf(stderr,"vrpn_Keyboard::get_report(): Could not read keyboard state\n"); return 0; } // Clear all 256 key values, then fill in the ones that are // nonzero. This is done because some of the keys from the // keyboard (control and shift) map into the same scan code; // if we just set all of the codes, then the right ones // overwrite the left ones. for (i = 0; i < 256; i++) { buttons[i] = 0; } for (i = 0; i < 256; i++) { unsigned scancode = MapVirtualKey(i, 0); if ( (scancode != 0) && ((0x80 & virtual_keys[i]) != 0) ) { buttons[scancode] = 1; } } #endif report_changes(); // Report updates to VRPN return 0; }
int vrpn_3DMicroscribe::get_report(void) { #ifdef VRPN_USE_MICROSCRIBE length_3D tipPosition; angle_3D tipOri; DWORD buts; int iResult = ArmGetTipPosition(&tipPosition); //retrieves the current stylus tip position in Cartesian coordinates iResult = ArmGetTipOrientation(&tipOri); //retrieves the current stylus tip's unit vector orientation iResult = ArmGetButtonsState(&buts); if(iResult == ARM_NOT_CONNECTED) { //error connecting VRPN_MSG_ERROR( "MicroScribe connection lost!" ); return 0; } //set the position, considering the scale, offset and origin matrix pos[0] = (tipPosition.y * m_Scale + m_OffSet[0])* MM_TO_METERS ; pos[1] = (tipPosition.z * m_Scale + m_OffSet[1])* MM_TO_METERS; pos[2] = (tipPosition.x * m_Scale + m_OffSet[2])* MM_TO_METERS; //vPosition = m_Matrix * vPosition + m_vPlaneOffset; extending the microscribe onto a plane //set the orientation, considering the origin matrix float ori[3]={tipOri.y, tipOri.z, tipOri.x}; ConvertOriToQuat(ori); status = STATUS_READING; // ready to process event packet vrpn_gettimeofday(×tamp, NULL); // set timestamp of this event buttons[0] = ((buts & 0x02) != 0); // button 1 buttons[1] = ((buts & 0x01) != 0); // button 2 #endif report_changes(); // Report updates to VRPN return 0; }
void vrpn_Dial_Example_Server::mainloop() { struct timeval current_time; int i; // Call the generic server mainloop, since we are a server server_mainloop(); // See if its time to generate a new report // IN A REAL SERVER, this check would not be done; although the // time of the report would be updated to the current time so // that the correct timestamp would be issued on the report. vrpn_gettimeofday(¤t_time, NULL); if (vrpn_TimevalDuration(current_time, timestamp) >= 1000000.0 / _update_rate) { // Update the time timestamp.tv_sec = current_time.tv_sec; timestamp.tv_usec = current_time.tv_usec; // Update the values for the dials, to say that each one has // moved the appropriate rotation (spin rate is revolutions per // second, update rate is report/second, the quotient is the number // of revolutions since the last report). When the changes are // reported, these values are set back to zero. // THIS CODE WILL BE REPLACED by the user code that tells how // many revolutions each dial has changed since the last report. for (i = 0; i < num_dials; i++) { dials[i] = _spin_rate / _update_rate; } // Send reports. Stays the same in a real server. report_changes(); } }
void vrpn_Griffin_PowerMate::mainloop(void) { update(); server_mainloop(); struct timeval current_time; vrpn_gettimeofday(¤t_time, NULL); if (vrpn_TimevalDuration(current_time, _timestamp) > POLL_INTERVAL ) { _timestamp = current_time; report_changes(); if (vrpn_Analog::num_channel > 0) { vrpn_Analog::server_mainloop(); } if (vrpn_Button::num_buttons > 0) { vrpn_Button::server_mainloop(); } if (vrpn_Dial::num_dials > 0) { vrpn_Dial::server_mainloop(); } } }
int vrpn_Mouse::get_report() { #if defined(linux) && defined(VRPN_USE_GPM_MOUSE) fd_set readset; FD_ZERO( &readset ); FD_SET( gpm_fd, &readset ); struct timeval timeout = { 0, 0 }; select( gpm_fd+1, &readset, NULL, NULL, &timeout ); if( ! FD_ISSET( gpm_fd, &readset ) ) return 0; Gpm_Event evt; if( Gpm_GetEvent( &evt ) <= 0 ) return 0; if( evt.type & GPM_UP ) { if( evt.buttons & GPM_B_LEFT ) buttons[0] = 0; if( evt.buttons & GPM_B_MIDDLE ) buttons[1] = 0; if( evt.buttons & GPM_B_RIGHT ) buttons[2] = 0; } else { buttons[0] = (evt.buttons & GPM_B_LEFT) ? 1 : 0; buttons[1] = (evt.buttons & GPM_B_MIDDLE) ? 1 : 0; buttons[2] = (evt.buttons & GPM_B_RIGHT) ? 1 : 0; } channel[0] = (vrpn_float64) evt.dx / gpm_mx; channel[1] = (vrpn_float64) evt.dy / gpm_my; return 1; #elif defined(_WIN32) const unsigned LEFT_MOUSE_BUTTON = 0x01; const unsigned RIGHT_MOUSE_BUTTON = 0x02; const unsigned MIDDLE_MOUSE_BUTTON = 0x04; // Find out if the mouse buttons are pressed. if (0x80000 & GetKeyState(LEFT_MOUSE_BUTTON)) { vrpn_Button::buttons[0] = 1; } else { vrpn_Button::buttons[0] = 0; } if (0x80000 & GetKeyState(MIDDLE_MOUSE_BUTTON)) { vrpn_Button::buttons[1] = 1; } else { vrpn_Button::buttons[1] = 0; } if (0x80000 & GetKeyState(RIGHT_MOUSE_BUTTON)) { vrpn_Button::buttons[2] = 1; } else { vrpn_Button::buttons[2] = 0; } // Find the position of the cursor in X,Y with range 0..1 across the screen POINT curPos; GetCursorPos(&curPos); vrpn_Analog::channel[0] = (vrpn_float64)(curPos.x - GetSystemMetrics(SM_XVIRTUALSCREEN)) / GetSystemMetrics(SM_CXVIRTUALSCREEN); vrpn_Analog::channel[1] = (vrpn_float64)(curPos.y - GetSystemMetrics(SM_YVIRTUALSCREEN)) / GetSystemMetrics(SM_CYVIRTUALSCREEN); vrpn_gettimeofday( ×tamp, NULL ); report_changes(); return 1; #else return 0; #endif }
/****************************************************************************** * NAME : vrpn_5dt::get_report * ROLE : This function will read characters until it has a full report, then * put that report into analog fields and call the report methods on these. * ARGUMENTS : void * RETURN : void ******************************************************************************/ void vrpn_5dt::get_report (void) { int l_ret; // Return value from function call to be checked // XXX This should be called when the first character of a report is read. vrpn_gettimeofday(×tamp, NULL); //-------------------------------------------------------------------- // Read as many bytes of this report as we can, storing them // in the buffer. We keep track of how many have been read so far // and only try to read the rest. //-------------------------------------------------------------------- l_ret = vrpn_read_available_characters (serial_fd, &_buffer [_bufcount], _expected_chars - _bufcount); if (l_ret == -1) { _5DT_ERROR ("Error reading the glove"); _status = STATUS_RESETTING; return; } #ifdef VERBOSE if (l_ret != 0) printf("... got %d characters (%d total)\n",l_ret, _bufcount); #endif //-------------------------------------------------------------------- // The time of the report is the time at which the first character for // the report is read. //-------------------------------------------------------------------- if ( (l_ret > 0) && (_bufcount == 0) ) { vrpn_gettimeofday(×tamp, NULL); } //-------------------------------------------------------------------- // We keep track of how many characters we have received and keep // going back until we get as many as we expect. //-------------------------------------------------------------------- _bufcount += l_ret; if (_bufcount < _expected_chars) { // Not done -- go back for more return; } //-------------------------------------------------------------------- // We now have enough characters to make a full report. First check to // make sure that the first one is what we expect. if (_buffer[0] != 128) { _5DT_WARNING ("Unexpected first character in report, resetting"); _status = STATUS_RESETTING; _bufcount = 0; return; } if (_wireless) { if (_buffer[_bufcount - 1] != 0x40 && _buffer[_bufcount - 1] != 0x01) { // The last byte wasn't a capability byte, so this report is invalid. // Reset! _5DT_WARNING ("Unexpected last character in report, resetting"); _status = STATUS_RESETTING; _bufcount = 0; return; } } #ifdef VERBOSE printf ("Got a complete report (%d of %d)!\n", _bufcount, _expected_chars); #endif //-------------------------------------------------------------------- // Decode the report and store the values in it into the analog values // if appropriate. //-------------------------------------------------------------------- channel[1] = _buffer[1] / 255.0; //Thumb channel[2] = _buffer[2] / 255.0; channel[3] = _buffer[3] / 255.0; channel[4] = _buffer[4] / 255.0; channel[5] = _buffer[5] / 255.0; // Pinkie channel[6] = 180 * _buffer[6] / 255.0; // Pitch channel[7] = 180 * _buffer[7] / 255.0; // Roll if (_wireless && !_gotInfo) { _gotInfo = true; // Bit 0 set in the capability byte implies a right-hand glove. if (_buffer[9] == 0x01) { _5DT_INFO ("A 'wireless-type' right glove is ready and reporting"); } else { _5DT_INFO ("A 'wireless-type' left glove is ready and reporting"); } } //-------------------------------------------------------------------- // Done with the decoding, send the reports and go back to syncing //-------------------------------------------------------------------- report_changes(); switch (_mode) { case 1: _status = STATUS_SYNCING; break; case 2: // Streaming Mode, just go back for the next report. _bufcount = 0; break; default : _5DT_ERROR ("vrpn_5dt::get_report : internal error : unknown state"); break; } }
void vrpn_Nidaq::mainloop(void) { server_mainloop(); report_changes(); }
int vrpn_ImmersionBox::get_report(void) { unsigned char responseString[MAX_IBOX_STRING]; int i; unsigned int buttonBits = 0; struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 100000; status = STATUS_SYNCING; // process as long as we can get characters while (1 == vrpn_read_available_characters(serial_fd, buffer, 1)) { // if not a record start, skip it if (buffer[0] != dataPacketHeader) { continue; } // we got a good one... we're reading now status = STATUS_READING; break; } // we broke out.. if we're not reading, then we have nothing to do if (STATUS_READING != status) { return 0; } // we're reading now, get the report // get the expected number of data record bytes int result = vrpn_read_available_characters(serial_fd, (unsigned char *) responseString, dataRecordLength, &timeout ); if (result < dataRecordLength) { status = STATUS_SYNCING; return 0; } // parse the report here buttonBits = responseString[0]; for (i = 0; i < _numbuttons; i++) { vrpn_Button::lastbuttons[i] = vrpn_Button::buttons[i]; vrpn_Button::buttons[i] = static_cast<unsigned char>(buttonBits & (1 << i)); } #if VERBOSE if (vrpn_Button::buttons[3]) cerr << "left button pressed " << endl; #endif // if we processed timer bits we would do so here // here is where we decode the analog stuff for (i = 0; i < _numchannels; i++) { vrpn_Analog::last[i] = vrpn_Analog::channel[i]; } // here is where we convert the angle encoders for (i = 0; i < _numencoders; i++) { vrpn_Dial::dials[i] = 0.0; } report_changes(); vrpn_gettimeofday(×tamp, NULL); // Set watchdog now return 1; }
int vrpn_Magellan::get_report(void) { int ret; // Return value from function call to be checked int i; // Loop counter int nextchar = 1; // Index of the next character to read //-------------------------------------------------------------------- // If we're SYNCing, then the next character we get should be the start // of a report. If we recognize it, go into READing mode and tell how // many characters we expect total. If we don't recognize it, then we // must have misinterpreted a command or something; reset the Magellan // and start over //-------------------------------------------------------------------- if (status == STATUS_SYNCING) { // Try to get a character. If none, just return. if (vrpn_read_available_characters(serial_fd, _buffer, 1) != 1) { return 0; } switch (_buffer[0]) { case 'k': _expected_chars = 5; status = STATUS_READING; break; case 'b': _expected_chars = 2; status = STATUS_READING; break; case 'm': _expected_chars = 3; status = STATUS_READING; break; case 'd': _expected_chars = 26; status = STATUS_READING; break; case 'n': _expected_chars = 3; status = STATUS_READING; break; case 'q': _expected_chars = 4; status = STATUS_READING; break; case 'z': _expected_chars = 2; status = STATUS_READING; break; case 'p': _expected_chars = 4; status = STATUS_READING; break; case 'c': _expected_chars = 4; status = STATUS_READING; break; default: fprintf(stderr,"vrpn_Magellan: Unknown command (%c), resetting\n", _buffer[0]); status = STATUS_RESETTING; return 0; } // Got the first character of a report -- go into READING mode // and record that we got one character at this time. The next // bit of code will attempt to read the rest of the report. // The time stored here is as close as possible to when the // report was generated. _bufcount = 1; vrpn_gettimeofday(×tamp, NULL); status = STATUS_READING; #ifdef VERBOSE printf("... Got the 1st char\n"); #endif } //-------------------------------------------------------------------- // Read as many bytes of this report as we can, storing them // in the buffer. We keep track of how many have been read so far // and only try to read the rest. //-------------------------------------------------------------------- ret = vrpn_read_available_characters(serial_fd, &_buffer[_bufcount], _expected_chars-_bufcount); if (ret == -1) { send_text_message("vrpn_Magellan: Error reading", timestamp, vrpn_TEXT_ERROR); status = STATUS_RESETTING; return 0; } _bufcount += ret; #ifdef VERBOSE if (ret != 0) printf("... got %d characters (%d total)\n",ret, _bufcount); #endif if (_bufcount < _expected_chars) { // Not done -- go back for more return 0; } //-------------------------------------------------------------------- // We now have enough characters to make a full report. Check to make // sure that its format matches what we expect. If it does, the next // section will parse it. If it does not, we need to go back into // synch mode and ignore this report. A well-formed report has the // last character '\r' //-------------------------------------------------------------------- if (_buffer[_expected_chars-1] != '\r') { status = STATUS_SYNCING; send_text_message("vrpn_Magellan: No carriage return in record", timestamp, vrpn_TEXT_ERROR); return 0; } #ifdef VERBOSE printf("got a complete report (%d of %d)!\n", _bufcount, _expected_chars); #endif //-------------------------------------------------------------------- // Decode the report and store the values in it into the parent classes // (analog or button) if appropriate. //-------------------------------------------------------------------- switch ( _buffer[0] ) { case 'k': // This is a button command from the device. It gives us the state // of each of the buttons on the device. Buttons 1-4 are encoded // in the 4 LSBs of the first byte (key 1 in the LSB); buttons 5-8 // are in the 4 LSBs of the second byte; the * button (which we'll // call button 0) is in the LSB of the third byte (the other 3 bits // don't seem to be used). buttons[0] = ( (_buffer[3] & 0x01) != 0); buttons[1] = ( (_buffer[1] & 0x01) != 0); buttons[2] = ( (_buffer[1] & 0x02) != 0); buttons[3] = ( (_buffer[1] & 0x04) != 0); buttons[4] = ( (_buffer[1] & 0x08) != 0); buttons[5] = ( (_buffer[2] & 0x01) != 0); buttons[6] = ( (_buffer[2] & 0x02) != 0); buttons[7] = ( (_buffer[2] & 0x04) != 0); buttons[8] = ( (_buffer[2] & 0x08) != 0); break; case 'b': // Beep command received. We don't care. break; case 'm': // Mode set command. We really only care that it is still in // 3D mode (as opposed to Mouse mode); the other fields tell // whether it is in dominant axis mode, and whether translations // and rotations are being sent. We can handle any of these without // incident. if ( (_buffer[1] & 0x08) != 0) { send_text_message("vrpn_Magellan: Was put into mouse mode, resetting", timestamp, vrpn_TEXT_ERROR); status = STATUS_RESETTING; return 1; } break; case 'd': // Axis data is being returned (telling what the X,Y,Z and A,B,C axes // are currently set to). This data is put into the range [-1,1] and // put into the analog channels (0=X, 1=Y, 2=Z, 3=A, 4=B, 5=C). It comes // from the device with each axis packed into the lower nybble of 4 // consecutive bytes; the translation back to a signed 16-bit integer // is done with (N0 * 4096) + (N1 * 256) + (N2 * 16) + (N3) - 32768 // for each value; this is then scaled to [-1,1]. nextchar = 1; // Skip the zeroeth character (the command) for (i = 0; i < _numchannels; i++) { long intval; intval = (0x0f & _buffer[nextchar++]) << 12; intval += (0x0f & _buffer[nextchar++]) << 8; intval += (0x0f & _buffer[nextchar++]) << 4; intval += (0x0f & _buffer[nextchar++]); intval -= 32768; // If the absolute value of the integer is <= the NULL radius, it should // be set to zero. if ( (intval <= _null_radius) && (intval >= - _null_radius) ) { intval = 0; } // The largest values that seem to come out of the Magellan I've got // even under the maximum acceleration are absolute value 7200 or so. // We'll divide by 7500 to keep it safe. double realval = intval / 7500.0; channel[i] = realval; } break; case 'n': // NULL radius set. This is the number of ticks around zero that should // count as zero, to allow a "dead zone" for the user near the center. // We store this for the analog parsing code. The low nybble in the data // word holds the new value _null_radius = 0x0f & _buffer[1]; break; case 'q': // Sensitivity set. We don't care. break; case 'z': // The device was zeroed. We don't care. break; case 'p': // The min/max periods were set. We don't care. break; case 'c': // Some extended command was sent. I hope we don't care. // XXX Should check to make sure compression is not on. break; default: fprintf(stderr,"vrpn_Magellan: Unknown [internal] command (%c), resetting\n", _buffer[0]); status = STATUS_RESETTING; return 1; } //-------------------------------------------------------------------- // Done with the decoding, send the reports and go back to syncing //-------------------------------------------------------------------- report_changes(); status = STATUS_SYNCING; _bufcount = 0; return 1; // We got a full report. }
int vrpn_BiosciencesTools::get_report(void) { int ret; // Return value from function call to be checked //-------------------------------------------------------------------- // If we're SYNCing, then the next character we get should be the start // of a report. If we recognize it, go into READing mode and tell how // many characters we expect total. If we don't recognize it, then we // must have misinterpreted a command or something; reset // and start over //-------------------------------------------------------------------- if (status == STATUS_SYNCING) { // Try to get a character. If none, just return. if (vrpn_read_available_characters(serial_fd, (unsigned char *)(d_buffer), 1) != 1) { return 0; } d_expected_chars = 8; // Got the first character of a report -- go into READING mode // and record that we got one character at this time. The next // bit of code will attempt to read the rest of the report. // The time stored here is as close as possible to when the // report was generated. d_bufcount = 1; vrpn_gettimeofday(×tamp, NULL); status = STATUS_READING; #ifdef VERBOSE printf("... Got the 1st char\n"); #endif } //-------------------------------------------------------------------- // Read as many bytes of this report as we can, storing them // in the buffer. We keep track of how many have been read so far // and only try to read the rest. //-------------------------------------------------------------------- ret = vrpn_read_available_characters(serial_fd, (unsigned char *)(&d_buffer[d_bufcount]), d_expected_chars-d_bufcount); if (ret == -1) { DO_ERROR("Error reading"); status = STATUS_RESETTING; return 0; } d_bufcount += ret; #ifdef VERBOSE if (ret != 0) printf("... got %d characters (%d total)\n",ret, d_bufcount); #endif if (d_bufcount < d_expected_chars) { // Not done -- go back for more return 0; } d_buffer[d_expected_chars] = '\0'; // NULL terminate. //-------------------------------------------------------------------- // We now have enough characters to make a full report. Check to make // sure that its format matches what we expect. If it does, the next // section will parse it. // Store the report into the appropriate analog channel. //-------------------------------------------------------------------- float value = convert_bytes_to_reading(d_buffer); if (value == -1000) { char msg[256]; sprintf(msg,"Invalid report, channel %d, resetting", d_next_channel_to_read); DO_ERROR(msg); status = STATUS_RESETTING; } channel[d_next_channel_to_read] = value; #ifdef VERBOSE printf("got a complete report (%d of %d)!\n", d_bufcount, d_expected_chars); #endif //-------------------------------------------------------------------- // Request a reading from the next channe. //-------------------------------------------------------------------- d_next_channel_to_read = (d_next_channel_to_read + 1) % 6; if (!request_temperature(d_next_channel_to_read)) { char msg[256]; sprintf(msg,"Can't request reading, channel %d, resetting", d_next_channel_to_read); DO_ERROR(msg); status = STATUS_RESETTING; } //-------------------------------------------------------------------- // Done with the decoding, send the reports and go back to syncing //-------------------------------------------------------------------- report_changes(); status = STATUS_SYNCING; d_bufcount = 0; return 1; }
// VRPN main loop // Poll the device and let the VRPN change notifications fire void vrpn_WiiMote::mainloop() { static time_t last_error = time(NULL); vrpn_gettimeofday(&_timestamp, NULL); //XXX Try to connect once a second if we have found but not connected device. server_mainloop(); // Poll to get the status of the device. When an event happens, call // the appropriate handler to fill in our data structures. To do this, // we need a list of pointers to WiiMotes, so we create one with a single // entry. wiimote_t *selected_one[1]; selected_one[0] = wiimote->device; if (wiimote->connected && wiiuse_poll(selected_one, 1) ) { switch (wiimote->device->event) { case WIIUSE_EVENT: // A generic event handle_event(); break; case WIIUSE_STATUS: // A status event // Nothing to do here, we're polling what we need to know in mainloop. break; case WIIUSE_DISCONNECT: case WIIUSE_UNEXPECTED_DISCONNECT: wiimote->connected = false; send_text_message("Disconnected", _timestamp, vrpn_TEXT_ERROR); break; case WIIUSE_READ_DATA: // Data we requested was returned. Take a look at wiimote->device->read_req // for the info. break; case WIIUSE_NUNCHUK_INSERTED: send_text_message("Nunchuck inserted", _timestamp); break; case WIIUSE_CLASSIC_CTRL_INSERTED: send_text_message("Classic controller inserted", _timestamp); break; case WIIUSE_GUITAR_HERO_3_CTRL_INSERTED: send_text_message("Guitar Hero 3 controller inserted", _timestamp); break; case WIIUSE_NUNCHUK_REMOVED: case WIIUSE_CLASSIC_CTRL_REMOVED: case WIIUSE_GUITAR_HERO_3_CTRL_REMOVED: send_text_message("An expansion controller was removed", _timestamp, vrpn_TEXT_WARNING); break; default: send_text_message("unknown event", _timestamp); break; } } // Send any changes out over the connection. vrpn_gettimeofday(&_timestamp, NULL); report_changes(); }
int vrpn_inertiamouse::get_report(void) { int ret; // Return value from function call to be checked // // If we're SYNCing, then the next character we get should be the // start of a report. If we recognize it, go into READing mode // and tell how many characters we expect total. If we don't // recognize it, then we must have misinterpreted a command or // something; reset the intertiamouse and start over // if (status_ == STATUS_SYNCING) { // Try to get a character. If none, just return. ret = vrpn_read_available_characters (serial_fd, &buffer_[0], 1); if (ret != 1) { return 0; } switch (buffer_[0]) { case 'D': expected_chars_ = 25; break; case 'B': expected_chars_ = 4; break; default: fprintf(stderr, "vrpn_inertiamouse: Unknown command (%c), resetting\n", buffer_[0]); status_ = STATUS_RESETTING; return 0; } bufcount_ = 1; vrpn_gettimeofday (×tamp, NULL); status_ = STATUS_READING; } ret = vrpn_read_available_characters(serial_fd, &buffer_[bufcount_], expected_chars_ - bufcount_); if (ret == -1) { send_text_message("vrpn_inertiamouse: Error reading", timestamp, vrpn_TEXT_ERROR); status_ = STATUS_RESETTING; return 0; } bufcount_ += ret; if (bufcount_ < expected_chars_) { // Not done -- go back for more return 0; } if (buffer_[expected_chars_ - 1] != '\n') { status_ = STATUS_SYNCING; send_text_message("vrpn_inertiamouse: No newline in record", timestamp, vrpn_TEXT_ERROR); return 0; } switch ( buffer_[0] ) { case 'D': { int i; int nextchar; for (i = 0, nextchar = 0; i < numchannels_; ++i) { int packet; packet = (buffer_[++nextchar] & 0xf0) << 8; packet |= (buffer_[++nextchar] & 0xf0) << 4; packet |= (buffer_[++nextchar] & 0xf0); packet |= (buffer_[++nextchar] & 0xf0) >> 4; int chnl = (packet >> 10) & 7; if (chnl >= Channels) { status_ = STATUS_SYNCING; send_text_message("vrpn_inertiamouse: Too-large channel value", timestamp, vrpn_TEXT_ERROR); return 0; } int acc = packet & 0x3ff; // 10 bits // normalize to interval [-1,1] // just a guess, block dc later double normval = ((double)(acc - 256) / (double)256); // normval *= 1.5; // update rotation data if ( (chnl == 4) || (chnl == 5) ) { channel[chnl] = normval; break; } normval = dcb_[chnl].filter (normval); normval = lp_[chnl].filter (normval); double dt = 0.25; // update velocity and position only when button[0] pressed if (buttons[0]) { double pos = vel_[chnl] * dt + normval * dt * dt / 2; vel_[chnl] += normval*dt; if(fabs (vel_[chnl]) < dt/2.0) vel_[chnl] *= 0.90; // else // if (fabs (vel_[chnl]) > 1.0) // vel_[chnl] *= 1.0 / fabs (vel_[chnl]); channel[chnl] = pos; // channel[chnl] *= 0.95; } else { vel_[chnl] = 0.0; channel[chnl] = 0.0; } } } break; case 'B': buttons[0] = ((buffer_[1] & 1) != 0); buttons[1] = ((buffer_[1] & 2) != 0); break; default: fprintf(stderr, "vrpn_inertiamouse: Unknown [internal] command (%c), resetting\n", buffer_[0]); status_ = STATUS_RESETTING; return 0; } // // Done with the decoding, send the reports and go back to syncing // report_changes(); status_ = STATUS_SYNCING; bufcount_ = 0; return 1; // We got a full report. }
int vrpn_Spaceball::get_report(void) { unsigned char rawbuf[1024]; // raw unprocessed incoming characters int i, num, packs; #if defined(DEBUG) int j; #endif packs = 0; /* no packs received yet */ // read up to 1023 unprocessed characters from the serial device at once num = vrpn_read_available_characters(serial_fd, rawbuf, 1023); // if we receive 1 or more chars, we will see if this completes any // pending packets we're trying to process. if (num > 0) { for (i=0; i<num; i++) { /* process potentially occurring escaped character sequences */ if (rawbuf[i] == '^') { if (!escapedchar) { escapedchar = 1; continue; /* eat the escape character from buffer */ } } /* if in escaped mode, we convert the escaped char to final form */ if (escapedchar) { escapedchar = 0; /* we're back out of escape mode after this */ switch (rawbuf[i]) { case '^': /* leave char in buffer unchanged */ break; case 'Q': case 'S': case 'M': rawbuf[i] &= 0x1F; /* convert character to unescaped form */ break; default: #if defined(DEBUG) printf("\nGot a bad escape sequence! 0x%02x", rawbuf[i]); if (isprint(rawbuf[i])) printf(" (%c)", rawbuf[i]); else printf(" (unprintable)"); printf("\n"); #endif break; } } /* figure out what kind of packet we received */ if (bufpos == 0) { status = STATUS_SYNCING; /* update our status */ switch(rawbuf[i]) { case 'D': /* Displacement packet */ packtype = 'D'; packlen = 16; /* D packets are 15 bytes long */ break; case 'K': /* Button/Key packet */ packtype = 'K'; packlen = 4; /* K packets are 3 bytes long */ break; case '.': /* Spaceball 4000 FLX "advanced" button press event */ packtype = '.'; packlen = 4; /* . packets are 3 bytes long */ break; case 'C': /* Communications mode packet */ packtype = 'C'; packlen = 4; break; case 'F': /* Spaceball sensitization mode packet */ packtype = 'F'; packlen = 4; break; case 'M': /* Movement mode packet */ packtype = 'M'; packlen = 5; break; case 'N': /* Null region packet */ packtype = 'N'; packlen = 3; break; case 'P': /* Update rate packet */ packtype = 'P'; packlen = 6; break; case '\v': /* XON at poweron */ packtype = '\v'; packlen = 1; break; case '\n': /* carriage return at poweron */ case '\r': /* carriage return at poweron */ packtype = '\r'; packlen = 1; break; case '@': /* Spaceball Hard/Soft Reset packet */ resetoccured=1; packtype = '@'; packlen = 62; /* Resets aren't longer than 62 chars */ break; case 'E': /* Error packet */ packtype = 'E'; packlen = 8; /* E packets are up to 7 bytes long */ break; case 'Z': /* Zero packet (Spaceball 2003/3003/4000 FLX) */ packtype = 'Z'; packlen = 14; /* Z packets are hardware dependent */ break; default: /* Unknown packet! */ #if defined(DEBUG) printf("\nUnknown packet (1) [%d]: 0x%02x \n ", i, rawbuf[i]); printf(" char: "); if (isprint(rawbuf[i])) printf("%c", rawbuf[i]); else printf(" (unprintable)"); printf("\n"); #endif continue; } } buf[bufpos] = rawbuf[i]; /* copy processed chars into long-term buffer */ bufpos++; /* go to next buffer slot */ /* Reset packet processing */ if (packtype == '@') { if (rawbuf[i] != '\r') continue; else packlen = bufpos; } /* Error packet processing */ if (packtype == 'E') { if (rawbuf[i] != '\r') continue; else packlen = bufpos; } else if (bufpos != packlen) continue; status = STATUS_READING; // ready to process event packet vrpn_gettimeofday(×tamp, NULL); // set timestamp of this event switch (packtype) { case 'D': /* ball displacement event */ { int nextchar, chan; /* number of 1/16ths of milliseconds since last */ /* ball displacement packet */ nextchar = 1; // this is where the timer data is, if we want it. nextchar = 3; // Skip the zeroeth character (the command) for (chan = 0; chan < _numchannels; chan++) { vrpn_int16 intval; intval = (buf[nextchar++]) << 8; intval |= (buf[nextchar++]); // If the absolute value of the integer is <= the NULL // radius, it should be set to zero. if ( (intval <= null_radius) && (intval >= - null_radius) ) { intval = 0; } // maximum possible values per axis are +/- 32768, although the // largest value I've ever observed among several devices // is only 20,000. For now, we'll divide by 32768, and if this is // too insensitive, we can do something better later. double realval = intval / 32768.0; channel[chan] = realval; // printf("XXX Channel[%d] = %f %d \n", z, realval, intval); } channel[2] = -channel[2]; // Negate Z translation channel[5] = -channel[5]; // Negate Z rotation } break; case 'K': /* button press event */ /* Spaceball 2003A, 2003B, 2003 FLX, 3003 FLX, 4000 FLX */ /* button packet. (4000 only for backwards compatibility) */ /* The lowest 5 bits of the first byte are buttons 5-9 */ /* Button '8' on a Spaceball 2003 is the rezero button */ /* The lowest 4 bits of the second byte are buttons 1-4 */ /* For Spaceball 2003, we'll map the buttons 1-7 normally */ /* skip 8, as its a hardware "rezero button" on that device */ /* and call the "pick" button "8". */ /* On the Spaceball 3003, the "right" button also triggers */ /* the "pick" bit. We OR the 2003/3003 rezero bits together */ /* if we have found a Spaceball 4000, then we ignore the 'K' */ /* packets entirely, and only use the '.' packets. */ if (spaceball4000) break; // XXX my original libsball button decoding code, for reference // buttons = // ((buf[1] & 0x10) << 3) | /* 2003 pick button is "8" */ // ((buf[1] & 0x20) << 9) | /* 3003 rezero button */ // ((buf[1] & 0x08) << 11) | /* 2003 rezero button */ // ((buf[1] & 0x07) << 4) | /* 5,6,7 (2003/4000) */ // ((buf[2] & 0x30) << 8) | /* 3003 Left/Right buttons */ // ((buf[2] & 0x0F)); /* 1,2,3,4 (2003/4000) */ // Mapping the buttons is tricky since different models // of the Spaceball have different button sets. // 2003 has 9 buttons (rezero included) // 3003 has 3 buttons (rezero included) // 4000 has 12 buttons, and can be in "lefty" or "righty" mode. // We'll skip reporting lefty/righty mode for now though. // Spaceball 2003/4000 buttons 1-4 mapped to slots 0-3 // Spaceball 3003 L/R buttons are mapped as slots 0/1 buttons[0] = static_cast<unsigned char>(((buf[2] & 0x01) != 0) | ((buf[2] & 0x10) != 0)); buttons[1] = static_cast<unsigned char>(((buf[2] & 0x02) != 0) | ((buf[2] & 0x20) != 0)); buttons[2] = static_cast<unsigned char>(((buf[2] & 0x04) != 0)); buttons[3] = static_cast<unsigned char>(((buf[2] & 0x08) != 0)); // Spaceball 2003/4000 buttons 5,6,7 mapped to slots 4-6 buttons[4] = static_cast<unsigned char>(((buf[1] & 0x01) != 0)); buttons[5] = static_cast<unsigned char>(((buf[1] & 0x02) != 0)); buttons[6] = static_cast<unsigned char>(((buf[1] & 0x04) != 0)); // Spaceball 2003/3003 rezero buttons are mapped to slot 7 // The rezero button's function is sometimes hard-wired, // and may or may not be used by applications, this is up // in the air still. For now, I'll map it to slot 7 which // keeps the numbering in a sane order on the 2003 device anyway. buttons[7] = static_cast<unsigned char>(((buf[1] & 0x20) != 0) | ((buf[1] & 0x08) != 0)); // Spaceball 2003 pick button mapped to slot 8 // Note: the pick button is the button embedded into the front // surface of the control sphere. buttons[8] = static_cast<unsigned char>(((buf[1] & 0x10) != 0)); break; case '.': /* button press event (4000) */ /* Spaceball 4000 FLX "expanded" button packet, with 12 buttons */ /* extra packet validity check, since we use this packet type */ /* to override the 'K' button packets, and determine if its a */ /* Spaceball 4000 or not... */ if (buf[3] != '\r') { break; /* if not terminated with a '\r', probably garbage */ } /* if we got a valid '.' packet, this must be a Spaceball 4000 */ #if defined(DEBUG) if (!spaceball4000) printf("\nDetected a Spaceball 4000 FLX\n"); #endif spaceball4000 = 1; /* Must be talking to a Spaceball 4000 */ // XXX my original libsball button decoding code, for reference // buttons = // (((~buf[1]) & 0x20) << 10) | /* "left handed" mode */ // ((buf[1] & 0x1F) << 7) | /* 8,9,10,11,12 */ // ((buf[2] & 0x3F) ) | /* 1,2,3,4,5,6 */ // ((buf[2] & 0x80) >> 1); /* 7 */ /* Spaceball 4000 series "expanded" button press event */ /* includes data for 12 buttons, and left/right orientation */ buttons[0] = ((buf[2] & 0x01) != 0); // SB 4000 button 1 buttons[1] = ((buf[2] & 0x02) != 0); // SB 4000 button 2 buttons[2] = ((buf[2] & 0x04) != 0); // SB 4000 button 3 buttons[3] = ((buf[2] & 0x08) != 0); // SB 4000 button 4 buttons[4] = ((buf[2] & 0x10) != 0); // SB 4000 button 5 buttons[5] = ((buf[2] & 0x20) != 0); // SB 4000 button 6 buttons[6] = ((buf[2] & 0x80) != 0); // SB 4000 button 7 buttons[7] = ((buf[1] & 0x01) != 0); // SB 4000 button 8 buttons[8] = ((buf[1] & 0x02) != 0); // SB 4000 button 9 buttons[9] = ((buf[1] & 0x04) != 0); // SB 4000 button 10 buttons[10] = ((buf[1] & 0x08) != 0); // SB 4000 button 11 buttons[11] = ((buf[1] & 0x10) != 0); // SB 4000 button 12 // XXX lefty/righty mode handling goes here if we wish to // represent it as a "button" etc.. //buttons[??] = ((~buf[1]) & 0x20) != 0) // SB 4000 "lefty" mode bit #if defined(DEBUG) if (leftymode4000 != ((buf[1] & 0x20) == 0)) printf("\nSpaceball 4000 mode changed to: %s\n", (((buf[1] & 0x20) == 0) ? "left handed" : "right handed")); #endif /* set "lefty" orientation mode if "lefty bit" is _clear_ */ if ((buf[1] & 0x20) == 0) leftymode4000 = 1; /* left handed mode */ else leftymode4000 = 0; /* right handed mode */ break; case 'C': /* Communications mode packet */ case 'F': /* Spaceball sensitization packet */ case 'P': /* Spaceball update rate packet */ case 'M': /* Spaceball movement mode packet */ case 'N': /* Null region packet */ case '\r': /* carriage return at poweron */ case '\v': /* XON at poweron */ /* eat and ignore these packets */ break; case '@': /* Reset packet */ #if defined(DEBUG) printf("Spaceball reset: "); for (j=0; j<packlen; j++) { if (isprint(buf[j])) printf("%c", buf[j]); } printf("\n"); #endif /* if we get a reset packet, we have to re-initialize */ /* the device, and assume that its completely schizophrenic */ /* at this moment, we must reset it again at this point */ resetoccured=1; reset(); // was sball_hwreset() break; case 'E': /* Error packet, hardware/software problem */ erroroccured++; #if defined(DEBUG) printf("\nSpaceball Error!! "); printf("Error code: "); for (j=0; j<packlen; j++) { printf(" 0x%02x ", buf[j]); } printf("\n"); #endif break; case 'Z': /* Zero packet (Spaceball 2003/3003/4000 FLX) */ /* We just ignore these... */ break; default: #if defined(DEBUG) printf("Unknown packet (2): 0x%02x\n", packtype); printf(" char: "); if (isprint(packtype)) printf("%c", packtype); else printf(" (unprintable)"); printf("\n"); #endif break; } /* reset */ bufpos = 0; packtype = 0; packlen = 1; packs++; } } report_changes(); // Report updates to VRPN if (packs > 0) return 1; // got at least 1 full report else return 0; // didn't get any full reports }