#include <stdio.h> // for fprintf, stderr, NULL #include "vrpn_Connection.h" // for vrpn_Connection, etc #include "vrpn_Dial.h" //#define VERBOSE vrpn_Dial::vrpn_Dial(const char *name, vrpn_Connection *c) : vrpn_BaseClass(name, c) { vrpn_BaseClass::init(); num_dials = 0; // Set the time to 0 just to have something there. timestamp.tv_usec = timestamp.tv_sec = 0; } int vrpn_Dial::register_types(void) { if (d_connection == NULL) { return 0; } change_m_id = d_connection->register_message_type("vrpn_Dial update"); if (change_m_id == -1) { fprintf(stderr, "vrpn_Dial: Can't register type IDs\n"); d_connection = NULL; } return 0; } vrpn_int32 vrpn_Dial::encode_to(char *buf, vrpn_int32 buflen, vrpn_int32 dial, vrpn_float64 delta) { vrpn_int32 buflensofar = buflen; // Message includes: vrpn_int32 dialNum, vrpn_float64 delta // We pack them with the delta first, so that everything is aligned // on the proper boundary. if (vrpn_buffer(&buf, &buflensofar, delta)) { fprintf(stderr, "vrpn_Dial::encode_to: Can't buffer delta\n"); return -1; } if (vrpn_buffer(&buf, &buflensofar, dial)) { fprintf(stderr, "vrpn_Dial::encode_to: Can't buffer dial\n"); return -1; } return sizeof(vrpn_float64) + sizeof(vrpn_int32); } // This will report any changes that have appeared in the dial values, // and then clear the dials back to 0. It only sends dials that have // changed (nonzero values) void vrpn_Dial::report_changes(void) { char msgbuf[1000]; vrpn_int32 i; vrpn_int32 len; if (d_connection) { for (i = 0; i < num_dials; i++) { if (dials[i] != 0) { len = encode_to(msgbuf, sizeof(msgbuf), i, dials[i]); if (d_connection->pack_message(len, timestamp, change_m_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "vrpn_Dial: can't write message: tossing\n"); } dials[i] = 0; // We've reported it the change. } } } } // This will report the dials whether they have changed or not; this // will result in some 0 dial values being sent. Normally, code will // use the report_changes method to avoid flooding the system with // un-needed messages. // It then clears the dials back to 0. void vrpn_Dial::report(void) { char msgbuf[1000]; vrpn_int32 i; vrpn_int32 len; if (d_connection) { for (i = 0; i < num_dials; i++) { len = encode_to(msgbuf, sizeof(msgbuf), i, dials[i]); if (d_connection->pack_message(len, timestamp, change_m_id, d_sender_id, msgbuf, vrpn_CONNECTION_RELIABLE)) { fprintf(stderr, "vrpn_Dial: can't write message: tossing\n"); } dials[i] = 0; // We've reported it the change. } } } // ************* EXAMPLE SERVER ROUTINES **************************** vrpn_Dial_Example_Server::vrpn_Dial_Example_Server(const char *name, vrpn_Connection *c, vrpn_int32 numdials, vrpn_float64 spin_rate, vrpn_float64 update_rate) : vrpn_Dial(name, c) , // Construct the base class, which registers message/sender _spin_rate(spin_rate) , // Set the rate at which the dials will spin _update_rate(update_rate) // Set the rate at which to generate reports { // Make sure we asked for a legal number of dials if (num_dials > vrpn_DIAL_MAX) { fprintf(stderr, "vrpn_Dial_Example_Server: Only using %d dials\n", vrpn_DIAL_MAX); num_dials = vrpn_DIAL_MAX; } else { num_dials = numdials; } // IN A REAL SERVER, open the device that will service the dials here } 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(); } } // ************* CLIENT ROUTINES **************************** vrpn_Dial_Remote::vrpn_Dial_Remote(const char *name, vrpn_Connection *c) : vrpn_Dial(name, c) { vrpn_int32 i; // Register a handler for the change callback from this device, // if we got a connection. if (d_connection) { if (register_autodeleted_handler(change_m_id, handle_change_message, this, d_sender_id)) { fprintf(stderr, "vrpn_Dial_Remote: can't register handler\n"); d_connection = NULL; } } else { fprintf(stderr, "vrpn_Dial_Remote: Can't get connection!\n"); } // At the start, as far as the client knows, the device could have // max channels -- the number of channels is specified in each // message. num_dials = vrpn_DIAL_MAX; for (i = 0; i < vrpn_DIAL_MAX; i++) { dials[i] = 0.0; } vrpn_gettimeofday(×tamp, NULL); } vrpn_Dial_Remote::~vrpn_Dial_Remote() {} void vrpn_Dial_Remote::mainloop() { client_mainloop(); if (d_connection) { d_connection->mainloop(); } } int vrpn_Dial_Remote::handle_change_message(void *userdata, vrpn_HANDLERPARAM p) { vrpn_Dial_Remote *me = (vrpn_Dial_Remote *)userdata; vrpn_DIALCB cp; const char *bufptr = p.buffer; cp.msg_time = p.msg_time; vrpn_unbuffer(&bufptr, &cp.change); vrpn_unbuffer(&bufptr, &cp.dial); // Go down the list of callbacks that have been registered. // Fill in the parameter and call each. me->d_callback_list.call_handlers(cp); return 0; }