LLC2_API
ll2.h
Go to the documentation of this file.
00001 /* ------------------------------------------------------------------------- */
00002 /* file ll2.h                                                                 */
00003 /* ------------------------------------------------------------------------- */
00004 /*   Copyright (C) 2011 Peter Milne, D-TACQ Solutions Ltd
00005  *                      <Peter dot Milne at D hyphen TACQ dot com>
00006  *  Created on: Sep 14, 2011
00007  *      Author: pgm
00008 
00009     http://www.d-tacq.com
00010 
00011     This program is free software; you can redistribute it and/or modify
00012     it under the terms of Version 2 of the GNU General Public License
00013     as published by the Free Software Foundation;
00014 
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU General Public License for more details.
00019 
00020     You should have received a copy of the GNU General Public License
00021     along with this program; if not, write to the Free Software
00022     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
00023 /* ------------------------------------------------------------------------- */
00024 
00025 /** @file ll2.h API definition for LOWLATENCY2.
00026  *
00027  */
00028 
00029 /**
00030 
00031 @mainpage llcontrol2
00032 
00033 @author Peter Milne <peter.milne@d-tacq.com>
00034 
00035 - Low Latency control operation:
00036  - Target push data transfer to slave memory on host card.
00037  - Data is delivered with minimum latency after the sample clock.
00038 
00039  - This implementation uses the same firmware and mechanism as the original
00040  LLCONTROL, but it's implemented as an API rather than a framework.
00041  In other words, USER code calls the API rather than the FRAMEWORK call USER code
00042  as before.
00043 
00044 
00045   - The API is implemented in C++. This allows the same efficient interface to the
00046   device driver as before, while at the same time making for a clean dynamic system instantiation.
00047   - The API is callable from C and, appropriately packaged from another math environment eg Python or IDL.
00048   - In particular, the API allows the user to work with a single array of each
00049   of AI, AO, DI, DO across multiple cards, and the complexity of memory buffering
00050   is completely hidden by the API.
00051   - The user defined the system using a simple config_file (xml).
00052   -The system generates an xml representation of itself. This should be used by
00053   higher level code to establish position of channels in the data buffers. The channel position does not change
00054   unless the configuration changes, so it is reasonables to code this as a constant.
00055   - Alternatively the system can be instantiated in a few lines of C++, with direct access methods for the channel offsets.
00056 
00057  - Implementing a control loop in C:
00058   -# Define the system cards and slots and operating parameters by calling RtSetup();
00059   -# Arm the system by calling RtArm()
00060   -# Run the control loop calling RtIO()
00061   -# Terminate RtStop();
00062 
00063  - Implementing a control loop in C++
00064   -# Define the system cards and slots, by creating an instance of LL_ControlSystem
00065   and populating it with ACQ_Cards.
00066   -# Define operating parameters using LL_ControlSystem::init();
00067   -# Set up IO buffers
00068   -# Call LL_ControlSystem::Arm()
00069   -# Run the control loop calling LL_ControlSystem::IO()
00070   -# Terminate with LL_ControlSystem::Stop();
00071 
00072 - For overview, please refer to
00073  - http://www.d-tacq.com/resources/D-Tacq_2G_UserGuide.pdf
00074 
00075 - Operation still relies on capture setup scripts as before, or the equivalent.
00076 - D-TACQ examples still use the same automated test environment of
00077  - MB : ACQ196 Master board
00078  - SB : optional ACQ196Slave board[s]
00079  - Sx : optional AO32 slave board[s]
00080  - CB : Clock Board - a further ACQ196 to provide external clock and trigger
00081 
00082 - D-TACQ recommends example-dynamic.cpp, this has complete system definition in xml and is therefore the most general example.
00083 - To run example-dynamic from bash prompt. Assume system definition "xml/example1-krypton.xml":
00084  - lookup_xml exports a few environment variables used in scripting..
00085 @verbatim
00086 ./xml_lookup xml/example1-krypton.xml system/exports
00087 CB=2 S1=3 MB=4
00088 export $(./xml_lookup xml/example1-krypton.xml system/exports)
00089 @endverbatim
00090  - Connect AO32 S1 AO0132 connector to ACQ196 MB AI0132 input
00091  - Connect AO32 S1 DO0132 connector to ACQ196 MB AI3364 input
00092  - Connect AO32 S1 DO3364 connector to ACQ196 MB AI6596 input
00093  - Host-side ACQ200 and AO32 drivers must be loaded.
00094 
00095  - Validate driver load:
00096 @verbatim
00097 acqcmd -s MB hostname
00098 
00099 set.ao32 $S1 AO_MODE M_AWGI
00100 get.ao32 $S1 AO_MODE
00101 # ... returns M_AWGI
00102 
00103 @endverbatim
00104  - Build LLC Software-
00105 @verbatim
00106 cd LOWLATENCY2; make
00107 @endverbatim
00108  - define the system by editing a local xml system def file:
00109   -eg xml/example1-krypton-96AI.xml
00110 @verbatim
00111 # create a job control file, example:
00112 
00113 # top-level-launcher
00114 cd PROJECTS/LOWLATENCY2/
00115  export LL2_SYSFILE=xml/example1-krypton.xml 
00116  export LL_OUTPUTS=data/ai-ramps.dat 
00117  export $(./xml_lookup $LL2_SYSFILE system/exports)
00118  cd scripts
00119  ./setup.ao32 $MB $S1
00120  ./deploy-script set.llc.wd $MB
00121  acqcmd -s $MB set.llc.wd
00122  source ./setup.clocks2 $MB 0 96 $CB
00123  init_clocks
00124 @endverbatim
00125  - now configure and run the system
00126 @verbatim
00127 source ./top-level-launcher
00128 # options
00129 ./web-trigger
00130 # run the shot -n ITERATIONS ECM (sample interval in 1usec ticks)
00131 ./example-dynamic -v 2 -n 10000 100
00132 @endverbatim
00133   - sample output
00134 @verbatim
00135 [dt100@krypton LOWLATENCY2]$ LL_OUTPUTS=data/ai-ramps.dat ./example-dynamic -v 2 -n 100 1000
00136 slot:2 class:acq196
00137 slot:3 class:ao32
00138 ECM 1000
00139 mmap 0xb7f4b000 offset 16
00140 data: 00000004 37400000 ffffffff 00000ec6
00141 mmapDmaBuffer() 01: open /dev/acq32/acq32.2.host
00142 mmapDmaBuffer() ask for full bigbuf portion 400000
00143 mmapDmaBuffer() fd_in:4 physaddr 0x37400000 vaddr 0xb7b42000 len 4194304
00144 mmapDmaBuffer() written host0.dat, zeroed
00145 speed=1197 ticks per microsecond
00146 ACQ196::init(0x9d49e1c) mbox 0x9d48ee8
00147 M_SYNC_2V sample size 256
00148 appEnterLLC_SYNC_2V() va:0xb7b42000 pa:0x37400000 MASTER slaves 1
00149 enterLLC()
00150 llSetAddr [2] 0x37400000
00151 leave LLC
00152 ~LL_ControlSystemI()
00153 @endverbatim
00154  - Validation
00155   - Channel 33-64 DO64 loopback to AI, data in AI.dat
00156 @verbatim
00157 [dt100@krypton LOWLATENCY2]$ ./scripts/dump.ai.decimal ai.dat 33-64 | ./scripts/do-analyse  | head
00158          1:00000000000000000000000000000000
00159          2:00000000000000000000000000000000
00160          3:11111111111111111111111111111111
00161          4:00000000000000000000000000000000
00162          5:11111111111111111111111111111111
00163          6:00000000000000000000000000000000
00164          7:11111111111111111111111111111111
00165          8:00000000000000000000000000000000
00166 @endverbatim
00167   - Timestamps
00168 @verbatim
00169 # NB: does not work on ACQ196-96-500, only ACQ196-96-250
00170 ./scripts/dump.status.decimal | cut -d\  -f 12 | tail
00171 9999920
00172 9999940
00173 9999960
00174 9999980
00175 10000000
00176 @endverbatim
00177   - AO/AI data. 
00178    - AO32 loopback to AI01-32 Data saved to ai.dat
00179    - use gnu-octave to view the data
00180 @verbatim
00181 cat llplot.m 
00182 
00183 1;
00184 nchan=96
00185 tb=1:100;
00186 fp=fopen("ai.dat");
00187 raw=fread(fp,Inf,"short");
00188 len=length(raw)
00189 chx=reshape(raw,nchan,len/nchan);
00190 plot(tb,chx(1:32,tb))
00191 octave
00192 octave:1> llplot
00193 
00194 @endverbatim
00195 
00196 */
00197 
00198 #ifndef LL2_H_
00199 #define LL2_H_
00200 
00201 #include <iostream>
00202 #include <vector>
00203 #include <stdio.h>
00204 #include <string.h>
00205 
00206 using namespace std;
00207 
00208 /** id's the classes of IO. */
00209 enum IO {
00210 
00211         AI, AO, DI, DO, ST, IONUM
00212 };
00213 
00214 /** id's the slot numbers. 1:1 correspondence */
00215 enum SLOTS {
00216 
00217         SLOT1=1, SLOT2, SLOT3, SLOT4, SLOT5, SLOT6, SLOT7, SLOT8
00218 };
00219 static const char* IO(enum IO io);
00220 
00221 /** new zero'd data - avoids valgrind errors. */
00222 template <class T> T* znew(int nwords) {
00223         T *buf = new T [nwords];
00224         memset(buf, 0, nwords*sizeof(T));
00225         return buf;
00226 }
00227 
00228 #define NO_VALUE                        0                               /**< null buffer arg (ignore). */
00229 #define AI_SIZE                         sizeof(short)
00230 #define AO_SIZE                         sizeof(short)
00231 #define DO_SIZE                         sizeof(u32)
00232 #define DI_SIZE                         sizeof(u32)
00233 #define STATUS_SIZE                     sizeof(u32)
00234 
00235 #define BITS_PER_DX_WORD        32              /**< DX packed into 32 bit words */
00236 
00237 /** base class for cards and system. */
00238 class ACQ {
00239 
00240 protected:
00241         const char* id;
00242         const int ai_count;
00243     const int di_count;
00244         const int ao_count;
00245         const int do_count;
00246 
00247 
00248         ACQ(int _ai_count, int _di_count, int _ao_count, int _do_count):
00249                 ai_count(_ai_count),
00250                 di_count(_di_count),
00251                 ao_count(_ao_count),
00252                 do_count(_do_count)
00253         {}
00254 
00255 public:
00256         virtual int getAI(short* ai_values) {
00257                 return -1;
00258         }
00259         virtual int putAO(const short* ao_values) {
00260                 return -1;
00261         }
00262         virtual int putDO(const unsigned *do_values){
00263                 return -1;
00264         }
00265         virtual int getDI(unsigned *di_values){
00266                 return -1;
00267         }
00268         virtual int getStatus(unsigned *status_values){
00269                 return -1;
00270         }
00271         virtual void print() {
00272                 cerr << id << " [" << "AI=" << ai_count << ","
00273                                            << "DI=" << di_count << ","
00274                                            << "AO=" << ao_count << ","
00275                                            << "DO=" << do_count << "]" << endl;
00276         }
00277 
00278         virtual int getAI_count(void) const { return ai_count; }
00279         virtual int getAO_count(void) const { return ao_count; }
00280         virtual int getDI_count(void) const { return di_count; }
00281         virtual int getDO_count(void) const { return do_count; }
00282         virtual int getStatus_count(void) const { return 0; }
00283         virtual ~ACQ() {}
00284 };
00285 
00286 /** opaque structure hooks to old llcontrol code. */
00287 struct Card;
00288 
00289 
00290 /** base class for physical cards. */
00291 class ACQ_Card: public ACQ {
00292 
00293 protected:
00294         const int slot;
00295         void registerCard(int slot);
00296 
00297 public:
00298         ACQ_Card(
00299                         int _slot,
00300                         int _ai_count, int _di_count, int _ao_count, int _do_count):
00301                 ACQ(_ai_count, _di_count, _ao_count, _do_count),
00302                 slot(_slot)
00303         {
00304                 registerCard(slot);
00305         }
00306         Card *card;
00307         virtual void init(Card *card) {}
00308 
00309         int getSlot() const { return slot; }
00310         static ACQ_Card* getCard(int slot);
00311 };
00312 
00313 
00314 class ACQ196 : public ACQ_Card {
00315 
00316 public:
00317         virtual int getAI(short* ai_values);
00318         virtual int putAO(const short* ao_values);
00319         virtual int putDO(const unsigned *do_values);
00320         virtual int getDI(unsigned *di_values);
00321         virtual int getStatus(unsigned *status_values);
00322         void toggle_wd();
00323 
00324 
00325         virtual void init(Card *card);
00326 
00327         ACQ196(int _slot, int _ai_count=96, int _di_count=32,
00328                 int _ao_count=16, int _do_count=0) :
00329                 ACQ_Card(_slot, _ai_count, _di_count, _ao_count, _do_count)
00330         {
00331                         char* _id = new char[64];
00332                         sprintf(_id, "acq196.%d", slot);
00333                         id = _id;
00334         }
00335         virtual ~ACQ196()
00336         {
00337                 delete [] id;
00338         }
00339         int getStatus_count(void) const;
00340 };
00341 
00342 class AO32 : public ACQ_Card {
00343         ACQ196* master;         /**< master card controlling this AO32. */
00344         int seq;                        /**< AO32 card # in set. */
00345 
00346 public:
00347         virtual int putAO(const short* ao_values);
00348         virtual int putDO(const unsigned *do_values);
00349 
00350         AO32(int _slot, int _ao_count=32, int _do_count=64) :
00351                 ACQ_Card(_slot, 0, 0, _ao_count, _do_count),
00352                 master(0), seq(0)
00353         {
00354                 char* _id = new char[64];
00355                 sprintf(_id, "ao32.%d", slot);
00356                 id = _id;
00357         }
00358 
00359         void setMaster(ACQ196* _master) {
00360                 master = _master;
00361         }
00362         void setIndex(int _index) {
00363                 seq = _index;
00364         }
00365         virtual ~AO32()
00366         {
00367                 delete [] id;
00368         }
00369 };
00370 
00371 
00372 
00373 /** abstract factory class - implementation detail hidden */
00374 class LL_ControlSystem : public ACQ {
00375 
00376 protected:
00377         LL_ControlSystem(const char *_id = "LL_ControlSystem"):
00378                 ACQ(0,0,0,0)
00379         {
00380                 id = _id;
00381         }
00382 
00383 public:
00384         virtual int addCard(ACQ196* _acq196) = 0;
00385         /**< add ACQ196 card to system. */
00386         virtual int addCard(AO32* _ao32) = 0;
00387         /**< add AO32 card to system. */
00388 
00389         virtual void print() = 0;
00390         /**< print a summary of the system.
00391          * xml output could be used to auto initialise application buffers
00392          */
00393 
00394         virtual void init(int argc, const char* argv[]) = 0;
00395         /**< initialise capture parameters. */
00396 
00397         virtual int Arm(
00398                         const short* ao_values_init = NO_VALUE,
00399                         const unsigned* do_values_init = NO_VALUE) = 0;
00400         /**< Arm the capture with initial conditions.
00401          * @param ao_values_init ensure initial AO condition.
00402          * @param do_values_init ensure initial DO condition.
00403          */
00404         virtual int IO(
00405                         const short* ao_values, const unsigned* do_values,
00406                         short* ai_values, unsigned* di_values, unsigned *status) = 0;
00407         /**< Block and return on next sample.
00408          *  Sets outputs before blocking, returns inputs.
00409          */
00410         virtual int Stop() = 0;
00411         /**< Stop the capture. */
00412 
00413         virtual int getSamples() const = 0;
00414         /**< returns samples to capture set in init(). */
00415 
00416         virtual int getOffset(ACQ_Card* card, enum IO io) = 0;
00417         /**< return offset in client vector for <card> with IO type <io>. */
00418         static LL_ControlSystem& create(const char *_id);
00419         /**< factory method
00420          * @param _id name to identify system
00421          * */
00422 
00423         static LL_ControlSystem& createFromFile(const char *config_file);
00424         /**< factory method
00425          * @param config_file names xml state file that pre-defines the system.
00426          * */
00427 
00428         static void closedown(LL_ControlSystem& sys);
00429         /**< cleanup */
00430 };
00431 
00432 #endif /* LL2_H_ */