LLC2_API
ll2.cpp
Go to the documentation of this file.
00001 /* ------------------------------------------------------------------------- */
00002 /* file ll2.cpp                                                                 */
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 25, 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.cpp API implementation for LOWLATENCY2.
00026  *
00027  */
00028 
00029 
00030 #include "local.h"
00031 #include <assert.h>
00032 #include <popt.h>
00033 #include <stdlib.h>
00034 #include <map>
00035 #include <iostream>
00036 #include <fstream>
00037 #include <string>
00038 using namespace std;
00039 
00040 
00041 #include "acq32ioctl.h"
00042 #include "acq32busprot.h"
00043 
00044 #include "llif.h"
00045 #include "llprotocol.h"
00046 #include "ll2.h"
00047 #include "llcontrol.h"
00048 #include "llcontrol-core.h"
00049 
00050 #include "xmlParser.h"
00051 
00052 #define VERID   "ll2 B1003"
00053 
00054 #define FOREACH(ii, vec) \
00055                 for (int lim = vec.size(), ii = 0; ii != lim; ++ii)
00056 
00057 
00058 int monitor = 0;
00059 
00060 
00061 static const char* IO(enum IO io)
00062 {
00063         switch(io){
00064         case AI: return "AI";
00065         case AO: return "AO";
00066         case DI: return "DI";
00067         case DO: return "DO";
00068         case ST: return "ST";
00069         default:
00070                         return "??";
00071         }
00072 }
00073 
00074 static std::map<int, ACQ_Card*> __slots;
00075 
00076 void ACQ_Card::registerCard(int slot)
00077 {
00078         if (__slots[slot] != 0){
00079                 fprintf(stderr, "ERROR: card already exists at slot:%d\n", slot);
00080                 exit(-1);
00081         }
00082         __slots[slot] = this;
00083 }
00084 
00085 ACQ_Card* ACQ_Card::getCard(int slot)
00086 {
00087         return __slots[slot];
00088 }
00089 
00090 int ACQ196::getAI(short* ai_values)
00091 {
00092         u32* adcs = getVaddr(card->buf, LLCV2_AI_HSBT);
00093         memcpy(ai_values, adcs, ai_count*AI_SIZE);
00094         return ai_count;
00095 }
00096 int ACQ196::putAO(const short* ao_values)
00097 {
00098         u32* dacs = getVaddr(card->buf, LLCV2_AO_HSBS);
00099 
00100         memcpy(dacs, ao_values, ao_count*AO_SIZE);
00101         return ao_count;
00102 }
00103 int ACQ196::putDO(const unsigned *do_values)
00104 {
00105         u32* va_base = getVaddr(card->buf, LLCV2_AO_HSBS);
00106         va_base[LLC_SYNC2V_DO] = *do_values;
00107         return do_count;
00108 }
00109 int ACQ196::getDI(unsigned *di_values)
00110 {
00111         u32* stats = getVaddr(card->buf, card->sync_2v_offset_status_hsbt);
00112         *di_values = stats[LLC_SYNC2V_IN_DI32];
00113         return di_count;
00114 }
00115 
00116 void ACQ196::toggle_wd(void)
00117 {
00118         u32* va_base = getVaddr(card->buf, LLCV2_AO_HSBS);
00119         unsigned wd_bit = va_base[LLC_SYNC2V_WD];
00120         va_base[LLC_SYNC2V_WD] = wd_bit ^ LLC_SYNC2V_WD_BIT;
00121 }
00122 
00123 #define STATUS_COUNT    16
00124 #define STATUS_LEN              (STATUS_COUNT*sizeof(u32))
00125 
00126 int ACQ196::getStatus(unsigned *status_values)
00127 {
00128         u32* stats = getVaddr(card->buf, card->sync_2v_offset_status_hsbt);
00129         memcpy(status_values, stats, STATUS_LEN);
00130         return STATUS_COUNT;
00131 }
00132 
00133 
00134 int ACQ196::getStatus_count(void) const { return STATUS_COUNT; }
00135 
00136 #define AO32_AO_COUNT   32
00137 #define AO32_AO_SIZE    (AO32_AO_COUNT*sizeof(short))
00138 #define AO32_AO_PAIRS   (AO32_AO_COUNT/2)
00139 #define AO32_DO_SIZE    8
00140 
00141 int AO32::putAO(const short* ao_values)
00142 {
00143         int offset_b = INDEX_OF_LLC_SYNC2V_AO32(seq)*sizeof(u32);
00144         u32* dacs = getVaddr(master->card->buf, LLCV2_AO_HSBS + offset_b);
00145         memcpy(dacs, ao_values, AO32_AO_SIZE);
00146         return AO32_AO_SIZE;
00147 }
00148 int AO32::putDO(const unsigned *do_values)
00149 {
00150         int offset_b = INDEX_OF_LLC_SYNC2V_AO32(seq)*sizeof(u32);
00151         u32* dacs = getVaddr(master->card->buf, LLCV2_AO_HSBS+offset_b);
00152 
00153         memcpy(dacs+AO32_AO_PAIRS, do_values, AO32_DO_SIZE);
00154         return AO32_DO_SIZE;
00155 }
00156 
00157 
00158 struct ClientBufCursor {
00159         ACQ_Card& card;                 /**< the card. */
00160         int client_offset;              /**< offset in client buffer. */
00161 
00162         ClientBufCursor(ACQ_Card& _card, int _client_offset) :
00163                 card(_card), client_offset(_client_offset)
00164         {}
00165         virtual ~ClientBufCursor()
00166         {}
00167 };
00168 
00169 typedef vector<ClientBufCursor*>::iterator CBI;
00170 
00171 XMLSTR stuff;
00172 
00173 /** concrete implementation, private to this module. */
00174 class LL_ControlSystemI : public  LL_ControlSystem {
00175 
00176         vector<ACQ_Card*> acq196;
00177         vector<ACQ_Card*> ao32;
00178         vector<ClientBufCursor*> AO_cursors;
00179         vector<ClientBufCursor*> AI_cursors;
00180         vector<ClientBufCursor*> DO_cursors;
00181         vector<ClientBufCursor*> DI_cursors;
00182         vector<ClientBufCursor*> ST_cursors;
00183 
00184         TestDescription *td;
00185 
00186         TimingStats tstats[MAXCARDS];
00187         u32 cmd;
00188         bool is_armed;
00189         bool finalize_done;
00190 
00191         void finalize(vector <ACQ_Card*>& cards, int offsets[4]);
00192         void finalize();
00193         void prime_ao(const short* ao_values);
00194         void prime_do(const unsigned* do_values);
00195         void gather_ai(short* ai_values);
00196         void gather_di(unsigned* di_values);
00197         void gather_status(unsigned *status);
00198         void toggle_wd(void);
00199 
00200         static void printClientOffset(const char *id, int offset);
00201 
00202         void printClientOffsets(ACQ_Card* card);
00203 
00204         static int lookupOffset(vector<ClientBufCursor*> cursors, const ACQ_Card* card);
00205 
00206         void simple_print();
00207         void print_xml(enum IO io, int len, int offset = 0);
00208         void print_xml(LL_ControlSystemI* sys, const char* typ);
00209         void print_xml(ACQ_Card* acq, enum IO io);
00210         void print_xml(ACQ_Card* card, const char* typ);
00211         void print_xml();
00212 
00213         static void setDefaults(TestDescription *td);
00214 
00215 public:
00216         LL_ControlSystemI(const char* _id):
00217                 LL_ControlSystem(_id),
00218                 finalize_done(false),
00219                 is_armed(false),
00220                 td(new TestDescription)
00221         {
00222                 setDefaults( td );
00223                 memset(tstats, 0, sizeof(tstats));
00224         }
00225         virtual ~LL_ControlSystemI();
00226 
00227         virtual int addCard(ACQ196* _acq196){
00228                 acq196.push_back(_acq196);
00229                 return acq196.size();
00230         }
00231         virtual int addCard(AO32* _ao32){
00232                 ao32.push_back(_ao32);
00233                 return ao32.size();
00234         }
00235         virtual int getAI_count(void) const;
00236         virtual int getAO_count(void) const;
00237         virtual int getDI_count(void) const;
00238         virtual int getDO_count(void) const;
00239         virtual int getStatus_count(void) const;
00240 
00241         virtual void init(int argc, const char* argv[]);
00242         virtual int Arm(const short* ao_values_init, const unsigned* do_values_init);
00243         virtual int IO(const short* ao_values, const unsigned* do_values,
00244                         short* ai_values, unsigned* di_values, unsigned *status);
00245         virtual int Stop();
00246 
00247         virtual void print();
00248 
00249         virtual int getSamples() const {
00250                 return td->iterations;                  /* iterations==#samples */
00251         }
00252 
00253         virtual int getOffset(ACQ_Card* card, enum IO io);
00254 };
00255 
00256 int LL_ControlSystemI::getOffset(ACQ_Card* card, enum IO io)
00257 {
00258         int offset;
00259         int channels_per_element = 1;
00260 
00261         switch(io){
00262         case AI:
00263                 offset = lookupOffset(AI_cursors, card);
00264                 break;
00265         case AO:
00266                 offset = lookupOffset(AO_cursors, card);
00267                 break;
00268         case DI:
00269                 offset = lookupOffset(DI_cursors, card);
00270                 channels_per_element = BITS_PER_DX_WORD;
00271                 break;
00272         case DO:
00273                 offset = lookupOffset(DO_cursors, card);
00274                 channels_per_element = BITS_PER_DX_WORD;
00275                 break;
00276         case ST:
00277                 offset = lookupOffset(ST_cursors, card);
00278                 break;
00279         }
00280 
00281         if (offset >= 0){
00282                 offset /= channels_per_element;
00283         }
00284         return offset;
00285 }
00286 
00287 int LL_ControlSystemI::getAI_count(void) const
00288 {
00289         int ai_count = 0;
00290         FOREACH(ii, acq196){
00291                 ai_count += acq196[ii]->getAI_count();
00292         }
00293         return ai_count;
00294 }
00295 int LL_ControlSystemI::getAO_count(void) const
00296 {
00297         int ao_count = 0;
00298         FOREACH(ii, acq196){
00299                 ao_count += acq196[ii]->getAO_count();
00300         }
00301         FOREACH(ii, ao32){
00302                 ao_count += ao32[ii]->getAO_count();
00303         }
00304         return ao_count;
00305 }
00306 int LL_ControlSystemI::getDI_count(void) const
00307 {
00308         int di_count = 0;
00309         FOREACH(ii, acq196){
00310                 di_count += acq196[ii]->getDI_count();
00311         }
00312         return di_count;
00313 
00314 }
00315 int LL_ControlSystemI::getDO_count(void) const
00316 {
00317         int do_count = 0;
00318         FOREACH(ii, ao32){
00319                 do_count += ao32[ii]->getDO_count();
00320         }
00321         return do_count;
00322 }
00323 int LL_ControlSystemI::getStatus_count(void) const
00324 {
00325         int st_count = 0;
00326         FOREACH(ii, acq196){
00327                 st_count += acq196[ii]->getStatus_count();
00328         }
00329         FOREACH(ii, ao32){
00330                 st_count += ao32[ii]->getStatus_count();
00331         }
00332         return st_count;
00333 }
00334 int LL_ControlSystemI::lookupOffset(
00335                 vector<ClientBufCursor*> cursors, const ACQ_Card* card)
00336 {
00337         FOREACH(ii, cursors){
00338                 if (cursors[ii]->card.getSlot() == card->getSlot()){
00339                         return cursors[ii]->client_offset;
00340                 };
00341         }
00342         return -1;
00343 }
00344 
00345 
00346 void LL_ControlSystemI::printClientOffset(
00347                 const char *id, int offset)
00348 {
00349         if (offset >= 0){
00350                 cerr << id << " " << offset  << endl;
00351         }
00352 }
00353 void LL_ControlSystemI::printClientOffsets(ACQ_Card* card)
00354 {
00355         printClientOffset("\tAI", getOffset(card, AI));
00356         printClientOffset("\tAO", getOffset(card, AO));
00357         printClientOffset("\tDI", getOffset(card, DI));
00358         printClientOffset("\tDO", getOffset(card, DO));
00359         printClientOffset("\tST", getOffset(card, ST));
00360 }
00361 
00362 void LL_ControlSystemI::simple_print() {
00363         cerr << id << endl;
00364         FOREACH(ii, acq196){
00365                 acq196[ii]->print();
00366                 printClientOffsets(acq196[ii]);
00367         }
00368         FOREACH(ii, ao32){
00369                 ao32[ii]->print();
00370                 printClientOffsets(ao32[ii]);
00371         }
00372 }
00373 
00374 
00375 char* indent(int level)
00376 {
00377         static char space[80];
00378         int ic;
00379 
00380         if (level > 80) level = 80;
00381 
00382         for (ic = 0; ic < level; ++ic){
00383                 space[ic] = ' ';
00384         }
00385         space[ic] = '\0';
00386         return space;
00387 }
00388 
00389 ofstream xml;
00390 
00391 void LL_ControlSystemI::print_xml(enum IO io, int len, int offset)
00392 {
00393         if (len > 0){
00394                 xml << indent(8) << "<data class=\"" << ::IO(io) << "\" len=\"" <<
00395                         len << "\" offset=\"" << offset << "\" />" << endl;
00396         }
00397 }
00398 void LL_ControlSystemI::print_xml(ACQ_Card* card, enum IO io)
00399 {
00400         int len;
00401         int offset = getOffset(card, io);
00402 
00403         switch(io){
00404         case AI:
00405                 len = card->getAI_count(); break;
00406         case AO:
00407                 len = card->getAO_count(); break;
00408         case DI:
00409                 len = card->getDI_count(); break;
00410         case DO:
00411                 len = card->getDO_count(); break;
00412         case ST:
00413                 len = card->getStatus_count(); break;
00414         }
00415 
00416         print_xml(io, len, offset);
00417 }
00418 void LL_ControlSystemI::print_xml(ACQ_Card* card, const char* typ)
00419 {
00420         xml << indent(4) << "<card class=\"" << typ << "\" slot=\"" <<
00421                                 card->getSlot() << "\" >" << endl;
00422         print_xml(card, AI);
00423         print_xml(card, AO);
00424         print_xml(card, DI);
00425         print_xml(card, DO);
00426         print_xml(card, ST);
00427 
00428         xml << indent(4) << "</card>" << endl;
00429 }
00430 
00431 class UnixQuery {
00432         char buf[80];
00433 public:
00434         UnixQuery(const char* command) {
00435                 FILE *fp = popen(command, "r");
00436                 assert(fp != 0);
00437                 assert(fgets(buf, 80, fp));
00438                 pclose(fp);
00439                 for (int ic = strlen(buf)-1; ic >=0; --ic){
00440                         if (buf[ic] == '\n'){
00441                                 buf[ic] = '\0';
00442                         }else{
00443                                 break;
00444                         }
00445                 }
00446         }
00447         ~UnixQuery() {
00448         }
00449         const char *toString() { return buf; };
00450 };
00451 class Date : public UnixQuery {
00452 public:
00453         Date() : UnixQuery("date") {
00454         }
00455 };
00456 
00457 class Host : public UnixQuery {
00458 public:
00459         Host() : UnixQuery("hostname") {}
00460 };
00461 
00462 class User : public UnixQuery {
00463 public:
00464         User() : UnixQuery("whoami") {}
00465 };
00466 
00467 void LL_ControlSystemI::print_xml(LL_ControlSystemI* sys, const char* typ)
00468 {
00469         Date date;
00470         Host host;
00471         User user;
00472 
00473         xml << indent(4) << "<!-- " << "summary defines applications's view of the data " << "-->" <<endl;
00474         xml << indent(4) << "<!-- summary created by " << user.toString() << "@" << host.toString() << " " << date.toString() << "-->" << endl;
00475         xml << indent(4) << "<!-- API version " << VERID <<  "-->" << endl;
00476         xml << indent(4) << "<summary>" << endl;
00477         print_xml(AI, getAI_count());
00478         print_xml(AO, getAO_count());
00479         print_xml(DI, getDI_count());
00480         print_xml(DO, getDO_count());
00481         print_xml(ST, getStatus_count());
00482 
00483         xml << indent(4) << "</summary>" << endl;
00484         if (stuff){
00485                 xml << stuff;
00486         }
00487 }
00488 
00489 
00490 #define NL      "\n"
00491 
00492 void LL_ControlSystemI::print_xml()
00493 {
00494         int level = 0;
00495 const char* offset_help = NL
00496 "function offset for each card is the start offset in the summary vector."      NL
00497 "value set programmatically after the system assembly has been finalized. "             NL
00498 "when instantiating by hand, set to zero, then if the app requires the offset, " NL
00499 "first create the offsets with the \"--print_quit option\", " NL
00500 "then parse the output file to determine the value of the offsets." NL
00501 "This value will be fixed between runs provided the set of cards is unchanged" NL;
00502 
00503         string fname(id);
00504         fname += ".xml";
00505         xml.open(fname.c_str());
00506         xml << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" << endl;
00507         xml << "<system name=\"" << id << "\">" << endl;
00508         xml << indent(4) << "<!-- WARNING: file overwritten every run" << " -->" << endl;
00509         xml << indent(4) << "<!-- Cards section defines stock of cards. Can modify by hand -->" <<endl;
00510         xml << indent(4) << "<!-- " << offset_help << "-->" << endl;
00511 
00512         FOREACH(ii, acq196){
00513                 print_xml(acq196[ii], "acq196");
00514         }
00515         FOREACH(ii, ao32){
00516                 print_xml(ao32[ii], "ao32");
00517         }
00518         print_xml(this, id);
00519         xml << "</system>" << endl;
00520         xml.close();
00521         cerr << "config:" << fname << " written" << endl;
00522 }
00523 void LL_ControlSystemI::print() {
00524         finalize();
00525         if (getenv("LLC2_SIMPLE_PRINT")){
00526                 simple_print();
00527         }else{
00528                 print_xml();
00529         }
00530 }
00531 
00532 
00533 void LL_ControlSystemI::finalize(vector <ACQ_Card*>& cards, int offsets[IONUM])
00534 {
00535         FOREACH(ii, cards){
00536                 ACQ_Card& card = *cards[ii];
00537                 if (card.getAI_count() != 0){
00538                         ClientBufCursor* cbc = new ClientBufCursor(card, offsets[AI]);
00539                         offsets[AI] += card.getAI_count();
00540                         AI_cursors.push_back(cbc);
00541                 }
00542                 if (card.getAO_count() != 0){
00543                         ClientBufCursor* cbc = new ClientBufCursor(card, offsets[AO]);
00544                         offsets[AO] += card.getAO_count();
00545                         AO_cursors.push_back(cbc);
00546                 }
00547                 if (card.getDO_count() != 0){
00548                         ClientBufCursor* cbc = new ClientBufCursor(card, offsets[DO]);
00549                         offsets[DO] += card.getDO_count();
00550                         DO_cursors.push_back(cbc);
00551                 }
00552                 if (card.getDI_count() != 0){
00553                         ClientBufCursor* cbc = new ClientBufCursor(card, offsets[DI]);
00554                         offsets[DI] += card.getDI_count();
00555                         DI_cursors.push_back(cbc);
00556                 }
00557                 if (card.getStatus_count() != 0){
00558                         ClientBufCursor* cbc = new ClientBufCursor(card, offsets[ST]);
00559                         offsets[ST] += card.getStatus_count();
00560                         ST_cursors.push_back(cbc);
00561                 }
00562         }
00563 }
00564 
00565 void LL_ControlSystemI::finalize()
00566 {
00567         if (!finalize_done){
00568                 int offsets[IONUM] = {};        /**< index by enum IO. */
00569 
00570                 finalize(acq196, offsets);
00571                 finalize(ao32, offsets);
00572 
00573                 ACQ196* master = dynamic_cast<ACQ196*>(acq196[0]);
00574                 if (master == 0){
00575                         cerr << "ERROR: configuration MUST include at least one ACQ196"
00576                                         <<endl;
00577                         exit(1);
00578                 }
00579 
00580                 FOREACH(ii, acq196){
00581                         acq196[ii]->init(&td->cards[ii]);
00582                         td->ncards += 1;
00583                 }
00584                 td->sample_offset = 256;  /* operate on 256 boundaries - easy debug */
00585 
00586                 td->sample_size = (getAI_count() + 32) * sizeof(short);
00587                 fprintf(stderr, "M_SYNC_2V sample size %d\n",
00588                                 td_sample_size(td));
00589 
00590                 FOREACH(ii, ao32){
00591                         AO32* slave = dynamic_cast<AO32*>(ao32[ii]);
00592                         slave->setMaster(master);
00593                         slave->setIndex(ii);
00594                         td->ao32_ids[td->ao32_count++] = ao32[ii]->getSlot();
00595                 }
00596 
00597                 if ( td->tlog ){
00598                         int ne = td->iterations;
00599                         FOREACHCARD{
00600                                 td->stats_buf[icard] = znew<TimingStats>(ne);
00601                         }
00602                 }
00603                 finalize_done = true;
00604         }
00605 }
00606 #define HELP \
00607                 "llcontrol [opts] mode \n"\
00608                 "\n"\
00609                 "opts:\n"\
00610                 "    -v verbose  verbose output\n"\
00611                 "    -d decimation {0..15} [default:1]\n"\
00612                 "    -n iterations [default:1]\n"\
00613                 "    -T {+,-} trigger edge [default:-]\n"\
00614                 "    -C {+,-} clock edge   [default:-]\n"\
00615                 "    -M <mask> use this interrupt mask\n"\
00616                 ""
00617 
00618 bool suppress_resource_init = false;
00619 
00620 void ACQ196::init(Card *_card)
00621 {
00622         card = _card;
00623         card->slot = slot;
00624         card->channels = getAI_count();
00625         if (suppress_resource_init) return;
00626 
00627         initCardResource(card);
00628         fprintf(stderr, "ACQ196::init(%p) mbox %p\n", card, card->mbx);
00629 }
00630 
00631 void LL_ControlSystemI::setDefaults(TestDescription *td)
00632 {
00633         memset(td, 0, sizeof(TestDescription));
00634         td->mode = TestDescription::M_SYNC_2VAO32;
00635         td->arg.interval = 0;
00636         td->iterations = 1;
00637         td->decimation = 1;
00638         td->overwrite = 0;
00639         td->clkpos = 1;
00640         td->trpos = 0;
00641         td->internal_loopback = 0;
00642 
00643         td->mask_ints = 0;
00644         td->mask_ints_mask = 0;
00645 
00646         td->update_dacs = 0;
00647         td->samples = 1;      /* samples > 1 is an acq216 thing */
00648 }
00649 
00650 static void setEdge( int* flag, const char* arg )
00651 {
00652         *flag = arg[0] == '+';
00653 }
00654 
00655 void makeIntMasks(TestDescription* td, const char* mask_on)
00656 {
00657         int len = strlen(mask_on);
00658 
00659         td->mask_ints = 1;
00660         td->mask_ints_mask = mask_on;
00661         td->unmask_ints_mask = new char[len+1];
00662         memset(td->unmask_ints_mask, '0', len);
00663         td->unmask_ints_mask[len] = '\0';
00664 }
00665 
00666 
00667 void LL_ControlSystemI::init(int argc, const char* argv[])
00668 {
00669 
00670 
00671         const char* arg;
00672         struct poptOption opt_table[] = {
00673                         { "verbose",    'v', POPT_ARG_INT,    &verbose,       0         },
00674                         { "decimation", 'd', POPT_ARG_INT,    &td->decimation, 0,
00675                                 "reduce output rate by N [1]"                                                   },
00676                         { "iterations", 'n', POPT_ARG_INT,    &td->iterations, 0,
00677                                 "capture samples [1]"                                                                   },
00678                         { "trgedge",    'T', POPT_ARG_STRING, &arg,          'T',
00679                                 "trigger edge {+|-} [-]"                                                                },
00680                         { "clkedge",    'C', POPT_ARG_STRING, &arg,          'C',
00681                                 "clock edge {+|-} [-]"                                                                  },
00682                         { "tstats",     't', POPT_ARG_NONE,   0,             't',
00683                                 "dump timing stats output to text file"                                 },
00684                         { "tstats_bin", 'b', POPT_ARG_STRING, &td->tlog_binfile, 'b',
00685                                 "dump timing stats output to binary file"                               },
00686                         { "int_mask",   'M', POPT_ARG_STRING, &arg,          'M',
00687                                 "masks interrupts ff...ff (64 chars) =ALL [0]"                  },
00688                         { "print_quit", 0,  POPT_ARG_NONE,   0,             'Q',
00689                                 "dump configuration and exit"                                                   },
00690                         { "monitor",    'm', POPT_ARG_INT,    &monitor,       0,
00691                                 "start a monitor co-routine to show progress"                   },
00692                         POPT_AUTOHELP
00693                         POPT_TABLEEND
00694         };
00695         poptContext opt_context = poptGetContext(argv[0], argc, argv, opt_table, 0);
00696         int rc;
00697 
00698         while ((rc = poptGetNextOpt(opt_context)) > 0 ){
00699                 switch( rc ){
00700                 case 'h':
00701                         fprintf(stderr, VERID "\n");
00702                         fprintf( stderr, HELP );
00703                         exit(1);
00704                 case 'T':
00705                         setEdge(&td->trpos, arg);
00706                         break;
00707                 case 'C':
00708                         setEdge(&td->clkpos, arg);
00709                         break;
00710                 case 'b': case 't':
00711                         td->tlog++;
00712                         break;
00713                 case 'M':
00714                         makeIntMasks(td, arg);
00715                         break;
00716                 case 'Q':
00717                         suppress_resource_init = true;
00718                         print();
00719                         exit(0);
00720                         break;
00721                 default:
00722                         ;
00723                 }
00724         }
00725 
00726         if ( (arg = poptGetArg( opt_context )) == NULL ){
00727                 td->arg.divisor = 100;
00728         }else{
00729                 td->arg.divisor = atoi(arg);
00730         }
00731         printf("ECM %d\n", td->arg.divisor);
00732 
00733         poptFreeContext(opt_context);
00734 }
00735 
00736 
00737 void LL_ControlSystemI::prime_ao(const short* ao_values) {
00738         if (ao_values == NO_VALUE) return;
00739 
00740         FOREACH(ii, AO_cursors){
00741                 ClientBufCursor* cbc = AO_cursors[ii];
00742                 ACQ& card = cbc->card;
00743                 card.putAO(ao_values+cbc->client_offset);
00744         }
00745 }
00746 void LL_ControlSystemI::gather_ai(short* ai_values) {
00747         if (ai_values == NO_VALUE) return;
00748 
00749         FOREACH(ii, AI_cursors){
00750                 ClientBufCursor* cbc = AI_cursors[ii];
00751                 ACQ& card = cbc->card;
00752                 card.getAI(ai_values+cbc->client_offset);
00753         }
00754 }
00755 
00756 void LL_ControlSystemI::prime_do(const unsigned* do_values)
00757 {
00758         if (do_values == NO_VALUE) return;
00759 
00760         FOREACH(ii, DO_cursors){
00761                 ClientBufCursor* cbc = DO_cursors[ii];
00762                 ACQ& card = cbc->card;
00763                 card.putDO(do_values+cbc->client_offset);
00764         }
00765 }
00766 void LL_ControlSystemI::gather_di(unsigned* di_values)
00767 {
00768         if (di_values == NO_VALUE) return;
00769 
00770         FOREACH(ii, DI_cursors){
00771                 ClientBufCursor* cbc = DI_cursors[ii];
00772                 ACQ& card = cbc->card;
00773                 card.getDI(di_values+cbc->client_offset);
00774         }
00775 }
00776 void LL_ControlSystemI::gather_status(unsigned *status)
00777 {
00778         if (status == NO_VALUE) return;
00779 
00780         FOREACH(ii, ST_cursors){
00781                 ClientBufCursor* cbc = ST_cursors[ii];
00782                 ACQ& card = cbc->card;
00783                 card.getStatus(status+cbc->client_offset);
00784         }
00785 
00786         if (td->tlog){
00787                 FOREACHCARD{
00788                         tstats[icard].target_poll = getMboxPollcount(EACHMBX(td));
00789                         updateTimingStats(
00790                                         td->stats_buf[icard], td->iter, &tstats[icard]);
00791                 }
00792         }
00793 }
00794 
00795 void LL_ControlSystemI::toggle_wd(void)
00796 {
00797         dynamic_cast<ACQ196*>(acq196[0])->toggle_wd();
00798 }
00799 #define OFFSET 0
00800 
00801 int LL_ControlSystemI::Arm(const short* ao_values, const unsigned* do_values)
00802 {
00803         finalize();
00804         setupAbortHandler(td);
00805         if ( monitor ){
00806                 setupMonitor(monitor);
00807         }
00808 
00809         prime_ao(ao_values);
00810         prime_do(do_values);
00811 
00812         FOREACHCARD{
00813                 appEnterLLC_SYNC_2VAO32(THIS_CARD, EACHMBX(td), td);
00814         }
00815 
00816         FOREACHCARD{
00817                 llSetTlatch(EACHMBX(td), tstats[icard].tlatch = 0xffffffff);
00818                 llv2InitDmaDone(getVaddr(EACHBUF(td),
00819                                                 EACHCARD(td)->sync_2v_offset_status_hsbt));
00820         }
00821         cmd = LLC_MAKE_DECIM(td->decimation);
00822 
00823 
00824         try {
00825                 FOREACHCARD{
00826                         updateTargetAddr(cmd+LLC_CSR_M_ARM, EACHCARD(td), OFFSET);
00827                 }
00828         } catch (int e) {
00829                 fprintf(stderr, "SNACK %08x\n", e);
00830                 exit(1);
00831         }
00832 
00833         if (td->mask_ints){
00834                 PRINTF(1)( "mask ints %s\n", td->mask_ints_mask );
00835                 FOREACHCARD{
00836                         acq200_setImask(EACHSLOT(td), td->mask_ints_mask);
00837                 }
00838         }
00839 
00840         return 0;
00841 }
00842 int LL_ControlSystemI::IO(const short* ao_values, const unsigned* do_values,
00843                 short* ai_values, unsigned* di_values, unsigned *status)
00844 {
00845         prime_ao(ao_values);
00846         prime_do(do_values);
00847 
00848         FOREACHCARD{
00849                 tstats[icard].tlatch = waitDmaDone(EACHCARD(td));
00850         }
00851         FOREACHCARD{
00852                 updateTstats(cmd, EACHCARD(td), &tstats[icard]);
00853         }
00854 
00855         gather_ai(ai_values);
00856         gather_di(di_values);
00857         gather_status(status);
00858         toggle_wd();
00859         ++td->iter;
00860         return 0;
00861 }
00862 int LL_ControlSystemI::Stop()
00863 {
00864         if (td->mask_ints){
00865                 PRINTF(1)( "mask ints 0x%04x\n", td->mask_ints_mask);
00866                 FOREACHCARD{
00867                         acq200_setImask(EACHSLOT(td), td->unmask_ints_mask);
00868                 }
00869         }
00870         try {
00871                 FOREACHCARD{
00872                         leaveLLC(EACHMBX(td));
00873                 }
00874         } catch (int e) {
00875                 fprintf(stderr, "SNACK %08x\n", e);
00876                 exit(1);
00877         }
00878 }
00879 
00880 
00881 template<class T>  void deleteClear(vector<T*>& vec){
00882         FOREACH(ii, vec){
00883                 delete vec[ii];
00884         }
00885         vec.clear();
00886 }
00887 
00888 LL_ControlSystemI::~LL_ControlSystemI()
00889 {
00890         printf("~LL_ControlSystemI()\n");
00891         doPostShotAnalysis(td);
00892 
00893         deleteClear<ClientBufCursor>(AO_cursors);
00894         deleteClear<ClientBufCursor>(AI_cursors);
00895         deleteClear<ClientBufCursor>(DO_cursors);
00896         deleteClear<ClientBufCursor>(DI_cursors);
00897         deleteClear<ClientBufCursor>(ST_cursors);
00898         deleteClear<ACQ_Card>(ao32);
00899         deleteClear<ACQ_Card>(acq196);
00900 }
00901 LL_ControlSystem& LL_ControlSystem::create(const char *_id)
00902 {
00903         return *new LL_ControlSystemI(strcpy(new char[strlen(_id)+1], _id));
00904 }
00905 
00906 const char* getAttribute(XMLNode& node, const char* attribute)
00907 {
00908         const char* attr = node.getAttribute(attribute);
00909         if (attr == NULL){
00910                 fprintf(stderr, "ERROR in xml node:\"%s\" missing attribute \"%s\"\n",
00911                                 node.getName(), attribute);
00912                 exit(-1);
00913         }
00914         return attr;
00915 }
00916 
00917 static char *newstr(const char* oldstr){
00918         return strcpy(new char[strlen(oldstr)+1], oldstr);
00919 }
00920 
00921 static int makeArgs(const XMLNode& runtime, char*** p_argv)
00922 {
00923         int nargs = runtime.nChildNode("arg")*2+1;
00924         if (nargs == 0) return 0;
00925         char** argv = new char* [++nargs];
00926         int ii = 0;
00927 
00928         argv[ii++] = newstr("ll2");
00929 
00930         for (; ii < nargs; ++ii){
00931                 /** three possibilities, all work:
00932                  * --key
00933                  * --key value
00934                  * value
00935                  */
00936                 XMLNode arg = runtime.getChildNode("arg", ii-1);
00937                 const char* key = arg.getAttribute("key");
00938                 if (key){
00939                         argv[ii++] = newstr(key);
00940                 }
00941                 const char* value = arg.getAttribute("value");
00942                 if (value){
00943                         argv[ii++] = newstr(value);
00944                 }
00945         }
00946         *p_argv = argv;
00947         return nargs;
00948 }
00949 LL_ControlSystem& LL_ControlSystem::createFromFile(const char *config_file)
00950 /**< factory method
00951  * @param init_file names xml state file that pre-defines the system.
00952  * */
00953 {
00954         XMLNode root = XMLNode::openFileHelper(config_file, "system");
00955         LL_ControlSystem& the_system = create(getAttribute(root, "name"));
00956         int ncards = root.nChildNode("card");
00957 
00958         for (int ic = 0; ic < ncards; ++ic){
00959                 int AI = 0;
00960                 int AO = 0;
00961                 int DO = 0;
00962                 int DI = 0;
00963                 XMLNode card = root.getChildNode("card", ic);
00964                 int slot = atoi(getAttribute(card, "slot"));
00965                 const char* acq_class = getAttribute(card, "class");
00966                 printf("slot:%d class:%s\n", slot, acq_class);
00967 
00968                 int ndata = card.nChildNode("data");
00969                 for (int id = 0; id < ndata; ++id){
00970                         XMLNode data = card.getChildNode("data", id);
00971                         const char* dclass = getAttribute(data, "class");
00972                         int dlen = atoi(getAttribute(data, "len"));
00973 
00974                         if (strcmp(dclass, "AI") == 0){
00975                                 AI = dlen;
00976                         }else if (strcmp(dclass, "AO") == 0){
00977                                 AO = dlen;
00978                         }else if (strcmp(dclass, "DI") == 0){
00979                                 DI = dlen;
00980                         }else if (strcmp(dclass, "DO") == 0){
00981                                 DO = dlen;
00982                         }else{
00983                                 ;
00984                         }
00985                 }
00986 
00987                 if (strcmp(acq_class, "acq196") == 0){
00988                         the_system.addCard(new ACQ196(slot, AI, DI, AO, DO));
00989                 }else if (strcmp(acq_class, "ao32") == 0){
00990                         the_system.addCard(new AO32(slot, AO, DO));
00991                 }else{
00992                         fprintf(stderr, "ERROR: bad acq_class \"%s\"\n", acq_class);
00993                 }
00994         }
00995         XMLNode runtime = root.getChildNode("runtime");
00996         if (!runtime.isEmpty()){
00997                 char **argv;
00998                 int argc = makeArgs(runtime, &argv);
00999                 stuff = runtime.createXMLString();
01000                 the_system.init(argc, (const char**)argv);
01001         }
01002         return the_system;
01003 }
01004 
01005 
01006 void LL_ControlSystem::closedown(LL_ControlSystem& sys)
01007 {
01008         delete &sys;
01009 }
01010 
01011 
01012 
01013