ACQ2XX_API
Acq132.cpp
Go to the documentation of this file.
00001 /* ------------------------------------------------------------------------- */
00002 /* Acq132.cpp: implementation of ACQ132 BURST MODE decoder                   */
00003 /* ------------------------------------------------------------------------- */
00004 /*   Copyright (C) 2009 Peter Milne, D-TACQ Solutions Ltd
00005  *                      <Peter dot Milne at D hyphen TACQ dot com>
00006  *                      http://www.d-tacq.com/
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of Version 2 of the GNU General Public License 
00010     as published by the Free Software Foundation;
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
00020 /* ------------------------------------------------------------------------- */
00021 
00022 #include <assert.h>
00023 #include <iostream>
00024 #include <map>
00025 #include <math.h>
00026 #include <string.h>
00027 
00028 #include "local.h"
00029 #include "Acq132.h"
00030 #include "AcqDataModel.h"
00031 
00032 // @@todo dynamic NUMCHANNELS?
00033 #define NUMCHAN 32
00034 
00035 
00036 /* Event data fields from rev 307+ */
00037 #define ACQ132_ES_DEC_CNT_MASK 0xff00
00038 #define ACQ132_ES_LAT_MASK      0x00fc
00039 
00040 #define ACQ132_ES_DEC_CNT(es)   (((es)&ACQ132_ES_DEC_CNT_MASK)>>8)
00041 #define ACQ132_ES_LAT_CNT(es)   (((es)&ACQ132_ES_LAT_MASK)>>2)
00042 
00043 /* 2 sample pipeline, could be more: eg with FIR.
00044  * values found for decimating boxcar found empirically */
00045 /* NACC [1..16] */
00046 static const int es_cold_offset_samples[129] = { /* [1..128] */
00047 /*      1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,0 */
00048         0,
00049         -5,-1,
00050               0,2,1,1,2,2,2,2,2,2,2,2,2,2,      /* 0 */
00051         2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,        /* 1 */
00052         2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,        /* 2 */
00053         2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,        /* 3 */
00054         2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,        /* 4 */
00055         2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,        /* 5 */
00056         2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,        /* 6 */
00057         2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,        /* 7 */
00058 };
00059 
00060 
00061 Channel::Channel(int _ch)
00062         : dump_path(""), ch(_ch)
00063 {
00064         char buf[16];
00065         sprintf(buf, "CH%02d", ch);
00066 
00067         name = buf;
00068         data.reserve(TBLOCK_ELEMS);
00069 }
00070 
00071 string& Channel::makeFileName() {
00072         return fileName = AcqDataModel::pfx + name;
00073 }
00074 void Channel::print() { 
00075         cerr << "Channel:" << ch << " len:" << data.size() << endl;
00076 }
00077 
00078 void Channel::dump(const string& root)
00079 {
00080         File f(root, makeFileName(), Channel::dump_mode);
00081 
00082         fwrite(&data[0], sizeof(short), data.size(), f.getFp());
00083         dump_path = f.getPath();
00084 }
00085 
00086 void Channel::dump(const string& root, unsigned s1, unsigned s2)
00087 {
00088         File f(root, makeFileName(), Channel::dump_mode);
00089 
00090         int len = (s2 <= data.size()? s2: data.size()) - s1;
00091 
00092         fwrite(&data[s1], sizeof(short), len, f.getFp());
00093         dump_path = f.getPath();
00094 }
00095 
00096 void Channel::clear()
00097 {
00098         data.clear();
00099 }
00100 
00101 class RGM_EventSignature : public EventSignature {
00102 
00103         static bool isES(const short _raw[]);
00104 
00105         RGM_EventSignature(short _raw[], unsigned long _sample_cursor):
00106                 EventSignature(_raw, _sample_cursor)
00107                 {
00108                         has_timestamp = 1;
00109                         dbg(1, "%d", _sample_cursor);
00110                 }
00111 public:
00112         static EventSignature* create(
00113                 short _raw[], unsigned long _sample_cursor)
00114 
00115         {
00116                 if (isES(_raw)){
00117                         return new RGM_EventSignature(_raw, _sample_cursor);
00118                 }else{
00119                         return 0;
00120                 }
00121         }
00122         virtual unsigned getCount() const {
00123                 union {
00124                         unsigned short s[2];
00125                         unsigned u;
00126                 } tmp;
00127                 
00128                 tmp.s[1] = raw[CHANROW/2];
00129                 tmp.s[0] = raw[CHANROW/2+2];
00130                 return tmp.u;   
00131         }
00132 };
00133 
00134 class DR_EventSignature : public EventSignature {
00135 
00136         static bool isES(const short _raw[]);
00137 
00138         DR_EventSignature(short _raw[], unsigned long _sample_cursor) :
00139                 EventSignature(_raw, _sample_cursor)
00140                 {
00141                         dbg(3, "%d", _sample_cursor);
00142                 }
00143 public:
00144 
00145         static EventSignature* create(
00146                 short _raw[], unsigned long _sample_cursor)
00147 
00148         {
00149                 if (isES(_raw)){
00150                         return new DR_EventSignature(_raw, _sample_cursor);
00151                 }else{
00152                         return 0;
00153                 }
00154         }
00155 
00156         virtual unsigned getCount() const {
00157                 return 0;
00158         }
00159 
00160         bool isTransitionToDiv1(void) const {
00161                 return (raw[3] & 0x1) != 0;
00162         }
00163 
00164         bool isTransitionToDiv0(void) const {
00165                 return (raw[3] & 0x2) != 0;
00166         }
00167 
00168         bool isBogusTransition(void) const {
00169                 bool A = isTransitionToDiv1();
00170                 bool B = isTransitionToDiv0();
00171                 return !(A ^ B);
00172         }
00173 
00174         virtual void print(void) {
00175                 printf("DR %u %04x %04x %04x %04x\n",
00176                        getSampleCursor(),
00177                        raw[0], raw[1], raw[2], raw[3]);
00178         }
00179 
00180         int getOffset(int div){
00181                 int offset = ACQ132_ES_LAT_CNT(raw[2]);
00182                 offset += es_cold_offset_samples[div];
00183                 return offset;          
00184         }
00185         int getDecimationPhase(void) {
00186                 return ACQ132_ES_DEC_CNT(raw[2]);
00187         }
00188         virtual unsigned long getSampleCursor(int div) {
00189 
00190                 return sample_cursor - getOffset(div);
00191         }
00192         virtual unsigned getSampleCursor() {
00193                 return getSampleCursor(0);
00194         }
00195 
00196 };
00197 
00198 EventSignature::EventSignature(short _raw[], unsigned long _sample_cursor) 
00199 :       sample_cursor(_sample_cursor), has_timestamp(0)
00200 {
00201         memcpy(raw, _raw, sizeof(raw));
00202 }
00203 
00204 bool DR_EventSignature::isES(const short _raw[]){
00205         const unsigned short* rr = (const unsigned short *)_raw;
00206 
00207         int rc = (rr[0] == 0xaa55) && (rr[1] == 0xaa55) &&
00208                  (rr[4] == 0xaa55) && (rr[5] == 0xaa55);
00209 
00210         
00211         if (rc){
00212                 dbg(2, "raw: %04x %04x %04x %04x %04x %04x %04x %04x rc:%d",
00213                     rr[0],      rr[1], rr[2],   rr[3],
00214                     rr[4],      rr[5], rr[6],   rr[7], rc);
00215         }else if (rr[0] == 0xaa55){
00216                 dbg(3, 
00217                 "raw part: %04x %04x %04x %04x %04x %04x %04x %04x rc:%d",
00218                     rr[0],      rr[1], rr[2],   rr[3],
00219                     rr[4],      rr[5], rr[6],   rr[7], rc);
00220         }
00221         return rc;
00222 }
00223 
00224 bool RGM_EventSignature::isES(const short _raw[]){
00225         const unsigned short* rr = (const unsigned short *)_raw;
00226 
00227         int rc = (rr[0] == 0xaa55) && (rr[1] == 0xaa55) &&
00228                  (rr[2] == 0xaa55) && (rr[3] == 0xaa55);
00229 
00230         
00231         if (rc){
00232                 dbg(2, "raw: %04x %04x %04x %04x %04x %04x %04x %04x rc:%d",
00233                     rr[0],      rr[1], rr[2],   rr[3],
00234                     rr[4],      rr[5], rr[6],   rr[7], rc);
00235         }else if (rr[0] == 0xaa55){
00236                 dbg(3, 
00237                 "raw part: %04x %04x %04x %04x %04x %04x %04x %04x rc:%d",
00238                     rr[0],      rr[1], rr[2],   rr[3],
00239                     rr[4],      rr[5], rr[6],   rr[7], rc);
00240         }
00241         return rc;
00242 }
00243 
00244 EventSignature* EventSignature::create(
00245         short _raw[], unsigned long _sample_cursor)
00246 {
00247         EventSignature *es = RGM_EventSignature::create(_raw, _sample_cursor);
00248 
00249         if (es){
00250                 return es;
00251         }else{
00252                 return es = DR_EventSignature::create(_raw, _sample_cursor);
00253         }
00254 }
00255 
00256 
00257 Quad::Quad(char _scan, char _lr, string mask) 
00258         : max_ch(0), scan(_scan),  lr(_lr)
00259 {
00260         if (acq200_debug){
00261                 cerr << "Quad() " << scan << lr << endl;
00262         }
00263         setChannels(mask);
00264         string::const_iterator cii;
00265 
00266         for(cii = mask.begin(); cii != mask.end(); cii++){
00267                 char cc = *cii;
00268                 if (cc != '0'){
00269                         if (cc >= '1' && cc <= '9'){
00270                                 speed = cc - '0';
00271                         }else if (cc >= 'a' && cc <= 'z'){
00272                                 speed = cc - 'a' + 10;
00273                         }else if (cc >= 'A' && cc <= 'Z' ){
00274                                 speed = cc - 'A' + 10 + 26;
00275                         }else{
00276                                 speed = 1;
00277                                 cerr << "Bad speed code: " << cc << endl;
00278                         }
00279                 }
00280         }
00281 };
00282 
00283 void Quad::print() {
00284         cerr << "Quad: scan:" << scan << 
00285                 " lr:" << lr << "speed:" << speed <<endl;
00286 
00287         for (int ic = 0; ic < CH_QUAD; ++ic){
00288                 if (channels[ic] != 0){
00289                         channels[ic]->print();
00290                 }
00291         }
00292 }
00293 
00294 void Quad::consume(int ic, short raw){
00295         if (channels[ic] != 0){
00296                 channels[ic]->data.push_back(raw);
00297         }
00298 }
00299 
00300 
00301 
00302 
00303 void DQuad::consume(short raw_row[]) {
00304         unsigned short *rr = (unsigned short *)raw_row;
00305         dbg(4, "raw: %04x %04x %04x %04x %04x %04x %04x %04x",
00306             rr[0],      rr[1], rr[2],   rr[3],
00307             rr[4],      rr[5], rr[6],   rr[7]);
00308         
00309         for (int ic = 0; ic < 2*CH_QUAD; ){
00310                 left.consume(ic/2,  rr[ic]); ic++;
00311                 right.consume(ic/2, rr[ic]); ic++;
00312         }
00313         ++sample_cursor;
00314 }
00315 
00316 void DQuad::print() {
00317         cerr << "DQuad: " << endl;
00318         left.print();
00319         right.print();
00320         cerr << "ES len: " << eventSignatures.size() << endl;
00321 }
00322 
00323 
00324 void DQuad::addES(EventSignature* _es, int eventOffset)
00325 {
00326         dbg(3, "01 offset %d", eventOffset);
00327 
00328         if (eventOffsets.size() == 0 || eventOffset != eventOffsets.back()){
00329                 eventSignatures.push_back(_es);
00330                 eventOffsets.push_back(eventOffset);
00331         }
00332 }
00333 
00334 vector<DQuad*> DQuad::instances;
00335 
00336 #define NQUAD   4
00337 
00338 struct ChannelMap {
00339         char scan;
00340         char lr;
00341         Channel channels[NQUAD];
00342 };
00343 
00344 struct ChannelMap default_channelMaps [] = {
00345 { SCAN_A, LEFT,  { Channel(13), Channel(14), Channel(15), Channel(16) } },
00346 { SCAN_A, RIGHT, { Channel(29), Channel(30), Channel(31), Channel(32) } },
00347 { SCAN_B, LEFT,  { Channel( 9), Channel(10), Channel(11), Channel(12) } },
00348 { SCAN_B, RIGHT, { Channel(25), Channel(26), Channel(27), Channel(28) } },
00349 { SCAN_C, LEFT,  { Channel( 5), Channel( 6), Channel( 7), Channel( 8) } },
00350 { SCAN_C, RIGHT, { Channel(21), Channel(22), Channel(23), Channel(24) } },
00351 { SCAN_D, LEFT,  { Channel( 1), Channel( 2), Channel( 3), Channel( 4) } },
00352 { SCAN_D, RIGHT, { Channel(17), Channel(18), Channel(19), Channel(20) } },      
00353 };
00354 
00355 struct ChannelMap lfp_channelMaps [] = {
00356 { SCAN_A, LEFT,  { Channel( 3), Channel( 4), Channel( 1), Channel( 2) } },
00357 { SCAN_A, RIGHT, { Channel(19), Channel(20), Channel(17), Channel(18) } },
00358 { SCAN_B, LEFT,  { Channel( 7), Channel( 8), Channel( 5), Channel( 6) } },
00359 { SCAN_B, RIGHT, { Channel(23), Channel(24), Channel(21), Channel(22) } },
00360 { SCAN_C, LEFT,  { Channel(11), Channel(12), Channel( 9), Channel(10) } },
00361 { SCAN_C, RIGHT, { Channel(27), Channel(28), Channel(25), Channel(26) } },
00362 { SCAN_D, LEFT,  { Channel(15), Channel(16), Channel(13), Channel(14) } },
00363 { SCAN_D, RIGHT, { Channel(31), Channel(32), Channel(29), Channel(30) } },
00364 };
00365 
00366 struct ChannelMap *channelMaps = default_channelMaps;
00367 
00368 #define NCHANNELMAPS 8
00369 
00370 class Cmask : public string {
00371 
00372 public:
00373         Cmask(string a_string) 
00374         : string(a_string)
00375         {
00376                 string::const_iterator cii;
00377                 int ii = 0;
00378 
00379                 for(cii = begin(); cii != end(); cii++, ++ii){
00380                         if (*cii != '0'){
00381                                 replace(ii, 1, "1");
00382                         }
00383                 }               
00384         }
00385 };
00386 
00387 
00388 void Quad::setChannels(string cs_mask)
00389 {
00390         int ix = (scan-SCAN_A)*2 + (lr==RIGHT);
00391         Cmask c_mask(cs_mask);
00392 
00393         assert(ix >= 0 && ix <= NCHANNELMAPS);
00394 
00395         ChannelMap *map = &channelMaps[ix];
00396 
00397         if (c_mask == "1111"){
00398                 channels[0] = &map->channels[0];
00399                 channels[1] = &map->channels[1];
00400                 channels[2] = &map->channels[2];
00401                 channels[3] = &map->channels[3];
00402         }else if (c_mask == "1010"){
00403                 channels[0] = &map->channels[2];        /* 3 */
00404                 channels[1] = &map->channels[2];        /* 3 */
00405                 channels[2] = &map->channels[0];        /* 1 */
00406                 channels[3] = &map->channels[0];        /* 1 */
00407         }else if (c_mask == "1000"){
00408                 channels[0] = 
00409                 channels[1] = 
00410                 channels[2] = 
00411                 channels[3] = &map->channels[0];        /* 1 */
00412         }else{
00413                 cerr << "Unknown mask:" << c_mask << endl;
00414         }
00415 
00416         for (int ch = 0; ch < CH_QUAD; ++ch){
00417                 for (int ch0 = 0; ch0 < max_ch; ++ch0){
00418                         if (channels[ch] == unique_channels[ch0]){
00419                                 goto next_channel;
00420                         }
00421                 }
00422                 unique_channels[max_ch++] = channels[ch];
00423 
00424         next_channel:
00425                 continue;
00426         }
00427 
00428 
00429 }
00430 
00431 void Quad::dump(const string& root)
00432 {
00433         dbg(2, "root %s", root.c_str());
00434         for (int ch = 0; ch < max_ch; ++ch){
00435                 unique_channels[ch]->dump(root);
00436         }
00437 }
00438 
00439 
00440 void Quad::dump(const string& root, unsigned s1, unsigned s2)
00441 {
00442         dbg(2, "root %s", root.c_str());
00443         for (int ch = 0; ch < max_ch; ++ch){
00444                 unique_channels[ch]->dump(root, s1, s2);
00445         }
00446 }
00447 
00448 void Quad::clear()
00449 {
00450         for (int ch = 0; ch < max_ch; ++ch){
00451                 unique_channels[ch]->clear();
00452         }
00453 }
00454 
00455 DQuad* DQuad::instance(Acq132DataModel& _parent, char scan, string mask)
00456 {
00457         vector<DQuad*>::iterator iter;
00458         DQuad *dq;
00459 
00460         for (iter = instances.begin(); iter != instances.end(); ++iter){
00461                 if ((*iter)->getScan() == scan){
00462                         cerr << "DQuad factory re-use:" << scan << endl;
00463                         return dq = *iter;
00464                 }
00465         }
00466         instances.push_back(dq = new DQuad(_parent, scan, mask));
00467         return dq;
00468 }
00469 
00470 
00471 unsigned EventSignature::getSamplesInPulse(EventSignature *es1)
00472 {
00473         return es1->sample_cursor - sample_cursor;
00474 }
00475 
00476 void DQuad::dumpTimebasePulse(
00477         File& ft, double ns, int samples_in_pulse,
00478         unsigned tsample)
00479 {
00480         double sec = ns/1e9;
00481         double sample_sec = ((double)tsample) / 1e9;
00482 
00483         for (int isam = 0; isam < samples_in_pulse; ++isam){
00484                 ft.write(&sec);
00485                 sec += sample_sec;
00486         }
00487 }
00488 
00489 void DQuad::dumpTimebase(const string& root, unsigned ess)
00490 {
00491         char tb_name[80];
00492 
00493         sprintf(tb_name, "%sTB%s", AcqDataModel::pfx.c_str(), id.c_str());
00494         File ft(root, tb_name);
00495 
00496         if (eventSignatures.size() == 0){
00497                 double ns = ess * Clock::sample_clock_ns;
00498                 dumpTimebasePulse(
00499                         ft, ns, left.channels[0]->data.size(), _tsample);
00500                 return;
00501         }
00502 
00503         vector<EventSignature*>::iterator iter = eventSignatures.begin();
00504         EventSignature* es0 = *iter;
00505         for (++iter; iter != eventSignatures.end(); ++iter){
00506                 EventSignature* es1 = *iter;
00507 
00508                 dumpTimebasePulse(ft, startNS(es0),
00509                         es0->getSamplesInPulse(es1), _tsample);
00510                 es0 = es1;
00511         }
00512         /* pick up last pulse */
00513         
00514         dumpTimebasePulse(ft, startNS(es0),
00515                 left.channels[0]->data.size() - es0->getSampleCursor(), 
00516                 _tsample);
00517 }
00518 
00519 double DQuad::dumpTimebaseUntil(
00520         File& ft, double t1, unsigned& begin, unsigned end, int div)
00521 {
00522         unsigned uu;
00523         double dt = Clock::sample_clock_ns * 1e-9 * div;
00524 
00525         dbg(1, "%g %u %d dt %g", t1, end, div, dt);
00526 
00527         for (uu = begin; uu < end; ++uu){
00528                 ft.write(&t1);
00529                 t1 += dt;
00530         }
00531         begin = end;
00532         return t1;
00533 }
00534 
00535 
00536 void DQuad::dumpTimebase(DumpDef& dd, EventSignature& es, unsigned s1, unsigned s2)
00537 {
00538         char tb_name[80];
00539         sprintf(tb_name, "%sTB%s", AcqDataModel::pfx.c_str(), id.c_str());
00540         File ft(dd.root, tb_name);
00541         unsigned delta_sam = dd.event_sample_start - dd.event_offset + s1;
00542         double t1_nsec;
00543 
00544         if (parent.timed_at_event){
00545                 if (es.getSampleCursor() ==
00546                                 (*eventSignatures.begin())->getSampleCursor()){
00547                         t1_nsec = (double)parent.msecs_start*NSEC_PER_MSEC -
00548                                                         dd.pre * _tsample;
00549                         first_s1 = s1;
00550                 }else{
00551                         t1_nsec = (double)parent.msecs_start*NSEC_PER_MSEC +
00552                                 (s1 - first_s1 - dd.pre) * _tsample;
00553                 }
00554         }else{
00555                 t1_nsec = (double)(delta_sam) *_tsample +
00556                           parent.msecs_start * NSEC_PER_MSEC;
00557         }
00558 
00559         dbg(1, "%s t1 %f _tsample %lu",
00560                 AcqDataModel::pfx.c_str(), t1_nsec/1.0e9, _tsample);
00561 
00562         dumpTimebasePulse(ft, t1_nsec, s2 - s1, _tsample);
00563 }
00564 
00565 static void dumpES_num(
00566         File& f, int offset, int decim_phase, int es_num, int len)
00567 {
00568         int *buf = new int[len];
00569         
00570         buf[0] = offset;
00571         buf[1] = offset;
00572         buf[2] = decim_phase;
00573         buf[3] = decim_phase;
00574         buf[4] = 128;
00575         buf[5] = 0;
00576         for (int ii = 6; ii < len; ++ii){
00577                 buf[ii] = es_num;
00578         }
00579         fwrite(buf, sizeof(int), len, f.getFp());
00580         delete [] buf;
00581 }
00582 
00583 static void dumpTimestamp(File& f, int sample, double t1, DR_EventSignature* dr)
00584 {
00585         int div = dr->isTransitionToDiv0()? DualRate::div1: DualRate::div0;
00586 
00587         fprintf(f.getFp(), "%10d %10.6f %3d %3d %d\n",
00588                 sample, t1, 
00589                 dr->getDecimationPhase(), dr->getOffset(div),
00590                 div);
00591 }
00592 
00593 
00594 void DQuad::dumpTimebaseDR(const string& root)
00595 /* first, decide if start in HI or LO
00596  * then, accumulate time at the appropriate rate
00597  */
00598 {
00599         // **todo ... use pfx
00600         File ft(root, "TB"+id);
00601         File tbix(root, "TBX"+id);
00602         File es_table(root, "ESvT"+id);
00603 
00604         vector<EventSignature*>::iterator iter;
00605         int es_count = 0;
00606         double ttotal = 0;
00607         unsigned sample = 0;
00608         DR_EventSignature* dr = 0;
00609 
00610         for (iter = eventSignatures.begin(); iter != eventSignatures.end(); ++iter){
00611                 EventSignature* es = *iter;
00612                 if (es->hasTimeStamp()){
00613                         dbg(1, "%s:skip bogus RGM event at %d", 
00614                             id.c_str(), es_count);
00615                         es->print();
00616                         continue;
00617                 }else{
00618                         int div;
00619 
00620                         dr = dynamic_cast<DR_EventSignature*>(es);
00621 
00622                         if (!dr){
00623                                 err("DOWNCAST to DR_EventSignature failed??");
00624                                 continue;
00625                         }else if (dr->isBogusTransition()){
00626                                 dbg(1, "skip bogus DR transition");
00627                                 continue;               
00628                         }else{
00629                                 div = dr->isTransitionToDiv0() ?
00630                                         DualRate::div1: DualRate::div0;
00631 
00632                                 dumpTimestamp(es_table, sample, ttotal, dr);
00633 
00634                                 dumpES_num(tbix, 
00635                                            dr->getOffset(div),
00636                                            dr->getDecimationPhase(),
00637                                            es_count, 
00638                                            dr->getSampleCursor(div) - sample);
00639 
00640                                 ttotal = dumpTimebaseUntil(ft, ttotal, sample,
00641                                            dr->getSampleCursor(div), div);
00642 
00643                         }
00644                 }
00645                 ++es_count;
00646         }
00647 
00648         if (dr){        
00649                 dumpTimebaseUntil(ft, ttotal, sample, getCursor(),      
00650                           dr->isTransitionToDiv0()? 
00651                                 DualRate::div0: DualRate::div1);
00652         }
00653                 
00654 }
00655 int DQuad::dumpES(const string& root)
00656 {
00657         File f(root, "ES"+id);
00658         vector<EventSignature*>::iterator iter;
00659         int es_count = 0;
00660 
00661         for (iter = eventSignatures.begin(); iter != eventSignatures.end(); ++iter){
00662                 unsigned count = (*iter)->getCount();
00663                 fwrite(&count, sizeof(unsigned), 1, f.getFp());
00664                 ++es_count;
00665         }
00666         return es_count;
00667 }
00668 
00669 
00670 int DQuad::scanES(const string& root)
00671 {
00672         File f(root, "ES-dump"+id);
00673         vector<EventSignature*>::iterator iter;
00674         vector<EventSignature*>::iterator behind;
00675         int es_count = 0;
00676 
00677         for (iter = eventSignatures.begin(); iter != eventSignatures.end(); ++iter, ++es_count){
00678                 unsigned long sc = (*iter)->getSampleCursor();
00679                 fwrite(&sc, sizeof(unsigned long), 1, f.getFp());
00680                 fwrite((*iter)->getRaw(), sizeof(short)*CHANROW, 1, f.getFp());
00681         }
00682         return es_count;
00683 }
00684 void DQuad::linkTimebase(const string& root, Quad& quad)
00685 {
00686         string tb = AcqDataModel::pfx + "TB"+id;
00687         int maxlen = root.length()+ AcqDataModel::pfx.length() + 20;
00688         char *ch_path = new char[maxlen];
00689 
00690         for (int ic = 0; ic < quad.max_ch; ++ic){
00691                 snprintf(ch_path, maxlen, "%s/%sTB%02d", root.c_str(),
00692                                 AcqDataModel::pfx.c_str(),
00693                                 quad.unique_channels[ic]->ch);
00694                 dbg(2, "calling symlink %s %s", tb.c_str(), ch_path);
00695                 symlink(tb.c_str(), ch_path);
00696 
00697                 if (DumpDef::common_timebase){
00698                         break;
00699                 }
00700         }
00701         delete [] ch_path;
00702 }
00703 void DQuad::dump(const string& root, unsigned ess)
00704 {
00705         dumpES(root);
00706 
00707         if (Clock::sample_clock_ns > 0){
00708                 if (DualRate::isDualRate()){
00709                         dumpTimebaseDR(root);
00710                 }else{
00711                         dumpTimebase(root, ess);
00712                 }
00713                 if (ess == 0){
00714                         linkTimebase(root, left);
00715                         linkTimebase(root, right);
00716                 }
00717         }
00718         left.dump(root);
00719         right.dump(root);
00720 }
00721 
00722 void DQuad::clear()
00723 {
00724         left.clear();
00725         right.clear();
00726         vector<EventSignature *>::iterator esit = eventSignatures.begin();
00727         for (; esit != eventSignatures.end(); ++esit){
00728                 delete (*esit);
00729         }
00730         eventSignatures.clear();
00731         eventOffsets.clear();
00732         sample_cursor = 0;
00733 }
00734 void DQuad::dump(DumpDef& dd)
00735 {
00736         vector<EventSignature *>::iterator esit = eventSignatures.begin();
00737         for (; esit != eventSignatures.end(); ++esit){
00738                 EventSignature *esp = *esit;
00739 
00740 
00741                 dbg(2, "sample_cursor %d with %d %s",
00742                                 esp->getRawSampleCursor(), dd.event_offset,
00743                                 esp->getRawSampleCursor() == dd.event_offset?
00744                                                 "MATCH": "no match");
00745 
00746                 if (esp->getRawSampleCursor() == dd.event_offset){
00747                         unsigned sc = esp->getSampleCursor();
00748                         unsigned s1 = sc > dd.pre? sc - dd.pre: 0;
00749                         unsigned s2 = sc + dd.post; //** @@todo overrun caught later?
00750 
00751                         dbg(2, "sample Cursor %ld s1 %d s2 %d\n", sc, s1, s2);
00752 
00753                         left.dump(dd.root, s1, s2);
00754                         right.dump(dd.root, s1, s2);
00755 
00756                         if (dd.dump_timebase){
00757                                 if (Clock::sample_clock_ns > 0){
00758                                         dumpTimebase(dd, *esp, s1, s2);
00759                                         linkTimebase(dd.root, left);
00760                                         linkTimebase(dd.root, right);
00761                                 }
00762                                 if (DumpDef::common_timebase){
00763                                         dd.dump_timebase = false;
00764                                 }
00765                         }
00766 
00767                         return;
00768                 }
00769         }
00770         err("FAILED to match event_offset");
00771 }
00772 
00773 
00774 Acq132DataModel::Acq132DataModel(
00775         string model_def,
00776         string _scanlist, string _channelMask) 
00777         : the_channels(),  maxsamples(0x7fffffff), actual_samples(0),
00778           timed_at_event(false)
00779 {
00780 #ifdef IKNOWWHATSWRONG
00781         string cm1 = "x" + _channelMask;
00782 #else
00783         char abuf[128];
00784         sprintf(abuf, "x%s", _channelMask.c_str());
00785         string cm1 = abuf;
00786 #endif
00787 
00788         dbg(1, "model_def %s scanlist %s channelMask %s",
00789                 model_def.c_str(), _scanlist.c_str(), _channelMask.c_str());
00790         dbg(1, "cm1 len %d \"%s\"", cm1.length(), cm1.c_str());
00791 
00792         if (model_def.find("lfp") != string::npos){
00793                 dbg(1, "setting lfp channel map");
00794                 channelMaps = lfp_channelMaps;
00795         }
00796 
00797         for (int ii = 0; ii != NCHANNELMAPS; ++ii){
00798                 for (int jj = 0; jj != NQUAD; ++jj){
00799                         Channel *channel = &channelMaps[ii].channels[jj];
00800                         the_channels[channel->ch] = channel;
00801                 }
00802         }
00803 #if 0
00804         for (int ii = 1; ii != 32; ++ii){
00805                 dbg(1, "ii %d ch %d", ii, the_channels[ii]->ch);
00806         }
00807 #endif
00808 
00809         string cmD = cm1.substr( 1, 4); string cmD2 = cm1.substr(17, 4);
00810         string cmC = cm1.substr( 5, 4); string cmC2 = cm1.substr(21, 4);
00811         string cmB = cm1.substr( 9, 4); string cmB2 = cm1.substr(25, 4);
00812         string cmA = cm1.substr(13, 4); string cmA2 = cm1.substr(29, 4);
00813 
00814         assert(cmD == cmD2);
00815         assert(cmC == cmC2);
00816         assert(cmB == cmB2);
00817         assert(cmA == cmA2);
00818 
00819         map<char, string> masks;
00820         masks[SCAN_A] = cmA;
00821         masks[SCAN_B] = cmB;
00822         masks[SCAN_C] = cmC;
00823         masks[SCAN_D] = cmD;
00824 
00825         for (unsigned iscan = 0; iscan < _scanlist.length(); ++iscan){
00826                 char scan = _scanlist[iscan];
00827                 scanlist.push_back(DQuad::instance(*this, scan, masks[scan]));
00828         }
00829 }
00830 vector<short>& Acq132DataModel::getChannel(int ichan)
00831 {
00832         return the_channels[ichan]->data;
00833 }
00834 
00835 void Acq132DataModel::print()
00836 {
00837         vector<DQuad*>::iterator iter;
00838 
00839         cerr << "Acq132Data:" << endl;
00840         for (iter = scanlist.begin(); iter != scanlist.end(); ++iter){
00841                 (*iter)->print();
00842         }       
00843 }
00844 
00845 static int SCAN_LIST3_HACK = getenv("SCAN_LIST3_HACK") != 0;
00846 
00847 void Acq132DataModel::processAll(short *data, int ndata)
00848 {
00849         vector<DQuad*>::iterator iter;
00850 
00851         dbg(1, "01 %p %d", data, ndata);
00852 
00853         int _actual_samples = 0;
00854         int hack_alert_count = 0;
00855         int first_time = 1;
00856         int isam;
00857         bool stash_es = true;
00858 
00859         if (AcqDataModel::processNoStashES(ndata)){
00860                 stash_es = false;
00861         }
00862 
00863         while (ndata > 0 && actual_samples < maxsamples){
00864 
00865                 for (iter = scanlist.begin(); iter != scanlist.end(); ++iter){
00866 
00867                         DQuad *dquad = *iter;
00868                         _actual_samples = actual_samples;
00869 
00870                         if (first_time+acq200_debug > 2){
00871                                 dquad->print();
00872                         }
00873 
00874                         for (isam = 0; ndata > 0 && isam < FIFOSAM; ++isam){
00875                                 int is_data;
00876 
00877                                 EventSignature *es = 
00878                                         EventSignature::create(
00879                                                 data, dquad->getCursor());
00880                                 if (es){
00881                                         if (stash_es){
00882                                                 dquad->addES(es, dquad->getCursor());
00883                                         }
00884                                         is_data = 0;
00885                                 }else{
00886                                         dquad->consume(data);
00887                                         is_data = 1;
00888                                 }
00889                                 data += CHANROW;
00890                                 ndata -= CHANROW;
00891 
00892                                 if (is_data && ++_actual_samples >= maxsamples){
00893                                         break;
00894                                 }
00895 
00896                         }
00897                 }
00898 
00899                 first_time = 0;
00900 
00901                 if (SCAN_LIST3_HACK){
00902 /** this is a HACK to test a theory about 1111111111110000 case*/
00903                         int len = 0;
00904                         for (iter = scanlist.begin(); 
00905                                 iter != scanlist.end(); ++iter){
00906                                 ++len;
00907                         }
00908                         if (len == 3){
00909                                 if (hack_alert_count++ == 0){
00910                                         info("HACK ALERT scanlist 3, skip one");
00911                                 }
00912                                 data += CHANROW * FIFOSAM;
00913                                 ndata -= CHANROW * FIFOSAM;
00914                                 
00915                         }
00916                         actual_samples = _actual_samples;
00917                 }
00918         }
00919 
00920 
00921         dbg(1, "99");
00922 }
00923 
00924 void Acq132DataModel::processSubBlock(short *data, int ndata)
00925 {
00926         vector<DQuad*>::iterator iter;
00927 
00928         dbg(1, "01 %p %d", data, ndata);
00929 
00930         int nsam = ndata / NUMCHAN;
00931         int first_time = 1;
00932 
00933         while (ndata > 0 && actual_samples < maxsamples){
00934 
00935                 for (iter = scanlist.begin(); iter != scanlist.end(); ++iter){
00936                         DQuad *dquad = *iter;
00937 
00938                         if (first_time+acq200_debug > 2){
00939                                 dquad->print();
00940                         }
00941 
00942                         for (int isam = 0; ndata > 0 && isam < nsam; ++isam){
00943                                 int is_data;
00944 
00945                                 EventSignature *es =
00946                                         EventSignature::create(
00947                                                 data, dquad->getCursor());
00948                                 if (es){
00949                                         dquad->addES(es, dquad->getCursor());
00950                                         is_data = 0;
00951                                 }else{
00952                                         dquad->consume(data);
00953                                         is_data = 1;
00954                                 }
00955                                 data += CHANROW;
00956                                 ndata -= CHANROW;
00957                         }
00958                         data += CHANROW * (FIFOSAM - nsam);
00959                 }
00960                 first_time = 0;
00961         }
00962 
00963         dbg(1, "99");
00964 }
00965 void Acq132DataModel::process(short *data, int ndata)
00966 {
00967         dbg(1, "%p %d abs %d", data, ndata, abs(ndata));
00968 
00969         if (abs(ndata) < FIFOSAM*NUMCHAN){
00970                 processSubBlock(data, ndata);
00971         }else{
00972                 processAll(data, ndata);
00973         }
00974 }
00975 
00976 void Acq132DataModel::trimSamples(void)
00977 {
00978         map<int, Channel*>::iterator it;
00979         unsigned shortest = 0;
00980         bool shortest_set = false;
00981 
00982         if (maxsamples){
00983                 shortest = maxsamples;
00984                 shortest_set = true;
00985 
00986         }
00987         for (it = the_channels.begin(); it != the_channels.end(); ++it){
00988                 if (!shortest_set || it->second->data.size() < shortest){
00989                         shortest = it->second->data.size();
00990                         shortest_set = true;
00991                 }
00992         }
00993 
00994         if (!shortest_set){
00995                 return;
00996         }
00997         for (it = the_channels.begin(); it != the_channels.end(); ++it){
00998                 for (unsigned ndel = it->second->data.size()-shortest; ndel; --ndel){
00999                         it->second->data.pop_back();
01000                 }
01001         }
01002 }
01003 
01004 void Acq132DataModel::dump(const string& root, unsigned ess)
01005 {
01006         dbg(2, "root %s", root.c_str());
01007 
01008         trimSamples();
01009 
01010         for (vector<DQuad*>::iterator iter = scanlist.begin();
01011                         iter != scanlist.end(); ++iter){
01012                 (*iter)->dump(root, ess);
01013         }
01014 
01015         for (vector<DQuad*>::iterator iter = scanlist.begin();
01016                         iter != scanlist.end(); ++iter){
01017                 (*iter)->scanES(root);
01018         }
01019 }
01020 
01021 void Acq132DataModel::setWallClockPolicy(
01022                 unsigned _msecs_start, bool _timed_at_event)
01023 {
01024         msecs_start = _msecs_start;
01025         timed_at_event = _timed_at_event;
01026 }
01027 void Acq132DataModel::clear()
01028 {
01029         for (vector<DQuad*>::iterator iter = scanlist.begin();
01030                         iter != scanlist.end(); ++iter){
01031                 (*iter)->clear();
01032         }
01033 }
01034 void Acq132DataModel::dump(DumpDef&dd)
01035 {
01036         // @@todo ... DO SOMETHING with dd. ie index to offset and don't repeat yourself ..
01037         vector<DQuad*>::iterator iter;
01038 
01039         dbg(1, "root %s", dd.root.c_str());
01040 
01041         for (iter = scanlist.begin(); iter != scanlist.end(); ++iter){
01042                 (*iter)->dump(dd);
01043         }
01044 }
01045 
01046 vector<int>& Acq132DataModel::getEvents()
01047 {
01048         DQuad* dquad = scanlist[0];
01049         dbg(2, "using dquad %c", dquad->getScan());
01050         return dquad->getEvents();
01051 }
01052 
01053 /* pick some defaults:
01054  * default ts_clock = 1MHz
01055  * default sample clock is 32MHz, prescale 4
01056  */
01057 
01058 #ifndef API
01059 double Clock::sample_clock_ns = 1000.0/32;
01060 #endif
01061 
01062 int DualRate::div0;
01063 int DualRate::div1;
01064 const char* Channel::dump_mode = getenv("CH_MODE")? getenv("CH_MODE"):"a";