μHAL (v2.8.17)
Part of the IPbus software repository
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
utilities.cpp
Go to the documentation of this file.
1
2/*
3---------------------------------------------------------------------------
4
5 This file is part of uHAL.
6
7 uHAL is a hardware access library and programming framework
8 originally developed for upgrades of the Level-1 trigger of the CMS
9 experiment at CERN.
10
11 uHAL is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 uHAL is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with uHAL. If not, see <http://www.gnu.org/licenses/>.
23
24 Tom Williams, Rutherford Appleton Laboratory, Oxfordshire
25 email: tom.williams <AT> cern.ch
26
27---------------------------------------------------------------------------
28*/
29
31
32
33#include <fstream>
34#include <iomanip>
35#include <memory>
36
37#include <boost/date_time/posix_time/posix_time.hpp>
38#include <boost/filesystem.hpp>
39
40#include "uhal/Node.hpp"
41
42
43namespace uhal {
44 namespace detail {
45
46 std::string getAddressDescription(const Node& aNode, const uint32_t aAddress, const size_t& aMaxListSize)
47 {
48 std::vector<const Node*> lMatches;
49 for ( Node::const_iterator lIt = aNode.begin(); lIt != aNode.end(); lIt++ ) {
50
51 if ( lIt->getMode() == uhal::defs::INCREMENTAL ) {
52 if ( ( aAddress >= lIt->getAddress() ) and ( aAddress < ( lIt->getAddress() + lIt->getSize() ) ) )
53 lMatches.push_back(&*lIt);
54 }
55 else if ( lIt->getMode() != uhal::defs::HIERARCHICAL ) {
56 if ( lIt->getAddress() == aAddress )
57 lMatches.push_back(&*lIt);
58 }
59 }
60
61 if ( lMatches.empty() )
62 return "no matching nodes";
63 else if ( lMatches.size() == 1 )
64 return "node \"" + lMatches.front()->getPath() + "\"";
65
66 const Node* lCommonAncestor = lMatches.front();
67 std::vector<const Node*> lCommonAncestorLineage = lCommonAncestor->getLineage(aNode);
68
69 for ( std::vector<const Node*>::const_iterator lIt = lMatches.begin()+1; lIt != lMatches.end(); lIt++ ) {
70 const std::vector<const Node*> lLineage = (*lIt)->getLineage(aNode);
71
72 size_t i = 0;
73 for ( ; i < std::min(lLineage.size(), lCommonAncestorLineage.size()); i++ ) {
74 if ( lCommonAncestorLineage.at(i) != lLineage.at(i) )
75 break;
76 }
77 lCommonAncestor = lLineage.at(i - 1);
78 lCommonAncestorLineage.assign(lLineage.begin(), lLineage.begin() + i);
79 }
80
81 if ( (aMaxListSize != 0) and (lMatches.size() > aMaxListSize) )
82 {
83 if ( lCommonAncestor == &aNode )
84 return std::to_string(lMatches.size()) + " nodes match";
85 else
86 return std::to_string(lMatches.size()) + " nodes under \"" + lCommonAncestor->getPath() + "\" match";
87 }
88 else
89 {
90 const std::string lCommonAncestorPath(lCommonAncestor->getPath());
91 const size_t lCommonPathLength(lCommonAncestor == &aNode ? 0 : lCommonAncestorPath.size() + 1);
92 std::ostringstream lOSS;
93 lOSS << "nodes \"" << lMatches.front()->getPath().substr(lCommonPathLength) << "\"";
94 for (auto lIt = lMatches.begin() + 1; lIt < lMatches.end(); lIt++)
95 lOSS << ", \"" << (*lIt)->getPath().substr(lCommonPathLength) << "\"";
96
97 if (lCommonAncestor != &aNode)
98 lOSS << " under \"" << lCommonAncestorPath << "\"";
99
100 return lOSS.str();
101 }
102 }
103
104
105 std::string getAddressDescription(const ClientInterface& aClient, const uint32_t aAddress, const size_t& aMaxListSize)
106 {
107 if ( std::shared_ptr<Node> lNode = aClient.mNode.lock() )
108 return getAddressDescription(*lNode, aAddress, aMaxListSize);
109 else
110 return "";
111 }
112
113
114 bool compareNodeAddr ( const Node* aNodeL, const Node* aNodeR )
115 {
116 return ( aNodeL->getAddress() < aNodeR->getAddress() );
117 }
118
119
120 std::vector<std::pair<const Node*, const Node*> > getAddressOverlaps(const Node& aNode)
121 {
122 std::vector<const Node*> lNodes;
123 for (Node::const_iterator lIt = aNode.begin() ; lIt.next() ; )
124 lNodes.push_back(&*lIt);
125 std::stable_sort ( lNodes.begin() , lNodes.end() , compareNodeAddr );
126
127 std::vector<std::pair<const Node*, const Node*> > lOverlappingNodes;
128 if (lNodes.size() < 2)
129 return lOverlappingNodes;
130
131 for (std::vector<const Node*>::const_iterator lIt1 = lNodes.begin() ; lIt1 != (lNodes.end() - 1); lIt1++)
132 {
133 const Node& lNode1 = **lIt1;
134 if (lNode1.getMode() == defs::HIERARCHICAL)
135 continue;
136
137 const uint32_t lMaxAddr1(lNode1.getMode() == defs::INCREMENTAL ? lNode1.getAddress() + lNode1.getSize() - 1 : lNode1.getAddress());
138
139 for (std::vector<const Node*>::const_iterator lIt2(lIt1 + 1) ; (lIt2 != lNodes.end()) and (*lIt2)->getAddress() <= lMaxAddr1; lIt2++)
140 {
141 if ((*lIt2)->getMode() == defs::HIERARCHICAL)
142 continue;
143
144 const Node& lNode2 = **lIt2;
145
146 if (lNode1.getMode() != defs::SINGLE or lNode2.getMode() != defs::SINGLE)
147 lOverlappingNodes.push_back( std::make_pair(&lNode1, &lNode2) );
148
149 else if (lNode1.getMask() & lNode2.getMask())
150 {
151 if (lNode1.getMask() == defs::NOMASK and lNode2.isChildOf(lNode1))
152 {
153 // Node 2 is masked child of node 1: No overlap
154 }
155 else if (lNode2.getMask() == defs::NOMASK and lNode1.isChildOf(lNode2))
156 {
157 // Node 1 is masked child of node 2: No overlap
158 }
159 else
160 lOverlappingNodes.push_back( std::make_pair(&lNode1, &lNode2) );
161 }
162 }
163 }
164
165 return lOverlappingNodes;
166 }
167
168
169 void printNodeOverlapDescription(std::ostream& aStream, const Node& aNode1, const Node& aNode2)
170 {
171 std::ios_base::fmtflags lInitialFlags = aStream.flags();
172 char lInitialFillChar = aStream.fill('0');
173 aStream << std::hex;
174
175 aStream << "Node '" << aNode1.getPath() << "' [";
176 if (aNode1.getMode() == defs::INCREMENTAL)
177 aStream << "addresses 0x" << std::setw ( 8 ) << aNode1.getAddress() << " - 0x" << std::setw ( 8 ) << aNode1.getAddress() + aNode1.getSize() - 1;
178 else if ( aNode2.getMode() == defs::INCREMENTAL )
179 aStream << "address 0x" << std::setw ( 8 ) << aNode1.getAddress();
180 else
181 aStream << "address 0x" << std::setw ( 8 ) << aNode1.getAddress() << ", mask 0x" << std::setw ( 8 ) << aNode1.getMask();
182
183 aStream << "] overlaps with '" << aNode2.getPath() << "' [";
184 if (aNode2.getMode() == defs::INCREMENTAL)
185 aStream << "addresses 0x" << std::setw ( 8 ) << aNode2.getAddress() << " - 0x" << std::setw ( 8 ) << aNode2.getAddress() + aNode2.getSize() - 1;
186 else if ( aNode1.getMode() == defs::INCREMENTAL )
187 aStream << "address 0x" << std::setw ( 8 ) << aNode2.getAddress();
188 else
189 aStream << "address 0x" << std::setw ( 8 ) << aNode2.getAddress() << ", mask 0x" << std::setw ( 8 ) << aNode2.getMask();
190 aStream << "].";
191
192 aStream.flags(lInitialFlags);
193 aStream.fill(lInitialFillChar);
194 }
195
196
197 bool writeNodeOverlapReport(const std::string& aFilePath, const std::vector<std::pair<const Node*, const Node*> >& aNodes, const std::string& aHeader)
198 {
199 // 1. Create main contents of report
200 std::stringstream lReport;
201 lReport << std::hex << std::setfill ( '0' );
202
203 for (const auto& x: aNodes)
204 {
205 printNodeOverlapDescription(lReport, *x.first, *x.second);
206 lReport << std::endl;
207 }
208
209 // 2. Write report to file
210 const bool lNewlyCreatedFile = not boost::filesystem::is_regular_file( boost::filesystem::path(aFilePath) );
211 std::ofstream lReportFile ( aFilePath.c_str() );
212
213 if ( lReportFile.is_open() )
214 {
215 lReportFile << aHeader << std::endl;
216 lReportFile << "Written at " << boost::posix_time::microsec_clock::local_time() << "." << std::endl;
217 lReportFile << std::endl;
218 lReportFile << lReport.rdbuf();
219 lReportFile.close();
220
221 if ( lNewlyCreatedFile )
222 {
223 boost::filesystem::permissions( aFilePath , boost::filesystem::perms( 0666 ) );
224 }
225
226 return true;
227 }
228 else
229 return false;
230 }
231
232 }
233}
An abstract base class for defining the interface to the various IPbus clients as well as providing t...
std::weak_ptr< Node > mNode
A heirarchical node for navigating heirarchical firmwares.
Definition: Node.hpp:85
const uint32_t & getMask() const
Return the mask to be applied if this node is a sub-field, rather than an entire register.
Definition: Node.cpp:262
bool isChildOf(const Node &aParent) const
Returns whether this node is child of the function's argument.
Definition: Node.cpp:724
std::vector< const Node * > getLineage(const Node &aAncestor) const
Returns ancestry path of nodes from (but not including) aAncestor to this node.
Definition: Node.cpp:707
const defs::BlockReadWriteMode & getMode() const
Return whether the node represents a single register, a block of registers or a block-read/write port...
Definition: Node.cpp:268
std::string getPath() const
Return the full path to the current node.
Definition: Node.cpp:197
const uint32_t & getAddress() const
Return the register address with which this node is associated.
Definition: Node.cpp:256
const_iterator end() const
Definition: Node.cpp:176
const uint32_t & getSize() const
Return the maximum size available to a block read/write.
Definition: Node.cpp:274
const_iterator begin() const
Definition: Node.cpp:170
const uint32_t NOMASK
define what it means to have no mask
Definition: definitions.hpp:56
bool writeNodeOverlapReport(const std::string &aFilePath, const std::vector< std::pair< const Node *, const Node * > > &aNodes, const std::string &aHeader)
Definition: utilities.cpp:197
std::string getAddressDescription(const ClientInterface &, const uint32_t, const size_t &)
Generates a short string summarising which nodes match the specified address.
Definition: utilities.cpp:105
bool compareNodeAddr(const Node *aNodeL, const Node *aNodeR)
Definition: utilities.cpp:114
void printNodeOverlapDescription(std::ostream &aStream, const Node &aNode1, const Node &aNode2)
Definition: utilities.cpp:169
std::vector< std::pair< const Node *, const Node * > > getAddressOverlaps(const Node &aNode)
Definition: utilities.cpp:120