Urbi SDK Remote for C++  2.7.5
fusion.cc
Go to the documentation of this file.
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 }