/*:>-------------------------------------------------------------------- **: FILE: mMvdFEM.c **: HISTORY: **: 00jan93-v000a-hpl- Created by stic Version **: Id: idl.y,v 1.2 1998/02/03 22:21:05 dave Exp **:<------------------------------------------------------------------*/ #include "mMvdFEM.h" void MvdMess_(char *name_of_function, short ierror, short level, char *message, ...); short bitcount10(short input); short vert_checksum ( TABLE_HEAD_ST *FEM_h, DMVDFEM_ST *FEM ); #define NO_ERROR 0 /* used for mesage output with no error */ #define ERROR1 1 /* illegal strip address */ #define ERROR2 2 /* illegal pad address */ #define LOUD 2 /* messages which are usually output */ #define QUIET 1 /* used for messages which are output at default setting */ #define SILENT 0 /* for messages which are usually not output */ #define NRESET 10000 /* number of clock ticks at which integrator reset is sent */ #define MAXAMU 63 /* number of AMU cells on AMU/ADC chip */ #define CAV_1 0X3FF /* 1st 10 bits on */ #define CAV_2 0 /* all bits off */ #define MVDID 0x800 /* 2 in upper 8 bits (MVD detector ID is 2) */ #define N_USER_WORDS 8 /* number of user words in output table */ #define MAXADC 256 /* number of ADCs per MCM */ #define MAXPANEL 12 /* number of panels per row in the barrel */ #define MAXROW 6 /* number of rows per shell in the barrel */ #define MAXSHELL 2 /* number of shells in the barrel */ #define MAXWEDGE 12 /* number of wedges in each endcap (pads) */ #define MAXEND 2 /* number of endcaps */ #define MAXROWPAD 21 /* max number of "rows" in each wedge */ #define MAXCOLUMN 12 /* max number of columns per wedge */ #define PADADCOFFSET 2 /* first pad detector channel is connected*/ /* to 3rd MCM input in pad detectors */ long mMvdFEM_( TABLE_HEAD_ST *bRaw_h, DMVBRAW_ST *bRaw , TABLE_HEAD_ST *cRaw_h, DMVCRAW_ST *cRaw , TABLE_HEAD_ST *FEM_h, DMVDFEM_ST *FEM ) { /*:>-------------------------------------------------------------------- **: ROUTINE: mMvdFEM_ **: DESCRIPTION: This module takes the staf "raw data" data tables for **: the MVD as input and generates "packets" in the format **: used by the MVD's DCM/IM modules as output. **: AUTHOR: J.P. Sullivan sullivan@lanl.gov 10-Jul-98 **: ARGUMENTS: **: IN: **: bRaw - raw data table for the barrel **: bRaw_h - header Structure for bRaw **: cRaw - raw data table for the endcaps (pads) **: cRaw_h - header Structure for cRaw **: INOUT: **: OUT: **: FEM - output table organized like DCM/IM packets **: FEM_h - header Structure for FEM **: RETURNS: STAF Condition Value **: **: HISTORY: **: JPSullivan 21-Jul-98 changed bitcount to count only 10 bits and changed the name to bitcount10. **:>------------------------------------------------------------------*/ static short clock=0; /* use as a primitive clock counter */ static int event=0; /* use as a primitive event counter */ static short amu1=-1; /* counts next amu cell, start from */ /* -1 so it is 0 after 1st increment*/ short amu2; int i; /* loop counter */ short nmcm; /* MCM number */ short ndcm; /* DCM number */ short nplex; /* either 0 or 1 -- used as part of */ /* multi-plexing of data in one DCM */ short parity; /* local copy of parity checksum */ int iadc,ipanel,irow,ishell;/* for loops */ int iwedge,iend; /* for loops */ short shell, row, cell, strip; /* local copies of contents of staf */ /* table, which are used in some cases */ /* to make the code more readable */ short wedge, end, column; /* local copies of endcap variables */ short nadc; /* adc number used as temp variable in */ /* a few places */ short MAX_MCM_BARREL=144; /* number of MCM's addresses in barrel,*/ /* which is not the number of MCM's in */ /* the barrel -- addresses are assigned*/ /* even for locations in the "hole" in */ /* the outer layer */ short bit11=0x400; /* bit 11 set */ short adc_parity; /* used to set parity bit in ADC's */ short adc_barrel[256][12][6][2]; short adc_pad[256][12][2]; /**********************************************************************/ MvdMess_("mMvdFEM",NO_ERROR,LOUD, "\nmMvdFEM{" ); /**********************************************************************/ /* This first section sets the various counters which are expected to */ /* appear in the MCM's output data */ clock++; /* increment clock counter */ if ( clock>NRESET ) clock=0; /* reset at NRESET clock counts */ event++; /* increment event counter */ amu1++; /* increment amu1 counter */ if ( amu1>MAXAMU ) amu1=0; /* reset to zero when it gets to */ /* the max allowed value */ amu2=amu1+1; /* assume second amu cell is */ /* immediately after the first */ if ( amu2>MAXAMU ) amu2=0; /* reset to zero when it gets to */ /* the max allowed value */ MvdMess_("mMvdFEM",NO_ERROR,SILENT, "\tclock=%d event=%d amu1=%d amu2=%d", clock, event, amu1, amu2); /************************************************************************/ /* This section prepares the ADC values given the raw data */ /* start by initializing all the arrays */ for (iadc=0; iadcnok ; i++ ) { strip = bRaw[i].strip; cell = bRaw[i].cell; row = bRaw[i].row; shell = bRaw[i].shell; if ( strip=0 && cell=0 && row=0 && shell=0 ) { adc_barrel[strip][cell][row][shell] += bRaw[i].adc; } else { MvdMess_("mMvdFEM",ERROR1,LOUD, "\tillegal strip address strip=%d cell=%d row=%d shell=%d", strip, cell, row, shell); } } for ( i=0 ; inok ; i++ ) { wedge = cRaw[i].wedge; end = cRaw[i].end; row = cRaw[i].row; column= cRaw[i].column; if ( wedge=0 && end=0 && row=0 && column=0 ) { nadc = row + column*MAXROWPAD + PADADCOFFSET; adc_pad[nadc][wedge][end] += cRaw[i].adc; } else { MvdMess_("mMvdFEM",ERROR2,LOUD, "\tillegal pad address wedge=%d end=%d row=%d column=%d", wedge, end, row, column); } } /* next, fill the output structures from these ADC arrays */ FEM_h->nok=0; /* start with nothing in the output */ /* put in the data from the strip detectors */ for ( ishell=0; ishell3 || ipanel<2 || ipanel>9 ) { nmcm = ipanel + irow*MAXPANEL + ishell*(MAXROW*MAXPANEL); ndcm = nmcm/2; nplex= nmcm - ndcm*2; FEM[FEM_h->nok].CAV1 = CAV_1; FEM[FEM_h->nok].det = MVDID; FEM[FEM_h->nok].Ecounter = event; FEM[FEM_h->nok].adr = ndcm*4 + nplex; /* low two bits are "plex" */ /* the rest is the dcm address */ FEM[FEM_h->nok].Flag = 0; /* I'm not sure what this is */ FEM[FEM_h->nok].Bcounter = clock; FEM[FEM_h->nok].amucells = 256*amu2 + amu1; /* high byte, low byte are */ /* 2nd, 1st ADC cells used */ /* next come the user words */ for ( i=0; inok].user[i] = 0; } /* the ADC values: */ for ( nadc=0; nadcnok].adc[nadc] = adc_barrel[nadc][ipanel][irow][ishell]; adc_parity = bitcount10(FEM[FEM_h->nok].adc[nadc]); if ( adc_parity%2 ) { /* set bit 11 if an odd number of bits are set in adc */ FEM[FEM_h->nok].adc[nadc] = FEM[FEM_h->nok].adc[nadc] | bit11; } } /* the stuff at the end: */ parity = vert_checksum( FEM_h, FEM ); FEM[FEM_h->nok].parity = parity; /* now save the bit sum -- I'm not sure */ /* if this is what the parity word will */ /* really be, but its a good guess */ FEM[FEM_h->nok].CAV2 = CAV_2; /* all bits off at end */ MvdMess_("mMvdFEM",NO_ERROR,SILENT, "\tstrips:panel=%d row=%d shell=%d FEM_h->nok=%d nmcm=%d ndcm=%d nplex=%d", ipanel, irow, ishell, FEM_h->nok, nmcm, ndcm, nplex ); MvdMess_("mMvdFEM",NO_ERROR,SILENT, "\tadr=%d amucells=%d 1st 2 ADC values=%x %x last 2=%x %x", FEM[FEM_h->nok].adr, FEM[FEM_h->nok].amucells, FEM[FEM_h->nok].adc[0], FEM[FEM_h->nok].adc[1],FEM[FEM_h->nok].adc[254], FEM[FEM_h->nok].adc[255]); FEM_h->nok++; /* now increment the number of rows in the table */ } } /* next come the pad detectors */ for ( iend=0; iendnok].CAV1 = CAV_1; FEM[FEM_h->nok].det = MVDID; FEM[FEM_h->nok].Ecounter = event; FEM[FEM_h->nok].adr = ndcm*4 + nplex; /* low two bits are "plex" */ /* the rest is the dcm address */ FEM[FEM_h->nok].Flag = 0; /* I'm not sure what this is */ FEM[FEM_h->nok].Bcounter = clock; FEM[FEM_h->nok].amucells = 256*amu2 + amu1; /* high byte, low byte are */ /* 2nd, 1st ADC cells used */ /* next come the user words */ for ( i=0; inok].user[i] = 0; } /* now the ADC values */ for ( nadc=0; nadcnok].adc[nadc] = adc_pad[nadc][iwedge][iend]; adc_parity = bitcount10(FEM[FEM_h->nok].adc[nadc])%2; if ( adc_parity%2 ) { /* set bit 11 if an odd number of bits are set in adc */ FEM[FEM_h->nok].adc[nadc] = FEM[FEM_h->nok].adc[nadc] | bit11; } /* if ( FEM[FEM_h->nok].adc[nadc]>0 ) { printf ( "adc%d=%x ",nadc,FEM[FEM_h->nok].adc[nadc]); if ( (nadc+1)%25 == 0 ) printf ("\n"); } */ } /* the words at the end: */ parity = vert_checksum( FEM_h, FEM ); FEM[FEM_h->nok].parity = parity; FEM[FEM_h->nok].CAV2 = CAV_2; /* all bits off at end */ MvdMess_("mMvdFEM",NO_ERROR,SILENT, "\tpads: wedge=%d end=%d FEM_h->nok=%d nmcm=%d ndcm=%d nplex=%d", iwedge, iend, FEM_h->nok, nmcm, ndcm, nplex); MvdMess_("mMvdFEM",NO_ERROR,SILENT, "\tadr=%d amucells=%d 1st 2 ADC values=%x %x last 2=%x %x", FEM[FEM_h->nok].adr, FEM[FEM_h->nok].amucells, FEM[FEM_h->nok].adc[2], FEM[FEM_h->nok].adc[3],FEM[FEM_h->nok].adc[252],FEM[FEM_h->nok].adc[253]); FEM_h->nok++; /* now increment the number of rows in the table */ } MvdMess_("mMvdFEM",NO_ERROR,LOUD,"}"); return STAFCV_OK; } short bitcount10(short input) /* This function was written by J.P.Sullivan 21-Jul-98. /* count non-zero bits in a 10 bit word */ { short count; short ibits[10]={1,2,4,8,0x10,0x20,0x40,0x80,0x100,0x200}; short i; count=0; for (i=0;i<10;i++) { if ( input&ibits[i] ) count++; } return count; } short vert_checksum ( TABLE_HEAD_ST *FEM_h, DMVDFEM_ST *FEM ) /* This function was written by J.P.Sullivan 10-Jul-98. It is intended to */ /* construct the checksum which appears in each MVD data packet. This */ /* checksum is constructed from the ADC data words and is summed across */ /* all the ADC words. The 1st bit of the checksum is the XOR of first bit */ /* of all data words, the 2nd bit of the checksum from the 2nd bit of all */ /* data words, etc. This word is sometimes called the "vertical checksum" */ /* -- from which I take the name of the function. */ /* I am not certain which words are intended to be included in the */ /* checksum -- I have assumed only the ADCs, but it is possible that the */ /* header/trailer words need to be included too */ { short nbit; short nadc; short result; short exor; short ibits[11]={1,2,4,8,0x10,0x20,0x40,0x80,0x100,0x200,0x400}; short one=1; result=0; for (nbit=0; nbit<12; nbit++){ exor=0; for ( nadc=0; nadc<256; nadc++){ if ( ibits[nbit]&FEM[FEM_h->nok].adc[nadc] ) exor = exor^one; } if ( exor>0 ) result=result|ibits[nbit]; } return result; }