00001 #include <canopen_master/objdict.h>
00002 #include <socketcan_interface/string.h>
00003 #include <boost/property_tree/ptree.hpp>
00004 #include <boost/property_tree/ini_parser.hpp>
00005 #include <boost/foreach.hpp>
00006 #include <boost/lexical_cast.hpp>
00007 #include <boost/algorithm/string.hpp>
00008
00009 namespace canopen{
00010 size_t hash_value(ObjectDict::Key const& k) { return k.hash; }
00011 std::ostream& operator<<(std::ostream& stream, const ObjectDict::Key &k) { return stream << std::string(k); }
00012 }
00013
00014 using namespace canopen;
00015
00016 template<> const String & HoldAny::get() const{
00017 return buffer;
00018 }
00019
00020 template<> String & ObjectStorage::Data::access(){
00021 if(!valid){
00022 THROW_WITH_KEY(std::length_error("buffer not valid") , key);
00023 }
00024 return buffer;
00025 }
00026 template<> String & ObjectStorage::Data::allocate(){
00027 buffer.resize(0);
00028 valid = true;
00029 return buffer;
00030 }
00031
00032 size_t ObjectDict::Key::fromString(const std::string &str){
00033 uint16_t index = 0;
00034 uint8_t sub_index = 0;
00035 int num = sscanf(str.c_str(),"%hxsub%hhx", &index, &sub_index);
00036 return (index << 16) | (num==2?sub_index:0xFFFF);
00037 }
00038 ObjectDict::Key::operator std::string() const{
00039 std::stringstream sstr;
00040 sstr << std::hex << index();
00041 if(hasSub()) sstr << "sub" << (int) sub_index();
00042 return sstr.str();
00043 }
00044 void ObjectStorage::Data::init(){
00045 boost::mutex::scoped_lock lock(mutex);
00046
00047 if(entry->init_val.is_empty()) return;
00048
00049 if(valid && !entry->def_val.is_empty() && buffer != entry->def_val.data()) return;
00050
00051 if(!valid || buffer != entry->init_val.data()){
00052 buffer = entry->init_val.data();
00053 valid = true;
00054 if(entry->writable && (entry->def_val.is_empty() || entry->init_val.data() != entry->def_val.data()))
00055 write_delegate(*entry, buffer);
00056 }
00057 }
00058 void ObjectStorage::Data::force_write(){
00059 boost::mutex::scoped_lock lock(mutex);
00060
00061 if(!valid && entry->readable){
00062 read_delegate(*entry, buffer);
00063 valid = true;
00064 }
00065 if(valid) write_delegate(*entry, buffer);
00066 }
00067
00068 void ObjectStorage::Data::reset(){
00069 boost::mutex::scoped_lock lock(mutex);
00070 if(!entry->def_val.is_empty() && entry->def_val.type() == type_guard){
00071 buffer = entry->def_val.data();
00072 valid = true;
00073 }else{
00074 valid = false;
00075 }
00076 }
00077
00078 bool ObjectDict::iterate(boost::unordered_map<Key, boost::shared_ptr<const Entry> >::const_iterator &it) const{
00079 if(it != boost::unordered_map<Key, boost::shared_ptr<const Entry> >::const_iterator()){
00080 ++it;
00081 }else it = dict_.begin();
00082 return it != dict_.end();
00083 }
00084 void set_access( ObjectDict::Entry &entry, std::string access){
00085 boost::algorithm::to_lower(access);
00086 entry.constant = false;
00087 if(access == "ro"){
00088 entry.readable = true;
00089 entry.writable = false;
00090 }else if (access == "wo"){
00091 entry.readable = false;
00092 entry.writable = true;
00093 }else if (access == "rw"){
00094 entry.readable = true;
00095 entry.writable = true;
00096 }else if (access == "rwr"){
00097 entry.readable = true;
00098 entry.writable = true;
00099 }else if (access == "rww"){
00100 entry.readable = true;
00101 entry.writable = true;
00102 }else if (access == "const"){
00103 entry.readable = true;
00104 entry.writable = false;
00105 entry.constant = true;
00106 }else{
00107 THROW_WITH_KEY(ParseException("Cannot determine access"), ObjectDict::Key(entry));
00108 }
00109 }
00110
00111 template<typename T> T int_from_string(const std::string &s);
00112
00113 template<> int8_t int_from_string(const std::string &s){
00114 return strtol(s.c_str(), 0, 0);
00115 }
00116 template<> uint8_t int_from_string(const std::string &s){
00117 return strtoul(s.c_str(), 0, 0);
00118 }
00119 template<> int16_t int_from_string(const std::string &s){
00120 return strtol(s.c_str(), 0, 0);
00121 }
00122 template<> uint16_t int_from_string(const std::string &s){
00123 return strtoul(s.c_str(), 0, 0);
00124 }
00125 template<> int32_t int_from_string(const std::string &s){
00126 return strtol(s.c_str(), 0, 0);
00127 }
00128 template<> uint32_t int_from_string(const std::string &s){
00129 return strtoul(s.c_str(), 0, 0);
00130 }
00131
00132 template<> int64_t int_from_string(const std::string &s){
00133 return strtoll(s.c_str(), 0, 0);
00134 }
00135 template<> uint64_t int_from_string(const std::string &s){
00136 return strtoull(s.c_str(), 0, 0);
00137 }
00138
00139 template<typename T> HoldAny parse_int(boost::property_tree::iptree &pt, const std::string &key){
00140 if(pt.count(key) == 0) return HoldAny(TypeGuard::create<T>());
00141
00142 std::string str = boost::trim_copy(pt.get<std::string>(key));
00143 if(boost::istarts_with(str,"$NODEID")){
00144 return HoldAny(NodeIdOffset<T>(int_from_string<T>(boost::trim_copy(str.substr(str.find("+",7)+1)))));
00145 }else return HoldAny(int_from_string<T>(str));
00146 }
00147
00148 template<typename T> HoldAny parse_octets(boost::property_tree::iptree &pt, const std::string &key){
00149 std::string out;
00150 if(pt.count(key) == 0 || can::hex2buffer(out,pt.get<std::string>(key), true)) return HoldAny(TypeGuard::create<T>());
00151 return HoldAny(T(out));
00152 }
00153
00154 template<typename T> HoldAny parse_typed_value(boost::property_tree::iptree &pt, const std::string &key){
00155 if(pt.count(key) == 0) return HoldAny(TypeGuard::create<T>());
00156 return HoldAny(pt.get<T>(key));
00157 }
00158 template<> HoldAny parse_typed_value<String>(boost::property_tree::iptree &pt, const std::string &key){
00159 if(pt.count(key) == 0) return HoldAny(TypeGuard::create<String>());
00160 return HoldAny(String(pt.get<std::string>(key)));
00161 }
00162
00163 struct ReadAnyValue{
00164 template<const ObjectDict::DataTypes dt> static HoldAny func(boost::property_tree::iptree &pt, const std::string &key);
00165 static HoldAny read_value(boost::property_tree::iptree &pt, uint16_t data_type, const std::string &key){
00166 return branch_type<ReadAnyValue, HoldAny (boost::property_tree::iptree &, const std::string &)>(data_type)(pt, key);
00167 }
00168 };
00169 template<> HoldAny ReadAnyValue::func<ObjectDict::DEFTYPE_INTEGER8>(boost::property_tree::iptree &pt, const std::string &key){ return parse_int<int8_t>(pt,key); }
00170 template<> HoldAny ReadAnyValue::func<ObjectDict::DEFTYPE_INTEGER16>(boost::property_tree::iptree &pt, const std::string &key){ return parse_int<int16_t>(pt,key); }
00171 template<> HoldAny ReadAnyValue::func<ObjectDict::DEFTYPE_INTEGER32>(boost::property_tree::iptree &pt, const std::string &key){ return parse_int<int32_t>(pt,key); }
00172 template<> HoldAny ReadAnyValue::func<ObjectDict::DEFTYPE_INTEGER64>(boost::property_tree::iptree &pt, const std::string &key){ return parse_int<int64_t>(pt,key); }
00173
00174 template<> HoldAny ReadAnyValue::func<ObjectDict::DEFTYPE_UNSIGNED8>(boost::property_tree::iptree &pt, const std::string &key){ return parse_int<uint8_t>(pt,key); }
00175 template<> HoldAny ReadAnyValue::func<ObjectDict::DEFTYPE_UNSIGNED16>(boost::property_tree::iptree &pt, const std::string &key){ return parse_int<uint16_t>(pt,key); }
00176 template<> HoldAny ReadAnyValue::func<ObjectDict::DEFTYPE_UNSIGNED32>(boost::property_tree::iptree &pt, const std::string &key){ return parse_int<uint32_t>(pt,key); }
00177 template<> HoldAny ReadAnyValue::func<ObjectDict::DEFTYPE_UNSIGNED64>(boost::property_tree::iptree &pt, const std::string &key){ return parse_int<uint64_t>(pt,key); }
00178
00179 template<> HoldAny ReadAnyValue::func<ObjectDict::DEFTYPE_DOMAIN>(boost::property_tree::iptree &pt, const std::string &key)
00180 { return parse_octets<ObjectStorage::DataType<ObjectDict::DEFTYPE_DOMAIN>::type>(pt,key); }
00181
00182 template<> HoldAny ReadAnyValue::func<ObjectDict::DEFTYPE_OCTET_STRING>(boost::property_tree::iptree &pt, const std::string &key)
00183 { return parse_octets<ObjectStorage::DataType<ObjectDict::DEFTYPE_OCTET_STRING>::type>(pt,key); }
00184
00185 template<const ObjectDict::DataTypes dt> HoldAny ReadAnyValue::func(boost::property_tree::iptree &pt, const std::string &key){
00186 return parse_typed_value<typename ObjectStorage::DataType<dt>::type>(pt, key);
00187 }
00188
00189 template<typename T> void read_optional(T& var, boost::property_tree::iptree &pt, const std::string &key){
00190 var = pt.get(key, T());
00191 }
00192
00193 template<typename T> void read_integer(T& var, boost::property_tree::iptree &pt, const std::string &key){
00194 var = int_from_string<T>(pt.get<std::string>(key));
00195 }
00196
00197 template<typename T> T read_integer(boost::property_tree::iptree &pt, const std::string &key){
00198 return int_from_string<T>(pt.get<std::string>(key, std::string()));
00199 }
00200
00201
00202 void read_var(ObjectDict::Entry &entry, boost::property_tree::iptree &object){
00203 read_integer<uint16_t>(entry.data_type, object, "DataType");
00204 entry.mappable = object.get<bool>("PDOMapping", false);
00205 try{
00206 set_access(entry, object.get<std::string>("AccessType"));
00207 }
00208 catch(...){
00209 THROW_WITH_KEY(ParseException("No AccessType") , ObjectDict::Key(entry));
00210
00211 }
00212 entry.def_val = ReadAnyValue::read_value(object, entry.data_type, "DefaultValue");
00213 entry.init_val = ReadAnyValue::read_value(object, entry.data_type, "ParameterValue");
00214 }
00215
00216 void parse_object(boost::shared_ptr<ObjectDict> dict, boost::property_tree::iptree &pt, const std::string &name, const uint8_t* sub_index = 0){
00217 boost::optional<boost::property_tree::iptree&> object = pt.get_child_optional(name.substr(2));
00218 if(!object) return;
00219
00220 boost::shared_ptr<ObjectDict::Entry> entry = boost::make_shared<ObjectDict::Entry>();
00221 entry->index = int_from_string<uint16_t>(name);
00222 entry->obj_code = ObjectDict::Code(int_from_string<uint16_t>(object->get<std::string>("ObjectType", boost::lexical_cast<std::string>((uint16_t)ObjectDict::VAR))));
00223 entry->desc = object->get<std::string>("Denotation",object->get<std::string>("ParameterName"));
00224
00225
00226 if(entry->obj_code == ObjectDict::VAR || entry->obj_code == ObjectDict::DOMAIN_DATA || sub_index){
00227 entry->sub_index = sub_index? *sub_index: 0;
00228 read_var(*entry, *object);
00229 dict->insert(sub_index != 0, entry);
00230 }else if(entry->obj_code == ObjectDict::ARRAY || entry->obj_code == ObjectDict::RECORD){
00231 uint8_t subs = read_integer<uint8_t>(*object, "CompactSubObj");
00232 if(subs){
00233 dict->insert(true, boost::make_shared<const canopen::ObjectDict::Entry>(entry->index, 0, ObjectDict::DEFTYPE_UNSIGNED8, "NrOfObjects", true, false, false, HoldAny(subs)));
00234
00235 read_var(*entry, *object);
00236
00237 for(uint8_t i=1; i< subs; ++i){
00238 std::string subname = pt.get<std::string>(name.substr(2)+"Name." + boost::lexical_cast<std::string>((int)i),entry->desc + boost::lexical_cast<std::string>((int)i));
00239 subname = pt.get<std::string>(name.substr(2)+"Denotation." + boost::lexical_cast<std::string>((int)i), subname);
00240
00241 dict->insert(true, boost::make_shared<const canopen::ObjectDict::Entry>(entry->index, i, entry->data_type, name, entry->readable, entry->writable, entry->mappable, entry->def_val,
00242 ReadAnyValue::read_value(pt, entry->data_type, name.substr(2)+"Value." + boost::lexical_cast<std::string>((int)i))));
00243 }
00244 }else{
00245 read_integer(subs, *object, "SubNumber");
00246 for(uint8_t i=0; i< subs; ++i){
00247 std::stringstream buf;
00248 buf << name << "sub" << std::hex << int(i);
00249
00250 parse_object(dict, pt, buf.str(), &i);
00251 }
00252 }
00253 }else{
00254 THROW_WITH_KEY(ParseException("Object type not supported") , ObjectDict::Key(*entry));
00255 }
00256 }
00257 void parse_objects(boost::shared_ptr<ObjectDict> dict, boost::property_tree::iptree &pt, const std::string &key){
00258 if(!pt.count(key)) return;
00259
00260 boost::property_tree::iptree objects = pt.get_child(key);
00261 uint16_t count = read_integer<uint16_t>(objects, "SupportedObjects");
00262 for(uint16_t i=0; i < count; ++i){
00263 std::string name = objects.get<std::string>(boost::lexical_cast<std::string>(i+1));
00264 parse_object(dict, pt, name);
00265 }
00266 }
00267 boost::shared_ptr<ObjectDict> ObjectDict::fromFile(const std::string &path, const ObjectDict::Overlay &overlay){
00268 DeviceInfo info;
00269 boost::property_tree::iptree pt;
00270 boost::shared_ptr<ObjectDict> dict;
00271
00272 boost::property_tree::read_ini(path, pt);
00273
00274 boost::property_tree::iptree di = pt.get_child("DeviceInfo");
00275
00276 read_optional(info.vendor_name, di, "VendorName");
00277 read_optional(info.vendor_number, di, "VendorNumber");
00278 read_optional(info.product_name, di, "ProductName");
00279 read_optional(info.product_number, di, "ProductNumber");
00280 read_optional(info.revision_number, di, "RevisionNumber");
00281 read_optional(info.order_code, di, "OrderCode");
00282 read_optional(info.simple_boot_up_master, di, "SimpleBootUpMaster");
00283 read_optional(info.simple_boot_up_slave, di, "SimpleBootUpSlave");
00284 read_optional(info.granularity, di, "Granularity");
00285 read_optional(info.dynamic_channels_supported, di, "DynamicChannelsSupported");
00286 read_optional(info.group_messaging, di, "GroupMessaging");
00287 read_optional(info.nr_of_rx_pdo, di, "NrOfRXPDO");
00288 read_optional(info.nr_of_tx_pdo, di, "NrOfTXPDO");
00289 read_optional(info.lss_supported, di, "LSS_Supported");
00290
00291 boost::unordered_set<uint32_t> baudrates;
00292 boost::unordered_set<uint16_t> dummy_usage;
00293
00294 BOOST_FOREACH(boost::property_tree::iptree::value_type &v, di){
00295 if(v.first.find("BaudRate_") == 0){
00296 uint16_t rate = int_from_string<uint16_t>(v.first.substr(9));
00297 if(v.second.get_value<bool>())
00298 info.baudrates.insert(rate * 1000);
00299 }
00300 }
00301
00302 if(pt.count("DummyUsage")){
00303 BOOST_FOREACH(boost::property_tree::iptree::value_type &v, pt.get_child("DummyUsage")){
00304 if(v.first.find("Dummy") == 0){
00305
00306 uint16_t dummy = int_from_string<uint16_t>("0x"+v.first.substr(5));
00307 if(v.second.get_value<bool>())
00308 info.dummy_usage.insert(dummy);
00309 }
00310 }
00311 }
00312
00313 dict = boost::make_shared<ObjectDict>(info);
00314
00315 for(Overlay::const_iterator it= overlay.begin(); it != overlay.end(); ++it){
00316 pt.get_child(it->first).put("ParameterValue", it->second);
00317 }
00318
00319 parse_objects(dict, pt, "MandatoryObjects");
00320 parse_objects(dict, pt, "OptionalObjects");
00321 parse_objects(dict, pt, "ManufacturerObjects");
00322
00323 return dict;
00324 }
00325
00326 size_t ObjectStorage::map(const boost::shared_ptr<const ObjectDict::Entry> &e, const ObjectDict::Key &key, const ReadDelegate & read_delegate, const WriteDelegate & write_delegate){
00327 boost::unordered_map<ObjectDict::Key, boost::shared_ptr<Data> >::iterator it = storage_.find(key);
00328
00329 if(it == storage_.end()){
00330
00331 boost::shared_ptr<Data> data;
00332
00333
00334 if(!e->def_val.type().valid()){
00335 THROW_WITH_KEY(std::bad_cast() , key);
00336 }
00337
00338 data = boost::make_shared<Data>(key, e,e->def_val.type(),read_delegate_, write_delegate_);
00339
00340 std::pair<boost::unordered_map<ObjectDict::Key, boost::shared_ptr<Data> >::iterator, bool> ok = storage_.insert(std::make_pair(key, data));
00341 it = ok.first;
00342 it->second->reset();
00343
00344 }
00345
00346 if(read_delegate && write_delegate){
00347 it->second->set_delegates(read_delegate_, write_delegate);
00348 it->second->force_write();
00349 it->second->set_delegates(read_delegate, write_delegate_);
00350 }else if(write_delegate) {
00351 it->second->set_delegates(read_delegate_, write_delegate);
00352 it->second->force_write();
00353 }else if(read_delegate){
00354 it->second->set_delegates(read_delegate, write_delegate_);
00355 }
00356 return it->second->size();
00357 }
00358
00359 size_t ObjectStorage::map(uint16_t index, uint8_t sub_index, const ReadDelegate & read_delegate, const WriteDelegate & write_delegate){
00360 boost::mutex::scoped_lock lock(mutex_);
00361
00362 try{
00363 ObjectDict::Key key(index,sub_index);
00364 const boost::shared_ptr<const ObjectDict::Entry> e = dict_->get(key);
00365 return map(e, key,read_delegate, write_delegate);
00366 }
00367 catch(std::out_of_range) {
00368 if(sub_index != 0) throw;
00369
00370 ObjectDict::Key key(index);
00371 const boost::shared_ptr<const ObjectDict::Entry> e = dict_->get(key);
00372 return map(e, key, read_delegate, write_delegate);
00373 }
00374 }
00375
00376 ObjectStorage::ObjectStorage(boost::shared_ptr<const ObjectDict> dict, uint8_t node_id, ReadDelegate read_delegate, WriteDelegate write_delegate)
00377 :read_delegate_(read_delegate), write_delegate_(write_delegate), dict_(dict), node_id_(node_id){
00378 assert(dict_);
00379 assert(!read_delegate_.empty());
00380 assert(!write_delegate_.empty());
00381 }
00382
00383 void ObjectStorage::init_nolock(const ObjectDict::Key &key, const boost::shared_ptr<const ObjectDict::Entry> &entry){
00384
00385 if(!entry->init_val.is_empty()){
00386 boost::unordered_map<ObjectDict::Key, boost::shared_ptr<Data> >::iterator it = storage_.find(key);
00387
00388 if(it == storage_.end()){
00389 boost::shared_ptr<Data> data = boost::make_shared<Data>(key,entry, entry->init_val.type(), read_delegate_, write_delegate_);
00390 std::pair<boost::unordered_map<ObjectDict::Key, boost::shared_ptr<Data> >::iterator, bool> ok = storage_.insert(std::make_pair(key, data));
00391 it = ok.first;
00392 if(!ok.second){
00393 THROW_WITH_KEY(std::bad_alloc() , key);
00394 }
00395 }
00396 it->second->init();
00397 }
00398 }
00399 void ObjectStorage::init(const ObjectDict::Key &key){
00400 boost::mutex::scoped_lock lock(mutex_);
00401 init_nolock(key, dict_->get(key));
00402 }
00403 void ObjectStorage::init_all(){
00404 boost::mutex::scoped_lock lock(mutex_);
00405
00406 boost::unordered_map<ObjectDict::Key, boost::shared_ptr<const ObjectDict::Entry> >::const_iterator entry_it;
00407 while(dict_->iterate(entry_it)){
00408 init_nolock(entry_it->first, entry_it->second);
00409 }
00410 }
00411
00412 void ObjectStorage::reset(){
00413 boost::mutex::scoped_lock lock(mutex_);
00414 for(boost::unordered_map<ObjectDict::Key, boost::shared_ptr<Data> >::iterator it = storage_.begin(); it != storage_.end(); ++it){
00415 it->second->reset();
00416 }
00417 }
00418
00419 template<const ObjectDict::DataTypes dt, typename T> std::string formatValue(const T &value){
00420 std::stringstream sstr;
00421 sstr << value;
00422 return sstr.str();
00423 }
00424 template<> std::string formatValue<ObjectDict::DEFTYPE_DOMAIN>(const std::string &value){
00425 return can::buffer2hex(value, false);
00426 }
00427 template<> std::string formatValue<ObjectDict::DEFTYPE_OCTET_STRING>(const std::string &value){
00428 return can::buffer2hex(value, false);
00429 }
00430
00431 struct PrintValue {
00432 template<const ObjectDict::DataTypes dt> static std::string func(ObjectStorage& storage, const ObjectDict::Key &key, bool cached){
00433 ObjectStorage::Entry<typename ObjectStorage::DataType<dt>::type> entry = storage.entry<typename ObjectStorage::DataType<dt>::type>(key);
00434 return formatValue<dt>(cached? entry.get_cached() : entry.get() );
00435 }
00436 static boost::function<std::string()> getReader(ObjectStorage& storage, const ObjectDict::Key &key, bool cached){
00437 ObjectDict::DataTypes data_type = (ObjectDict::DataTypes) storage.dict_->get(key)->data_type;
00438 return boost::bind(branch_type<PrintValue, std::string (ObjectStorage&, const ObjectDict::Key &, bool)>(data_type),boost::ref(storage), key, cached);
00439 }
00440 };
00441
00442 boost::function<std::string()> ObjectStorage::getStringReader(const ObjectDict::Key &key, bool cached){
00443 return PrintValue::getReader(*this, key, cached);
00444 }
00445
00446 struct WriteStringValue {
00447 typedef HoldAny (*reader_type)(boost::property_tree::iptree &, const std::string &);
00448 template<typename T> static void write(ObjectStorage::Entry<T> entry, bool cached, reader_type reader, const std::string &value){
00449 boost::property_tree::iptree pt;
00450 pt.put("value", value);
00451 HoldAny any = reader(pt, "value");
00452 if(cached){
00453 entry.set_cached(any.get<T>());
00454 } else {
00455 entry.set(any.get<T>());
00456 }
00457 }
00458 template<const ObjectDict::DataTypes dt> static boost::function<void (const std::string&)> func(ObjectStorage& storage, const ObjectDict::Key &key, bool cached){
00459 ObjectStorage::Entry<typename ObjectStorage::DataType<dt>::type> entry = storage.entry<typename ObjectStorage::DataType<dt>::type>(key);
00460 reader_type reader = branch_type<ReadAnyValue, HoldAny (boost::property_tree::iptree &, const std::string &)>(dt);
00461 return boost::bind(&WriteStringValue::write<typename ObjectStorage::DataType<dt>::type >, entry, cached, reader, _1);
00462 }
00463 static boost::function<void (const std::string&)> getWriter(ObjectStorage& storage, const ObjectDict::Key &key, bool cached){
00464 ObjectDict::DataTypes data_type = (ObjectDict::DataTypes) storage.dict_->get(key)->data_type;
00465 return branch_type<WriteStringValue, boost::function<void (const std::string&)> (ObjectStorage&, const ObjectDict::Key &, bool)>(data_type)(storage, key, cached);
00466 }
00467 };
00468
00469 boost::function<void (const std::string&)> ObjectStorage::getStringWriter(const ObjectDict::Key &key, bool cached){
00470 return WriteStringValue::getWriter(*this, key, cached);
00471 }