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> 
   52namespace arg = std::placeholders;
 
  153    std::vector< std::pair<std::string, std::string> >  lAddressFiles;
 
  156    if ( lAddressFiles.size() != 1 )
 
  158      exception::IncorrectAddressTableFileCount lExc;
 
  159      log ( lExc , 
"Exactly one address table file must be specified. The expression " , 
Quote ( aFilenameExpr ) , 
" contains " , 
Integer ( lAddressFiles.size() ) , 
" valid file expressions." );
 
  163    std::vector< const Node* > lNodes;
 
  166    if ( lNodes.size() != 1 )
 
  168      exception::IncorrectAddressTableFileCount lExc;
 
  169      log ( lExc , 
"Exactly one address table file must be specified. The expression " , 
Quote ( lAddressFiles[0].second ) , 
" refers to " , 
Integer ( lNodes.size() ) , 
" valid files." );
 
  173    Node* lNode ( lNodes[0]->clone() );
 
  180    for(
const auto& x: 
mNodes)
 
  198  void NodeTreeBuilder::CallBack ( 
const std::string& aProtocol , 
const boost::filesystem::path& aPath , std::vector<uint8_t>& aFile , std::vector< const Node* >& aNodes )
 
  200    std::string lName ( aProtocol + ( aPath.string() ) );
 
  201    std::unordered_map< std::string , const Node* >::iterator lNodeIt = 
mNodes.find ( lName );
 
  203    if ( lNodeIt != 
mNodes.end() )
 
  205      aNodes.push_back ( lNodeIt->second );
 
  209    std::string lExtension ( aPath.extension().string().substr ( 0,4 ) );
 
  210    boost::to_lower ( lExtension ); 
 
  212    if ( lExtension == 
".xml" )
 
  214      log ( 
Info() , 
"Reading XML address file " , 
Quote( aPath.c_str() ) );
 
  228        log ( 
Error() , 
"No XML node called ", 
Quote ( 
"node" ) , 
" in file " , aPath.c_str() );
 
  232      Node* lNode ( 
build ( lXmlNode , aPath ) );
 
  233      mNodes.insert ( std::make_pair ( lName , lNode ) );
 
  234      aNodes.push_back ( lNode );
 
  237    else if ( lExtension == 
".txt" )
 
  240      log ( 
Error() , 
"Parser problems mean that this method has been disabled." );
 
  245      log ( 
Error() , 
"Extension " , 
Quote ( lExtension ) , 
" not known." );
 
  254    setUid ( aRequireId , aXmlNode , lNode );
 
  266    log ( 
Debug() , lNode->
mUid , 
" built by " , __PRETTY_FUNCTION__ );
 
  283    setUid ( aRequireId , aXmlNode , lNode );
 
  295    log ( 
Debug() , lNode->
mUid , 
" built by " , __PRETTY_FUNCTION__ );
 
  310    if ( aXmlNode.
child ( 
"node" ) )
 
  312      exception::MaskedNodeCannotHaveChild lExc;
 
  313      log ( lExc , 
"Bit-masked nodes are not allowed to have child nodes" );
 
  318    setUid ( aRequireId , aXmlNode , lNode );
 
  330    log ( 
Debug() , lNode->
mUid , 
" built by " , __PRETTY_FUNCTION__ );
 
  341    if ( aRequireId and ( not lHasId ) )
 
  344      throw exception::NodeMustHaveUID(
"'id' attribute is missing from address table node");
 
  349      if ( aNode->
mUid.empty() )
 
  350        throw exception::NodeAttributeIncorrectValue(
"Invalid node ID specified (empty)");
 
  351      else if ( aNode->
mUid.find(
'.') != std::string::npos )
 
  352        throw exception::NodeAttributeIncorrectValue(
"Invalid node ID '" + aNode->
mUid + 
"' specified (contains dots)");
 
  353      else if ( ( aNode->
mUid.at(0) == 
' ' ) or ( aNode->
mUid.at(aNode->
mUid.size()-1) == 
' ' ) )
 
  354        throw exception::NodeAttributeIncorrectValue(
"Invalid node ID '" + aNode->
mUid + 
"' specified (contains spaces)");
 
  361    uint32_t lAddr ( 0 );
 
  370    std::string lClassStr;
 
  378    std::string lParsStr;
 
  382    if ( lParsStr.size() )
 
  385      std::string::const_iterator lBegin ( lParsStr.begin() );
 
  386      std::string::const_iterator lEnd ( lParsStr.end() );
 
  387      std::unordered_map<std::string, std::string> lPars;
 
  403    if ( lStr.size() && aNode->
mTags.size() )
 
  406      aNode->
mTags += lStr;
 
  409    else if ( lStr.size() && !aNode->
mTags.size() )
 
  445    std::string lPermissionAttr;
 
  450      if (lPermission == NULL)
 
  452        throw exception::NodeAttributeIncorrectValue(
"Permission attribute for node with ID '" + aNode->
mUid + 
"' has incorrect value '" + lPermissionAttr + 
"'");
 
  470    std::string lModeAttr;
 
  477        throw exception::NodeAttributeIncorrectValue(
"Mode attribute for node with ID '" + aNode->
mUid + 
"' has incorrect value '" + lModeAttr + 
"'");
 
  480        aNode->
