LLC2_API
|
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