• Main Page
  • Related Pages
  • Data Structures
  • Files
  • File List
  • Globals

llcontrol.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002  *
00003  * File: llcontrol.c
00004  *
00005  * $RCSfile: llcontrol.c,v $
00006  * 
00007  * Copyright (C) 2001 D-TACQ Solutions Ltd
00008  * not to be used without owner's permission
00009  *
00010  * Description:
00011  *     application implementing the LOW LATENCY CONTROL feture
00012  *
00013 <<<<<<< llcontrol.c
00014  * $Id: llcontrol.c,v 1.30.2.43 2010/08/26 16:25:52 pgm Exp $
00015 =======
00016  * $Id: llcontrol.c,v 1.30.2.43 2010/08/26 16:25:52 pgm Exp $
00017 >>>>>>> 1.30.2.8.2.9
00018  * $Log: llcontrol.c,v $
00019  * Revision 1.30.2.43  2010/08/26 16:25:52  pgm
00020  * more switchable instrumentation
00021  *
00022  * Revision 1.30.2.42  2009/09/29 13:09:14  pgm
00023  * RFM emulation (not complete)
00024  *
00025  * Revision 1.30.2.41  2009/08/13 19:15:32  pgm
00026  * ALT doc
00027  *
00028  * Revision 1.30.2.40  2009/08/06 18:31:42  pgm
00029  * README.RFM
00030  *
00031  * Revision 1.30.2.39  2009/04/02 13:19:01  pgm
00032  * docs away
00033  *
00034  * Revision 1.30.2.38  2009/03/28 22:23:05  pgm
00035  * ao32cpci first cut looks good
00036  *
00037  * Revision 1.30.2.37  2009/03/28 18:47:39  pgm
00038  * sync2VAO32 take 1
00039  *
00040  * Revision 1.30.2.36  2007/02/19 15:22:23  pgm
00041  * *** empty log message ***
00042  *
00043  * Revision 1.30.2.35  2006/01/18 14:55:24  pgm
00044  * *** empty log message ***
00045  *
00046  * Revision 1.30.2.34  2006/01/15 11:18:18  pgm
00047  * SYNC_2V
00048  *
00049  * Revision 1.30.2.33  2006/01/09 13:40:31  pgm
00050  * SYNC_2V mode implemented
00051  *
00052  * Revision 1.30.2.32  2005/12/07 10:21:14  pgm
00053  * *** empty log message ***
00054  *
00055  * Revision 1.30.2.31  2005/12/06 21:22:40  pgm
00056  * ACQ216HS channels=2 pulls in antiphase
00057  *
00058  * Revision 1.30.2.30  2005/12/06 18:11:31  pgm
00059  * ACQ216HS (ChannelMask) option
00060  *
00061  * Revision 1.30.2.29  2005/11/30 12:03:36  pgm
00062  * *** empty log message ***
00063  *
00064  * Revision 1.30.2.28  2005/11/30 11:51:09  pgm
00065  * *** empty log message ***
00066  *
00067  * Revision 1.30.2.27  2005/11/30 10:52:53  pgm
00068  * *** empty log message ***
00069  *
00070  * Revision 1.30.2.26  2005/11/04 17:26:18  pgm
00071  * *** empty log message ***
00072  *
00073  * Revision 1.30.2.25  2005/10/22 19:38:36  pgm
00074  * *** empty log message ***
00075  *
00076  * Revision 1.30.2.24  2005/10/20 20:51:00  pgm
00077  * *** empty log message ***
00078  *
00079  * Revision 1.30.2.23  2005/10/03 15:03:48  pgm
00080  * acq216 llc with prams
00081  *
00082  * Revision 1.30.2.22  2005/09/25 20:31:50  pgm
00083  * samples
00084  *
00085  * Revision 1.30.2.21  2005/08/12 20:28:20  pgm
00086  * *** empty log message ***
00087  *
00088  * Revision 1.30.2.20  2005/08/12 09:51:25  pgm
00089  * *** empty log message ***
00090  *
00091  * Revision 1.30.2.19  2005/08/11 10:02:24  pgm
00092  * SYNC_ECM - init host side slave memory areas
00093  *
00094  * Revision 1.30.2.18  2005/08/01 12:39:55  pgm
00095  * includes bridge test
00096  *
00097  * Revision 1.30.2.17  2005/08/01 11:10:24  pgm
00098  * V2 part 1 running - local status, no hbpoll - ECM 100 acheived
00099  *
00100  * Revision 1.30.2.16  2004/12/13 21:39:15  pgm
00101  * correct DAC base offset
00102  *
00103  * Revision 1.30.2.15  2004/12/10 12:01:26  pgm
00104  * fix timing
00105  *
00106  * Revision 1.30.2.14  2004/12/09 22:31:57  pgm
00107  * microsecond timestamps do the BIZ - ECM20 here we go
00108  *
00109  * Revision 1.30.2.13  2004/12/09 12:58:34  pgm
00110  * various attempts at repartitioning for speed
00111  *
00112  * Revision 1.30.2.12  2004/11/04 07:14:02  pgm
00113  * w
00114  *
00115  * Revision 1.30.2.11  2004/11/04 07:13:13  pgm
00116  * merged multicard case
00117  *
00118 <<<<<<< llcontrol.c
00119  * Revision 1.30.2.10  2004/09/25 08:40:16  pgm
00120  * last commit in WRONG BRANCH
00121  *
00122  * Revision 1.30.2.9  2004/09/25 08:35:55  pgm
00123  * test mod
00124  *
00125 =======
00126  * Revision 1.30.2.8.2.9  2004/09/28 18:15:40  pgm
00127  * release to pcdaqdpcs
00128  *
00129  * Revision 1.30.2.8.2.8  2004/09/28 06:00:06  pgm
00130  * two card case
00131  *
00132  * Revision 1.30.2.8.2.7  2004/09/26 19:50:58  pgm
00133  * *** empty log message ***
00134  *
00135  * Revision 1.30.2.8.2.6  2004/09/26 15:28:40  pgm
00136  * *** empty log message ***
00137  *
00138  * Revision 1.30.2.8.2.5  2004/09/26 11:32:38  pgm
00139  * multiboard tstats pollstats in
00140  *
00141  * Revision 1.30.2.8.2.4  2004/09/25 21:16:28  pgm
00142  * multiboard case runs
00143  *
00144  * Revision 1.30.2.8.2.3  2004/09/25 11:53:03  pgm
00145  * first pass multi done - check it works for n==1
00146  *
00147  * Revision 1.30.2.8.2.2  2004/09/25 09:08:31  pgm
00148  * first UI/test split
00149  *
00150  * Revision 1.30.2.8.2.1  2004/09/25 08:40:57  pgm
00151  * multicard test commit
00152  *
00153 >>>>>>> 1.30.2.8.2.9
00154  * Revision 1.30.2.8  2004/09/15 12:48:21  pgm
00155  * use internal var for llWaitDmaDone, reformat
00156  *
00157  * Revision 1.30.2.7  2004/08/10 07:35:46  pgm
00158  * works with ACQ196
00159  *
00160  * Revision 1.30.2.6  2004/07/31 21:48:25  pgm
00161  * now with Feedback - but why does it plot backwards\/
00162  *
00163  * Revision 1.30.2.5  2004/07/30 19:44:27  pgm
00164  * correct end of ao
00165  *
00166  * Revision 1.30.2.4  2004/07/27 20:49:06  pgm
00167  * llcontrol 2G with AO - in debug
00168  *
00169  * Revision 1.30.2.3  2004/07/26 20:17:23  pgm
00170  * *** empty log message ***
00171  *
00172  * Revision 1.30.2.2  2004/07/25 20:39:38  pgm
00173  * hbpolling, 96 channels
00174  *
00175  * Revision 1.30.2.1  2004/07/25 20:34:59  pgm
00176  * ACQ196 pass 1
00177  *
00178  * Revision 1.30  2003/07/03 11:18:35  pgm
00179  * help update
00180  *
00181  * Revision 1.29  2003/07/03 11:15:21  pgm
00182  * set dacs
00183  *
00184  * Revision 1.28  2003/02/14 09:48:03  pgm
00185  * bigbuf def now comes from driver
00186  *
00187  * Revision 1.27  2002/09/25 09:50:49  pgm
00188  * opt to use bigbuf
00189  *
00190  * Revision 1.26  2002/09/02 15:36:14  pgm
00191  * hook up int masking
00192  *
00193  * Revision 1.25  2002/09/02 11:01:44  pgm
00194  * better fill buffer, int mask handling
00195  *
00196  * Revision 1.24  2002/08/29 13:26:44  pgm
00197  * *** empty log message ***
00198  *
00199  * Revision 1.23  2002/08/29 13:22:21  pgm
00200  * better docs
00201  *
00202  * Revision 1.22  2002/04/02 10:15:38  pgm
00203  * emacs indent, untabify
00204  *
00205  * Revision 1.21  2002/03/12 15:37:51  pgm
00206  * emacs format rools OK
00207  *
00208  * Revision 1.20  2002/02/19 19:29:56  pgm
00209  * aims to shut down cleanly
00210  *
00211  * Revision 1.19  2002/02/10 20:51:08  pgm
00212  * overwrite doesn't need such a large buffer
00213  *
00214  * Revision 1.18  2002/01/21 20:19:18  pgm
00215  * separate timing stats
00216  *
00217  * Revision 1.17  2001/11/25 11:42:19  pgm
00218  * reformatted again
00219  *
00220  * Revision 1.16  2001/08/23 20:00:50  pgm
00221  * mod protocol avoids races and works
00222  *
00223  * Revision 1.15  2001/08/17 07:25:38  pgm
00224  * ll, aync update, has race
00225  *
00226  * Revision 1.14  2001/06/22 22:05:41  pgm
00227  * fix bug where tprocess was being overwritten
00228  * !
00229  *
00230  * Revision 1.13  2001/05/25 17:17:59  pgm
00231  * time for release now
00232  *
00233  * Revision 1.12  2001/05/25 13:12:42  pgm
00234  * embedded stats
00235  *
00236  * Revision 1.11  2001/05/25 12:05:15  pgm
00237  * its a runner - shippit quick
00238  *
00239  * Revision 1.10  2001/05/23 19:16:21  pgm
00240  * doc
00241  *
00242  * Revision 1.9  2001/05/21 20:43:29  pgm
00243  * *** empty log message ***
00244  *
00245  * Revision 1.8  2001/05/21 17:50:36  pgm
00246  * reform again
00247  *
00248  * Revision 1.7  2001/05/21 17:42:38  pgm
00249  * reformed
00250  *
00251  * Revision 1.6  2001/05/20 21:24:10  pgm
00252  * ll WIP - almost works
00253  *
00254  * Revision 1.5  2001/05/19 19:46:15  pgm
00255  * enters LL mode with good bufs, mboxes
00256  *
00257  * Revision 1.4  2001/05/19 07:03:40  pgm
00258  * LL done for SOFT CLOCK, compiles
00259  *
00260  * Revision 1.3  2001/05/18 20:21:13  pgm
00261  * compiles. needs algorithms
00262  *
00263  * Revision 1.2  2001/05/18 07:09:37  pgm
00264  * first cut - wont compile :-(
00265  *
00266  * Revision 1.1  2001/05/17 18:58:18  pgm
00267  * *** empty log message ***
00268  *
00269  *
00270 \*****************************************************************************/
00271 
00272 
00273 
00274 /** @file llcontrol.c <b>MAIN</b> llcontrol top level and "UI".
00275  * llcontrol -
00276  * - mmapMboxes() - get app mapping for mailboxes
00277  * - mmapBuffer() - get dmabuff and phys addresses
00278  * - runSCM() - capture using soft trigger
00279  * - runECM() - capture using external clock
00280  */
00281 
00282 /** 
00283 
00284 @mainpage llcontrol $Revision: 1.30.2.43 $
00285 
00286 @author Peter Milne <peter.milne@d-tacq.com>
00287 
00288 - Low Latency control operation:
00289  - Target push data transfer to slave memory on host card.
00290  - Data is delivered with minimum latency after the sample clock.
00291 
00292 - For overview, please refer to 
00293  - http://www.d-tacq.com/resources/D-Tacq_2G_UserGuide.pdf
00294 
00295 - For operating instructions, please refer to 
00296  - <a href="../README.ACQ196">README.ACQ196</a> readme file for ACQ196 operation
00297  - <a href="../README.ACQ216">README.ACQ216</a> readme file for ACQ216 operation
00298  - <a href="../README.AO32">README.AO32</a> readme file for AO32 operation
00299   - <a href="ao-ramps.png">ao-ramps.png</a>
00300   - <a href="walking-bit.png">walking-bit.png</a>
00301  - <a href="../README.RFM">README.RFM</a>   readme file for RFM/"ALTERNATE TARGET" operation
00302 
00303  - as a consequence of evolution, llcontrol has many operating modes
00304   - SOFT -> ECM -> syncECM -> SYNC2V
00305   - SYNC2V is the prefered mode.
00306    - SYNC2V_AO32 : SYNC2V with output to AO32 cards
00307    - SYNC2V+ALT : alternate VI destination eg RFM. 
00308         <b>NB<a> ALT does NOT affect llcontrol AT ALL.
00309 
00310  - llcontrol-core.c implements the core of the llcontrol loop, and ECM mode
00311  - llcontrol-sync2v-core.c implements <b>SYNC_2V</b> mode
00312  - llcontrol-sync2VAO32-core.c detail of <b>AO32CPCI</b> control
00313 
00314  - llcontrol-syncECM-core.c implements "SYNC_ECM mode" 
00315  - llcontrol-acq216-core.c detail of ACQ216 control
00316 */
00317  
00318 #include "local.h"
00319 
00320 #include <assert.h>
00321 #include <stdio.h>
00322 #include <stdlib.h>
00323 
00324 #include <errno.h>
00325 #include <fcntl.h>
00326 #include <sys/ioctl.h>
00327 #include <sys/mman.h>
00328 #include <sys/stat.h>
00329 #include <sys/time.h>
00330 #include <sys/types.h>
00331 #include <stdio.h>
00332 #include <unistd.h>
00333 
00334 #include <popt.h>
00335 
00336 #include "acq32ioctl.h"
00337 #include "acq32busprot.h"
00338 
00339 #include "llif.h"
00340 #include "llprotocol.h"
00341 
00342 
00343 #include "llcontrol.h"
00344 
00345 #ifdef __ACQ196__
00346 #define FLAVOR "ACQ196"
00347 #else
00348 #define FLAVOR "ACQ32"
00349 #endif
00350 
00351 #define VERID "llcontrol $Revision: 1.30.2.43 $ B1051 " FLAVOR "\n"
00352 extern const char* core_ident;
00353 #define HELP \
00354 "llcontrol [opts] mode \n"\
00355 "mode:\n"\
00356 "    A : Soft Clock Master - alt SCM [interval-usecs]\n"\
00357 "    Bi: Ext Clock Slave   - alt ECS\n"\
00358 "    Bii: Ext Clock Master - alt ECM <divisor>\n\n"\
00359 "    SYNC_ECM <divisor> - Syncronous update ECM (LLCV2)\n"\
00360 "    SYNC_2V <divisor> - Syncronous update 2V mode\n"\
00361 "    SYNC_2VAO32 <divisor> AO32ID [AO32ID...]\n"\
00362 "    N : null enter lowlatency mode and escape again\n"\
00363 "    MBL : Measure Bridge Latency\n" \
00364 "\n"\
00365 "opts:\n"\
00366 "    -b board [default:1]\n"\
00367 "    -o file   output data (- is stdout)\n"\
00368 "    -v verbose  verbose output\n"\
00369 "    -d decimation {0..15} [default:1]\n"\
00370 "    -t log clock times (embeds status info in data)\n" \
00371 "    --tlogbin <file> log clock times binary out (better with octave)\n" \
00372 "    -l use internal loopback\n"\
00373 "    -n iterations [default:1]\n"\
00374 "    -m <millisec> - monitor at this rate\n"\
00375 "\n"\
00376 "    -O overwrite data\n"\
00377 "    -A append data\n"\
00378 "    -T {+,-} trigger edge [default:-]\n"\
00379 "    -C {+,-} clock edge   [default:-]\n"\
00380 "\n"\
00381 "    -W do \"work\" - copy data to user buffer in real time\n"\
00382 "    -M <mask> use this interrupt mask\n"\
00383 "    -F --feedback <channel> feed this data back to outputs\n"\
00384 "    -c <channels> channel count [32]\n"\
00385 "    --samples <len> #samples per cycle [1]\n"\
00386 "    --hbpoll host buffer polling\n"\
00387 "    --bigbuf   use bigbuf definition from driver\n"\
00388 "    --dacs <def-file> update dacs: def-file has dac data definition\n" \
00389 "    --mlt 1 : minimum latency timing - drops tinst tproc time query\n" \
00390 "    --V2 1 : set V2 mode\n" \
00391 "    --HWGO 1 : set hardware gate off (don't poll for counter stopped)\n" \
00392 "    --prams <pram-file> configure prams each shot (ACQ216 only)\n" \
00393 "    --cliplimit N - stats format control default: 100000\n"\
00394 ""
00395 
00396 
00397 /*
00398  * globals (keep to minimum)
00399  */
00400 int verbose = 0;
00401 
00402 
00403 /*
00404  * class Testdescription 
00405  */
00406  
00407 
00408 
00409 int G_quit;
00410 
00411 
00412 static void setDefaults( struct TestDescription* td )
00413 {
00414         td->mode = M_SCM;
00415         td->arg.interval = 0;
00416         td->iterations = 1;
00417         td->decimation = 1;
00418         td->overwrite = 0;
00419         td->clkpos = 1;
00420         td->trpos = 0;
00421         td->internal_loopback = 0;
00422 
00423         td->mask_ints = 0;
00424         td->mask_ints_mask = 0;
00425 
00426         td->update_dacs = 0;
00427         td->samples = 1;      /* samples > 1 is an acq216 thing */
00428 #ifdef __ACQ196__
00429         td->channels = 64;     /* most popular llc variant */
00430 #else
00431         td->channels = 32;
00432 #endif
00433 
00434         if (isAcq216()){
00435                 td->overwrite = 1;  
00436                 td->hb_polling = 1;
00437         }
00438 }
00439 
00440 #include <sys/types.h>
00441 #include <sys/stat.h>
00442 #include <unistd.h>
00443 
00444 
00445 static void loadPramfile(struct TestDescription *td, const char* pram_file)
00446 /** ACQ216 ONLY: pram_file contains binary array of struct LLC200_INIT.
00447  */
00448 {
00449 
00450         if (!isAcq216()){
00451                 return;
00452         }
00453 
00454         struct stat stats;
00455 
00456         if (stat(pram_file, &stats) == 0){
00457                 int records = stats.st_size/LLC200_INIT_SZ;
00458                         
00459                 if (records*sizeof(struct LLC200_INIT) != stats.st_size){
00460                         fprintf(stderr,
00461                                 "ERROR: pram file size mismatch "
00462                                 "%d * %lu != %d\n",
00463                                 records, LLC200_INIT_SZ, (int)stats.st_size);
00464                         exit(1);
00465                 }else{
00466                         FILE *fp = fopen(pram_file, "r");
00467 
00468                         assert(fp);
00469 
00470                         td->llc200_init = calloc(records, LLC200_INIT_SZ);
00471                         assert(td->llc200_init);
00472                                 
00473                         fread(td->llc200_init, LLC200_INIT_SZ, records, fp);
00474                         fclose(fp);
00475                         td->llc200_init_count = records;
00476                         fprintf(stderr, "prams: %d records loaded\n",
00477                                 records);
00478                 }
00479         }else{
00480                 fprintf(stderr, 
00481                         "ERROR failed to open pram file \"%s\"\n",
00482                         pram_file);
00483         }
00484 }
00485 
00486 
00487 static inline u32 makeChannelMask(struct TestDescription* td){
00488         int channels = td->channels;
00489 
00490         if (isAcq216HS()){
00491                 switch(channels){
00492                 case 2:
00493                         return 0x000f;
00494                 case 4:
00495                         if (td->acq216hs_ch12ch34_bonding){
00496                                 return 0x000f;      
00497                         }else{
00498                                 return 0x00f0;
00499                         }
00500                 case 8: 
00501                         return 0x0ff0;
00502                 default:
00503                         return 0xfff0;
00504                 }
00505         }else{
00506                 switch(channels){
00507                 case 4:
00508                         return 0x000f;
00509                 case 8:
00510                         return 0x00ff;
00511                 case 12:
00512                         return 0x0fff;
00513                 default:
00514                         return 0xffff;
00515                 }
00516         }
00517 }
00518 
00519 static void initPrams(struct TestDescription *td) 
00520 /** force channel mask if not already set in prams data. */
00521 {
00522         if (td->channels != 0 &&
00523             (td->llc200_init->mask&LLC200_INIT_MASK_CHANNEL) == 0){
00524                 td->llc200_init->channel_mask = makeChannelMask(td);
00525                 if (isAcq216HS()){
00526                         td->llc200_init->channel_mask |= 
00527                                 LLC200_INIT_CHANNEL_MASK_ANTIPHASE;
00528                 }
00529                 td->llc200_init->mask |= LLC200_INIT_MASK_CHANNEL;
00530                 fprintf(stderr,
00531                         "setChannelMask 0x%08x", 
00532                         td->llc200_init->channel_mask);
00533         }
00534 }
00535 
00536 static int make_output_file(
00537         struct TestDescription* td, 
00538         int slot,
00539         const char* class)
00540 {
00541         if (td->outfname == 0){
00542                 return 0;                // no file 
00543         }else if ( td->outfname[0] == '-' ){
00544                 return 1;                // use stdout
00545         }else{
00546                 char outfname[128];
00547                 int fd_out;
00548 
00549                 sprintf(outfname, "%s.%d.%s", td->outfname, slot, class);
00550                 fd_out = open( outfname, O_WRONLY|O_CREAT|O_TRUNC, 0666 );
00551 
00552                 if (fd_out <= 0){
00553                         fprintf(stderr, "ERROR: failed to open file %s\n",
00554                                 outfname);
00555                         exit( -1 );
00556                 }
00557                 return fd_out;
00558         }
00559 }
00560 
00561 void updateTimingStats(
00562         struct TimingStats* buffer, int iter, struct TimingStats* tstats)
00563 {
00564         struct TimingStats* cursor = &buffer[iter];
00565 
00566         memcpy(cursor, tstats, sizeof(struct TimingStats));
00567         cursor->iter = iter;
00568 }
00569 
00570 
00571 static int CLIP_LIMIT = 100000;
00572 
00573 /** CLIP bogus times - not to try hide anything - big number spoils display */
00574 #define CLIP(t) ((t) < 0? -1: (t) > CLIP_LIMIT? (-1): (t))
00575 
00576 static inline int extractTprocess(struct TimingStats *ts)
00577 /** if TP is available, USE IT, else calculate from tlatch, tinst
00578  *  this is valid because either it is accurate IOP calc, or 
00579  *  worst case Host calc
00580  */
00581 {
00582         if (!isAcq216() && CLIP(ts->tprocess)){
00583                 return CLIP(ts->tprocess);
00584         }else{
00585                 return CLIP(ts->tinst) - CLIP(ts->tlatch);
00586         }
00587 }
00588 
00589 static void dumpTimingStats( struct TestDescription* td, FILE* fp )
00590 {
00591 #define HFMT "%8s, %10s, %10s, %8s, %8s, %6s, %4s, "
00592 #define DFMT "%8d, %10d, %10d, %8d, %8d, %6d, %4d, "
00593 
00594         int iter;
00595 
00596         u32 old_tlatch[MAXCARDS] = {};
00597         EACHCARD_INIT;
00598 
00599         if (isAcq216()){
00600                 CLIP_LIMIT = 10000000;
00601         }
00602         FOREACHCARD{
00603                 fprintf(fp,  "%60s: %d", "CARD", EACHSLOT(td));
00604         }
00605         fprintf(fp, "\n");
00606         FOREACHCARD{
00607                 int it;
00608                 fprintf(fp,  HFMT, 
00609                        "iter", "tinst", "tlatch",  "tprocess", "tclock",
00610                        "hpol","tpol");
00611                 for (it = 0; it != MAXTEST; ++it){
00612                         fprintf(fp,  "%6d,", it);
00613                 }
00614         }
00615         fprintf(fp, "\n");
00616     
00617         for (iter = 0; iter != td->iterations; ++iter){
00618                 
00619                 if ( iter && td->stats_buf[0][iter].iter == 0 ){
00620                         fprintf(fp, "\n");
00621                         break;
00622                 }else       
00623 
00624                 FOREACHCARD{
00625                         struct TimingStats *ts = &td->stats_buf[icard][iter];
00626                         int tclock = ts->tlatch - old_tlatch[icard];
00627                         int it;
00628                         int tp1 = 0;
00629                         int tp2 = 0;
00630 
00631                         fprintf(fp,  DFMT, 
00632                                 ts->iter,
00633                                 CLIP(ts->tinst),
00634                                 CLIP(ts->tlatch),
00635                                 extractTprocess(ts),
00636                                 CLIP(tclock),
00637                                 ts->hb_poll,
00638                                 ts->target_poll);
00639                         old_tlatch[icard] = ts->tlatch;
00640 
00641                         for (it = 0; it != MAXTEST; ++it){
00642                                 int tp = ts->test_points[it];
00643                                 if (tp){
00644                                         if (tp1 == 0){
00645                                                 tp1 = tp;
00646                                         }else if (tp > tp2){
00647                                                 tp2 = tp;
00648                                         }
00649                                 }
00650                                 fprintf(fp,  "%6d,", tp);
00651                         }
00652                         fprintf(fp, " T:%3d, ", tp2 - tp1);
00653                 }
00654 
00655                 fprintf(fp, "\n");
00656         }
00657 #undef HFMT
00658 #undef DFMT
00659 #undef CLIP
00660 }
00661 
00662 
00663 static void dumpTimingStatsBin(struct TestDescription* td, const char *bfile)
00664 {
00665         FILE* fp = fopen(bfile, "w");
00666 
00667         u32 tclock;
00668         int iter;
00669         EACHCARD_INIT;
00670         u32 old_tinst[MAXCARDS] = {};   
00671 
00672         assert(fp);
00673 
00674         for ( iter = 0; iter != td->iterations; ++iter ){       
00675                 FOREACHCARD{
00676                         struct TimingStats *ts = &td->stats_buf[icard][iter];
00677 
00678                         fwrite(&ts, sizeof(struct TimingStats), 1, fp);
00679                         tclock = ts->tinst - old_tinst[icard];
00680                         fwrite(&tclock, sizeof(u32), 1, fp);
00681                         old_tinst[icard] = ts->tinst;
00682                 }
00683         }
00684         fclose(fp);
00685 }
00686 
00687 static void td_allocate_dac_data(struct TestDescription* td, int nsamples)
00688 {
00689         td->dac_data = calloc(nsamples, DAC_SAMPLE_SIZE);
00690         assert(td->dac_data);
00691         td->dac_data_samples = nsamples;
00692         td->dac_cursor = 0;
00693 }
00694 
00695 static void td_load_dac_data_impulse(struct TestDescription* td)
00696 /* load an impulse pattern to the dac data */
00697 {
00698         td_allocate_dac_data(td, 128);
00699         ((short*)td->dac_data)[0] = 0x7fff;  /* single impulse, channel 0 */
00700 
00701         ((u32 *)(td->dac_data+128*DAC_SAMPLE_SIZE-4))[0] = 0xcafebabe;
00702 }
00703 
00704 static int get_file_size(const char* fname)
00705 {
00706         struct stat stat_buf;
00707 
00708         if (lstat(fname, &stat_buf) == 0){
00709                 return (int)stat_buf.st_size;
00710         }else{
00711                 return 0;
00712         }
00713 }
00714 
00715 static void td_load_dac_data_file(
00716         struct TestDescription* td, const char* fname)
00717 {
00718         FILE* fp = fopen(fname, "r");
00719         int fsize = get_file_size(fname);
00720 
00721         if (!fp || !fsize){
00722                 char buf[128];
00723                 sprintf(buf, "ERROR: failed to open file \"%s\"\n", fname);
00724                 perror(buf);
00725                 exit(errno);
00726         }
00727         
00728         if (fsize%DAC_SAMPLE_SIZE){
00729                 fsize = (fsize%DAC_SAMPLE_SIZE) + DAC_SAMPLE_SIZE;
00730         }
00731         td_allocate_dac_data(td, fsize/DAC_SAMPLE_SIZE);
00732         fread(td->dac_data, sizeof(short), fsize/sizeof(short), fp);
00733         fclose(fp);
00734 }
00735 
00736 static void td_load_dac_data(struct TestDescription* td)
00737 {
00738         if (strcmp(td->dac_data_file, "i") == 0){
00739                 td_load_dac_data_impulse(td);
00740         }else{
00741                 td_load_dac_data_file(td, td->dac_data_file);
00742         }
00743         td->update_dacs = 1;
00744         printf("PGMWASHERE: td->update_dacs set 1\n");
00745 }
00746 
00747 
00748 
00749 
00750 
00751 static void setEdge( int* flag, const char* arg )
00752 {
00753         *flag = arg[0] == '+';
00754 }
00755 
00756 
00757 
00758 static void selectBoards(struct TestDescription *td, const char* board_def)
00759 /* slots in comma sep list, max 8 */
00760 {
00761         EACHCARD_INIT;
00762 
00763         td->ncards = sscanf(board_def, "%d,%d,%d,%d,%d,%d,%d,%d",
00764                             &td->cards[0].slot,
00765                             &td->cards[1].slot,
00766                             &td->cards[2].slot,
00767                             &td->cards[3].slot,
00768                             &td->cards[4].slot,
00769                             &td->cards[5].slot,
00770                             &td->cards[6].slot,
00771                             &td->cards[7].slot);
00772 
00773         FOREACHCARD{
00774                 fprintf(stderr, "card %d\n", EACHSLOT(td));
00775         }
00776 }
00777 
00778 
00779 static void doWorkBufDataOutput(struct TestDescription *td)
00780 {
00781         EACHCARD_INIT;
00782 
00783         FOREACHCARD{
00784                 int iter;
00785                 int offset = 0;
00786                 int fd_out = make_output_file(td, EACHSLOT(td), "userbuf");
00787 
00788                 for (iter = 0; iter != td->iterations; ++iter){
00789                         write(fd_out, td->work_buf[icard]+offset,
00790                               td_sample_size(td)*td->samples);
00791                         offset += td_sample_size(td)*td->samples;
00792                 }
00793                 close(fd_out);
00794         }
00795 }
00796 static void doDmaBufDataOutput(struct TestDescription *td)
00797 {
00798         EACHCARD_INIT;
00799 
00800         FOREACHCARD{
00801                 int iter;
00802                 int offset = 0;
00803                 int fd_out = make_output_file(td, EACHSLOT(td), "dmabuf");
00804 
00805                 for (iter = 0; iter != td->iterations; ++iter){
00806                         write(fd_out, getVaddr(EACHBUF(td), offset), 
00807                               td_sample_size(td)*td->samples);
00808                         if (td->overwrite){
00809                                 break;
00810                         }
00811                         offset += td->sample_offset;
00812 
00813                 }
00814                 close(fd_out);
00815         }
00816 }
00817 static void doPostShotAnalysis(struct TestDescription *td)
00818 {
00819         if ( td->tlog ){
00820                 if (td->tlog_binfile != 0){
00821                         dumpTimingStatsBin(td, td->tlog_binfile);
00822                 }else{
00823                         FILE *fp = fopen("/tmp/llcontrol.tstats", "w");
00824                         dumpTimingStats(td, fp);
00825                         fclose(fp);
00826                         printf("timing stats stored in /tmp/llcontrol.tstats\n");
00827 //                      dumpTimingStats(td, stdout);
00828                 }
00829         }    
00830         if ( td->outfname != 0 ){
00831                 doDmaBufDataOutput(td);
00832                 if (td->do_work){
00833                         doWorkBufDataOutput(td);
00834                 }
00835         }
00836 }
00837 
00838 
00839 static void initWorkBuf(struct TestDescription *td)
00840 {
00841         EACHCARD_INIT;
00842         int len = td->samples * td_sample_size(td)*td->iterations;
00843 
00844         FOREACHCARD{
00845                 td->work_buf[icard] = malloc(len);
00846                 if(td->work_buf[icard] == 0){
00847                         perror("malloc failed");
00848                         exit(errno);
00849                 }
00850         }
00851 }
00852 
00853 extern void initV2Stats(struct TestDescription* td);
00854 
00855 static void initV2(struct TestDescription *td)
00856 /** LLC V2 initialization - pick up prams from config file. */
00857 {
00858         fprintf(stderr, "initV2\n");
00859         td->V2_BUFS[LLCV2_INIT_MARKER] = LLCV2_INIT_MAGIC_MARKER;
00860 /** WORKTODO V2 */
00861         td->V2_BUFS[LLCV2_INIT_AI_HSBT] = V2_NOBUF;
00862         td->V2_BUFS[LLCV2_INIT_AO_HSBS] = V2_NOBUF;
00863         td->V2_BUFS[LLCV2_INIT_DO_HSBS] = V2_NOBUF;
00864         td->V2_BUFS[ LLCV2_INIT_STATUS_HSBT] = LLCV2_OFFSET_STATUS_HSBT;
00865 
00866         td->hb_polling = 0;
00867         initV2Stats(td);
00868 }
00869 
00870 static int is_v2 = 0;
00871 
00872 int main( int argc, const char* argv[] )
00873 {
00874         struct TestDescription *td = calloc(1,sizeof(struct TestDescription)); 
00875         const char* arg;
00876         int rc;
00877         char* board_def = "1";
00878         int monitor = 0;
00879         /* WARNING: really should use bigbuf ALL THE TIME */
00880         int use_bigbuf = 1;
00881         char *pram_file;
00882         EACHCARD_INIT;
00883         
00884     
00885         struct poptOption opt_table[] = {
00886                 { "help",       'h', POPT_ARG_NONE,   0,             'h'  },
00887                 { "version",    'V', POPT_ARG_NONE,   0,             'V'  },
00888                 { "verbose",    'v', POPT_ARG_INT,    &verbose,       0   },
00889                 { "output",     'o', POPT_ARG_STRING, &td->outfname,  0   },
00890                 { "decimation", 'd', POPT_ARG_INT,    &td->decimation, 0  },
00891                 { "histogram",  't', POPT_ARG_NONE,   0,             't'  },
00892                 { "iterations", 'n', POPT_ARG_INT,    &td->iterations, 0  },
00893                 { "board",      'b', POPT_ARG_STRING, &board_def,    'X'  },
00894                 { "internal",   'l', POPT_ARG_NONE,   0,             'l'  },
00895                 { "monitor",    'm', POPT_ARG_INT,    &monitor,       0   },
00896                 { "overwrite",  'O', POPT_ARG_NONE,   0,             'O'  },
00897                 { "append",     'A', POPT_ARG_NONE,   0,             'A'  },
00898                 { "trgedge",    'T', POPT_ARG_STRING, &arg,          'T'  },
00899                 { "clkedge",    'C', POPT_ARG_STRING, &arg,          'C'  },
00900                 { "int_mask",   'M', POPT_ARG_STRING, &arg,          'M'  },
00901                 { "bigbuf",     'B', POPT_ARG_NONE,   0,             'B'  },
00902                 { "samples",   'L', POPT_ARG_INT,    &td->samples       },
00903                 { "dacs",       'D', POPT_ARG_STRING, &td->dac_data_file,'D'},
00904                 { "hbpoll",     ' ', POPT_ARG_NONE,   0,              'H' },
00905                 { "channels",   'c', POPT_ARG_INT,    &td->channels,   'c'  },
00906                 { "feedback",   'F', POPT_ARG_INT,  &td->feedback_channel,'F'},
00907                 { "tlogbin",    ' ', POPT_ARG_STRING, &arg,           'b' },
00908                 { "work",       'W', POPT_ARG_NONE,   0,   'W' },
00909                 { "mlt",        0,  POPT_ARG_INT,    &td->min_latency_test,0},
00910                 { "V2",         0,  POPT_ARG_INT,     &is_v2, 0 },
00911                 { "HWGO",       0,  POPT_ARG_INT,   &td->hardware_gate_off, 0},
00912                 { "prams",      0,  POPT_ARG_STRING, &pram_file, 'P' },
00913                 { "cliplimit",  0,  POPT_ARG_INT,    &CLIP_LIMIT, 0 },
00914                 { }
00915         };
00916 
00917         poptContext opt_context;
00918         setDefaults( td );
00919 
00920 
00921         opt_context = poptGetContext(argv[0], argc, argv, opt_table, 0);
00922 
00923         while ( (rc = poptGetNextOpt( opt_context )) > 0 ){
00924                 switch( rc ){
00925                 case 'X':
00926                         selectBoards(td, board_def);
00927                         break;
00928                 case 'V':
00929                         fprintf(stderr, VERID);
00930                         fprintf(stderr, core_ident);
00931                         break;
00932                 case 'h':
00933                         fprintf(stderr, VERID);
00934                         fprintf(stderr, core_ident);
00935                         fprintf( stderr, HELP );
00936                         return 1;
00937                 case 'b':
00938                         td->tlog_binfile = arg;  /* fall thru */
00939                 case 't':
00940                         td->tlog = 1;
00941                         break;
00942                 case 'W':               
00943                         td->do_work = 1;
00944                         break;
00945                 case 'O':
00946                         td->overwrite = 1;
00947                         break;
00948                 case 'A':
00949                         td->overwrite = 0;
00950                         break;    
00951                 case 'T':
00952                         setEdge(&td->trpos, arg);
00953                         break;
00954                 case 'C':
00955                         setEdge(&td->clkpos, arg);
00956                         break;
00957                 case 'l':
00958                         td->internal_loopback = 1;
00959                         break;    
00960                 case 'M':
00961                         td->mask_ints = 1;
00962                         td->mask_ints_mask = strtoul( arg, 0, 0 );
00963                 case 'B':
00964                         use_bigbuf = 1;
00965                         break;
00966                 case 'H':
00967                         td->hb_polling = 1;
00968                         break;
00969                 case 'D':
00970                         td_load_dac_data(td);
00971                         break;
00972                 case 'F':
00973                         td->feedback = 1;
00974                         break;
00975                 case 'P':
00976                         loadPramfile(td, pram_file);
00977                         break;
00978                 case 'c':
00979                         if (td->channels == 2 && isAcq216HS()){
00980                                 fprintf(stderr, "ANTIPHASE\n");
00981                                 td->acq216hs_ch12ch34_bonding = 1;
00982                                 td->channels = 4;           /* interleaved */
00983                         }
00984                 }
00985         }  // processes all other opts via arg pointers
00986 
00987         if ( (arg = poptGetArg( opt_context )) == NULL ){
00988                 fprintf( stderr, "please specify mode\n" );
00989                 return 1;
00990         }else{
00991                 const char* arg2 = poptGetArg( opt_context );
00992             
00993                 if ( STREQ( arg, "A" ) || STREQ( arg, "SCM" ) ){
00994                         td->mode = M_SCM;
00995                         if ( arg2 ){
00996                                 td->arg.interval = atoi( arg2 );
00997                         }
00998                 }else if ( STREQ( arg, "Bi" ) || STREQ( arg, "ECS" ) ){
00999                         td->mode = M_ECS;
01000                 }else if ( STREQ( arg, "Bii" ) || STREQ( arg, "ECM" ) ){
01001                         td->mode = M_ECM;
01002                         if ( arg2 == 0 ){
01003                                 fprintf( stderr, "please specify divisor\n" );
01004                                 return 1;
01005                         }else{
01006                                 td->arg.divisor = atoi( arg2 );
01007                         }
01008                 }else if (STREQ(arg, "SYNC_ECM")){
01009                         td->mode = M_SYNC_ECM;
01010                         if ( arg2 == 0 ){
01011                                 fprintf( stderr, "please specify divisor\n" );
01012                                 return 1;
01013                         }else{
01014                                 td->arg.divisor = atoi( arg2 );
01015                         }
01016                 }else if (STREQ(arg, "SYNC_2VAO32")){
01017                         td->mode = M_SYNC_2VAO32;
01018                         if ( arg2 == 0 ){
01019                                 fprintf( stderr, "please specify divisor\n" );
01020                                 return 1;
01021                         }else{
01022                                 td->arg.divisor = atoi( arg2 );
01023                                 while((arg = poptGetArg(opt_context)) != NULL){
01024                                         if (td->ao32_count < MAXAO32){
01025                                                 td->ao32_ids[td->ao32_count++] 
01026                                                                     = atoi(arg);
01027                                         }else{
01028                                                 fprintf(stderr, 
01029                                                  "max ao32count=%d\n", MAXAO32);
01030                                         }
01031                                 }
01032                         }                       
01033                 }else if (STREQ(arg, "SYNC_2V")){
01034                         td->mode = M_SYNC_2V;
01035                         if ( arg2 == 0 ){
01036                                 fprintf( stderr, "please specify divisor\n" );
01037                                 return 1;
01038                         }else{
01039                                 td->arg.divisor = atoi( arg2 );
01040                         }
01041                 }else if (STREQ(arg, "SYNC_2VRFM")){
01042                         td->mode = M_SYNC_2VRFM;
01043                         if ( arg2 == 0 ){
01044                                 fprintf( stderr, "please specify divisor\n" );
01045                                 return 1;
01046                         }else{
01047                                 td->arg.divisor = atoi( arg2 );
01048                         }                       
01049                 }else if ( STREQ( arg, "N" ) || STREQ( arg, "NULL" ) ){
01050                         td->mode = M_NULL;
01051                 }else if (STREQ(arg, "MBL")){
01052                         td->mode = M_MEASURE_BRIDGE;
01053                 }else{
01054                         fprintf( stderr, "sorry, don't understand mode \"%s\"\n", arg );
01055                         return 1;
01056                 }
01057         }
01058 
01059 
01060 #ifdef __ACQ196__    
01061         FOREACHCARD{
01062                 initCardResource(EACHCARD(td));
01063         }
01064 #else
01065         if ( use_bigbuf ){
01066                 td->buf = mmapBigBuffer(board, td->overwrite?0x10000:td_dss(td));
01067                 mmapValidateDmaBuffer( td->mbx, td->iterations );
01068         }else{
01069 
01070                 td->buf = mmapDmaBuffer( 
01071                         board, td->overwrite? 0x10000: MAX(td_dss(td), 0x200000 ) 
01072                         );
01073 
01074         }
01075 #endif
01076 
01077         td->sample_offset = 256;  /* operate on 256 boundaries - easy debug */
01078 
01079         if (td->llc200_init_count){
01080                 initPrams(td);
01081         }
01082         if (is_v2){
01083                 initV2(td);
01084         }
01085 
01086         if (IS_SYNC_2V(td->mode)){
01087                 td->sample_size = (td->channels + 32) * sizeof(short);
01088                 fprintf(stderr, "M_SYNC_2V sample size %d\n",
01089                         td_sample_size(td));
01090         }else{
01091                 td->sample_size = td->channels * sizeof(short);
01092         }
01093         if (td->do_work){
01094                 initWorkBuf(td);
01095         }
01096 
01097         setupAbortHandler(td);
01098         if ( monitor ){
01099                 setupMonitor(monitor);
01100         }
01101         rc = runTest(td);    
01102 
01103         doPostShotAnalysis(td);
01104 
01105         return rc;
01106 }
01107 
01108 
01109 
01110 
01111 
01112 
01113 unsigned  llcv2_hb_offset = LLCV2_HB_OFFSET;

Generated on Wed Jan 5 2011 for llcontrol by  doxygen 1.7.1