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

llcontrol-sync2VAO32-core.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002  *
00003  * File: llcontrol-sync2VAO32-core.c
00004  *
00005  * $RCSfile: llcontrol-sync2VAO32-core.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 feature
00012  *
00013  * $Id: llcontrol-sync2VAO32-core.c,v 1.4 2009/04/02 13:19:01 pgm Exp $
00014  * $Log: llcontrol-sync2VAO32-core.c,v $
00015  * Revision 1.4  2009/04/02 13:19:01  pgm
00016  * docs away
00017  *
00018  * Revision 1.3  2009/03/30 16:33:51  pgm
00019  * AO32 output now WORKS
00020  *
00021  * Revision 1.2  2009/03/28 22:23:05  pgm
00022  * ao32cpci first cut looks good
00023  *
00024  * Revision 1.1  2009/03/28 18:47:39  pgm
00025  * sync2VAO32 take 1
00026  *
00027  * Revision 1.1  2009/03/26 14:52:03  pgm
00028  * split sync2v, acq216 from main core
00029  *
00030  * Revision 1.1.4.27  2009/03/26 12:40:36  pgm
00031  * reuse same dac_src for each card, avoid data overrun
00032  */
00033 
00034 /** @file llcontrol-sync2VAO32-core.c 
00035         demonstrates <b>SYNC_2V mode with AO32CPCI</b>. 
00036 
00037  - llcontrol [opts] --dacs aoramps -W SYNC2V_AO32 ECM slave1 [..slaveN]
00038   - aoramps is a simple binary ramp file provided as an example
00039   - generates a "walking bit" pattern on DO64
00040   - slave1 : slot # of first slave
00041   - supports up to MAXAO32 (6) slaves
00042   
00043  - ao32cpci: x86 host driver must have been preloaded.
00044   - the driver enumerates the PCI bus - remember, although ACQ196 is doing most of the data moving on the PCI bus, HOST is still the system slot card.
00045   - driver enables all the AO32CPCI slave cards
00046   - driver exposes the bus addresses of the slave cards. 
00047   - LLCONTROL loads the slave bus addresses and communicates them to ACQ196
00048 */
00049 
00050 #include "local.h"
00051 
00052 #include <assert.h>
00053 #include <stdio.h>
00054 #include <stdlib.h>
00055 
00056 #include <errno.h>
00057 #include <fcntl.h>
00058 #include <sys/ioctl.h>
00059 #include <sys/mman.h>
00060 #include <sys/stat.h>
00061 #include <sys/time.h>
00062 #include <sys/types.h>
00063 #include <stdio.h>
00064 #include <unistd.h>
00065 
00066 #include <popt.h>
00067 
00068 #include "acq32ioctl.h"
00069 #include "acq32busprot.h"
00070 
00071 #include "llif.h"
00072 #include "llprotocol.h"
00073 
00074 
00075 #include "llcontrol.h"
00076 #include "x86timer.h"
00077 
00078 #define FLAVOR "ACQ196"
00079 #include "llcontrol-core.h"
00080 
00081 
00082 static void sync_2v_updateTstats(
00083         u32 cmd, struct Card* card, struct TimingStats* tstats)
00084 /** updates timing stats from embedded host buffer data */
00085 {
00086 #define SAMPLE_SIZE (96*2)   /* WORKTODO */
00087         u32* stats = getVaddr(card->buf, card->sync_2v_offset_status_hsbt);
00088         tstats->tinst = llv2_extend32(stats[LLC_SYNC2V_IN_MBOX2], 
00089                                       stats[LLC_SYNC2V_IN_TINST]);
00090         tstats->tprocess = LLC_GET_TCYCLE(stats[LLC_SYNC2V_IN_MBOX0]);
00091 }
00092 
00093 static u32 card_sync_2v_WaitDmaDone(struct Card* card)
00094 {
00095         return card->tlatch = llv2WaitDmaDone_2v(card->mbx, 
00096                   getVaddr(card->buf, card->sync_2v_offset_status_hsbt),
00097                   card->tlatch
00098         );
00099 }
00100 
00101 /*
00102 PA data from driver: one BAR per line:
00103 [dt100@kilda ~]$ cat /dev/ao32cpci/ctrl/ao32cpci.6/resource
00104 0x00000000fdefec00 0x00000000fdefec7f 0x0000000000000200
00105 0x0000000000000000 0x0000000000000000 0x0000000000000000
00106 0x00000000fdefd000 0x00000000fdefdfff 0x0000000000000200
00107 0x00000000fdefc000 0x00000000fdefcfff 0x0000000000000200
00108 0x00000000fdefb000 0x00000000fdefbfff 0x0000000000000200
00109 0x0000000000000000 0x0000000000000000 0x0000000000000000
00110 0x0000000000000000 0x0000000000000000 0x0000000000000000
00111 */
00112 
00113 #define BAR_FIFO        3
00114 
00115 static u32 getSlavePa(int slot)
00116 {
00117         char fname[128];
00118         char line[80];
00119         FILE *fp;
00120         int bar;
00121         u32 pa = 0;
00122 
00123         sprintf(fname, "/dev/ao32cpci/ctrl/ao32cpci.%d/resource", slot);
00124         
00125         fp = fopen(fname, "r");
00126         if (!fp){
00127                 fprintf(stderr, "ERROR: failed to open \"%s\"\n", fname);
00128                 exit(errno);
00129         }
00130 
00131         for (bar = 0; fgets(line, 80, fp); ++bar){
00132                 if (bar == BAR_FIFO){
00133                         long long pa0, pa1, len;
00134                         if (sscanf(line, 
00135                                 "%Lx %Lx %Lx", &pa0, &pa1, &len) == 3){
00136                                 pa = (u32)pa0;
00137                         }                       
00138                 }
00139         }
00140         fclose(fp);
00141 
00142         if (pa == 0){
00143                 fprintf(stderr, 
00144                         "ERROR: failed to get sensible PA for %d\n", slot);
00145         }
00146         return pa;
00147 }
00148 
00149 
00150 static void setSlaveData(u32* aovec, void* src)
00151 /** create some data for AO32CPCI.
00152   AO32 gets AO16 data duplicated, DO64 gets a walking bit 
00153 */
00154 {
00155         static int ibit;
00156         unsigned long long DO_PAT = 1ULL<<ibit;
00157 
00158         if (++ibit > 64){
00159                 ibit = 0;
00160         }
00161 
00162         memcpy(aovec, src, 16*sizeof(short));
00163         memcpy(aovec+8, src, 16*sizeof(short));
00164         memcpy(aovec+16, &DO_PAT, sizeof(unsigned long long));
00165 }
00166 
00167 
00168 void appEnterLLC_SYNC_2VAO32(
00169         int icard, struct MU *mu, struct TestDescription *td)
00170 /** set up LLCV2_INIT buffer and enter mode.
00171  *  Buffer set up as 4K block at offset 0
00172  * @todo - this overwrites settings from initV2Stats(), initV2Stats is therefore redundant.
00173 */
00174 {
00175         u32* init_buf = getVaddr(EACHBUF(td), 0);
00176         u32 target_pa = getBusAddr(EACHBUF(td), 0);
00177         struct Card* card = &td->cards[icard];
00178         int islave = 0;
00179         PRINTF(2)("appEnterLLC_SYNC_2V() va:%p pa:0x%08x %s slaves %d\n",
00180                   init_buf, target_pa, MASTER? "MASTER": "",td->ao32_count);
00181 
00182                         
00183         /** set up for single 4K buffer */
00184         llcv2_hb_offset = 0;
00185         card->sync_2v_offset_status_hsbt = 
00186                 LLCV2_AI_HSBT + td->channels*sizeof(short);
00187         card->tlatch = 0;
00188 
00189         /** uses V2 synchronization */
00190         updateTstats = sync_2v_updateTstats;
00191         waitDmaDone  = card_sync_2v_WaitDmaDone;
00192 
00193         init_buf[LLCV2_INIT_MARKER] = LLCV2_INIT_MAGIC_AO32;
00194         init_buf[LLCV2_INIT_AI_HSBT] = target_pa + LLCV2_AI_HSBT;
00195         init_buf[LLCV2_INIT_AO_HSBS] = target_pa + LLCV2_AO_HSBS;
00196 
00197 /* make a zero terminated list of slave pa's */
00198         if (MASTER){
00199                 for (islave = 0; islave < td->ao32_count; ++islave){
00200                         init_buf[LLCV2_INIT_AO32PA0+islave] =
00201                                 getSlavePa(td->ao32_ids[islave]);
00202                 }
00203         }
00204         init_buf[LLCV2_INIT_AO32PA0+islave] = 0;
00205 
00206         enterLLC_SYNC_ECM(
00207                 mu, td->clkpos, td->trpos, 
00208                 td->arg.divisor,td->internal_loopback,
00209                 BP_FC_SET_LLCV2_INIT,
00210                 target_pa );
00211 }
00212 
00213 int runSYNC_2VAO32(struct TestDescription *td, int soft_clock)
00214 /** runs the test SYNC_2V mode.
00215  * PSEUDO-CODE:
00216  *
00217  - (1) Clear the latch timer
00218  - (2) Set a local memory target address and arm the capture
00219  - (3) Poll for counter running (hardware counter starts on external gate)
00220  - (4) Iterate for required number of samples:
00221  - (5)     [optionally send a soft clock command]  trigger an acquisition
00222  - (6)     Wait for DMA Done - at this point data is available in target mem.
00223  *         A "real" control application is probably getting most of its calcs 
00224  *         done here rather than simply polling
00225  - (7)     [Get the latch (sample) and current uSec counters from the boards - 
00226  *          only if interested]
00227  - (8)     Check the process has not stopped (external gate high)
00228  - (b)     write data to host side buffer(LLCV2_AO_HSBS) 
00229  - (b.1)
00230          * take the incoming value on feedback_channel
00231          * and propagate to all DACS.
00232          * default is to assume HAWG on DAC0
00233          * (so feedback_channel better be 0 !),
00234          * but td->update_dacs makes a better test.
00235          * <b> NB: Feedback is on RTMAO, not AO32CPCI </b>
00236  - (b.15)  
00237          * special case where we are DRIVING the
00238          * initial DAC signal from host side. 
00239  - (b.2)
00240          *  simple feedforward case - just drive all DACS
00241          *  from AWG pattern.
00242  */
00243 {
00244         struct TimingStats tstats[MAXCARDS] = {};
00245         struct DacBuf {
00246                 MFA mfa;
00247                 void* bbb;
00248         } dac_buf[MAXCARDS];
00249 #define EACHBBB      (dac_buf[icard].bbb)
00250 #define EACHDAC_BASE (EACHBBB + LLCV2_AO_HSBS)
00251 #define EACHDAC_BASE16 ((u16*)EACHDAC_BASE)
00252 #define BASE_AO32(ic) ((u32*)EACHDAC_BASE+INDEX_OF_LLC_SYNC2V_AO32(ic))
00253 #define V2SETDACS(src, icard) \
00254         memcpy(EACHDAC_BASE, (src)+(icard)*32, DAC_SAMPLE_SIZE)
00255 
00256 
00257         u32 cmd = LLC_MAKE_DECIM(td->decimation);
00258 #define OFFSET 0
00259 
00260         int uses_dacs = td->update_dacs || td->feedback;
00261         void* dac_data;
00262 
00263         EACHCARD_INIT;
00264 
00265         if (uses_dacs) FOREACHCARD { /* (a) */
00266                 EACHBBB = getVaddr(EACHBUF(td), 0);
00267                 printf("card %d uses_dacs EACHBBB %p "
00268                        "EACHDAC_BASE %p bus 0x%08x\n",
00269                        icard, EACHBBB, EACHDAC_BASE,
00270                        getBusAddr(EACHBUF(td), LLCV2_AO_HSBS) );
00271         }
00272 
00273         FOREACHCARD{ /* (1) */
00274                 llSetTlatch(EACHMBX(td), tstats[icard].tlatch = 0xffffffff);
00275                 llv2InitDmaDone(
00276                         getVaddr(EACHBUF(td), 
00277                                  EACHCARD(td)->sync_2v_offset_status_hsbt));
00278         }
00279    
00280         FOREACHCARD{ /* (2) */
00281                 updateTargetAddr(cmd+LLC_CSR_M_ARM, EACHCARD(td), OFFSET);
00282         }
00283 
00284         if (td->update_dacs){
00285                 dac_data = td_get_next_dac_data(td);    
00286                 FOREACHCARD{
00287                         V2SETDACS(dac_data, icard);
00288                 }
00289         }       
00290 
00291 #if 0
00292         // wait for gate /* (3) */
00293 
00294         while( !llCounterRunning(FIRSTMBX(td), cmd) ){ 
00295                 POLLALERT(ipoll, "Polling for Counter Running\n");
00296         }
00297 #endif
00298         INIT_TIMER;
00299         /* WORKTODO - assumes all cards now running */
00300 
00301         for ( td->iter = 0; td->iter != td->iterations; ++td->iter ){ /* (4) */
00302                 if (soft_clock) FOREACHCARD{ /* (5) */
00303                         llSetCmd(EACHMBX(td), cmd+LLC_CSR_M_SOFTCLOCK);
00304                 }
00305         
00306                 FOREACHCARD{                                  /* (6)+(7) */
00307                         MARK_TIME(1, "waitDmaDone() before");
00308                         tstats[icard].tlatch = waitDmaDone(EACHCARD(td));
00309                         MARK_TIME(2, "waitDmaDone() after");
00310                 }
00311 
00312                 if (!td->min_latency_test) FOREACHCARD{        /* (6)+(7) */
00313                         updateTstats(cmd, EACHCARD(td), &tstats[icard]);    
00314                 }
00315 
00316                 
00317                 if (td->do_work){
00318                         doApplicationWork(td, OFFSET);
00319                 }
00320 
00321                 if (td->feedback) { /* (b.1) */
00322                         u16 *pvin = (u16 *)getVaddr(FIRSTBUF(td), OFFSET);
00323                         u16 vin = pvin[td->feedback_channel];
00324                         u32 feedback = vin << 16 | vin;
00325 
00326                         PRINTF(1)("feedback 0x%08x\n", feedback);
00327 
00328                         FOREACHCARD{   
00329                                 MARK_TIME(3, "feedback 1");
00330                                 memset32(EACHDAC_BASE, feedback, DAC_COUNT/2);
00331 
00332                                 if (td->update_dacs){ /* (b.15) */
00333 
00334                                         u16* excite = td_get_next_dac_data(td);
00335                                 
00336                                         EACHDAC_BASE16[td->feedback_channel] 
00337                                          = excite[td->feedback_channel];
00338                                 }
00339                                 MARK_TIME(4, "feedback 2");
00340                         }
00341                 }else if (td->update_dacs){ /** (b.2) */
00342                         int islave;
00343 
00344                         dac_data = td_get_next_dac_data(td);
00345                         FOREACHCARD{
00346                                 V2SETDACS(dac_data, icard);
00347                                 MARK_TIME(5, "update_dacs");
00348                         }
00349 
00350                         /** AO32 update: apply to MASTER only */
00351                         for(THIS_CARD = 0, islave = 0; 
00352                                         islave != td->ao32_count; ++islave){
00353                                 setSlaveData(BASE_AO32(islave), dac_data);
00354                         }
00355                 }
00356 
00357 #if IGNORE_COUNTER_STOP
00358 /** @todo - check counter running in local memory */
00359         /* check process completion.
00360          * if hardware_gateoff is employed, then the app would need
00361          * to make use of a pre-arranged DIO encoding for on/off instead
00362          */              
00363                 if (!td->hardware_gate_off &&
00364                      !llCounterRunning(FIRSTMBX(td), cmd )){          /* (8) */
00365                         fprintf( stderr, "Trigger is off - stop\n" );
00366                         break;
00367                 }
00368 #endif          
00369                 FOREACHCARD_MARK_TIME(9, "after llCounterRunning check");
00370 
00371                 if (td->tlog){          
00372                         FOREACHCARD{
00373                                 tstats[icard].target_poll =
00374                                         getMboxPollcount(EACHMBX(td));
00375                                 MARK_TIME(10, "10");
00376                                 updateTimingStats(
00377                                         td->stats_buf[icard], 
00378                                         td->iter, 
00379                                         &tstats[icard]);
00380                         }
00381                 }       
00382                 TIMER_CHECK_OVERFLOW;
00383         }
00384 
00385         G_quit = 1;
00386         return 0;
00387 #undef EACHMFA
00388 #undef EACHBBB
00389 #undef EACHDAC_BASE
00390 #undef EACHDAC_BASE16
00391 }
00392 

Generated on Wed Jan 5 2011 for llcontrol by  doxygen 1.7.1