iCub-main
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010 RobotCub Consortium, European Commission FP6 Project IST-004370
3 * Author: Ugo Pattacini
4 * email: ugo.pattacini@iit.it
5 * website: www.robotcub.org
6 * Permission is granted to copy, distribute, and/or modify this program
7 * under the terms of the GNU General Public License, version 2 or any
8 * later version published by the Free Software Foundation.
9 *
10 * A copy of the license can be found at
11 * http://www.robotcub.org/icub/license/gpl.txt
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16 * Public License for more details
17*/
18
257
258#include <cstdio>
259#include <cstdarg>
260#include <mutex>
261#include <sstream>
262#include <string>
263#include <map>
264#include <deque>
265
266#include <yarp/os/all.h>
267
268using namespace std;
269using namespace yarp::os;
270
271#define CMD_ADD createVocab32('a','d','d')
272#define CMD_DEL createVocab32('d','e','l')
273#define CMD_GET createVocab32('g','e','t')
274#define CMD_SET createVocab32('s','e','t')
275#define CMD_LOCK createVocab32('l','o','c','k')
276#define CMD_UNLOCK createVocab32('u','n','l','o')
277#define CMD_OWNER createVocab32('o','w','n','e')
278#define CMD_TIME createVocab32('t','i','m','e')
279#define CMD_DUMP createVocab32('d','u','m','p')
280#define CMD_ASK createVocab32('a','s','k')
281#define CMD_SYNC createVocab32('s','y','n','c')
282#define CMD_ASYNC createVocab32('a','s','y','n')
283#define CMD_QUIT createVocab32('q','u','i','t')
284#define CMD_BYE createVocab32('b','y','e')
285
286#define REP_ACK createVocab32('a','c','k')
287#define REP_NACK createVocab32('n','a','c','k')
288#define REP_UNKNOWN createVocab32('u','n','k','n')
289
290#define OPT_ALL createVocab32('a','l','l')
291#define OPT_DISABLED (-1.0)
292#define OPT_OWNERSHIP_ALL ("all")
293
294#define PROP_ID ("id")
295#define PROP_LIFETIMER ("lifeTimer")
296#define PROP_SET ("propSet")
297#define BCTAG_EMPTY ("empty")
298#define BCTAG_SYNC ("sync")
299#define BCTAG_ASYNC ("async")
300
301
303{
304
305/************************************************************************/
306bool alwaysTrue(Value &a, Value &b)
307{
308 return true;
309}
310
311
312/************************************************************************/
313bool greater(Value &a, Value &b)
314{
315 if (a.isFloat64() && b.isFloat64())
316 return (a.asFloat64()>b.asFloat64());
317 else if (a.isInt32() && b.isInt32())
318 return (a.asInt32()>b.asInt32());
319 else
320 return false;
321}
322
323
324/************************************************************************/
325bool greaterEqual(Value &a, Value &b)
326{
327 if (a.isFloat64() && b.isFloat64())
328 return (a.asFloat64()>=b.asFloat64());
329 else if (a.isInt32() && b.isInt32())
330 return (a.asInt32()>=b.asInt32());
331 else
332 return false;
333}
334
335
336/************************************************************************/
337bool lower(Value &a, Value &b)
338{
339 if (a.isFloat64() && b.isFloat64())
340 return (a.asFloat64()<b.asFloat64());
341 else if (a.isInt32() && b.isInt32())
342 return (a.asInt32()<b.asInt32());
343 else
344 return false;
345}
346
347
348/************************************************************************/
349bool lowerEqual(Value &a, Value &b)
350{
351 if (a.isFloat64() && b.isFloat64())
352 return (a.asFloat64()<=b.asFloat64());
353 else if (a.isInt32() && b.isInt32())
354 return (a.asInt32()<=b.asInt32());
355 else
356 return false;
357}
358
359
360/************************************************************************/
361bool equal(Value &a, Value &b)
362{
363 if (a.isFloat64() && b.isFloat64())
364 return (a.asFloat64()==b.asFloat64());
365 else if (a.isInt32() && b.isInt32())
366 return (a.asInt32()==b.asInt32());
367 else if (a.isString() && b.isString())
368 {
369 string aStr=a.asString();
370 string bStr=b.asString();
371 return (aStr==bStr);
372 }
373 else
374 return false;
375}
376
377
378/************************************************************************/
379bool notEqual(Value &a, Value &b)
380{
381 if (a.isFloat64() && b.isFloat64())
382 return (a.asFloat64()!=b.asFloat64());
383 else if (a.isInt32() && b.isInt32())
384 return (a.asInt32()!=b.asInt32());
385 else if (a.isString() && b.isString())
386 {
387 string aStr=a.asString();
388 string bStr=b.asString();
389 return (aStr!=bStr);
390 }
391 else
392 return false;
393}
394
395}
396
397
398/************************************************************************/
399class DataBase : public PeriodicThread
400{
401protected:
402 /************************************************************************/
403 struct Item
404 {
405 Property *prop;
407 string owner;
408
412 };
413
414 /************************************************************************/
416 {
417 string prop;
418 bool (*compare)(Value&,Value&);
419 Value val;
420 };
421
422 ResourceFinder *rf;
423 map<int,Item> itemsMap;
424 mutex mtx;
425 int idCnt;
429
430 BufferedPort<Bottle> *pBroadcastPort;
432
433 /************************************************************************/
434 void clear()
435 {
436 for (map<int,Item>::iterator it=itemsMap.begin(); it!=itemsMap.end(); it++)
437 delete it->second.prop;
438
439 itemsMap.clear();
440 }
441
442 /************************************************************************/
443 void eraseItem(map<int,Item>::iterator &it)
444 {
445 delete it->second.prop;
446 itemsMap.erase(it);
447 }
448
449 /************************************************************************/
450 void write(FILE *stream)
451 {
452 int i=0;
453 for (map<int,Item>::iterator it=itemsMap.begin(); it!=itemsMap.end(); it++)
454 fprintf(stream,"item_%d (%s %d) (%s)\n",
455 i++,PROP_ID,it->first,it->second.prop->toString().c_str());
456 }
457
458 /************************************************************************/
459 bool recursiveCheck(Property *item, deque<Condition> &condList,
460 deque<string> &opList, const unsigned int i=0)
461 {
462 bool result;
463 if (item->check(condList[i].prop))
464 {
465 // take the current value of the item's property under test
466 Value &val=item->find(condList[i].prop);
467
468 // compute the condition over the current value
469 result=(*condList[i].compare)(val,condList[i].val);
470 }
471 else
472 result=false;
473
474 if ((i+1)>=condList.size())
475 return result;
476 else if (opList[i]=="||")
477 return (result||recursiveCheck(item,condList,opList,i+1));
478 else // at this point we know we deal with "&&" operations
479 {
480 unsigned int j;
481 for (j=i+1; j<condList.size(); j++)
482 {
483 if (result)
484 {
485 if (item->check(condList[j].prop))
486 {
487 Value &val=item->find(condList[j].prop);
488 result=result&&(*condList[j].compare)(val,condList[j].val);
489 }
490 else
491 result=false;
492 }
493
494 if (j<opList.size())
495 if (opList[j]=="||")
496 break;
497 }
498
499 if (j>=condList.size())
500 return result;
501 else
502 return (result||recursiveCheck(item,condList,opList,j+1));
503 }
504 }
505
506 /************************************************************************/
507 void run()
508 {
510 }
511
512public:
513 /************************************************************************/
514 DataBase() : PeriodicThread(1.0)
515 {
516 pBroadcastPort=NULL;
517 asyncBroadcast=false;
518 initialized=false;
519 nosavedb=false;
520 quitting=false;
521 idCnt=0;
522 }
523
524 /************************************************************************/
526 {
527 if (isRunning())
528 stop();
529
530 save();
531 clear();
532 }
533
534 /************************************************************************/
535 void configure(ResourceFinder &rf)
536 {
537 this->rf=&rf;
538 if (initialized)
539 {
540 yWarning("database already initialized ...");
541 return;
542 }
543
544 nosavedb=rf.check("no-save-db");
545 if (!rf.check("no-load-db"))
546 load();
547
548 dump();
549 initialized=true;
550 yInfo("database ready ...");
551
552 if (rf.check("sync-bc"))
553 {
554 setPeriod(rf.check("sync-bc",Value(1.0)).asFloat64());
555 start();
556 }
557
558 asyncBroadcast=rf.check("async-bc");
559 }
560
561 /************************************************************************/
562 void setBroadcastPort(BufferedPort<Bottle> &broadcastPort)
563 {
564 pBroadcastPort=&broadcastPort;
565 }
566
567 /************************************************************************/
568 void load()
569 {
570 string dbFileName=rf->findFile("db");
571 if (dbFileName.empty())
572 {
573 yWarning("requested database to be loaded not found!");
574 return;
575 }
576
577 yInfo("loading database from %s ...",dbFileName.c_str());
578
579 lock_guard<mutex> lck(mtx);
580 clear();
581 idCnt=0;
582
583 Property finProperty;
584 finProperty.fromConfigFile(dbFileName);
585
586 Bottle finBottle;
587 finBottle.fromString(finProperty.toString());
588 for (int i=0; i<finBottle.size(); i++)
589 {
590 ostringstream tag;
591 tag<<"item_"<<i;
592 Bottle &b1=finBottle.findGroup(tag.str());
593
594 if (b1.isNull())
595 continue;
596
597 if (b1.size()<3)
598 {
599 yWarning("error while loading %s!",tag.str().c_str());
600 continue;
601 }
602
603 Bottle *b2=b1.get(1).asList();
604 Bottle *b3=b1.get(2).asList();
605 if ((b2==NULL) || (b3==NULL))
606 {
607 yWarning("error while loading %s!",tag.str().c_str());
608 continue;
609 }
610
611 if (b2->size()<2)
612 {
613 yWarning("error while loading %s!",tag.str().c_str());
614 continue;
615 }
616
617 int id=b2->get(1).asInt32();
618 itemsMap[id].prop=new Property(b3->toString().c_str());
619
620 if (idCnt<=id)
621 idCnt=id+1;
622 }
623
624 yInfo("database loaded");
625 }
626
627 /************************************************************************/
628 void save()
629 {
630 if (nosavedb)
631 return;
632
633 lock_guard<mutex> lck(mtx);
634 string dbFileName=rf->getHomeContextPath();
635 dbFileName+="/";
636 dbFileName+=rf->find("db").asString();
637 yInfo("saving database in %s ...",dbFileName.c_str());
638
639 FILE *fout=fopen(dbFileName.c_str(),"w");
640 write(fout);
641 fclose(fout);
642
643 yInfo("database stored");
644 }
645
646 /************************************************************************/
647 void dump()
648 {
649 lock_guard<mutex> lck(mtx);
650 yInfo("dumping database content ...");
651
652 if (itemsMap.size()==0)
653 yInfo("empty");
654 else
655 write(stdout);
656 }
657
658 /************************************************************************/
659 void broadcast(const string &type)
660 {
661 if (pBroadcastPort!=NULL)
662 {
663 if (pBroadcastPort->getOutputCount()>0)
664 {
665 lock_guard<mutex> lck(mtx);
666 Bottle &bottle=pBroadcastPort->prepare();
667 bottle.clear();
668
669 bottle.addString(type);
670 if (itemsMap.empty())
671 bottle.addString(BCTAG_EMPTY);
672 else for (map<int,Item>::iterator it=itemsMap.begin(); it!=itemsMap.end(); it++)
673 {
674 Bottle &item=bottle.addList();
675 item.read(*it->second.prop);
676
677 Bottle &idList=item.addList();
678 idList.addString(PROP_ID);
679 idList.addInt32(it->first);
680 }
681
682 pBroadcastPort->writeStrict();
683 }
684 }
685 }
686
687 /************************************************************************/
688 bool add(Bottle *content)
689 {
690 if (content==NULL)
691 return false;
692
693 if (content->check(PROP_ID))
694 {
695 yWarning("%s field cannot be specified as a property!",PROP_ID);
696 return false;
697 }
698
699 lock_guard<mutex> lck(mtx);
700 itemsMap[idCnt].prop=new Property(content->toString().c_str());
701 itemsMap[idCnt].lastUpdate=Time::now();
702
703 return true;
704 }
705
706 /************************************************************************/
707 bool remove(Bottle *content)
708 {
709 if (content==NULL)
710 return false;
711
712 if (content->size()==1)
713 {
714 if (content->get(0).isVocab32() || content->get(0).isString())
715 {
716 if (content->get(0).asVocab32()==OPT_ALL)
717 {
718 lock_guard<mutex> lck(mtx);
719 clear();
720 yInfo("database cleared");
721 return true;
722 }
723 }
724 }
725
726 if (!content->check(PROP_ID))
727 {
728 yWarning("%s field not present within the request!",PROP_ID);
729 return false;
730 }
731
732 int id=content->find(PROP_ID).asInt32();
733
734 lock_guard<mutex> lck(mtx);
735 map<int,Item>::iterator it=itemsMap.find(id);
736 if (it!=itemsMap.end())
737 {
738 Bottle *propSet=content->find(PROP_SET).asList();
739 if (propSet!=NULL)
740 {
741 for (int i=0; i<propSet->size(); i++)
742 it->second.prop->unput(propSet->get(i).asString());
743
744 it->second.lastUpdate=Time::now();
745 }
746 else
747 eraseItem(it);
748
749 return true;
750 }
751
752 return false;
753 }
754
755 /************************************************************************/
756 bool get(Bottle *content, Bottle &response)
757 {
758 if (content==NULL)
759 return false;
760
761 if (!content->check(PROP_ID))
762 {
763 yWarning("%s field not present within the request!",PROP_ID);
764 return false;
765 }
766
767 int id=content->find(PROP_ID).asInt32();
768
769 lock_guard<mutex> lck(mtx);
770 map<int,Item>::iterator it=itemsMap.find(id);
771 if (it!=itemsMap.end())
772 {
773 Property *pProp=it->second.prop;
774 response.clear();
775
776 Bottle *propSet=content->find(PROP_SET).asList();
777 if (propSet!=NULL)
778 {
779 Property prop;
780 for (int i=0; i<propSet->size(); i++)
781 {
782 string propName=propSet->get(i).asString();
783 if (pProp->check(propName))
784 prop.put(propName,pProp->find(propName));
785 }
786
787 response.read(prop);
788 }
789 else
790 response.read(*pProp);
791
792 return true;
793 }
794
795 return false;
796 }
797
798 /************************************************************************/
799 bool set(Bottle *content, const string &agent)
800 {
801 if (content==NULL)
802 return false;
803
804 if (!content->check(PROP_ID))
805 {
806 yWarning("%s field not present within the request!",PROP_ID);
807 return false;
808 }
809
810 int id=content->find(PROP_ID).asInt32();
811
812 lock_guard<mutex> lck(mtx);
813 map<int,Item>::iterator it=itemsMap.find(id);
814 if (it!=itemsMap.end())
815 {
816 string owner=it->second.owner;
817 if ((owner==OPT_OWNERSHIP_ALL) || (owner==agent))
818 {
819 Property *pProp=it->second.prop;
820 for (int i=0; i<content->size(); i++)
821 {
822 if (Bottle *option=content->get(i).asList())
823 {
824 if (option->size()<2)
825 continue;
826
827 string prop=option->get(0).asString();
828 Value val=option->get(1);
829
830 if (prop==PROP_ID)
831 continue;
832
833 pProp->unput(prop);
834 pProp->put(prop,val);
835 }
836 else
837 continue;
838 }
839
840 it->second.lastUpdate=Time::now();
841 return true;
842 }
843 }
844
845 return false;
846 }
847
848 /************************************************************************/
849 bool lock(Bottle *content, const string &agent)
850 {
851 if (content==NULL)
852 return false;
853
854 if (!content->check(PROP_ID))
855 {
856 yWarning("%s field not present within the request!",PROP_ID);
857 return false;
858 }
859
860 int id=content->find(PROP_ID).asInt32();
861
862 lock_guard<mutex> lck(mtx);
863 map<int,Item>::iterator it=itemsMap.find(id);
864 if (it!=itemsMap.end())
865 {
866 string owner=it->second.owner;
867 if ((owner==OPT_OWNERSHIP_ALL) || (owner==agent))
868 {
869 it->second.owner=agent;
870 return true;
871 }
872 }
873
874 return false;
875 }
876
877 /************************************************************************/
878 bool unlock(Bottle *content, const string &agent)
879 {
880 if (content==NULL)
881 return false;
882
883 if (!content->check(PROP_ID))
884 {
885 yWarning("%s field not present within the request!",PROP_ID);
886 return false;
887 }
888
889 int id=content->find(PROP_ID).asInt32();
890
891 lock_guard<mutex> lck(mtx);
892 map<int,Item>::iterator it=itemsMap.find(id);
893 if (it!=itemsMap.end())
894 {
895 string owner=it->second.owner;
896 if ((owner==OPT_OWNERSHIP_ALL) || (owner==agent))
897 {
898 it->second.owner=OPT_OWNERSHIP_ALL;
899 return true;
900 }
901 }
902
903 return false;
904 }
905
906 /************************************************************************/
907 bool owner(Bottle *content, Bottle &response)
908 {
909 if (content==NULL)
910 return false;
911
912 if (!content->check(PROP_ID))
913 {
914 yWarning("%s field not present within the request!",PROP_ID);
915 return false;
916 }
917
918 int id=content->find(PROP_ID).asInt32();
919
920 lock_guard<mutex> lck(mtx);
921 map<int,Item>::iterator it=itemsMap.find(id);
922 if (it!=itemsMap.end())
923 {
924 response.clear();
925 string &owner=it->second.owner;
926 response.addString(owner);
927 return true;
928 }
929
930 return false;
931 }
932
933 /************************************************************************/
934 bool time(Bottle *content, Bottle &response)
935 {
936 if (content==NULL)
937 return false;
938
939 if (!content->check(PROP_ID))
940 {
941 yWarning("%s field not present within the request!",PROP_ID);
942 return false;
943 }
944
945 int id=content->find(PROP_ID).asInt32();
946
947 lock_guard<mutex> lck(mtx);
948 map<int,Item>::iterator it=itemsMap.find(id);
949 if (it!=itemsMap.end())
950 {
951 response.clear();
952 if (it->second.lastUpdate<0.0)
953 response.addFloat64(it->second.lastUpdate);
954 else
955 {
956 double dt=Time::now()-it->second.lastUpdate;
957 response.addFloat64(dt);
958 }
959 return true;
960 }
961
962 return false;
963 }
964
965 /************************************************************************/
966 bool ask(Bottle *content, Bottle &response)
967 {
968 if (content==NULL)
969 return false;
970
971 lock_guard<mutex> lck(mtx);
972 if (content->size()==1)
973 {
974 if (content->get(0).isVocab32() || content->get(0).isString())
975 {
976 if (content->get(0).asVocab32()==OPT_ALL)
977 {
978 response.clear();
979
980 for (map<int,Item>::iterator it=itemsMap.begin(); it!=itemsMap.end(); it++)
981 response.addInt32(it->first);
982
983 return true;
984 }
985 }
986 }
987
988 deque<Condition> condList;
989 deque<string> opList;
990
991 // we cannot accept a conditions string ending with
992 // a boolean operator
993 if (!(content->size()&0x01))
994 {
995 yWarning("uncorrect conditions received!");
996 return false;
997 }
998
999 // parse the received conditions and build the lists
1000 for (int i=0; i<content->size(); i+=2)
1001 {
1002 if (Bottle *b=content->get(i).asList())
1003 {
1004 Condition condition;
1005 string operation;
1006
1007 if (b->size()==1)
1008 {
1009 condition.prop=b->get(0).asString();
1011 }
1012 else if (b->size()>2)
1013 {
1014 condition.prop=b->get(0).asString();
1015 operation=b->get(1).asString();
1016 condition.val=b->get(2);
1017
1018 if (operation==">")
1020 else if (operation==">=")
1022 else if (operation=="<")
1024 else if (operation=="<=")
1026 else if (operation=="==")
1028 else if (operation=="!=")
1030 else
1031 {
1032 yWarning("unknown relational operator '%s'!",operation.c_str());
1033 return false;
1034 }
1035 }
1036 else
1037 {
1038 yWarning("wrong condition given!");
1039 return false;
1040 }
1041
1042 condList.push_back(condition);
1043
1044 if ((i+1)<content->size())
1045 {
1046 operation=content->get(i+1).asString();
1047 if ((operation!="||") && (operation!="&&"))
1048 {
1049 yWarning("unknown boolean operator '%s'!",operation.c_str());
1050 return false;
1051 }
1052 else
1053 opList.push_back(operation);
1054 }
1055 }
1056 else
1057 {
1058 yWarning("wrong condition given!");
1059 return false;
1060 }
1061 }
1062
1063 response.clear();
1064
1065 // apply the conditions to each item
1066 for (map<int,Item>::iterator it=itemsMap.begin(); it!=itemsMap.end(); it++)
1067 {
1068 // do recursion and keep only the item that
1069 // satisfies the whole list of conditions
1070 if (recursiveCheck(it->second.prop,condList,opList))
1071 response.addInt32(it->first);
1072 }
1073
1074 return true;
1075 }
1076
1077 /************************************************************************/
1078 void periodicHandler(const double dt) // manage the items life-timers
1079 {
1080 mtx.lock();
1081 bool erased=false;
1082 for (map<int,Item>::iterator it=itemsMap.begin(); it!=itemsMap.end(); it++)
1083 {
1084 Property *pProp=it->second.prop;
1085 if (pProp->check(PROP_LIFETIMER))
1086 {
1087 double lifeTimer=pProp->find(PROP_LIFETIMER).asFloat64()-dt;
1088 if (lifeTimer<=0.0)
1089 {
1090 eraseItem(it);
1091 erased=true;
1092 break;
1093 }
1094 else
1095 {
1096 pProp->unput(PROP_LIFETIMER);
1097 pProp->put(PROP_LIFETIMER,lifeTimer);
1098 }
1099 }
1100 }
1101 mtx.unlock();
1102
1103 if (asyncBroadcast && erased)
1105 }
1106
1107 /************************************************************************/
1108 bool isQuitting() const
1109 {
1110 return quitting;
1111 }
1112
1113 /************************************************************************/
1114 void respond(ConnectionReader &connection, const Bottle &command, Bottle &reply)
1115 {
1116 string agent=connection.getRemoteContact().getName();
1117 if (command.size()<1)
1118 {
1119 reply.addVocab32(REP_NACK);
1120 return;
1121 }
1122
1123 reply.clear();
1124 int cmd=command.get(0).asVocab32();
1125 switch(cmd)
1126 {
1127 //-----------------
1128 case CMD_ADD:
1129 {
1130 if (command.size()<2)
1131 {
1132 reply.addVocab32(REP_NACK);
1133 break;
1134 }
1135
1136 Bottle *content=command.get(1).asList();
1137 if (add(content))
1138 {
1139 reply.addVocab32(REP_ACK);
1140 Bottle &b=reply.addList();
1141 b.addString(PROP_ID);
1142 b.addInt32(idCnt);
1143 idCnt++;
1144
1145 if (asyncBroadcast)
1147 }
1148 else
1149 reply.addVocab32(REP_NACK);
1150
1151 break;
1152 }
1153
1154 //-----------------
1155 case CMD_DEL:
1156 {
1157 if (command.size()<2)
1158 {
1159 reply.addVocab32(REP_NACK);
1160 break;
1161 }
1162
1163 Bottle *content=command.get(1).asList();
1164 if (remove(content))
1165 {
1166 reply.addVocab32(REP_ACK);
1167 if (asyncBroadcast)
1169 }
1170 else
1171 reply.addVocab32(REP_NACK);
1172
1173 break;
1174 }
1175
1176 //-----------------
1177 case CMD_GET:
1178 {
1179 if (command.size()<2)
1180 {
1181 reply.addVocab32(REP_NACK);
1182 break;
1183 }
1184
1185 Bottle response;
1186 Bottle *content=command.get(1).asList();
1187 if (get(content,response))
1188 {
1189 reply.addVocab32(REP_ACK);
1190 reply.addList()=response;
1191 }
1192 else
1193 reply.addVocab32(REP_NACK);
1194
1195 break;
1196 }
1197
1198 //-----------------
1199 case CMD_SET:
1200 {
1201 if (command.size()<2)
1202 {
1203 reply.addVocab32(REP_NACK);
1204 break;
1205 }
1206
1207 Bottle *content=command.get(1).asList();
1208 if (set(content,agent))
1209 {
1210 reply.addVocab32(REP_ACK);
1211 if (asyncBroadcast)
1213 }
1214 else
1215 reply.addVocab32(REP_NACK);
1216
1217 break;
1218 }
1219
1220 //-----------------
1221 case CMD_LOCK:
1222 {
1223 if (command.size()<2)
1224 {
1225 reply.addVocab32(REP_NACK);
1226 break;
1227 }
1228
1229 Bottle *content=command.get(1).asList();
1230 if (lock(content,agent))
1231 reply.addVocab32(REP_ACK);
1232 else
1233 reply.addVocab32(REP_NACK);
1234
1235 break;
1236 }
1237
1238 //-----------------
1239 case CMD_UNLOCK:
1240 {
1241 if (command.size()<2)
1242 {
1243 reply.addVocab32(REP_NACK);
1244 break;
1245 }
1246
1247 Bottle *content=command.get(1).asList();
1248 if (unlock(content,agent))
1249 reply.addVocab32(REP_ACK);
1250 else
1251 reply.addVocab32(REP_NACK);
1252
1253 break;
1254 }
1255
1256 //-----------------
1257 case CMD_OWNER:
1258 {
1259 if (command.size()<2)
1260 {
1261 reply.addVocab32(REP_NACK);
1262 break;
1263 }
1264
1265 Bottle response;
1266 Bottle *content=command.get(1).asList();
1267 if (owner(content,response))
1268 {
1269 reply.addVocab32(REP_ACK);
1270 reply.addList()=response;
1271 }
1272 else
1273 reply.addVocab32(REP_NACK);
1274
1275 break;
1276 }
1277
1278 //-----------------
1279 case CMD_TIME:
1280 {
1281 if (command.size()<2)
1282 {
1283 reply.addVocab32(REP_NACK);
1284 break;
1285 }
1286
1287 Bottle response;
1288 Bottle *content=command.get(1).asList();
1289 if (time(content,response))
1290 {
1291 reply.addVocab32(REP_ACK);
1292 reply.addList()=response;
1293 }
1294 else
1295 reply.addVocab32(REP_NACK);
1296
1297 break;
1298 }
1299
1300 //-----------------
1301 case CMD_DUMP:
1302 {
1303 dump();
1304 reply.addVocab32(REP_ACK);
1305 break;
1306 }
1307
1308 //-----------------
1309 case CMD_SYNC:
1310 {
1311 if (command.size()<2)
1312 {
1313 reply.addVocab32(REP_NACK);
1314 break;
1315 }
1316
1317 int opt=command.get(1).asVocab32();
1318 if (opt==Vocab32::encode("start"))
1319 {
1320 if (command.size()>=3)
1321 setPeriod(command.get(2).asFloat64());
1322
1323 if (!isRunning())
1324 start();
1325 else if (isSuspended())
1326 resume();
1327
1328 reply.addVocab32(REP_ACK);
1329 }
1330 else if (opt==Vocab32::encode("stop"))
1331 {
1332 if (isRunning() && !isSuspended())
1333 suspend();
1334
1335 reply.addVocab32(REP_ACK);
1336 }
1337 else
1338 reply.addVocab32(REP_NACK);
1339
1340 break;
1341 }
1342
1343 //-----------------
1344 case CMD_ASYNC:
1345 {
1346 if (command.size()<2)
1347 {
1348 reply.addVocab32(REP_NACK);
1349 break;
1350 }
1351
1352 int opt=command.get(1).asVocab32();
1353 if (opt==Vocab32::encode("on"))
1354 {
1355 asyncBroadcast=true;
1356 reply.addVocab32(REP_ACK);
1357 }
1358 else if (opt==Vocab32::encode("off"))
1359 {
1360 asyncBroadcast=false;
1361 reply.addVocab32(REP_ACK);
1362 }
1363 else
1364 reply.addVocab32(REP_NACK);
1365
1366 break;
1367 }
1368
1369 //-----------------
1370 case CMD_ASK:
1371 {
1372 if (command.size()<2)
1373 {
1374 reply.addVocab32(REP_NACK);
1375 break;
1376 }
1377
1378 Bottle response;
1379 Bottle *content=command.get(1).asList();
1380 if (ask(content,response))
1381 {
1382 reply.addVocab32(REP_ACK);
1383 Bottle &b=reply.addList();
1384 b.addString(PROP_ID);
1385 b.addList()=response;
1386 }
1387 else
1388 reply.addVocab32(REP_NACK);
1389
1390 break;
1391 }
1392
1393 //-----------------
1394 case CMD_QUIT:
1395 case CMD_BYE:
1396 {
1397 quitting=true;
1398 reply.addVocab32(REP_ACK);
1399 break;
1400 }
1401
1402 //-----------------
1403 default:
1404 {
1405 yWarning("received unknown command!");
1406 reply.addVocab32(REP_UNKNOWN);
1407 }
1408 }
1409 }
1410
1411 /************************************************************************/
1412 bool modify(const Bottle &content)
1413 {
1414 if (content.size()==0)
1415 return false;
1416
1417 string type=content.get(0).asString();
1418 if ((type!=BCTAG_EMPTY) && (type!=BCTAG_SYNC) && (type!=BCTAG_ASYNC))
1419 return false;
1420
1421 mtx.lock();
1422 clear();
1423
1424 if (type!=BCTAG_EMPTY)
1425 {
1426 idCnt=0;
1427 for (int i=1; i<content.size(); i++)
1428 {
1429 if (Bottle *item=content.get(i).asList())
1430 {
1431 if (Bottle *idList=item->get(0).asList())
1432 {
1433 if (idList->size()==2)
1434 {
1435 if (idList->get(0).asString()==PROP_ID)
1436 {
1437 int id=idList->get(1).asInt32();
1438 itemsMap[id].prop=new Property(item->tail().toString().c_str());
1439
1440 if (idCnt<=id)
1441 idCnt=id+1;
1442 }
1443 }
1444 }
1445 }
1446 }
1447 }
1448
1449 mtx.unlock();
1450
1451 if (asyncBroadcast)
1453
1454 return true;
1455 }
1456};
1457
1458
1459/************************************************************************/
1460class RpcProcessor : public PortReader
1461{
1462protected:
1464 unsigned int nCalls;
1465 double cumTime;
1466
1467 /************************************************************************/
1468 bool read(ConnectionReader &connection)
1469 {
1470 Bottle command;
1471 if (!command.read(connection) || (pDataBase==NULL))
1472 return false;
1473
1474 Bottle reply;
1475 double t0=Time::now();
1476 pDataBase->respond(connection,command,reply);
1477 cumTime+=Time::now()-t0;
1478 nCalls++;
1479
1480 if (ConnectionWriter *writer=connection.getWriter())
1481 reply.write(*writer);
1482
1483 return true;
1484 }
1485
1486public:
1487 /************************************************************************/
1489 {
1490 pDataBase=NULL;
1491 nCalls=0;
1492 cumTime=0.0;
1493 }
1494
1495 /************************************************************************/
1496 void setDataBase(DataBase &dataBase)
1497 {
1498 pDataBase=&dataBase;
1499 }
1500
1501 /************************************************************************/
1502 void getStats(unsigned int &nCalls, double &cumTime) const
1503 {
1504 nCalls=this->nCalls;
1505 cumTime=this->cumTime;
1506 }
1507};
1508
1509
1510/************************************************************************/
1511class DataBaseModifyPort : public BufferedPort<Bottle>
1512{
1513protected:
1515
1516 /************************************************************************/
1517 void onRead(Bottle &content)
1518 {
1519 if (pDataBase!=NULL)
1520 pDataBase->modify(content);
1521 }
1522
1523public:
1524 /************************************************************************/
1526
1527 /************************************************************************/
1528 void setDataBase(DataBase &dataBase)
1529 {
1530 pDataBase=&dataBase;
1531 }
1532};
1533
1534
1535/************************************************************************/
1537{
1538private:
1539 DataBase dataBase;
1540 RpcProcessor rpcProcessor;
1541 DataBaseModifyPort modifyPort;
1542 RpcServer rpcPort;
1543 BufferedPort<Bottle> bcPort;
1544
1545 int cnt;
1546 bool stats;
1547 unsigned int nCallsOld;
1548 double cumTimeOld;
1549
1550public:
1551 /************************************************************************/
1552 bool configure(ResourceFinder &rf)
1553 {
1554 dataBase.configure(rf);
1555 stats=rf.check("stats");
1556
1557 string name=rf.check("name",Value("objectsPropertiesCollector")).asString();
1558 dataBase.setBroadcastPort(bcPort);
1559 rpcProcessor.setDataBase(dataBase);
1560 rpcPort.setReader(rpcProcessor);
1561 modifyPort.setDataBase(dataBase);
1562 modifyPort.useCallback();
1563 rpcPort.open("/"+name+"/rpc");
1564 bcPort.open("/"+name+"/broadcast:o");
1565 modifyPort.open("/"+name+"/modify:i");
1566
1567 cnt=0;
1568 nCallsOld=0;
1569 cumTimeOld=0.0;
1570
1571 return true;
1572 }
1573
1574 /************************************************************************/
1575 bool close()
1576 {
1577 modifyPort.disableCallback();
1578 dataBase.stop();
1579
1580 rpcPort.interrupt();
1581 bcPort.interrupt();
1582 modifyPort.interrupt();
1583
1584 rpcPort.close();
1585 bcPort.close();
1586 modifyPort.close();
1587
1588 return true;
1589 }
1590
1591 /************************************************************************/
1593 {
1594 dataBase.periodicHandler(getPeriod());
1595
1596 // back-up straightaway the database each 15 minutes
1597 if ((++cnt)*getPeriod()>(15.0*60.0))
1598 {
1599 dataBase.save();
1600 cnt=0;
1601 }
1602
1603 if (stats)
1604 {
1605 unsigned int nCalls; double cumTime;
1606 rpcProcessor.getStats(nCalls,cumTime);
1607
1608 unsigned int calls=nCalls-nCallsOld;
1609 double timeSpent=cumTime-cumTimeOld;
1610 yInfo("*** Statistics: received %d/%g [requests/s]; %g [ms/request] spent on average",
1611 calls,getPeriod(),timeSpent==0.0?0.0:(1e3*timeSpent)/(double)calls);
1612
1613 nCallsOld=nCalls;
1614 cumTimeOld=cumTime;
1615 }
1616
1617 return !dataBase.isQuitting();
1618 }
1619
1620 /************************************************************************/
1621 double getPeriod()
1622 {
1623 return 1.0;
1624 }
1625};
1626
1627
1628/************************************************************************/
1629int main(int argc, char *argv[])
1630{
1631 Network yarp;
1632
1633 ResourceFinder rf;
1634 rf.setDefaultContext("objectsPropertiesCollector");
1635 rf.setDefault("db","dataBase.ini");
1636 rf.configure(argc,argv);
1637
1638 if (rf.check("help"))
1639 {
1640 printf("Options\n");
1641 printf("\t--name <name>: collector name (default: objectsPropertiesCollector)\n");
1642 printf("\t--db <fileName>: database file name to load at startup/save at shutdown (default: dataBase.ini)\n");
1643 printf("\t--context <context>: context to search for database file (default: objectsPropertiesCollector)\n");
1644 printf("\t--no-load-db : start an empty database\n");
1645 printf("\t--no-save-db : prevent from saving the content of database at shutdown\n");
1646 printf("\t--sync-bc <T>: broadcast the database content each T seconds\n");
1647 printf("\t--async-bc : broadcast the database content whenever a change occurs\n");
1648 printf("\t--stats : enable statistics printouts\n");
1649 printf("\n");
1650 return 0;
1651 }
1652
1653 if (!yarp.checkNetwork())
1654 {
1655 yError("YARP server not available!");
1656 return 1;
1657 }
1658
1660 return collector.runModule(rf);
1661}
1662
1663
void setDataBase(DataBase &dataBase)
Definition main.cpp:1528
void onRead(Bottle &content)
Definition main.cpp:1517
DataBase * pDataBase
Definition main.cpp:1514
BufferedPort< Bottle > * pBroadcastPort
Definition main.cpp:430
void run()
Definition main.cpp:507
map< int, Item > itemsMap
Definition main.cpp:423
bool owner(Bottle *content, Bottle &response)
Definition main.cpp:907
void broadcast(const string &type)
Definition main.cpp:659
bool add(Bottle *content)
Definition main.cpp:688
bool asyncBroadcast
Definition main.cpp:431
bool modify(const Bottle &content)
Definition main.cpp:1412
bool remove(Bottle *content)
Definition main.cpp:707
int idCnt
Definition main.cpp:425
void load()
Definition main.cpp:568
void respond(ConnectionReader &connection, const Bottle &command, Bottle &reply)
Definition main.cpp:1114
bool time(Bottle *content, Bottle &response)
Definition main.cpp:934
bool isQuitting() const
Definition main.cpp:1108
bool initialized
Definition main.cpp:426
bool get(Bottle *content, Bottle &response)
Definition main.cpp:756
bool recursiveCheck(Property *item, deque< Condition > &condList, deque< string > &opList, const unsigned int i=0)
Definition main.cpp:459
mutex mtx
Definition main.cpp:424
void write(FILE *stream)
Definition main.cpp:450
bool unlock(Bottle *content, const string &agent)
Definition main.cpp:878
void setBroadcastPort(BufferedPort< Bottle > &broadcastPort)
Definition main.cpp:562
void save()
Definition main.cpp:628
bool quitting
Definition main.cpp:428
bool set(Bottle *content, const string &agent)
Definition main.cpp:799
void periodicHandler(const double dt)
Definition main.cpp:1078
~DataBase()
Definition main.cpp:525
bool nosavedb
Definition main.cpp:427
DataBase()
Definition main.cpp:514
void dump()
Definition main.cpp:647
void configure(ResourceFinder &rf)
Definition main.cpp:535
void eraseItem(map< int, Item >::iterator &it)
Definition main.cpp:443
ResourceFinder * rf
Definition main.cpp:422
bool ask(Bottle *content, Bottle &response)
Definition main.cpp:966
void clear()
Definition main.cpp:434
bool lock(Bottle *content, const string &agent)
Definition main.cpp:849
DataBase * pDataBase
Definition main.cpp:1463
double cumTime
Definition main.cpp:1465
void getStats(unsigned int &nCalls, double &cumTime) const
Definition main.cpp:1502
bool read(ConnectionReader &connection)
Definition main.cpp:1468
unsigned int nCalls
Definition main.cpp:1464
void setDataBase(DataBase &dataBase)
Definition main.cpp:1496
bool configure(ResourceFinder &rf)
Definition main.cpp:1552
cmd
Definition dataTypes.h:30
#define CMD_QUIT
Definition main.cpp:283
#define BCTAG_SYNC
Definition main.cpp:298
#define CMD_SYNC
Definition main.cpp:281
#define BCTAG_EMPTY
Definition main.cpp:297
#define REP_UNKNOWN
Definition main.cpp:288
#define CMD_DEL
Definition main.cpp:272
#define OPT_ALL
Definition main.cpp:290
#define CMD_GET
Definition main.cpp:273
#define REP_ACK
Definition main.cpp:286
#define CMD_TIME
Definition main.cpp:278
#define PROP_SET
Definition main.cpp:296
#define OPT_DISABLED
Definition main.cpp:291
#define CMD_ADD
Definition main.cpp:271
#define CMD_OWNER
Definition main.cpp:277
#define BCTAG_ASYNC
Definition main.cpp:299
#define CMD_BYE
Definition main.cpp:284
#define PROP_ID
Definition main.cpp:294
#define CMD_DUMP
Definition main.cpp:279
#define CMD_UNLOCK
Definition main.cpp:276
#define CMD_LOCK
Definition main.cpp:275
#define CMD_ASK
Definition main.cpp:280
#define CMD_SET
Definition main.cpp:274
#define PROP_LIFETIMER
Definition main.cpp:295
#define CMD_ASYNC
Definition main.cpp:282
#define REP_NACK
Definition main.cpp:287
#define OPT_OWNERSHIP_ALL
Definition main.cpp:292
int main()
Definition main.cpp:67
bool equal(Value &a, Value &b)
Definition main.cpp:361
bool lower(Value &a, Value &b)
Definition main.cpp:337
bool greater(Value &a, Value &b)
Definition main.cpp:313
bool alwaysTrue(Value &a, Value &b)
Definition main.cpp:306
bool greaterEqual(Value &a, Value &b)
Definition main.cpp:325
bool notEqual(Value &a, Value &b)
Definition main.cpp:379
bool lowerEqual(Value &a, Value &b)
Definition main.cpp:349
Copyright (C) 2008 RobotCub Consortium.
fprintf(fid,'\n')
axis equal
fclose(fileID)
degrees time
Definition sine.m:5
bool(* compare)(Value &, Value &)
Definition main.cpp:418
double lastUpdate
Definition main.cpp:406
Property * prop
Definition main.cpp:405
string owner
Definition main.cpp:407