003f7eea695caf1dc60da18936c20cbb17b0cd78
[u/mrichter/AliRoot.git] / HLT / RCU / AliHLTAltroChannelSelectorComponent.cxx
1 // $Id$
2
3 //**************************************************************************
4 //* This file is property of and copyright by the ALICE HLT Project        * 
5 //* ALICE Experiment at CERN, All rights reserved.                         *
6 //*                                                                        *
7 //* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
8 //*                  for The ALICE HLT Project.                            *
9 //*                                                                        *
10 //* Permission to use, copy, modify and distribute this software and its   *
11 //* documentation strictly for non-commercial purposes is hereby granted   *
12 //* without fee, provided that the above copyright notice appears in all   *
13 //* copies and that both the copyright notice and this permission notice   *
14 //* appear in the supporting documentation. The authors make no claims     *
15 //* about the suitability of this software for any purpose. It is          *
16 //* provided "as is" without express or implied warranty.                  *
17 //**************************************************************************
18
19 /** @file   AliHLTAltroChannelSelectorComponent.cxx
20     @author Matthias Richter
21     @date   
22     @brief  A filter/selective readout component for Altro data.
23 */
24
25 // see header file for class documentation
26 // or
27 // refer to README to build package
28 // or
29 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
30
31 #include <cassert>
32 #include "AliHLTAltroChannelSelectorComponent.h"
33 #include "AliAltroDecoder.h"
34 #include "AliAltroData.h"
35
36 /** ROOT macro for the implementation of ROOT specific class methods */
37 ClassImp(AliHLTAltroChannelSelectorComponent)
38
39 AliHLTAltroChannelSelectorComponent::AliHLTAltroChannelSelectorComponent()
40   :
41   AliHLTProcessor(),
42   fSkipCorrupted(false),
43   fTalkative(false)
44 {
45   // see header file for class documentation
46   // or
47   // refer to README to build package
48   // or
49   // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
50 }
51
52 AliHLTAltroChannelSelectorComponent::~AliHLTAltroChannelSelectorComponent()
53 {
54   // see header file for class documentation
55 }
56
57 const char* AliHLTAltroChannelSelectorComponent::GetComponentID()
58 {
59   // see header file for class documentation
60   return "AltroChannelSelector";
61 }
62
63 void AliHLTAltroChannelSelectorComponent::GetInputDataTypes(AliHLTComponentDataTypeList& list)
64 {
65   // see header file for class documentation
66   list.clear();
67   list.push_back(kAliHLTDataTypeDDLRaw|kAliHLTDataOriginTPC);
68   list.push_back(kAliHLTDataTypeHwAddr16);
69 }
70
71 AliHLTComponentDataType AliHLTAltroChannelSelectorComponent::GetOutputDataType()
72 {
73   // see header file for class documentation
74   return kAliHLTDataTypeDDLRaw|kAliHLTDataOriginTPC;
75 }
76
77 void AliHLTAltroChannelSelectorComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
78 {
79   // see header file for class documentation
80   constBase=0;
81   inputMultiplier=1.0;
82 }
83
84 AliHLTComponent* AliHLTAltroChannelSelectorComponent::Spawn()
85 {
86   // see header file for class documentation
87   return new AliHLTAltroChannelSelectorComponent;
88 }
89
90 int AliHLTAltroChannelSelectorComponent::DoInit(int argc, const char** argv)
91 {
92   // see header file for class documentation
93   int iResult=0;
94   TString argument="";
95   bool bMissingParam=0;
96   for (int i=0; i<argc && iResult>=0; i++) {
97     argument=argv[i];
98     if (argument.IsNull()) continue;
99
100     // -skip-corrupted
101     if (argument.CompareTo("-skip-corrupted")==0) {
102       fSkipCorrupted=true;
103
104     // -talkative
105     } else if (argument.CompareTo("-talkative")==0) {
106       fTalkative=true;
107     } else {
108       HLTError("unknown argument %s", argument.Data());
109       iResult=-EINVAL;
110     }
111   }
112
113   if (bMissingParam) {
114     HLTError("missing parameter for argument %s", argument.Data());
115     iResult=-EINVAL;
116   }
117
118   return iResult;
119 }
120
121 int AliHLTAltroChannelSelectorComponent::DoDeinit()
122 {
123   // see header file for class documentation
124   return 0;
125 }
126
127 int AliHLTAltroChannelSelectorComponent::DoEvent(const AliHLTComponentEventData& evtData,
128                                                  const AliHLTComponentBlockData* blocks, 
129                                                  AliHLTComponentTriggerData& /*trigData*/,
130                                                  AliHLTUInt8_t* outputPtr, 
131                                                  AliHLTUInt32_t& size,
132                                                  AliHLTComponentBlockDataList& outputBlocks )
133 {
134   // see header file for class documentation
135   int iResult=0;
136   const int cdhSize=32;
137
138   if (!IsDataEvent()) {
139     size=0;
140     return 0;
141   }
142
143   // process the DLL input
144   int blockno=0;
145   const AliHLTComponentBlockData* pDesc=NULL;
146
147   AliAltroDecoder* decoder=NULL;
148   for (pDesc=GetFirstInputBlock(kAliHLTDataTypeDDLRaw); pDesc!=NULL; pDesc=GetNextInputBlock(), blockno++) {
149     iResult=0;
150     if (pDesc->fSize<=32) {
151       continue;
152     }
153
154     // search for the active pad information
155     AliHLTUInt16_t* pActiveHwAddressArray=NULL;
156     int iArraySize=0;
157     for (int i=0; i<(int)evtData.fBlockCnt; i++ ) {
158       // search for selection data of hw address type
159       // which matches the data specification of the block
160       if (blocks[i].fDataType==kAliHLTDataTypeHwAddr16 && blocks[i].fSpecification==pDesc->fSpecification) {
161         pActiveHwAddressArray=reinterpret_cast<AliHLTUInt16_t*>(blocks[i].fPtr);
162         iArraySize=blocks[i].fSize/sizeof(AliHLTUInt16_t);
163         break;
164       }
165     }
166     if (pActiveHwAddressArray==NULL) {
167       HLTWarning("no block of type %s for specification 0x%08x available, data block unchanged", 
168                  DataType2Text(kAliHLTDataTypeHwAddr16).c_str(), 
169                  pDesc->fSpecification);
170       iResult=-EFAULT;
171     }
172
173     if (decoder) delete decoder;
174     decoder=new AliAltroDecoder;
175     if (decoder->SetMemory(reinterpret_cast<UChar_t*>(pDesc->fPtr), pDesc->fSize)<0) {
176       HLTWarning("corrupted data block: initialization of decoder failed for block: %s specification %#x size %d",
177                  DataType2Text(pDesc->fDataType).c_str(), pDesc->fSpecification, pDesc->fSize);
178       iResult=-EFAULT;
179     } else {
180       if (decoder->Decode()) {
181         HLTDebug("init decoder %p size %d", pDesc->fPtr,pDesc->fSize);
182       } else {
183         HLTWarning("corrupted data block: decoding failed for raw data block: %s specification %#x size %d",
184                    DataType2Text(pDesc->fDataType).c_str(), pDesc->fSpecification, pDesc->fSize);
185         iResult=-EFAULT;
186       }
187     }
188
189     unsigned int rcuTrailerLength=0;
190     if (iResult>=0 &&
191         ((rcuTrailerLength=decoder->GetRCUTrailerSize())==0 ||
192          rcuTrailerLength>pDesc->fSize-cdhSize)) {
193       if (rcuTrailerLength>0) {
194         HLTWarning("corrupted data block: RCU trailer length exceeds buffer size");
195       } else {
196         HLTWarning("corrupted data block: RCU trailer of zero length"); 
197       }
198       iResult=-EFAULT;
199     }
200
201     if (iResult<0) {
202       // TODO: here the trigger has to come into play. It is up to
203       // policy if a corrupted data block should be kept (original
204       // DDL) or discarded. In any case, the block is not going to
205       // be part of HLTOUT
206       HLTWarning("skipping corrupted data block for event %lu, data block %s 0x%08x", evtData.fEventID,
207                  DataType2Text(pDesc->fDataType).c_str(), pDesc->fSpecification);
208       iResult=0;
209       continue;
210     }
211
212     int iSelected=0;
213     int iTotal=0;
214     int iCorrupted=0;
215     AliHLTUInt32_t iOutputSize=0;
216     AliHLTUInt32_t iNofAltro40=0;
217     AliHLTUInt32_t iCapacity=size;
218     AliAltroData channel;
219
220     // first add the RCU trailer
221     AliHLTUInt8_t* pSrc=reinterpret_cast<AliHLTUInt8_t*>(pDesc->fPtr);
222     pSrc+=pDesc->fSize-rcuTrailerLength;
223     if ((iResult=CopyBlockToEnd(outputPtr, iCapacity, iOutputSize, pSrc, rcuTrailerLength))>=0) {
224       assert(iResult==(int)rcuTrailerLength);
225       iOutputSize+=rcuTrailerLength;
226     } else {
227       HLTError("failed to write RCU trailer of length %d for block %d, too little space in output buffer?", rcuTrailerLength, blockno);
228       iResult=-ENOSPC;
229       break;
230     }
231
232     while (decoder->NextChannel(&channel) && iResult>=0) {
233       iTotal++;
234
235       int hwAddress=channel.GetHadd();
236       int active=0;
237       for (active=0; active<iArraySize; active++) {
238         if (pActiveHwAddressArray[active]==(AliHLTUInt16_t)hwAddress) {
239           break;
240         }
241       }
242       if (active>=iArraySize) {
243         HLTDebug("ALTRO block %#x (%d) discarded (inactive)", hwAddress, hwAddress);
244         continue;
245       }
246
247       // no of 10 bit words is without the fill words to fill complete 40 bit words
248       // in addition, align to complete 40 bit words (the '+3')
249       // also, the 5 bytes of the Altro trailer must be added to get the full size
250       int channelSize=((channel.GetDataSize()+3)/4)*5;
251       if (channelSize==0) {
252         if (fTalkative) HLTWarning("skipping zero length channel (hw address %d)", hwAddress);
253         iCorrupted++;
254         continue;
255       }
256       channelSize+=5;
257       HLTDebug("ALTRO block hwAddress 0x%08x (%d) selected (active), size %d", hwAddress, hwAddress, channelSize);
258
259       if ((iResult=decoder->CopyBackward(outputPtr, iCapacity-iOutputSize))>=0) {
260         if (channelSize == iResult) {
261           if (channelSize%5 == 0) {
262             iNofAltro40+=channelSize/5;
263             iOutputSize+=channelSize;
264           } else {
265             if (fTalkative) HLTWarning("corrupted ALTRO channel: incomplete 40 bit word (channel hw address %d)", hwAddress);
266             iCorrupted++;
267             continue;
268           }
269         } else {
270           if (fTalkative) HLTWarning("internal error: failed to copy full channel: %d out of %d bytes (hw address %d)", iResult, channelSize, hwAddress);
271           iCorrupted++;
272           continue;
273         }
274       } else {
275         if (fTalkative) HLTError("failed to write ALTRO channel of length %d for block %d  (hw address %d)", channelSize, blockno, hwAddress);
276         // corrupted channel, but keep going
277         iCorrupted++;
278         iResult=0;
279         continue;
280       }
281       iSelected++;
282     }
283     if (iResult>=0) {
284       // write the common data header
285       if ((iResult=CopyBlockToEnd(outputPtr, iCapacity, iOutputSize, pDesc->fPtr, cdhSize))>=0) {
286         assert(iResult==cdhSize);
287         iOutputSize+=cdhSize;
288
289         // set new length of the data block
290         AliHLTUInt32_t* pCdhSize=reinterpret_cast<AliHLTUInt32_t*>(outputPtr+iCapacity-iOutputSize);
291         *pCdhSize=iOutputSize;
292
293         // set number of Altro words
294         AliHLTUInt32_t* pNofAltro40=reinterpret_cast<AliHLTUInt32_t*>(outputPtr+iCapacity-rcuTrailerLength);
295         *pNofAltro40=iNofAltro40;
296
297         // insert block descriptor
298         AliHLTComponentBlockData bd;
299         FillBlockData(bd);
300         bd.fOffset=iCapacity-iOutputSize;
301         bd.fSize=iOutputSize;
302         bd.fDataType=pDesc->fDataType;
303         bd.fSpecification=pDesc->fSpecification;
304         outputBlocks.push_back(bd);
305         iCapacity-=iOutputSize;
306       } else {
307         HLTError("failed to write CDH of length %d for block %d", cdhSize, blockno);
308         break;
309       }
310     }
311     if (fTalkative) HLTImportant("data block %d (0x%08x): selected %d out of %d ALTRO channel(s), %d corrupted channels skipped", blockno, pDesc->fSpecification, iSelected, iTotal, iCorrupted);
312   }
313   if (decoder) delete decoder;
314
315   if (iResult<0) {
316     outputBlocks.clear();
317   }
318
319   // all data blocks need to be moved to the beginning of the
320   // buffer because PubSub is not able to handle data blocks entirely
321   // at the end of the buffer. The problem is that the component always
322   // indicates to use the full size of the buffer
323   if (outputBlocks.size()>0) {
324     int offset=outputBlocks.back().fOffset;
325     size-=offset;
326     memmove(outputPtr, outputPtr+offset, size);
327     for (AliHLTComponentBlockDataList::iterator block=outputBlocks.begin();
328          block!=outputBlocks.end();
329          block++) {
330       block->fOffset-=offset;
331     }
332   }
333
334   return iResult;
335 }
336
337 int AliHLTAltroChannelSelectorComponent::CopyBlockToEnd(AliHLTUInt8_t* pTgt, unsigned capacity, unsigned position, void* pSrc, unsigned size)
338 {
339   int iResult=0;
340   if (pTgt==NULL || pSrc==NULL) return -EINVAL;
341   if (capacity-position<size) return -ENOSPC;
342   
343   memcpy(pTgt+(capacity-position-size), pSrc, size);
344   iResult=size;
345   
346   return iResult;
347 }