// created: 2019/03/12 // filename: VrpnLite.cpp // // author: Guillaume Sanahuja // Copyright Heudiasyc UMR UTC/CNRS 7253 // // version: $Id: $ // // purpose: vrpnlite, to forward it to bth for exemple // usefull to reduce vrpn frame size // /*********************************************************************/ #include "VrpnLite.h" #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace flair::core; using namespace flair::sensor; using namespace flair::gui; //if we don'receive ack from client, do not send vrpnobjects anymore #define REMOVE_TIMEOUT (Time)2000000000 VrpnLite::VrpnLite(int vrpnLitePort,string vrpnServerAddress): Thread(getFrameworkManager(),"VrpnLite",90) { vrpnclient=new VrpnClient("vrpn", vrpnServerAddress,80); Tab* tab=new Tab(vrpnclient->GetTabWidget(),"Main"); killButton=new PushButton(tab->NewRow(),"kill"); dataSocket = new UdpSocket(this,"client socket",vrpnLitePort); vrpnclient->Start(); } VrpnLite::~VrpnLite() { } void VrpnLite::Run(void) { Time dataSocketTimeout; char msg[256]; int src_id; while (!ToBeStopped()) { if(killButton->Clicked()) SafeStop(); //get last vrpnobject VrpnObject* lastVrpnObject=NULL; if(connections.size()!=0) { if(connections.back().vrpnobjects.size()!=0) lastVrpnObject=lastVrpnObject=connections.back().vrpnobjects.back(); } if(lastVrpnObject!=NULL) { //wait for last one to be sure all are up to date //but if object is not tracked we send nothing... send it unsynchronized??? if(WaitUpdate(lastVrpnObject,100000000)) { SendObjects(); } dataSocketTimeout=TIME_NONBLOCK; } else { dataSocketTimeout=100000000; } ssize_t rcv=dataSocket->RecvMessage(msg,sizeof(msg),dataSocketTimeout,NULL,NULL,&src_id); connection_t* matchConnection=ConnectionOfSrcId(src_id); //receive an ack if(rcv==1) { if(matchConnection!=NULL) matchConnection->lastAck=GetTime(); continue;//do not handle add or remove cases } if(rcv>0) {//add or remove int16_t id; string objectName=string(msg,rcv-sizeof(id)); memcpy(&id,&msg[rcv-sizeof(id)],sizeof(id)); dataSocket->HostToNetwork((char*)&id,sizeof(id)); if(id>0) { //add object if(matchConnection==NULL) { connection_t connection; connection.lastAck=GetTime(); connection.srcId=src_id; connections.push_back(connection); matchConnection=&(connections.back()); } //assume we receive it in the good order if(id==matchConnection->vrpnobjects.size()+1) {//id 0 is not used as we use positive and negative id for add/remove Printf("adding object %s with id %i from client %i\n",objectName.c_str(),id,src_id); VrpnObject* vrpnobject = new VrpnObject(objectName,vrpnclient->GetTabWidget()); matchConnection->vrpnobjects.push_back(vrpnobject); }else { Err("adding object %s failed, expected id %i, got %i\n",objectName.c_str(),matchConnection->vrpnobjects.size()+1,id); } } else { //remove object for (auto it = matchConnection->vrpnobjects.begin();it < matchConnection->vrpnobjects.end(); it++) { if ((*it)->ObjectName() == objectName) { Printf("removing object %s with id %i from client %i\n",objectName.c_str(),-id,src_id); delete (*it); auto iteratorEnd=remove(matchConnection->vrpnobjects.begin(), matchConnection->vrpnobjects.end(),(*it)); matchConnection->vrpnobjects.erase(iteratorEnd, matchConnection->vrpnobjects.end()); if(matchConnection->vrpnobjects.size()==0) { Printf("TODO: removing empty client %i\n",src_id); //auto iteratorEnd=remove(connections.begin(), connections.end(),*matchConnection); //connections.erase(iteratorEnd, connections.end()); } break; } } } } } } VrpnLite::connection_t* VrpnLite::ConnectionOfSrcId(uint16_t srcId) { for (int i=0;iObjectName().c_str(),connections.at(i).srcId,sizeof(datas)); vrpnobject->GetPosition(objectPosition); vrpnobject->GetQuaternion(objectQuaternion); time=vrpnobject->GetLastPacketTime(); position[0]=ConvertPosition(objectPosition.x); position[1]=ConvertPosition(objectPosition.y); position[2]=ConvertPosition(objectPosition.z); quaternion[0]=ConvertQuaternion(objectQuaternion.q0); quaternion[1]=ConvertQuaternion(objectQuaternion.q1); quaternion[2]=ConvertQuaternion(objectQuaternion.q2); quaternion[3]=ConvertQuaternion(objectQuaternion.q3); for(int i=0;i<3;i++) dataSocket->HostToNetwork((char*)(&position[i]),sizeof(position[i])); for(int i=0;i<4;i++) dataSocket->HostToNetwork((char*)(&quaternion[i]),sizeof(quaternion[i])); memcpy(datasPtr,position, sizeof(position)); datasPtr+=sizeof(position); memcpy(datasPtr,quaternion, sizeof(quaternion)); datasPtr+=sizeof(quaternion); } dataSocket->HostToNetwork((char*)(&time),sizeof(Time)); memcpy(datasPtr,&time, sizeof(time));//only one time for all VrpnObject; suppose it is the same! dataSocket->SendMessage(datas,sizeof(datas),connections.at(i).srcId); //printf("%lld send client %i size %i\n",GetTime()/1000000,connections.at(i).srcId,sizeof(datas)); } } int16_t VrpnLite::ConvertQuaternion(float value) const{ int16_t tmp; tmp=value*32767.; if(value<-1) { tmp=-32767; Warn("position value is %f, saturating it to %i\n",value,tmp); } if(value>1) { tmp=32767; Warn("position value is %f, saturating it to %i\n",value,tmp); } return tmp; } int16_t VrpnLite::ConvertPosition(float value) const{ int16_t tmp; tmp=value*1000; if(value<-32.768) { tmp=-32768; Warn("position value is %f, saturating it to %i\n",value,tmp); } if(value>32.767) { tmp=32767; Warn("position value is %f, saturating it to %i\n",value,tmp); } return tmp; }