μHAL (v2.6.5)
Part of the IPbus software repository
DummyHardware.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 
34 
35 
36 #include <deque>
37 #include <vector>
38 
39 #include <arpa/inet.h>
40 
41 #include <boost/chrono/chrono_io.hpp>
42 #include <boost/thread/thread.hpp>
43 
44 #include "uhal/log/LogLevels.hpp"
46 #include "uhal/log/log.hpp"
47 #include "uhal/ProtocolIPbus.hpp"
48 
49 
50 namespace uhal
51 {
52  namespace tests
53  {
54 
55 
56  template< uint8_t IPbus_major , uint8_t IPbus_minor >
57  DummyHardware<IPbus_major, IPbus_minor>::DummyHardware ( const uint32_t& aReplyDelay, const bool& aBigEndianHack ) :
58  DummyHardwareInterface( boost::chrono::seconds(aReplyDelay) ),
59  HostToTargetInspector< IPbus_major , IPbus_minor >(),
60  mMemory (),
61  mConfigurationSpace(),
62  mReceive ( BUFFER_SIZE , 0x00000000 ),
63  mReply ( BUFFER_SIZE , 0x00000000 ),
64  mReplyHistory ( REPLY_HISTORY_DEPTH , std::make_pair ( 0 , mReply ) ),
65  mLastPacketHeader ( 0x200000f0 ),
66  mTrafficHistory ( 16, 0x00 ),
67  mReceivedControlPacketHeaderHistory ( 4 , 0x00000000 ),
68  mSentControlPacketHeaderHistory ( 4 , 0x00000000 ),
69  mBigEndianHack ( aBigEndianHack )
70  {
71  for (size_t i = 0; i < 10; i++)
72  mConfigurationSpace.push_back( (uint16_t(getpid()) << 16) | i );
73  }
74 
75  template< uint8_t IPbus_major , uint8_t IPbus_minor >
77  {
78  }
79 
80 
81  template< uint8_t IPbus_major , uint8_t IPbus_minor >
83  {
84  // std::cout << aByteCount << " bytes received" << std::endl;
85  if ( IPbus_major == 2 )
86  {
87  bool is_status_request = ( *mReceive.begin() == 0xF1000020 );
88  bool is_resend_request = ( ( *mReceive.begin() & 0xFF0000FF ) == 0xF2000020 );
89 
90  if ( mBigEndianHack || is_status_request || is_resend_request )
91  {
92  for ( std::vector<uint32_t>::iterator lIt ( mReceive.begin() ) ; lIt != mReceive.begin() + ( aByteCount>>2 ) ; ++lIt )
93  {
94  *lIt = ntohl ( *lIt );
95  }
96  }
97  }
98 
99  std::vector<uint32_t>::const_iterator lBegin, lEnd;
100 
101  //
102  //-----------------------------------------------------------------------------------------------------------------------------------------------------------------
103  if ( LoggingIncludes ( Debug() ) )
104  {
105  log ( Debug() , "\n=============================================== RECEIVED ===============================================" );
107  lBegin = mReceive.begin();
108  lEnd = mReceive.begin() + ( aByteCount>>2 );
109  lHostToTargetDebugger.analyze ( lBegin , lEnd );
110  }
111 
112  //-----------------------------------------------------------------------------------------------------------------------------------------------------------------
113  //
114  lBegin = mReceive.begin();
115  lEnd = mReceive.begin() + ( aByteCount>>2 );
116 
117  if ( ! base_type::analyze ( lBegin , lEnd ) ) // Cope with receiving bad headers
118  {
119  log ( Error() , "Found a bad header" );
120  mReply.push_back ( IPbus< IPbus_major , IPbus_minor >::ExpectedHeader ( base_type::mType , base_type::mWordCounter , base_type::mTransactionId , ( IPbus_major==1 ? 2 : 1 ) ) );
121  }
122 
123  if ( ( base_type::mPacketType == 0 ) && ( mReply.size() != 0 ) )
124  {
125  mReplyHistory.push_back ( std::make_pair ( base_type::mPacketCounter , mReply ) );
126  mReplyHistory.pop_front();
127  }
128 
129  if ( mReplyDelay > boost::chrono::microseconds(0) )
130  {
131  log ( Info() , "Sleeping for " , mReplyDelay );
132  boost::this_thread::sleep_for( mReplyDelay );
133  mReplyDelay = boost::chrono::microseconds(0);
134  log ( Info() , "Now replying " );
135  }
136 
137  //
138  //-----------------------------------------------------------------------------------------------------------------------------------------------------------------
139  if ( LoggingIncludes ( Debug() ) && ! mReply.empty() )
140  {
141  log ( Debug() , "\n=============================================== SENDING ===============================================" );
143  lBegin = mReply.begin();
144  lEnd = mReply.end();
145  lTargetToHostDebugger.analyze ( lBegin , lEnd );
146  }
147 
148  //-----------------------------------------------------------------------------------------------------------------------------------------------------------------
149  //
150 
151  if ( IPbus_major == 2 )
152  {
153  if ( mBigEndianHack || base_type::mPacketType == 1 )
154  {
155  for ( std::vector<uint32_t>::iterator lIt ( mReply.begin() ) ; lIt != mReply.end() ; ++lIt )
156  {
157  *lIt = htonl ( *lIt );
158  }
159  }
160  }
161  }
162 
163 
164  template< uint8_t IPbus_major , uint8_t IPbus_minor >
165  void DummyHardware<IPbus_major, IPbus_minor>::SetEndpoint( const uint32_t& aAddress , const uint32_t& aValue )
166  {
167  if( ! mMemory.size() )
168  mMemory.resize( ADDRESSMASK + 1 );
169  mMemory.at ( aAddress & ADDRESSMASK ) = aValue;
170  }
171 
172 
173  template< uint8_t IPbus_major , uint8_t IPbus_minor >
174  uint32_t DummyHardware<IPbus_major, IPbus_minor>::GetEndpoint( const uint32_t& aAddress )
175  {
176  if( ! mMemory.size() )
177  mMemory.resize( ADDRESSMASK + 1 );
178  return mMemory.at ( aAddress & ADDRESSMASK );
179  }
180 
181 
182  template< uint8_t IPbus_major , uint8_t IPbus_minor >
184  {
185  mReceivedControlPacketHeaderHistory.push_back ( base_type::mPacketHeader );
186  mReceivedControlPacketHeaderHistory.pop_front();
187  uint32_t lExpected ( IPbus< IPbus_major , IPbus_minor >::ExpectedHeader ( base_type::mType , 0 , base_type::mTransactionId ) );
188  mReply.push_back ( lExpected );
189  mSentControlPacketHeaderHistory.push_back ( lExpected );
190  mSentControlPacketHeaderHistory.pop_front();
191  }
192 
193 
194  template< uint8_t IPbus_major , uint8_t IPbus_minor >
195  void DummyHardware<IPbus_major, IPbus_minor>::ni_read ( const uint32_t& aAddress )
196  {
197  mReceivedControlPacketHeaderHistory.push_back ( base_type::mPacketHeader );
198  mReceivedControlPacketHeaderHistory.pop_front();
199  uint32_t lAddress ( aAddress );
200  uint32_t lExpected ( IPbus< IPbus_major , IPbus_minor >::ExpectedHeader ( base_type::mType , base_type::mWordCounter , base_type::mTransactionId ) );
201  mReply.push_back ( lExpected );
202  mSentControlPacketHeaderHistory.push_back ( lExpected );
203  mSentControlPacketHeaderHistory.pop_front();
204 
205  for ( ; base_type::mWordCounter!=0 ; --base_type::mWordCounter )
206  {
207  mReply.push_back ( GetEndpoint( lAddress ) );
208  }
209  }
210 
211 
212  template< uint8_t IPbus_major , uint8_t IPbus_minor >
213  void DummyHardware<IPbus_major, IPbus_minor>::read ( const uint32_t& aAddress )
214  {
215  mReceivedControlPacketHeaderHistory.push_back ( base_type::mPacketHeader );
216  mReceivedControlPacketHeaderHistory.pop_front();
217  uint32_t lAddress ( aAddress );
218  uint32_t lExpected ( IPbus< IPbus_major , IPbus_minor >::ExpectedHeader ( base_type::mType , base_type::mWordCounter , base_type::mTransactionId ) );
219  mReply.push_back ( lExpected );
220  mSentControlPacketHeaderHistory.push_back ( lExpected );
221  mSentControlPacketHeaderHistory.pop_front();
222 
223  for ( ; base_type::mWordCounter!=0 ; --base_type::mWordCounter )
224  {
225  mReply.push_back ( GetEndpoint( lAddress++ ) );
226  }
227  }
228 
229 
230  template< uint8_t IPbus_major , uint8_t IPbus_minor >
232  {
233  mReceivedControlPacketHeaderHistory.push_back ( base_type::mPacketHeader );
234  mReceivedControlPacketHeaderHistory.pop_front();
235  uint32_t lAddress ( aAddress );
236  uint32_t lExpected ( IPbus< IPbus_major , IPbus_minor >::ExpectedHeader ( base_type::mType , base_type::mWordCounter , base_type::mTransactionId ) );
237  mReply.push_back ( lExpected );
238  mSentControlPacketHeaderHistory.push_back ( lExpected );
239  mSentControlPacketHeaderHistory.pop_front();
240 
241  for ( ; base_type::mWordCounter!=0 ; --base_type::mWordCounter )
242  {
243  mReply.push_back ( mConfigurationSpace.at( lAddress++ ) );
244  }
245  }
246 
247 
248  template< uint8_t IPbus_major , uint8_t IPbus_minor >
249  void DummyHardware<IPbus_major, IPbus_minor>::ni_write ( const uint32_t& aAddress , std::vector<uint32_t>::const_iterator& aIt , const std::vector<uint32_t>::const_iterator& aEnd )
250  {
251  mReceivedControlPacketHeaderHistory.push_back ( base_type::mPacketHeader );
252  mReceivedControlPacketHeaderHistory.pop_front();
253  uint32_t lAddress ( aAddress );
254 
255  while ( aIt != aEnd )
256  {
257  SetEndpoint ( lAddress , *aIt++ );
258  }
259 
260  uint32_t lExpected;
261 
262  if ( IPbus_major == 1 )
263  {
264  lExpected = IPbus< IPbus_major , IPbus_minor >::ExpectedHeader ( base_type::mType , 0 , base_type::mTransactionId );
265  }
266  else
267  {
268  lExpected = IPbus< IPbus_major , IPbus_minor >::ExpectedHeader ( base_type::mType , base_type::mWordCounter , base_type::mTransactionId );
269  }
270 
271  mReply.push_back ( lExpected );
272  mSentControlPacketHeaderHistory.push_back ( lExpected );
273  mSentControlPacketHeaderHistory.pop_front();
274  }
275 
276 
277  template< uint8_t IPbus_major , uint8_t IPbus_minor >
278  void DummyHardware<IPbus_major, IPbus_minor>::write ( const uint32_t& aAddress , std::vector<uint32_t>::const_iterator& aIt , const std::vector<uint32_t>::const_iterator& aEnd )
279  {
280  mReceivedControlPacketHeaderHistory.push_back ( base_type::mPacketHeader );
281  mReceivedControlPacketHeaderHistory.pop_front();
282  uint32_t lAddress ( aAddress );
283 
284  while ( aIt != aEnd )
285  {
286  SetEndpoint ( lAddress++ , *aIt++ );
287  }
288 
289  uint32_t lExpected;
290 
291  if ( IPbus_major == 1 )
292  {
293  lExpected = IPbus< IPbus_major , IPbus_minor >::ExpectedHeader ( base_type::mType , 0 , base_type::mTransactionId );
294  }
295  else
296  {
297  lExpected = IPbus< IPbus_major , IPbus_minor >::ExpectedHeader ( base_type::mType , base_type::mWordCounter , base_type::mTransactionId );
298  }
299 
300  mReply.push_back ( lExpected );
301  mSentControlPacketHeaderHistory.push_back ( lExpected );
302  mSentControlPacketHeaderHistory.pop_front();
303  }
304 
305 
306  template< uint8_t IPbus_major , uint8_t IPbus_minor >
307  void DummyHardware<IPbus_major, IPbus_minor>::rmw_sum ( const uint32_t& aAddress , const uint32_t& aAddend )
308  {
309  mReceivedControlPacketHeaderHistory.push_back ( base_type::mPacketHeader );
310  mReceivedControlPacketHeaderHistory.pop_front();
311  uint32_t lAddress ( aAddress );
312  uint32_t lExpected ( IPbus< IPbus_major , IPbus_minor >::ExpectedHeader ( base_type::mType , 1 , base_type::mTransactionId ) );
313  mReply.push_back ( lExpected );
314  mSentControlPacketHeaderHistory.push_back ( lExpected );
315  mSentControlPacketHeaderHistory.pop_front();
316 
317  if ( IPbus_major == 1 )
318  {
319  //IPbus 1.x returns modified value
320  uint32_t lValue( GetEndpoint( lAddress ) );
321  lValue += aAddend;
322  SetEndpoint( lAddress , lValue );
323  mReply.push_back ( lValue );
324  }
325  else
326  {
327  //IPbus 2.x returns pre-modified value
328  uint32_t lValue( GetEndpoint( lAddress ) );
329  mReply.push_back ( lValue );
330  lValue += aAddend;
331  SetEndpoint( lAddress , lValue );
332  }
333  }
334 
335 
336  template< uint8_t IPbus_major , uint8_t IPbus_minor >
337  void DummyHardware<IPbus_major, IPbus_minor>::rmw_bits ( const uint32_t& aAddress , const uint32_t& aAndTerm , const uint32_t& aOrTerm )
338  {
339  mReceivedControlPacketHeaderHistory.push_back ( base_type::mPacketHeader );
340  mReceivedControlPacketHeaderHistory.pop_front();
341  uint32_t lAddress ( aAddress );
342  uint32_t lExpected ( IPbus< IPbus_major , IPbus_minor >::ExpectedHeader ( base_type::mType , 1 , base_type::mTransactionId ) );
343  mReply.push_back ( lExpected );
344  mSentControlPacketHeaderHistory.push_back ( lExpected );
345  mSentControlPacketHeaderHistory.pop_front();
346 
347  if ( IPbus_major == 1 )
348  {
349  //IPbus 1.x returns modified value
350  uint32_t lValue( GetEndpoint( lAddress ) );
351  lValue &= aAndTerm;
352  lValue |= aOrTerm;
353  SetEndpoint( lAddress , lValue );
354  mReply.push_back ( lValue );
355  }
356  else
357  {
358  //IPbus 2.x returns pre-modified value
359  uint32_t lValue( GetEndpoint( lAddress ) );
360  mReply.push_back ( lValue );
361  lValue &= aAndTerm;
362  lValue |= aOrTerm;
363  SetEndpoint( lAddress , lValue );
364  }
365  }
366 
367 
368  template< uint8_t IPbus_major , uint8_t IPbus_minor >
370  {
371  log ( Error() , Integer ( base_type::mHeader, IntFmt<hex,fixed>() ) , " is an unknown IPbus transaction header. Returning error code." );
372  mReceivedControlPacketHeaderHistory.push_back ( base_type::mPacketHeader );
373  mReceivedControlPacketHeaderHistory.pop_front();
374  uint32_t lExpected ( IPbus< IPbus_major , IPbus_minor >::ExpectedHeader ( base_type::mType , 0 , base_type::mTransactionId , 1 ) );
375  mReply.push_back ( lExpected );
376  mSentControlPacketHeaderHistory.push_back ( lExpected );
377  mSentControlPacketHeaderHistory.pop_front();
378  }
379 
380 
381  template< uint8_t IPbus_major , uint8_t IPbus_minor >
383  {
384  // if ( LoggingIncludes ( Debug() ) )
385  // {
386  // base_type::control_packet_header();
387  // }
388  if ( base_type::mPacketCounter != 0 )
389  {
390  uint16_t lTemp ( ( ( mLastPacketHeader>>8 ) &0x0000FFFF ) + 1 );
391 
392  if ( lTemp == 0 )
393  {
394  lTemp = 1;
395  }
396 
397  if ( base_type::mPacketCounter != lTemp )
398  {
399  mTrafficHistory.push_back ( 5 );
400  mTrafficHistory.pop_front();
401  log(Notice(), "Dummy hardware received control packet with ID ", Integer(base_type::mPacketCounter), ", but expected ID ", Integer(lTemp));
402  return false;
403  }
404 
405  mLastPacketHeader = base_type::mPacketHeader;
406  }
407 
408  mReply.push_back ( base_type::mPacketHeader );
409  mTrafficHistory.push_back ( 2 );
410  mTrafficHistory.pop_front();
411  return true;
412  }
413 
414 
415  template< uint8_t IPbus_major , uint8_t IPbus_minor >
417  {
418  // if ( LoggingIncludes ( Debug() ) )
419  // {
420  // base_type::status_packet_header();
421  // }
422  mReply.push_back ( base_type::mPacketHeader );
423  mReply.push_back ( BUFFER_SIZE * sizeof ( uint32_t ) );
424  mReply.push_back ( REPLY_HISTORY_DEPTH );
425  uint16_t lTemp ( ( ( mLastPacketHeader>>8 ) &0x0000FFFF ) + 1 );
426 
427  if ( lTemp == 0 )
428  {
429  lTemp = 1;
430  }
431 
432  mReply.push_back ( ( mLastPacketHeader & 0xFF0000FF ) | ( ( lTemp <<8 ) & 0x00FFFF00 ) );
433  std::deque< uint8_t >::const_iterator lIt ( mTrafficHistory.begin() );
434 
435  for ( uint32_t i = 0; i != 4 ; ++i )
436  {
437  uint32_t lTemp ( 0x00000000 );
438 
439  for ( uint32_t j = 0; j != 4 ; ++j )
440  {
441  lTemp <<= 8;
442  lTemp |= ( uint32_t ) ( *lIt );
443  lIt++;
444  }
445 
446  mReply.push_back ( lTemp );;
447  }
448 
449  for ( std::deque< uint32_t >::const_iterator i = mReceivedControlPacketHeaderHistory.begin(); i != mReceivedControlPacketHeaderHistory.end() ; ++i )
450  {
451  mReply.push_back ( *i );
452  }
453 
454  for ( std::deque< uint32_t >::const_iterator i = mSentControlPacketHeaderHistory.begin(); i != mSentControlPacketHeaderHistory.end() ; ++i )
455  {
456  mReply.push_back ( *i );
457  }
458 
459  mTrafficHistory.push_back ( 3 );
460  mTrafficHistory.pop_front();
461  }
462 
463 
464  template< uint8_t IPbus_major , uint8_t IPbus_minor >
466  {
467  // if ( LoggingIncludes ( Debug() ) )
468  // {
469  // base_type::resend_packet_header();
470  // }
471  std::deque< std::pair< uint32_t , std::vector< uint32_t > > >::reverse_iterator lIt = mReplyHistory.rbegin();
472 
473  for ( ; lIt!=mReplyHistory.rend() ; ++lIt )
474  {
475  if ( lIt->first == base_type::mPacketCounter )
476  {
477  mReply = lIt->second;
478  break;
479  }
480  }
481 
482  mTrafficHistory.push_back ( 4 );
483  mTrafficHistory.pop_front();
484  }
485 
486 
487  template< uint8_t IPbus_major , uint8_t IPbus_minor >
489  {
490  mTrafficHistory.push_back ( 5 );
491  mTrafficHistory.pop_front();
492  }
493 
494 
495  template class DummyHardware<1, 3>;
496  template class DummyHardware<2, 0>;
497  }
498 }
499 
500 
501 
bool analyze(std::vector< uint32_t >::const_iterator &aIt, const std::vector< uint32_t >::const_iterator &aEnd, const bool &aContinueOnError=true)
Analyse an IPbus packet held as a vector of uint32_t&#39;s.
NoticeLevel Notice
Definition: LogLevels.cpp:96
A class which provides the version-specific functionality for IPbus.
Helper class to decode IPbus packets as passed from the Client to the Target.
static const uint32_t BUFFER_SIZE
Size of the receive and reply buffers.
std::vector< uint32_t >::const_iterator j
Common abstract base class for IPbus 1.3 and 2.0 dummy hardware.
Helper class to decode IPbus packets as passed from the Target to the Client.
ErrorLevel Error
Definition: LogLevels.cpp:61
Empty struct which acts as a dummy variable for passing the formatting information around...
static const uint32_t REPLY_HISTORY_DEPTH
The size of the reply history for IPbus 2.0.
bool analyze(std::vector< uint32_t >::const_iterator &aIt, const std::vector< uint32_t >::const_iterator &aEnd, const bool &aContinueOnError=true)
Analyse an IPbus packet held as a vector of uint32_t&#39;s.
DebugLevel Debug
Definition: LogLevels.cpp:133
Abstract base class to emulate IPbus hardware.
static const uint32_t ADDRESSMASK
The mask for the address space (size of the address space in one larger than this) ...
DummyHardware(const uint32_t &aReplyDelay, const bool &aBigEndianHack)
Constructor.
InfoLevel Info
Definition: LogLevels.cpp:114
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
c write(addr, xx[0])