// %flair:license{ // This file is part of the Flair framework distributed under the // CECILL-C License, Version 1.0. // %flair:license} // created: 2013/04/03 // filename: VrpnClient_impl.cpp // // author: César Richard, Guillaume Sanahuja // Copyright Heudiasyc UMR UTC/CNRS 7253 // // version: $Id: $ // // purpose: objet se connectant au serveur vrpn // // /*********************************************************************/ #include "VrpnClient.h" #include "VrpnClient_impl.h" #include "VrpnObject.h" #include "VrpnObject_impl.h" #include #include #include #include #include #include #include #include #include #include #include #include using std::string; using std::vector; using namespace flair::core; using namespace flair::gui; using namespace flair::sensor; VrpnClient_impl::VrpnClient_impl(VrpnClient *self, string name, std::string address,flair::sensor::VrpnClient::ConnectionType_t connectionType) { this->self = self; this->address = address; this->connectionType = connectionType; isConnected=false; if(connectionType==VrpnClient::Vrpn) { connection = vrpn_get_connection_by_name(address.c_str()); Printf("Connecting to VRPN server on %s\n",address.c_str()); } else if(connectionType==VrpnClient::VrpnLite) { dataSocket =new UdpSocket(getFrameworkManager(), "data_socket", address); Printf("Connecting to VRPN-lite server on %s\n",address.c_str()); } else { self->Err("Bad connection type, try using naother constructor\n"); } CommonConstructor(name); } VrpnClient_impl::VrpnClient_impl(VrpnClient *self, string name, SerialPort *serialport, uint16_t us_period) { this->us_period = us_period; this->self = self; this->serialport = serialport; connectionType=VrpnClient::Xbee; serialport->SetBaudrate(111111); serialport->SetRxTimeout(us_period * 1000); CommonConstructor(name); Printf("Connecting to VRPN server through xbee on %s\n",serialport->ObjectName().c_str()); } void VrpnClient_impl::CommonConstructor(std::string name) { mutex = new Mutex(self, name); // station sol main_tab = new Tab(getFrameworkManager()->GetTabWidget(), name); tab = new TabWidget(main_tab->NewRow(), name); setup_tab = new Tab(tab, "Reglages"); rotation_1 = new OneAxisRotation(setup_tab->NewRow(), "post rotation 1",OneAxisRotation::PreRotation); rotation_2 = new OneAxisRotation(setup_tab->NewRow(), "post rotation 2",OneAxisRotation::PreRotation); } VrpnClient_impl::~VrpnClient_impl() { if (connectionType==VrpnClient::Vrpn|| connectionType==VrpnClient::VrpnLite) { // on fait une copie car le delete touche a trackables_copy via // RemoveTrackable vector trackables_copy = trackables; for (unsigned int i = 0; i < trackables_copy.size(); i++) delete trackables_copy.at(i)->self; // trackables.clear(); } else if(connectionType==VrpnClient::Xbee ) { // on fait une copie car le delete touche a xbee_objects_copy via // RemoveTrackable vector xbeeObjects_copy = xbeeObjects; for (unsigned int i = 0; i < xbeeObjects_copy.size(); i++) delete xbeeObjects_copy.at(i).vrpnobject->self; } delete main_tab; if (connectionType==VrpnClient::Vrpn) { // it will automatically delete connection connection->removeReference(); } } void VrpnClient_impl::ComputeRotations(Vector3Df &point) { rotation_1->ComputeRotation(point); rotation_2->ComputeRotation(point); } void VrpnClient_impl::ComputeRotations(Quaternion &quat) { rotation_1->ComputeRotation(quat); rotation_2->ComputeRotation(quat); } void VrpnClient_impl::AddTrackable(VrpnObject_impl *obj) { if (connectionType==VrpnClient::Vrpn) { mutex->GetMutex(); trackables.push_back(obj); mutex->ReleaseMutex(); } else if (connectionType==VrpnClient::VrpnLite) { if(trackables.size()GetMutex(); trackables.push_back(obj); mutex->ReleaseMutex(); char char_array[obj->self->ObjectName().length() + sizeof(id)]; strcpy(char_array, obj->self->ObjectName().c_str()); dataSocket->HostToNetwork((char*)(&id),sizeof(id)); memcpy(&char_array[obj->self->ObjectName().length()],&id,sizeof(id)); dataSocket->SendMessage(char_array,obj->self->ObjectName().length() + sizeof(id)); }else { self->Warn("too much trackables for vrpnlite connection, not adding %s\n",obj->self->ObjectName().c_str()); } } else { self->Warn("AddTrackable called but not in vrpn mode nor in vrpnlite mode\n"); } } void VrpnClient_impl::AddTrackable(VrpnObject_impl *obj, uint8_t id) { if (connectionType==VrpnClient::Xbee) { xbeeObject_t tmp; tmp.vrpnobject = obj; tmp.id = id; mutex->GetMutex(); xbeeObjects.push_back(tmp); mutex->ReleaseMutex(); } else { self->Warn("AddTrackable called but not in xbee mode\n"); } } void VrpnClient_impl::RemoveTrackable(VrpnObject_impl *obj) { mutex->GetMutex(); //send remove notification to vrpnlite if (connectionType==VrpnClient::VrpnLite) { for (size_t i = 0; i < trackables.size(); i++) { if(trackables.at(i)==obj) { int16_t id=-(i+1);//avoid 0; positive values for adding, negative for removing char char_array[obj->self->ObjectName().length() + sizeof(id)]; strcpy(char_array, obj->self->ObjectName().c_str()); dataSocket->HostToNetwork((char*)(&id),sizeof(id)); memcpy(&char_array[obj->self->ObjectName().length()],&id,sizeof(id)); dataSocket->SendMessage(char_array,obj->self->ObjectName().length() + sizeof(id)); break; } } } //update vector if (connectionType==VrpnClient::Vrpn || connectionType==VrpnClient::VrpnLite) { for (vector::iterator it = trackables.begin();it < trackables.end(); it++) { if (*it == obj) { trackables.erase(it); break; } } } if ( connectionType==VrpnClient::Xbee) { for (vector::iterator it = xbeeObjects.begin();it < xbeeObjects.end(); it++) { if ((*it).vrpnobject == obj) { xbeeObjects.erase(it); break; } } } mutex->ReleaseMutex(); } void VrpnClient_impl::Run(void) { struct timeval timeout; timeout.tv_sec=0; timeout.tv_usec=100000; while (!self->ToBeStopped()) { if (connectionType==VrpnClient::Xbee) { ssize_t read = 0; uint8_t response[38] = {0}; read = serialport->Read(response, sizeof(response)); if (read > 0 && read != sizeof(response)) read += serialport->Read(&response[read], sizeof(response) - read); // int temps=(float)self->GetTime()/(1000*1000); // self->Printf("%i %i %i\n",temps-last,temps,last); // last=temps; if (read < 0) { // self->Warn("erreur rt_dev_read (%s)\n",strerror(-read)); } else if (read != sizeof(response)) { self->Warn("serial read error %i/%i\n", read, sizeof(response)); } else { // for(ssize_t i=0;iErr("checksum error\n"); } else { vrpn_TRACKERCB t; float pos[3]; float quat[4]; uint8_t id = response[8]; mutex->GetMutex(); if (id < xbeeObjects.size()) { memcpy(pos, &response[9], sizeof(pos)); memcpy(quat, &response[9] + sizeof(pos), sizeof(quat)); for (int i = 0; i < 3; i++) t.pos[i] = pos[i]; for (int i = 0; i < 4; i++) t.quat[i] = quat[i]; if (fabs(pos[0] > 10) || fabs(pos[1] > 10) || fabs(pos[2] > 10)) { Printf("prob pos %f %f %f\n", pos[0], pos[1], pos[2]); } else { // self->Printf("%i %f %f %f // %f\n",id,pos[0],pos[1],pos[2],(float)self->GetTime()/(1000*1000)); VrpnObject_impl::handle_pos(xbeeObjects.at(id).vrpnobject, t); } } mutex->ReleaseMutex(); } } } else if(connectionType==VrpnClient::Vrpn) { if(connection->connected()==vrpn_true && !isConnected) { isConnected=true; Printf("VRPN connected to %s\n",address.c_str()); } if(connection->connected()==vrpn_false && isConnected) { isConnected=false; Printf("VRPN disconnected to %s\n",address.c_str()); } //timeout in mainloop is not well handled if not connected... if(isConnected) { //this is when trackables callbacks are called: if(connection->mainloop(&timeout)!=0) { self->Warn("connection dropped from\n",address.c_str()); } //printf("%lld\n",GetTime()/(1000*1000)); mutex->GetMutex(); for (unsigned int i = 0; i < trackables.size(); i++) { // Printf("tracker %i\n",i); trackables.at(i)->tracker->mainloop(); //Printf("tracker %i ok\n",i); } mutex->ReleaseMutex(); } else { connection->mainloop(); self->SleepMS(10); } }else if(connectionType==VrpnClient::VrpnLite) { mutex->GetMutex(); int16_t pos[3]; int16_t quat[4]; Time time; char datas[trackables.size()*(sizeof(pos)+sizeof(quat))+ sizeof(time)]; char *datasPtr=datas; int rcv=dataSocket->RecvMessage(datas,sizeof(datas),50*1000*1000); if(rcv!=sizeof(datas)) { if(rcv>0) Printf("discarding message (size %i/%i)\n",rcv,sizeof(datas)); mutex->ReleaseMutex(); continue; } memcpy(&time, datasPtr+sizeof(datas)-sizeof(time), sizeof(time)); dataSocket->NetworkToHost((char*)(&time),sizeof(time)); for (vector::iterator it = trackables.begin();it < trackables.end(); it++) { memcpy(pos, datasPtr, sizeof(pos)); datasPtr+=sizeof(pos); memcpy(quat,datasPtr, sizeof(quat)); datasPtr+=sizeof(quat); for(int i=0;i<3;i++) dataSocket->NetworkToHost((char*)(&pos[i]),sizeof(pos[i])); for(int i=0;i<4;i++) dataSocket->NetworkToHost((char*)(&quat[i]),sizeof(quat[i])); vrpn_TRACKERCB t; for (int i = 0; i < 3; i++) t.pos[i] = ConvertPosition(pos[i]); // warning: t.quat is defined as (qx,qy,qz,qw), which is different from // flair::core::Quaternion t.quat[0] = ConvertQuaternion(quat[1]); t.quat[1] = ConvertQuaternion(quat[2]); t.quat[2] = ConvertQuaternion(quat[3]); t.quat[3] = ConvertQuaternion(quat[0]); t.msg_time.tv_sec=time/((Time)1000000000); t.msg_time.tv_usec=(time%((Time)1000000000))/((Time)1000); //Printf("%i %lld %lld %lld\n",id,time,t.msg_time.tv_sec,t.msg_time.tv_usec); VrpnObject_impl::handle_pos((void*)(*it), t); } mutex->ReleaseMutex(); } } } float VrpnClient_impl::ConvertPosition(int16_t value) const { return (float)value/1000.; } float VrpnClient_impl::ConvertQuaternion(int16_t value) const { return (float)value/32767.; }