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".