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