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);
00016 const int CAENV890::m_nTdcMaxVal(4095);
00017
00018
00019 typedef u_char byte;
00020
00021
00022
00023
00024 struct CAENProm {
00025 byte m_pad0[0x26];
00026 u_short m_OUIMsb;
00027 u_short m_pad1;
00028 u_short m_OUI;
00029 u_short m_pad2;
00030 u_short m_OUILsb;
00031 u_short m_pad3;
00032 u_short m_Version;
00033 u_short m_pad4;
00034 u_short m_BoardTypeMSB;
00035 u_short m_pad5;
00036 u_short m_BoardType;
00037 u_short m_pad6;
00038 u_short m_BoardTypeLSB;
00039 byte m_pad7[0x0e];
00040 u_short m_Revision;
00041 byte m_pad8[0xeb2];
00042 u_short m_SerialMsb;
00043 u_short m_pad9;
00044 u_short m_SerialLsb;
00045 };
00046 static const unsigned int CAENPROMSize(sizeof(CAENProm));
00047
00048
00049
00050
00051 struct CAENRegisters {
00052 u_long m_OutputBuffer[0x1000/sizeof(u_long)];
00053 u_short m_ControlRegister;
00054 u_short m_StatusRegister;
00055 u_short m_Ader32;
00056 u_short m_Ader24;
00057 u_short m_EnableAder;
00058 u_short m_IPL;
00059 u_short m_Vector;
00060 u_short m_Geo;
00061 u_short m_MCSTBase;
00062 u_short m_MCSTCtl;
00063 u_short m_Reset;
00064 u_short m_Pad;
00065 u_short m_Clear;
00066 u_short m_SWEventReset;
00067 u_short m_SWTrigger;
00068 u_short m_EventCounter;
00069 u_short m_EventStored;
00070 u_short m_AlmostFullLvl;
00071 u_short m_BLTEventNumber;
00072 u_short m_FWRevision;
00073 u_short m_TestLow;
00074 u_short m_TestHigh;
00075 u_short m_OutProgControl;
00076 volatile u_short m_Micro;
00077 volatile u_short m_MicroHandshake;
00078
00079 };
00080 static const unsigned int CAENRegisterSize(sizeof(CAENRegisters));
00081
00082
00083
00084 const u_short STAT_DATAREADY(1);
00085
00086
00087
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
00097
00098
00099 const u_short UH_WRITE_OK(1);
00100 const u_short UH_READ_OK(2);
00101
00102
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) {
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
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
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
00250
00251 CVMEInterface::Unmap(pDevice, pProm, CAENPROMSize);
00252
00253
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();
00263
00264
00265
00266
00267
00268
00269
00270
00271 volatile CAENRegisters* pRegisters = (volatile CAENRegisters*)m_pModule;
00272 try {
00273 if(m_fGeographical) {
00274 pRegisters->m_Ader32 = m_nSlot;
00275 pRegisters->m_Ader24 = 0;
00276 pRegisters->m_EnableAder = 1;
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 {
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;
00324 if(state) control |= CTL_ENABLE_EMPTY;
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);
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
00416
00417
00428 void
00429 CAENV890::LoadDefaultConfig()
00430 {
00431
00432
00433
00434 WriteMicro(0x0500);
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
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
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 }