v890.cpp

Go to the documentation of this file.
00001 #include <config.h>
00002 #include <v890.h>
00003 #include <string>
00004 #include <CVMEInterface.h>
00005 #include <sys/types.h>
00006 #include <unistd.h>
00007 #include <assert.h>
00008 #include <stdio.h>
00009 #ifdef HAVE_STD_NAMESPACE
00010 using namespace std;
00011 #endif
00012 
00013 static const unsigned int CAENPROMOffset(0x4000);
00014 static const unsigned int assinine_delay(10);
00015 const int CAENV890::m_nTdcClock(25);    // TDC clock in ns.
00016 const int CAENV890::m_nTdcMaxVal(4095); // Maximum TDC value.
00017 
00018 
00019 typedef u_char byte;
00020 
00021 
00022 //   PROM layout
00023 
00024 struct CAENProm {
00025   byte    m_pad0[0x26];         // 0x4000
00026   u_short m_OUIMsb;             // 0x4026
00027   u_short m_pad1;               // 0x4028
00028   u_short m_OUI;                // 0x402a
00029   u_short m_pad2;               // 0x402c
00030   u_short m_OUILsb;             // 0x402e
00031   u_short m_pad3;               // 0x4030
00032   u_short m_Version;            // 0x4032
00033   u_short m_pad4;               // 0x4034
00034   u_short m_BoardTypeMSB;       // 0x4036
00035   u_short m_pad5;               // 0x4038
00036   u_short m_BoardType;          // 0x403a
00037   u_short m_pad6;               // 0x403c
00038   u_short m_BoardTypeLSB;       // 0x403e
00039   byte    m_pad7[0x0e];         // 0x4040
00040   u_short m_Revision;           // 0x404e
00041   byte    m_pad8[0xeb2];        // 0x4050
00042   u_short m_SerialMsb;          // 0x4f02
00043   u_short m_pad9;               // 0x4f04
00044   u_short m_SerialLsb;          // 0x4f06
00045 };
00046 static const unsigned int CAENPROMSize(sizeof(CAENProm));
00047 
00048 
00049 // Module register map.
00050 
00051 struct CAENRegisters {
00052   u_long  m_OutputBuffer[0x1000/sizeof(u_long)]; // 0x0000
00053   u_short m_ControlRegister;    // 0x1000
00054   u_short m_StatusRegister;     // 0x1002
00055   u_short m_Ader32;             // 0x1004
00056   u_short m_Ader24;             // 0x1006
00057   u_short m_EnableAder;         // 0x1008
00058   u_short m_IPL;                // 0x100a
00059   u_short m_Vector;             // 0x100c
00060   u_short m_Geo;                // 0x100e
00061   u_short m_MCSTBase;           // 0x1010
00062   u_short m_MCSTCtl;            // 0x1012
00063   u_short m_Reset;              // 0x1014
00064   u_short m_Pad;                // 0x1016
00065   u_short m_Clear;              // 0x1018
00066   u_short m_SWEventReset;       // 0x101a
00067   u_short m_SWTrigger;          // 0x101c
00068   u_short m_EventCounter;       // 0x101e
00069   u_short m_EventStored;        // 0x1020
00070   u_short m_AlmostFullLvl;      // 0x1022
00071   u_short m_BLTEventNumber;     // 0x1024
00072   u_short m_FWRevision;         // 0x1026
00073   u_short m_TestLow;            // 0x1028
00074   u_short m_TestHigh;           // 0x102a
00075   u_short m_OutProgControl;     // 0x102c
00076   volatile u_short m_Micro;     // 0x102e
00077   volatile u_short m_MicroHandshake; // 0x1030
00078 
00079 };
00080 static const unsigned int CAENRegisterSize(sizeof(CAENRegisters));
00081 
00082 // Status Register bits:
00083 
00084 const u_short STAT_DATAREADY(1);
00085 
00086 
00087 // Control register bits:
00088 
00089 const u_short CTL_BERREN(1);
00090 const u_short CTL_TERM(2);
00091 const u_short CTL_TERMSW(4);
00092 const u_short CTL_ENABLE_EMPTY(8);
00093 const u_short CTL_ALIGN_64(16);
00094 const u_short CTL_TEST(32);
00095 
00096 // Micro handshake register:
00097 
00098 
00099 const u_short UH_WRITE_OK(1);
00100 const u_short UH_READ_OK(2);
00101 
00102 // Data format bits:
00103 
00104 const u_long DATA_GLOBALTYPE_MASK(0xc0000000);
00105 const u_long DATA_GLOBALTYPE_GBLHEADER(0x40000000);
00106 const u_long DATA_GLOBALTYPE_DATA(0x00000000);
00107 const u_long DATA_GLOBALTYPE_GBLEOB(0x80000000);
00108 const u_long DATA_GLOBALTYPE_FILLER(0xc0000000);
00109 
00110 const u_long DATA_TDCTYPE_MASK(0xf8000000);
00111 const u_long DATA_TDCTYPE_HEADER(0x08000000);
00112 const u_long DATA_TDCTYPE_CHANNEL(0x00000000);
00113 const u_long DATA_TDCTYPE_EOB(0x18000000);
00114 const u_long DATA_TDCTYPE_ERROR(0x20000000);
00115 
00116 
00145 CAENV890::CAENV890(int           nSlot,
00146                    int           nCrate,
00147                    bool          fGeo,
00148                    unsigned long lBase) :
00149   m_nSlot(nSlot),
00150   m_nCrate(nCrate),
00151   m_fGeographical(fGeo),
00152   m_lBase(lBase),
00153   m_pModule(0),
00154   m_pVmeDevice(0),
00155   m_nModuleType(0)
00156 {
00157   MapModule();
00158 
00159 }
00160    
00164 CAENV890::~CAENV890() 
00165 {
00166   if(m_pModule && m_pVmeDevice) { // Have mapping and file: unmap.
00167     CVMEInterface::Unmap(m_pVmeDevice,
00168                          m_pModule,
00169                          CAENRegisterSize);
00170   }
00171 }
00172 
00185 void*
00186 CAENV890::MapRegions(void* pfd, unsigned long base)
00187 {
00188   m_pModule = CVMEInterface::Map(pfd, base, CAENRegisterSize);
00189   return      CVMEInterface::Map(pfd, base + CAENPROMOffset,
00190                                  CAENPROMSize);
00191 }
00192 
00193 
00205 void
00206 CAENV890::MapModule()
00207 {
00208   // Open the vme crate.
00209 
00210   void* pDevice;
00211   CAENProm* pProm;
00212   unsigned long mapbase;
00213   try {
00214     if(m_fGeographical) {
00215       pDevice = CVMEInterface::Open(CVMEInterface::GEO, 
00216                                     m_nCrate);
00217       mapbase = m_nSlot << 19;
00218     }
00219     else {
00220       pDevice = CVMEInterface::Open(CVMEInterface::A32, 
00221                                     m_nCrate);
00222       mapbase = m_lBase;
00223     }
00224   }
00225 
00226   catch (string& reason) {
00227     throw (string("Can't open VME bus: ") + reason);
00228   }
00229 
00230   // Map to the module registers and prom initially.
00231 
00232 
00233   string MapFail1("Can't make ");
00234 
00235   MapFail1 += m_fGeographical ? "Geo map: " : "A32 map: ";
00236 
00237   try {
00238     pProm = (CAENProm*)MapRegions(pDevice, mapbase);
00239 
00240   }
00241   catch (string& reason) {
00242     throw (MapFail1 + reason);
00243   }
00244   
00245   m_pVmeDevice = pDevice;
00246   m_nModuleType = ReadModuleType(pProm);
00247  
00248 
00249   // Unmap the prom 
00250  
00251   CVMEInterface::Unmap(pDevice, pProm, CAENPROMSize);
00252 
00253   // The module must be a v890:
00254 
00255   if(m_nModuleType != 890) {
00256     CVMEInterface::Unmap(pDevice, m_pModule, sizeof(CAENRegisterSize));
00257     char message[100];
00258     sprintf(message, "Module in slot %d is not a V890",
00259             m_nSlot);
00260     throw string(message);
00261   }
00262   Reset();                      // Reset the module.
00263 
00264   // If the mapping was geographical, program base address and
00265   // remap as A32 with slot derived addressing.  This is needed in order to
00266   // allow us to access the buffer memory.  We choose a base address of
00267   //   slot << 24 
00268   // which allows us to just programthe geographical address in adrhigh and
00269   // leave adr low empty.
00270   //
00271   volatile CAENRegisters* pRegisters = (volatile CAENRegisters*)m_pModule;
00272   try {
00273     if(m_fGeographical) {
00274       pRegisters->m_Ader32 = m_nSlot; // Set the address base registers
00275       pRegisters->m_Ader24 = 0;
00276       pRegisters->m_EnableAder = 1;       // Enable address reloc.
00277       
00278       CVMEInterface::Unmap(m_pVmeDevice, m_pModule , CAENRegisterSize);
00279       CVMEInterface::Close(m_pVmeDevice);
00280       m_pVmeDevice = CVMEInterface::Open(CVMEInterface::A32, m_nCrate);
00281       pProm     = (CAENProm*)MapRegions(m_pVmeDevice, (m_nSlot << 24));
00282 
00283       int mtype = ReadModuleType(pProm);
00284       assert(mtype = m_nModuleType);
00285 
00286       CVMEInterface::Unmap(m_pVmeDevice, pProm,CAENPROMSize);
00287 
00288     }
00289     else {                      // program geo address.
00290       pRegisters->m_Geo = m_nSlot;
00291     }
00292   }
00293   catch(string& reason) {
00294     string Exception("Couldn't remap geo->a32 ");
00295     Exception += reason;
00296     throw Exception;
00297   }
00298   
00299 }
00300 
00301 
00307 unsigned 
00308 CAENV890::getSlotRegister() const
00309 {
00310   return (((volatile CAENRegisters*)m_pModule)->m_Geo) & 0x1f;
00311 }
00312 
00319 void
00320 CAENV890::EmptyEvent(bool state)
00321 {
00322   u_short control = ((volatile CAENRegisters*)m_pModule)->m_ControlRegister;
00323   control        &= ~CTL_ENABLE_EMPTY;  // Turn off the bit...
00324   if(state)  control |= CTL_ENABLE_EMPTY;       // Turn it back on.
00325   ((volatile CAENRegisters*)m_pModule)->m_ControlRegister = control;
00326 }
00331 bool
00332 CAENV890::EmptyEventOn()
00333 {
00334   u_short control = ((volatile CAENRegisters*)m_pModule)->m_ControlRegister;
00335   return (control & CTL_ENABLE_EMPTY) != 0;
00336 }
00341 void
00342 CAENV890::Reset()
00343 {
00344   ((volatile CAENRegisters*)m_pModule)->m_Reset = 0;
00345   usleep(1*1024*1024);          // That's a megasecond :-).
00346 }
00350 void
00351 CAENV890::Clear()
00352 {
00353   ((volatile CAENRegisters*)m_pModule)->m_Clear = 0;
00354 }
00355 
00370 u_int
00371 CAENV890::Read(u_int nBufferSize, void* pBuffer)
00372 {
00373   u_long* p = (u_long*)pBuffer;
00374   u_long datum;
00375   u_int  nRead(0);
00376 
00377   volatile CAENRegisters* pModule = (CAENRegisters*)m_pModule;
00378 
00379   if(nBufferSize > sizeof(pModule->m_OutputBuffer)) {
00380     throw string("CAENV890::Read buffersize is too big");
00381   }
00382 
00383   while(((datum = pModule->m_OutputBuffer[nRead]) & DATA_GLOBALTYPE_MASK) 
00384         != DATA_GLOBALTYPE_FILLER) {
00385     *p++ = datum;
00386     nRead++;
00387   }
00388   return nRead;
00389 }
00390 
00399 void
00400 CAENV890::TestMode(bool enable, u_long nPattern)
00401 {
00402   volatile CAENRegisters* pModule=(volatile CAENRegisters*)m_pModule;
00403   
00404   if(enable) {
00405     pModule->m_ControlRegister |= CTL_TEST;
00406     pModule->m_TestLow = nPattern & 0xffff;
00407     pModule->m_TestHigh= nPattern >> 16;
00408   } 
00409   else {
00410     pModule->m_ControlRegister &= ~CTL_TEST;
00411   }
00412 }
00414 // 
00415 // Functions that operateon acquisition modes:
00416 //
00417 
00428 void
00429 CAENV890::LoadDefaultConfig()
00430 {
00431 
00432   // Write the command code:
00433   
00434   WriteMicro(0x0500);   // Load the code.
00435 }
00441 bool
00442 CAENV890::isTriggerMatching()
00443 {
00444   WriteMicro(0x0200);
00445 
00446 
00447   u_short data = ReadMicro();
00448 
00449   return ((data & 1) != 0);
00450 
00451 }
00463 void 
00464 CAENV890::ReadTriggerConfig(TriggerInfo* pTriggerInfo)
00465 {
00466   ReadMicroArray(0x1600, 5, (short*)pTriggerInfo);
00467 
00468 }
00474 void
00475 CAENV890::SetTriggerMatchingMode()
00476 {
00477   WriteMicro(0x0000);
00478 }
00484 void
00485 CAENV890::SetContinuousStorageMode()
00486 {
00487   WriteMicro(0x0100);
00488 }
00495 bool
00496 CAENV890::isTriggerMatchingMode()
00497 {
00498   u_short mode;
00499   ReadMicroArray(0x0200, 1, &mode);
00500   return ((mode & 1) == 1);
00501 }
00502 
00504 //   Functions that operate on the channel enables:
00505 
00511 void
00512 CAENV890::EnableChannel(int nChan)
00513 {
00514   if(nChan > 127) {
00515     char message[80];
00516     sprintf(message, "CAENV890::EnableChannel channel value %d out of range",
00517             nChan);
00518     throw string(message);
00519   }
00520   u_short op = 0x4000 | nChan;
00521   WriteMicro(op);
00522 }
00528 void
00529 CAENV890::DisableChannel(int nChan)
00530 {
00531   if(nChan > 127) {
00532     char message[80];
00533     sprintf(message, "CAENV890::DisableChannel channel value %d out of range",
00534             nChan);
00535   }
00536   u_short op = 0x4100 | nChan;
00537   WriteMicro(op);
00538 }
00542 void
00543 CAENV890::EnableAllChannels()
00544 {
00545   WriteMicro(0x4200);
00546 }
00550 void
00551 CAENV890::DisableAllChannels()
00552 {
00553   WriteMicro(0x4300);
00554 }
00563 void
00564 CAENV890::SetChannelMask(u_short* pMask)
00565 {
00566   WriteMicroArray(0x4400, 8, pMask);
00567 
00568 }
00575 void
00576 CAENV890::ReadChannelEnables(u_short* pTriggerInfo)
00577 {
00578   ReadMicroArray(0x4500, 8, pTriggerInfo);
00579 }
00589 void
00590 CAENV890::SetWindowWidth(int ns)
00591 {
00592   int MaxNs = TicksToNs(m_nTdcMaxVal);
00593   if(ns > MaxNs) {
00594     char message[100];
00595     sprintf(message, "CAENV890::SetWindowWidth %d out of range of 0-%d",
00596             ns, MaxNs);
00597     throw string(message);
00598   }
00599   int steps = NsToTicks(ns);
00600   if(steps > 4095) {
00601     char message[100];
00602     sprintf(message, 
00603             "CAENV890::SetWindowWidth computed with value %d out of [0,%d]",
00604             steps, m_nTdcMaxVal);
00605   }
00606   WriteMicroArray(0x1000, 1, &steps);
00607   
00608 }
00614 int
00615 CAENV890::GetWindowWidth()
00616 {
00617   TriggerInfo TriggerData;;
00618   ReadTriggerConfig(&TriggerData);
00619   int steps = TriggerData.Window;
00620   return TicksToNs(steps);
00621 }
00631 void
00632 CAENV890::SetWindowOffset(int ns)
00633 {
00634   int ticks = NsToTicks(ns);
00635   if ((ticks < -2048) || (ticks > 40) ) {
00636     char msg[100];
00637     sprintf(msg, "CAENV890::SetWindowOffset offset %d is out of range",
00638             ns);
00639     throw string(msg);
00640   }
00641 
00642   WriteMicroArray(0x1100, 1, &ticks);
00643 }
00649 int
00650 CAENV890::GetWindowOffset()
00651 {
00652   TriggerInfo info;
00653   ReadTriggerConfig(&info);
00654   return TicksToNs(info.Offset);
00655 }
00659 void
00660 CAENV890::EnableTriggerSubtraction()
00661 {
00662   WriteMicro(0x1400);
00663 }
00667 void
00668 CAENV890::DisableTriggerSubtraction()
00669 {
00670   WriteMicro(0x1500);
00671 }
00678 bool
00679 CAENV890::TriggerSubtractionEnabled()
00680 {
00681   TriggerInfo info;
00682   ReadTriggerConfig(&info);
00683   return (info.SubtractionEnabled & 1) != 0;
00684 }
00692 void
00693 CAENV890::SetEdgeDetection(CAENV890::EdgeDetectSelection edge)
00694 {
00695   if((edge < EdgePairs) || (edge > EitherEdge)) {
00696     throw string("CAENV890::SetEdgeDetection invalid edge selector");
00697   }
00698   WriteMicroArray(0x2200, 1, &edge);
00699 }
00705 CAENV890::EdgeDetectSelection
00706 CAENV890::GetEdgeDetection()
00707 {
00708   short value;
00709   ReadMicroArray(0x2300, 1, &value);
00710   return (EdgeDetectSelection)(value & 0x3);
00711 }
00720 void
00721 CAENV890::SetResolution(CAENV890::ResolutionSelection res)
00722 {
00723   if((res < ps800) || (res > ps100)) {
00724     throw string("CAENV890::SetResolution invalid resolution value");
00725   }
00726   WriteMicroArray(0x2400, 1, &res);
00727 
00728 }
00733 CAENV890::ResolutionSelection
00734 CAENV890::GetResolution()
00735 {
00736   short res;
00737   ReadMicroArray(0x2600, 1, &res);
00738   return (ResolutionSelection)(res & 0x3);
00739 }
00744 void
00745 CAENV890::EnableDelimeters()
00746 {
00747   WriteMicro(0x300);
00748 }
00753 void
00754 CAENV890::DisableDelimeters()
00755 {
00756   WriteMicro(0x3100);
00757 }
00765 bool
00766 CAENV890::DelimetersEnabled()
00767 {
00768   short flag;
00769   ReadMicroArray(0x3200, 1, &flag);
00770   return (flag & 1) != 0;
00771 }
00782 void
00783 CAENV890::SetMaxHits(CAENV890::MaxHitSelection hits)
00784 {
00785   if(hits > HitMaxNoLimit) {
00786     throw string("CAENV890::SetMaxHits - Invalid value for hits parameter");
00787   }
00788   WriteMicroArray(0x3300, 1, &hits);
00789 }
00790 
00795 CAENV890::MaxHitSelection
00796 CAENV890::GetMaxHits()
00797 {
00798   short hits;
00799   ReadMicroArray(0x3400, 1, &hits);
00800   return (MaxHitSelection)(hits & 0xf);
00801 }
00811 void
00812 CAENV890::WriteMicro(u_short opcode)
00813 {
00814   volatile CAENRegisters* pModule = (volatile CAENRegisters*)m_pModule;
00815 
00816   while((pModule->m_MicroHandshake & UH_WRITE_OK) == 0)
00817     ;
00818   usleep(assinine_delay);
00819   pModule->m_Micro = opcode;
00820 }
00821 
00831 u_short
00832 CAENV890::ReadMicro()
00833 {
00834   volatile CAENRegisters* pModule = (volatile CAENRegisters*)m_pModule;
00835   while((pModule->m_MicroHandshake & UH_READ_OK) == 0)
00836     ;
00837   usleep(assinine_delay);
00838   return pModule->m_Micro;
00839 }
00850 void
00851 CAENV890::ReadMicroArray(u_short opcode, u_short nWords, void* pBuffer)
00852 {
00853   u_short* p((u_short*)pBuffer);
00854   WriteMicro(opcode);
00855   for(int i=0; i < nWords; i++) {
00856     *p++ = ReadMicro();
00857   }
00858 }
00869 void
00870 CAENV890::WriteMicroArray(u_short opcode, u_short nWords, void* pBuffer)
00871 {
00872   u_short* p((u_short*)pBuffer);
00873   WriteMicro(opcode);
00874   for(int i =0; i < nWords; i++) {
00875     WriteMicro(*p++);
00876   }
00877 }
00881 int
00882 CAENV890::ReadModuleType(void* prom)
00883 {
00884   CAENProm* p((CAENProm*)prom);
00885   return ((p->m_BoardTypeMSB & 0xff) << 16) |
00886          ((p->m_BoardType & 0xff)    <<  8)   |
00887          ((p->m_BoardTypeLSB & 0xff) );
00888 }
00898 int
00899 CAENV890::TicksToNs(int ticks)
00900 {
00901   return ticks*m_nTdcClock;
00902 }
00910 int
00911 CAENV890::NsToTicks(int ns)
00912 {
00913   // ns can be signed!!!!
00914 
00915   bool negative = ns < 0;
00916   int  rounder  = (negative ? -1 : 1)*m_nTdcClock/2;
00917   int ticks;
00918   return (ns + rounder)/m_nTdcClock;
00919 
00920 }
00924 bool
00925 CAENV890::DataReady()
00926 {
00927   CAENRegisters* pModule = (CAENRegisters*)m_pModule;
00928   return (pModule->m_StatusRegister & STAT_DATAREADY) != 0;
00929 }

Generated on Wed Sep 17 08:38:09 2008 for NSCL Device support. by  doxygen 1.5.1