μHAL (v2.6.5)
Part of the IPbus software repository
ProtocolIPbus.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 
33 #include "uhal/ProtocolIPbus.hpp"
34 
35 
36 #include <stdint.h>
37 #include <ostream>
38 
39 #include <boost/date_time/posix_time/posix_time_types.hpp> // for seconds
40 #include <boost/shared_ptr.hpp> // for shared_ptr
41 #include <boost/thread/lock_guard.hpp> // for lock_guard
42 
43 #include "uhal/Buffers.hpp"
44 #include "uhal/ClientInterface.hpp"
45 #include "uhal/log/LogLevels.hpp"
48 #include "uhal/log/log.hpp"
49 #include "uhal/ValMem.hpp"
50 
51 
52 namespace uhal
53 {
54 
55  // --------------------------------------------------------------------------------------------------------------------------------------------------------------
56  template< uint8_t IPbus_minor >
57  IPbus< 1 , IPbus_minor >::IPbus ( const std::string& aId, const URI& aUri ) :
58  IPbusCore ( aId , aUri , boost::posix_time::seconds ( 1 ) )
59  // , mSendPadding ( 8 , implementCalculateHeader ( B_O_T , 0 , 0 ) ),
60  // mReplyPadding ( 8 , 0x00000000 )
61  {
62  }
63 
64 
65  template< uint8_t IPbus_minor >
67  {
68  }
69 
70  template< uint8_t IPbus_minor >
72  {
73  implementBOT(); //this is really just initializing the payload, rather than a true preamble
74  }
75 
76  template< uint8_t IPbus_minor >
78  {
79  return 1;
80  }
81 
82  template< uint8_t IPbus_minor >
84  {
85  uint32_t lWords ( aBuffers->sendCounter() >> 2 );
86  //IPbus 1.3 requires that there are 8 words of IPbus payload, excluding any non-payload preamble. In this version of the protocol, the preamble is really just initializing the payload, rather than a true preamble, so, if nothing else was sent, then we need 7 more words of padding.
87  int32_t lPaddingWords ( ( 7 + this->getPreambleSize() ) - lWords );
88 
89  if ( lPaddingWords > 0 )
90  {
91  // aBuffers->send ( ( uint8_t* ) ( & ( mSendPadding[0] ) ) , lPaddingWords<<2 );
92  // aBuffers->receive ( ( uint8_t* ) ( & ( mReplyPadding[0] ) ) , lPaddingWords<<2 );
93  for ( int32_t lWords = 0 ; lWords != lPaddingWords ; ++lWords )
94  {
95  log ( Debug() , "Adding padding word." );
96  // We do not need to check for space here as this condition is only met when the current filling buffer is severely underfull
97  aBuffers->send ( CalculateHeader ( B_O_T , 0 , 0 ) );
98  std::pair < ValHeader , _ValHeader_* > lReply ( CreateValHeader() );
99  lReply.second->IPbusHeaders.push_back ( 0 );
100  aBuffers->add ( lReply.first );
101  aBuffers->receive ( lReply.second->IPbusHeaders.back() );
102  }
103  }
104  }
105 
106  template< uint8_t IPbus_minor >
107  uint32_t IPbus< 1 , IPbus_minor >::CalculateHeader ( const eIPbusTransactionType& aType , const uint32_t& aWordCount , const uint32_t& aTransactionId , const uint8_t& aInfoCode )
108  {
109  uint8_t lType ( 0x00 );
110 
111  switch ( aType )
112  {
113  case B_O_T :
114  lType = 0xF8;
115  break;
116  case READ :
117  lType = 0x18;
118  break;
119  case WRITE :
120  lType = 0x20;
121  break;
122  case RMW_BITS :
123  lType = 0x28;
124  break;
125  case RMW_SUM :
126  lType = 0x30;
127  break;
128  case R_A_I :
129  lType = 0xF0;
130  break;
131  case NI_READ :
132  lType = 0x40;
133  break;
134  case NI_WRITE :
135  lType = 0x48;
136  break;
137  case CONFIG_SPACE_READ :
138  {
139  exception::ValidationError lExc;
140  log ( lExc , "Configuration space read undefined in IPbus version 1" );
141  throw lExc;
142  }
143  }
144 
145  return ( 0x10000000 | ( ( aTransactionId&0x7ff ) <<17 ) | ( ( aWordCount&0x1ff ) <<8 ) | lType | ( aInfoCode&0x7 ) );
146  }
147 
148 
149  template< uint8_t IPbus_minor >
150  uint32_t IPbus< 1 , IPbus_minor >::ExpectedHeader ( const eIPbusTransactionType& aType , const uint32_t& aWordCount , const uint32_t& aTransactionId, const uint8_t& aInfoCode )
151  {
152  return ( IPbus< 1 , IPbus_minor >::CalculateHeader ( aType , aWordCount , aTransactionId , aInfoCode | 0x4 ) );
153  }
154 
155  template< uint8_t IPbus_minor >
156  bool IPbus< 1 , IPbus_minor >::ExtractHeader ( const uint32_t& aHeader , eIPbusTransactionType& aType , uint32_t& aWordCount , uint32_t& aTransactionId , uint8_t& aInfoCode )
157  {
158  uint32_t lProtocolVersion ( ( aHeader >> 28 ) & 0xF );
159 
160  if ( lProtocolVersion != 1 )
161  {
162  log ( Error() , "Wrong Protocol Version! " , Integer ( lProtocolVersion ) , " != 1" );
163  return false;
164  }
165 
166  switch ( aHeader & 0xF8 )
167  {
168  case 0xF8 :
169  aType = B_O_T;
170  break;
171  case 0x18 :
172  aType = READ;
173  break;
174  case 0x20 :
175  aType = WRITE;
176  break;
177  case 0x28 :
178  aType = RMW_BITS;
179  break;
180  case 0x30 :
181  aType = RMW_SUM;
182  break;
183  case 0xF0 :
184  aType = R_A_I;
185  break;
186  case 0x40 :
187  aType = NI_READ;
188  break;
189  case 0x48 :
190  aType = NI_WRITE;
191  break;
192  default:
193  log ( Error() , "Unknown IPbus-header " , Integer ( uint8_t ( ( aHeader & 0xF8 ) ) , IntFmt<hex,fixed>() ) );
194  return false;
195  }
196 
197  aWordCount = ( aHeader >> 8 ) & 0x1ff;
198  aTransactionId = ( aHeader >> 17 ) & 0x7ff;
199  aInfoCode = aHeader & 0x3;
200  return true;
201  }
202 
203  template< uint8_t IPbus_minor >
204  uint32_t IPbus< 1 , IPbus_minor >::implementCalculateHeader ( const eIPbusTransactionType& aType , const uint32_t& aWordCount , const uint32_t& aTransactionId , const uint8_t& aInfoCode )
205  {
206  return IPbus< 1 , IPbus_minor >::CalculateHeader ( aType , aWordCount , aTransactionId , aInfoCode );
207  }
208 
209  template< uint8_t IPbus_minor >
210  bool IPbus< 1 , IPbus_minor >::implementExtractHeader ( const uint32_t& aHeader , eIPbusTransactionType& aType , uint32_t& aWordCount , uint32_t& aTransactionId , uint8_t& aInfoCode )
211  {
212  return IPbus< 1 , IPbus_minor >::ExtractHeader ( aHeader , aType , aWordCount , aTransactionId , aInfoCode );
213  }
214 
215  template< uint8_t IPbus_minor >
217  {
218  log ( Info() , ThisLocation() );
220  }
221 
222  template< uint8_t IPbus_minor >
223  void IPbus< 1 , IPbus_minor >::translateInfoCode(std::ostream& aStream, const uint8_t& aInfoCode) {
224  switch (aInfoCode) {
225  case 0:
226  aStream << "success";
227  break;
228  case 1:
229  aStream << "partial";
230  break;
231  case 2:
232  aStream << "failure";
233  break;
234  default:
235  aStream << "UNKNOWN";
236  }
237  }
238  // --------------------------------------------------------------------------------------------------------------------------------------------------------------
239 
240 
241 
242  // --------------------------------------------------------------------------------------------------------------------------------------------------------------
243  template< uint8_t IPbus_minor >
244  IPbus< 2 , IPbus_minor >::IPbus ( const std::string& aId, const URI& aUri ) :
245  IPbusCore ( aId , aUri , boost::posix_time::seconds ( 1 ) ),
246  mPacketCounter (
247 #ifndef DISABLE_PACKET_COUNTER_HACK
248  1
249 #else
250  0
251 #endif
252  )
253  {
254  }
255 
256 
257  template< uint8_t IPbus_minor >
259  {
260  }
261 
262  template< uint8_t IPbus_minor >
264  {
265  aBuffers->send ( 0x200000F0 | ( ( mPacketCounter&0xffff ) <<8 ) );
266 #ifndef DISABLE_PACKET_COUNTER_HACK
267  mPacketCounter++;
268 #endif
269  {
270  boost::lock_guard<boost::mutex> lLock ( mReceivePacketMutex );
271  mReceivePacketHeader.push_back ( 0x00000000 );
272  aBuffers->receive ( mReceivePacketHeader.back() );
273  }
274  }
275 
276 
277  template< uint8_t IPbus_minor >
279  {
280  return 1;
281  }
282 
283 
284  template< uint8_t IPbus_minor >
286  {
287  }
288 
289 
290 
291  template< uint8_t IPbus_minor >
293  uint8_t* aSendBufferEnd ,
294  std::deque< std::pair< uint8_t* , uint32_t > >::iterator aReplyStartIt ,
295  std::deque< std::pair< uint8_t* , uint32_t > >::iterator aReplyEndIt )
296  {
297  //log ( Debug() , ThisLocation() );
298  //log ( Notice() , "Memory location = " , Integer ( ( std::size_t ) ( aReplyStartIt->first ) , IntFmt<hex,fixed>() ), " Memory value = " , Integer ( * ( std::size_t* ) ( aReplyStartIt->first ) , IntFmt<hex,fixed>() ), " & size = " , Integer ( aReplyStartIt->second ) );
299  if ( * ( uint32_t* ) ( aSendBufferStart ) != * ( uint32_t* ) ( aReplyStartIt ->first ) )
300  {
301  uhal::exception::IPbus2PacketHeaderMismatch* lExc = new uhal::exception::IPbus2PacketHeaderMismatch();
302  log ( *lExc , "Returned Packet Header from URI " , Quote ( this->uri() ) , ", " , Integer ( * ( uint32_t* ) ( aReplyStartIt ->first ) , IntFmt<hex,fixed>() ) ,
303  " does not match that sent " , Integer ( * ( uint32_t* ) ( aSendBufferStart ) , IntFmt<hex,fixed>() ) );
304  return lExc;
305  }
306 
307  {
308  boost::lock_guard<boost::mutex> lLock ( mReceivePacketMutex );
309  mReceivePacketHeader.pop_front();
310  }
311 
312  // log ( Info() , "IPbus 2.0 has validated the packet header" );
313  return IPbusCore::validate ( ( aSendBufferStart+=4 ) , aSendBufferEnd , ( ++aReplyStartIt ) , aReplyEndIt );
314  }
315 
316 
317 
318 
319  template< uint8_t IPbus_minor >
320  uint32_t IPbus< 2 , IPbus_minor >::CalculateHeader ( const eIPbusTransactionType& aType , const uint32_t& aWordCount , const uint32_t& aTransactionId, const uint8_t& aInfoCode )
321  {
322  uint8_t lType ( 0x00 );
323 
324  switch ( aType )
325  {
326  case B_O_T :
327  {
328  exception::ValidationError lExc;
329  log ( lExc , "Byte-Order-Transaction undefined in IPbus version 2" );
330  throw lExc;
331  }
332  case READ :
333  lType = 0x00;
334  break;
335  case WRITE :
336  lType = 0x10;
337  break;
338  case NI_READ :
339  lType = 0x20;
340  break;
341  case NI_WRITE :
342  lType = 0x30;
343  break;
344  case RMW_BITS :
345  lType = 0x40;
346  break;
347  case RMW_SUM :
348  lType = 0x50;
349  break;
350  case CONFIG_SPACE_READ :
351  lType = 0x60;
352  break;
353  case R_A_I :
354  {
355  exception::ValidationError lExc;
356  log ( lExc , "Reserved address information transaction is undefined in IPbus version 2" );
357  throw lExc;
358  }
359  }
360 
361  return ( 0x20000000 | ( ( aTransactionId&0xfff ) <<16 ) | ( ( aWordCount&0xff ) <<8 ) | lType | ( aInfoCode&0xF ) );
362  }
363 
364 
365  template< uint8_t IPbus_minor >
366  uint32_t IPbus< 2 , IPbus_minor >::ExpectedHeader ( const eIPbusTransactionType& aType , const uint32_t& aWordCount , const uint32_t& aTransactionId, const uint8_t& aInfoCode )
367  {
368  return ( IPbus< 2 , IPbus_minor >::CalculateHeader ( aType , aWordCount , aTransactionId , aInfoCode ) );
369  }
370 
371 
372  template< uint8_t IPbus_minor >
373  bool IPbus< 2 , IPbus_minor >::ExtractHeader ( const uint32_t& aHeader , eIPbusTransactionType& aType , uint32_t& aWordCount , uint32_t& aTransactionId , uint8_t& aInfoCode )
374  {
375  uint32_t lProtocolVersion ( ( aHeader >> 28 ) & 0xF );
376 
377  if ( lProtocolVersion != 2 )
378  {
379  log ( Error() , "Wrong Protocol Version! " , Integer ( lProtocolVersion ) , " != 2" );
380  return false;
381  }
382 
383  switch ( aHeader & 0xF0 )
384  {
385  case 0x00 :
386  aType = READ;
387  break;
388  case 0x10 :
389  aType = WRITE;
390  break;
391  case 0x20 :
392  aType = NI_READ;
393  break;
394  case 0x30 :
395  aType = NI_WRITE;
396  break;
397  case 0x40 :
398  aType = RMW_BITS;
399  break;
400  case 0x50 :
401  aType = RMW_SUM;
402  break;
403  case 0x60 :
404  aType = CONFIG_SPACE_READ;
405  break;
406  default:
407  log ( Error() , "Unknown IPbus-header " , Integer ( uint8_t ( ( aHeader & 0xF0 ) >>4 ) , IntFmt<hex,fixed>() ) );
408  return false;
409  }
410 
411  aWordCount = ( aHeader >> 8 ) & 0xff;
412  aTransactionId = ( aHeader >> 16 ) & 0xfff;
413  aInfoCode = aHeader & 0xf;
414  return true;
415  }
416 
417  template< uint8_t IPbus_minor >
418  uint32_t IPbus< 2 , IPbus_minor >::implementCalculateHeader ( const eIPbusTransactionType& aType , const uint32_t& aWordCount , const uint32_t& aTransactionId , const uint8_t& aInfoCode )
419  {
420  return IPbus< 2 , IPbus_minor >::CalculateHeader ( aType , aWordCount , aTransactionId , aInfoCode );
421  }
422 
423  template< uint8_t IPbus_minor >
424  bool IPbus< 2 , IPbus_minor >::implementExtractHeader ( const uint32_t& aHeader , eIPbusTransactionType& aType , uint32_t& aWordCount , uint32_t& aTransactionId , uint8_t& aInfoCode )
425  {
426  return IPbus< 2 , IPbus_minor >::ExtractHeader ( aHeader , aType , aWordCount , aTransactionId , aInfoCode );
427  }
428 
429  template< uint8_t IPbus_minor >
431  {
432  log ( Info() , ThisLocation() );
433 #ifndef DISABLE_PACKET_COUNTER_HACK
434  mPacketCounter = 1;
435 #else
436  mPacketCounter = 0;
437 #endif
438  mReceivePacketHeader.clear();
440  }
441 
442  template< uint8_t IPbus_minor >
443  void IPbus< 2 , IPbus_minor >::translateInfoCode(std::ostream& aStream, const uint8_t& aInfoCode)
444  {
445  switch (aInfoCode) {
446  case 0:
447  aStream << "success";
448  break;
449  case 1:
450  aStream << "bad header";
451  break;
452  case 4:
453  aStream << "bus error on read";
454  break;
455  case 5:
456  aStream << "bus error on write";
457  break;
458  case 6:
459  aStream << "bus timeout on read";
460  break;
461  case 7:
462  aStream << "bus timeout on write";
463  break;
464  case 0xf:
465  aStream << "outbound request";
466  break;
467  default:
468  aStream << "UNKNOWN";
469  }
470  }
471 
472  // --------------------------------------------------------------------------------------------------------------------------------------------------------------
473 
474 
475  template class IPbus<1, 3>;
476  template class IPbus<2, 0>;
477 }
478 
479 
A class which provides the version-specific functionality for IPbus.
eIPbusTransactionType
Enumerated type to define the IPbus transaction type.
virtual void dispatchExceptionHandler()
Function which is called when an exception is thrown.
An abstract base exception class providing an interface to a throw/ThrowAsDerivedType mechanism which...
Definition: exception.hpp:89
ErrorLevel Error
Definition: LogLevels.cpp:61
virtual exception::exception * validate(uint8_t *aSendBufferStart, uint8_t *aSendBufferEnd, std::deque< std::pair< uint8_t *, uint32_t > >::iterator aReplyStartIt, std::deque< std::pair< uint8_t *, uint32_t > >::iterator aReplyEndIt)
Function which the transport protocol calls when the IPbus reply is received to check that the header...
Empty struct which acts as a dummy variable for passing the formatting information around...
_Quote< T > Quote(const T &aT)
A class providing the core IPbus packing functionality.
#define ThisLocation()
std::string uri
Definition: test_single.cpp:89
DebugLevel Debug
Definition: LogLevels.cpp:133
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...
Struct to store a URI when parsed by boost spirit.
Definition: URI.hpp:49