/* Compile line: gcc -o altro-loopback{,.c} -I./TPCrdo_new/rcu -I./TPCrdo_new/fec -I/date/rorc -I/date/fec /date/rorc/Linux/{rorc_lib_q,rorc_ddl_q,rorc_aux}.o /date/fec/Linux/fec2rorc_lib.o -L./TPCrdo_new/rcu -L./TPCrdo_new/fec -L./TPCrdo_new/tools -lrcu -lfec -ltools */ #include #include #include /* for RCU lib */ #include #include #include #include chan_key *rorc; //u_int packageId=102; //u_int traceLevel=0; extern u_int packageId; extern u_int traceLevel; /* !!!! modified versions of the library functions !!!! */ int FEC_WPMEM_Sequence_BuildBC(u_int offset, u_int nwords, u_int *ped_data, u_int *im_seq); int FEC_PMEM_WriteBC(u_int offset, u_int nwords, u_int *pmem_data); int ddlReadDataBlock2(rorc_pci_dev_t *dev, unsigned long data_phys, unsigned long return_phys, rorcReadyFifo_t *rf, __u32 fee_address, long long int timeout, stword_t *stw, int *n_reply, int *step); int ddl_readBlock2 (chan_key *ptr, u_long fee_address, u_long *buffer, u_long buffer_size); /* !!!! modified versions of the library functions !!!! */ struct Event { unsigned long CDH[8]; int altro_data[0x1000][1025]; int altro_n10[0x1000]; unsigned long RCU_trailer[10]; }; const char *argp_program_version= "altro-loopback 0.9"; const char *argp_program_bug_address= ""; static const char doc[]= "A loopback test for the whole ALTRO-DAQ chain."; #define OPT_DDL_SERIAL 1 #define OPT_DDL_REVISION 2 #define OPT_DDL_CHANNEL 3 #define OPT_ACTIVE_FECS 4 #define OPT_LEAVE_ON 5 #define OPT_DUMP_TO_FILE 6 #define OPT_CONFIGURE_ONLY 7 static const struct argp_option options[]={ {"partition", 'p',"PARTITION", 0,"Use this partition"}, {"fecs", 'f',"FEC1[,FEC2...]",0,"Use these FECs"}, {"altros", 'a',"ALTRO1[,ALTRO2...]",0,"Use these ALTROs" " (for each selected card, though)"}, {"channels", 'c',"CHANNEL1[,CHANNEL2...]",0,"Use only these ADC channels" " (for each selected card and ALTRO, though)"}, {"ddl-serial", OPT_DDL_SERIAL,"SERIAL_NUMBER",0,"Use this RORC"}, {"ddl-revision", OPT_DDL_REVISION,"REVISION",0,"Use this revision"}, {"ddl-channel", OPT_DDL_CHANNEL,"CHANNEL",0,"Use this DDL-channel"}, {"active-fecs",OPT_ACTIVE_FECS,0,0,"Use the FECs that are allready active"}, {"configure-only",OPT_CONFIGURE_ONLY,0,0,"... and dont send any trigger"}, {"leave-on",OPT_LEAVE_ON,0,0,"Leave the FECs on after testing"}, {"number-of-samples",'n',"NSAMPLES", 0,"The number of samples"}, {"output-file", 'o',"FILENAME", 0,"Write errors into that file"}, {"verbose", 'v',0, 0,"Be verbose"}, {"dump-file",OPT_DUMP_TO_FILE,"FILENAME",0,"Write aquised data into that" " file"}, {"pattern", 'P',"PATTERN-TYPE", 0,"Use that pattern to check."}, {"reversed-order",'r',0, 0,"Use reversed order read-out."}, {"new-format",'N',0, 0,"Use the new (2+3x10) data format."}, { 0 } }; static const struct { const char *name; int id; } patterns[]={ {"ones", 0x3FF}, {"f", 0x3FF}, {"1", 0x3FF}, {"zeros", 0x000}, {"0", 0x000}, {"5", 0x155}, {"A", 0x2AA}, {"a", 0x2AA}, {"chess", 1}, {"chess2",2}, {"ramp", 3}, {"ramp2", 4}, {"0f", 5}, {0} }; struct arguments { rorc_node_t node; unsigned int fecs; int active_fecs; int leave_on; unsigned int altros; unsigned int channels; int partition; int n_samples; int n_triggers; int pattern_id; int verbose; int format; FILE *ofile; FILE *errorfile; }; static error_t parse_opt(int key,char *arg,struct argp_state *state) { int ret,i; FILE *f; const char *env; char varname[100]; struct arguments *arguments=(struct arguments*)state->input; int warn_mixed=0; char *token; char *arg_copy; switch (key) { case 'N': arguments->format=2; break; case 'r': arguments->format=1; break; case 'f': arguments->fecs=0x00000000; arg_copy=strdup(arg); token=strtok(arg_copy,","); do { int fec=atoi(token); if (0<=fec&&fec<=31) arguments->fecs|=1<altros=0x00; arg_copy=strdup(arg); token=strtok(arg_copy,","); do { int altro=atoi(token); if (0<=altro&&altro<=7) arguments->altros|=1<channels=0x00000000; arg_copy=strdup(arg); token=strtok(arg_copy,","); do { int channel=atoi(token); if (0<=channel&&channel<=31) arguments->channels|=1<verbose=1; break; case OPT_CONFIGURE_ONLY: arguments->n_triggers=0; break; case OPT_DDL_SERIAL: arguments->node.serial=atoi(arg); break; case OPT_DDL_REVISION: arguments->node.revision=atoi(arg); break; case OPT_DDL_CHANNEL: arguments->node.channel=atoi(arg); break; case OPT_ACTIVE_FECS: arguments->active_fecs=1; break; case OPT_LEAVE_ON: arguments->leave_on=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 'n': arguments->n_samples=atoi(arg); if (arguments->n_samples<0 || arguments->n_samples>1008) { fprintf(stderr,"error: invalid number of samples (%s) specified. Valid" " range is [0:1008]\n",arg); exit(1); } break; case OPT_DUMP_TO_FILE: arguments->ofile=fopen(arg,"wb"); if (!arguments->ofile) { fprintf(stderr,"error while opening file \"%s\" for writing: %s\n", arg,strerror(errno)); exit(1); } break; case 'o': arguments->errorfile=fopen(arg,"wb"); if (!arguments->errorfile) { fprintf(stderr,"error while opening file \"%s\" for writing: %s\n", arg,strerror(errno)); exit(1); } break; case 'P': for (i=0;patterns[i].name;++i) if (strcmp(arg,patterns[i].name)==0) { arguments->pattern_id=patterns[i].id; break; } if (!patterns[i].name) { fprintf(stderr,"error: No such pattern: %s\n",arg); exit(1); } break; case ARGP_KEY_END: if (arguments->fecs==0x00000000 && !arguments->active_fecs) { switch(arguments->partition) { case 0: arguments->fecs=0x1ff01ff; break; case 1: arguments->fecs=0xfff1fff; break; case 2: arguments->fecs=0x1ff01ff; break; case 3: arguments->fecs=0x3ff03ff; break; case 4: arguments->fecs=0x3ff03ff; break; case 5: arguments->fecs=0x3ff03ff; break; case -1: fprintf(stderr,"error: Neigther partition nor FEC specified.\n"); exit(1); break; } } if (!(arguments->node.serial==-1 &&arguments->node.revision==-1 &&arguments->node.channel==-1 || arguments->node.serial!=-1 &&arguments->node.revision!=-1 &&arguments->node.channel!=-1)) { warn_mixed=1; } if (arguments->node.serial==-1) { if (arguments->partition!=-1) { sprintf(varname,"RORC_SERIAL%d",arguments->partition); if (env=getenv(varname)) arguments->node.serial=atoi(env); else { fprintf(stderr,"No serial number specified (neigther via the" " commandline, nor via the 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->node.revision==-1) { if (arguments->partition!=-1) { sprintf(varname,"RORC_REVISION%d",arguments->partition); if (env=getenv(varname)) arguments->node.revision=atoi(env); else { fprintf(stderr,"No revision specified (neigther via thecommandline," " nor via the 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->node.channel==-1) { if (arguments->partition!=-1) { sprintf(varname,"RORC_CHANNEL%d",arguments->partition); if (env=getenv(varname)) arguments->node.channel=atoi(env); else { fprintf(stderr,"No channel number specified (neigther via the" " commandline, nor the via 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}; void print_arguments(struct arguments arguments) { int i; printf("DDL: serial=%d, revision=%d, channel=%d\n",arguments.node.serial, arguments.node.revision,arguments.node.channel); if (arguments.active_fecs) printf("Using active FECs only.\n"); else { printf("Used FECs:\n"); printf(" Branch A: "); for (i=0;i<16;++i) printf("%3d",i); printf("\n"); printf(" "); for (i=0;i<16;++i) printf("%3d",(arguments.fecs&(1<>offset&0x03FF; } unsigned int getword32(const unsigned char data[],int index) { return ( data[index*4+0]<<0 |data[index*4+1]<<8 |data[index*4+2]<<16 |data[index*4+3]<<24); } int decode_event(struct Event *decoded,unsigned char *data,int event_size, int n_samples) { int hwaddr; int i; int n10; int pos10; pos10=n10=event_size*32/40*4; for (hwaddr=0;hwaddr<0xFFF;++hwaddr) decoded->altro_n10[hwaddr]=-1; while (pos10>0) { int pos8=pos10/4*5; int hwaddr=(data[pos8-4]&0x0F)<<8|data[pos8-5]; int length=(data[pos8-2]&0x03)<<8|data[pos8-3]; int p1=data[pos8-1]<<6|data[pos8-2]>>2; int p2=data[pos8-4]>>4; if (p1!=0x2AAA || p2!=0xA || decoded->altro_n10[hwaddr]!=-1 || length != n_samples+2) { printf("error: wrong ALTRO trailer:\n"); printf("| %03x| %03x| %03x| %03x| (10 bits)\n", getword10(data,pos10-1),getword10(data,pos10-2), getword10(data,pos10-3),getword10(data,pos10-4)); printf("| %04x|%4d| %01x| %03x| (2AAA, length (decimal), A, " "channel address)\n",p1,length,p2,hwaddr); if (p1!=0x2AAA) printf(" (0x2AAA pattern wrong)\n"); if (p2!=0xA) printf(" (0xA pattern wrong)\n"); if (decoded->altro_n10[hwaddr]!=-1) printf(" (channel appears more then once)\n"); if (length != n_samples+2) printf(" (wrong length - should be %d)\n",n_samples+2); } pos10-=((length+3)/4+1)*4; if (pos10<0) { printf("ALTRO trailers are not consistent.\n"); return 1; } else { for (i=0;ialtro_data[hwaddr][i]=getword10(data,pos10+i); } decoded->altro_n10[hwaddr]=length-2; if (getword10(data,pos10+i)!=15+n_samples-1) { printf("error: channel with hwaddr %#05x: wrong time stamp (%d instead" " of %d)\n", hwaddr,getword10(data,pos10+i),15+n_samples-1); } ++i; if (getword10(data,pos10+i)!=n_samples+2) { printf("error: channel with hwaddr %#05x: chunk length (%d instead" " of %d)\n", hwaddr,getword10(data,pos10+i),n_samples+2); } ++i; for (;i%4;++i) if (getword10(data,pos10+i)!=0x2AA) printf("error: channel with hwaddr %#05x: wrong event padding " "(%#05x instead of 0x2AA).\n", hwaddr,getword10(data,pos10+i)); } } return 0; } int decode_event_reversed(struct Event *decoded,unsigned char *data, int event_size,int n_samples) { int hwaddr; int i; int n10; int pos10; // pos10=n10=event_size*32/40*4; n10=event_size*32/40*4; pos10=4; // points at data (after trailer) for (hwaddr=0;hwaddr<0xFFF;++hwaddr) decoded->altro_n10[hwaddr]=-1; while (pos10>2; int p2=data[pos8-4]>>4; if (p1==0x2AEE) { printf("corrected ALTRO trailer received:\n"); printf("| %03x| %03x| %03x| %03x| (10 bits)\n", getword10(data,pos10-1),getword10(data,pos10-2), getword10(data,pos10-3),getword10(data,pos10-4)); printf("| %04x|%4d| %01x| %03x| (2AEE, length (decimal), A, " "channel address)\n",p1,length,p2,hwaddr); /* pos10+=4; pos8=pos10/4*5; p1=data[pos8-1]<<6|data[pos8-2]>>2; p2=data[pos8-4]>>4; int hwaddr2=(data[pos8-4]&0x0F)<<8|data[pos8-5]; int length2=(data[pos8-2]&0x03)<<8|data[pos8-3]; printf("sent, wrong ALTRO trailer:\n"); printf("| %03x| %03x| %03x| %03x| (10 bits)\n", getword10(data,pos10-1),getword10(data,pos10-2), getword10(data,pos10-3),getword10(data,pos10-4)); printf("| %04x|%4d| %01x| %03x| (2AAA, length (decimal), A, " "channel address)\n",p1,length2,p2,hwaddr2); if (p1!=0x2AAA) printf(" (0x2AAA pattern wrong)\n"); if (p2!=0xA) printf(" (0xA pattern wrong)\n"); if (decoded->altro_n10[hwaddr]!=-1) printf(" (channel appears more then once)\n"); if (length2 != n_samples+2) printf(" (wrong length - should be %d)\n",n_samples+2); */ } else { if (p1!=0x2AAA || p2!=0xA || decoded->altro_n10[hwaddr]!=-1 || length != n_samples+2) { printf("error: wrong ALTRO trailer:\n"); printf("| %03x| %03x| %03x| %03x| (10 bits)\n", getword10(data,pos10-1),getword10(data,pos10-2), getword10(data,pos10-3),getword10(data,pos10-4)); printf("| %04x|%4d| %01x| %03x| (2AAA, length (decimal), A, " "channel address)\n",p1,length,p2,hwaddr); if (p1!=0x2AAA) printf(" (0x2AAA pattern wrong)\n"); if (p2!=0xA) printf(" (0xA pattern wrong)\n"); if (decoded->altro_n10[hwaddr]!=-1) printf(" (channel appears more then once)\n"); if (length != n_samples+2) printf(" (wrong length - should be %d)\n",n_samples+2); } } // pos10-=((length+3)/4+1)*4; if (pos10+((length+3)/4+1)*4>n10+4) { printf("ALTRO trailers are not consistent.\n"); return 1; } else { for (i=0;ialtro_data[hwaddr][i] =getword10(data,pos10+(length+3)/4*4-(i/4+1)*4+i%4); } decoded->altro_n10[hwaddr]=length-2; if (getword10(data,pos10+(length+3)/4*4-(i/4+1)*4+i%4)!=15+n_samples-1) { printf("error: channel with hwaddr %#05x: wrong time stamp (%d instead" " of %d)\n", hwaddr, getword10(data,pos10+(length+3)/4*4-(i/4+1)*4+i%4), 15+n_samples-1); } ++i; if (getword10(data,pos10+(length+3)/4*4-(i/4+1)*4+i%4)!=n_samples+2) { printf("error: channel with hwaddr %#05x: chunk length (%d instead" " of %d)\n", hwaddr, getword10(data,pos10+(length+3)/4*4-(i/4+1)*4+i%4), n_samples+2); } ++i; for (;i%4;++i) if (getword10(data,pos10+(length+3)/4*4-(i/4+1)*4+i%4)!=0x2AA) printf("error: channel with hwaddr %#05x: wrong event padding " "(%#05x instead of 0x2AA).\n", hwaddr, getword10(data,pos10+(length+3)/4*4-(i/4+1)*4+i%4)); } pos10+=((length+3)/4+1)*4; } return 0; } int decode_event_new(struct Event *decoded,unsigned char *data,int event_size, int n_samples) { int hwaddr; int i,j; for (hwaddr=0;hwaddr<0xFFF;++hwaddr) decoded->altro_n10[hwaddr]=-1; i=0; while (i>30)!=0x1) { printf("error: expected ALTRO trailer, but did not find any, try to re-align to next...\n"); while ((getword32(data,i)>>30)!=0x1 && i>16; decoded->altro_n10[hwaddr]=n10-2; ++i; int cl=getword32(data,i)>>20&0x3ff; int ts=getword32(data,i)>>10&0x3ff; if (ts!=15+n_samples-1) { printf("error: channel with hwaddr %#05x: wrong time stamp (%d instead" " of %d)\n", hwaddr, ts, 15+n_samples-1); } if (cl!=n_samples+2) { printf("error: channel with hwaddr %#05x: chunk length (%d instead" " of %d)\n", hwaddr, cl, n_samples+2); } for (j=2;jaltro_data[hwaddr][n10-1-j]=getword32(data,i+j/3)>>((2-j%3)*10)&0x3ff; } for (;j%3;++j) if (getword32(data,i+j/3)>>(j%3)&0x3ff != 0x000) { printf("error: channel with hwaddr %#05x: wrong event padding " "(%#05x instead of 0x000).\n", hwaddr, getword32(data,i+j/3)>>(j%3*10)&0x3ff); } i+=j/3; } return 0; } void loopback(int n_samples,unsigned int pmem[4][1008], struct Event *events[4],FILE* ofile,int format) { int ret; int event; int i; unsigned long *buffer; /* write data and generate the 4 software triggers */ printf("Writing data to ALTROs for event: "); for (event=0;event<4;++event) { printf("%d...",event+1);fflush(stdout); ret=FEC_PMEM_WriteBC(0,n_samples,pmem[event]); if (ret) { fprintf(stderr,"FEC_PMEM_WriteBC failed and returned: %d\n",ret); exit(1); } ret=RCU_Exec_SWTTRG(); if (ret) { fprintf(stderr,"RCU_SWTTRG failed and returned: %d\n",ret); exit(1); } usleep(100000); } printf("done.\n"); // TODO: BUG: the 2nd software trigger fucks up the hitlist memory u_long htlm[128]; for (i=0;i<128;++i) htlm[i]=0xFFFFFFFF; ret=RCU_HITM_Write(0,128,htlm); if (ret) { fprintf(stderr,"RCU_HTLM_Write failed and returned: %d\n",ret); exit(1); } /* read the 4 events */ if (!(buffer=malloc(2*4*(DDL_MAX_WORD+1)))) { fprintf(stderr,"error: malloc failed: %s\n",strerror(errno)); exit(1); } printf("Reading data from ALTROs for event: "); ret=rorcStartTrigger(&rorc->rorc,1000000,rorc->stw); if (ret) { fprintf(stderr,"error: rorcStartTrigger failed and returned %d.\n",ret); exit(1); } for (event=0;event<4;++event) { int length; printf("%d...",event+1);fflush(stdout); length=ddl_readBlock2(rorc,0,buffer,DDL_MAX_WORD+1); if (length<0) { fprintf(stderr,"error: ddl_readBlock2 failed and returned %d.\n",length); exit(1); } if (rorc->rf[0].status & 0x100) { int length2=ddl_readBlock2(rorc,0,buffer+length,DDL_MAX_WORD+1); if (length2<0) { fprintf(stderr,"error: ddl_readBlock2 failed and returned %d.\n", length2); exit(1); } length+=length2; } /* ignore CDH (first 7 words) and RCU trailer (last 10 words) */ printf("%d words, ",length);fflush(stdout); if (ofile) { fprintf(ofile,"#Event %d:\n\n",event+1); for (i=0;i>20&0x3ff,buffer[i]>>10&0x3ff,buffer[i]>>0&0x3ff); fprintf(ofile,"\n\n"); } switch (format) { case 1: decode_event_reversed(events[event],(unsigned char*)(buffer+(event==0?7:8)), length-(event==0?17:18),n_samples); break; case 0: decode_event(events[event],(unsigned char*)(buffer+(event==0?7:8)), length-(event==0?17:18),n_samples); break; case 2: decode_event_new(events[event],(unsigned char*)(buffer+(event==0?7:8)), length-(event==0?16:17),n_samples); break; } } ret=rorcStopTrigger(&rorc->rorc,1000000,rorc->stw); if (ret) { fprintf(stderr,"error: rorcStopTrigger failed and returned %d.\n",ret); exit(1); } printf("done.\n"); free(buffer); } void verify(unsigned int fecs,unsigned int altros,unsigned int channels, int n_samples,unsigned int pmem[4][1008],struct Event *events[4], FILE* errorfile) { int event,fec,altro,channel; int sample; printf("Verifying event: ");fflush(stdout); for (event=0;event<4;++event) { printf("%d...",event+1);fflush(stdout); for (fec=0;fec<32;++fec) if (fecs&1<altro_n10[hwaddr]==-1) { printf("error: event %d: FEC %d, ALTRO %d, channel %d " "(hwaddr %#05x): not present.\n", event,fec,altro,channel,hwaddr); if (errorfile) fprintf(errorfile,"%d %d %d %d all (not present)\n", event,fec,altro,channel); } else if (events[event]->altro_n10[hwaddr]!=n_samples) { printf("error: event %d: FEC %d, ALTRO %d, channel %d " "(hwaddr %#05x) did not send the right amount of " "data (%d instead of %d words).\n", event,fec,altro,channel,hwaddr, events[event]->altro_n10[hwaddr],n_samples); if (errorfile) fprintf(errorfile,"%d %d %d %d all (wrong amount of data" "- %d instead of %d words)\n", event,fec,altro,channel, events[event]->altro_n10[hwaddr],n_samples); } for (sample=0; samplealtro_n10[hwaddr]; ++sample) { if (events[event]->altro_data[hwaddr][sample] != pmem[event][sample]) { printf("error: event %d: FEC %d, ALTRO %d, channel %d " "(hwaddr %#05x): verification error in word %#05x: " "%#05x istead of %#05x.\n", event,fec,altro,channel,hwaddr,sample, events[event]->altro_data[hwaddr][sample], pmem[event][sample]); if (errorfile) fprintf(errorfile,"%d %d %d %d %d " "(%#05x instead of %#05x)\n", event,fec,altro,channel,sample, events[event]->altro_data[hwaddr][sample], pmem[event][sample]); } } } } printf("done.\n"); } void switchFECS(unsigned long fecs) { int active_fecs; int fec; int ret; ret=RCU_ACTFECLIST_Read(&active_fecs); if (ret) { fprintf(stderr,"RCU_ACTFECLIST_Read failed and returned: %d\n",ret); exit(1); } if (active_fecs & ~fecs) { printf("Switching off FEC ");fflush(stdout); for (fec=0;fec<32;++fec) { if ((active_fecs & ~fecs)&1<length = -1; rf->status = -1; rorcReset(dev, RORC_RESET_FF); if (pRorc(dev)) { pRorcInitCmdProc(dev); rorcPushFreeFifo(dev, data_phys, DDL_MAX_WORD, 0); pRorcWaitCmdProc(dev); } else { dRorcPushRxFreeFifo(dev, data_phys, DDL_MAX_WORD, 0); } debug("ddlReadDataBlock: push phys= 0x%08lx, return_phys = 0x%08lx\n", data_phys, return_phys); rorcStartDataReceiver(dev, return_phys); *step = 2; // wait for data last_DMA_count = rorcReadRxDmaCount(dev); j = 1; while(1) { i = 0; while (!rorcHasData(rf, 0)) { if (++i == timeout) { exit_code = RORC_TIMEOUT; break; } } if (exit_code == RORC_TIMEOUT) { DMA_count = rorcReadRxDmaCount(dev); if (interrupt_arrived || (DMA_count == last_DMA_count)) { debug("ddlReadDataBlock: RX DMA count (%d) did not change during the %d%s timeout period\n", DMA_count, j, th(j)); return (exit_code); } debug("ddlReadDataBlock: RX DMA count changed from %d to %d in timeout period of %lld loops\n", last_DMA_count, DMA_count, timeout); j++; last_DMA_count = DMA_count; exit_code = 0; continue; } debug("ddlReadDataBlock: Transfer done during the %d%s timeout period.\n", j, th(j)); break; } debug("ddlReadDataBlock: Data block arrived. Len = %ld (0x%lx), DTSTW = 0x%08lx\n", rf->length, rf->length, rf->status); return exit_code; } int ddl_readBlock2 (chan_key *ptr, u_long fee_address, u_long *buffer, u_long buffer_size) { int num_words; int n_reply; int step; int ret = 0; if (ptr->status != R_OPEN) { return R_NOT_OPEN_ERR; } ret = ddlReadDataBlock2( &(ptr->rorc), ptr->buffer_phys, ptr->return_phys, ptr->rf, fee_address, ptr->ustimeout, ptr->stw, &n_reply, &step); n_reply=1; if (ret == 0) { num_words = ptr->rf[n_reply-1].length; if (num_words > buffer_size) return ERR_SMALL_BUFFER; memset (buffer, 0x0, buffer_size*sizeof(u_long)); memcpy (buffer, ptr->buffer_addr, num_words*sizeof(u_long)); return num_words; // good return } else { return ret; } }