mMode = *lMode;
 
  487          exception::IncrementalNodeRequiresSizeAttribute lExc;
 
  497          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." );
 
  503      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.");
 
  511    std::string lFwInfoStr;
 
  514    if ( lFwInfoStr.size() )
 
  517      std::string::const_iterator lBegin ( lFwInfoStr.begin() );
 
  518      std::string::const_iterator lEnd ( lFwInfoStr.end() );
 
  539        exception::BlockAccessNodeCannotHaveChild lExc;
 
  540        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" );
 
  546      for ( ; lXmlNode; lXmlNode = lXmlNode.
next_sibling ( 
"node" ) )
 
  551      for (
const auto& lChild: aNode->
mChildren)
 
  552        aNode->
mChildrenMap.insert ( std::make_pair ( lChild->mUid , lChild ) );
 
  567        bool lAllMasked ( 
true );
 
  595      uint64_t lTopAddr ( ( uint64_t ) ( aNode->
mPartialAddr ) + ( uint64_t ) ( aNode->
mSize-1 ) );
 
  598      if ( lTopAddr >> 32 )
 
  600        exception::ArraySizeExceedsRegisterBound lExc;
 
  639    if ( not lOverlappingNodes.empty() )
 
  642      std::string lDirName(
"/tmp");
 
  643      if (
char* lUsername = std::getenv(
"USER"))
 
  645        lDirName += 
"/" + std::string(lUsername);
 
  649      boost::filesystem::path lDir ( lDirName );
 
  650      lDir.make_preferred();
 
  653        if ( !boost::filesystem::is_directory ( lDir ) )
 
  655          if ( boost::filesystem::create_directories ( lDir ) )
 
  657            boost::filesystem::permissions( lDir , boost::filesystem::all_all );
 
  661            log ( 
Error() , 
"Address overlaps observed - attempted and failed to create directory " , 
Quote ( lDirName ) );
 
  667      catch(
const boost::filesystem::filesystem_error& e)
 
  669        log ( 
Error() , 
"Address overlaps observed - failed to create directory " , 
Quote ( lDirName ) , 
" for report file; caught filesystem_error exception with what returning:  ", e.what() );
 
  673      std::string lFilename ( aPath.string() );
 
  674      boost::replace_all ( lFilename , 
"/" , 
"-" );
 
  675      const std::string lReportPath( ( lDir / ( 
"OverlapReport" + lFilename + 
".txt" ) ).
string() );
 
  679        log ( 
Warning() , 
"Address overlaps observed - report file written at " , 
Quote ( lReportPath ) );
 
  683        log ( 
Error() , 
"Address overlaps observed - failed to create report file " , 
Quote ( lReportPath ) );
 
