Cat
ICECALv3.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
2 //
3 // Package : ICECALv3
4 //
5 // Description:
6 //
7 // Author(s) : Joan Mauricio
8 // Date : 2014/05/16
9 //
10 //------------------------------------------------------------------------------
11 
12 // local include file
13 #include "ICECALv3.h"
14 
15 //Constructor
17  setType("ICECALv3");
18  setId(0);
19 
21  debug("ICECALv3 built.","ICECALv3::ICECALv3");
22 
23  //Configuration register initilization:
24  //Sub-address = 9.
25  //#bytes = 3 (address + data<1> + data<0>).
26  confReg=new Register();
27  confReg->setName("ConfigRegister");
28  confReg->io()->setSubAddress(9);
29  confReg->io()->defDataU8(3);
31 
32  addChild(confReg);
33 }
34 
35 //Configuration file is read and parameters are applied to the electronics.
36 PyObject* ICECALv3::loadConfig(string configFile)
37 {
38  string paramName[64];
39  int paramValue[64], nParams;
40  PyObject* asicParams;
41 
42  PyObject* fullConfiguration = PyList_New(0);
43  //These are the names of the parameters that we are looking for in each case.
44  string mainParams[] = {"VCONTROL_OE","BXID_SYN_OE","CLK_REFRESH","IBIAS_OB","IBIAS_CE_TH","IBIAS_TH","IBIAS_INT","IBIAS_CE_IN","IBIAS_CE_PZ","IBIAS_0T","IBIAS_PZ","IBIAS_V0T"};
45  string analogParams[4][7]= { {"CINT_SUBCH0[0]","CINT_SUBCH1[0]","IOFF_SUBCH0[0]","IOFF_SUBCH1[0]","ZERO[0]","POLE[0]","ZIN[0]"}
46  , {"CINT_SUBCH0[1]","CINT_SUBCH1[1]","IOFF_SUBCH0[1]","IOFF_SUBCH1[1]","ZERO[1]","POLE[1]","ZIN[1]"}
47  , {"CINT_SUBCH0[2]","CINT_SUBCH1[2]","IOFF_SUBCH0[2]","IOFF_SUBCH1[2]","ZERO[2]","POLE[2]","ZIN[2]"}
48  , {"CINT_SUBCH0[3]","CINT_SUBCH1[3]","IOFF_SUBCH0[3]","IOFF_SUBCH1[3]","ZERO[3]","POLE[3]","ZIN[3]"} };
49  string delayLineParams[4][5]= { {"PHASE_ADC[0]","PHASE_TH[0]","PHASE_INT[0]","LOC_SEL[0]","LVDS_OEN[0]"}
50  ,{"PHASE_ADC[1]","PHASE_TH[1]","PHASE_INT[1]","LOC_SEL[1]","LVDS_OEN[1]"}
51  ,{"PHASE_ADC[2]","PHASE_TH[2]","PHASE_INT[2]","LOC_SEL[2]","LVDS_OEN[2]"}
52  ,{"PHASE_ADC[3]","PHASE_TH[3]","PHASE_INT[3]","LOC_SEL[3]","LVDS_OEN[3]"} };
53 
54  nParams = parseParameterList(configFile, paramName, paramValue);
55 
56  if(nParams != -1)
57  {
58  //At this point we have an array of parameter names (string) and an array of values (int).
59  //We obtain the parameter values of the 'mainParams' array by searching on the C++ dictionary.
60  asicParams = fillParams(mainParams,12,paramName,paramValue,nParams);
61  setMainReg(asicParams);
62  PyList_Append(fullConfiguration,asicParams);
63 
64  for(int iCh=0 ; iCh<4 ; iCh++)
65  {
66  asicParams = fillParams(analogParams[iCh],7,paramName,paramValue,nParams); //Parameters of the analog channel.
67  setAnalogCh(iCh,asicParams);
68  PyList_Append(fullConfiguration,asicParams);
69  asicParams = fillParams(delayLineParams[iCh],5,paramName,paramValue,nParams); //Parameters of the delay line channel.
70  setDelayLineCh(iCh,asicParams);
71  PyList_Append(fullConfiguration,asicParams);
72  }
73  }
74  return fullConfiguration;
75 }
76 
77 int ICECALv3::parseParameterList(string configFile, string paramName[64], int paramValue[64])
78 {
79  int iParams = 0, eqPos;
80  string line;
81 
82  std::ifstream fd(configFile.c_str());
83  if(!fd) //File NOT OK.
84  {
85  error(configFile+" could not be opened.","ICECALv3::loadConfig");
86  return -1;
87  }
88  else //File OK.
89  {
90  while(!fd.eof())
91  {
92  getline(fd,line);
93  eqPos = line.find("=");
94  if((eqPos != string::npos) && (line[0] != '#')) //If current line contains "=" and DO NOT start with "#", is a good parameter.
95  {
96  paramName[iParams] = line.substr(0,eqPos); //We store the parameter name
97  paramValue[iParams] = atoi(line.substr(eqPos+1,string::npos).c_str()); //and the parameter value.
98  iParams++;
99  }
100  }
101  return iParams;
102  }
103 }
104 
105 //This function generates the Python list.
106 PyObject* ICECALv3::fillParams(string paramListRet[],int paramListLen,string paramName[64],int paramValue[64],int fileParamLen)
107 {
108  int iParamFile;
109  bool found;
110  PyObject* asicParams = PyList_New(0);
111 
112  //For each of the parameters of the list...
113  for(int iList=0 ; iList<paramListLen ; iList++)
114  {
115  iParamFile=0;
116  found = false;
117  //We look for the parameter name in the C++ dictionary.
118  while(iParamFile < fileParamLen && !found)
119  {
120  if(paramName[iParamFile].find(paramListRet[iList]) != string::npos)
121  {
122  PyList_Append(asicParams, PyInt_FromLong(paramValue[iParamFile]));
123  found = true;
124  }
125  iParamFile++;
126  }
127  }
128  return asicParams;
129 }
130 
131 //Configuration is dumped to a file.
132 StatusCode ICECALv3::dumpConfig(string configFile, PyObject* chipId)
133 {
134  PyObject* asicParams = PyList_New(0);
135  bool ok;
136 
137  //The first list item is the Chip Identifier.
138  PyList_Append(asicParams, chipId);
139 
140  //Let's ask for the configuration to our chip.
141  //Each function will return the corresponding parameter list
142  //of that register.
143  for(int i=0;i<4;i++)
144  {
145  PyList_Append(asicParams, getDelayLineCh(i) );
146  PyList_Append(asicParams, getAnalogCh(i) );
147  }
148  PyList_Append(asicParams, getMainReg() );
149 
150  ok = writeAsicParams(configFile,asicParams);
151 
152  if(ok) return StatusCode::SUCCESS;
153  else return StatusCode::FAILURE;
154 }
155 
156 bool ICECALv3::writeAsicParams(string fileName, PyObject* asicParams)
157 {
158  time_t rawtime;
159  struct tm * timeinfo;
160  char dStr[64], tStr[64];
161  ofstream fd;
162  PyObject* l; //Temporary list to accomodate 'asicParams' main list list objects.
163 
164  //'asicParams' output example:
165  //['R1403C0000', [19, 24, 0, 0, 1], [2, 3, 6, 0, 0, 0, 19, 48, 0], [19, 24, 0, 0, 1],
166  // [2, 3, 6, 0, 0, 0, 19, 48, 0], [19, 24, 0, 0, 1], [2, 3, 6, 0, 0, 0, 19, 48, 0],
167  // [19, 24, 0, 0, 1], [2, 3, 6, 0, 0, 0, 19, 48, 0], [0, 0, 0, 56, 0, 56, 0, 9, 56, 0, 56, 0]]
168 
169  time (&rawtime);
170  timeinfo = localtime (&rawtime);
171  strftime (dStr,64,"%Y/%m/%d",timeinfo);
172  strftime (tStr,64,"%R",timeinfo);
173 
174  fd.open (fileName.c_str(), ios_base::out);
175  if(fd.is_open())
176  {
177  fd << "#########################################################" << endl;
178  fd << "############# ICECAL CALIBRATION FILE ###############" << endl;
179  fd << "#########################################################" << endl;
180  fd << "" << endl;
181  fd << "#File Version : v" << CALIBRATION_FILE_VER << endl;
182  fd << "#Date (YYYY/MM/DD): " << string(dStr) << endl;
183  fd << "#Time (HH:MM) : " << string(tStr) << endl;
184  fd << "#ICECAL Chip ID : " << PyString_AsString(PyList_GetItem(asicParams,0)) << endl;
185  fd << "" << endl << endl;
186 
187  fd << "#########################################################" << endl;
188  fd << "# ICECAL Main Register Parameters:" << endl;
189  fd << "#########################################################" << endl;
190  fd << "" << endl;
191 
192  l = PyList_GetItem(asicParams,9); //list item 9. ICECAL Main config reg.
193  fd << "VCONTROL_OE = " << PyInt_AsLong(PyList_GetItem(l,0)) << endl;
194  fd << "BXID_SYN_OE = " << PyInt_AsLong(PyList_GetItem(l,1)) << endl;
195  fd << "CLK_REFRESH = " << PyInt_AsLong(PyList_GetItem(l,2)) << endl;
196  fd << "IBIAS_OB = " << PyInt_AsLong(PyList_GetItem(l,3)) << endl;
197  fd << "IBIAS_CE_TH = " << PyInt_AsLong(PyList_GetItem(l,4)) << endl;
198  fd << "IBIAS_TH = " << PyInt_AsLong(PyList_GetItem(l,5)) << endl;
199  fd << "IBIAS_INT = " << PyInt_AsLong(PyList_GetItem(l,6)) << endl;
200  fd << "IBIAS_CE_IN = " << PyInt_AsLong(PyList_GetItem(l,7)) << endl;
201  fd << "IBIAS_CE_PZ = " << PyInt_AsLong(PyList_GetItem(l,8)) << endl;
202  fd << "IBIAS_0T = " << PyInt_AsLong(PyList_GetItem(l,9)) << endl;
203  fd << "IBIAS_PZ = " << PyInt_AsLong(PyList_GetItem(l,10)) << endl;
204  fd << "IBIAS_V0T = " << PyInt_AsLong(PyList_GetItem(l,11)) << endl;
205  fd << "" << endl << endl;
206 
207  for(int i=0;i<4;i++)
208  {
209  fd << "#########################################################" << endl;
210  fd << "#Channel #" << i << " Parameters:" << endl;
211  fd << "#########################################################" << endl;
212  fd << "" << endl;
213 
214  l = PyList_GetItem(asicParams,1+2*i); //list items 1, 3, 5, 7. Delay line config regs.
215  fd << "PHASE_ADC[" << i << "] = " << PyInt_AsLong(PyList_GetItem(l,0)) << endl;
216  fd << "PHASE_TH[" << i << "] = " << PyInt_AsLong(PyList_GetItem(l,1)) << endl;
217  fd << "PHASE_INT[" << i << "] = " << PyInt_AsLong(PyList_GetItem(l,2)) << endl;
218  fd << "LOC_SEL[" << i << "] = " << PyInt_AsLong(PyList_GetItem(l,3)) << endl;
219  fd << "LVDS_OEN[" << i << "] = " << PyInt_AsLong(PyList_GetItem(l,4)) << endl;
220 
221  l = PyList_GetItem(asicParams,2+2*i); //list items 2, 4, 6, 8. ICECAL Analog config regs.
222  fd << "CINT_SUBCH0[" << i << "] = " << PyInt_AsLong(PyList_GetItem(l,0)) << endl;
223  fd << "CINT_SUBCH1[" << i << "] = " << PyInt_AsLong(PyList_GetItem(l,1)) << endl;
224  fd << "IOFF_SUBCH0[" << i << "] = " << PyInt_AsLong(PyList_GetItem(l,2)) << endl;
225  fd << "IOFF_SUBCH1[" << i << "] = " << PyInt_AsLong(PyList_GetItem(l,3)) << endl;
226  fd << "ZERO[" << i << "] = " << PyInt_AsLong(PyList_GetItem(l,4)) << endl;
227  fd << "POLE[" << i << "] = " << PyInt_AsLong(PyList_GetItem(l,5)) << endl;
228  fd << "ZIN[" << i << "] = " << PyInt_AsLong(PyList_GetItem(l,6)) << endl;
229  fd << "" << endl;
230  }
231 
232  fd.close();
233  return true;
234  }
235  else return false;
236 }
237 
243 
244 //Verbosely commented code.
245 //Reads the delay line SPI register and returns all the values by means of a PyList of PyOject.
246 PyObject* ICECALv3::getDelayLineCh(int ch)
247 {
248  U8 spiAddr = delayLineAddrCh[ch]; //The SPI address of this delay line channel.
249  U16 rxData = spiRead(spiAddr); //rxData contains the 16 bits corresponding to the delay line channel.
250 
251  int phaseADC, phaseTH, phaseINT, locSel, lvdsOEn;
252  PyObject* dllParams = PyList_New(0);
253 
254  if(err) PyList_Append(dllParams, PyInt_FromLong(-1));
255  else
256  {
257  phaseADC = (rxData >> 11) & 0x1F; //5 bits.
258  phaseTH = (rxData >> 6 ) & 0x1F; //5 bits.
259  phaseINT = (rxData >> 3 ) & 0x07; //3 bits.
260  locSel = (rxData >> 1 ) & 0x03; //2 bits.
261  lvdsOEn = (rxData & 0x01); //1 bit.
262 
263  //Converts integers to PyInt objects and then appends them to the PyList
264  PyList_Append(dllParams, PyInt_FromLong(phaseADC));
265  PyList_Append(dllParams, PyInt_FromLong(phaseTH));
266  PyList_Append(dllParams, PyInt_FromLong(phaseINT));
267  PyList_Append(dllParams, PyInt_FromLong(locSel));
268  PyList_Append(dllParams, PyInt_FromLong(lvdsOEn));
269 
270  info("Delay Line Channel <"+itos(ch)+"> configuration (@SPI = 0x"+itohs(spiAddr)+"):","ICECALv3::getDelayLine");
271  info(" ·Phase ADC : "+itos(phaseADC),"ICECALv3::getDelayLine");
272  info(" ·Phase T&H : "+itos(phaseTH) ,"ICECALv3::getDelayLine");
273  info(" ·Phase INT : "+itos(phaseINT),"ICECALv3::getDelayLine");
274  info(" ·LVDS Current Sel : "+itos(locSel) ,"ICECALv3::getDelayLine");
275  info(" ·LVDS Output enable : "+itos(lvdsOEn) ,"ICECALv3::getDelayLine");
276  }
277  return dllParams;
278 }
279 
280 //Reads the delay line SPI register and returns all the values by means of a PyList of PyOject.
281 StatusCode ICECALv3::setDelayLineCh(int ch, PyObject* dllParams)
282 {
283  U16 txData;
284  int phaseADC, phaseTH, phaseINT, locSel, lvdsOEn;
285 
286  U8 spiAddr = delayLineAddrCh[ch]; //The SPI address of this delay line channel.
287 
288  //Converts the elements of the PyList to integers.
289  phaseADC = PyInt_AsLong(PyList_GetItem(dllParams,0));
290  phaseTH = PyInt_AsLong(PyList_GetItem(dllParams,1));
291  phaseINT = PyInt_AsLong(PyList_GetItem(dllParams,2));
292  locSel = PyInt_AsLong(PyList_GetItem(dllParams,3));
293  lvdsOEn = PyInt_AsLong(PyList_GetItem(dllParams,4));
294 
295  //txData contains the 16 bits corresponding to the delay line channel.
296  txData = ((phaseADC & 0x1F) << 11) | ((phaseTH & 0x1F) << 6) | ((phaseINT & 0x1F) << 3) | ((locSel & 0x03) << 1) | (lvdsOEn & 0x01);
297 
298  //Data is sent and checked. If there is a random write/read error, data is written again.
299  err = spiWriteSafe(spiAddr,txData);
300 
301  if(err) return StatusCode::FAILURE;
302  else return StatusCode::SUCCESS;
303 }
304 
310 
311 //Non-verbosely commented code. If you have questions, look at the code above.
312 PyObject* ICECALv3::getAnalogCh(int ch)
313 {
314  U8 spiLsbAddr = icecalLSBAddrCh[ch]; //The SPI address of the 16 LSBs.
315  U8 spiMsbAddr = icecalMSBAddrCh[ch]; //The SPI address of the 16 MSBs.
316 
317  int cIntMsb, cIntLsb0, cIntLsb1, iOffMsb, cIntSubCh0, cIntSubCh1, iOffLsb0, iOffLsb1, iOffSubCh0, iOffSubCh1, zero, pole, zIn;
318  PyObject* icecalChParams = PyList_New(0);
319 
320  //32 bit register from two SPI 16-bit registers.
321  U32 rxData = (spiRead(spiMsbAddr) << 16) | spiRead(spiLsbAddr);
322 
323  if(err) PyList_Append(icecalChParams, PyInt_FromLong(-1));
324  else
325  {
326  cIntMsb = (rxData >> 30) & 0x03; //2 bits.
327  cIntLsb0 = (rxData >> 27) & 0x07; //3 bits.
328  cIntLsb1 = (rxData >> 24) & 0x07; //3 bits.
329  iOffMsb = (rxData >> 20) & 0x0F; //4 bits.
330  iOffLsb0 = (rxData >> 18) & 0x03; //2 bits.
331  iOffLsb1 = (rxData >> 16) & 0x03; //2 bits.
332  zero = (rxData >> 11) & 0x1F; //5 bits.
333  pole = (rxData >> 5) & 0x3F; //6 bits.
334  zIn = (rxData) & 0x1F; //5 bits.
335 
336  cIntSubCh0 = (cIntMsb << 3) | cIntLsb0; //cInt: The 2 MSB are shared between subchannels.
337  cIntSubCh1 = (cIntMsb << 3) | cIntLsb1; //The 3 LSB may differ from subchannels.
338  iOffSubCh0 = (iOffMsb << 2) | iOffLsb0; //iOff: 4 common + 2 different.
339  iOffSubCh1 = (iOffMsb << 2) | iOffLsb1;
340 
341  PyList_Append(icecalChParams, PyInt_FromLong(cIntSubCh0));
342  PyList_Append(icecalChParams, PyInt_FromLong(cIntSubCh1));
343  PyList_Append(icecalChParams, PyInt_FromLong(iOffSubCh0));
344  PyList_Append(icecalChParams, PyInt_FromLong(iOffSubCh1));
345  PyList_Append(icecalChParams, PyInt_FromLong(zero));
346  PyList_Append(icecalChParams, PyInt_FromLong(pole));
347  PyList_Append(icecalChParams, PyInt_FromLong(zIn));
348 
349  info("ICECAL Analog Channel <"+itos(ch)+"> (MSB @SPI = 0x"+itohs(spiMsbAddr)+". LSB @SPI = 0x"+itohs(spiLsbAddr)+"):","ICECALv3::getIcecal");
350  info(" ·Integrator capacitor SubCh<0> : "+itos(cIntSubCh0) ,"ICECALv3::getAnalogCh");
351  info(" ·Integrator capacitor SubCh<1> : "+itos(cIntSubCh1) ,"ICECALv3::getAnalogCh");
352  info(" ·Offset Current SubCh<0> : "+itos(iOffSubCh0) ,"ICECALv3::getAnalogCh");
353  info(" ·Offset Current SubCh<1> : "+itos(iOffSubCh1) ,"ICECALv3::getAnalogCh");
354  info(" ·PZ Zero capacitor : "+itos(zero) ,"ICECALv3::getAnalogCh");
355  info(" ·PZ Pole capacitor : "+itos(pole) ,"ICECALv3::getAnalogCh");
356  info(" ·Input impedance control : "+itos(zIn) ,"ICECALv3::getAnalogCh");
357  }
358  return icecalChParams;
359 }
360 
361 StatusCode ICECALv3::setAnalogCh(int ch, PyObject* icecalChParams)
362 {
363  U16 hTx, lTx;
364  int cIntMsb, cIntLsb0, cIntLsb1, cIntSubCh0, cIntSubCh1, iOffMsb, iOffLsb0, iOffLsb1;
365  int iOffSubCh0, iOffSubCh1, zero, pole, zIn;
366 
367  U8 spiLsbAddr = icecalLSBAddrCh[ch]; //The SPI address of the 16 LSBs.
368  U8 spiMsbAddr = icecalMSBAddrCh[ch]; //The SPI address of the 16 MSBs.
369 
370  cIntSubCh0 = PyInt_AsLong(PyList_GetItem(icecalChParams,0));
371  cIntSubCh1 = PyInt_AsLong(PyList_GetItem(icecalChParams,1));
372  iOffSubCh0 = PyInt_AsLong(PyList_GetItem(icecalChParams,2));
373  iOffSubCh1 = PyInt_AsLong(PyList_GetItem(icecalChParams,3));
374  zero = PyInt_AsLong(PyList_GetItem(icecalChParams,4));
375  pole = PyInt_AsLong(PyList_GetItem(icecalChParams,5));
376  zIn = PyInt_AsLong(PyList_GetItem(icecalChParams,6));
377 
378  //Integretor Capacitor and Offset current configuration registers share the MSBs between subchannels.
379  //Therefore, these MSBs must be equal. Otherwise registers won't be properly configured.
380  if(((cIntSubCh0 & 0x18) == (cIntSubCh1 & 0x18)) && ((iOffSubCh0 & 0x3C) == (iOffSubCh1 & 0x3C)))
381  {
382  //Integretor capacitor: 2 + 3 bits.
383  cIntMsb = (cIntSubCh0 >> 3) & 0x3;
384  cIntLsb0 = cIntSubCh0 & 0x7;
385  cIntLsb1 = cIntSubCh1 & 0x7;
386  //Offset current: 4 + 2 bits.
387  iOffMsb = (iOffSubCh0 >> 2) & 0xF;
388  iOffLsb0 = iOffSubCh0 & 0x3;
389  iOffLsb1 = iOffSubCh1 & 0x3;
390 
391  hTx = ((cIntMsb & 0x3) << 14) | ((cIntLsb0 & 0x7) << 11) | ((cIntLsb1 & 0x7) << 8) |
392  ((iOffMsb & 0xF) << 4) | ((iOffLsb0 & 0x3) << 2) | ((iOffLsb1 & 0x3));
393  lTx = ((zero & 0x1F) << 11) | ((pole & 0x3F) << 5) | (zIn & 0x1F);
394 
395  err = spiWriteSafe(spiMsbAddr,hTx);
396  if(!err) err = spiWriteSafe(spiLsbAddr,lTx);
397 
398  if(err) return StatusCode::FAILURE;
399  else return StatusCode::SUCCESS;
400  }
401  else
402  {
403  if((cIntSubCh0 & 0x18) != (cIntSubCh1 & 0x18)) error("Integrator Cap MSB sub-channel mismatch. MSB<0> = "+itohs(cIntSubCh0)+", MSB<1> = "+itohs(cIntSubCh1)+".","ICECALv3::setAnalogCh");
404  if((iOffSubCh0 & 0x3C) != (iOffSubCh1 & 0x3C)) error("Offset Current MSB sub-channel mismatch. MSB<0> = "+itohs(iOffSubCh0)+", MSB<1> = "+itohs(iOffSubCh1)+".","ICECALv3::setAnalogCh");
405  return StatusCode::FAILURE;
406  }
407 }
408 
414 
416 {
417  U16 rxD[4];
418 
419  int vCtlOE, bxidSynOE, clkRefreshEn, iBiasOB, iBiasCETH, iBiasTH, iBiasINT;
420  int iBiasCEINT, iBiasCEPZ, iBias0T, iBiasPZ, iBiasV0T;
421  PyObject* icecalMainParams = PyList_New(0);
422 
423  for(int i=0;i<4;i++) rxD[i] = spiRead(icecalMainAddr[i]); //4 registers of 16 bits.
424 
425  if(err) PyList_Append(icecalMainParams, PyInt_FromLong(-1));
426  else
427  {
428  //Delay Line & Slow Control main configuration bits.
429  vCtlOE = !((rxD[3] >> 15) & 0x01); //1 bit (active low) (d63).
430  bxidSynOE = !((rxD[3] >> 14) & 0x01); //1 bit (active low) (d62).
431  clkRefreshEn = !((rxD[3] >> 13) & 0x01); //1 bit (active low) (d61).
432 
433  //Bias currents for the analog channels.
434  iBiasOB = (rxD[3] >> 6) & 0x3F; //6 bits (d59..54).
435  iBiasCETH = (rxD[3]) & 0x3F; //6 bits (d53..48).
436  iBiasTH = (rxD[2] >> 6) & 0x3F; //6 bits (d43..38).
437  iBiasINT = (rxD[2] ) & 0x3F; //6 bits (d37..32).
438  iBiasCEINT =((rxD[1] >> 9) & 0x38) | ((rxD[0] >> 12) & 0x7); //6 bits (d30..28, d14..12).
439  iBiasCEPZ = (rxD[1] >> 6) & 0x3F; //6 bits (d27..22).
440  iBias0T = (rxD[1]) & 0x3F; //6 bits (d21..16).
441  iBiasPZ = (rxD[0] >> 6) & 0x3F; //6 bits (d11..06).
442  iBiasV0T = (rxD[0]) & 0x3F; //6 bits (d05..00).
443 
444  PyList_Append(icecalMainParams, PyInt_FromLong(vCtlOE));
445  PyList_Append(icecalMainParams, PyInt_FromLong(bxidSynOE));
446  PyList_Append(icecalMainParams, PyInt_FromLong(clkRefreshEn));
447  PyList_Append(icecalMainParams, PyInt_FromLong(iBiasOB));
448  PyList_Append(icecalMainParams, PyInt_FromLong(iBiasCETH));
449  PyList_Append(icecalMainParams, PyInt_FromLong(iBiasTH));
450  PyList_Append(icecalMainParams, PyInt_FromLong(iBiasINT));
451  PyList_Append(icecalMainParams, PyInt_FromLong(iBiasCEINT));
452  PyList_Append(icecalMainParams, PyInt_FromLong(iBiasCEPZ));
453  PyList_Append(icecalMainParams, PyInt_FromLong(iBias0T));
454  PyList_Append(icecalMainParams, PyInt_FromLong(iBiasPZ));
455  PyList_Append(icecalMainParams, PyInt_FromLong(iBiasV0T));
456 
457  info("ICECAL Main Register (@SPI = [0x"+itohs(icecalMainAddr[3])+"..0x"+itohs(icecalMainAddr[0])+"]):","ICECALv3::getIcecalMain");
458  info(" ·DLL Control Voltage Output Enable: " + itos(vCtlOE) ,"ICECALv3::getIcecalMain");
459  info(" ·BXID Resynch Output Enable : " + itos(bxidSynOE) ,"ICECALv3::getIcecalMain");
460  info(" ·SPI Clock refresh Enable : " + itos(clkRefreshEn) ,"ICECALv3::getIcecalMain");
461  info(" ·Output Buffer bias : " + itos(iBiasOB) ,"ICECALv3::getIcecalMain");
462  info(" ·Track & Hold OpAmp bias (CE) : " + itos(iBiasCETH) ,"ICECALv3::getIcecalMain");
463  info(" ·Track & Hold OpAmp bias : " + itos(iBiasTH) ,"ICECALv3::getIcecalMain");
464  info(" ·Integrator OpAmp bias : " + itos(iBiasINT) ,"ICECALv3::getIcecalMain");
465  info(" ·Integrator OpAmp bias (CE) : " + itos(iBiasCEINT) ,"ICECALv3::getIcecalMain");
466  info(" ·Pole-Zero OpAmp bias (CE) : " + itos(iBiasCEPZ) ,"ICECALv3::getIcecalMain");
467  info(" ·0T bias : " + itos(iBias0T) ,"ICECALv3::getIcecalMain");
468  info(" ·Pole-Zero OpAmp bias : " + itos(iBiasPZ) ,"ICECALv3::getIcecalMain");
469  info(" ·0T bias (V0T) : " + itos(iBiasV0T) ,"ICECALv3::getIcecalMain");
470  }
471  return icecalMainParams;
472 }
473 
474 StatusCode ICECALv3::setMainReg(PyObject* icecalMainParams)
475 {
476  U16 txD[4];
477 
478  int vCtlOE, bxidSynOE, clkRefreshEn, iBiasOB, iBiasCETH, iBiasTH, iBiasINT;
479  int iBiasCEINT, iBiasCEPZ, iBias0T, iBiasPZ, iBiasV0T;
480 
481  vCtlOE = !PyInt_AsLong(PyList_GetItem(icecalMainParams,0)); //Active low.
482  bxidSynOE = !PyInt_AsLong(PyList_GetItem(icecalMainParams,1)); //Active low.
483  clkRefreshEn = !PyInt_AsLong(PyList_GetItem(icecalMainParams,2)); //Active low.
484  iBiasOB = PyInt_AsLong(PyList_GetItem(icecalMainParams,3));
485  iBiasCETH = PyInt_AsLong(PyList_GetItem(icecalMainParams,4));
486  iBiasTH = PyInt_AsLong(PyList_GetItem(icecalMainParams,5));
487  iBiasINT = PyInt_AsLong(PyList_GetItem(icecalMainParams,6));
488  iBiasCEINT = PyInt_AsLong(PyList_GetItem(icecalMainParams,7));
489  iBiasCEPZ = PyInt_AsLong(PyList_GetItem(icecalMainParams,8));
490  iBias0T = PyInt_AsLong(PyList_GetItem(icecalMainParams,9));
491  iBiasPZ = PyInt_AsLong(PyList_GetItem(icecalMainParams,10));
492  iBiasV0T = PyInt_AsLong(PyList_GetItem(icecalMainParams,11));
493 
494  txD[3] = ((vCtlOE & 0x1) << 15) | ((bxidSynOE & 0x1) << 14) | ((clkRefreshEn & 0x1) << 13) | ((iBiasOB & 0x3F) << 6) | (iBiasCETH & 0x3F);
495  txD[2] = ((iBiasTH & 0x3F) << 6) | (iBiasINT & 0x3F);
496  txD[1] = ((iBiasCEINT & 0x38) << 9) | ((iBiasCEPZ & 0x3F) << 6) | (iBias0T & 0x3F);
497  txD[0] = ((iBiasCEINT & 0x7) << 12) | ((iBiasPZ & 0x3F) << 6) | (iBiasV0T & 0x3F);
498 
499  //Four 16-bit registers are written.
500  err = 0;
501  for(int i=0;i<4;i++) err |= spiWriteSafe(icecalMainAddr[i],txD[i]);
502 
503  if(err) return StatusCode::FAILURE;
504  else return StatusCode::SUCCESS;
505 }
506 
512 
514 {
515  U16 rxRegData;
516  bool ok = true;
517  int iteration = 0;
518 
519  do{
520  //Data is sent and read back...
521  spiWrite(confRegAddr,confRegData);
522  rxRegData = spiRead(confRegAddr);
523 
524  //Exit conditions are computed.
525  ok = (rxRegData == confRegData);
526  iteration++;
527 
528  if(!ok) warning("Mismatch ("+itohs(iteration)+") in @SPI = 0x"+itohs(confRegAddr)+". Read: 0x"+itohs(rxRegData)+". Expected: 0x"+itohs(confRegAddr)+".","ICECALv3::spiWriteSafe");
529 
530  }while(!ok && iteration<= nRetries);
531 
532  if(!ok) error("Too many errors ("+itohs(iteration)+"). Check electronics!","ICECALv3::spiWriteSafe");
533  return !ok;
534 }
535 
536 //Basic reading operation...
537 U16 ICECALv3::spiRead(U8 confRegAddr, U8 offsetAddr)
538 {
539  U16 rxData;
540 
541  U8* buffer = confReg->io()->dataU8();
542  buffer[2] = confRegAddr + offsetAddr; //+128 = read
543 
544  if (confReg->read().isFailure())
545  {
546  warning("ICECALv3 read (@"+itohs(confRegAddr)+") error.","ICECALv3::spiRead");
547  err = true;
548  return 0;
549  }
550  else
551  {
552  err = false;
553  rxData = ((U16)buffer[1] * 256) + (U16)buffer[0];
554  debug("Register (@"+ itohs(confRegAddr) + ") = 0x" + itohs(rxData),"ICECALv3::spiRead");
555  return rxData;
556  }
557 
558 }
559 
560 //Basic writing operation...
562 {
563  U8* buffer = confReg->io()->dataU8();
564  buffer[2] = confRegAddr; //Frame = buffer<2>, buffer<1>, buffer<0>
565  buffer[1] = (confRegData >> 8) & 0xFF;
566  buffer[0] = confRegData & 0xFF;
567 
568  err = confReg->write().isFailure();
569 
570  if(err) warning("ICECALv3 write error.","ICECALv3::spiWrite");
571  else debug("ICECALv3 write (@"+ itohs(confRegAddr) + ") = 0x" + itohs(confRegData),"ICECALv3::spiWrite");
572 }
573 
575 // SPI Slave FER Test //
577 PyObject* ICECALv3::spiFERTest(long nTest)
578 {
579  long iTest, nBadTx=0, nBadRx=0, nFatal=0, nBad, regErrorHistogram[16];
580  int iFrame, iRetry, readOk, writeOk;
581  double fer;
582  U16 writeData = 0x0000;
583  U16 readData, retry;
584  PyObject* ferStatistics = PyList_New(0);
585  PyObject* confRegAddresses = PyList_New(0);
586  PyObject* confRegHistogram = PyList_New(0);
587 
588  U8 addr;
589  U8 confRegList[16] = {icecalMainAddr[0] , icecalMainAddr[1] , icecalMainAddr[2] , icecalMainAddr[3] , delayLineAddrCh[0] , delayLineAddrCh[1] , delayLineAddrCh[2] , delayLineAddrCh[3] ,
590  icecalLSBAddrCh[0], icecalLSBAddrCh[1], icecalLSBAddrCh[2], icecalLSBAddrCh[3], icecalMSBAddrCh[0] , icecalMSBAddrCh[1] , icecalMSBAddrCh[2] , icecalMSBAddrCh[3]};
591 
592  //Error histogram. This will compute the number of error in each register address.
593  for(int i=0 ; i<16 ; i++) regErrorHistogram[i] = 0;
594 
595  info("Starting SPI FER test...","ICECALv3::spiFERTest");
596 
597  //FER Test is performed N Times
598  for(iTest=0 ; iTest<nTest ; iTest++)
599  {
600  //For each test we check the 16 RW registers of the chip.
601  for(iFrame=0 ; iFrame<16 ; iFrame++)
602  {
603  addr = confRegList[iFrame];
604 
605  //Random data to be sent.
606  writeData = rand() + rand();
607 
608  //Write + Read back.
609  spiWrite(addr,writeData);
610  readData = spiRead(addr);
611 
612  //Data mismatch: let's see if it's a read, write or FATAL error;
613  if(writeData != readData)
614  {
615  //The number of coincidences are counted. This loop will break when 5 R/W coincidences are found or after 50 retrials.
616  iRetry = 0; readOk = 0; writeOk = 0;
617  do
618  {
619  retry = spiRead(addr);
620  if(retry == readData ) readOk++;
621  if(retry == writeData) writeOk++;
622  iRetry++;
623  }
624  while(readOk < 5 && writeOk < 5 && iRetry < 50);
625 
626  //Number of total errors according to the source.
627  if (iRetry >= 50) { error("Mismatch: the source of the SPI error could not be determined","ICECALv3::spiFER"); nFatal++; }
628  else if (readOk >= 5) { error("Mismatch: Write error @SPI = 0x"+itohs(addr)+". W = 0x"+itohs(writeData)+", R = 0x"+itohs(readData)+".","ICECALv3::spiFER"); nBadTx++; }
629  else { error("Mismatch: Read error @SPI = 0x"+itohs(addr)+". W = 0x"+itohs(writeData)+", R = 0x"+itohs(readData)+".","ICECALv3::spiFER"); nBadRx++; }
630 
631  //Number of total errors according to the number of SPI register.
632  regErrorHistogram[iFrame]++;
633  }
634  }
635  }
636  nBad = nFatal + nBadTx + nBadRx; //Global number of errors.
637  fer = (double)nBad / ((double)nTest * 16.0); //Frame Rate Error.
638 
639  for(iFrame=0 ; iFrame<16 ; iFrame++) PyList_Append(confRegAddresses, PyInt_FromLong(confRegList[iFrame])); //A list with the SPI @s.
640  for(iFrame=0 ; iFrame<16 ; iFrame++) PyList_Append(confRegHistogram, PyInt_FromLong(regErrorHistogram[iFrame])); //The number of errors in this SPI @s.
641 
642  //FER statistics list:
643  PyList_Append(ferStatistics, PyInt_FromLong(nBad)); //# Bad frames (global).
644  PyList_Append(ferStatistics, PyFloat_FromDouble(fer)); //Global FER (0 ~ 1).
645  PyList_Append(ferStatistics, PyInt_FromLong(nFatal)); //# Fatal frames.
646  PyList_Append(ferStatistics, PyInt_FromLong(nBadTx)); //# Bad TX frames.
647  PyList_Append(ferStatistics, PyInt_FromLong(nBadRx)); //# Bad RX frames.
648  PyList_Append(ferStatistics, confRegAddresses); //SPI @ list.
649  PyList_Append(ferStatistics, confRegHistogram); //SPI error counters list.
650 
651  warning("SPI BER test finished!!!");
652  return ferStatistics;
653 }
654 
656 
657 }
658 
659 //Get version of the ICECAL Chip:
661 {
662  U16 rxversion;
663  double major,minor,version;
664  string version_str;
665 
666  rxversion = spiRead(ICECAL_VERSION_ADDR, 0x00 );
667 
668  major = (double)((rxversion>>12) & 0x0F);
669  minor = (double)((rxversion >>8) & 0x0F);
670  version_str = itos(major) + "." + itos(minor);
671  version = atof( version_str.c_str() );
672 
673  info("ICECAL Version: " + ftos(version),"ICECALv3::version");
674  return version;
675 }
676 
678 {
679  U16 rxData;
680 
681  rxData = spiRead(BXID_RESYNCH_ADDR, 0x00 );
682 
683  info("RX = " + itohs(rxData),"");
684  return(rxData > 127);
685 
686 }
687 
689 {
690  U16 rxData;
691  unsigned int addr, rw, pumpRst, conf, regSel;
692 
693  for(addr=0; addr<256; addr++)
694  {
695  rw = (addr>>7);
696  pumpRst = (addr>>6) & 0x01;
697  conf = (addr>>5) & 0x01;
698  regSel = addr & 0x1F;
699 
700  rxData = spiRead( (U8) addr , 0x00 );
701  warning("R/!W="+itos(rw)+" PUMPrst="+itos(pumpRst)+" !CONF/STAT="+itos(conf)+" REGsel="+itos(regSel)+" ~ SPI(@=0x"+itohs(addr)+") = 0x"+itohs(rxData),"ICECALv3::spiAddressScan");
702  }
703 }
void info(std::string mymsg)
Definition: Object.h:38
int nRetries
Definition: ICECALv3.h:137
std::string itos(int)
Definition: Tools.cpp:46
#define BXID_RESYNCH_ADDR
Definition: ICECALv3.h:37
bool isFailure() const
Definition: StatusCode.h:68
ICECALv3()
Definition: ICECALv3.cpp:16
Register * confReg
Definition: ICECALv3.h:129
std::string ftos(float)
Definition: Tools.cpp:53
const int icecalMSBAddrCh[4]
Definition: ICECALv3.h:47
PyObject * getMainReg()
Definition: ICECALv3.cpp:415
void add(int attribut)
Definition: Attrib.h:67
virtual StatusCode write()
Definition: IOobject.h:80
PyObject * getAnalogCh(int ch)
Definition: ICECALv3.cpp:312
void setName(std::string name)
Definition: Object.h:51
void spiAddressScan()
Definition: ICECALv3.cpp:688
const int icecalMainAddr[4]
Definition: ICECALv3.h:50
PyObject * spiFERTest(long nTest)
Definition: ICECALv3.cpp:577
StatusCode dumpConfig(string configFile, PyObject *chipId)
Definition: ICECALv3.cpp:132
StatusCode setAnalogCh(int ch, PyObject *)
Definition: ICECALv3.cpp:361
virtual StatusCode read()
Definition: IOobject.h:73
StatusCode setMainReg(PyObject *)
Definition: ICECALv3.cpp:474
void setType(std::string type)
Definition: Object.h:52
unsigned char U8
Definition: ICECALv3.h:55
bool writeAsicParams(string fileName, PyObject *params)
Definition: ICECALv3.cpp:156
bool bxidResynchStatus()
Definition: ICECALv3.cpp:677
void error(std::string mymsg)
Definition: Object.h:40
void setId(unsigned char id)
Definition: Object.h:53
void debug(std::string mymsg)
Definition: Object.h:37
const int icecalLSBAddrCh[4]
Definition: ICECALv3.h:45
double version()
Definition: ICECALv3.cpp:660
int parseParameterList(string configFile, string paramName[64], int paramValue[64])
Definition: ICECALv3.cpp:77
void spiWrite(U8 confRegAddr, U16 confRegData)
Definition: ICECALv3.cpp:561
StatusCode setDelayLineCh(int ch, PyObject *)
Definition: ICECALv3.cpp:281
std::string itohs(int value)
Definition: ICECALv3.h:164
const int delayLineAddrCh[4]
Definition: ICECALv3.h:42
StatusCode setSubAddress(U32 subAddress)
Definition: IOdata.h:81
unsigned long U32
Definition: ICECALv3.h:53
PyObject * getDelayLineCh(int ch)
Definition: ICECALv3.cpp:246
U8 * dataU8()
Definition: IOdata.h:214
virtual void addChild(Hierarchy *element)
Definition: Hierarchy.cpp:83
PyObject * fillParams(string paramListRet[], int paramListLen, string paramName[64], int paramValue[64], int fileParamLen)
Definition: ICECALv3.cpp:106
#define ICECAL_VERSION_ADDR
Definition: ICECALv3.h:36
PyObject * loadConfig(string configFile)
Definition: ICECALv3.cpp:36
#define CALIBRATION_FILE_VER
Definition: ICECALv3.h:27
StatusCode setWordSize(IOdata::WordSize wordSize)
Definition: IOdata.h:126
unsigned short U16
Definition: ICECALv3.h:54
void defDataU8(unsigned long size)
Definition: IOdata.h:179
U16 spiRead(U8 confRegAddr, U8 offsetAddr=128)
Definition: ICECALv3.cpp:537
void warning(std::string mymsg)
Definition: Object.h:39
bool err
Definition: ICECALv3.h:139
IOdata * io()
Definition: IOobject.h:66
bool spiWriteSafe(U8 confRegAddr, U16 confRegData)
Definition: ICECALv3.cpp:513
void reset()
Definition: ICECALv3.cpp:655