|
Urbi SDK Remote for C++
2.7.5
|
00001 /* 00002 * Copyright (C) 2011-2012, Gostai S.A.S. 00003 * 00004 * This software is provided "as is" without warranty of any kind, 00005 * either expressed or implied, including but not limited to the 00006 * implied warranties of fitness for a particular purpose. 00007 * 00008 * See the LICENSE file for more information. 00009 */ 00010 00011 #include <urbi/uobject.hh> 00012 #include <urbi/customuvar.hh> 00013 using namespace urbi; 00014 00020 class Fusion: public UObject 00021 { 00022 public: 00023 Fusion(const std::string& n); 00024 ~Fusion(); 00025 void init(); 00029 unsigned int addSource(UVar& src, const std::string& dst); 00031 void require(unsigned int uid, bool enable); 00033 void trigger(unsigned int uid, bool enable); 00037 void interpolate(unsigned int uid, bool enable); 00039 UVar rtpBackend; 00040 private: 00041 struct VarData 00042 { 00043 VarData(); 00044 bool trigger; 00045 bool require; 00046 bool interpolate; 00047 std::string dst; 00048 bool updated; // got a value (reset upon commit) 00049 }; 00050 void commit(); 00051 void onChange(UVar& v); 00052 void onBackendChange(std::string v); 00053 bool triggerMet; 00054 libport::utime_t interpTimestamp; // Target timestamp of interpolation 00055 unsigned int nRequire; // total number of requires setup 00056 unsigned int nRequireMet; // number of met requires 00057 typedef CustomUVar<VarData> FusionVar; 00058 std::vector<FusionVar*> vars; 00059 UObject* rtp_; 00060 }; 00061 00062 static 00063 std::string 00064 fusion_id() 00065 { 00066 return libport::format("Fusion_%s_%s", getFilteredHostname(), 00067 // Under uclibc, each thread has a different pid. 00068 #ifdef __UCLIBC__ 00069 "default" 00070 #else 00071 getpid() 00072 #endif 00073 ); 00074 } 00075 00076 ::urbi::URBIStarter<Fusion> 00077 starter_Fusion(urbi::isPluginMode() ? "Fusion" : fusion_id()); 00078 00079 Fusion::Fusion(const std::string& s) 00080 : UObject(s) 00081 , triggerMet(false) 00082 , nRequire(0) 00083 , nRequireMet(0) 00084 , rtp_(0) 00085 { 00086 UBindFunctions(Fusion, init, addSource, require, trigger, interpolate); 00087 UBindVars(Fusion, rtpBackend); 00088 UNotifyChange(rtpBackend, &Fusion::onBackendChange); 00089 static bool first = true; 00090 if (first) 00091 { 00092 first = false; 00093 UObject::send("var fusion = " + __name + "|"); 00094 } 00095 } 00096 00097 Fusion::VarData::VarData() 00098 : trigger(false) 00099 , require(false) 00100 , interpolate(false) 00101 , updated(false) 00102 { 00103 } 00104 00105 Fusion::~Fusion() 00106 { 00107 } 00108 00109 void Fusion::init() 00110 { 00111 } 00112 00113 void Fusion::onBackendChange(std::string v) 00114 { 00115 rtp_ = getUObject(v); 00116 if (rtp_ && !vars.empty()) 00117 UVar(*rtp_, "commitTriggerVarName") = vars.back()->data().dst; 00118 } 00119 00120 unsigned int Fusion::addSource(UVar& src, const std::string& dst) 00121 { 00122 FusionVar* fv = new FusionVar(src.get_name()); 00123 fv->data().dst = dst; 00124 vars.push_back(fv); 00125 if (rtp_) 00126 UVar(*rtp_, "commitTriggerVarName") = dst; 00127 return vars.size()-1; 00128 } 00129 00130 #define SETTER(Name, ...) \ 00131 void Fusion::Name(unsigned int uid, bool enable) \ 00132 { \ 00133 if (uid >= vars.size()) \ 00134 throw std::runtime_error("uid out of range"); \ 00135 if (vars[uid]->data().Name == enable) \ 00136 return; \ 00137 vars[uid]->data().Name = enable; \ 00138 __VA_ARGS__; \ 00139 } 00140 SETTER(trigger, 00141 if (enable) 00142 UNotifyChange(*vars[uid], &Fusion::onChange); 00143 else 00144 vars[uid]->unnotify()) 00145 SETTER(require, nRequire+=enable?1:-1) 00146 SETTER(interpolate, require(uid, enable); 00147 throw std::runtime_error("Not implemented");) 00148 #undef SETTER 00149 00150 void Fusion::onChange(UVar& v) 00151 { 00152 FusionVar& fv = reinterpret_cast<FusionVar&>(v); 00153 VarData& d = fv.data(); 00154 if (d.trigger) 00155 triggerMet = true; 00156 if (d.require && !d.updated) 00157 nRequireMet++; 00158 d.updated = true; 00159 assert(nRequireMet <= nRequire); 00160 if (triggerMet && nRequireMet == nRequire) 00161 commit(); 00162 } 00163 00164 void Fusion::commit() 00165 { 00166 if (rtp_) 00167 { 00168 foreach(FusionVar* fv, vars) 00169 { 00170 ctx_->rtpSendGrouped(rtp_, fv->data().dst, fv->val(), fv->timestamp()); 00171 } 00172 } 00173 else 00174 { 00175 foreach(FusionVar* fv, vars) 00176 { 00177 UVar tmp(fv->data().dst); 00178 tmp = fv->val(); // FIXME: preserve timestamp 00179 } 00180 } 00181 foreach(FusionVar* fv, vars) 00182 { 00183 VarData& d = fv->data(); 00184 d.updated = false; 00185 } 00186 triggerMet = false; 00187 nRequireMet = 0; 00188 }