μHAL (v2.7.9)
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 <ostream>
37 #include <stdint.h>
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"
47 #include "uhal/log/log.hpp"
48 #include "uhal/ValMem.hpp"
49 
50 
51 namespace uhal
52 {
53 
54  // --------------------------------------------------------------------------------------------------------------------------------------------------------------
55  template< uint8_t IPbus_minor >
56  IPbus< 1 , IPbus_minor >::IPbus ( const std::string& aId, const URI& aUri ) :
57  IPbusCore ( aId , aUri , boost::posix_time::seconds ( 1 ) )
58  {
59  }
60 
61 
62  template< uint8_t IPbus_minor >
64  {
65  }
66 
67 
68  template< uint8_t IPbus_minor >
70  {
71  implementBOT(); //this is really just initializing the payload, rather than a true preamble
72  }
73 
74 
75  template< uint8_t IPbus_minor >
77  {
78  return 1;
79  }
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 
107  template< uint8_t IPbus_minor >
108  uint32_t IPbus< 1 , IPbus_minor >::CalculateHeader ( const IPbusTransactionType& aType , const uint32_t& aWordCount , const uint32_t& aTransactionId , const uint8_t& aInfoCode )
109  {
110  uint8_t lType ( 0x00 );
111 
112  switch ( aType )
113  {
114  case B_O_T :
115  lType = 0xF8;
116  break;
117  case READ :
118  lType = 0x18;
119  break;
120  case WRITE :
121  lType = 0x20;
122  break;
123  case RMW_BITS :
124  lType = 0x28;
125  break;
126  case RMW_SUM :
127  lType = 0x30;
128  break;
129  case R_A_I :
130  lType = 0xF0;
131  break;
132  case NI_READ :
133  lType = 0x40;
134  break;
135  case NI_WRITE :
136  lType = 0x48;
137  break;
138  case CONFIG_SPACE_READ :
139  {
140  exception::ValidationError lExc;
141  log ( lExc , "Configuration space read undefined in IPbus version 1" );
142  throw lExc;
143  }
144  }
145 
146  return ( 0x10000000 | ( ( aTransactionId&0x7ff ) <<17 ) | ( ( aWordCount&0x1ff ) <<8 ) | lType | ( aInfoCode&0x7 ) );
147  }
148 
149 
150  template< uint8_t IPbus_minor >
151  uint32_t IPbus< 1 , IPbus_minor >::ExpectedHeader ( const IPbusTransactionType& aType , const uint32_t& aWordCount , const uint32_t& aTransactionId, const uint8_t& aInfoCode )
152  {
153  return ( IPbus< 1 , IPbus_minor >::CalculateHeader ( aType , aWordCount , aTransactionId , aInfoCode | 0x4 ) );
154  }
155 
156 
157  template< uint8_t IPbus_minor >
158  bool IPbus< 1 , IPbus_minor >::ExtractHeader ( const uint32_t& aHeader , IPbusTransactionType& aType , uint32_t& aWordCount , uint32_t& aTransactionId , uint8_t& aInfoCode )
159  {
160  uint32_t lProtocolVersion ( ( aHeader >> 28 ) & 0xF );
161 
162  if ( lProtocolVersion != 1 )
163  {
164  log ( Error() , "Wrong Protocol Version! " , Integer ( lProtocolVersion ) , " != 1" );
165  return false;
166  }
167 
168  switch ( aHeader & 0xF8 )
169  {
170  case 0xF8 :
171  aType = B_O_T;
172  break;
173  case 0x18 :
174  aType = READ;
175  break;
176  case 0x20 :
177  aType = WRITE;
178  break;
179  case 0x28 :
180  aType = RMW_BITS;
181  break;
182  case 0x30 :
183  aType = RMW_SUM;
184  break;
185  case 0xF0 :
186  aType = R_A_I;
187  break;
188  case 0x40 :
189  aType = NI_READ;
190  break;
191  case 0x48 :
192  aType = NI_WRITE;
193  break;
194  default:
195  log ( Error() , "Unknown IPbus-header " , Integer ( uint8_t ( ( aHeader & 0xF8 ) ) , IntFmt<hex,fixed>() ) );
196  return false;
197  }
198 
199  aWordCount = ( aHeader >> 8 ) & 0x1ff;
200  aTransactionId = ( aHeader >> 17 ) & 0x7ff;
201  aInfoCode = aHeader & 0x3;
202  return true;
203  }
204 
205 
206  template< uint8_t IPbus_minor >
207  uint32_t IPbus< 1 , IPbus_minor >::implementCalculateHeader ( const IPbusTransactionType& aType , const uint32_t& aWordCount , const uint32_t& aTransactionId , const uint8_t& aInfoCode )
208  {
209  return IPbus< 1 , IPbus_minor >::CalculateHeader ( aType , aWordCount , aTransactionId , aInfoCode );
210  }
211 
212 
213  template< uint8_t IPbus_minor >
214  bool IPbus< 1 , IPbus_minor >::implementExtractHeader ( const uint32_t& aHeader , IPbusTransactionType& aType , uint32_t& aWordCount , uint32_t& aTransactionId , uint8_t& aInfoCode )
215  {
216  return IPbus< 1 , IPbus_minor >::ExtractHeader ( aHeader , aType , aWordCount , aTransactionId , aInfoCode );
217  }
218 
219 
220  template< uint8_t IPbus_minor >
222  {
224  }
225 
226 
227  template< uint8_t IPbus_minor >
228  void IPbus< 1 , IPbus_minor >::translateInfoCode(std::ostream& aStream, const uint8_t& aInfoCode) {
229  switch (aInfoCode) {
230  case 0:
231  aStream << "success";
232  break;
233  case 1:
234  aStream << "partial";
235  break;
236  case 2:
237  aStream << "failure";
238  break;
239  default:
240  aStream << "UNKNOWN";
241  }
242  }
243  // --------------------------------------------------------------------------------------------------------------------------------------------------------------
244 
245 
246 
247  // --------------------------------------------------------------------------------------------------------------------------------------------------------------
248  template< uint8_t IPbus_minor >
249  IPbus< 2 , IPbus_minor >::IPbus ( const std::string& aId, const URI& aUri ) :
250  IPbusCore ( aId , aUri , boost::posix_time::seconds ( 1 ) ),
251  mPacketCounter (0)
252  {
253  }
254 
255 
256  template< uint8_t IPbus_minor >
258  {
259  }
260 
261  template< uint8_t IPbus_minor >
263  {
264  aBuffers->send ( 0x200000F0 | ( ( mPacketCounter&0xffff ) <<8 ) );
265  {
266  boost::lock_guard<boost::mutex> lLock ( mReceivePacketMutex );
267  mReceivePacketHeader.push_back ( 0x00000000 );
268  aBuffers->receive ( mReceivePacketHeader.back() );
269  }
270  }
271 
272 
273  template< uint8_t IPbus_minor >
275  {
276  return 1;
277  }
278 
279 
280  template< uint8_t IPbus_minor >
282  {
283  }
284 
285 
286 
287  template< uint8_t IPbus_minor >
289  uint8_t* aSendBufferEnd ,
290  std::deque< std::pair< uint8_t* , uint32_t > >::iterator aReplyStartIt ,
291  std::deque< std::pair< uint8_t* , uint32_t > >::iterator aReplyEndIt )
292  {
293  if ( * ( uint32_t* ) ( aSendBufferStart ) != * ( uint32_t* ) ( aReplyStartIt ->first ) )
294  {
295  uhal::exception::IPbus2PacketHeaderMismatch* lExc = new uhal::exception::IPbus2PacketHeaderMismatch();
296  log ( *lExc , "Returned Packet Header from URI " , Quote ( this->uri() ) , ", " , Integer ( * ( uint32_t* ) ( aReplyStartIt ->first ) , IntFmt<hex,fixed>() ) ,
297  " does not match that sent " , Integer ( * ( uint32_t* ) ( aSendBufferStart ) , IntFmt<hex,fixed>() ) );
298  return lExc;
299  }
300 
301  {
302  boost::lock_guard<boost::mutex> lLock ( mReceivePacketMutex );
303  mReceivePacketHeader.pop_front();
304  }
305 
306  return IPbusCore::validate ( ( aSendBufferStart+=4 ) , aSendBufferEnd , ( ++aReplyStartIt ) , aReplyEndIt );
307  }
308 
309 
310 
311 
312  template< uint8_t IPbus_minor >
313  uint32_t IPbus< 2 , IPbus_minor >::CalculateHeader ( const IPbusTransactionType& aType , const uint32_t& aWordCount , const uint32_t& aTransactionId, const uint8_t& aInfoCode )
314  {
315  uint8_t lType ( 0x00 );
316 
317  switch ( aType )
318  {
319  case B_O_T :
320  {
321  exception::ValidationError lExc;
322  log ( lExc , "Byte-Order-Transaction undefined in IPbus version 2" );
323  throw lExc;
324  }
325  case READ :
326  lType = 0x00;
327  break;
328  case WRITE :
329  lType = 0x10;
330  break;
331  case NI_READ :
332  lType = 0x20;
333  break;
334  case NI_WRITE :
335  lType = 0x30;
336  break;
337  case RMW_BITS :
338  lType = 0x40;
339  break;
340  case RMW_SUM :
341  lType = 0x50;
342  break;
343  case CONFIG_SPACE_READ :
344  lType = 0x60;
345  break;
346  case R_A_I :
347  {
348  exception::ValidationError lExc;
349  log ( lExc , "Reserved address information transaction is undefined in IPbus version 2" );
350  throw lExc;
351  }
352  }
353 
354  return ( 0x20000000 | ( ( aTransactionId&0xfff ) <<16 ) | ( ( aWordCount&0xff ) <<8 ) | lType | ( aInfoCode&0xF ) );
355  }
356 
357 
358  template< uint8_t IPbus_minor >
359  uint32_t IPbus< 2 , IPbus_minor >::ExpectedHeader ( const IPbusTransactionType& aType , const uint32_t& aWordCount , const uint32_t& aTransactionId, const uint8_t& aInfoCode )
360  {
361  return ( IPbus< 2 , IPbus_minor >::CalculateHeader ( aType , aWordCount , aTransactionId , aInfoCode ) );
362  }
363 
364 
365  template< uint8_t IPbus_minor >
366  bool IPbus< 2 , IPbus_minor >::ExtractHeader ( const uint32_t& aHeader , IPbusTransactionType& aType , uint32_t& aWordCount , uint32_t& aTransactionId , uint8_t& aInfoCode )
367  {
368  uint32_t lProtocolVersion ( ( aHeader >> 28 ) & 0xF );
369 
370  if ( lProtocolVersion != 2 )
371  {
372  log ( Error() , "Wrong Protocol Version! " , Integer ( lProtocolVersion ) , " != 2" );
373  return false;
374  }
375 
376  switch ( aHeader & 0xF0 )
377  {
378  case 0x00 :
379  aType = READ;
380  break;
381  case 0x10 :
382  aType = WRITE;
383  break;
384  case 0x20 :
385  aType = NI_READ;
386  break;
387  case 0x30 :
388  aType = NI_WRITE;
389  break;
390  case 0x40 :
391  aType = RMW_BITS;
392  break;
393  case 0x50 :
394  aType = RMW_SUM;
395  break;
396  case 0x60 :
397  aType = CONFIG_SPACE_READ;
398  break;
399  default:
400  log ( Error() , "Unknown IPbus-header " , Integer ( uint8_t ( ( aHeader & 0xF0 ) >>4 ) , IntFmt<hex,fixed>() ) );
401  return false;
402  }
403 
404  aWordCount = ( aHeader >> 8 ) & 0xff;
405  aTransactionId = ( aHeader >> 16 ) & 0xfff;
406  aInfoCode = aHeader & 0xf;
407  return true;
408  }
409 
410 
411  template< uint8_t IPbus_minor >
412  uint32_t IPbus< 2 , IPbus_minor >::implementCalculateHeader ( const IPbusTransactionType& aType , const uint32_t& aWordCount , const uint32_t& aTransactionId , const uint8_t& aInfoCode )
413  {
414  return IPbus< 2 , IPbus_minor >::CalculateHeader ( aType , aWordCount , aTransactionId , aInfoCode );
415  }
416 
417 
418  template< uint8_t IPbus_minor >
419  bool IPbus< 2 , IPbus_minor >::implementExtractHeader ( const uint32_t& aHeader , IPbusTransactionType& aType , uint32_t& aWordCount , uint32_t& aTransactionId , uint8_t& aInfoCode )
420  {
421  return IPbus< 2 , IPbus_minor >::ExtractHeader ( aHeader , aType , aWordCount , aTransactionId , aInfoCode );
422  }
423 
424 
425  template< uint8_t IPbus_minor >
427  {
428  mPacketCounter = 0;
429  mReceivePacketHeader.clear();
431  }
432 
433 
434  template< uint8_t IPbus_minor >
435  void IPbus< 2 , IPbus_minor >::translateInfoCode(std::ostream& aStream, const uint8_t& aInfoCode)
436  {
437  switch (aInfoCode) {
438  case 0:
439  aStream << "success";
440  break;
441  case 1:
442  aStream << "bad header";
443  break;
444  case 4:
445  aStream << "bus error on read";
446  break;
447  case 5:
448  aStream << "bus error on write";
449  break;
450  case 6:
451  aStream << "bus timeout on read";
452  break;
453  case 7:
454  aStream << "bus timeout on write";
455  break;
456  case 0xf:
457  aStream << "outbound request";
458  break;
459  default:
460  aStream << "UNKNOWN";
461  }
462  }
463 
464  // --------------------------------------------------------------------------------------------------------------------------------------------------------------
465 
466 
467  template class IPbus<1, 3>;
468  template class IPbus<2, 0>;
469 }
470 
471 
uhal::WRITE
@ WRITE
Definition: ProtocolIPbusCore.hpp:77
uhal::NI_READ
@ NI_READ
Definition: ProtocolIPbusCore.hpp:81
uhal::IPbusCore
A class providing the core IPbus packing functionality.
Definition: ProtocolIPbusCore.hpp:117
boost::shared_ptr
Definition: DerivedNodeFactory.hpp:52
uhal::IPbusTransactionType
IPbusTransactionType
Enumerated type to define the IPbus transaction type.
Definition: ProtocolIPbusCore.hpp:74
uhal::IPbus
A class which provides the version-specific functionality for IPbus.
Definition: ProtocolIPbus.hpp:69
boost
Definition: log.hpp:13
uhal::READ
@ READ
Definition: ProtocolIPbusCore.hpp:76
uhal::IPbusCore::validate
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...
Definition: ProtocolIPbusCore.cpp:143
uhal::IntFmt
Empty struct which acts as a dummy variable for passing the formatting information around.
Definition: log_inserters.integer.hpp:68
uhal::CONFIG_SPACE_READ
@ CONFIG_SPACE_READ
Definition: ProtocolIPbusCore.hpp:83
uhal::exception::exception
An abstract base exception class, including an interface to throw as the derived type (for passing ex...
Definition: exception.hpp:71
uhal::B_O_T
@ B_O_T
Definition: ProtocolIPbusCore.hpp:75
uhal
Definition: HttpResponseGrammar.hpp:49
uhal::RMW_BITS
@ RMW_BITS
Definition: ProtocolIPbusCore.hpp:78
uhal::IPbusCore::dispatchExceptionHandler
virtual void dispatchExceptionHandler()
Function which is called when an exception is thrown.
Definition: ProtocolIPbusCore.cpp:535
uhal::RMW_SUM
@ RMW_SUM
Definition: ProtocolIPbusCore.hpp:79
uhal::NI_WRITE
@ NI_WRITE
Definition: ProtocolIPbusCore.hpp:82
uhal::log
void log(FatalLevel &aFatal, const T0 &aArg0)
Function to add a log entry at Fatal level.
Definition: log.hxx:20
log_inserters.integer.hpp
uhal::Integer
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
Definition: log_inserters.integer.hxx:43
ProtocolIPbus.hpp
uhal::Error
ErrorLevel Error
Definition: LogLevels.cpp:61
uhal::Quote
_Quote< T > Quote(const T &aT)
Definition: log_inserters.quote.hxx:49
uhal::tests::uri
std::string uri
Definition: test_single.cpp:89
uhal::Debug
DebugLevel Debug
Definition: LogLevels.cpp:133
log.hpp
ValMem.hpp
LogLevels.hpp
uhal::URI
Struct to store a URI when parsed by boost spirit.
Definition: URI.hpp:50
uhal::R_A_I
@ R_A_I
Definition: ProtocolIPbusCore.hpp:80
ClientInterface.hpp
Buffers.hpp