μHAL (v2.8.17)
Part of the IPbus software repository
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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
34
35
36#include <memory>
37#include <mutex>
38#include <ostream>
39#include <stdint.h>
40
41#include <boost/date_time/posix_time/posix_time_types.hpp> // for seconds
42
43#include "uhal/Buffers.hpp"
47#include "uhal/log/log.hpp"
48#include "uhal/ValMem.hpp"
49
50
51namespace 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 >
69 void IPbus< 1 , IPbus_minor >::preamble ( std::shared_ptr< Buffers > )
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 >
83 void IPbus< 1 , IPbus_minor >::predispatch ( std::shared_ptr< Buffers > aBuffers )
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 >
262 void IPbus< 2 , IPbus_minor >:: preamble ( std::shared_ptr< Buffers > aBuffers )
263 {
264 aBuffers->send ( 0x200000F0 | ( ( mPacketCounter&0xffff ) <<8 ) );
265 {
266 std::lock_guard<std::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 >
281 void IPbus< 2 , IPbus_minor >::predispatch ( std::shared_ptr< Buffers > )
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 std::lock_guard<std::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
\rst Wraps a Python iterator so that it can also be used as a C++ input iterator
Definition: pytypes.h:1102
A class providing the core IPbus packing functionality.
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...
virtual void dispatchExceptionHandler()
Function which is called when an exception is thrown.
A class which provides the version-specific functionality for IPbus.
An abstract base exception class, including an interface to throw as the derived type (for passing ex...
Definition: exception.hpp:71
DebugLevel Debug
Definition: LogLevels.cpp:133
_Quote< T > Quote(const T &aT)
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
IPbusTransactionType
Enumerated type to define the IPbus transaction type.
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
constexpr int first(int i)
Implementation details for constexpr functions.
Definition: common.h:795
Empty struct which acts as a dummy variable for passing the formatting information around.
Struct to store a URI when parsed by boost spirit.
Definition: URI.hpp:50