#ifndef ALTROPLAYER_H #define ALTROPLAYER_H #include #include #include #include #include /* for RCU lib */ #include #include #include chan_key *ddl; long data_size_total = 0; unsigned int active_fecs = 0; const char *argp_program_version="altro-player 1.0"; const char *argp_program_bug_address=""; static const char doc[]= "Loads the ALTRO pedestal memories to replay data from a ddl file."; #define OPT_DDL_SERIAL 1 #define OPT_DDL_REVISION 2 #define OPT_DDL_CHANNEL 3 static const struct argp_option options[]={ {"file" ,'f' ,"DDL-FILE" ,0,"The DDL file to be played" }, {"verbosity" ,'v' ,"VERBOSITY" ,0,"Set verbosity level (0-3, default=1)" }, {"zs-threshold" ,'z' ,"LEVEL" ,0,"Suppress samples below LEVEL (default=1)" }, {"acq-start" ,'s' ,"T" ,0,"Acquisition starts at time T (default=0)" }, {"acq-end" ,'e' ,"T" ,0,"Acquisition ends at time T (default=1000)" }, {"partition" ,'p' ,"PARTITION" ,0,"Use this partition to determine DDL from environment"}, {"keep-pmem" ,'k' ,0 ,0,"Dont erase PMEMs before writing (do it is default)" }, {"noconf" ,'n' ,0 ,0,"Dont configure ALTROs (do it is default)" }, {"baseline" ,'b' ,"LEVEL" ,0,"Use this value to clear the samples (default=0)" }, {"delay" ,'d' ,"DT" ,0,"Shift signals by DT timebins (default=0)" }, {"self-trigger" ,'t' ,0 ,0,"Software trigger, print rdo time (default no)" }, {"ddl-serial" ,OPT_DDL_SERIAL ,"SERIAL_NUMBER",0,"Use this RORC" }, {"ddl-revision" ,OPT_DDL_REVISION,"REVISION" ,0,"Use this RORC revision" }, {"ddl-channel" ,OPT_DDL_CHANNEL ,"CHANNEL" ,0,"Use this DDL-channel" }, { 0 } }; struct arguments { FILE *ddlfile; int rorc_serial; int rorc_revision; int rorc_channel; int partition; int acq_start; int acq_end; int verbosity; int zs_thr; int baseline; int dt; int pmem_clear; int trigger; int noconf; }; static error_t parse_opt(int key,char *arg,struct argp_state *state) { struct arguments *arguments=(struct arguments*)state->input; int warn_mixed=0; char varname[100]; const char *env; switch (key) { case OPT_DDL_SERIAL: arguments->rorc_serial=atoi(arg); break; case OPT_DDL_REVISION: arguments->rorc_revision=atoi(arg); break; case OPT_DDL_CHANNEL: arguments->rorc_channel=atoi(arg); break; case 't': arguments->trigger=1; break; case 's': arguments->acq_start=atoi(arg); break; case 'e': arguments->acq_end=atoi(arg); break; case 'k': arguments->pmem_clear=0; break; case 'n': arguments->noconf=1; break; case 'b': arguments->baseline=atoi(arg); break; case 'd': arguments->dt=atoi(arg); break; case 'z': if (arg) arguments->zs_thr=atoi(arg); else arguments->zs_thr=1; break; case 'v': if (arg) arguments->verbosity=atoi(arg); else arguments->verbosity=1; break; case 'f': arguments->ddlfile=fopen(arg,"rb"); if (!arguments->ddlfile) { fprintf(stderr,"Error: could not open DDL file.\n"); exit(1); } break; case 'p': if (arguments->partition!=-1) { fprintf(stderr,"Error: partition may be set only once.\n"); exit(1); } arguments->partition=atoi(arg); if (!(0<=arguments->partition&&arguments->partition<=5)) { fprintf(stderr,"Error: invalid argument: no such partition: %s\n",arg); exit(1); } break; case ARGP_KEY_END: if (!((arguments->rorc_serial==-1 &&arguments->rorc_revision==-1 &&arguments->rorc_channel==-1) || (arguments->rorc_serial!=-1 &&arguments->rorc_revision!=-1 &&arguments->rorc_channel!=-1))) { warn_mixed=1; } if (arguments->rorc_serial==-1) { if (arguments->partition!=-1) { sprintf(varname,"RORC_SERIAL%d",arguments->partition); if ((env=getenv(varname))) arguments->rorc_serial=atoi(env); else { fprintf(stderr, "No serial number specified (use either commandline or environment variable \"%s\".\n", varname); exit(1); } } else { fprintf(stderr, "No serial number specified and no partion given to get it from the environment.\n"); exit(1); } } if (arguments->rorc_revision==-1) { if (arguments->partition!=-1) { sprintf(varname,"RORC_REVISION%d",arguments->partition); if ((env=getenv(varname))) arguments->rorc_revision=atoi(env); else { fprintf(stderr, "No revision specified (use either commandline or environment variable \"%s\".\n", varname); exit(1); } } else { fprintf(stderr,"No revision number specified and no partion given to get it from the environment.\n"); exit(1); } } if (arguments->rorc_channel==-1) { if (arguments->partition!=-1) { sprintf(varname,"RORC_CHANNEL%d",arguments->partition); if ((env=getenv(varname))) arguments->rorc_channel=atoi(env); else { fprintf(stderr, "No channel number specified (use either commandline or environment variable \"%s\".\n", varname); exit(1); } } else { fprintf(stderr, "No channel number specified and no partion given to get it from the environment.\n"); exit(1); } } if (warn_mixed) { printf("warning: DDL serial number, revision and channel are defined partly via the\n" " commandline and partly via theenvironment.\n" " Are you sure that is what you want?\n"); } break; default: return ARGP_ERR_UNKNOWN; } return 0; } static struct argp argp={options,parse_opt,0,doc}; unsigned int imem_cache[4096]; int imem_cache_ptr=0; unsigned int get_w32(const unsigned char* data) { return data[3]<<24|data[2]<<16|data[1]<<8|data[0]; } //======================================================================== int exec_imem(int verbosity) { // unsigned int ff=0xffffffff; unsigned int busbsy; int ret; int nread; if (imem_cache_ptr==0) return 0; imem_cache[imem_cache_ptr++] = 0x38<<16; // END_SEQ while (imem_cache_ptr<4096) imem_cache[imem_cache_ptr++]=0xffffffff; if (verbosity>=3) printf("Write Imem...\n"); ret = rcu_write(ddl,0x0000,imem_cache,4096); if (ret) { fprintf(stderr, "Error: cannot write IMEM, rcu_write returned %d\n", ret); exit(-1); } if (verbosity>=3) printf("Done!\n"); imem_cache_ptr=0; if (verbosity>=3) printf("Execute...\n"); ret=rcu_write(ddl,0x5304,&ff,1); if (ret) { fprintf(stderr, "Error: cannot give EXESQ cmd, rcu_write returned %d\n", ret); exit(-1); } if (verbosity>=3) printf("Done!\n"); if (verbosity>=3) printf("Read BUSBSY...\n"); nread=1; do { ret=rcu_read(ddl,0x5116,&busbsy,&nread); } while (ret==0 && nread==1 && (busbsy & 0x1)); if (ret) { fprintf(stderr, "Error: cannot read BUSBSY reg, rcu_read returned %d\n", ret); exit(-1); } if (verbosity>=3) printf("Done!\n"); if (nread!=1) { fprintf(stderr, "Error: cannot read BUSBSY reg, rcu_read read %d instead of 1 word.\n", nread); exit(-1); } if (busbsy & 0x2) { fprintf(stderr, "Error: BUSBSY: last sequence failed.\n"); exit(-1); } return 0; } //======================================================================== int add_imem(unsigned int *imem,int nimem, int verbosity) { // int iimem=0; while (iimem=3) printf("Executing IMEM ...\n"); exec_imem(verbosity); if (verbosity>=3) printf("...Done!\n"); } } return 0; } //======================================================================== void clear_pmems(int baseline,int verbosity) { // unsigned int imem[4096]; int iimem; int t; // clear all pedestal memories in broadcast mode // (lower 1023 words only, but this is enough anyway) iimem=0; for (t=0;t<1023;++t) { imem[iimem++] = 0x2<<20 | 0x1<<18 | 0x0D; imem[iimem++] = t; imem[iimem++] = 0x2<<20 | 0x1<<18 | 0x07; imem[iimem++] = baseline&0x3ff; } add_imem(imem,iimem,verbosity); } //======================================================================== void write_channel(FILE *ddlfile,int acq_start,int acq_end,unsigned int header, int dt, int verbosity) { // unsigned int imem[4096]; int iimem; int t; int cw; int ci; int nread; int hwaddr; int nwords10; int nwords32; int i10; int si10; int i32; unsigned int w10; unsigned int w32; unsigned char buffer[4096]; int tmin; int tmax; hwaddr =header &0xfff; nwords10=header>>16&0x3ff; nwords32=(nwords10+2)/3; if (verbosity>=2) printf("Channel 0x%03x with %4d 10-bit (%3d 32-bit) words found (header: %08x).\n", hwaddr,nwords10,nwords32,header); nread=fread(buffer,1,4*nwords32,ddlfile); if (nread!=nwords32*4) { fprintf(stderr, "Error: hwaddr 0x%03x: reading of channel payload from file failed. Read %d instead of %d bytes.\n", hwaddr,nread,nwords32*4); exit(-1); } // check if FEC is on int fecaddr=(hwaddr>>7)&0x1f; if ( !((active_fecs)&(1<=1) printf("Warning: Channel 0x%03x (hwaddr) can not be written because FEC is currently off!\n", hwaddr); return; } tmin=1024; tmax=0; t =-1000000; cw=-1; ci= 0; iimem=0; for (i10=0;i10>si10) & 0x3ff; if (w32>>30 != 0x0) { fprintf(stderr,"Error: hwaddr 0x%03x: expected channel data, but read 0x%08x\n",hwaddr,w32); exit(-1); } if (cw<0) { cw=w10; if (verbosity>=3) printf("cw=%d\n",cw); } else if (t<=-1000000) { t=w10+dt; if (verbosity>=3) printf("ts=%d\n",t); } else { if (t<14) { fprintf(stderr, "Error: hwaddr 0x%03x: samples before t=14 are not supported (t=%d)...\n", hwaddr,t); exit(-1); } if (t>1022) { fprintf(stderr, "Error: hwaddr 0x%03x: samples after t=1022 are not supported (t=%d)...\n", hwaddr,t); exit(-1); } if (ttmax) tmax=t; if (ci==0 && w10==0x000) { if (t<=1021) { fprintf(stdout, "info: hwaddr 0x%03x: there must have been a bunch after t=%d. Adding a sample at t=%d with value 1023 to emulate it.\n ", hwaddr,t,t+1); if (t+1>tmax) tmax=t+1; imem[iimem++] = 0x2<<20 | hwaddr<<5 | 0x0D; imem[iimem++] = (t+1)-14; imem[iimem++] = 0x2<<20 | hwaddr<<5 | 0x07; imem[iimem++] = 0x3ff; ++data_size_total; } else fprintf(stderr, "warning: hwaddr 0x%03x: there must have been a bunch after t=%d. But I cannot add a sample there to emulate it (out of PMEM range).\n ", hwaddr,t); } if (ci==cw-1 && w10==0x000) { if (t<15) { fprintf(stdout, "info: hwaddr 0x%03x: there must have been a bunch before t=%d. Adding a sample at t=%d with value 1023 to emulate it.\n ", hwaddr,t,t-1); if (t-1>tmax) tmax=t-1; imem[iimem++] = 0x2<<20 | hwaddr<<5 | 0x0D; imem[iimem++] = (t-1)-14; imem[iimem++] = 0x2<<20 | hwaddr<<5 | 0x07; imem[iimem++] = 0x3ff; ++data_size_total; } else fprintf(stderr, "warning: there hwaddr 0x%03x: must have been a bunch before t=%d. But I cannot add a sample there to emulate it (out of PMEM range).\n ", hwaddr,t); } imem[iimem++] = 0x2<<20 | hwaddr<<5 | 0x0D; imem[iimem++] = t-14; imem[iimem++] = 0x2<<20 | hwaddr<<5 | 0x07; imem[iimem++] = w10; ++data_size_total; // printf("s(%d)=%d\n",t,w10); } --t; ++ci; if (ci==cw) { t=-1000000; cw=-1; ci= 0; } } if (cw!=-1) { fprintf(stderr, "Error: hwaddr 0x%03x: corrupted ALTRO data: cluster was not complete: read %d of %d words.", hwaddr,ci,cw); exit(-1); } if (tminacq_end) fprintf(stderr, "warning: hwaddr 0x%03x: data time range [%d:%d] extends specified acquisition time [%d:%d].\n", hwaddr,tmin,tmax,acq_start,acq_end); // for (i10=0;i10<1024;++i10)printf("%03x ",pmem[i10]);printf("\n"); if (acq_start<0) acq_start=tmin; if (acq_end <0) acq_end =tmax; // imem[iimem++] = 0x2<<20 | hwaddr<<5 | 0x0A; // write | hwaddr | TRCFG // imem[iimem++] = (acq_start&0x3ff)<<10 | (acq_end&0x3ff); // ACQ_START=acq_start | ACQ_END=acq_end add_imem(imem,iimem, verbosity); } //======================================================================== void write_pmem(FILE* ddlfile,int acq_start,int acq_end,int dt,int verbosity) { // int i,n; unsigned char buffer[4096]; int is_last; unsigned int w32; int channels[4096]; int nchannels, hwaddr; n=fread(buffer,1,32,ddlfile); if (n!=32) { fprintf(stderr,"Error: reading of CDH from file failed. Read %d instead of 32 bytes.\n",n); exit(-1); } if (verbosity>=2) for (i=0;i<8;++i) printf("CDH word %d: 0x%08x\n",i,get_w32(&buffer[i*4])); nchannels=0; is_last=0; do { n=fread(buffer,1,4,ddlfile); w32=get_w32(buffer); if (n!=4) { fprintf(stderr,"Error: reading of payload header word failed.\n"); exit(-1); } switch (w32>>30) { case 0x0: fprintf(stderr,"Error: expected either channel header or RCU trailer, but received 0x%08x\n",w32); exit(-1); break; case 0x1: hwaddr=w32&0xfff; // check if FEC is on and write int fecaddr=(hwaddr>>7)&0x1f; if ( ((active_fecs)&(1<=2) printf("RCU trailer word: 0x%08x\n",w32); break; case 0x3: if (verbosity>=2) printf("RCU trailer word: 0x%08x (last)\n",w32); is_last=1; break; } } while (!is_last); } //======================================================================== void readAFL(int verbosity) { // int nread; int ret; nread=1; ret=rcu_read(ddl,0x5100,&active_fecs,&nread); if (ret || nread==0) { fprintf(stderr, "Error: cannot read ACTFECLIST reg, rcu_read returned %d (%d words read)\n", ret,nread); exit(-1); } active_fecs=active_fecs&0xFFFFFFFF; if (verbosity>=1) printf("AFL is 0x%x\n",active_fecs); } //======================================================================== void config_altros(int acq_start,int acq_end,int zs_thr, int verbosity) { // unsigned int imem[4096]; int iimem; if (acq_start<0) acq_start= 0; if (acq_end <0) acq_end =1000; imem[iimem++] = 0x1<<20 | 1<<18 | 0x1D; // command | broad cast | ERCLR imem[iimem++] = 0x1<<20 | 1<<18 | 0x1C; // command | broad cast | TRCLR imem[iimem++] = 0x2<<20 | 1<<18 | 0x00; // write | broad cast | K1 imem[iimem++] = 0x0000; // K1=0 imem[iimem++] = 0x2<<20 | 1<<18 | 0x01; // write | broad cast | K2 imem[iimem++] = 0x0000; // K2=0 imem[iimem++] = 0x2<<20 | 1<<18 | 0x02; // write | broad cast | K3 imem[iimem++] = 0x0000; // K3=0 imem[iimem++] = 0x2<<20 | 1<<18 | 0x03; // write | broad cast | L1 imem[iimem++] = 0x0000; // K1=0 imem[iimem++] = 0x2<<20 | 1<<18 | 0x04; // write | broad cast | L2 imem[iimem++] = 0x0000; // L2=0 imem[iimem++] = 0x2<<20 | 1<<18 | 0x05; // write | broad cast | L3 imem[iimem++] = 0x0000; // L3=0 imem[iimem++] = 0x2<<20 | 1<<18 | 0x06; // write | broad cast | VFPED imem[iimem++] = 0x000; // FPD=0x000 imem[iimem++] = 0x2<<20 | 1<<18 | 0x08; // write | broad cast | ZSTHR imem[iimem++] = 0x000<<10 | (zs_thr&0x3ff); // OFFSET=0x000 | ZS_THR=zs_thr imem[iimem++] = 0x2<<20 | 1<<18 | 0x09; // write | broad cast | BCTHR imem[iimem++] = 0x000<<10 | 0x000; // THR_HI=0x000 | THR_LO=0x000 imem[iimem++] = 0x2<<20 | 1<<18 | 0x0A; // write | broad cast | TRCFG imem[iimem++] = (acq_start&0x3ff)<<10 | (acq_end&0x3ff); // ACQ_START=acq_start | ACQ_END=acq_end imem[iimem++] = 0x2<<20 | 1<<18 | 0x0B; // write | broad cast | DPCFG imem[iimem++] = 0x80<<12 | 0x00<<5 | 0x0A;// ZS_CFG=enable,no pre- or post-samples,no glitch filter | BC2_CFG=disable | BC1_CFG=f(t)-fpd imem[iimem++] = 0x2<<20 | 1<<18 | 0x0C; // write | broad cast | DPCF2 imem[iimem++] = 0x0<<6 | 0x0<<5 | 0x0<<4 | 0x0; // PWSV=off | FLT_EN=off | NBUF=4 | PTRG=0 add_imem(imem,iimem, verbosity); } //======================================================================== void trigger() { // unsigned int ff=0x8; unsigned int rdo_time; int nread; int ret; // STRG command ff=0xffffffff; ret=rcu_write(ddl,0x5306,&ff,1); if (ret) { fprintf(stderr, "Error: cannot give 1st STRG cmd, rcu_write returned %d\n", ret); exit(-1); } usleep(900000); // Read RDO time nread=1; ret=rcu_read(ddl,0x5132,&rdo_time,&nread); if (ret || nread==0) { fprintf(stderr, "Error: cannot read RDOTIME reg, rcu_read returned %d (%d words read)\n", ret,nread); exit(-1); } printf("sparse read-out time: %6u cycles",rdo_time); //printf("%6lu\t%6u\n", data_size_total, rdo_time); // Configure full rdo usleep(900000); ff=0x8; ret=rcu_write(ddl,0x5103,&ff,1); if (ret) { fprintf(stderr, "Error: cannot write readout reg for full readout, rcu_write returned %d\n", ret); exit(-1); } // Give STRG again ret=rcu_write(ddl,0x5306,&ff,1); if (ret) { fprintf(stderr, "Error: cannot give 2nd STRG cmd, rcu_write returned %d\n", ret); exit(-1); } usleep(900000); // Read RDO time again nread=1; ret=rcu_read(ddl,0x5132,&rdo_time,&nread); if (ret || nread==0) { fprintf(stderr, "Error: cannot read RDOTIME reg, rcu_read returned %d (%d words read)\n", ret,nread); exit(-1); } printf(" full read-out time: %6u cycles.\n", rdo_time); //printf("%6lu\t%6u\n", data_size_total, rdo_time); // Set back to SPARSE RDO ff=0xc; ret=rcu_write(ddl,0x5103,&ff,1); if (ret) { fprintf(stderr, "Error: cannot write readout reg to set it back to Sparse, rcu_write returned %d\n", ret); exit(-1); } } #endif // ALTROPLAYER_H