xml_parse_result load_buffer_inplace(void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
 
xml_node child(const char_t *name) const
 
xml_node next_sibling() const
 
xml_attribute attribute(const char_t *name) const
 
Node * convertToClassType(Node *aNode)
 
static DerivedNodeFactory & getInstance()
Static method to retrieve the single instance of the class.
 
A heirarchical node for navigating heirarchical firmwares.
 
std::unordered_map< std::string, std::string > mFirmwareInfo
parameters to infer the VHDL address decoding
 
std::vector< Node * > mChildren
The direct children of the node.
 
uint32_t mAddr
The register address with which this node is associated.
 
defs::BlockReadWriteMode mMode
Whether the node represents a single register, a block of registers or a block-read/write port.
 
uint32_t mMask
The mask to be applied if this node is a sub-field, rather than an entire register.
 
std::unordered_map< std::string, Node * > mChildrenMap
Helper to assist look-up of a particular child node, given a name.
 
std::string mUid
The Unique ID of this node.
 
std::string mClassName
Class name used to construct the derived node type.
 
std::string mDescription
Optional string which the user can specify.
 
std::unordered_map< std::string, std::string > mParameters
Additional parameters of the node.
 
defs::NodePermission mPermission
The read/write access permissions of this node.
 
std::string mModule
The name of the module in which the current node resides.
 
uint32_t mPartialAddr
The register address with which this node is associated.
 
uint32_t mSize
The maximum size available to a block read/write.
 
std::string mTags
Optional string which the user can specify.
 
Node * mParent
The parent of the current node.
 
A class to build a node tree from an address table file.
 
void setModule(const pugi::xml_node &aXmlNode, Node *aNode)
 
static NodeTreeBuilder & getInstance()
Static method to retrieve the single instance of the class.
 
static const std::string mModeAttribute
 
uhal::NodeTreeBuilder::permissions_lut mPermissionsLut
An instance of a look-up table that the boost qi parser uses for associating strings with enumerated ...
 
void setModeAndSize(const pugi::xml_node &aXmlNode, Node *aNode)
 
static const std::string mTagsAttribute
 
void setPermissions(const pugi::xml_node &aXmlNode, Node *aNode)
 
NodeTreeBuilder()
Default constructor This is private since only a single instance is to be created,...
 
Parser< Node * > mTopLevelNodeParser
 
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.
 
void setUid(const bool &aRequireId, const pugi::xml_node &aXmlNode, Node *aNode)
 
void setMask(const pugi::xml_node &aXmlNode, Node *aNode)
 
void setTags(const pugi::xml_node &aXmlNode, Node *aNode)
 
grammars::NodeTreeFirmwareinfoAttributeGrammar mNodeTreeFirmwareInfoAttributeGrammar
 
static const std::string mSizeAttribute
 
void setClassName(const pugi::xml_node &aXmlNode, Node *aNode)
 
static const std::string mParametersAttribute
 
static const std::string mModuleAttribute
 
std::deque< boost::filesystem::path > mFileCallStack
 
static std::shared_ptr< NodeTreeBuilder > mInstance
The single instance of the class.
 
void setAddr(const pugi::xml_node &aXmlNode, Node *aNode)
 
static const std::string mAddressAttribute
 
static const std::string mMaskAttribute
 
Parser< Node * > mNodeParser
 
void setDescription(const pugi::xml_node &aXmlNode, Node *aNode)
 
static const std::string mFirmwareInfo
 
Node * getNodeTree(const std::string &aFilenameExpr, const boost::filesystem::path &aPath)
Construct a node tree from file whose name is specified.
 
void checkForAddressCollisions(Node *aNode, const boost::filesystem::path &aPath)
 
uhal::NodeTreeBuilder::mode_lut mModeLut
An instance of a look-up table that the boost qi parser uses for associating strings with enumerated ...
 
void calculateHierarchicalAddresses(Node *aNode, const uint32_t &aAddr)
Propagate the addresses down through the hierarchical structure.
 
void clearAddressFileCache()
Clears address filename -> Node tree cache. NOT thread safe; for tread-safety, use ConnectionManager ...
 
static const std::string mClassAttribute
 
static const std::string mDescriptionAttribute
 
std::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 ...
 
grammars::NodeTreeParametersGrammar mNodeTreeParametersGrammar
 
virtual ~NodeTreeBuilder()
Destructor.
 
void setFirmwareInfo(const pugi::xml_node &aXmlNode, Node *aNode)
 
Node * plainNodeCreator(const bool &aRequireId, const pugi::xml_node &aXmlNode)
 
Node * moduleNodeCreator(const bool &aRequireId, const pugi::xml_node &aXmlNode)
 
Node * bitmaskNodeCreator(const bool &aRequireId, const pugi::xml_node &aXmlNode)
 
static const std::string mPermissionsAttribute
 
void setPars(const pugi::xml_node &aXmlNode, Node *aNode)
 
void addChildren(const pugi::xml_node &aXmlNode, Node *aNode)
 
static const std::string mIdAttribute
 
Node * build(const pugi::xml_node &aNode, const boost::filesystem::path &aAddressFilePath)
 
Rule for matching XML attributes.
 
Rule< R > & optional(const std::string &aStr)
Add an optional attribute to the rule.
 
Rule< R > & require(const std::string &aStr)
Add a required attribute to the rule.
 
BlockReadWriteMode
define whether transactions target a single register, a block of registers, a block-read/write port o...
 
NodePermission
define Read and Write permissions of a uhal Node
 
const uint32_t NOMASK
define what it means to have no mask
 
bool writeNodeOverlapReport(const std::string &aFilePath, const std::vector< std::pair< const Node *, const Node * > > &aNodes, const std::string &aHeader)
 
bool compareNodeAddr(const Node *aNodeL, const Node *aNodeR)
 
std::vector< std::pair< const Node *, const Node * > > getAddressOverlaps(const Node &aNode)
 
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.
 
template bool GetXMLattribute< false >(const pugi::xml_node &aNode, const std::string &aAttrName, std::string &aTarget)
 
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.
 
void OpenFile(const std::string &aProtocol, const std::string &aFilenameExpr, const boost::filesystem::path &aParentPath, const detail::FileCallback_t &aCallback)
Given a protocol and either a URL or a linux shell expression, open the file and call the callback fu...
 
_Quote< T > Quote(const T &aT)
 
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
 
void log(FatalLevel &aFatal, const T0 &aArg0)
Function to add a log entry at Fatal level.
 
constexpr int first(int i)
Implementation details for constexpr functions.
 
Annotation for arguments.
 
Empty struct which acts as a dummy variable for passing the formatting information around.
 
A look-up table that the boost qi parser uses for associating strings ("single","block",...
 
mode_lut()
The actual function that the boost qi parser uses for associating strings with enumerated permissions...
 
A look-up table that the boost qi parser uses for associating strings ("r","w","rw",...
 
permissions_lut()
The actual function that the boost qi parser uses for associating strings with enumerated permissions...
 
Struct to store the name and member variables within a node endpoint attribute when parsed by boost s...
 
std::string mType
The endpoint type.
 
NameValuePairVectorType mArguments
The member variable of the endpoint stored as "name1=val1;name2=val2;name3=val3".