μHAL (v2.7.9)
Part of the IPbus software repository
NodeTreeBuilder.cpp
Go to the documentation of this file.
1 /*
2 ---------------------------------------------------------------------------
3 
4  This file is part of uHAL.
5 
6  uHAL is a hardware access library and programming framework
7  originally developed for upgrades of the Level-1 trigger of the CMS
8  experiment at CERN.
9 
10  uHAL is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  uHAL is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with uHAL. If not, see <http://www.gnu.org/licenses/>.
22 
23 
24  Andrew Rose, Imperial College, London
25  email: awr01 <AT> imperial.ac.uk
26 
27  Marc Magrans de Abril, CERN
28  email: marc.magrans.de.abril <AT> cern.ch
29 
30 ---------------------------------------------------------------------------
31 */
32 
33 #include "uhal/NodeTreeBuilder.hpp"
34 
35 
36 #include <boost/bind.hpp>
37 #include <boost/chrono/chrono_io.hpp>
38 #include <boost/chrono/system_clocks.hpp>
39 #include <boost/spirit/include/qi.hpp>
40 #include <boost/date_time/posix_time/posix_time.hpp>
41 #include <boost/algorithm/string/replace.hpp>
42 #include <boost/filesystem.hpp>
43 
46 #include "uhal/log/log.hpp"
47 #include "uhal/utilities/files.hpp"
48 #include "uhal/utilities/xml.hpp"
49 
50 
51 #if BOOST_VERSION >= 106000
52 // Resolve boost bind placeholders (_1, _2, ...) that moved within boost::laceholders namespace from v1.60
53 using boost::placeholders::_1;
54 using boost::placeholders::_2;
55 using boost::placeholders::_3;
56 #endif
57 
58 
59 namespace uhal
60 {
61 
62  const std::string NodeTreeBuilder::mIdAttribute = "id";
63  const std::string NodeTreeBuilder::mAddressAttribute = "address";
64  const std::string NodeTreeBuilder::mParametersAttribute = "parameters";
65  const std::string NodeTreeBuilder::mTagsAttribute = "tags";
66  const std::string NodeTreeBuilder::mDescriptionAttribute = "description";
67  const std::string NodeTreeBuilder::mPermissionsAttribute = "permission";
68  const std::string NodeTreeBuilder::mMaskAttribute = "mask";
69  const std::string NodeTreeBuilder::mModeAttribute = "mode";
70  const std::string NodeTreeBuilder::mSizeAttribute = "size";
71  const std::string NodeTreeBuilder::mClassAttribute = "class";
72  const std::string NodeTreeBuilder::mModuleAttribute = "module";
73  const std::string NodeTreeBuilder::mFirmwareInfo = "fwinfo";
74 
75 
77 
78 
80  {
81  //------------------------------------------------------------------------------------------------------------------------
82  Rule<Node*> lPlainNode;
83  lPlainNode.optional ( NodeTreeBuilder::mClassAttribute ) //.forbid ( NodeTreeBuilder::mClassAttribute ) //see https://svnweb.cern.ch/trac/cactus/ticket/452
86  .optional ( NodeTreeBuilder::mIdAttribute )
89  .optional ( NodeTreeBuilder::mFirmwareInfo )
95  //------------------------------------------------------------------------------------------------------------------------
96  Rule<Node*> lBitMask;
100  .optional ( NodeTreeBuilder::mAddressAttribute ) // .forbid ( NodeTreeBuilder::mAddressAttribute ) //see https://svnweb.cern.ch/trac/cactus/ticket/92
104  .optional ( NodeTreeBuilder::mFirmwareInfo )
106  .optional ( NodeTreeBuilder::mTagsAttribute )
108  //------------------------------------------------------------------------------------------------------------------------
109  Rule<Node*> lModule;
113  .optional ( NodeTreeBuilder::mClassAttribute ) //.forbid ( NodeTreeBuilder::mClassAttribute ) //see https://svnweb.cern.ch/trac/cactus/ticket/452
119  .optional ( NodeTreeBuilder::mFirmwareInfo )
120  .optional ( NodeTreeBuilder::mTagsAttribute )
122  //------------------------------------------------------------------------------------------------------------------------
123  mTopLevelNodeParser.addRule ( lPlainNode , boost::bind ( &NodeTreeBuilder::plainNodeCreator , this , false , _1 ) );
124  mTopLevelNodeParser.addRule ( lBitMask , boost::bind ( &NodeTreeBuilder::bitmaskNodeCreator , this , false , _1 ) );
125  mTopLevelNodeParser.addRule ( lModule , boost::bind ( &NodeTreeBuilder::moduleNodeCreator , this , false , _1 ) );
126  //------------------------------------------------------------------------------------------------------------------------
127  lPlainNode.require ( NodeTreeBuilder::mIdAttribute );
130  //------------------------------------------------------------------------------------------------------------------------
131  mNodeParser.addRule ( lPlainNode , boost::bind ( &NodeTreeBuilder::plainNodeCreator , this , true , _1 ) );
132  mNodeParser.addRule ( lBitMask , boost::bind ( &NodeTreeBuilder::bitmaskNodeCreator , this , true , _1 ) );
133  mNodeParser.addRule ( lModule , boost::bind ( &NodeTreeBuilder::moduleNodeCreator , this , true , _1 ) );
134  //------------------------------------------------------------------------------------------------------------------------
135  }
136 
137 
139  {
141  }
142 
143 
145  {
146  if ( ! mInstance )
147  {
148  mInstance.reset(new NodeTreeBuilder());
149  }
150 
151  return *mInstance;
152  }
153 
154 
155  Node* NodeTreeBuilder::getNodeTree ( const std::string& aFilenameExpr , const boost::filesystem::path& aPath )
156  {
157  std::vector< std::pair<std::string, std::string> > lAddressFiles;
158  uhal::utilities::ParseSemicolonDelimitedUriList ( aFilenameExpr , lAddressFiles );
159 
160  if ( lAddressFiles.size() != 1 )
161  {
162  exception::IncorrectAddressTableFileCount lExc;
163  log ( lExc , "Exactly one address table file must be specified. The expression " , Quote ( aFilenameExpr ) , " contains " , Integer ( lAddressFiles.size() ) , " valid file expressions." );
164  throw lExc;
165  }
166 
167  std::vector< const Node* > lNodes;
168  uhal::utilities::OpenFile ( lAddressFiles[0].first , lAddressFiles[0].second , aPath.parent_path() , boost::bind ( &NodeTreeBuilder::CallBack, boost::ref ( *this ) , _1 , _2 , _3 , boost::ref ( lNodes ) ) );
169 
170  if ( lNodes.size() != 1 )
171  {
172  exception::IncorrectAddressTableFileCount lExc;
173  log ( lExc , "Exactly one address table file must be specified. The expression " , Quote ( lAddressFiles[0].second ) , " refers to " , Integer ( lNodes.size() ) , " valid files." );
174  throw lExc;
175  }
176 
177  Node* lNode ( lNodes[0]->clone() );
178  return lNode;
179  }
180 
181 
183  {
184  for(boost::unordered_map<std::string, const Node*>::const_iterator it=mNodes.begin(); it != mNodes.end(); it++)
185  {
186  delete it->second;
187  }
188  mNodes.clear();
189  }
190 
191 
192  Node* NodeTreeBuilder::build(const pugi::xml_node& aNode, const boost::filesystem::path& aAddressFilePath)
193  {
194  mFileCallStack.push_back ( aAddressFilePath );
195  Node* lNode ( mTopLevelNodeParser ( aNode ) );
196  mFileCallStack.pop_back( );
197  calculateHierarchicalAddresses ( lNode , 0x00000000 );
198  checkForAddressCollisions ( lNode , aAddressFilePath ); // Needs further investigation - disabled for now as it causes exceptions with valid tables.
199 
200  return lNode;
201  }
202 
203 
204  void NodeTreeBuilder::CallBack ( const std::string& aProtocol , const boost::filesystem::path& aPath , std::vector<uint8_t>& aFile , std::vector< const Node* >& aNodes )
205  {
206  std::string lName ( aProtocol + ( aPath.string() ) );
207  boost::unordered_map< std::string , const Node* >::iterator lNodeIt = mNodes.find ( lName );
208 
209  if ( lNodeIt != mNodes.end() )
210  {
211  aNodes.push_back ( lNodeIt->second );
212  return;
213  }
214 
215  std::string lExtension ( aPath.extension().string().substr ( 0,4 ) );
216  boost::to_lower ( lExtension ); //just in case someone decides to use capitals in their file extensions.
217 
218  if ( lExtension == ".xml" )
219  {
220  log ( Info() , "Reading XML address file " , Quote( aPath.c_str() ) );
221  pugi::xml_document lXmlDocument;
222  pugi::xml_parse_result lLoadResult = lXmlDocument.load_buffer_inplace ( & ( aFile[0] ) , aFile.size() );
223 
224  if ( !lLoadResult )
225  {
226  uhal::utilities::PugiXMLParseResultPrettifier ( lLoadResult , aPath , aFile );
227  return;
228  }
229 
230  pugi::xml_node lXmlNode = lXmlDocument.child ( "node" );
231 
232  if ( !lXmlNode )
233  {
234  log ( Error() , "No XML node called ", Quote ( "node" ) , " in file " , aPath.c_str() );
235  return;
236  }
237 
238  Node* lNode ( build ( lXmlNode , aPath ) );
239  mNodes.insert ( std::make_pair ( lName , lNode ) );
240  aNodes.push_back ( lNode );
241  return;
242  }
243  else if ( lExtension == ".txt" )
244  {
245  log ( Info() , "TXT file" );
246  log ( Error() , "Parser problems mean that this method has been disabled." );
247  return;
248  }
249  else
250  {
251  log ( Error() , "Extension " , Quote ( lExtension ) , " not known." );
252  return;
253  }
254  }
255 
256 
257  Node* NodeTreeBuilder::plainNodeCreator ( const bool& aRequireId , const pugi::xml_node& aXmlNode )
258  {
259  Node* lNode ( new Node() );
260  setUid ( aRequireId , aXmlNode , lNode );
261  setAddr ( aXmlNode , lNode );
262  setPars ( aXmlNode , lNode );
263  setFirmwareInfo ( aXmlNode , lNode );
264  setClassName ( aXmlNode , lNode );
265  setTags ( aXmlNode , lNode );
266  setDescription ( aXmlNode , lNode );
267  setModule ( aXmlNode , lNode );
268  setPermissions ( aXmlNode , lNode );
269  //setMask( aXmlNode , lNode );
270  setModeAndSize ( aXmlNode , lNode );
271  addChildren ( aXmlNode , lNode );
272  log ( Debug() , lNode->mUid , " built by " , __PRETTY_FUNCTION__ );
273 
274  if ( lNode->mClassName.size() )
275  {
277  }
278  else
279  {
280  return lNode;
281  }
282  }
283 
284  Node* NodeTreeBuilder::moduleNodeCreator ( const bool& aRequireId , const pugi::xml_node& aXmlNode )
285  {
286  std::string lModule;
288  Node* lNode ( getNodeTree ( lModule , mFileCallStack.back( ) ) );
289  setUid ( aRequireId , aXmlNode , lNode );
290  setAddr ( aXmlNode , lNode );
291  setClassName ( aXmlNode , lNode );
292  setPars ( aXmlNode , lNode );
293  setFirmwareInfo ( aXmlNode , lNode );
294  setTags ( aXmlNode , lNode );
295  setDescription ( aXmlNode , lNode );
296  setModule ( aXmlNode , lNode );
297  //setPermissions( aXmlNode , lNode );
298  //setMask( aXmlNode , lNode );
299  //setModeAndSize( aXmlNode , lNode );
300  //addChildren( aXmlNode , lNode );
301  log ( Debug() , lNode->mUid , " built by " , __PRETTY_FUNCTION__ );
302 
303  if ( lNode->mClassName.size() )
304  {
306  }
307  else
308  {
309  return lNode;
310  }
311  }
312 
313 
314  Node* NodeTreeBuilder::bitmaskNodeCreator ( const bool& aRequireId , const pugi::xml_node& aXmlNode )
315  {
316  if ( aXmlNode.child ( "node" ) )
317  {
318  exception::MaskedNodeCannotHaveChild lExc;
319  log ( lExc , "Bit-masked nodes are not allowed to have child nodes" );
320  throw lExc;
321  }
322 
323  Node* lNode ( new Node() );
324  setUid ( aRequireId , aXmlNode , lNode );
325  setAddr ( aXmlNode , lNode ); //was commented out, see https://svnweb.cern.ch/trac/cactus/ticket/92
326  setClassName ( aXmlNode , lNode );
327  setPars ( aXmlNode , lNode );
328  setFirmwareInfo ( aXmlNode , lNode );
329  setTags ( aXmlNode , lNode );
330  setDescription ( aXmlNode , lNode );
331  setModule ( aXmlNode , lNode );
332  setPermissions ( aXmlNode , lNode );
333  setMask ( aXmlNode , lNode );
334  //setModeAndSize( aXmlNode , lNode );
335  //addChildren( aXmlNode , lNode );
336  log ( Debug() , lNode->mUid , " built by " , __PRETTY_FUNCTION__ );
337  return lNode;
338  }
339 
340 
341 
342 
343  void NodeTreeBuilder::setUid ( const bool& aRequireId , const pugi::xml_node& aXmlNode , Node* aNode )
344  {
345  const bool lHasId = uhal::utilities::GetXMLattribute<false> ( aXmlNode , NodeTreeBuilder::mIdAttribute , aNode->mUid );
346 
347  if ( aRequireId and ( not lHasId ) )
348  {
349  //error description is given in the function itself so no more elaboration required
350  throw exception::NodeMustHaveUID("'id' attribute is missing from address table node");
351  }
352 
353  if ( lHasId )
354  {
355  if ( aNode->mUid.empty() )
356  throw exception::NodeAttributeIncorrectValue("Invalid node ID specified (empty)");
357  else if ( aNode->mUid.find('.') != std::string::npos )
358  throw exception::NodeAttributeIncorrectValue("Invalid node ID '" + aNode->mUid + "' specified (contains dots)");
359  else if ( ( aNode->mUid.at(0) == ' ' ) or ( aNode->mUid.at(aNode->mUid.size()-1) == ' ' ) )
360  throw exception::NodeAttributeIncorrectValue("Invalid node ID '" + aNode->mUid + "' specified (contains spaces)");
361  }
362  }
363 
364  void NodeTreeBuilder::setAddr ( const pugi::xml_node& aXmlNode , Node* aNode )
365  {
366  //Address is an optional attribute for hierarchical addressing
367  uint32_t lAddr ( 0 );
369  aNode->mPartialAddr |= lAddr;
370  }
371 
372 
373  void NodeTreeBuilder::setClassName ( const pugi::xml_node& aXmlNode , Node* aNode )
374  {
375  //Address is an optional attribute for hierarchical addressing
376  std::string lClassStr;
378 
379  aNode->mClassName = lClassStr;
380  }
381 
382  void NodeTreeBuilder::setPars ( const pugi::xml_node& aXmlNode , Node* aNode )
383  {
384  std::string lParsStr;
385  //get attribute from xml file as string
387 
388  if ( lParsStr.size() )
389  {
390  //parse the string into a NodeTreeParameters object
391  std::string::const_iterator lBegin ( lParsStr.begin() );
392  std::string::const_iterator lEnd ( lParsStr.end() );
393  boost::unordered_map<std::string, std::string> lPars;
394  boost::spirit::qi::phrase_parse ( lBegin , lEnd , mNodeTreeParametersGrammar , boost::spirit::ascii::space , lPars );
395  // Update the parameters map
396  // Add to lPars those previously defined (module node)
397  lPars.insert ( aNode->mParameters.begin(), aNode->mParameters.end() );
398  // Swap the containers
399  aNode->mParameters.swap ( lPars );
400  }
401  }
402 
403  void NodeTreeBuilder::setTags ( const pugi::xml_node& aXmlNode , Node* aNode )
404  {
405  std::string lStr;
406  //Tags is an optional attribute to allow the user to add a description to a node
408 
409  if ( lStr.size() && aNode->mTags.size() )
410  {
411  aNode->mTags += "[";
412  aNode->mTags += lStr;
413  aNode->mTags += "]";
414  }
415  else if ( lStr.size() && !aNode->mTags.size() )
416  {
417  aNode->mTags = lStr;
418  }
419  }
420 
421 
422  void NodeTreeBuilder::setDescription ( const pugi::xml_node& aXmlNode , Node* aNode )
423  {
424  std::string lStr;
425  //Tags is an optional attribute to allow the user to add a description to a node
427 
428  if ( lStr.size() && aNode->mDescription.size() )
429  {
430  aNode->mDescription += "[";
431  aNode->mDescription += lStr;
432  aNode->mDescription += "]";
433  }
434  else if ( lStr.size() && !aNode->mDescription.size() )
435  {
436  aNode->mDescription = lStr;
437  }
438  }
439 
440  void NodeTreeBuilder::setModule ( const pugi::xml_node& aXmlNode , Node* aNode )
441  {
442  if ( mFileCallStack.size() )
443  {
444  aNode->mModule = mFileCallStack.back( ).string();
445  }
446  }
447 
448  void NodeTreeBuilder::setPermissions ( const pugi::xml_node& aXmlNode , Node* aNode )
449  {
450  //Permissions is an optional attribute for specifying read/write permissions
451  std::string lPermissionAttr;
452 
454  {
455  const defs::NodePermission* const lPermission = mPermissionsLut.find(lPermissionAttr.c_str());
456  if (lPermission == NULL)
457  {
458  throw exception::NodeAttributeIncorrectValue("Permission attribute for node with ID '" + aNode->mUid + "' has incorrect value '" + lPermissionAttr + "'");
459  }
460  else
461  aNode->mPermission = *lPermission;
462  }
463  }
464 
465 
466  void NodeTreeBuilder::setMask ( const pugi::xml_node& aXmlNode , Node* aNode )
467  {
468  //Tags is an optional attribute to allow the user to add a description to a node
470  }
471 
472 
473  void NodeTreeBuilder::setModeAndSize ( const pugi::xml_node& aXmlNode , Node* aNode )
474  {
475  //Mode is an optional attribute for specifying whether a block is incremental, non-incremental or a single register
476  std::string lModeAttr;
477 
479  {
480  const defs::BlockReadWriteMode* const lMode = mModeLut.find(lModeAttr.c_str());
481  if (lMode == NULL)
482  {
483  throw exception::NodeAttributeIncorrectValue("Mode attribute for node with ID '" + aNode->mUid + "' has incorrect value '" + lModeAttr + "'");
484  }
485  else
486  aNode->mMode = *lMode;
487 
488  if ( aNode->mMode == defs::INCREMENTAL )
489  {
490  //If a block is incremental it requires a size attribute
492  {
493  exception::IncrementalNodeRequiresSizeAttribute lExc;
494  log ( lExc , "Node " , Quote ( aNode->mUid ) , " has type " , Quote ( "INCREMENTAL" ) , ", which requires a " , Quote ( NodeTreeBuilder::mSizeAttribute ) , " attribute" );
495  throw lExc;
496  }
497  }
498  else if ( aNode->mMode == defs::NON_INCREMENTAL )
499  {
500  //If a block is non-incremental, then a size attribute is recommended
502  {
503  log ( Notice() , "Node " , Quote ( aNode->mUid ) , " has type " , Quote ( "NON_INCREMENTAL" ) , " but does not have a " , Quote ( NodeTreeBuilder::mSizeAttribute ) , " attribute. This is not necessarily a problem, but if there is a limit to the size of the read/write operation from this port, then please consider adding this attribute for the sake of safety." );
504  }
505  }
506  }
507  else if ( not aXmlNode.attribute ( NodeTreeBuilder::mSizeAttribute.c_str() ).empty() )
508  {
509  log ( Warning() , "Invalid combination of attributes for node " , Quote ( aNode->mUid ) , ": Size attribute specified, but mode missing, hence size ignored. Please specify mode here or remove the size attribute. Address table parser will throw an exception for this in future releases.");
510  }
511 
512  }
513 
514  void NodeTreeBuilder::setFirmwareInfo ( const pugi::xml_node& aXmlNode , Node* aNode )
515  {
516  //Address is an optional attribute for hierarchical addressing
517  std::string lFwInfoStr;
519 
520  if ( lFwInfoStr.size() )
521  {
522  //parse the string into a NodeTreeFwInfoAttribute object
523  std::string::const_iterator lBegin ( lFwInfoStr.begin() );
524  std::string::const_iterator lEnd ( lFwInfoStr.end() );
526  boost::spirit::qi::phrase_parse ( lBegin , lEnd , mNodeTreeFirmwareInfoAttributeGrammar , boost::spirit::ascii::space , lFwInfo );
527  aNode->mFirmwareInfo.insert ( make_pair ( "type",lFwInfo.mType ) );
528 
529  if ( lFwInfo.mArguments.size() )
530  {
531  aNode->mFirmwareInfo.insert ( lFwInfo.mArguments.begin() , lFwInfo.mArguments.end() );
532  }
533  }
534  }
535 
536 
537  void NodeTreeBuilder::addChildren ( const pugi::xml_node& aXmlNode , Node* aNode )
538  {
539  pugi::xml_node lXmlNode = aXmlNode.child ( "node" );
540 
541  if ( aNode->mMode == defs::NON_INCREMENTAL )
542  {
543  if ( lXmlNode )
544  {
545  exception::BlockAccessNodeCannotHaveChild lExc;
546  log ( lExc , "Block access nodes are not allowed to have child nodes, but the node " , Quote ( aNode->mUid ) , " has a child node in the address table" );
547  throw lExc;
548  }
549  }
550  else
551  {
552  for ( ; lXmlNode; lXmlNode = lXmlNode.next_sibling ( "node" ) )
553  {
554  aNode->mChildren.push_back ( mNodeParser ( lXmlNode ) );
555  }
556 
557  for ( std::vector< Node* >::iterator lIt = aNode->mChildren.begin(); lIt != aNode->mChildren.end(); ++lIt )
558  {
559  aNode->mChildrenMap.insert ( std::make_pair ( ( **lIt ).mUid , *lIt ) );
560  }
561  }
562  }
563 
564  void NodeTreeBuilder::calculateHierarchicalAddresses ( Node* aNode , const uint32_t& aAddr )
565  {
566  if ( aNode->mMode == defs::HIERARCHICAL )
567  {
568  if ( aNode->mChildren.size() == 0 )
569  {
570  aNode->mMode = defs::SINGLE;
571  }
572  else
573  {
574  // bool lAnyMasked( false );
575  bool lAllMasked ( true );
576 
577  for ( std::vector< Node* >::iterator lIt = aNode->mChildren.begin(); lIt != aNode->mChildren.end(); ++lIt )
578  {
579  if ( ( **lIt ).mMask == defs::NOMASK )
580  {
581  lAllMasked = false;
582  }
583 
584  // else
585  // {
586  // lAnyMasked = true;
587  // }
588  }
589 
590  // if( lAnyMasked && !lAllMasked )
591  // {
592  // log ( Error() , "Both masked and unmasked children found in branch " , Quote ( aNode->mUid ) );
593  // throw exception::// BothMaskedAndUnmaskedChildren();
594  // }
595 
596  if ( lAllMasked )
597  {
598  aNode->mMode = defs::SINGLE;
599  }
600  }
601  }
602 
603  if ( aNode->mMode == defs::INCREMENTAL )
604  {
605  uint64_t lTopAddr ( ( uint64_t ) ( aNode->mPartialAddr ) + ( uint64_t ) ( aNode->mSize-1 ) );
606 
607  //Check that the requested block size does not extend outside register space
608  if ( lTopAddr >> 32 )
609  {
610  exception::ArraySizeExceedsRegisterBound lExc;
611  log ( lExc , "A block size of " , Integer ( aNode->mSize ) , " and a base address of " , Integer ( aNode->mAddr , IntFmt<hex,fixed>() ) , " exceeds bounds of address space" );
612  throw lExc;
613  }
614 
615  /*
616  //Test for overlap with parent
617  if ( ( uint32_t ) ( lTopAddr ) & aAddr ) //should set the most significant bit of the child address and then AND this with the parent address
618  {
619  log ( Warning() , "The partial address of the top register in the current branch, " , Quote ( aNode->mUid ) , " , (" , Integer ( ( uint32_t ) ( lTopAddr ) , IntFmt<hex,fixed>() ) , ") overlaps with the partial address of the parent branch (" , Integer ( aAddr , IntFmt<hex,fixed>() ) , "). This might contradict the hierarchical design principal. For now this is a warning, but in the future this may be upgraded to throw an exception." );
620  }
621 
622  }
623  else
624  {
625  //Test for overlap with parent
626  if ( aNode->mPartialAddr & aAddr ) //should set the most significant bit of the child address and then AND this with the parent address
627  {
628  log ( Warning() , "The partial address of the top register in the current branch, " , Quote ( aNode->mUid ) , " , (" , Integer ( aNode->mPartialAddr , IntFmt<hex,fixed>() ) , ") overlaps with the partial address of the parent branch (" , Integer ( aAddr , IntFmt<hex,fixed>() ) , "). This might contradict the hierarchical design principal. For now this is a warning, but in the future this may be upgraded to throw an exception." );
629  }
630  */
631  }
632 
633  aNode->mAddr = aNode->mPartialAddr + aAddr;
634 
635  for ( std::vector< Node* >::iterator lIt = aNode->mChildren.begin(); lIt != aNode->mChildren.end(); ++lIt )
636  {
637  ( **lIt ).mParent = aNode;
638  calculateHierarchicalAddresses ( *lIt , aNode->mAddr );
639  }
640 
641  std::sort ( aNode->mChildren.begin() , aNode->mChildren.end() , detail::compareNodeAddr );
642  }
643 
644 
645  void NodeTreeBuilder::checkForAddressCollisions ( Node* aNode , const boost::filesystem::path& aPath )
646  {
647  std::vector<std::pair<const Node*, const Node*> > lOverlappingNodes = detail::getAddressOverlaps(*aNode);
648 
649  if ( not lOverlappingNodes.empty() )
650  {
651  // Add username to the collisions report filepath if environment variable USER is defined
652  std::string lDirName("/tmp");
653  if (char* lUsername = std::getenv("USER"))
654  {
655  lDirName += "/" + std::string(lUsername);
656  }
657  lDirName += "/uhal";
658 
659  boost::filesystem::path lDir ( lDirName );
660  lDir.make_preferred();
661 
662  try{
663  if ( !boost::filesystem::is_directory ( lDir ) )
664  {
665  if ( boost::filesystem::create_directories ( lDir ) )
666  {
667  boost::filesystem::permissions( lDir , boost::filesystem::all_all );
668  }
669  else
670  {
671  log ( Error() , "Address overlaps observed - attempted and failed to create directory " , Quote ( lDirName ) );
672  return;
673  }
674 
675  }
676  }
677  catch(const boost::filesystem::filesystem_error& e)
678  {
679  log ( Error() , "Address overlaps observed - failed to create directory " , Quote ( lDirName ) , " for report file; caught filesystem_error exception with what returning: ", e.what() );
680  return;
681  }
682 
683  std::string lFilename ( aPath.string() );
684  boost::replace_all ( lFilename , "/" , "-" );
685  const std::string lReportPath( ( lDir / ( "OverlapReport" + lFilename + ".txt" ) ).string() );
686 
687  if ( detail::writeNodeOverlapReport(lReportPath, lOverlappingNodes, "Overlap report for \"" + aPath.string() + "\".") )
688  {
689  log ( Warning() , "Address overlaps observed - report file written at " , Quote ( lReportPath ) );
690  }
691  else
692  {
693  log ( Error() , "Address overlaps observed - failed to create report file " , Quote ( lReportPath ) );
694  }
695  }
696  }
697 
698 
700  {
701  add
702  ( "r" , defs::READ )
703  ( "w" , defs::WRITE )
704  ( "read" , defs::READ )
705  ( "write" , defs::WRITE )
706  ( "rw" , defs::READWRITE )
707  ( "wr" , defs::READWRITE )
708  ( "readwrite" , defs::READWRITE )
709  ( "writeread" , defs::READWRITE )
710  ;
711  }
712 
714 
715 
717  {
718  add
719  ( "single" , defs::SINGLE )
720  ( "block" , defs::INCREMENTAL )
721  ( "port" , defs::NON_INCREMENTAL )
722  ( "incremental" , defs::INCREMENTAL )
723  ( "non-incremental" , defs::NON_INCREMENTAL )
724  ( "inc" , defs::INCREMENTAL )
725  ( "non-inc" , defs::NON_INCREMENTAL )
726  ;
727  }
728 
730 
731 }
uhal::NodeTreeBuilder::setPermissions
void setPermissions(const pugi::xml_node &aXmlNode, Node *aNode)
Definition: NodeTreeBuilder.cpp:448
uhal::Node::mTags
std::string mTags
Optional string which the user can specify.
Definition: Node.hpp:354
uhal::NodeTreeBuilder::mAddressAttribute
static const std::string mAddressAttribute
Definition: NodeTreeBuilder.hpp:157
uhal::detail::compareNodeAddr
bool compareNodeAddr(const Node *aNodeL, const Node *aNodeR)
Definition: utilities.cpp:115
uhal::NodeTreeBuilder::NodeTreeBuilder
NodeTreeBuilder()
Default constructor This is private since only a single instance is to be created,...
Definition: NodeTreeBuilder.cpp:79
uhal::NodeTreeBuilder::mode_lut
A look-up table that the boost qi parser uses for associating strings ("single","block",...
Definition: NodeTreeBuilder.hpp:191
uhal::NodeTreeFirmwareInfoAttribute
Struct to store the name and member variables within a node endpoint attribute when parsed by boost s...
Definition: NodeTreeFirmwareInfoAttributeGrammar.hpp:58
boost::shared_ptr
Definition: DerivedNodeFactory.hpp:52
uhal::Node::mModule
std::string mModule
The name of the module in which the current node resides.
Definition: Node.hpp:360
uhal::NodeTreeBuilder::mClassAttribute
static const std::string mClassAttribute
Definition: NodeTreeBuilder.hpp:165
uhal::defs::NodePermission
NodePermission
define Read and Write permissions of a uhal Node
Definition: definitions.hpp:50
uhal::NodeTreeBuilder::setMask
void setMask(const pugi::xml_node &aXmlNode, Node *aNode)
Definition: NodeTreeBuilder.cpp:466
uhal::NodeTreeBuilder::CallBack
void CallBack(const std::string &aProtocol, const boost::filesystem::path &aPath, std::vector< uint8_t > &aFile, std::vector< const Node * > &aAddressTable)
Method called once the file specified in the call to getNodeTree( aFilenameExpr ) has been opened.
Definition: NodeTreeBuilder.cpp:204
uhal::Node::mAddr
uint32_t mAddr
The register address with which this node is associated.
Definition: Node.hpp:342
uhal::Node::mFirmwareInfo
boost::unordered_map< std::string, std::string > mFirmwareInfo
parameters to infer the VHDL address decoding
Definition: Node.hpp:369
xml.hpp
uhal::NodeTreeBuilder::permissions_lut::permissions_lut
permissions_lut()
The actual function that the boost qi parser uses for associating strings with enumerated permissions...
Definition: NodeTreeBuilder.cpp:699
uhal::NodeTreeFirmwareInfoAttribute::mType
std::string mType
The endpoint type.
Definition: NodeTreeFirmwareInfoAttributeGrammar.hpp:60
uhal::Node::mUid
std::string mUid
The Unique ID of this node.
Definition: Node.hpp:337
uhal::Node::mDescription
std::string mDescription
Optional string which the user can specify.
Definition: Node.hpp:357
uhal::NodeTreeBuilder::setClassName
void setClassName(const pugi::xml_node &aXmlNode, Node *aNode)
Definition: NodeTreeBuilder.cpp:373
sort
PUGI__FN void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7457
uhal::NodeTreeBuilder::mTagsAttribute
static const std::string mTagsAttribute
Definition: NodeTreeBuilder.hpp:159
uhal::NodeTreeBuilder::build
Node * build(const pugi::xml_node &aNode, const boost::filesystem::path &aAddressFilePath)
Definition: NodeTreeBuilder.cpp:192
uhal::NodeTreeBuilder::setFirmwareInfo
void setFirmwareInfo(const pugi::xml_node &aXmlNode, Node *aNode)
Definition: NodeTreeBuilder.cpp:514
uhal::IntFmt
Empty struct which acts as a dummy variable for passing the formatting information around.
Definition: log_inserters.integer.hpp:68
uhal::NodeTreeBuilder::mModeLut
uhal::NodeTreeBuilder::mode_lut mModeLut
An instance of a look-up table that the boost qi parser uses for associating strings with enumerated ...
Definition: NodeTreeBuilder.cpp:729
uhal::NodeTreeBuilder::mDescriptionAttribute
static const std::string mDescriptionAttribute
Definition: NodeTreeBuilder.hpp:160
uhal::Node::mPartialAddr
uint32_t mPartialAddr
The register address with which this node is associated.
Definition: Node.hpp:340
uhal::NodeTreeBuilder::mModuleAttribute
static const std::string mModuleAttribute
Definition: NodeTreeBuilder.hpp:166
uhal::Node::mChildren
std::vector< Node * > mChildren
The direct children of the node.
Definition: Node.hpp:375
uhal::defs::HIERARCHICAL
@ HIERARCHICAL
Definition: definitions.hpp:53
uhal::NodeTreeBuilder::mMaskAttribute
static const std::string mMaskAttribute
Definition: NodeTreeBuilder.hpp:162
uhal::NodeTreeBuilder::mIdAttribute
static const std::string mIdAttribute
Definition: NodeTreeBuilder.hpp:156
pugi::xml_node::child
xml_node child(const char_t *name) const
Definition: pugixml.cpp:5497
uhal::NodeTreeBuilder
A class to build a node tree from an Address table file NOTE! This is a factory method and must be Mu...
Definition: NodeTreeBuilder.hpp:88
uhal::NodeTreeBuilder::setModeAndSize
void setModeAndSize(const pugi::xml_node &aXmlNode, Node *aNode)
Definition: NodeTreeBuilder.cpp:473
uhal::NodeTreeBuilder::plainNodeCreator
Node * plainNodeCreator(const bool &aRequireId, const pugi::xml_node &aXmlNode)
Definition: NodeTreeBuilder.cpp:257
uhal
Definition: HttpResponseGrammar.hpp:49
uhal::utilities::ParseSemicolonDelimitedUriList
void ParseSemicolonDelimitedUriList(const std::string &aSemicolonDelimitedUriList, std::vector< std::pair< std::string, std::string > > &aUriList)
Parse a semicolon delimited list of URIs into a vector of protocol/address pairs.
Definition: files.cpp:46
uhal::NodeTreeBuilder::mParametersAttribute
static const std::string mParametersAttribute
Definition: NodeTreeBuilder.hpp:158
uhal::NodeTreeBuilder::mNodeTreeFirmwareInfoAttributeGrammar
grammars::NodeTreeFirmwareinfoAttributeGrammar mNodeTreeFirmwareInfoAttributeGrammar
Definition: NodeTreeBuilder.hpp:198
uhal::NodeTreeFirmwareInfoAttribute::mArguments
NameValuePairVectorType mArguments
The member variable of the endpoint stored as "name1=val1;name2=val2;name3=val3".
Definition: NodeTreeFirmwareInfoAttributeGrammar.hpp:62
uhal::NodeTreeBuilder::setUid
void setUid(const bool &aRequireId, const pugi::xml_node &aXmlNode, Node *aNode)
Definition: NodeTreeBuilder.cpp:343
uhal::NodeTreeBuilder::mPermissionsAttribute
static const std::string mPermissionsAttribute
Definition: NodeTreeBuilder.hpp:161
uhal::Node::mMode
defs::BlockReadWriteMode mMode
Whether the node represents a single register, a block of registers or a block-read/write port.
Definition: Node.hpp:349
uhal::NodeTreeBuilder::mNodes
boost::unordered_map< std::string, const Node * > mNodes
Hash map associating a Node tree with a file name so that we do not need to repeatedly parse the xml ...
Definition: NodeTreeBuilder.hpp:179
files.hpp
uhal::NodeTreeBuilder::mNodeTreeParametersGrammar
grammars::NodeTreeParametersGrammar mNodeTreeParametersGrammar
Definition: NodeTreeBuilder.hpp:197
uhal::Node
A heirarchical node for navigating heirarchical firmwares.
Definition: Node.hpp:86
uhal::NodeTreeBuilder::checkForAddressCollisions
void checkForAddressCollisions(Node *aNode, const boost::filesystem::path &aPath)
Definition: NodeTreeBuilder.cpp:645
uhal::NodeTreeBuilder::mFileCallStack
std::deque< boost::filesystem::path > mFileCallStack
Definition: NodeTreeBuilder.hpp:172
uhal::Rule::optional
Rule< R > & optional(const std::string &aStr)
Add an optional attribute to the rule.
Definition: XmlParser.hxx:140
uhal::detail::getAddressOverlaps
std::vector< std::pair< const Node *, const Node * > > getAddressOverlaps(const Node &aNode)
Definition: utilities.cpp:121
uhal::NodeTreeBuilder::setPars
void setPars(const pugi::xml_node &aXmlNode, Node *aNode)
Definition: NodeTreeBuilder.cpp:382
uhal::defs::BlockReadWriteMode
BlockReadWriteMode
define whether transactions target a single register, a block of registers, a block-read/write port o...
Definition: definitions.hpp:53
uhal::Info
InfoLevel Info
Definition: LogLevels.cpp:115
uhal::log
void log(FatalLevel &aFatal, const T0 &aArg0)
Function to add a log entry at Fatal level.
Definition: log.hxx:20
uhal::NodeTreeBuilder::setDescription
void setDescription(const pugi::xml_node &aXmlNode, Node *aNode)
Definition: NodeTreeBuilder.cpp:422
uhal::Integer
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
Definition: log_inserters.integer.hxx:43
pugi::xml_node
Definition: pugixml.hpp:455
uhal::Rule
Rule for matching XML attributes.
Definition: XmlParser.hpp:145
uhal::Warning
WarningLevel Warning
Definition: LogLevels.cpp:79
pugi::xml_attribute::empty
bool empty() const
Definition: pugixml.cpp:5212
uhal::NodeTreeBuilder::mTopLevelNodeParser
Parser< Node * > mTopLevelNodeParser
Definition: NodeTreeBuilder.hpp:169
uhal::NodeTreeBuilder::mNodeParser
Parser< Node * > mNodeParser
Definition: NodeTreeBuilder.hpp:170
uhal::Error
ErrorLevel Error
Definition: LogLevels.cpp:61
uhal::NodeTreeBuilder::mFirmwareInfo
static const std::string mFirmwareInfo
Definition: NodeTreeBuilder.hpp:167
uhal::defs::NON_INCREMENTAL
@ NON_INCREMENTAL
Definition: definitions.hpp:53
uhal::Quote
_Quote< T > Quote(const T &aT)
Definition: log_inserters.quote.hxx:49
uhal::Rule::require
Rule< R > & require(const std::string &aStr)
Add a required attribute to the rule.
Definition: XmlParser.hxx:110
uhal::Node::mClassName
std::string mClassName
Class name used to construct the derived node type.
Definition: Node.hpp:363
uhal::NodeTreeBuilder::mSizeAttribute
static const std::string mSizeAttribute
Definition: NodeTreeBuilder.hpp:164
uhal::DerivedNodeFactory::convertToClassType
Node * convertToClassType(Node *aNode)
Definition: DerivedNodeFactory.cpp:74
pugi::xml_node::next_sibling
xml_node next_sibling() const
Definition: pugixml.cpp:5528
uhal::NodeTreeBuilder::~NodeTreeBuilder
virtual ~NodeTreeBuilder()
Destructor.
Definition: NodeTreeBuilder.cpp:138
uhal::defs::INCREMENTAL
@ INCREMENTAL
Definition: definitions.hpp:53
uhal::NodeTreeBuilder::permissions_lut
A look-up table that the boost qi parser uses for associating strings ("r","w","rw",...
Definition: NodeTreeBuilder.hpp:183
uhal::NodeTreeBuilder::bitmaskNodeCreator
Node * bitmaskNodeCreator(const bool &aRequireId, const pugi::xml_node &aXmlNode)
Definition: NodeTreeBuilder.cpp:314
uhal::NodeTreeBuilder::mode_lut::mode_lut
mode_lut()
The actual function that the boost qi parser uses for associating strings with enumerated permissions...
Definition: NodeTreeBuilder.cpp:716
uhal::Node::mSize
uint32_t mSize
The maximum size available to a block read/write.
Definition: Node.hpp:351
uhal::utilities::GetXMLattribute< false >
template bool GetXMLattribute< false >(const pugi::xml_node &aNode, const std::string &aAttrName, std::string &aTarget)
uhal::defs::READWRITE
@ READWRITE
Definition: definitions.hpp:50
uhal::utilities::OpenFile
void OpenFile(const std::string &aProtocol, const std::string &aFilenameExpr, const boost::filesystem::path &aParentPath, boost::_bi::bind_t< R, F, L > aBinder)
Given a protocol and either a URL or a linux shell expression, open the file and call the callback fu...
Definition: files.hpp:353
uhal::Debug
DebugLevel Debug
Definition: LogLevels.cpp:133
uhal::detail::writeNodeOverlapReport
bool writeNodeOverlapReport(const std::string &aFilePath, const std::vector< std::pair< const Node *, const Node * > > &aNodes, const std::string &aHeader)
Definition: utilities.cpp:198
uhal::utilities::PugiXMLParseResultPrettifier
void PugiXMLParseResultPrettifier(const pugi::xml_parse_result &aLoadResult, const boost::filesystem::path &aPath, const std::vector< uint8_t > &aFile)
Helper function to make debugging failures when parsing XML files easier.
Definition: xml.cpp:57
uhal::Node::mPermission
defs::NodePermission mPermission
The read/write access permissions of this node.
Definition: Node.hpp:347
pugi::xml_node::attribute
xml_attribute attribute(const char_t *name) const
Definition: pugixml.cpp:5507
uhal::Node::mChildrenMap
boost::unordered_map< std::string, Node * > mChildrenMap
Helper to assist look-up of a particular child node, given a name.
Definition: Node.hpp:378
DerivedNodeFactory.hpp
uhal::Node::mMask
uint32_t mMask
The mask to be applied if this node is a sub-field, rather than an entire register.
Definition: Node.hpp:345
uhal::Notice
NoticeLevel Notice
Definition: LogLevels.cpp:97
log.hpp
uhal::NodeTreeBuilder::setTags
void setTags(const pugi::xml_node &aXmlNode, Node *aNode)
Definition: NodeTreeBuilder.cpp:403
uhal::NodeTreeBuilder::addChildren
void addChildren(const pugi::xml_node &aXmlNode, Node *aNode)
Definition: NodeTreeBuilder.cpp:537
pugi::xml_document
Definition: pugixml.hpp:1001
NodeTreeBuilder.hpp
uhal::NodeTreeBuilder::getNodeTree
Node * getNodeTree(const std::string &aFilenameExpr, const boost::filesystem::path &aPath)
Construct a node tree from file whose name is specified.
Definition: NodeTreeBuilder.cpp:155
pugi::xml_document::load_buffer_inplace
xml_parse_result load_buffer_inplace(void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:7142
uhal::NodeTreeBuilder::setModule
void setModule(const pugi::xml_node &aXmlNode, Node *aNode)
Definition: NodeTreeBuilder.cpp:440
uhal::DerivedNodeFactory::getInstance
static DerivedNodeFactory & getInstance()
Static method to retrieve the single instance of the class.
Definition: DerivedNodeFactory.cpp:63
uhal::Node::mParameters
boost::unordered_map< std::string, std::string > mParameters
Additional parameters of the node.
Definition: Node.hpp:366
uhal::NodeTreeBuilder::getInstance
static NodeTreeBuilder & getInstance()
Static method to retrieve the single instance of the class.
Definition: NodeTreeBuilder.cpp:144
uhal::defs::NOMASK
const uint32_t NOMASK
define what it means to have no mask
Definition: definitions.hpp:56
uhal::NodeTreeBuilder::mInstance
static boost::shared_ptr< NodeTreeBuilder > mInstance
The single instance of the class.
Definition: NodeTreeBuilder.hpp:176
uhal::NodeTreeBuilder::mModeAttribute
static const std::string mModeAttribute
Definition: NodeTreeBuilder.hpp:163
uhal::defs::WRITE
@ WRITE
Definition: definitions.hpp:50
uhal::NodeTreeBuilder::moduleNodeCreator
Node * moduleNodeCreator(const bool &aRequireId, const pugi::xml_node &aXmlNode)
Definition: NodeTreeBuilder.cpp:284
uhal::defs::READ
@ READ
Definition: definitions.hpp:50
pugi::xml_parse_result
Definition: pugixml.hpp:979
utilities.hpp
uhal::NodeTreeBuilder::clearAddressFileCache
void clearAddressFileCache()
Clears address filename -> Node tree cache. NOT thread safe; for tread-safety, use ConnectionManager ...
Definition: NodeTreeBuilder.cpp:182
uhal::NodeTreeBuilder::setAddr
void setAddr(const pugi::xml_node &aXmlNode, Node *aNode)
Definition: NodeTreeBuilder.cpp:364
uhal::NodeTreeBuilder::mPermissionsLut
uhal::NodeTreeBuilder::permissions_lut mPermissionsLut
An instance of a look-up table that the boost qi parser uses for associating strings with enumerated ...
Definition: NodeTreeBuilder.cpp:713
uhal::defs::SINGLE
@ SINGLE
Definition: definitions.hpp:53
uhal::NodeTreeBuilder::calculateHierarchicalAddresses
void calculateHierarchicalAddresses(Node *aNode, const uint32_t &aAddr)
Propagate the addresses down through the hierarchical structure.
Definition: NodeTreeBuilder.cpp:564